blend testing and code cleanup

This commit is contained in:
erysdren 2024-10-15 13:00:11 -05:00
parent a1ca05248e
commit 32687e5360
3 changed files with 137 additions and 37 deletions

BIN
art/image.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
art/test.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

174
editor.c
View file

@ -30,6 +30,7 @@ SOFTWARE.
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include "tinyfiledialogs.h"
@ -62,6 +63,17 @@ SOFTWARE.
#define SGN(x) ((x < 0) ? -1 : ((x > 0) ? 1 : 0))
#endif
#ifndef SQR
#define SQR(x) ((x) * (x))
#endif
enum {
REDO_NO,
REDO_YES
};
#define PIXEL(s, x, y) (((uint8_t *)((s)->pixels))[(y) * (s)->pitch + (x) * (s)->format->BytesPerPixel])
/* palette */
unsigned char palette[768] = {
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x18, 0x18, 0x18,
@ -229,6 +241,7 @@ static int top_bitmap = 1;
/* temp layer */
int templayer[BITMAP_HEIGHT][BITMAP_WIDTH];
/* tools */
enum {
TOOL_PEN,
TOOL_LINE,
@ -243,11 +256,12 @@ static eui_color_t current_color = 0;
/* filter patterns for save/load dialogs */
static const char *filter_patterns[1] = {"*.bmp"};
static SDL_Window *window;
static SDL_Surface *surface8;
static SDL_Surface *surface32;
static SDL_Renderer *renderer;
static SDL_Texture *texture;
static SDL_Window *window = NULL;
static SDL_Surface *surface8 = NULL;
static SDL_Surface *surface32 = NULL;
static SDL_Surface *clut = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_Texture *texture = NULL;
static SDL_Rect blit_rect;
static SDL_Color colors[256];
static Uint64 next_time = 0;
@ -273,6 +287,77 @@ static void speed_limiter(void)
next_time += DELAY;
}
static int palette_search(SDL_Palette *palette, int r, int g, int b)
{
int i, pen = 0, dist = INT_MAX;
for (i = 0; i < palette->ncolors; i++)
{
int rank =
SQR(palette->colors[i].r - r) +
SQR(palette->colors[i].g - g) +
SQR(palette->colors[i].b - b);
if (rank < dist)
{
pen = i;
dist = rank;
}
}
return pen;
}
static SDL_Surface *generate_clut(SDL_Palette *palette)
{
SDL_Surface *clut = SDL_CreateRGBSurfaceWithFormat(0, palette->ncolors, palette->ncolors, 8, SDL_PIXELFORMAT_INDEX8);
SDL_SetSurfacePalette(clut, palette);
for (int y = 0; y < palette->ncolors; y++)
{
for (int x = 0; x < palette->ncolors; x++)
{
int r, g, b;
r = (palette->colors[x].r + palette->colors[y].r) >> 1;
g = (palette->colors[x].g + palette->colors[y].g) >> 1;
b = (palette->colors[x].b + palette->colors[y].b) >> 1;
PIXEL(clut, x, y) = palette_search(palette, r, g, b);
}
}
return clut;
}
/* setup editor colors */
static void setup_colors(SDL_Palette *palette)
{
eui_config_t *config;
/* set palette for screen */
SDL_SetSurfacePalette(surface8, palette);
/* regenerate clut */
if (clut) SDL_FreeSurface(clut);
clut = generate_clut(palette);
/* setup colors */
config = eui_get_config();
config->button.border_color = palette_search(palette, 0, 0, 0);
config->button.border_color_hover = palette_search(palette, 255, 255, 255);
config->button.bg_color = palette_search(palette, 255, 255, 255);
config->button.bg_color_hover = palette_search(palette, 0, 0, 0);
config->button.text_color = palette_search(palette, 0, 0, 0);
config->button.text_color_hover = palette_search(palette, 255, 255, 255);
}
/* do blend */
static Uint8 do_blend(int x, int y, eui_color_t color)
{
return PIXEL(clut, bitmap[y][x], color);
}
/* push bitmap to stack */
void bitmap_push(int redo)
{
@ -295,7 +380,7 @@ void bitmap_push(int redo)
/* move bitmap stack down */
for (i = 0; i < current_bitmap; i++)
{
memcpy(&bitmap_history[i], &bitmap_history[i + 1], sizeof(bitmap_history[i]));
SDL_memcpy(&bitmap_history[i], &bitmap_history[i + 1], sizeof(bitmap_history[i]));
}
}
else
@ -306,13 +391,13 @@ void bitmap_push(int redo)
/* clear upper bitmap stack */
for (i = current_bitmap; i < MAX_UNDOS; i++)
{
memset(&bitmap_history[i], 0, sizeof(bitmap_history[i]));
SDL_memset(&bitmap_history[i], 0, sizeof(bitmap_history[i]));
}
}
/* copy current bitmap to next in stack */
top_bitmap = current_bitmap;
memcpy(&bitmap_history[current_bitmap], bitmap, sizeof(bitmap));
SDL_memcpy(&bitmap_history[current_bitmap], bitmap, sizeof(bitmap));
}
/* pop bitmap from stack */
@ -328,15 +413,15 @@ void button_undo(void *user)
{
EUI_UNUSED(user);
bitmap_pop();
memcpy(bitmap, &bitmap_history[current_bitmap], sizeof(bitmap));
SDL_memcpy(bitmap, &bitmap_history[current_bitmap], sizeof(bitmap));
}
/* redo button */
void button_redo(void *user)
{
EUI_UNUSED(user);
bitmap_push(EUI_TRUE);
memcpy(bitmap, &bitmap_history[current_bitmap], sizeof(bitmap));
bitmap_push(REDO_YES);
SDL_memcpy(bitmap, &bitmap_history[current_bitmap], sizeof(bitmap));
}
/* clear button */
@ -344,10 +429,10 @@ void button_clear(void *user)
{
EUI_UNUSED(user);
memset(&bitmap, 0, sizeof(bitmap));
memset(templayer, -1, sizeof(templayer));
SDL_memset(&bitmap, 0, sizeof(bitmap));
SDL_memset(templayer, -1, sizeof(templayer));
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
}
/* save button */
@ -384,7 +469,7 @@ void button_save(void *user)
ptr = (uint8_t *)bmp->pixels;
for (y = 0; y < bmp->h; y++)
{
memcpy(ptr, &bitmap[y][0], bmp->w * sizeof(eui_color_t));
SDL_memcpy(ptr, &bitmap[y][0], bmp->w * sizeof(eui_color_t));
ptr += bmp->pitch;
}
@ -439,10 +524,13 @@ void button_load(void *user)
ptr = (uint8_t *)bmp->pixels;
for (y = 0; y < bmp->h; y++)
{
memcpy(&bitmap[y][0], ptr, bmp->w * sizeof(eui_color_t));
SDL_memcpy(&bitmap[y][0], ptr, bmp->w * sizeof(eui_color_t));
ptr += bmp->pitch;
}
/* setup palette */
setup_colors(bmp->format->palette);
SDL_FreeSurface(bmp);
}
@ -476,7 +564,7 @@ void tool_fill(int x, int y, eui_color_t color)
if (started)
{
/* push bitmap stack for undo/redo */
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
/* turn off started flag */
started = EUI_FALSE;
@ -521,7 +609,7 @@ void tool_fill(int x, int y, eui_color_t color)
if (read == seed)
{
/* set pixel */
bitmap[y][x] = color;
bitmap[y][x] = do_blend(x, y, color);
/* add neighboring pixel positions */
PUSH(x + 1, y);
@ -548,7 +636,7 @@ void tool_pen(int x, int y, eui_color_t color)
if (started)
{
/* push bitmap stack for undo/redo */
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
/* turn off started flag */
started = EUI_FALSE;
@ -562,7 +650,7 @@ void tool_pen(int x, int y, eui_color_t color)
color = 0;
/* plot pixel */
bitmap[y][x] = color;
bitmap[y][x] = do_blend(x, y, color);
/* we're doing it */
started = EUI_TRUE;
@ -589,19 +677,19 @@ void tool_rect(int x, int y, eui_color_t color)
for (xx = 0; xx < BITMAP_WIDTH; xx++)
{
if (templayer[yy][xx] >= 0)
bitmap[yy][xx] = templayer[yy][xx];
bitmap[yy][xx] = do_blend(xx, yy, templayer[yy][xx]);
}
}
/* push bitmap stack for undo/redo */
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
/* turn off started flag */
started = EUI_FALSE;
}
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
return;
}
@ -621,7 +709,7 @@ void tool_rect(int x, int y, eui_color_t color)
ysgn = SGN(endpos.y - startpos.y);
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
/* vertical lines */
for (yy = startpos.y; yy != endpos.y; yy += ysgn)
@ -675,19 +763,19 @@ void tool_line(int x, int y, eui_color_t color)
for (xx = 0; xx < BITMAP_WIDTH; xx++)
{
if (templayer[yy][xx] >= 0)
bitmap[yy][xx] = templayer[yy][xx];
bitmap[yy][xx] = do_blend(xx, yy, templayer[yy][xx]);
}
}
/* push bitmap stack for undo/redo */
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
/* turn off started flag */
started = EUI_FALSE;
}
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
return;
}
@ -706,7 +794,7 @@ void tool_line(int x, int y, eui_color_t color)
endpos.y = y;
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
/* do line drawing */
dir.x = endpos.x - startpos.x;
@ -806,19 +894,19 @@ void tool_filled_rect(int x, int y, eui_color_t color)
for (xx = 0; xx < BITMAP_WIDTH; xx++)
{
if (templayer[yy][xx] >= 0)
bitmap[yy][xx] = templayer[yy][xx];
bitmap[yy][xx] = do_blend(xx, yy, templayer[yy][xx]);
}
}
/* push bitmap stack for undo/redo */
bitmap_push(EUI_FALSE);
bitmap_push(REDO_NO);
/* turn off started flag */
started = EUI_FALSE;
}
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
return;
}
@ -838,7 +926,7 @@ void tool_filled_rect(int x, int y, eui_color_t color)
ysgn = SGN(endpos.y - startpos.y);
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
/* vertical lines */
for (yy = startpos.y; yy != endpos.y; yy += ysgn)
@ -935,11 +1023,15 @@ int main(int argc, char **argv)
colors[i].r = palette[i * 3];
colors[i].g = palette[i * 3 + 1];
colors[i].b = palette[i * 3 + 2];
colors[i].a = 255;
}
/* install palette */
SDL_SetPaletteColors(surface8->format->palette, colors, 0, 256);
/* setup editor colors */
setup_colors(surface8->format->palette);
/* create display surface */
format = SDL_GetWindowPixelFormat(window);
SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask);
@ -956,8 +1048,8 @@ int main(int argc, char **argv)
blit_rect.h = HEIGHT;
/* clear bitmap */
memset(&bitmap, 0, sizeof(bitmap));
memset(templayer, -1, sizeof(templayer));
SDL_memset(&bitmap, 0, sizeof(bitmap));
SDL_memset(templayer, -1, sizeof(templayer));
/* set default color */
current_color = 63;
@ -1146,7 +1238,7 @@ int main(int argc, char **argv)
eui_text(pos, 31, "color=---");
/* clear temp layer */
memset(templayer, -1, sizeof(templayer));
SDL_memset(templayer, -1, sizeof(templayer));
}
/* move to top left alignment */
@ -1261,8 +1353,15 @@ int main(int argc, char **argv)
}
/* blit to screen */
SDL_BlitSurface(surface8, &blit_rect, surface32, &blit_rect);
SDL_UpdateTexture(texture, NULL, surface32->pixels, surface32->pitch);
int dst_pitch;
void *dst_pixels;
if (SDL_LockTexture(texture, NULL, &dst_pixels, &dst_pitch) == 0)
{
SDL_BlitSurface(surface8, &blit_rect, surface32, &blit_rect);
SDL_memcpy(dst_pixels, surface32->pixels, surface32->pitch * surface32->h);
SDL_UnlockTexture(texture);
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
@ -1273,6 +1372,7 @@ int main(int argc, char **argv)
/* quit */
done:
SDL_FreeSurface(clut);
SDL_FreeSurface(surface8);
SDL_FreeSurface(surface32);
SDL_DestroyTexture(texture);