ref: d13d5a8ae53c840222223cfefa4b721e3e185e47
dir: /pt_pal_editor/src/main.c/
// for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> #endif #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <math.h> #include <sys/stat.h> #ifdef _WIN32 #define WIN32_MEAN_AND_LEAN #include <windows.h> #else #include <unistd.h> #endif #include <SDL2/SDL.h> #include "config.h" #include "palette.h" #include "gui.h" #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #ifdef _MSC_VER #pragma warning(disable: 4204) #pragma warning(disable: 4221) #endif static SDL_Window *window; static SDL_Renderer *renderer; static SDL_Texture *texture; // globals volatile bool programRunning, redrawScreen, allowSigterm = true; uint32_t *frameBuffer; keyb_t keyb; mouse_t mouse; static bool setupVideo(void); static void readMouseXY(void); static void handleInput(void); #ifdef __APPLE__ static void osxSetDirToProgramDirFromArgs(char **argv); #endif int main(int argc, char *argv[]) { // for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif (void)argc; (void)argv; #ifdef __APPLE__ osxSetDirToProgramDirFromArgs(argv); #endif if (!setupVideo()) { SDL_Quit(); return 0; } setupGUI(); redrawScreen = true; programRunning = true; while (programRunning) { readMouseXY(); handleInput(); if (redrawScreen) { redrawScreen = false; // redraw screen SDL_UpdateTexture(texture, NULL, frameBuffer, SCREEN_W * sizeof (int32_t)); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } SDL_Delay((1000 / 60) + 1); // ~60Hz } if (loadedFile != NULL) free(loadedFile); free(frameBuffer); SDL_Quit(); return 0; } static void readMouseXY(void) { int32_t windowX, windowY, mx, my; SDL_GetGlobalMouseState(&mx, &my); SDL_GetWindowPosition(window, &windowX, &windowY); mx -= windowX; my -= windowY; mouse.x = (int32_t)(mx * mouse.fMouseXMul); mouse.y = (int32_t)(my * mouse.fMouseYMul); } static void showAskToSaveDialog(void) { int32_t whichButtonPressed; const SDL_MessageBoxButtonData buttons[2] = { { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "No" }, { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Yes" }, }; const SDL_MessageBoxData messageBoxData = { SDL_MESSAGEBOX_WARNING, window, "Warning", "Colors are unsaved. Save before quitting?", SDL_arraysize(buttons), buttons, NULL }; if (SDL_ShowMessageBox(&messageBoxData, &whichButtonPressed) < 0) { allowSigterm = true; programRunning = false; return; } if (whichButtonPressed == 1) savePalette(0); programRunning = false; } void showErrorMsgBox(const char *fmt, ...) { char strBuf[1024]; va_list args; // format the text string va_start(args, fmt); vsnprintf(strBuf, sizeof (strBuf), fmt, args); va_end(args); // window can be NULL here, no problem... SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", strBuf, NULL); } static void handleInput(void) { SDL_Event inputEvent; while (SDL_PollEvent(&inputEvent)) { if (inputEvent.type == SDL_QUIT && allowSigterm) { if (!configIsSaved) { allowSigterm = false; showAskToSaveDialog(); } else { programRunning = false; } } else if (inputEvent.type == SDL_KEYDOWN) { keyDownHandler(inputEvent.key.keysym.sym); } else if (inputEvent.type == SDL_MOUSEBUTTONUP) { if (inputEvent.button.button == SDL_BUTTON_LEFT) mouseButtonUpHandler(); } else if (inputEvent.type == SDL_MOUSEBUTTONDOWN) { if (inputEvent.button.button == SDL_BUTTON_LEFT) mouseButtonDownHandler(); } } handleSlidersHeldDown(); handleRainbowHeldDown(); handleRainbowUpDownButtons(); } // macOS/OS X specific routines #ifdef __APPLE__ static void osxSetDirToProgramDirFromArgs(char **argv) { char *tmpPath; int32_t i, tmpPathLen; /* OS X/macOS: hackish way of setting the current working directory to the place where we double clicked ** on the icon (for protracker.ini loading) */ // if we launched from the terminal, argv[0][0] would be '.' if (argv[0] != NULL && argv[0][0] == '/') // don't do the hack if we launched from the terminal { tmpPath = strdup(argv[0]); if (tmpPath != NULL) { // cut off program filename tmpPathLen = strlen(tmpPath); for (i = tmpPathLen-1; i >= 0; i--) { if (tmpPath[i] == '/') { tmpPath[i] = '\0'; break; } } chdir(tmpPath); // path to binary chdir("../../../"); // we should now be in the directory where the config can be. free(tmpPath); } } } #endif static bool setupVideo(void) { int32_t renderW, renderH; /* SDL 2.0.9 for Windows has a serious bug where you need to initialize the joystick subsystem ** (even if you don't use it) or else weird things happen like random stutters, keyboard (rarely) being ** reinitialized in Windows and what not. ** Ref.: https://bugzilla.libsdl.org/show_bug.cgi?id=4391 */ #if defined _WIN32 && SDL_PATCHLEVEL == 9 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0) #else if (SDL_Init(SDL_INIT_VIDEO) != 0) #endif { showErrorMsgBox("Couldn't initialize SDL: %s", SDL_GetError()); return false; } window = SDL_CreateWindow("Palette editor for ProTracker 2 clone", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_W * 2, SCREEN_H * 2, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); if (window == NULL) { showErrorMsgBox("Couldn't create an SDL2 window: %s", SDL_GetError()); return false; } renderer = SDL_CreateRenderer(window, -1, 0); if (renderer == NULL) { showErrorMsgBox("Couldn't create an SDL2 renderer: %s", SDL_GetError()); return false; } SDL_RenderSetLogicalSize(renderer, SCREEN_W, SCREEN_H); #if SDL_PATCHLEVEL >= 5 SDL_RenderSetIntegerScale(renderer, SDL_TRUE); #endif SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); SDL_SetHint("SDL_RENDER_SCALE_QUALITY", "nearest"); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_W, SCREEN_H); if (texture == NULL) { showErrorMsgBox("Couldn't create an SDL2 texture: %s", SDL_GetError()); return false; } SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE); // frame buffer used by SDL (for texture) frameBuffer = (uint32_t *)malloc(SCREEN_W * SCREEN_H * sizeof (int32_t)); if (frameBuffer == NULL) { showErrorMsgBox("Out of memory!"); return false; } SDL_GetWindowSize(window, &renderW, &renderH); if (renderW > 0) mouse.fMouseXMul = (float)SCREEN_W / renderW; if (renderH > 0) mouse.fMouseYMul = (float)SCREEN_H / renderH; return true; }