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 <stdbool.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <ctype.h> 11 #include "gui.h" 12 #include "palette.h" 13 #include "unicode.h" 14 #include "tinyfiledialogs/tinyfiledialogs.h" 15 16 #ifndef _WIN32 17 #define _stricmp strcasecmp 18 #define _strnicmp strncasecmp 19 #endif 20 21 #define SWAP16(value) \ 22 ( \ 23 (((uint16_t)((value) & 0x00FF)) << 8) | \ 24 (((uint16_t)((value) & 0xFF00)) >> 8) \ 25 ) 26 27 UNICHAR *loadedFile = NULL; 28 bool configIsSaved = true; 29 30 static uint8_t hex2int(char ch) 31 { 32 ch = (char)toupper(ch); 33 34 if (ch >= 'A' && ch <= 'F') return 10 + (ch - 'A'); 35 else if (ch >= '0' && ch <= '9') return ch - '0'; 36 37 return 0; // not a hex 38 } 39 40 static bool _loadPaletteFromColorsIni(FILE *f) 41 { 42 char *configBuffer, *configLine; 43 uint16_t color; 44 uint32_t line, fileSize, lineLen; 45 46 // get filesize 47 fseek(f, 0, SEEK_END); 48 fileSize = ftell(f); 49 rewind(f); 50 51 configBuffer = (char *)malloc(fileSize + 1); 52 if (configBuffer == NULL) 53 { 54 fclose(f); 55 showErrorMsgBox("Couldn't parse colors.ini: Out of memory!"); 56 return false; 57 } 58 59 fread(configBuffer, 1, fileSize, f); 60 configBuffer[fileSize] = '\0'; 61 fclose(f); 62 63 // do parsing 64 configLine = strtok(configBuffer, "\n"); 65 while (configLine != NULL) 66 { 67 lineLen = (uint32_t)strlen(configLine); 68 69 // read palette 70 if (lineLen >= sizeof ("[Palette]")-1) 71 { 72 if (!_strnicmp("[Palette]", configLine, sizeof ("[Palette]")-1)) 73 { 74 configLine = strtok(NULL, "\n"); 75 76 line = 0; 77 while (configLine != NULL && line < 8) 78 { 79 color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]); 80 palette[line] = color & 0xFFF; 81 82 configLine = strtok(NULL, "\n"); 83 line++; 84 } 85 } 86 87 if (configLine == NULL) 88 break; 89 90 lineLen = (uint32_t)strlen(configLine); 91 } 92 93 // read VU-meter colors 94 if (lineLen >= sizeof ("[VU-meter]")-1) 95 { 96 if (!_strnicmp("[VU-meter]", configLine, sizeof ("[VU-meter]")-1)) 97 { 98 configLine = strtok(NULL, "\n"); 99 100 line = 0; 101 while (configLine != NULL && line < 48) 102 { 103 color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]); 104 vuColors[line] = color & 0xFFF; 105 106 configLine = strtok(NULL, "\n"); 107 line++; 108 } 109 } 110 111 if (configLine == NULL) 112 break; 113 114 lineLen = (uint32_t)strlen(configLine); 115 } 116 117 // read spectrum analyzer colors 118 if (lineLen >= sizeof ("[SpectrumAnalyzer]")-1) 119 { 120 if (!_strnicmp("[SpectrumAnalyzer]", configLine, sizeof ("[SpectrumAnalyzer]")-1)) 121 { 122 configLine = strtok(NULL, "\n"); 123 124 line = 0; 125 while (configLine != NULL && line < 36) 126 { 127 color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]); 128 analyzerColors[line] = color & 0xFFF; 129 130 configLine = strtok(NULL, "\n"); 131 line++; 132 } 133 } 134 135 if (configLine == NULL) 136 break; 137 } 138 139 configLine = strtok(NULL, "\n"); 140 } 141 142 free(configBuffer); 143 return true; 144 } 145 146 static void _loadPaletteFromPtConfig(FILE *f) 147 { 148 uint16_t tmp16; 149 int32_t i; 150 151 // read palette 152 fseek(f, 154, SEEK_SET); 153 for (i = 0; i < 8; i++) 154 { 155 fread(&tmp16, 2, 1, f); // stored as Big-Endian 156 tmp16 = SWAP16(tmp16); 157 158 palette[i] = tmp16 & 0xFFF; 159 } 160 161 // read vu colors 162 fseek(f, 546, SEEK_SET); 163 for (i = 0; i < 48; i++) 164 { 165 fread(&tmp16, 2, 1, f); // stored as Big-Endian 166 tmp16 = SWAP16(tmp16); 167 168 vuColors[i] = tmp16 & 0xFFF; 169 } 170 171 // read spectrum analyzer colors 172 fseek(f, 642, SEEK_SET); 173 for (i = 0; i < 36; i++) 174 { 175 fread(&tmp16, 2, 1, f); // stored as Big-Endian 176 tmp16 = SWAP16(tmp16); 177 178 analyzerColors[i] = tmp16 & 0xFFF; 179 } 180 } 181 182 static bool loadPaletteFromConfig(const UNICHAR *file, uint8_t ptDotConfig) 183 { 184 char cfgString[26]; 185 uint32_t filesize; 186 FILE *f; 187 188 f = UNICHAR_FOPEN(file, "rb"); 189 if (f == NULL) 190 { 191 showErrorMsgBox("Couldn't open file for reading!"); 192 return false; 193 } 194 195 fseek(f, 0, SEEK_END); 196 filesize = ftell(f); 197 rewind(f); 198 199 if (ptDotConfig) 200 { 201 if (filesize != 1024) 202 { 203 fclose(f); 204 showErrorMsgBox("This is not valid a PT.Config file!"); 205 return false; 206 } 207 208 // check if file is a PT.Config file 209 fread(cfgString, 1, 25, f); 210 rewind(f); 211 cfgString[25] = '\0'; // add null terminator 212 213 cfgString[2] = '1'; // force version to 1.0 so that we can compare string easily 214 cfgString[4] = '0'; 215 216 if (!strcmp(cfgString, "PT1.0 Configuration File\012")) 217 { 218 _loadPaletteFromPtConfig(f); 219 } 220 else 221 { 222 fclose(f); 223 showErrorMsgBox("This is not a valid PT.Config file!"); 224 return false; 225 } 226 } 227 else 228 { 229 _loadPaletteFromColorsIni(f); 230 } 231 232 fclose(f); 233 234 if (!ptDotConfig) 235 { 236 if (loadedFile != NULL) 237 free(loadedFile); 238 239 loadedFile = UNICHAR_STRDUP(file); 240 } 241 242 fillCancel1Colors(); 243 fillCancel2Colors(); 244 updateBMPs(); 245 drawTracker(); 246 drawColorPicker1(); 247 drawColorPicker2(); 248 redrawScreen = true; 249 250 configIsSaved = false; 251 return true; 252 } 253 254 void loadColorsDotIni(void) 255 { 256 #ifdef _WIN32 257 const UNICHAR *aFilterPatterns[] = { L"colors.ini" }; 258 #else 259 const UNICHAR *aFilterPatterns[] = { "colors.ini" }; 260 #endif 261 const UNICHAR *file; 262 263 #ifdef _WIN32 264 file = tinyfd_openFileDialogW(L"Please select a colors.ini to load...", L"colors.ini", 1, 265 aFilterPatterns, NULL, 0); 266 #else 267 #ifdef __APPLE__ 268 file = tinyfd_openFileDialog("Please select a colors.ini to load...", "colors.ini", 0, 269 NULL, NULL, 0); 270 #else 271 file = tinyfd_openFileDialog("Please select a colors.ini to load...", "colors.ini", 1, 272 aFilterPatterns, NULL, 0); 273 #endif 274 #endif 275 276 if (file != NULL) 277 loadPaletteFromConfig(file, 0); 278 } 279 280 void loadPTDotConfig(void) 281 { 282 const UNICHAR *file; 283 284 #ifdef _WIN32 285 file = tinyfd_openFileDialogW(L"Please select a PT.Config file to load...", NULL, 0, NULL, NULL, 0); 286 #else 287 file = tinyfd_openFileDialog("Please select a PT.Config file to load...", NULL, 0, NULL, NULL, 0); 288 #endif 289 290 if (file != NULL) 291 loadPaletteFromConfig(file, 1); 292 } 293 294 bool savePalette(bool showNotes) 295 { 296 int32_t i; 297 FILE *f; 298 UNICHAR *folder; 299 300 if (loadedFile == NULL) 301 { 302 loadedFile = (UNICHAR *)calloc(4096+2, sizeof (UNICHAR)); 303 if (loadedFile == NULL) 304 { 305 configIsSaved = 0; 306 showErrorMsgBox("Out of memory!"); 307 return false; 308 } 309 } 310 311 if (loadedFile[0] == '\0' && loadedFile[1] == '\0') 312 { 313 #ifdef _WIN32 314 folder = (UNICHAR *)tinyfd_selectFolderDialogW(L"Please select ProTracker clone folder...", NULL); 315 if (folder == NULL || UNICHAR_STRLEN(folder) < 1) 316 return false; 317 318 UNICHAR_STRCPY(loadedFile, folder); 319 UNICHAR_STRCAT(loadedFile, L"\\"); 320 UNICHAR_STRCAT(loadedFile, L"colors.ini"); 321 #else 322 folder = (UNICHAR *)tinyfd_selectFolderDialog("Please select ProTracker clone folder...", NULL); 323 if (folder == NULL || UNICHAR_STRLEN(folder) < 1) 324 return false; 325 326 UNICHAR_STRCPY(loadedFile, folder); 327 UNICHAR_STRCAT(loadedFile, "/"); 328 UNICHAR_STRCAT(loadedFile, "colors.ini"); 329 #endif 330 } 331 332 f = UNICHAR_FOPEN(loadedFile, "w"); 333 if (f == NULL) 334 { 335 showErrorMsgBox("Sorry, couldn't write to config.ini! Is the file in use?\n"); 336 return false; 337 } 338 339 fprintf(f, "; WARNING: DO NOT TOUCH ANYTHING EXCEPT THE HEX VALUES!\n"); 340 fprintf(f, "; I recommend that you use the palette editor tool instead.\n"); 341 fprintf(f, "; You can find it at www.16-bits.org/pt.php\n"); 342 fprintf(f, ";\n"); 343 fprintf(f, "; Info:\n"); 344 fprintf(f, "; - Colors are stored as 12-bit RGB in hex (4096 total colors).\n"); 345 fprintf(f, "; The palette order is the same as ProTracker on Amiga.\n"); 346 fprintf(f, ";\n"); 347 fprintf(f, "; To convert a 24-bit RGB hex value to 12-bit RGB hex, just\n"); 348 fprintf(f, "; skip every other digit. F.ex. 89ABCD -> 8AC\n"); 349 fprintf(f, ";\n"); 350 fprintf(f, "; To convert the other way around, repeat the digits.\n"); 351 fprintf(f, "; F.ex. 8AC -> 88AACC\n"); 352 fprintf(f, "\n"); 353 fprintf(f, "[Palette]\n"); 354 fprintf(f, "%03X ; Background\n", palette[0]); 355 fprintf(f, "%03X ; GUI box light border / static text\n", palette[1]); 356 fprintf(f, "%03X ; GUI box background color\n", palette[2]); 357 fprintf(f, "%03X ; GUI box dark border / static text shadow\n", palette[3]); 358 fprintf(f, "%03X ; Quadrascope / disk op. text / pos. ed. text\n", palette[4]); 359 fprintf(f, "%03X ; Pattern cursor\n", palette[5]); 360 fprintf(f, "%03X ; GUI box (non-static) text\n", palette[6]); 361 fprintf(f, "%03X ; Pattern text\n", palette[7]); 362 fprintf(f, "\n"); 363 364 fprintf(f, "[VU-meter]\n"); 365 for (i = 0; i < 48; i++) 366 fprintf(f, "%03X\n", vuColors[i]); 367 fprintf(f, "\n"); 368 369 fprintf(f, "[SpectrumAnalyzer]\n"); 370 for (i = 0; i < 36; i++) 371 fprintf(f, "%03X\n", analyzerColors[i]); 372 373 fclose(f); 374 375 configIsSaved = true; 376 377 if (showNotes) 378 SDL_ShowSimpleMessageBox(0, "Note", "Colors were successfully saved to colors.ini!", NULL); 379 380 return true; 381 } 382