Optimized window drawing. Added window caching.

This commit is contained in:
Scott Duensing 2022-06-15 20:02:39 -05:00
parent 7d32a1df31
commit 10196882ef
12 changed files with 585 additions and 231 deletions

View file

@ -4,8 +4,8 @@ CONFIG -= qt
CONFIG += console CONFIG += console
CONFIG += c99 CONFIG += c99
#CONFIG += BACKEND_SDL2 CONFIG += BACKEND_SDL2
CONFIG += BACKEND_DJGPP #CONFIG += BACKEND_DJGPP
SHARED = $$PWD/../shared SHARED = $$PWD/../shared

View file

@ -1,7 +1,20 @@
#include "font.h" #include "font.h"
#include "gui.h"
#include "platform/platform.h" #include "platform/platform.h"
static FontT *_font = NULL;
static ColorT _foreground = 0;
static ColorT _background = 0;
static uint8_t _allowMods = 1;
void fontColorSet(ColorT foreground, ColorT background) {
_foreground = foreground;
_background = background;
}
FontT *fontFromRAMLoad(uint8_t *pointer) { FontT *fontFromRAMLoad(uint8_t *pointer) {
FontT *font = NULL; FontT *font = NULL;
uint32_t size = 0; uint32_t size = 0;
@ -67,7 +80,12 @@ FontT *fontLoad(char *filename) {
} }
void fontRender(FontT *font, char *string, ColorT foreground, ColorT background, uint16_t x, uint16_t y) { void fontModsEnabledSet(uint8_t enabled) {
_allowMods = enabled;
}
void fontRender(char *string, uint16_t x, uint16_t y) {
uint8_t cx; uint8_t cx;
uint8_t cy; uint8_t cy;
uint16_t offset; uint16_t offset;
@ -83,37 +101,54 @@ void fontRender(FontT *font, char *string, ColorT foreground, ColorT background,
for (c=0; c<strlen(string); c++) { for (c=0; c<strlen(string); c++) {
character = string[c]; character = string[c];
if (_allowMods) {
// Change _foreground to GUI Color Index.
if (character == 1) {
character = string[++c];
if (character == 16) character = 0; // Because we can't pass NULL in a string, 16 is used for black.
_foreground = __guiBaseColors[character];
continue;
}
// Change _background to GUI Color Index.
if (character == 2) {
character = string[++c];
if (character == 16) character = 0; // Because we can't pass NULL in a string, 16 is used for black.
_background = __guiBaseColors[character];
continue;
}
}
// Find character position in font grid. // Find character position in font grid.
cx = character % font->span; cx = character % _font->span;
cy = character / font->span; cy = character / _font->span;
yp = y; yp = y;
// Half byte or full byte font? // Half byte or full byte font?
if (font->width == 4) { if (_font->width == 4) {
// Half Byte. // Half Byte.
// Which half of the byte do we want? // Which half of the byte do we want?
odd = ((cx & 1) == 1); odd = ((cx & 1) == 1);
// Find offset byte based on font bits. // Find offset byte based on font bits.
offset = cy * (font->span / 2) * font->height + cx * ((float)font->width / 8.0f); offset = cy * (_font->span / 2) * _font->height + cx * ((float)_font->width / 8.0f);
for (yl=0; yl<font->height; yl++) { for (yl=0; yl<_font->height; yl++) {
// We do 4 pixels unrolled hoping it's fast. // We do 4 pixels unrolled hoping it's fast.
data = font->bits[offset]; data = _font->bits[offset];
offset += (font->span / 2); offset += (_font->span / 2);
if (odd) { if (odd) {
surfacePixelSet(x, yp, (data & 0x08) ? foreground : background); surfacePixelSet(x, yp, (data & 0x08) ? _foreground : _background);
surfacePixelSet(x + 1, yp, (data & 0x04) ? foreground : background); surfacePixelSet(x + 1, yp, (data & 0x04) ? _foreground : _background);
surfacePixelSet(x + 2, yp, (data & 0x02) ? foreground : background); surfacePixelSet(x + 2, yp, (data & 0x02) ? _foreground : _background);
surfacePixelSet(x + 3, yp, (data & 0x01) ? foreground : background); surfacePixelSet(x + 3, yp, (data & 0x01) ? _foreground : _background);
} else { } else {
surfacePixelSet(x, yp, (data & 0x80) ? foreground : background); surfacePixelSet(x, yp, (data & 0x80) ? _foreground : _background);
surfacePixelSet(x + 1, yp, (data & 0x40) ? foreground : background); surfacePixelSet(x + 1, yp, (data & 0x40) ? _foreground : _background);
surfacePixelSet(x + 2, yp, (data & 0x20) ? foreground : background); surfacePixelSet(x + 2, yp, (data & 0x20) ? _foreground : _background);
surfacePixelSet(x + 3, yp, (data & 0x10) ? foreground : background); surfacePixelSet(x + 3, yp, (data & 0x10) ? _foreground : _background);
} }
yp++; yp++;
@ -122,38 +157,43 @@ void fontRender(FontT *font, char *string, ColorT foreground, ColorT background,
// Full Byte. // Full Byte.
// Find offset byte based on font bits. // Find offset byte based on font bits.
offset = cy * font->span * font->height + cx; offset = cy * _font->span * _font->height + cx;
// Draw out 8 lines. // Draw out 8 lines.
for (yl=0; yl<font->height; yl++) { for (yl=0; yl<_font->height; yl++) {
// We do 8 pixels unrolled hoping it's fast. // We do 8 pixels unrolled hoping it's fast.
data = font->bits[offset]; data = _font->bits[offset];
offset += font->span; offset += _font->span;
surfacePixelSet(x, yp, (data & 0x80) ? foreground : background); surfacePixelSet(x, yp, (data & 0x80) ? _foreground : _background);
surfacePixelSet(x + 1, yp, (data & 0x40) ? foreground : background); surfacePixelSet(x + 1, yp, (data & 0x40) ? _foreground : _background);
surfacePixelSet(x + 2, yp, (data & 0x20) ? foreground : background); surfacePixelSet(x + 2, yp, (data & 0x20) ? _foreground : _background);
surfacePixelSet(x + 3, yp, (data & 0x10) ? foreground : background); surfacePixelSet(x + 3, yp, (data & 0x10) ? _foreground : _background);
surfacePixelSet(x + 4, yp, (data & 0x08) ? foreground : background); surfacePixelSet(x + 4, yp, (data & 0x08) ? _foreground : _background);
surfacePixelSet(x + 5, yp, (data & 0x04) ? foreground : background); surfacePixelSet(x + 5, yp, (data & 0x04) ? _foreground : _background);
surfacePixelSet(x + 6, yp, (data & 0x02) ? foreground : background); surfacePixelSet(x + 6, yp, (data & 0x02) ? _foreground : _background);
surfacePixelSet(x + 7, yp, (data & 0x01) ? foreground : background); surfacePixelSet(x + 7, yp, (data & 0x01) ? _foreground : _background);
yp++; yp++;
} }
} }
x += font->width; x += _font->width;
} }
} }
void fontSet(FontT *font) {
_font = font;
}
void fontUnload(FontT **font) { void fontUnload(FontT **font) {
FontT *f = *font; FontT *f = *font;
free(f->bits); free(f->bits);
free(f); free(f);
f = NULL; *font = NULL;
} }

View file

@ -17,10 +17,13 @@ typedef struct FontS {
} FontT; } FontT;
void fontColorSet(ColorT foreground, ColorT background);
FontT *fontFromRAMLoad(uint8_t *pointer); FontT *fontFromRAMLoad(uint8_t *pointer);
uint16_t fontHeightGet(FontT *font); uint16_t fontHeightGet(FontT *font);
FontT *fontLoad(char *filename); FontT *fontLoad(char *filename);
void fontRender(FontT *font, char *string, ColorT foreground, ColorT background, uint16_t x, uint16_t y); void fontModsEnabledSet(uint8_t enabled);
void fontRender(char *string, uint16_t x, uint16_t y);
void fontSet(FontT *font);
void fontUnload(FontT **font); void fontUnload(FontT **font);
uint16_t fontWidthGet(FontT *font); uint16_t fontWidthGet(FontT *font);

View file

@ -13,7 +13,9 @@ typedef struct WidgetCatalogS {
ColorT *__guiBaseColors = NULL; ColorT *__guiBaseColors = NULL;
SurfaceT *__guiBackBuffer = NULL; SurfaceT *__guiBackBuffer = NULL;
FontT *__guiFontVGA8x8 = NULL;
FontT *__guiFontVGA8x14 = NULL; FontT *__guiFontVGA8x14 = NULL;
FontT *__guiFontVGA8x16 = NULL;
static uint8_t _magicCount = 0; static uint8_t _magicCount = 0;
@ -23,10 +25,9 @@ static SurfaceT *_mousePointer = NULL;
static ColorT _mouseTransparency; static ColorT _mouseTransparency;
void guiRun(void) { void guiEventsDo(void) {
EventT event = { 0 }; EventT event = { 0 };
while (_guiRunning) {
// Read mouse & keyboard. // Read mouse & keyboard.
platformEventGet(&event); platformEventGet(&event);
@ -45,7 +46,6 @@ void guiRun(void) {
// Emergency Exit? // Emergency Exit?
if (event.flags & EVENT_FLAG_KEYPRESS && event.key == KEY_ESC) guiStop(); if (event.flags & EVENT_FLAG_KEYPRESS && event.key == KEY_ESC) guiStop();
}
} }
@ -56,9 +56,20 @@ void guiRegister(WidgetRegisterT widgetRegister) {
} }
void guiRun(void) {
while (_guiRunning) {
// Process all GUI events.
guiEventsDo();
}
}
void guiShutdown(void) { void guiShutdown(void) {
free(__guiBaseColors); DEL(__guiBaseColors);
while (hmlen(_widgetCatalog) > 0) { while (hmlen(_widgetCatalog) > 0) {
if (_widgetCatalog[0].value->unregister) _widgetCatalog[0].value->unregister(NULL); if (_widgetCatalog[0].value->unregister) _widgetCatalog[0].value->unregister(NULL);
@ -68,10 +79,12 @@ void guiShutdown(void) {
wmShutdown(); wmShutdown();
fontUnload(&__guiFontVGA8x16);
fontUnload(&__guiFontVGA8x14); fontUnload(&__guiFontVGA8x14);
fontUnload(&__guiFontVGA8x8);
surfaceDestroy(_mousePointer); surfaceDestroy(&_mousePointer);
surfaceDestroy(__guiBackBuffer); surfaceDestroy(&__guiBackBuffer);
platformShutdown(); platformShutdown();
} }
@ -111,10 +124,15 @@ uint8_t guiStartup(int16_t width, int16_t height, int16_t depth) {
_mousePointer = imageLoad("mouse.png"); _mousePointer = imageLoad("mouse.png");
_mouseTransparency = surfacePixelGet(_mousePointer, surfaceWidthGet(_mousePointer) - 2, 0); // Find our transparency color. _mouseTransparency = surfacePixelGet(_mousePointer, surfaceWidthGet(_mousePointer) - 2, 0); // Find our transparency color.
__guiFontVGA8x8 = fontLoad("vga8x8.dat");
__guiFontVGA8x14 = fontLoad("vga8x14.dat"); __guiFontVGA8x14 = fontLoad("vga8x14.dat");
__guiFontVGA8x16 = fontLoad("vga8x16.dat");
fontSet(__guiFontVGA8x14);
fontColorSet(GUI_WHITE, GUI_BLACK);
wmStartup(); wmStartup();
// Register all known widgets with the GUI.
guiRegister(windowRegister); guiRegister(windowRegister);
return SUCCESS; return SUCCESS;
@ -135,4 +153,16 @@ void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, ui
widget->r.h = h; widget->r.h = h;
widget->reg = hmget(_widgetCatalog, magic); widget->reg = hmget(_widgetCatalog, magic);
widget->dirty = 1; // Everything starts dirty to force a paint.
}
uint8_t guiWidgetDirtyGet(WidgetT *widget) {
return widget->dirty;
}
void guiWidgetDirtySet(WidgetT *widget, uint8_t dirty) {
widget->dirty = dirty;
} }

View file

@ -31,16 +31,17 @@ typedef struct RectS {
} RectT; } RectT;
typedef struct RegisterS { typedef struct RegisterS {
char *widgetName; char *widgetName; // Text name of widget.
WidgetEventT paint; WidgetEventT paint; // Paint routine.
WidgetEventT destroy; WidgetEventT destroy; // Destroy routine.
GuiCallbackT unregister; GuiCallbackT unregister; // Unregister routine.
} RegisterT; } RegisterT;
typedef struct WidgetS { typedef struct WidgetS {
uint8_t magic; uint8_t magic; // Magic ID of widget.
RectT r; RectT r; // Outer bounds, except for windows.
RegisterT *reg; RegisterT *reg; // Registration information.
uint8_t dirty; // Is the widget dirty?
} WidgetT; } WidgetT;
typedef RegisterT *(*WidgetRegisterT)(uint8_t); typedef RegisterT *(*WidgetRegisterT)(uint8_t);
@ -49,7 +50,9 @@ typedef RegisterT *(*WidgetRegisterT)(uint8_t);
extern SurfaceT *__guiBackBuffer; extern SurfaceT *__guiBackBuffer;
extern SurfaceT *__guiScreenBuffer; extern SurfaceT *__guiScreenBuffer;
extern ColorT *__guiBaseColors; extern ColorT *__guiBaseColors;
extern FontT *__guiFontVGA8x8;
extern FontT *__guiFontVGA8x14; extern FontT *__guiFontVGA8x14;
extern FontT *__guiFontVGA8x16;
#define GUI_BLACK __guiBaseColors[0] #define GUI_BLACK __guiBaseColors[0]
@ -70,13 +73,19 @@ extern FontT *__guiFontVGA8x14;
#define GUI_WHITE __guiBaseColors[15] #define GUI_WHITE __guiBaseColors[15]
void guiModesShow(void); #define W (WidgetT *) // Cast any widget to base WidgetT type.
#define C(n) ((n) << 3) // Multiply by 8 to get "cells".
void guiEventsDo(void);
void guiRegister(WidgetRegisterT widgetRegister); void guiRegister(WidgetRegisterT widgetRegister);
void guiRun(void); void guiRun(void);
void guiShutdown(void); void guiShutdown(void);
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth); uint8_t guiStartup(int16_t width, int16_t height, int16_t depth);
void guiStop(void); void guiStop(void);
void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, uint16_t w, uint16_t h); void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
uint8_t guiWidgetDirtyGet(WidgetT *widget);
void guiWidgetDirtySet(WidgetT *widget, uint8_t dirty);
#endif // GUI_H #endif // GUI_H

View file

@ -111,8 +111,6 @@ SurfaceT *surfaceCreate(int16_t width, int16_t height) {
return NULL; return NULL;
} }
memset(surface->buffer.bits8, 0, surface->bytes);
return surface; return surface;
} }
@ -160,9 +158,19 @@ void surfaceBoxFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c)
} }
void surfaceDestroy(SurfaceT *surface) { void surfaceBoxHighlight(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT highlight, ColorT shadow) {
free(surface->buffer.bits8); surfaceLineH(x1, x2, y1, highlight);
free(surface); surfaceLineV(x1, y1, y2, highlight);
surfaceLineH(x1, x2, y2, shadow);
surfaceLineV(x2, y1, y2, shadow);
}
void surfaceDestroy(SurfaceT **surface) {
SurfaceT *s = *surface;
DEL(s->buffer.bits8);
DEL(s);
*surface = NULL;
} }
@ -176,6 +184,66 @@ int16_t surfaceHeightGet(SurfaceT *surface) {
} }
void surfaceLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) {
int16_t x;
int16_t y;
int16_t dx;
int16_t dy;
int16_t incX;
int16_t incY;
int16_t balance;
if (x2 >= x1) {
dx = x2 - x1;
incX = 1;
} else {
dx = x1 - x2;
incX = -1;
}
if (y2 >= y1) {
dy = y2 - y1;
incY = 1;
} else {
dy = y1 - y2;
incY = -1;
}
x = x1;
y = y1;
if (dx >= dy) {
dy <<= 1;
balance = dy - dx;
dx <<= 1;
while (x != x2) {
surfacePixelSet(x, y, color);
if (balance >= 0) {
y += incY;
balance -= dx;
}
balance += dy;
x += incX;
}
surfacePixelSet(x, y, color);
} else {
dx <<= 1;
balance = dx - dy;
dy <<= 1;
while (y != y2) {
surfacePixelSet(x, y, color);
if (balance >= 0) {
x += incX;
balance -= dy;
}
balance += dx;
y += incY;
}
surfacePixelSet(x, y, color);
}
}
void surfaceLineH(int16_t x1, int16_t x2, int16_t y, ColorT c) { void surfaceLineH(int16_t x1, int16_t x2, int16_t y, ColorT c) {
int16_t i; int16_t i;
int16_t t; int16_t t;

View file

@ -52,9 +52,11 @@ ColorT surfaceColorMake(uint8_t r, uint8_t g, uint8_t b);
SurfaceT *surfaceCreate(int16_t width, int16_t height); SurfaceT *surfaceCreate(int16_t width, int16_t height);
void surfaceBox(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c); void surfaceBox(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c);
void surfaceBoxFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c); void surfaceBoxFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT c);
void surfaceDestroy(SurfaceT *surface); void surfaceBoxHighlight(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT highlight, ColorT shadow);
void surfaceDestroy(SurfaceT **surface);
SurfaceT *surfaceGet(void); SurfaceT *surfaceGet(void);
int16_t surfaceHeightGet(SurfaceT *surface); int16_t surfaceHeightGet(SurfaceT *surface);
void surfaceLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color);
void surfaceLineH(int16_t x1, int16_t x2, int16_t y, ColorT c); void surfaceLineH(int16_t x1, int16_t x2, int16_t y, ColorT c);
void surfaceLineV(int16_t x, int16_t y1, int16_t y2, ColorT c); void surfaceLineV(int16_t x, int16_t y1, int16_t y2, ColorT c);
void surfaceSet(SurfaceT *surface); void surfaceSet(SurfaceT *surface);

