summaryrefslogtreecommitdiff
path: root/src/gfx/sdl-1.2
diff options
context:
space:
mode:
Diffstat (limited to 'src/gfx/sdl-1.2')
-rw-r--r--src/gfx/sdl-1.2/CMakeLists.txt19
-rw-r--r--src/gfx/sdl-1.2/include/gfx/port.h58
-rw-r--r--src/gfx/sdl-1.2/private_include/gfx/private.h26
-rw-r--r--src/gfx/sdl-1.2/src/CMakeLists.txt23
-rw-r--r--src/gfx/sdl-1.2/src/env.c204
-rw-r--r--src/gfx/sdl-1.2/src/line.c16
-rw-r--r--src/gfx/sdl-1.2/src/quad.c44
-rw-r--r--src/gfx/sdl-1.2/src/rect.c35
-rw-r--r--src/gfx/sdl-1.2/src/sprite.c143
9 files changed, 568 insertions, 0 deletions
diff --git a/src/gfx/sdl-1.2/CMakeLists.txt b/src/gfx/sdl-1.2/CMakeLists.txt
new file mode 100644
index 0000000..11d2245
--- /dev/null
+++ b/src/gfx/sdl-1.2/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wanix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(src)
+target_include_directories(gfx PUBLIC include PRIVATE private_include)
+target_link_libraries(gfx PUBLIC SDL::SDL PRIVATE SDL::SDL_gfx)
diff --git a/src/gfx/sdl-1.2/include/gfx/port.h b/src/gfx/sdl-1.2/include/gfx/port.h
new file mode 100644
index 0000000..bf94a38
--- /dev/null
+++ b/src/gfx/sdl-1.2/include/gfx/port.h
@@ -0,0 +1,58 @@
+#ifndef GFX_SDL_H
+#define GFX_SDL_H
+
+#include <SDL.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct gfx_sprite
+{
+ SDL_Surface *s, *s_x;
+ short x, y, w, h;
+ unsigned char u, v;
+ bool transparent;
+};
+
+struct quad
+{
+ unsigned char r, g, b;
+ short x0, x1, x2, x3;
+ short y0, y1, y2, y3;
+ unsigned char u0, u1, u2, u3;
+ unsigned char v0, v1, v2, v3;
+ short w, h;
+ bool transparent;
+ SDL_Surface *s, *s_x;
+};
+
+struct gfx_rect
+{
+ unsigned char r, g, b;
+ short x, y, w, h;
+ bool stp;
+};
+
+struct stp_4line
+{
+ short x, y;
+ unsigned char r, g, b;
+
+ struct stp_4line_vtx
+ {
+ unsigned char r, g, b;
+ short x, y;
+ } vertices[4];
+};
+
+#define common_get_or_ret(t, x, ret) \
+ struct t x##__, *const x = &x##__
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_SDL_H */
diff --git a/src/gfx/sdl-1.2/private_include/gfx/private.h b/src/gfx/sdl-1.2/private_include/gfx/private.h
new file mode 100644
index 0000000..e1af764
--- /dev/null
+++ b/src/gfx/sdl-1.2/private_include/gfx/private.h
@@ -0,0 +1,26 @@
+#ifndef GFX_SDL_12_PRIVATE_H
+#define GFX_SDL_12_PRIVATE_H
+
+#include <gfx/gfx.h>
+#include <SDL.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum
+{
+ SCREEN_W = 320,
+ SCREEN_H = 240
+};
+
+int sprite_screen_resize_ev(struct gfx_sprite *s);
+void gfx_register_sprite(struct gfx_sprite *s);
+SDL_Surface *gfx_screen(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_SDL_12_PRIVATE_H */
diff --git a/src/gfx/sdl-1.2/src/CMakeLists.txt b/src/gfx/sdl-1.2/src/CMakeLists.txt
new file mode 100644
index 0000000..4cef50b
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wanix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ env.c
+ line.c
+ quad.c
+ rect.c
+ sprite.c
+)
diff --git a/src/gfx/sdl-1.2/src/env.c b/src/gfx/sdl-1.2/src/env.c
new file mode 100644
index 0000000..2a51b97
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/env.c
@@ -0,0 +1,204 @@
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int screen_w = SCREEN_W, screen_h = SCREEN_H;
+static bool fullscreen;
+static SDL_Surface *screen;
+static struct gfx_sprite **list;
+static size_t list_len;
+
+void gfx_deinit(void)
+{
+ /* screen should be already freed by SDL_Quit. */
+ free(list);
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+static struct
+{
+ int w, h;
+} display, windowed;
+
+void gfx_register_sprite(struct gfx_sprite *const s)
+{
+ list = realloc(list, (list_len + 1) * sizeof *list);
+
+ if (list)
+ list[list_len++] = s;
+}
+
+static int resize_screen(int w, int h, const bool full_screen)
+{
+ Uint32 flags = SDL_HWSURFACE | SDL_RESIZABLE | SDL_ANYFORMAT | SDL_DOUBLEBUF;
+
+ const SDL_VideoInfo *const info = SDL_GetVideoInfo();
+
+ if (!info)
+ {
+ fprintf(stderr, "SDL_GetVideoInfo: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ static bool init;
+
+ if (!init)
+ {
+ display.w = info->current_w;
+ display.h = info->current_h;
+ init = true;
+ }
+
+ if (fullscreen)
+ {
+ flags |= SDL_FULLSCREEN;
+ w = display.w;
+ h = display.h;
+ }
+ else
+ {
+ windowed.w = w;
+ windowed.h = h;
+ }
+
+ int bpp = info->vfmt->BitsPerPixel;
+
+ if (screen)
+ SDL_FreeSurface(screen);
+
+ const int max_bpp = SDL_VideoModeOK(w, h, 0, flags);
+
+ if (max_bpp < 0)
+ {
+ fprintf(stderr, "SDL_VideoModeOK: %s\n", SDL_GetError());
+ return -1;
+ }
+ else if (bpp > max_bpp)
+ bpp = max_bpp;
+
+ if (!(screen = SDL_SetVideoMode(w, h, 0, flags)))
+ {
+ fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ for (size_t i = 0; i < list_len; i++)
+ if (sprite_screen_resize_ev(list[i]))
+ return -1;
+
+ screen_w = w;
+ screen_h = h;
+ fullscreen = full_screen;
+ return 0;
+}
+
+SDL_Surface *gfx_screen(void)
+{
+ return screen;
+}
+
+int gfx_display_size(short *const w, short *const h)
+{
+ *w = display.w;
+ *h = display.h;
+ return 0;
+}
+
+int gfx_init(void)
+{
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO))
+ {
+ fprintf(stderr, "%s: SDL_InitSubSystem: %s\n",
+ __func__, SDL_GetError());
+ return -1;
+ }
+
+ return resize_screen(screen_w, screen_h, fullscreen);
+}
+
+bool gfx_inside_drawenv(const short x, const short y, const short w,
+ const short h)
+{
+ return (x + w >= 0)
+ && x < screen_w
+ && (y + h >= 0)
+ && y < screen_h;
+}
+
+static int get_resize_events(void)
+{
+ int n;
+ SDL_Event ev;
+
+ while ((n = SDL_PeepEvents(&ev, 1, SDL_GETEVENT,
+ SDL_VIDEORESIZEMASK)) > 0)
+ {
+ if (ev.type == SDL_VIDEORESIZE)
+ {
+ const SDL_ResizeEvent *const res = &ev.resize;
+
+ if (resize_screen(res->w, res->h, false))
+ return -1;
+ }
+ }
+
+ if (n < 0)
+ {
+ fprintf(stderr, "%s: SDL_PeepEvents: %s\n",
+ __func__, SDL_GetError());
+ return -1;
+ }
+
+ return 0;
+}
+
+int gfx_toggle_fullscreen(void)
+{
+ fullscreen ^= true;
+
+ const int w = fullscreen ? display.w : windowed.w;
+ const int h = fullscreen ? display.h : windowed.h;
+
+ return resize_screen(w, h, fullscreen);
+}
+
+int gfx_set_fullscreen(const short w, const short h)
+{
+ return resize_screen(display.w = w, display.h = h, fullscreen = true);
+}
+
+bool gfx_fullscreen_available(void)
+{
+ return true;
+}
+
+bool gfx_fullscreen(void)
+{
+ return fullscreen;
+}
+
+int gfx_draw(void)
+{
+ enum {FPS = 50, REFRESH_MS = 1000 / FPS};
+ static Uint32 prev;
+ const Uint32 cur = SDL_GetTicks();
+
+ if (cur - prev < REFRESH_MS)
+ SDL_Delay(REFRESH_MS - (cur - prev));
+
+ prev = SDL_GetTicks();
+
+ if (SDL_Flip(screen))
+ {
+ fprintf(stderr, "SDL_Flip: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ get_resize_events();
+ return 0;
+}
diff --git a/src/gfx/sdl-1.2/src/line.c b/src/gfx/sdl-1.2/src/line.c
new file mode 100644
index 0000000..b06a414
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/line.c
@@ -0,0 +1,16 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <stddef.h>
+
+void stp_4line_init(struct stp_4line *const l)
+{
+}
+
+void semitrans_stp_4line_init(struct stp_4line *r)
+{
+}
+
+void stp_4line_sort(struct stp_4line *const r)
+{
+}
diff --git a/src/gfx/sdl-1.2/src/quad.c b/src/gfx/sdl-1.2/src/quad.c
new file mode 100644
index 0000000..1617a8b
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/quad.c
@@ -0,0 +1,44 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int quad_from_sprite(const struct gfx_sprite *const s, struct quad *const q)
+{
+ q->s = s->s;
+ q->s_x = s->s_x;
+ q->u0 = q->u2 = s->u;
+ q->v0 = q->v1 = s->v;
+ q->u1 = q->u3 = s->u + s->w - 1;
+ q->v2 = q->v3 = s->v + s->h - 1;
+ q->w = s->w;
+ q->h = s->h;
+ return 0;
+}
+
+void quad_sort(struct quad *const q)
+{
+ const bool xflip = q->x0 > q->x1;
+
+ SDL_Rect r =
+ {
+ .x = xflip ? q->x1 : q->x0,
+ .y = q->y0
+ };
+
+ const short w = q->u1 - q->u0 + 1, h = q->v2 - q->v0 + 1;
+
+ SDL_Rect clip =
+ {
+ .x = xflip ? q->w - q->u0 - w: q->u0,
+ .y = q->v0,
+ .w = w,
+ .h = h
+ };
+
+ SDL_Surface *const s = xflip ? q->s_x : q->s;
+
+ if (SDL_BlitSurface(s, &clip, gfx_screen(), &r))
+ fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
+}
diff --git a/src/gfx/sdl-1.2/src/rect.c b/src/gfx/sdl-1.2/src/rect.c
new file mode 100644
index 0000000..57a2ab3
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/rect.c
@@ -0,0 +1,35 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+
+void gfx_rect_sort(struct gfx_rect *const r)
+{
+ SDL_Rect rct =
+ {
+ .x = r->x,
+ .y = r->y,
+ .w = r->w,
+ .h = r->h
+ };
+
+ SDL_Surface *const screen = gfx_screen();
+ const Uint32 map = SDL_MapRGB(screen->format, r->r, r->g, r->b);
+
+ if (SDL_FillRect(screen, &rct, map))
+ {
+ fprintf(stderr, "SDL_FillRect: %s\n", SDL_GetError());
+ return;
+ }
+}
+
+void gfx_rect_init(struct gfx_rect *const r)
+{
+ *r = (const struct gfx_rect){0};
+}
+
+void semitrans_rect_init(struct gfx_rect *const r)
+{
+ gfx_rect_init(r);
+ r->stp = true;
+}
diff --git a/src/gfx/sdl-1.2/src/sprite.c b/src/gfx/sdl-1.2/src/sprite.c
new file mode 100644
index 0000000..086e2b5
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/sprite.c
@@ -0,0 +1,143 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <header.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+#include <SDL_rotozoom.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void sprite_free(struct gfx_sprite *const s)
+{
+ if (s && s->s)
+ SDL_FreeSurface(s->s);
+}
+
+int sprite_clone(const struct gfx_sprite *const src, struct gfx_sprite *const dst)
+{
+ *dst = *src;
+ return 0;
+}
+
+static int set_transparent(SDL_Surface *const s)
+{
+ /* Magenta as transparent. */
+ const Uint32 map = SDL_MapRGB(s->format, 255, 0, 255);
+ const int ret = SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, map);
+
+ if (ret)
+ fprintf(stderr, "SDL_SetColorKey: %s\n", SDL_GetError());
+
+ return ret;
+}
+
+int sprite_screen_resize_ev(struct gfx_sprite *const s)
+{
+ int ret = -1;
+ SDL_Surface *const old = s->s, *const old_x = s->s_x;
+
+ if (s->transparent && (set_transparent(old) || set_transparent(old_x)))
+ goto end;
+ else if (!(s->s = SDL_DisplayFormat(old)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(s->s_x = SDL_DisplayFormat(old_x)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ SDL_FreeSurface(old);
+ SDL_FreeSurface(old_x);
+ return ret;
+}
+
+static int load_header(struct gfx_sprite *const s, FILE *const f)
+{
+ if (header_load_bool(f, "transparent", &s->transparent))
+ return -1;
+
+ return 0;
+}
+
+static int load_bitmap(struct gfx_sprite *const s, FILE *const f)
+{
+ int ret = -1;
+ SDL_RWops *ops = NULL;
+ SDL_Surface *ts = NULL, *zs = NULL;
+
+ if (!(ops = SDL_RWFromFP(f, 0)))
+ {
+ fprintf(stderr, "SDL_RWFromFP: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(ts = SDL_LoadBMP_RW(ops, 0)))
+ {
+ fprintf(stderr, "SDL_LoadBMP_RW: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(zs = zoomSurface(ts, -1, 1, 0)))
+ {
+ fprintf(stderr, "zoomSurface: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (s->transparent && (set_transparent(ts) || set_transparent(zs)))
+ goto end;
+ else if (!(s->s = SDL_DisplayFormat(ts)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(s->s_x = SDL_DisplayFormat(zs)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+
+ gfx_register_sprite(s);
+ s->w = ts->w;
+ s->h = ts->h;
+ ret = 0;
+
+end:
+ SDL_FreeRW(ops);
+ SDL_FreeSurface(ts);
+ SDL_FreeSurface(zs);
+ return ret;
+}
+
+int sprite_from_fp(struct gfx_sprite *const s, FILE *const f)
+{
+ *s = (const struct gfx_sprite){0};
+
+ if (load_header(s, f) || load_bitmap(s, f))
+ return -1;
+
+ return 0;
+}
+
+void sprite_sort(struct gfx_sprite *const s)
+{
+ SDL_Rect r =
+ {
+ .x = s->x,
+ .y = s->y
+ };
+
+ SDL_Rect clip =
+ {
+ .x = s->u,
+ .y = s->v,
+ .w = s->w,
+ .h = s->h
+ };
+
+ if (SDL_BlitSurface(s->s, &clip, gfx_screen(), &r))
+ fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
+}