1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <math.h>
4 #include "ft2_palette.h"
5 #include "ft2_gui.h"
6 #include "ft2_config.h"
7 #include "ft2_video.h"
8 #include "ft2_palette.h"
9 #include "ft2_tables.h"
10 
11 uint8_t cfg_ColorNum = 0; // globalized
12 
13 static uint8_t cfg_Red, cfg_Green, cfg_Blue, cfg_Contrast;
14 
15 static const uint8_t FTC_EditOrder[6] = { PAL_PATTEXT, PAL_BLCKMRK, PAL_BLCKTXT, PAL_MOUSEPT, PAL_DESKTOP, PAL_BUTTONS };
16 static const uint8_t scaleOrder[3] = { 8, 4, 9 };
17 
18 static uint8_t palContrast[12][2] = // palette desktop/button contrasts
19 {
20 	{59, 55}, {59, 53}, {56, 59}, {68, 55}, {57, 59}, {48, 55},
21 	{66, 62}, {68, 57}, {58, 42}, {57, 55}, {62, 57}, {52, 57}
22 };
23 
setCustomPalColor(uint32_t color)24 void setCustomPalColor(uint32_t color)
25 {
26 	video.palette[PAL_CUSTOM] = (PAL_CUSTOM << 24) | color;
27 }
28 
setPal16(pal16 * p,bool redrawScreen)29 void setPal16(pal16 *p, bool redrawScreen)
30 {
31 #define LOOP_PIN_COL_SUB 110
32 #define TEXT_MARK_COLOR 0x0078D7
33 #define BOX_SELECT_COLOR 0x7F7F7F
34 
35 	int16_t r, g, b;
36 
37 	// set main palette w/ 18-bit -> 24-bit conversion
38 	for (int32_t i = 0; i < 16; i++)
39 	{
40 		r = P6_TO_P8(p[i].r); // 0..63 -> 0..255
41 		g = P6_TO_P8(p[i].g);
42 		b = P6_TO_P8(p[i].b);
43 
44 		video.palette[i] = (i << 24) | RGB32(r, g, b);
45 	}
46 
47 	// set custom FT2 clone palette entries
48 
49 	video.palette[PAL_TEXTMRK] = (PAL_TEXTMRK << 24) | TEXT_MARK_COLOR;
50 	video.palette[PAL_BOXSLCT] = (PAL_BOXSLCT << 24) | BOX_SELECT_COLOR;
51 
52 	r = RGB32_R(video.palette[PAL_PATTEXT]);
53 	g = RGB32_G(video.palette[PAL_PATTEXT]);
54 	b = RGB32_B(video.palette[PAL_PATTEXT]);
55 
56 	r = MAX(r - LOOP_PIN_COL_SUB, 0);
57 	g = MAX(g - LOOP_PIN_COL_SUB, 0);
58 	b = MAX(b - LOOP_PIN_COL_SUB, 0);
59 
60 	video.palette[PAL_LOOPPIN] = (PAL_LOOPPIN << 24) | RGB32(r, g, b);
61 
62 	// update framebuffer pixels with new palette
63 	if (redrawScreen && video.frameBuffer != NULL)
64 	{
65 		for (int32_t i = 0; i < SCREEN_W*SCREEN_H; i++)
66 			video.frameBuffer[i] = video.palette[(video.frameBuffer[i] >> 24) & 15]; // ARGB alpha channel = palette index
67 	}
68 }
69 
showColorErrorMsg(void)70 static void showColorErrorMsg(void)
71 {
72 	okBox(0, "System message", "Default colors cannot be modified.");
73 }
74 
showMouseColorErrorMsg(void)75 static void showMouseColorErrorMsg(void)
76 {
77 	okBox(0, "System message", "Mouse color can only be changed when \"Software mouse\" is enabled.");
78 }
79 
palPow(double dX,double dY)80 static double palPow(double dX, double dY)
81 {
82 	if (dY == 1.0)
83 		return dX;
84 
85 	dY *= log(fabs(dX));
86 	dY = CLAMP(dY, -86.0, 86.0);
87 
88 	return exp(dY);
89 }
90 
palMax(int32_t c)91 uint8_t palMax(int32_t c)
92 {
93 	return (uint8_t)CLAMP(c, 0, 63);
94 }
95 
drawCurrentPaletteColor(void)96 static void drawCurrentPaletteColor(void)
97 {
98 	const uint8_t palIndex = FTC_EditOrder[cfg_ColorNum];
99 
100 	const uint8_t r = P6_TO_P8(cfg_Red);
101 	const uint8_t g = P6_TO_P8(cfg_Green);
102 	const uint8_t b = P6_TO_P8(cfg_Blue);
103 
104 	textOutShadow(516, 3, PAL_FORGRND, PAL_DSKTOP2, "Palette:");
105 	hexOutBg(573, 3, PAL_FORGRND, PAL_DESKTOP, RGB32(r, g, b) & 0xFFFFFF, 6);
106 	clearRect(616, 2, 12, 10);
107 	fillRect(617, 3, 10, 8, palIndex);
108 }
109 
updatePaletteEditor(void)110 static void updatePaletteEditor(void)
111 {
112 	const uint8_t colorNum = FTC_EditOrder[cfg_ColorNum];
113 
114 	cfg_Red = palTable[config.cfg_StdPalNum][colorNum].r;
115 	cfg_Green = palTable[config.cfg_StdPalNum][colorNum].g;
116 	cfg_Blue = palTable[config.cfg_StdPalNum][colorNum].b;
117 
118 	if (cfg_ColorNum == 4 || cfg_ColorNum == 5)
119 		cfg_Contrast = palContrast[config.cfg_StdPalNum][cfg_ColorNum-4];
120 	else
121 		cfg_Contrast = 0;
122 
123 	setScrollBarPos(SB_PAL_R, cfg_Red, false);
124 	setScrollBarPos(SB_PAL_G, cfg_Green, false);
125 	setScrollBarPos(SB_PAL_B, cfg_Blue, false);
126 	setScrollBarPos(SB_PAL_CONTRAST, cfg_Contrast, false);
127 
128 	drawCurrentPaletteColor();
129 }
130 
paletteDragMoved(void)131 static void paletteDragMoved(void)
132 {
133 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
134 	{
135 		updatePaletteEditor(); // resets colors/contrast vars
136 		showColorErrorMsg();
137 		return;
138 	}
139 
140 	if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
141 	{
142 		updatePaletteEditor(); // resets colors/contrast vars
143 		showMouseColorErrorMsg();
144 		return;
145 	}
146 
147 	const uint8_t colorNum = FTC_EditOrder[cfg_ColorNum];
148 	const uint8_t p = (uint8_t)config.cfg_StdPalNum;
149 
150 	palTable[p][colorNum].r = cfg_Red;
151 	palTable[p][colorNum].g = cfg_Green;
152 	palTable[p][colorNum].b = cfg_Blue;
153 
154 	if (cfg_ColorNum == 4 || cfg_ColorNum == 5)
155 	{
156 		double dRed = cfg_Red;
157 		double dGreen = cfg_Green;
158 		double dBlue = cfg_Blue;
159 
160 		int32_t contrast = cfg_Contrast;
161 		if (contrast < 1)
162 			contrast = 1;
163 
164 		const double dContrast = contrast * (1.0 / 40.0);
165 
166 		for (int32_t i = 0; i < 3; i++)
167 		{
168 			const int32_t k = scaleOrder[i] + (cfg_ColorNum - 4) * 2;
169 
170 			double dMul = palPow((i + 1) * (1.0 / 2.0), dContrast);
171 
172 			palTable[p][k].r = palMax((int32_t)((dRed * dMul) + 0.5));
173 			palTable[p][k].g = palMax((int32_t)((dGreen * dMul) + 0.5));
174 			palTable[p][k].b = palMax((int32_t)((dBlue * dMul) + 0.5));
175 		}
176 
177 		palContrast[p][cfg_ColorNum-4] = cfg_Contrast;
178 	}
179 	else
180 	{
181 		cfg_Contrast = 0;
182 
183 		setScrollBarPos(SB_PAL_R, cfg_Red, false);
184 		setScrollBarPos(SB_PAL_G, cfg_Green, false);
185 		setScrollBarPos(SB_PAL_B, cfg_Blue, false);
186 	}
187 
188 	setScrollBarPos(SB_PAL_CONTRAST, cfg_Contrast, false);
189 
190 	setPal16(palTable[config.cfg_StdPalNum], true);
191 	drawCurrentPaletteColor();
192 }
193 
sbPalRPos(uint32_t pos)194 void sbPalRPos(uint32_t pos)
195 {
196 	if (cfg_Red != (uint8_t)pos)
197 	{
198 		cfg_Red = (uint8_t)pos;
199 		paletteDragMoved();
200 	}
201 }
202 
sbPalGPos(uint32_t pos)203 void sbPalGPos(uint32_t pos)
204 {
205 	if (cfg_Green != (uint8_t)pos)
206 	{
207 		cfg_Green = (uint8_t)pos;
208 		paletteDragMoved();
209 	}
210 }
211 
sbPalBPos(uint32_t pos)212 void sbPalBPos(uint32_t pos)
213 {
214 	if (cfg_Blue != (uint8_t)pos)
215 	{
216 		cfg_Blue = (uint8_t)pos;
217 		paletteDragMoved();
218 	}
219 }
220 
sbPalContrastPos(uint32_t pos)221 void sbPalContrastPos(uint32_t pos)
222 {
223 	if (cfg_Contrast != (uint8_t)pos)
224 	{
225 		cfg_Contrast = (uint8_t)pos;
226 		paletteDragMoved();
227 	}
228 }
229 
configPalRDown(void)230 void configPalRDown(void)
231 {
232 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
233 		showColorErrorMsg();
234 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
235 		showMouseColorErrorMsg();
236 	else
237 		scrollBarScrollLeft(SB_PAL_R, 1);
238 }
239 
configPalRUp(void)240 void configPalRUp(void)
241 {
242 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
243 		showColorErrorMsg();
244 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
245 		showMouseColorErrorMsg();
246 	else
247 		scrollBarScrollRight(SB_PAL_R, 1);
248 }
249 
configPalGDown(void)250 void configPalGDown(void)
251 {
252 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
253 		showColorErrorMsg();
254 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
255 		showMouseColorErrorMsg();
256 	else
257 		scrollBarScrollLeft(SB_PAL_G, 1);
258 }
259 
configPalGUp(void)260 void configPalGUp(void)
261 {
262 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
263 		showColorErrorMsg();
264 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
265 		showMouseColorErrorMsg();
266 	else
267 		scrollBarScrollRight(SB_PAL_G, 1);
268 }
269 
configPalBDown(void)270 void configPalBDown(void)
271 {
272 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
273 		showColorErrorMsg();
274 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
275 		showMouseColorErrorMsg();
276 	else
277 		scrollBarScrollLeft(SB_PAL_B, 1);
278 }
279 
configPalBUp(void)280 void configPalBUp(void)
281 {
282 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
283 		showColorErrorMsg();
284 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
285 		showMouseColorErrorMsg();
286 	else
287 		scrollBarScrollRight(SB_PAL_B, 1);
288 }
289 
configPalContDown(void)290 void configPalContDown(void)
291 {
292 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
293 		showColorErrorMsg();
294 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
295 		showMouseColorErrorMsg();
296 	else
297 		scrollBarScrollLeft(SB_PAL_CONTRAST, 1);
298 }
299 
configPalContUp(void)300 void configPalContUp(void)
301 {
302 	if (config.cfg_StdPalNum != PAL_USER_DEFINED)
303 		showColorErrorMsg();
304 	else if ((config.specialFlags2 & HARDWARE_MOUSE) && cfg_ColorNum == 3)
305 		showMouseColorErrorMsg();
306 	else
307 		scrollBarScrollRight(SB_PAL_CONTRAST, 1);
308 }
309 
showPaletteEditor(void)310 void showPaletteEditor(void)
311 {
312 	charOutShadow(503, 17, PAL_FORGRND, PAL_DSKTOP2, 'R');
313 	charOutShadow(503, 31, PAL_FORGRND, PAL_DSKTOP2, 'G');
314 	charOutShadow(503, 45, PAL_FORGRND, PAL_DSKTOP2, 'B');
315 
316 	showScrollBar(SB_PAL_R);
317 	showScrollBar(SB_PAL_G);
318 	showScrollBar(SB_PAL_B);
319 	showPushButton(PB_CONFIG_PAL_R_DOWN);
320 	showPushButton(PB_CONFIG_PAL_R_UP);
321 	showPushButton(PB_CONFIG_PAL_G_DOWN);
322 	showPushButton(PB_CONFIG_PAL_G_UP);
323 	showPushButton(PB_CONFIG_PAL_B_DOWN);
324 	showPushButton(PB_CONFIG_PAL_B_UP);
325 
326 	showRadioButtonGroup(RB_GROUP_CONFIG_PAL_ENTRIES);
327 
328 	textOutShadow(516, 59, PAL_FORGRND, PAL_DSKTOP2, "Contrast:");
329 	showScrollBar(SB_PAL_CONTRAST);
330 	showPushButton(PB_CONFIG_PAL_CONT_DOWN);
331 	showPushButton(PB_CONFIG_PAL_CONT_UP);
332 
333 	updatePaletteEditor();
334 }
335 
rbConfigPalPatternText(void)336 void rbConfigPalPatternText(void)
337 {
338 	cfg_ColorNum = 0;
339 	checkRadioButton(RB_CONFIG_PAL_PATTERNTEXT);
340 	updatePaletteEditor();
341 }
342 
rbConfigPalBlockMark(void)343 void rbConfigPalBlockMark(void)
344 {
345 	cfg_ColorNum = 1;
346 	checkRadioButton(RB_CONFIG_PAL_BLOCKMARK);
347 	updatePaletteEditor();
348 }
349 
rbConfigPalTextOnBlock(void)350 void rbConfigPalTextOnBlock(void)
351 {
352 	cfg_ColorNum = 2;
353 	checkRadioButton(RB_CONFIG_PAL_TEXTONBLOCK);
354 	updatePaletteEditor();
355 }
356 
rbConfigPalMouse(void)357 void rbConfigPalMouse(void)
358 {
359 	cfg_ColorNum = 3;
360 	checkRadioButton(RB_CONFIG_PAL_MOUSE);
361 	updatePaletteEditor();
362 }
363 
rbConfigPalDesktop(void)364 void rbConfigPalDesktop(void)
365 {
366 	cfg_ColorNum = 4;
367 	checkRadioButton(RB_CONFIG_PAL_DESKTOP);
368 	updatePaletteEditor();
369 }
370 
rbConfigPalButttons(void)371 void rbConfigPalButttons(void)
372 {
373 	cfg_ColorNum = 5;
374 	checkRadioButton(RB_CONFIG_PAL_BUTTONS);
375 	updatePaletteEditor();
376 }
377 
rbConfigPalArctic(void)378 void rbConfigPalArctic(void)
379 {
380 	config.cfg_StdPalNum = PAL_ARCTIC;
381 	updatePaletteEditor();
382 	setPal16(palTable[config.cfg_StdPalNum], true);
383 	checkRadioButton(RB_CONFIG_PAL_ARCTIC);
384 }
385 
rbConfigPalLitheDark(void)386 void rbConfigPalLitheDark(void)
387 {
388 	config.cfg_StdPalNum = PAL_LITHE_DARK;
389 	updatePaletteEditor();
390 	setPal16(palTable[config.cfg_StdPalNum], true);
391 	checkRadioButton(RB_CONFIG_PAL_LITHE_DARK);
392 }
393 
rbConfigPalAuroraBorealis(void)394 void rbConfigPalAuroraBorealis(void)
395 {
396 	config.cfg_StdPalNum = PAL_AURORA_BOREALIS;
397 	updatePaletteEditor();
398 	setPal16(palTable[config.cfg_StdPalNum], true);
399 	checkRadioButton(RB_CONFIG_PAL_AURORA_BOREALIS);
400 }
401 
rbConfigPalRose(void)402 void rbConfigPalRose(void)
403 {
404 	config.cfg_StdPalNum = PAL_ROSE;
405 	updatePaletteEditor();
406 	setPal16(palTable[config.cfg_StdPalNum], true);
407 	checkRadioButton(RB_CONFIG_PAL_ROSE);
408 }
409 
rbConfigPalBlues(void)410 void rbConfigPalBlues(void)
411 {
412 	config.cfg_StdPalNum = PAL_BLUES;
413 	updatePaletteEditor();
414 	setPal16(palTable[config.cfg_StdPalNum], true);
415 	checkRadioButton(RB_CONFIG_PAL_BLUES);
416 }
417 
rbConfigPalDarkMode(void)418 void rbConfigPalDarkMode(void)
419 {
420 	config.cfg_StdPalNum = PAL_DARK_MODE;
421 	updatePaletteEditor();
422 	setPal16(palTable[config.cfg_StdPalNum], true);
423 	checkRadioButton(RB_CONFIG_PAL_DARK_MODE);
424 }
425 
rbConfigPalGold(void)426 void rbConfigPalGold(void)
427 {
428 	config.cfg_StdPalNum = PAL_GOLD;
429 	updatePaletteEditor();
430 	setPal16(palTable[config.cfg_StdPalNum], true);
431 	checkRadioButton(RB_CONFIG_PAL_GOLD);
432 }
433 
rbConfigPalViolent(void)434 void rbConfigPalViolent(void)
435 {
436 	config.cfg_StdPalNum = PAL_VIOLENT;
437 	updatePaletteEditor();
438 	setPal16(palTable[config.cfg_StdPalNum], true);
439 	checkRadioButton(RB_CONFIG_PAL_VIOLENT);
440 }
441 
rbConfigPalHeavyMetal(void)442 void rbConfigPalHeavyMetal(void)
443 {
444 	config.cfg_StdPalNum = PAL_HEAVY_METAL;
445 	updatePaletteEditor();
446 	setPal16(palTable[config.cfg_StdPalNum], true);
447 	checkRadioButton(RB_CONFIG_PAL_HEAVY_METAL);
448 }
449 
rbConfigPalWhyColors(void)450 void rbConfigPalWhyColors(void)
451 {
452 	config.cfg_StdPalNum = PAL_WHY_COLORS;
453 	updatePaletteEditor();
454 	setPal16(palTable[config.cfg_StdPalNum], true);
455 	checkRadioButton(RB_CONFIG_PAL_WHY_COLORS);
456 }
457 
rbConfigPalJungle(void)458 void rbConfigPalJungle(void)
459 {
460 	config.cfg_StdPalNum = PAL_JUNGLE;
461 	updatePaletteEditor();
462 	setPal16(palTable[config.cfg_StdPalNum], true);
463 	checkRadioButton(RB_CONFIG_PAL_JUNGLE);
464 }
465 
rbConfigPalUserDefined(void)466 void rbConfigPalUserDefined(void)
467 {
468 	config.cfg_StdPalNum = PAL_USER_DEFINED;
469 	updatePaletteEditor();
470 	setPal16(palTable[config.cfg_StdPalNum], true);
471 	checkRadioButton(RB_CONFIG_PAL_USER_DEFINED);
472 }
473