You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

618 lines
22KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #define STDIO_OVERRIDE Rackdep
  18. #include <cstdio>
  19. #include <cstring>
  20. #include "nanovg.h"
  21. // fix bogaudio build, another missing symbol
  22. #ifndef NDEBUG
  23. namespace bogaudio {
  24. struct FollowerBase {
  25. static float efGainMaxDecibelsDebug;
  26. };
  27. float FollowerBase::efGainMaxDecibelsDebug = 12.0f;
  28. }
  29. #endif
  30. // Special nvgRGB for blank panels
  31. extern "C" {
  32. NVGcolor nvgRGBblank(unsigned char, unsigned char, unsigned char)
  33. {
  34. return nvgRGB(0x20, 0x20, 0x20);
  35. }
  36. }
  37. // Compile those nice implementation-in-header little libraries
  38. #define NANOSVG_IMPLEMENTATION
  39. #define NANOSVG_ALL_COLOR_KEYWORDS
  40. #undef nsvgParseFromFile
  41. #include <nanosvg.h>
  42. // Custom Cardinal filtering
  43. static const struct {
  44. const char* const filename;
  45. const char* shapeIdsToIgnore[5];
  46. const int shapeNumberToIgnore;
  47. } svgFilesToInvert[] = {
  48. // MIT
  49. { "/21kHz/res/Panels/D_Inf.svg", {}, -1 },
  50. { "/21kHz/res/Panels/PalmLoop.svg", {}, -1 },
  51. { "/21kHz/res/Panels/TachyonEntangler.svg", {}, -1 },
  52. // MIT
  53. {"/AaronStatic/res/ChordCV.svg", {}, -1 },
  54. {"/AaronStatic/res/DiatonicCV.svg", {}, -1 },
  55. {"/AaronStatic/res/RandomNoteCV.svg", {}, -1 },
  56. {"/AaronStatic/res/ScaleCV.svg", {}, -1 },
  57. // GPL3.0-or-later
  58. { "/Algoritmarte/res/Clockkky.svg", {}, -1 },
  59. { "/Algoritmarte/res/CyclicCA.svg", {}, -1 },
  60. { "/Algoritmarte/res/HoldMeTight.svg", {}, -1 },
  61. { "/Algoritmarte/res/MusiFrog.svg", {}, -1 },
  62. { "/Algoritmarte/res/MusiMath.svg", {}, -1 },
  63. { "/Algoritmarte/res/Planetz.svg", {}, -1 },
  64. { "/Algoritmarte/res/Zefiro.svg", {}, -1 },
  65. // Custom, runtime dark mode used with permission
  66. { "/ArableInstruments/res/Joni.svg", {}, -1 },
  67. // Custom, runtime dark mode used with permission
  68. { "/AudibleInstruments/res/Blinds.svg", {}, -1 },
  69. { "/AudibleInstruments/res/Braids.svg", {}, -1 },
  70. { "/AudibleInstruments/res/Branches.svg", {}, -1 },
  71. { "/AudibleInstruments/res/Clouds.svg", {}, -1 },
  72. { "/AudibleInstruments/res/Elements.svg", {}, -1 },
  73. { "/AudibleInstruments/res/Frames.svg", {}, -1 },
  74. { "/AudibleInstruments/res/Kinks.svg", {}, -1 },
  75. { "/AudibleInstruments/res/Links.svg", {}, -1 },
  76. { "/AudibleInstruments/res/Marbles.svg", {}, -1 },
  77. { "/AudibleInstruments/res/Peaks.svg", {}, -1 },
  78. { "/AudibleInstruments/res/Plaits.svg", {}, -1 },
  79. { "/AudibleInstruments/res/Rings.svg", {}, -1 },
  80. { "/AudibleInstruments/res/Ripples.svg", {}, -1 },
  81. { "/AudibleInstruments/res/Shades.svg", {}, -1 },
  82. { "/AudibleInstruments/res/Sheep.svg", {}, -1 },
  83. { "/AudibleInstruments/res/Shelves.svg", {}, -1 },
  84. { "/AudibleInstruments/res/Stages.svg", {}, -1 },
  85. { "/AudibleInstruments/res/Streams.svg", {}, -1 },
  86. { "/AudibleInstruments/res/Tides.svg", {}, -1 },
  87. { "/AudibleInstruments/res/Tides2.svg", {}, -1 },
  88. { "/AudibleInstruments/res/Veils.svg", {}, -1 },
  89. { "/AudibleInstruments/res/Warps.svg", {}, -1 },
  90. // CC-BY-NC-ND-4.0, runtime dark mode used with permission
  91. { "/Bidoo/res/ACNE.svg", {}, -1 },
  92. { "/Bidoo/res/ANTN.svg", {}, -1 },
  93. { "/Bidoo/res/BAFIS.svg", {}, -1 },
  94. { "/Bidoo/res/BANCAU.svg", {}, -1 },
  95. { "/Bidoo/res/BAR.svg", {"rect833"}, -1 },
  96. { "/Bidoo/res/BISTROT.svg", {}, -1 },
  97. { "/Bidoo/res/BORDL.svg", {"rect959-3-0-7-5","rect959-3-0-7","rect959-3-0","rect959-3"}, -1 },
  98. { "/Bidoo/res/CANARD.svg", {"rect959-3-7"}, -1 },
  99. { "/Bidoo/res/CHUTE.svg", {}, -1 },
  100. { "/Bidoo/res/DFUZE.svg", {}, -1 },
  101. { "/Bidoo/res/DIKTAT.svg", {"rect843","rect843-0","rect843-0-8"}, -1 },
  102. { "/Bidoo/res/DILEMO.svg", {}, -1 },
  103. { "/Bidoo/res/DTROY.svg", {"rect959-3"}, -1 },
  104. { "/Bidoo/res/DUKE.svg", {}, -1 },
  105. { "/Bidoo/res/EDSAROS.svg", {"rect959-3-7","rect959-3-7-8","rect959-3-7-8-1","rect959-3-7-8-1-4"}, -1 },
  106. { "/Bidoo/res/EMILE.svg", {}, -1 },
  107. { "/Bidoo/res/FLAME.svg", {}, -1 },
  108. { "/Bidoo/res/FORK.svg", {}, -1 },
  109. { "/Bidoo/res/FREIN.svg", {}, -1 },
  110. { "/Bidoo/res/HCTIP.svg", {}, -1 },
  111. { "/Bidoo/res/HUITRE.svg", {}, -1 },
  112. { "/Bidoo/res/LAMBDA.svg", {}, -1 },
  113. { "/Bidoo/res/LATE.svg", {}, -1 },
  114. { "/Bidoo/res/LIMBO.svg", {}, -1 },
  115. { "/Bidoo/res/LIMONADE.svg", {"rect839","rect839-6"}, -1 },
  116. { "/Bidoo/res/LOURDE.svg", {"rect847","rect847-7","rect847-5","rect847-3"}, -1 },
  117. { "/Bidoo/res/MAGMA.svg", {}, -1 },
  118. { "/Bidoo/res/MINIBAR.svg", {"rect833"}, -1 },
  119. { "/Bidoo/res/MOIRE.svg", {"rect843","rect843-7"}, -1 },
  120. { "/Bidoo/res/MS.svg", {}, -1 },
  121. { "/Bidoo/res/MU.svg", {"rect864"}, -1 },
  122. { "/Bidoo/res/OAI.svg", {}, -1 },
  123. { "/Bidoo/res/OUAIVE.svg", {"rect959-3-7"}, -1 },
  124. { "/Bidoo/res/PERCO.svg", {}, -1 },
  125. { "/Bidoo/res/PILOT.svg", {"rect843-6-4-5","rect843","rect843-4","rect843-6-4","rect843-6-7"}, -1 },
  126. { "/Bidoo/res/POUPRE.svg", {}, -1 },
  127. { "/Bidoo/res/RABBIT.svg", {}, -1 },
  128. { "/Bidoo/res/REI.svg", {}, -1 },
  129. { "/Bidoo/res/SIGMA.svg", {}, -1 },
  130. { "/Bidoo/res/SPORE.svg", {}, -1 },
  131. { "/Bidoo/res/TIARE.svg", {}, -1 },
  132. { "/Bidoo/res/TOCANTE.svg", {"rect843"}, -1 },
  133. { "/Bidoo/res/VOID.svg", {}, -1 },
  134. { "/Bidoo/res/ZINC.svg", {}, -1 },
  135. { "/Bidoo/res/ZOUMAI.svg", {}, -1 },
  136. { "/Bidoo/res/ZOUMAIExpander.svg", {}, -1 },
  137. // BSD-3-Clause
  138. { "/cf/res/ALGEBRA.svg", {}, -1 },
  139. { "/cf/res/BUFFER.svg", {}, -1 },
  140. { "/cf/res/CHOKE.svg", {}, -1 },
  141. { "/cf/res/CUBE.svg", {}, -1 },
  142. { "/cf/res/CUTS.svg", {}, -1 },
  143. { "/cf/res/DISTO.svg", {}, -1 },
  144. { "/cf/res/EACH.svg", {}, -1 },
  145. { "/cf/res/FOUR.svg", {}, -1 },
  146. { "/cf/res/FUNKTION.svg", {}, -1 },
  147. { "/cf/res/L3DS3Q.svg", {}, 3 },
  148. { "/cf/res/LABEL.svg", {}, -1 },
  149. { "/cf/res/LEDS.svg", {}, -1 },
  150. { "/cf/res/LEDSEQ.svg", {}, 3 },
  151. { "/cf/res/MASTER.svg", {}, -1 },
  152. { "/cf/res/METRO.svg", {}, -1 },
  153. { "/cf/res/MONO.svg", {}, -1 },
  154. { "/cf/res/PATCH.svg", {}, -1 },
  155. { "/cf/res/PEAK.svg", {}, -1 },
  156. { "/cf/res/PLAY.svg", {}, -1 },
  157. { "/cf/res/PLAYER.svg", {}, -1 },
  158. { "/cf/res/SLIDERSEQ.svg", {}, -1 },
  159. { "/cf/res/STEPS.svg", {}, -1 },
  160. { "/cf/res/STEREO.svg", {}, -1 },
  161. { "/cf/res/SUB.svg", {}, -1 },
  162. { "/cf/res/trSEQ.svg", {}, -1 },
  163. { "/cf/res/VARIABLE.svg", {}, -1 },
  164. // CC0-1.0
  165. { "/DrumKit/res/Baronial.svg", {}, -1 },
  166. { "/DrumKit/res/BD9.svg", {}, -1 },
  167. { "/DrumKit/res/ClosedHH.svg", {}, -1 },
  168. { "/DrumKit/res/CR78.svg", {}, -1 },
  169. { "/DrumKit/res/DMX.svg", {}, -1 },
  170. { "/DrumKit/res/Gnome.svg", {}, -1 },
  171. { "/DrumKit/res/Marionette.svg", {}, -1 },
  172. { "/DrumKit/res/OpenHH.svg", {}, -1 },
  173. { "/DrumKit/res/SBD.svg", {}, -1 },
  174. { "/DrumKit/res/Sequencer.svg", {}, -1 },
  175. { "/DrumKit/res/Snare.svg", {}, -1 },
  176. { "/DrumKit/res/Tomi.svg", {}, -1 },
  177. // Custom, runtime dark mode used with permission
  178. { "/ESeries/res/E340.svg", {}, -1 },
  179. // CC0-1.0
  180. { "/HetrickCV/res/1OpChaos.svg", {}, -1},
  181. { "/HetrickCV/res/2OpChaos.svg", {}, -1},
  182. { "/HetrickCV/res/2To4.svg", {}, -1},
  183. { "/HetrickCV/res/3OpChaos.svg", {}, -1},
  184. { "/HetrickCV/res/ASR.svg", {}, -1},
  185. { "/HetrickCV/res/AToD.svg", {}, -1},
  186. { "/HetrickCV/res/BinaryGate.svg", {}, -1},
  187. { "/HetrickCV/res/BinaryNoise.svg", {}, -1},
  188. { "/HetrickCV/res/Bitshift.svg", {}, -1},
  189. { "/HetrickCV/res/Boolean3.svg", {}, -1},
  190. { "/HetrickCV/res/ChaoticAttractors.svg", {}, -1},
  191. { "/HetrickCV/res/ClockedNoise.svg", {}, -1},
  192. { "/HetrickCV/res/Comparator.svg", {}, -1},
  193. { "/HetrickCV/res/Contrast.svg", {}, -1},
  194. { "/HetrickCV/res/Crackle.svg", {}, -1},
  195. { "/HetrickCV/res/DataCompander.svg", {}, -1},
  196. { "/HetrickCV/res/Delta.svg", {}, -1},
  197. { "/HetrickCV/res/DToA.svg", {}, -1},
  198. { "/HetrickCV/res/Dust.svg", {}, -1},
  199. { "/HetrickCV/res/Exponent.svg", {}, -1},
  200. { "/HetrickCV/res/FBSineChaos.svg", {}, -1},
  201. { "/HetrickCV/res/FlipFlop.svg", {}, -1},
  202. { "/HetrickCV/res/FlipPan.svg", {}, -1},
  203. { "/HetrickCV/res/GateJunction.svg", {}, -1},
  204. { "/HetrickCV/res/Gingerbread.svg", {}, -1},
  205. { "/HetrickCV/res/LogicCombiner.svg", {}, -1},
  206. { "/HetrickCV/res/LogicInverter.svg", {}, -1},
  207. { "/HetrickCV/res/MidSide.svg", {}, -1},
  208. { "/HetrickCV/res/MinMax.svg", {}, -1},
  209. { "/HetrickCV/res/RandomGates.svg", {}, -1},
  210. { "/HetrickCV/res/Rotator.svg", {}, -1},
  211. { "/HetrickCV/res/Rungler.svg", {}, -1},
  212. { "/HetrickCV/res/Scanner.svg", {}, -1},
  213. { "/HetrickCV/res/TrigShaper.svg", {}, -1},
  214. { "/HetrickCV/res/Waveshape.svg", {}, -1},
  215. { "/HetrickCV/res/XYToPolar.svg", {}, -1},
  216. { "/HetrickCV/res/Blanks/BlankPanel1.svg", {}, -1},
  217. { "/HetrickCV/res/Blanks/BlankPanel2.svg", {}, -1},
  218. { "/HetrickCV/res/Blanks/BlankPanel3.svg", {}, -1},
  219. { "/HetrickCV/res/Blanks/BlankPanel5.svg", {}, -1},
  220. { "/HetrickCV/res/Blanks/BlankPanel6.svg", {}, -1},
  221. { "/HetrickCV/res/Blanks/BlankPanel7.svg", {}, -1},
  222. { "/HetrickCV/res/Blanks/BlankPanel8.svg", {}, -1},
  223. // BSD-3-Clause
  224. { "/JW-Modules/res/Add5.svg", {}, -1 },
  225. { "/JW-Modules/res/BlankPanel1hp.svg", {}, -1 },
  226. { "/JW-Modules/res/BlankPanelLarge.svg", {}, -1 },
  227. { "/JW-Modules/res/BlankPanelMedium.svg", {}, -1 },
  228. { "/JW-Modules/res/BlankPanelSmall.svg", {}, -1 },
  229. { "/JW-Modules/res/BouncyBalls.svg", {}, -1 },
  230. { "/JW-Modules/res/D1v1de.svg", {}, -1 },
  231. { "/JW-Modules/res/DivSeq.svg", {}, -1 },
  232. { "/JW-Modules/res/EightSeq.svg", {}, -1 },
  233. { "/JW-Modules/res/GridSeq.svg", {}, -1 },
  234. { "/JW-Modules/res/MinMax.svg", {"path38411"}, -1 },
  235. { "/JW-Modules/res/NoteSeq.svg", {}, -1 },
  236. { "/JW-Modules/res/NoteSeq16.svg", {}, -1 },
  237. { "/JW-Modules/res/NoteSeqFu.svg", {}, -1 },
  238. { "/JW-Modules/res/OnePattern.svg", {}, -1 },
  239. { "/JW-Modules/res/Patterns.svg", {}, -1 },
  240. { "/JW-Modules/res/Pres1t.svg", {}, -1 },
  241. { "/JW-Modules/res/PT.svg", {}, -1 },
  242. { "/JW-Modules/res/Str1ker.svg", {"rect2094","rect995","rect169"}, -1 },
  243. { "/JW-Modules/res/Trigs.svg", {}, -1 },
  244. { "/JW-Modules/res/WavHeadPanel.svg", {}, -1 },
  245. { "/JW-Modules/res/XYPad.svg", {}, -1 },
  246. // GPL3.0-or-later
  247. { "/LilacLoop/res/Looper.svg", {}, -1 },
  248. // EUPL-1.2
  249. { "/LittleUtils/res/Bias_Semitone.svg", {}, -1 },
  250. { "/LittleUtils/res/ButtonModule.svg", {}, -1 },
  251. { "/LittleUtils/res/MulDiv.svg", {}, -1 },
  252. { "/LittleUtils/res/PulseGenerator.svg", {}, -1 },
  253. { "/LittleUtils/res/TeleportIn.svg", {}, -1 },
  254. { "/LittleUtils/res/TeleportOut.svg", {}, -1 },
  255. // GPL-3.0-or-later
  256. { "/kocmoc/res/DDLY.svg", {}, -1 },
  257. { "/kocmoc/res/LADR.svg", {}, -1 },
  258. { "/kocmoc/res/MUL.svg", {}, -1 },
  259. { "/kocmoc/res/OP.svg", {}, -1 },
  260. { "/kocmoc/res/PHASR.svg", {}, -1 },
  261. { "/kocmoc/res/SKF.svg", {}, -1 },
  262. { "/kocmoc/res/SVF.svg", {}, -1 },
  263. { "/kocmoc/res/TRG.svg", {}, -1 },
  264. // CC0-1.0
  265. { "/nonlinearcircuits/res/NLC - 4seq.svg", {}, -1 },
  266. { "/nonlinearcircuits/res/NLC - 8 BIT CIPHER.svg", {}, -1 },
  267. { "/nonlinearcircuits/res/BOOLs2.svg", {}, -1 },
  268. { "/nonlinearcircuits/res/NLC - DIVIDE & CONQUER.svg", {}, -1 },
  269. { "/nonlinearcircuits/res/NLC - DIVINE CMOS.svg", {}, -1 },
  270. { "/nonlinearcircuits/res/DoubleNeuronRef.svg", {}, -1 },
  271. { "/nonlinearcircuits/res/NLC - GENiE.svg", {}, -1 },
  272. { "/nonlinearcircuits/res/LetsSplosh.svg", {}, -1 },
  273. { "/nonlinearcircuits/res/NLC - NEURON.svg", {}, -1 },
  274. { "/nonlinearcircuits/res/NLC - NUMBERWANG.svg", {}, -1 },
  275. { "/nonlinearcircuits/res/NLC - SEGUE.svg", {}, -1 },
  276. { "/nonlinearcircuits/res/squid-axon-papernoise-panel2.svg", {}, -1 },
  277. { "/nonlinearcircuits/res/NLC - STATUES.svg", {}, -1 },
  278. // Custom, runtime dark mode used with permission
  279. { "/ParableInstruments/res/Neil.svg", {}, -1 },
  280. // GPL-3.0-or-later
  281. { "/PathSet/res/AstroVibe.svg", {}, -1 },
  282. { "/PathSet/res/IceTray.svg", {}, -1 },
  283. { "/PathSet/res/ShiftyMod.svg", {}, -1 },
  284. // BSD-3-Clause
  285. { "/voxglitch/res/autobreak_front_panel.svg", {}, -1 },
  286. { "/voxglitch/res/bytebeat_front_panel.svg", {}, -1 },
  287. { "/voxglitch/res/digital_programmer_front_panel.svg", {}, -1 },
  288. { "/voxglitch/res/digital_sequencer_front_panel.svg", {}, -1 },
  289. { "/voxglitch/res/digital_sequencer_xp_front_panel.svg", {}, -1 },
  290. { "/voxglitch/res/ghosts_front_panel.svg", {}, -1 },
  291. { "/voxglitch/res/glitch_sequencer_front_panel.svg", {}, -1 },
  292. { "/voxglitch/res/goblins_front_panel.svg", {}, -1 },
  293. { "/voxglitch/res/grain_engine_mk2_expander_front_panel.svg", {}, -1 },
  294. { "/voxglitch/res/grain_engine_mk2_front_panel_r3.svg", {}, -1 },
  295. { "/voxglitch/res/grain_fx_front_panel.svg", {}, -1 },
  296. { "/voxglitch/res/hazumi_front_panel.svg", {}, -1 },
  297. { "/voxglitch/res/looper_front_panel.svg", {}, -1 },
  298. { "/voxglitch/res/repeater_front_panel.svg", {}, -1 },
  299. { "/voxglitch/res/samplerx8_front_panel.svg", {}, -1 },
  300. { "/voxglitch/res/satanonaut_front_panel.svg", {}, -1 },
  301. { "/voxglitch/res/wav_bank_front_panel.svg", {}, -1 },
  302. { "/voxglitch/res/wav_bank_mc_front_panel_v2.svg", {}, -1 },
  303. { "/voxglitch/res/xy_front_panel.svg", {}, -1 },
  304. };
  305. static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const char* const svgFileToInvert = nullptr)
  306. {
  307. if (paint.type == NSVG_PAINT_LINEAR_GRADIENT && svgFileToInvert != nullptr)
  308. {
  309. // Special case for DrumKit background gradient
  310. if (std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0)
  311. {
  312. paint.type = NSVG_PAINT_COLOR;
  313. paint.color = 0xff191919;
  314. return true;
  315. }
  316. // Special case for PathSet shifty gradient
  317. if (std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0)
  318. {
  319. paint.gradient->stops[0].color = 0xff7c4919; // 50% darker than main blue
  320. paint.gradient->stops[1].color = 0xff5b3a1a; // 33.3% darker than main blue
  321. return false;
  322. }
  323. }
  324. if (paint.type == NSVG_PAINT_NONE)
  325. return true;
  326. if (paint.type != NSVG_PAINT_COLOR)
  327. return false;
  328. // Special case for Bidoo red color
  329. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/Bidoo/", 7) == 0)
  330. {
  331. if (paint.color == 0xff001fcd)
  332. {
  333. paint.color = 0xcf8b94c4;
  334. return true;
  335. }
  336. if (paint.color == 0xff000000 && shape->stroke.type == NSVG_PAINT_COLOR)
  337. {
  338. switch (shape->stroke.color)
  339. {
  340. case 0xff777777:
  341. case 0xff7c7c7c:
  342. case 0xff828282:
  343. case 0xffb1b1b1:
  344. case 0xffb2b2b2:
  345. return false;
  346. }
  347. }
  348. }
  349. // Special case for JW-Modules colors
  350. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/JW-Modules/", 12) == 0)
  351. {
  352. switch (paint.color)
  353. {
  354. // do nothing
  355. case 0x320997ff:
  356. case 0x32099aff:
  357. case 0x3209f1ff:
  358. case 0x3209f3ff:
  359. case 0x32fc1a8f:
  360. case 0x32fc1a90:
  361. case 0x32fc9418:
  362. case 0x32fc9619:
  363. case 0xc7fc9619:
  364. case 0xff050505:
  365. case 0xffead7be:
  366. case 0xfff7a540:
  367. case 0xfffa9c2a:
  368. case 0xfffc9619:
  369. case 0xfffcb654:
  370. case 0xfffd9c17:
  371. case 0xffffffff:
  372. return false;
  373. // make more transparent
  374. case 0xffbad6eb:
  375. case 0xffbae8eb:
  376. case 0xffeabed5:
  377. case 0xffead6bd:
  378. paint.color = 0x32000000 | (paint.color & 0xffffff);
  379. return true;
  380. // make it more white
  381. case 0xffa0a0a0:
  382. paint.color = 0xffc0c0c0;
  383. return true;
  384. }
  385. }
  386. // Special case for Lilac
  387. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/LilacLoop/", 11) == 0)
  388. {
  389. switch (paint.color)
  390. {
  391. // main bg (custom)
  392. case 0xffd5d5da:
  393. paint.color = 0xff242228;
  394. return true;
  395. // main color (do nothing)
  396. case 0xffbfb7d7:
  397. return false;
  398. // screws (hide)
  399. case 0xffc8c8cf:
  400. case 0xffbcbcbc:
  401. case 0xffb1b1bb:
  402. case 0xffacacac:
  403. case 0xff898991:
  404. case 0xff727272:
  405. paint.color = 0x00000000;
  406. return true;
  407. }
  408. }
  409. // Special case for Nonlinear Circuits
  410. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/nonlinearcircuits/", 19) == 0)
  411. {
  412. switch (paint.color)
  413. {
  414. case 0xff9a7900:
  415. case 0xff96782c:
  416. case 0xff6a07ae:
  417. case 0xffcf8044:
  418. case 0xff2ac6ba:
  419. case 0xff5ba85c:
  420. case 0xffa97b00:
  421. case 0xff9f7a00:
  422. case 0xffff7300:
  423. case 0xffa47b00:
  424. case 0xffb09423:
  425. return false;
  426. case 0xffffffff:
  427. paint.color = 0x00000000;
  428. return true;
  429. }
  430. }
  431. // Special case for PathSet colors
  432. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/PathSet/", 9) == 0)
  433. {
  434. switch (paint.color)
  435. {
  436. // main blue tone
  437. case 0xffdf7a1a:
  438. if (shape->opacity == 0.5f && std::strcmp(svgFileToInvert, "/PathSet/res/AstroVibe.svg") == 0)
  439. {
  440. shape->opacity = 0.2f;
  441. return true;
  442. }
  443. if (shape->opacity == 0.25f)
  444. shape->opacity = 0.75f;
  445. return false;
  446. // bottom logo stuff, set to full white
  447. case 0xff000000:
  448. if (shape->stroke.type != NSVG_PAINT_NONE)
  449. {
  450. paint.color = 0xffffffff;
  451. return true;
  452. }
  453. break;
  454. // pink step 2 (pink with 50% opacity on bg)
  455. case 0xffef73ea:
  456. paint.color = 0xff812d7d;
  457. return true;
  458. // pink step 3 (pink with 33.3% opacity on bg)
  459. case 0xfff49ff0:
  460. paint.color = 0xff4d234c;
  461. return true;
  462. // pink and orange
  463. case 0xffe941e2:
  464. case 0xff698efb:
  465. return false;
  466. // blue darker 1 (blue with 50% opacity on bg)
  467. case 0xffde944f:
  468. case 0xffe3b080:
  469. case 0xffe4cbb3:
  470. case 0xfff5c99f:
  471. case 0xfff6d1b0:
  472. paint.color = 0xff7c4919;
  473. return true;
  474. // blue darker 2 (blue with 33.3% opacity on bg)
  475. case 0xffe5d9cd:
  476. case 0xfff8dcc2:
  477. case 0xffe1a265:
  478. paint.color = 0xff5b3a1a;
  479. return true;
  480. // blue darker 3 (blue with 25% opacity on bg)
  481. case 0xffe5cbb3:
  482. paint.color = 0xff4b321a;
  483. return true;
  484. }
  485. }
  486. // Special case for voxglitch colors
  487. if (svgFileToInvert != nullptr && std::strncmp(svgFileToInvert, "/voxglitch/", 11) == 0)
  488. {
  489. switch (paint.color)
  490. {
  491. // wavbank blue
  492. case 0xffc5ae8a:
  493. // various black
  494. case 0xff121212:
  495. case 0xff2a2828:
  496. return false;
  497. // satanonaut
  498. case 0xff595959:
  499. paint.color = 0x7f3219ac;
  500. return true;
  501. }
  502. }
  503. switch (paint.color)
  504. {
  505. // scopes or other special things (do nothing)
  506. case 0x40ffffff:
  507. case 0xff004200:
  508. case 0xff2b281e:
  509. case 0xff2d2827:
  510. case 0xff303030:
  511. case 0xff362c23:
  512. case 0xff40352c:
  513. case 0xff5735d9:
  514. case 0xff5935d8:
  515. case 0xff5c26d9:
  516. case 0xff6140db:
  517. case 0xffa09400:
  518. case 0xffa19400:
  519. case 0xffa7a100:
  520. case 0xffa8a200:
  521. case 0xffaba102:
  522. case 0xff22a5e9:
  523. case 0xff6140da:
  524. case 0xff119ee6:
  525. case 0xff2432ed:
  526. case 0xff0095fe:
  527. case 0xff4d9a4d:
  528. case 0xff4d4d9a:
  529. case 0xff0187fc:
  530. return false;
  531. // pure black (convert to not quite pure white)
  532. case 0xff000000:
  533. paint.color = 0xffd0d0d0;
  534. return true;
  535. // all others (direct invert)
  536. default:
  537. paint.color = (paint.color & 0xff000000)
  538. | (0xff0000 - (paint.color & 0xff0000))
  539. | (0xff00 - (paint.color & 0xff00))
  540. | (0xff - (paint.color & 0xff));
  541. return true;
  542. }
  543. }
  544. extern "C" {
  545. NSVGimage* nsvgParseFromFileCardinal(const char* filename, const char* units, float dpi);
  546. }
  547. NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* const units, const float dpi)
  548. {
  549. if (NSVGimage* const handle = nsvgParseFromFile(filename, units, dpi))
  550. {
  551. for (size_t i = 0; i < sizeof(svgFilesToInvert)/sizeof(svgFilesToInvert[0]); ++i)
  552. {
  553. const char* const svgFileToInvert = svgFilesToInvert[i].filename;
  554. const size_t filenamelen = std::strlen(filename);
  555. const size_t filterlen = std::strlen(svgFileToInvert);
  556. if (filenamelen < filterlen)
  557. continue;
  558. if (std::strncmp(filename + (filenamelen-filterlen), svgFileToInvert, filterlen) != 0)
  559. continue;
  560. const char* const* const shapeIdsToIgnore = svgFilesToInvert[i].shapeIdsToIgnore;
  561. const int shapeNumberToIgnore = svgFilesToInvert[i].shapeNumberToIgnore;
  562. int shapeCounter = 0;
  563. for (NSVGshape* shape = handle->shapes; shape != nullptr; shape = shape->next, ++shapeCounter)
  564. {
  565. if (shapeNumberToIgnore == shapeCounter)
  566. continue;
  567. bool ignore = false;
  568. for (size_t j = 0; j < 5 && shapeIdsToIgnore[j] != nullptr; ++j)
  569. {
  570. if (std::strcmp(shape->id, shapeIdsToIgnore[j]) == 0)
  571. {
  572. ignore = true;
  573. break;
  574. }
  575. }
  576. if (ignore)
  577. continue;
  578. if (invertPaint(shape, shape->fill, svgFileToInvert))
  579. invertPaint(shape, shape->stroke, svgFileToInvert);
  580. }
  581. return handle;
  582. }
  583. // Special case for AmalgamatedHarmonics background color
  584. if (handle->shapes != nullptr && handle->shapes->fill.color == 0xff000000)
  585. if (std::strstr(filename, "/AmalgamatedHarmonics/") != nullptr)
  586. handle->shapes->fill.color = 0xff191919;
  587. return handle;
  588. }
  589. return nullptr;
  590. }