ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

ft2_help.c (9938B)


      1 // for finding memory leaks in debug mode with Visual Studio
      2 #if defined _DEBUG && defined _MSC_VER
      3 #include <crtdbg.h>
      4 #endif
      5 
      6 #include <stdint.h>
      7 #include <stdio.h>
      8 #include "ft2_header.h"
      9 #include "ft2_gui.h"
     10 #include "ft2_help.h"
     11 #include "ft2_video.h"
     12 #include "ft2_pattern_ed.h"
     13 #include "ft2_bmp.h"
     14 #include "ft2_structs.h"
     15 #include "helpdata/ft2_help_data.h"
     16 
     17 typedef struct
     18 {
     19 	bool bigFont, noLine;
     20 	uint8_t color;
     21 	int16_t xPos;
     22 	char text[100];
     23 } helpRec;
     24 
     25 #define HELP_LINES 15
     26 #define MAX_HELP_LINES 768
     27 #define HELP_SIZE sizeof (helpRec)
     28 #define MAX_SUBJ 10
     29 #define HELP_COLUMN 135
     30 #define HELP_WIDTH (596 - HELP_COLUMN)
     31 
     32 static uint8_t fHlp_Num;
     33 static int16_t textLine, fHlp_Line, subjLen[MAX_SUBJ];
     34 static int32_t helpBufferPos;
     35 static helpRec *subjPtrArr[MAX_SUBJ];
     36 
     37 static void addText(helpRec *t, int16_t xPos, uint8_t color, char *text)
     38 {
     39 	if (*text == '\0')
     40 		return;
     41 
     42 	t->xPos = xPos;
     43 	t->color = color;
     44 	t->bigFont = false;
     45 	t->noLine = false;
     46 	strcpy(t->text, text);
     47 	*text = '\0'; // empty old string
     48 
     49 	textLine++;
     50 }
     51 
     52 static bool getLine(char *output)
     53 {
     54 	if (helpBufferPos >= (int32_t)sizeof (helpData))
     55 	{
     56 		*output = '\0';
     57 		return false;
     58 	}
     59 
     60 	const uint8_t strLen = helpData[helpBufferPos++];
     61 	memcpy(output, &helpData[helpBufferPos], strLen);
     62 	output[strLen] = '\0';
     63 
     64 	helpBufferPos += strLen;
     65 
     66 	return true;
     67 }
     68 
     69 static int16_t controlCodeToNum(const char *controlCode)
     70 {
     71 	return (((controlCode[0]-'0')%10)*100) + (((controlCode[1]-'0')%10)*10) + ((controlCode[2]-'0')%10);
     72 }
     73 
     74 static char *ltrim(char *s)
     75 {
     76 	if (*s == '\0')
     77 		return (s);
     78 
     79 	while (*s == ' ') s++;
     80 
     81 	return s;
     82 }
     83 
     84 static char *rtrim(char *s)
     85 {
     86 	if (*s == '\0')
     87 		return (s);
     88 
     89 	int32_t i = (int32_t)strlen(s) - 1;
     90 	while (i >= 0)
     91 	{
     92 		if (s[i] != ' ')
     93 		{
     94 			s[i+1] = '\0';
     95 			break;
     96 		}
     97 
     98 		i--;
     99 	}
    100 
    101 	return s;
    102 }
    103 
    104 static void readHelp(void) // this is a bit messy...
    105 {
    106 	char text[256], text2[256], *s, *sEnd, *s3;
    107 	int16_t a, b, i, k;
    108 
    109 	helpRec *tempText = (helpRec *)malloc(HELP_SIZE * MAX_HELP_LINES);
    110 	if (tempText == NULL)
    111 	{
    112 		okBox(0, "System message", "Not enough memory!", NULL);
    113 		return;
    114 	}
    115 	
    116 	text[0] = '\0';
    117 	text2[0] = '\0';
    118 
    119 	char *s2 = text2;
    120 
    121 	helpBufferPos = 0;
    122 	for (int16_t subj = 0; subj < MAX_SUBJ; subj++)
    123 	{
    124 		textLine = 0;
    125 		int16_t currColumn = 0;
    126 		uint8_t currColor = PAL_FORGRND;
    127 
    128 		getLine(text); s = text;
    129 		while (strncmp(s, "END", 3) != 0)
    130 		{
    131 			if (*s == ';')
    132 			{
    133 				if (!getLine(text))
    134 					break;
    135 
    136 				s = text;
    137 				continue;
    138 			}
    139 
    140 			if (*(uint16_t *)s == 0x4C40) // @L - "big font"
    141 			{
    142 				addText(&tempText[textLine], currColumn, currColor, s2);
    143 				s += 2;
    144 
    145 				if (*(uint16_t *)s == 0x5840) // @X - "change X position"
    146 				{
    147 					currColumn = controlCodeToNum(&s[2]);
    148 					s += 5;
    149 				}
    150 
    151 				if (*(uint16_t *)s == 0x4340) // @C - "change color
    152 				{
    153 					currColor = (uint8_t)controlCodeToNum(&s[2]);
    154 					currColor = (currColor < 2) ? PAL_FORGRND : PAL_BUTTONS;
    155 					s += 5;
    156 				}
    157 
    158 				helpRec *t = &tempText[textLine];
    159 				t->xPos = currColumn;
    160 				t->color = currColor;
    161 				t->bigFont = true;
    162 				t->noLine = false;
    163 				strcpy(t->text, s);
    164 				textLine++;
    165 
    166 				t = &tempText[textLine];
    167 				t->noLine = true;
    168 				textLine++;
    169 			}
    170 			else
    171 			{
    172 				if (*s == '>')
    173 				{
    174 					addText(&tempText[textLine], currColumn, currColor, s2);
    175 					s++;
    176 				}
    177 
    178 				if (*(uint16_t *)s == 0x5840) // @X - "set X position (relative to help X start)"
    179 				{
    180 					currColumn = controlCodeToNum(&s[2]);
    181 					s += 5;
    182 				}
    183 
    184 				if (*(uint16_t *)s == 0x4340) // @C - "change color"
    185 				{
    186 					currColor = (uint8_t)controlCodeToNum(&s[2]);
    187 					currColor = (currColor < 2) ? PAL_FORGRND : PAL_BUTTONS;
    188 					s += 5;
    189 				}
    190 
    191 				s = ltrim(rtrim(s));
    192 				if (*s == '\0')
    193 				{
    194 					addText(&tempText[textLine], currColumn, currColor, s2);
    195 					strcpy(s2, " ");
    196 					addText(&tempText[textLine], currColumn, currColor, s2);
    197 				}
    198 
    199 				int16_t sLen = (int16_t)strlen(s);
    200 
    201 				sEnd = &s[sLen];
    202 				while (s < sEnd)
    203 				{
    204 					if (sLen < 0)
    205 						sLen = 0;
    206 
    207 					i = 0;
    208 					while (s[i] != ' ' && i < sLen) i++;
    209 					i++;
    210 
    211 					if (*(uint16_t *)s == 0x5440) // @T - "set absolute X position (in the middle of text)"
    212 					{
    213 						k = controlCodeToNum(&s[2]);
    214 						s += 5; sLen -= 5;
    215 
    216 						s3 = &s2[strlen(s2)];
    217 						while (textWidth(s2) + charWidth(' ') + 1 < k-currColumn)
    218 						{
    219 							s3[0] = ' ';
    220 							s3[1] = '\0';
    221 							s3++;
    222 						}
    223 
    224 						b = textWidth(s2) + 1;
    225 						if (b < k-currColumn)
    226 						{
    227 							s3 = &s2[strlen(s2)];
    228 							for (a = 0; a < k-b-currColumn; a++)
    229 								s3[a] = 127; // one-pixel spacer glyph
    230 							s3[a] = '\0';
    231 						}
    232 					}
    233 
    234 					if (textWidth(s2)+textNWidth(s,i)+2 > HELP_WIDTH-currColumn)
    235 						addText(&tempText[textLine], currColumn, currColor, s2);
    236 
    237 					strncat(s2, s, i);
    238 
    239 					s += i; sLen -= i;
    240 					if ((*s == '\0') || (s >= sEnd))
    241 						strcat(s2, " ");
    242 				}
    243 			}
    244 
    245 			if (textLine >= MAX_HELP_LINES || !getLine(text))
    246 				break;
    247 
    248 			s = text;
    249 		}
    250 
    251 		subjPtrArr[subj] = (helpRec *)malloc(HELP_SIZE * textLine);
    252 		if (subjPtrArr[subj] == NULL)
    253 		{
    254 			okBox(0, "System message", "Not enough memory!", NULL);
    255 			break;
    256 		}
    257 
    258 		memcpy(subjPtrArr[subj], tempText, HELP_SIZE * textLine);
    259 		subjLen[subj] = textLine;
    260 	}
    261 
    262 	free(tempText);
    263 }
    264 
    265 static void bigTextOutHalf(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, bool lowerHalf, const char *textPtr)
    266 {
    267 	assert(textPtr != NULL);
    268 
    269 	uint16_t currX = xPos;
    270 	while (true)
    271 	{
    272 		const char chr = *textPtr++ & 0x7F;
    273 		if (chr == '\0')
    274 			break;
    275 
    276 		if (chr != ' ')
    277 		{
    278 			const uint8_t *srcPtr = &bmp.font2[chr * FONT2_CHAR_W];
    279 			if (!lowerHalf)
    280 				srcPtr += (FONT2_CHAR_H / 2) * FONT2_WIDTH;
    281 
    282 			uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + currX];
    283 			const uint32_t pixVal = video.palette[paletteIndex];
    284 
    285 			for (uint32_t y = 0; y < FONT2_CHAR_H/2; y++)
    286 			{
    287 				for (uint32_t x = 0; x < FONT2_CHAR_W; x++)
    288 				{
    289 					if (srcPtr[x])
    290 						dstPtr[x] = pixVal;
    291 				}
    292 
    293 				srcPtr += FONT2_WIDTH;
    294 				dstPtr += SCREEN_W;
    295 			}
    296 		}
    297 
    298 		currX += charWidth16(chr);
    299 	}
    300 }
    301 
    302 static void writeHelp(void)
    303 {
    304 	helpRec *ptr = subjPtrArr[fHlp_Num];
    305 	if (ptr == NULL)
    306 		return;
    307 
    308 	for (int16_t i = 0; i < HELP_LINES; i++)
    309 	{
    310 		const int16_t k = i + fHlp_Line;
    311 		if (k >= subjLen[fHlp_Num])
    312 			break;
    313 
    314 		clearRect(HELP_COLUMN, 5 + (i * 11), HELP_WIDTH, 11);
    315 
    316 		if (ptr[k].noLine)
    317 		{
    318 			if (i == 0)
    319 				bigTextOutHalf(HELP_COLUMN + ptr[k-1].xPos, 5 + (i * 11), PAL_FORGRND, false, ptr[k-1].text);
    320 		}
    321 		else
    322 		{
    323 			if (ptr[k].bigFont)
    324 			{
    325 				if (i == HELP_LINES-1)
    326 				{
    327 					bigTextOutHalf(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), PAL_FORGRND, true, ptr[k].text);
    328 					return;
    329 				}
    330 				else
    331 				{
    332 					clearRect(HELP_COLUMN, 5 + ((i + 1) * 11), HELP_WIDTH, 11);
    333 					bigTextOut(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), PAL_FORGRND, ptr[k].text);
    334 					i++;
    335 				}
    336 			}
    337 			else
    338 			{
    339 				textOut(HELP_COLUMN + ptr[k].xPos, 5 + (i * 11), ptr[k].color, ptr[k].text);
    340 			}
    341 		}
    342 	}
    343 }
    344 
    345 void helpScrollUp(void)
    346 {
    347 	if (fHlp_Line > 0)
    348 	{
    349 		scrollBarScrollUp(SB_HELP_SCROLL, 1);
    350 		writeHelp();
    351 	}
    352 }
    353 
    354 void helpScrollDown(void)
    355 {
    356 	if (fHlp_Line < subjLen[fHlp_Num]-1)
    357 	{
    358 		scrollBarScrollDown(SB_HELP_SCROLL, 1);
    359 		writeHelp();
    360 	}
    361 }
    362 
    363 void helpScrollSetPos(uint32_t pos)
    364 {
    365 	if (fHlp_Line != (int16_t)pos)
    366 	{
    367 		fHlp_Line = (int16_t)pos;
    368 		writeHelp();
    369 	}
    370 }
    371 
    372 void showHelpScreen(void)
    373 {
    374 	uint16_t tmpID;
    375 
    376 	if (ui.extendedPatternEditor)
    377 		exitPatternEditorExtended();
    378 
    379 	hideTopScreen();
    380 	ui.helpScreenShown = true;
    381 
    382 	drawFramework(0,   0, 128, 173, FRAMEWORK_TYPE1);
    383 	drawFramework(128, 0, 504, 173, FRAMEWORK_TYPE1);
    384 	drawFramework(130, 2, 479, 169, FRAMEWORK_TYPE2);
    385 
    386 	showPushButton(PB_HELP_EXIT);
    387 	showPushButton(PB_HELP_SCROLL_UP);
    388 	showPushButton(PB_HELP_SCROLL_DOWN);
    389 
    390 	uncheckRadioButtonGroup(RB_GROUP_HELP);
    391 	switch (fHlp_Num)
    392 	{
    393 		default:
    394 		case 0: tmpID = RB_HELP_FEATURES;       break;
    395 		case 1: tmpID = RB_HELP_EFFECTS;        break;
    396 		case 2: tmpID = RB_HELP_KEYBINDINGS;    break;
    397 		case 3: tmpID = RB_HELP_HOW_TO_USE_FT2; break;
    398 		case 4: tmpID = RB_HELP_FAQ;            break;
    399 		case 5: tmpID = RB_HELP_KNOWN_BUGS;     break;
    400 	}
    401 	radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
    402 
    403 	showRadioButtonGroup(RB_GROUP_HELP);
    404 
    405 	showScrollBar(SB_HELP_SCROLL);
    406 
    407 	textOutShadow(4,   4, PAL_FORGRND, PAL_DSKTOP2, "Subjects:");
    408 	textOutShadow(21, 19, PAL_FORGRND, PAL_DSKTOP2, "Features");
    409 	textOutShadow(21, 35, PAL_FORGRND, PAL_DSKTOP2, "Effects");
    410 	textOutShadow(21, 51, PAL_FORGRND, PAL_DSKTOP2, "Keybindings");
    411 	textOutShadow(21, 67, PAL_FORGRND, PAL_DSKTOP2, "How to use FT2");
    412 	textOutShadow(21, 83, PAL_FORGRND, PAL_DSKTOP2, "Problems/FAQ");
    413 	textOutShadow(21, 99, PAL_FORGRND, PAL_DSKTOP2, "Known bugs");
    414 
    415 	writeHelp();
    416 }
    417 
    418 void hideHelpScreen(void)
    419 {
    420 	hidePushButton(PB_HELP_EXIT);
    421 	hidePushButton(PB_HELP_SCROLL_UP);
    422 	hidePushButton(PB_HELP_SCROLL_DOWN);
    423 
    424 	hideRadioButtonGroup(RB_GROUP_HELP);
    425 	hideScrollBar(SB_HELP_SCROLL);
    426 
    427 	ui.helpScreenShown = false;
    428 }
    429 
    430 void exitHelpScreen(void)
    431 {
    432 	hideHelpScreen();
    433 	showTopScreen(true);
    434 }
    435 
    436 static void setHelpSubject(uint8_t Nr)
    437 {
    438 	fHlp_Num = Nr;
    439 	fHlp_Line = 0;
    440 
    441 	setScrollBarEnd(SB_HELP_SCROLL, subjLen[fHlp_Num]);
    442 	setScrollBarPos(SB_HELP_SCROLL, 0, false);
    443 }
    444 
    445 void rbHelpFeatures(void)
    446 {
    447 	checkRadioButton(RB_HELP_FEATURES);
    448 	setHelpSubject(0);
    449 	writeHelp();
    450 }
    451 
    452 void rbHelpEffects(void)
    453 {
    454 	checkRadioButton(RB_HELP_EFFECTS);
    455 	setHelpSubject(1);
    456 	writeHelp();
    457 }
    458 
    459 void rbHelpKeybindings(void)
    460 {
    461 	checkRadioButton(RB_HELP_KEYBINDINGS);
    462 	setHelpSubject(2);
    463 	writeHelp();
    464 }
    465 
    466 void rbHelpHowToUseFT2(void)
    467 {
    468 	checkRadioButton(RB_HELP_HOW_TO_USE_FT2);
    469 	setHelpSubject(3);
    470 	writeHelp();
    471 }
    472 
    473 void rbHelpFAQ(void)
    474 {
    475 	checkRadioButton(RB_HELP_FAQ);
    476 	setHelpSubject(4);
    477 	writeHelp();
    478 }
    479 
    480 void rbHelpKnownBugs(void)
    481 {
    482 	checkRadioButton(RB_HELP_KNOWN_BUGS);
    483 	setHelpSubject(5);
    484 	writeHelp();
    485 }
    486 
    487 void initFTHelp(void)
    488 {
    489 	readHelp();
    490 	setHelpSubject(0);
    491 }
    492 
    493 void windUpFTHelp(void)
    494 {
    495 	for (int16_t i = 0; i < MAX_SUBJ; i++)
    496 	{
    497 		if (subjPtrArr[i] != NULL)
    498 		{
    499 			free(subjPtrArr[i]);
    500 			subjPtrArr[i] = NULL;
    501 		}
    502 	}
    503 }