View file

@ -3,9 +3,13 @@
#include "font.h" #include "font.h"
#define USE_CACHING
uint8_t __MAGIC_WINDOW = 0; uint8_t __MAGIC_WINDOW = 0;
static WindowT **_windowList = NULL; static WindowT **_windowList = NULL;
static WindowT *_windowTop = NULL;
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, uint8_t flags, ...) { WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, uint8_t flags, ...) {
@ -22,8 +26,12 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl
win->maximize.x = win->maximize.y = win->maximize.x2 = win->maximize.y2 = 0; win->maximize.x = win->maximize.y = win->maximize.x2 = win->maximize.y2 = 0;
win->bounds.x = win->bounds.y = win->bounds.x2 = win->bounds.y2 = 0; win->bounds.x = win->bounds.y = win->bounds.x2 = win->bounds.y2 = 0;
win->cached = NULL;
arrput(_windowList, win); arrput(_windowList, win);
windowFocusSet(win);
return win; return win;
} }
@ -32,169 +40,288 @@ void windowDestroy(struct WidgetS *widget, ...) {
uint16_t i; uint16_t i;
WindowT *window = (WindowT *)widget; WindowT *window = (WindowT *)widget;
// Find the window to delete.
for (i=0; i<arrlen(_windowList); i++) { for (i=0; i<arrlen(_windowList); i++) {
if (window == _windowList[i]) { if (window == _windowList[i]) {
// Was it the focused window?
if (_windowList[i] == _windowTop) {
// Find new topmost window on next call to focus.
_windowTop = NULL;
}
// Free the title.
if (_windowList[i]->title) DEL(_windowList[i]->title); if (_windowList[i]->title) DEL(_windowList[i]->title);
// Free cached surface.
if (_windowList[i]->cached) surfaceDestroy(&_windowList[i]->cached);
// Delete the window.
DEL(_windowList[i]); DEL(_windowList[i]);
// Remove it from window list.
arrdel(_windowList, i); arrdel(_windowList, i);
// Fixup focus.
windowFocusSet(NULL);
break; break;
} }
} }
} }
void windowPaint(struct WidgetS *widget, ...) { void windowFocusSet(WindowT *win) {
WindowT *w = (WindowT *)widget; int16_t i;
uint16_t x1 = w->base.r.x;
uint16_t y1 = w->base.r.y;
uint16_t x2 = w->base.r.x + w->base.r.w - 1;
uint16_t y2 = w->base.r.y + w->base.r.h - 1;
uint16_t tx1;
uint16_t ty1;
uint16_t tx2;
uint16_t ty2;
uint16_t minimizeOffset = 0;
ColorT titleBackgroundColor = GUI_DARKGRAY;
// Fake Window contents. // Do we have a focused window at the moment?
surfaceBoxFilled(x1, y1, x2, y2, GUI_BLACK); if (!_windowTop || !win) {
// If there's a list of windows, use the topmost.
if (arrlen(_windowList) > 0) {
_windowTop = _windowList[arrlen(_windowList) - 1];
guiWidgetDirtySet(W(_windowTop), 1);
} else {
// If no list, set it to NULL.
_windowTop = NULL;
}
return;
}
// Did they even pass in a window? If not, we're just intended to fixup _windowTop.
if (!win) return;
// Are we already the topmost window?
if (win == _windowTop) return;
// Mark old focus and new focus dirty to repaint title bar.
guiWidgetDirtySet(W(win), 1);
guiWidgetDirtySet(W(_windowTop), 1);
// Change who has focus.
_windowTop = win;
// Reorder window list.
i = arrlen(_windowList) - 2;
if (i >= 0) {
for (; i>=0; i--) {
if (_windowList[i] == win) {
arrdel(_windowList, i);
arrput(_windowList, win);
break;
}
}
}
}
void windowMoveTo(WindowT *w, uint16_t x, uint16_t y) {
int16_t dx = x - w->base.r.x;
int16_t dy = y - w->base.r.y;
// This is all because we draw the window at 0,0 in order to cache it.
// To keep the coordinates correct, we have to adjust them all when
// the window is moved.
// If we need a titlebar, it's 18px.
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) { if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
if (w->flags & WIN_CLOSE) {
w->close.x += dx;
w->close.y += dy;
w->close.x2 += dx;
w->close.y2 += dy;
}
// Draw title bar background. if (w->flags & WIN_MAXIMIZE) {
y1 -= 18; w->maximize.x += dx;
surfaceBoxFilled(x1, y1, x2, y1 + 17, titleBackgroundColor); w->maximize.y += dy;
w->maximize.x2 += dx;
w->maximize.y2 += dy;
}
if (w->flags & WIN_MINIMIZE) {
w->minimize.x += dx;
w->minimize.y += dy;
w->minimize.x2 += dx;
w->minimize.y2 += dy;
}
w->titlebar.x += dx;
w->titlebar.y += dy;
w->titlebar.x2 += dx;
w->titlebar.y2 += dy;
}
w->bounds.x += dx;
w->bounds.y += dy;
w->bounds.x2 += dx;
w->bounds.y2 += dy;
w->base.r.x = x;
w->base.r.y = y;
}
void windowPaint(struct WidgetS *widget, ...) {
int16_t i;
int16_t x1;
int16_t y1;
int16_t x2;
int16_t y2;
int16_t tx1;
int16_t tx2;
int16_t ty2;
int16_t originalX;
int16_t originalY;
WindowT *w;
SurfaceT *target;
ColorT titleBackgroundColor;
ColorT widgetColor;
target = surfaceGet();
w = (WindowT *)widget;
#ifdef USE_CACHING
// Do we need redrawn?
if (guiWidgetDirtyGet(widget)) {
guiWidgetDirtySet(widget, 0);
// Move the window to 0,0 to cache to it's own surface.
originalX = w->base.r.x;
originalY = w->base.r.y;
w->base.r.x = 0;
w->base.r.y = 0;
// Do we have a cached surface already?
if (w->cached) {
// Did the size change?
if ((surfaceWidthGet(w->cached) != w->base.r.w) || (surfaceHeightGet(w->cached) != w->base.r.h)) {
// Yeah. We will recreate it.
surfaceDestroy(&w->cached);
}
}
// Do we need to create a surface?
if (!w->cached) {
w->cached = surfaceCreate(w->base.r.w, w->base.r.h);
}
// Draw into cache.
surfaceSet(w->cached);
#endif
// Determine some colors.
titleBackgroundColor = (w == _windowTop) ? GUI_DARKGRAY : GUI_LIGHTGRAY;
widgetColor = (w == _windowTop) ? GUI_LIGHTGRAY : GUI_DARKGRAY;
// Get ready!
x1 = w->base.r.x;
y1 = w->base.r.y;
x2 = w->base.r.x + w->base.r.w - 1;
y2 = w->base.r.y + w->base.r.h - 1;
// Draw border.
surfaceBoxHighlight(x1, y1, x2, y2, GUI_WHITE, GUI_BLACK);
x1++; y1++; x2--; y2--;
for (i=0; i<3; i++) {
surfaceBox(x1, y1, x2, y2, GUI_LIGHTGRAY);
x1++; y1++; x2--; y2--;
}
surfaceBoxHighlight(x1, y1, x2, y2, GUI_BLACK, GUI_WHITE);
x1++; y1++; x2--; y2--;
// Do we need a titlebar?
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
tx1 = x1;
tx2 = x2;
ty2 = y1 + 20;
// Close box? // Close box?
if (w->flags & WIN_CLOSE) { if (w->flags & WIN_CLOSE) {
// 26px wide, 18 tall including highlight and shadow. tx1 += 20;
w->close.x = x1 + 1; w->close.x = x1;
w->close.y = y1 + 1; w->close.y = y1;
w->close.x2 = w->close.x + 24; w->close.x2 = tx1 - 1;
w->close.y2 = w->close.y + 15; w->close.y2 = ty2 - 1;
surfaceBoxFilled(w->close.x + 1, w->close.y + 1, w->close.x2 - 1, w->close.y2 - 1, GUI_LIGHTGRAY); surfaceBoxFilled(w->close.x + 1, w->close.y + 1, w->close.x2 - 1, w->close.y2 - 1, titleBackgroundColor);
surfaceLineH(w->close.x, w->close.x2, w->close.y, GUI_WHITE); surfaceBoxHighlight(w->close.x + 3, w->close.y + 8, w->close.x2 - 3, w->close.y2 - 8, GUI_WHITE, widgetColor);
surfaceLineV(w->close.x, w->close.y, w->close.y2, GUI_WHITE); surfaceBoxHighlight(w->close.x, w->close.y, w->close.x2, w->close.y2, GUI_WHITE, GUI_BLACK);
// Button is 8px down, 3px tall, and 4px in on both sides.
tx1 = w->close.x + 4;
ty1 = w->close.y + 7;
tx2 = w->close.x2 - 4;
ty2 = w->close.y + 9;
surfaceLineH(tx1, tx2, ty1, GUI_WHITE);
surfacePixelSet(tx1, ty1 + 1, GUI_WHITE);
surfaceLineH(tx1, tx2, ty2, GUI_BLACK);
surfaceLineV(tx2, ty1, ty2, GUI_BLACK);
// Set titlebar area.
w->titlebar.x = w->close.x2 + 2;
} else { } else {
// No close box - set titlebar area. w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
w->titlebar.x = x1;
} }
w->titlebar.y = y1;
w->titlebar.x2 = x2;
w->titlebar.y2 = y1 + 17;
// Maximize box? // Maximize box?
if (w->flags & WIN_MAXIMIZE) { if (w->flags & WIN_MAXIMIZE) {
// 26px wide, 18 tall including highlight and shadow. tx2 -= 20;
w->maximize.y = y1 + 1; w->maximize.x = tx2 + 1;
w->maximize.x2 = x2 - 1; w->maximize.y = y1;
w->maximize.x = w->maximize.x2 - 24; w->maximize.x2 = tx2 + 20;
w->maximize.y2 = w->maximize.y + 15; w->maximize.y2 = ty2 - 1;
surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, GUI_LIGHTGRAY); surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, titleBackgroundColor);
surfaceLineH(w->maximize.x, w->maximize.x2, w->maximize.y, GUI_WHITE); surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y + 4, GUI_WHITE);
surfaceLineV(w->maximize.x, w->maximize.y, w->maximize.y2, GUI_WHITE); surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y2 - 3, GUI_WHITE);
// Button is 3px down, and 4px in on both sides. surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y + 4, widgetColor);
tx1 = w->maximize.x + 4; surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y2 - 3, widgetColor);
ty1 = w->maximize.y + 4; surfaceBoxHighlight(w->maximize.x, w->maximize.y, w->maximize.x2, w->maximize.y2, GUI_WHITE, GUI_BLACK);
tx2 = w->maximize.x2 - 3; } else {
ty2 = w->maximize.y + 12; w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
surfaceLineH(tx1, tx2, ty1, GUI_WHITE);
surfaceLineV(tx1, ty1, ty2, GUI_WHITE);
surfaceLineH(tx1, tx2, ty2, GUI_BLACK);
surfaceLineV(tx2, ty1, ty2, GUI_BLACK);
// Move minimize button over.
minimizeOffset = 26;
// Set titlebar area.
w->titlebar.x2 -= 26;
} }
// Minimize box? // Minimize box?
if (w->flags & WIN_MINIMIZE) { if (w->flags & WIN_MINIMIZE) {
// 26px wide, 18 tall including highlight and shadow. tx2 -= 20;
w->minimize.y = y1 + 1; w->minimize.x = tx2 + 1;
w->minimize.x2 = x2 - 1 - minimizeOffset; w->minimize.y = y1;
w->minimize.x = w->minimize.x2 - 24; w->minimize.x2 = tx2 + 20;
w->minimize.y2 = w->minimize.y + 15; w->minimize.y2 = ty2 - 1;
surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, GUI_LIGHTGRAY); surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, titleBackgroundColor);
surfaceLineH(w->minimize.x, w->minimize.x2, w->minimize.y, GUI_WHITE); surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, widgetColor);
surfaceLineV(w->minimize.x, w->minimize.y, w->minimize.y2, GUI_WHITE); surfaceBoxHighlight(w->minimize.x, w->minimize.y, w->minimize.x2, w->minimize.y2, GUI_WHITE, GUI_BLACK);
tx1 = w->minimize.x + 10; } else {
ty1 = w->minimize.y + 6; w->minimize.x = w->minimize.y = w->minimize.x2 = w->maximize.y2 = 0;
tx2 = w->minimize.x2 - 8;
ty2 = w->minimize.y + 9;
surfaceLineH(tx1, tx2, ty1, GUI_WHITE);
surfaceLineV(tx1, ty1, ty2, GUI_WHITE);
surfaceLineH(tx1, tx2, ty2, GUI_BLACK);
surfaceLineV(tx2, ty1, ty2, GUI_BLACK);
// Set titlebar area.
w->titlebar.x2 -= 26;
} }
// Title font area is 12px high. // Draw titlebar background.
surfaceLineH(w->titlebar.x, w->titlebar.x2 - 1, w->titlebar.y, GUI_WHITE); w->titlebar.x = tx1;
surfaceLineV(w->titlebar.x, w->titlebar.y, w->titlebar.y2 - 1, GUI_WHITE); w->titlebar.y = y1;
w->titlebar.x2 = tx2;
w->titlebar.y2 = ty2 - 1;
surfaceBoxFilled(w->titlebar.x + 1, w->titlebar.y + 1, w->titlebar.x2 - 1, w->titlebar.y2 - 1, titleBackgroundColor);
if (w->title) { if (w->title) {
ty1 = w->titlebar.y + 2; fontSet(__guiFontVGA8x16);
tx1 = w->titlebar.x + 2 + (w->titlebar.x2 - w->titlebar.x - 4) * 0.5 - ((strlen(w->title) * 8) * 0.5); fontColorSet(GUI_WHITE, titleBackgroundColor);
fontRender(__guiFontVGA8x14, w->title, GUI_WHITE, titleBackgroundColor, tx1, ty1); fontRender(w->title, w->titlebar.x + 12, w->titlebar.y + 2);
} }
surfaceBoxHighlight(w->titlebar.x, w->titlebar.y, w->titlebar.x2, w->titlebar.y2, GUI_WHITE, GUI_BLACK);
} else {
w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
w->minimize.x = w->minimize.y = w->minimize.x2 = w->maximize.y2 = 0;
w->titlebar.x = w->titlebar.y = w->titlebar.x2 = w->titlebar.y2 = 0;
} }
// Innermost shadow frame. 1px wide. // Find content area.
x1--; y1 += 20;
y1--; w->bounds.x = x1;
x2++; w->bounds.y = y1;
y2++; w->bounds.x2 = x2;
surfaceLineH(x1, x2, y2, GUI_WHITE); w->bounds.y2 = y2;
surfaceLineV(x2, y1, y2, GUI_WHITE);
surfaceLineH(x1, x2, y1, GUI_DARKGRAY);
surfaceLineV(x1, y1, y2, GUI_DARKGRAY);
// Frame Border. 4px wide.
x1 -= 4;
y1 -= 4;
x2 += 4;
y2 += 4;
surfaceBoxFilled(x1, y1, x1 + 3, y2, GUI_LIGHTGRAY);
surfaceBoxFilled(x2, y1, x2 - 3, y2, GUI_LIGHTGRAY);
surfaceBoxFilled(x1, y1, x2, y1 + 3, GUI_LIGHTGRAY);
surfaceBoxFilled(x1, y2, x2, y2 - 3, GUI_LIGHTGRAY);
// Resize handle. // Resize handle.
if (w->flags & WIN_RESIZE) { if (w->flags & WIN_RESIZE) {
ty1 = y2 - 15 - 3; x1 = w->base.r.x + w->base.r.w - 2;
tx1 = x2 - 15 - 3; x2 = x1 - 3;
surfaceLineH(x2, x2 - 3, ty1, GUI_DARKGRAY); y1 = w->base.r.y + w->base.r.h - 21;
surfaceLineH(x2, x2 - 3, ty1 + 1, GUI_WHITE); surfaceLineH(x1, x2, y1, GUI_BLACK);
surfaceLineV(tx1, y2, y2 - 3, GUI_DARKGRAY); surfaceLineH(x1, x2, y1 + 1, GUI_WHITE);
surfaceLineV(tx1 + 1, y2, y2 - 3, GUI_WHITE); x1 = w->base.r.x + w->base.r.w - 21;
y1 = w->base.r.y + w->base.r.h - 2;
y2 = y1 - 3;
surfaceLineV(x1, y1, y2, GUI_BLACK);
surfaceLineV(x1 + 1, y1, y2, GUI_WHITE);
} }
// Outermost shadow frame. 1px wide. // Fake Window contents.
x1--; surfaceBoxFilled(w->bounds.x, w->bounds.y, w->bounds.x2, w->bounds.y2, GUI_BLACK);
y1--;
x2++; #ifdef USE_CACHING
y2++; // Fixup all the widget coordinates.
surfaceLineH(x1, x2, y1, GUI_WHITE); windowMoveTo(w, originalX, originalY);
surfaceLineV(x1, y1, y2, GUI_WHITE); }
surfaceLineH(x1, x2, y2, GUI_DARKGRAY);
surfaceLineV(x2, y1, y2, GUI_DARKGRAY); // By now we have a valid cached window. Blit it.
w->bounds.x = x1; surfaceBlit(target, w->base.r.x, w->base.r.y, w->cached);
w->bounds.x2 = x2; #endif
w->bounds.y = y1;
w->bounds.y2 = y2;
} }
@ -215,6 +342,8 @@ RegisterT *windowRegister(uint8_t magic) {
void wmPaint(EventT *event) { void wmPaint(EventT *event) {
int16_t i; int16_t i;
int16_t x2;
int16_t y2;
WidgetT *widget; WidgetT *widget;
WindowT *win; WindowT *win;
static uint8_t dragging = 0; static uint8_t dragging = 0;
@ -233,25 +362,29 @@ void wmPaint(EventT *event) {
// Get top window. // Get top window.
win = _windowList[arrlen(_windowList) - 1]; win = _windowList[arrlen(_windowList) - 1];
// Get right/bottom of window.
x2 = win->base.r.x + win->base.r.w - 1;
y2 = win->base.r.y + win->base.r.h - 1;
// Wrap left button processing with a 'for' so we can 'break' out of it. // Wrap left button processing with a 'for' so we can 'break' out of it.
for (;;) { for (;;) {
// Is the left mouse button down? // Is the left mouse button down?
if (event->buttons & BUTTON_LEFT) { if (event->buttons & BUTTON_LEFT) {
// DEBUG - draw active regions. ***TODO*** No resize grabber here. // DEBUG - draw active regions. ***TODO*** No resize grabber here.
surfaceBox(win->bounds.x, win->bounds.y, win->bounds.x2, win->bounds.y2, GUI_YELLOW); surfaceSet(__guiBackBuffer);
surfaceBox(win->base.r.x, win->base.r.y, win->base.r.x + win->base.r.w - 1, win->base.r.y + win->base.r.h - 1, GUI_YELLOW); surfaceBox(win->base.r.x, win->base.r.y, x2, y2, GUI_YELLOW);
surfaceBox(win->close.x, win->close.y, win->close.x2, win->close.y2, GUI_RED); surfaceBox(win->bounds.x, win->bounds.y, win->bounds.x2, win->bounds.y2, GUI_CYAN);
surfaceBox(win->titlebar.x, win->titlebar.y, win->titlebar.x2, win->titlebar.y2, GUI_RED); surfaceBox(win->close.x, win->close.y, win->close.x2, win->close.y2, GUI_LIGHTBLUE);
surfaceBox(win->minimize.x, win->minimize.y, win->minimize.x2, win->minimize.y2, GUI_RED); surfaceBox(win->titlebar.x, win->titlebar.y, win->titlebar.x2, win->titlebar.y2, GUI_LIGHTCYAN);
surfaceBox(win->minimize.x, win->minimize.y, win->minimize.x2, win->minimize.y2, GUI_LIGHTGREEN);
surfaceBox(win->maximize.x, win->maximize.y, win->maximize.x2, win->maximize.y2, GUI_RED); surfaceBox(win->maximize.x, win->maximize.y, win->maximize.x2, win->maximize.y2, GUI_RED);
// Are we currently dragging? // Are we currently dragging?
if (dragging) { if (dragging) {
// Move window to new mouse location. // Move window to new mouse location.
win->base.r.x = event->x - dragOffset.x; windowMoveTo(win, event->x - dragOffset.x, event->y - dragOffset.y);
win->base.r.y = event->y - dragOffset.y;
break; break;
} else { // Dragging. } else { // Dragging.
@ -260,11 +393,10 @@ void wmPaint(EventT *event) {
if (event->flags & EVENT_FLAG_LEFT_DOWN) { if (event->flags & EVENT_FLAG_LEFT_DOWN) {
// Are we on the topmost window? // Are we on the topmost window?
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) {
//***TODO*** Are we inside the window content? Most likely, check first. //***TODO*** Are we inside the window content? Most likely, check first.
if (event->x <= (win->base.r.x + win->base.r.w - 1) && event->x >= win->base.r.x && if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
event->y <= (win->base.r.y + win->base.r.h - 1) && event->y >= win->base.r.y) {
//***TODO*** Send to window for processing. //***TODO*** Send to window for processing.
} }
@ -288,10 +420,13 @@ void wmPaint(EventT *event) {
if (i >= 0) { if (i >= 0) {
for (; i>=0; i--) { for (; i>=0; i--) {
win = _windowList[i]; win = _windowList[i];
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { // Get right/bottom of window.
x2 = win->base.r.x + win->base.r.w - 1;
y2 = win->base.r.y + win->base.r.h - 1;
// Inside this window?
if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) {
// Bring this window forward. // Bring this window forward.
arrdel(_windowList, i); windowFocusSet(win);
arrput(_windowList, win);
// If we happened to be in the title bar, go ahead and start dragging. // If we happened to be in the title bar, go ahead and start dragging.
if (event->x <= win->titlebar.x2 && event->x >= win->titlebar.x && event->y <= win->titlebar.y2 && event->y >= win->titlebar.y) { if (event->x <= win->titlebar.x2 && event->x >= win->titlebar.x && event->y <= win->titlebar.y2 && event->y >= win->titlebar.y) {
dragging = 1; dragging = 1;

View file

@ -13,22 +13,25 @@
typedef struct WindowS { typedef struct WindowS {
WidgetT base; WidgetT base; // Required by all widgets.
char *title; char *title; // Title of window.
uint8_t flags; uint8_t flags; // Window flags (see defines above).
RectT close; RectT close; // Coordinates of close box, if any.
RectT titlebar; RectT titlebar; // Coordinates of title bar, if any.
RectT minimize; RectT minimize; // Coordinates of minimize box, if any.
RectT maximize; RectT maximize; // Coordinates of maximize box, if any.
RectT bounds; RectT bounds; // Inside edge of window frame.
SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing.
} WindowT; } WindowT;
extern uint8_t __MAGIC_WINDOW; extern uint8_t __MAGIC_WINDOW; // Magic ID assigned to us from the GUI.
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, uint8_t flags, ...); WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, uint8_t flags, ...);
void windowDestroy(struct WidgetS *widget, ...); void windowDestroy(struct WidgetS *widget, ...);
void windowFocusSet(WindowT *win);
void windowMoveTo(WindowT *win, uint16_t x, uint16_t y);
void windowPaint(struct WidgetS *widget, ...); void windowPaint(struct WidgetS *widget, ...);
RegisterT *windowRegister(uint8_t magic); RegisterT *windowRegister(uint8_t magic);

View file

@ -25,3 +25,61 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
/*
int tui(int argc, char *argv[]) {
EventT event = { 0 };
uint16_t x = 5;
uint16_t y = 5;
uint16_t tx;
uint16_t ty;
FontT *vga8x16 = NULL;
FontT *vga8x8 = NULL;
(void)argc;
memoryStartup(argv[0]);
logOpenByHandle(memoryLogHandleGet());
if (guiStartup(800, 600, 32) == SUCCESS) {
vga8x8 = fontLoad("vga8x8.dat");
vga8x16 = fontLoad("vga8x16.dat");
// Run until keypress.
while (1) {
// Paint desktop.
surfaceSet(__guiBackBuffer);
surfaceClear(GUI_CYAN);
// Paint GUI.
ty = y;
fontSet(vga8x16);
fontRender("\x1\xf\x2\x8 Title Bar _ \xfe X ", C(x), C(ty++)); ty++;
fontSet(vga8x8);
fontRender("\x2\x7\xda\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xbf\x1e", C(x), C(ty++));
for (tx=0; tx<10; tx++) fontRender("\xb3 \xb3\xb0", C(x), C(ty++));
fontRender("\xc0\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xd9\x1f", C(x), C(ty++));
fontRender("\x11\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\x10\xfe", C(x), C(ty++));
// Copy to screen.
videoBlit(0, 0, __guiBackBuffer);
// Check for exit.
platformEventGet(&event);
if (event.flags & EVENT_FLAG_KEYPRESS && event.key == KEY_ESC) break;
}
fontUnload(&vga8x16);
fontUnload(&vga8x8);
guiShutdown();
}
logClose();
memoryShutdown();
return 0;
}
*/

View file

@ -187,18 +187,22 @@ void platformEventGet(EventT *event) {
int16_t meta = bioskey(KEYBOARD_META_EXTENDED); int16_t meta = bioskey(KEYBOARD_META_EXTENDED);
int16_t key = 0; int16_t key = 0;
union REGS regs; union REGS regs;
static int32_t lastX = 0;
static int32_t lastY = 0;
// Read mouse motion. // Read mouse motion.
regs.x.ax = MOUSE_GETMOTION; regs.x.ax = MOUSE_GETMOTION;
int86(MOUSE_INT, &regs, &regs); int86(MOUSE_INT, &regs, &regs);
dx = regs.x.cx; // Temporary assignment changes values to signed. dx = regs.x.cx; // Temporary assignment changes values to signed.
dy = regs.x.dx; // Don't skip this step. :-) dy = regs.x.dx; // Don't skip this step. :-)
x = event->x + dx; x = lastX + dx;
y = event->y + dy; y = lastY + dy;
if (x < 0) x = 0; if (x < 0) x = 0;
if (x > w - 1) x = w - 1; if (x > w - 1) x = w - 1;
if (y < 0) y = 0; if (y < 0) y = 0;
if (y > h - 1) y = h - 1; if (y > h - 1) y = h - 1;
lastX = x;
lastY = y;
event->x = x; event->x = x;
event->y = y; event->y = y;

View file

@ -1,7 +1,7 @@
#ifdef BACKEND_SDL2 #ifdef BACKEND_SDL2
#include "sdl2.h" #include <SDL2/SDL.h>
#include "platform.h" #include "platform.h"
@ -104,7 +104,7 @@ void platformShutdown(void) {
} }
void platformStartup(int16_t width, int16_t height, int16_t depth) { uint8_t platformStartup(int16_t width, int16_t height, int16_t depth) {
SDL_PixelFormatEnum pixelFormat; SDL_PixelFormatEnum pixelFormat;
(void)depth; (void)depth;
@ -159,6 +159,8 @@ void platformStartup(int16_t width, int16_t height, int16_t depth) {
_height = height; _height = height;
surfaceStartup(depth); surfaceStartup(depth);
return SUCCESS;
} }