ref: 3b4630b51b22432a93ee69ab065be9da458c9f1b
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;
}