diff options
Diffstat (limited to 'src/gfx')
36 files changed, 1891 insertions, 0 deletions
diff --git a/src/gfx/CMakeLists.txt b/src/gfx/CMakeLists.txt new file mode 100644 index 0000000..acb07d2 --- /dev/null +++ b/src/gfx/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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_library(gfx) +add_subdirectory(src) +target_include_directories(gfx PUBLIC include) + +if(PS1_BUILD) + add_subdirectory(ps1) +elseif(SDL1_2_BUILD) + add_subdirectory(sdl-1.2) +endif() diff --git a/src/gfx/include/gfx/gfx.h b/src/gfx/include/gfx/gfx.h new file mode 100644 index 0000000..95c602a --- /dev/null +++ b/src/gfx/include/gfx/gfx.h @@ -0,0 +1,48 @@ +/* + * 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/>. + */ + +#ifndef GFX_H +#define GFX_H + +#include <gfx/port.h> +#include <stdbool.h> +#include <stdio.h> + +int gfx_init(void); +int gfx_draw(void); +bool gfx_ready(void); +int gfx_toggle_fullscreen(void); +int gfx_set_fullscreen(short w, short h); +bool gfx_fullscreen_available(void); +bool gfx_fullscreen(void); +int gfx_display_size(short *w, short *h); + +void gfx_rect_init(struct gfx_rect *r); +void semitrans_rect_init(struct gfx_rect *r); +void stp_4line_init(struct stp_4line *l); +void quad_sort(struct quad *q); +void gfx_rect_sort(struct gfx_rect *r); +void stp_4line_sort(struct stp_4line *l); +int sprite_from_fp(struct gfx_sprite *s, FILE *f); +int quad_from_sprite(const struct gfx_sprite *s, struct quad *q); +bool gfx_inside_drawenv(short x, short y, short w, short h); +void gfx_deinit(void); + +extern int screen_w, screen_h; + +#endif /* GFX_H */ diff --git a/src/gfx/include/gfx/sprite.h b/src/gfx/include/gfx/sprite.h new file mode 100644 index 0000000..9746524 --- /dev/null +++ b/src/gfx/include/gfx/sprite.h @@ -0,0 +1,32 @@ +/* + * 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/>. + */ + +#ifndef GFX_SPRITE_H +#define GFX_SPRITE_H + +#include <gfx/port.h> +#include <stddef.h> + +typedef int (*gfx_read)(void *buf, size_t n, void *args); + +int gfx_sprite_load(struct gfx_sprite *s, gfx_read r, void *args); +int gfx_sprite_sort(struct gfx_sprite *s); +int gfx_sprite_clone(const struct gfx_sprite *src, struct gfx_sprite *dst); +void gfx_sprite_free(struct gfx_sprite *s); + +#endif diff --git a/src/gfx/ps1/CMakeLists.txt b/src/gfx/ps1/CMakeLists.txt new file mode 100644 index 0000000..1de20a7 --- /dev/null +++ b/src/gfx/ps1/CMakeLists.txt @@ -0,0 +1,40 @@ +# 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 PRIVATE + drv_ps1_bios + drv_ps1_dma + drv_ps1_interrupt + drv_ps1_gpu +) + +set(modes VMODE_PAL VMODE_NTSC) + +if(VIDEO_MODE) + if(NOT "${VIDEO_MODE}" IN_LIST modes) + message(FATAL_ERROR "Invalid video mode ${VIDEO_MODE}. Available options:\n" + "${modes}\n" + "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL") + endif() + + target_compile_definitions(gfx PRIVATE VIDEO_MODE=${VIDEO_MODE}) +else() + message(FATAL_ERROR "Please define video mode. Available options:\n" + "${modes}\n" + "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL") +endif() diff --git a/src/gfx/ps1/include/gfx/port.h b/src/gfx/ps1/include/gfx/port.h new file mode 100644 index 0000000..2e609d1 --- /dev/null +++ b/src/gfx/ps1/include/gfx/port.h @@ -0,0 +1,126 @@ +/* + * 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/>. + */ + +#ifndef GFX_PS1_H +#define GFX_PS1_H + +#include <stdint.h> + +union gfx_common +{ + struct + { + uint32_t tpagex :4, tpagey :1, stp :2, bpp :2, dither :1, + draw_to_disp :1, disable :1, xflip :1, yflip :1, :10; + uint8_t cmd; + } f; + + uint32_t mask; +}; + +union gfx_sznext +{ + struct + { + uint32_t next :24, sz :8; + } f; + + uint32_t cmd_next; +}; + +struct gfx_sprite +{ + union gfx_sznext sznext; + union gfx_common common; + uint8_t r, g, b; + uint8_t cmd; + int16_t x, y; + uint8_t u, v; + uint16_t clutid; + uint16_t w, h; +}; + +struct quad +{ + union gfx_sznext sznext; + uint8_t r, g, b; + uint8_t cmd; + int16_t x0, y0; + uint8_t u0, v0; + uint16_t clutid; + int16_t x1, y1; + uint8_t u1, v1; + + union + { + struct + { + /* 0-8 Same as GP0(E1h).Bit0-8. */ + uint16_t lb :9; + uint16_t :2; + /* 11 Same as GP0(E1h).Bit11. */ + uint16_t hb :1; + uint16_t :4; + } bit; + + uint16_t mask; + } tpage; + + int16_t x2, y2; + uint8_t u2, v2; + uint16_t :16; + int16_t x3, y3; + uint8_t u3, v3; + uint16_t :16; +}; + +struct gfx_rect +{ + union gfx_sznext sznext; + union gfx_common common; + uint8_t r, g, b; + uint8_t cmd; + int16_t x, y; + uint16_t w, h; +}; + +struct stp_4line +{ + union gfx_sznext sznext; + union gfx_common common; + uint8_t r, g, b; + uint8_t cmd; + int16_t x, y; + + struct stp_4line_vtx + { + uint32_t r :8, g :8, b :8, :8; + int16_t x, y; + } vertices[4]; + + uint32_t end; +}; + +void gfx_add_to_list(union gfx_sznext *p); +void *gfx_heap_top(void); +struct gfx_sprite *gfx_sprite_get(void); +struct quad *quad_get(void); +struct gfx_rect *rect_get(void); +struct stp_4line *stp_4line_get(void); + +#endif diff --git a/src/gfx/ps1/private_include/gfx/private.h b/src/gfx/ps1/private_include/gfx/private.h new file mode 100644 index 0000000..72d8f39 --- /dev/null +++ b/src/gfx/ps1/private_include/gfx/private.h @@ -0,0 +1,19 @@ +#ifndef GFX_PS1_PRIVATE_H +#define GFX_PS1_PRIVATE_H + +#include <gfx/gfx.h> + +enum +{ + SCREEN_W = 640, + SCREEN_H = 480 +}; + +void gfx_swapheap(void); +void gfx_initenvs(void); +void gfx_swapbuffers(void); +void gfx_swapenvs(void); + +extern int gfx_vblank_ev; + +#endif diff --git a/src/gfx/ps1/src/4line.c b/src/gfx/ps1/src/4line.c new file mode 100644 index 0000000..766eb2d --- /dev/null +++ b/src/gfx/ps1/src/4line.c @@ -0,0 +1,15 @@ +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <psxgpu.h> +#include <stdint.h> +#include <string.h> + +void stp_4line_init(struct stp_4line *const l) +{ + memset(l, 0, sizeof *l); + l->sznext.f.sz = (sizeof *l - sizeof l->sznext) / sizeof (uint32_t); + l->common.f.cmd = DRAW_MODE; + l->cmd = 0x5A; + enum {TERMINATION_CODE = 0x55555555}; + l->end = TERMINATION_CODE; +} diff --git a/src/gfx/ps1/src/CMakeLists.txt b/src/gfx/ps1/src/CMakeLists.txt new file mode 100644 index 0000000..418bd3b --- /dev/null +++ b/src/gfx/ps1/src/CMakeLists.txt @@ -0,0 +1,32 @@ +# 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 + # 4line.c + # env.c + draw.c + heap.c + init.c + ready.c + swapenvs.c + # quad.c + # rect.c + # sort.c + # sprite.c + vblank.c +) + +add_subdirectory(sprite) diff --git a/src/gfx/ps1/src/add_to_list.c b/src/gfx/ps1/src/add_to_list.c new file mode 100644 index 0000000..dff4910 --- /dev/null +++ b/src/gfx/ps1/src/add_to_list.c @@ -0,0 +1,39 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <stddef.h> +#include <stdint.h> + +static union gfx_sznext *first, *last; + +void gfx_add_to_list(union gfx_sznext *const p) +{ + if (!first) + first = p; + else if (last) + last->f.next = (uint32_t)p; + + last = p; +} + +void *gfx_heap_top(void) +{ + return first; +} diff --git a/src/gfx/ps1/src/deinit.c b/src/gfx/ps1/src/deinit.c new file mode 100644 index 0000000..ccf6c2d --- /dev/null +++ b/src/gfx/ps1/src/deinit.c @@ -0,0 +1,24 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> + +void gfx_deinit(void) +{ +} diff --git a/src/gfx/ps1/src/draw.c b/src/gfx/ps1/src/draw.c new file mode 100644 index 0000000..40abdf7 --- /dev/null +++ b/src/gfx/ps1/src/draw.c @@ -0,0 +1,70 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <drv/ps1/dma.h> +#include <drv/ps1/gpu.h> + +static union gfx_sznext *first, *last; + +void gfx_add_to_list(union gfx_sznext *const p) +{ + if (!first) + first = p; + else if (last) + last->f.next = (uint32_t)p; + + last = p; +} + +int gfx_draw(void) +{ + static union gfx_sznext term = {.cmd_next = 0xffffff}; + + gfx_add_to_list(&term); + + if (SCREEN_W != 640) + gfx_swapenvs(); + + gfx_swapheap(); + + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .dma = + { + .cmd = GP1_DMA_DIR, + .dir = GP1_DMA_DIR_CPU_TO_GP0 + } + }.mask; + + D2_MADR->mask = (uint32_t)first; + D2_BCR->syncmode_2.reserved = 0; + D2_CHCR->mask = (const union chcr) + { + .bits = + { + .sync_mode = CHCR_SYNC_MODE_LINKED_LIST, + .dir = CHCR_DIR_FROM_RAM, + .start_busy = 1 + } + }.mask; + + first = NULL; + return 0; +} diff --git a/src/gfx/ps1/src/env.c b/src/gfx/ps1/src/env.c new file mode 100644 index 0000000..100f366 --- /dev/null +++ b/src/gfx/ps1/src/env.c @@ -0,0 +1,71 @@ +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <psxgpu.h> +#include <errno.h> +#include <stdbool.h> + +static GsDispEnv dispenv; +enum {ENV_Y = SCREEN_H + 16}; + +static GsDrawEnv drawenv = +{ + .y = ENV_Y, + .w = SCREEN_W, + .h = SCREEN_H +}; + +int screen_w = SCREEN_W, screen_h = SCREEN_H; + +void gfx_swapbuffers(void) +{ + const short y = drawenv.y; + + drawenv.y = dispenv.y; + dispenv.y = y; + GsSetDrawEnv(&drawenv); + GsSetDispEnv(&dispenv); +} + +void gfx_initenvs(void) +{ + GsSetDrawEnv(&drawenv); + GsSetDispEnv(&dispenv); +} + +int gfx_toggle_fullscreen(void) +{ + errno = ENOTSUP; + return -1; +} + +int gfx_set_fullscreen(const short w, const short h) +{ + errno = ENOTSUP; + return -1; +} + +bool gfx_fullscreen_available(void) +{ + return false; +} + +bool gfx_fullscreen(void) +{ + return true; +} + +int gfx_display_size(short *const w, short *const h) +{ + *w = SCREEN_W; + *h = SCREEN_H; + return 0; +} + +bool gfx_inside_drawenv(const short x, const short y, const short w, + const short h) +{ + return (x + w >= 0) + && x < drawenv.w + && (y + h >= 0) + && y < drawenv.h; +} diff --git a/src/gfx/ps1/src/heap.c b/src/gfx/ps1/src/heap.c new file mode 100644 index 0000000..feb95c9 --- /dev/null +++ b/src/gfx/ps1/src/heap.c @@ -0,0 +1,73 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <stddef.h> + +static unsigned int sel; +static size_t heap_i; + +void gfx_swapheap(void) +{ + sel ^= 1; + heap_i = 0; +} + +static void *get_element(const size_t sz) +{ + enum {HEAP_SZ = 49152, N_HEAPS = 2}; + static char heaps[N_HEAPS][HEAP_SZ]; + const size_t new_sz = heap_i + sz; + void *ret = NULL; + + if (new_sz < sizeof *heaps / sizeof **heaps) + { + ret = &heaps[sel][heap_i]; + heap_i += sz; + } + else + { + static volatile int a; + + a++; + return NULL; + } + + return ret; +} + +struct gfx_sprite *gfx_sprite_get(void) +{ + return get_element(sizeof (struct gfx_sprite)); +} + +struct quad *quad_get(void) +{ + return get_element(sizeof (struct quad)); +} + +struct gfx_rect *rect_get(void) +{ + return get_element(sizeof (struct gfx_rect)); +} + +struct stp_4line *stp_4line_get(void) +{ + return get_element(sizeof (struct stp_4line)); +} diff --git a/src/gfx/ps1/src/init.c b/src/gfx/ps1/src/init.c new file mode 100644 index 0000000..3a94f32 --- /dev/null +++ b/src/gfx/ps1/src/init.c @@ -0,0 +1,153 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <drv/ps1/bios.h> +#include <drv/ps1/dma.h> +#include <drv/ps1/gpu.h> +#include <drv/ps1/interrupt.h> +#include <stddef.h> + +struct res +{ + int hres, hres2, vres, interlace; +}; + +static void getres(const short w, struct res *const r) +{ + *r = (const struct res){0}; + + switch (w) + { + case 320: + r->hres = 1; + break; + case 368: + r->hres2 = 1; + break; + case 512: + r->hres = 2; + break; + case 640: + r->hres = 3; + r->vres = 1; + r->interlace = 1; + break; + } +} + +int gfx_init(void) +{ + const union dpcr dpcr = {.bits.gpu_en = 1}; + const int event = OpenEvent(CLASS_VBLANK, SPEC_INTERRUPTED, MODE_READY, + NULL); + + if (event == -1) + return -1; + + DPCR->mask |= dpcr.mask; + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .dma = + { + .cmd = GP1_DMA_DIR, + .dir = GP1_DMA_DIR_CPU_TO_GP0 + } + }.mask; + + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .display = + { + .cmd = GP1_DISPLAY_ENABLE, + } + }.mask; + + GP0->mask = (const union drv_ps1_gpu_gp0) + {.draw_mode.cmd = GP0_DRAW_MODE}.mask; + + GP0->mask = (const union drv_ps1_gpu_gp0) + {.tex_window.cmd = GP0_TEX_WINDOW}.mask; + + GP0->mask = (const union drv_ps1_gpu_gp0) + {.draw_area_tl.cmd = GP0_DRAW_AREA_TOP_LEFT}.mask; + + GP0->mask = (const union drv_ps1_gpu_gp0) + { + .draw_area_br = + { + .cmd = GP0_DRAW_AREA_BOTTOM_RIGHT, + .x = SCREEN_W - 1, + .y = SCREEN_H - 1, + } + }.mask; + + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .h_display_range = + { + .cmd = GP1_H_DISPLAY_RANGE, + .x1 = 0x260, + .x2 = 0x260 + 320 * 8 + } + }.mask; + +#if 0 + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .v_display_range = + { + .cmd = GP1_V_DISPLAY_RANGE, +#if VIDEO_MODE == VMODE_PAL + .y1 = 0xa3, + .y2 = 0xa3 + (SCREEN_H / 2) +#elif VIDEO_MODE == VMODE_NTSC + .y1 = 0x88 - (224 / 2), + .y2 = 0x88 + (224 / 2) +#endif + } + }.mask; +#else + GP1->mask = 0x06C4E24E; + GP1->mask = 0x07040010; +#endif + + struct res r; + + getres(SCREEN_W, &r); + + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .display_mode = + { + .cmd = GP1_DISPLAY_MODE, + .hres = r.hres, + .hres2 = r.hres2, + .vres = r.vres, + .vinterlace = r.interlace, +#if VIDEO_MODE == VMODE_PAL + .vmode = 1 +#endif + } + }.mask; + + I_MASK->bits.vblank = 1; + EnableEvent(gfx_vblank_ev = event); + return 0; +} diff --git a/src/gfx/ps1/src/quad.c b/src/gfx/ps1/src/quad.c new file mode 100644 index 0000000..bfabee2 --- /dev/null +++ b/src/gfx/ps1/src/quad.c @@ -0,0 +1,24 @@ +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <gfx/port.h> +#include <stdint.h> +#include <string.h> + +static void quad_init(struct quad *const q) +{ + memset(q, 0, sizeof *q); + q->sznext.f.sz = (sizeof *q - sizeof q->sznext) / sizeof (uint32_t); + q->cmd = 0x2d; +} + +int quad_from_sprite(const struct gfx_sprite *const s, struct quad *const q) +{ + quad_init(q); + q->tpage.mask = s->common.mask; + q->clutid = s->clutid; + 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; + return 0; +} diff --git a/src/gfx/ps1/src/ready.c b/src/gfx/ps1/src/ready.c new file mode 100644 index 0000000..0e17cdb --- /dev/null +++ b/src/gfx/ps1/src/ready.c @@ -0,0 +1,27 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <drv/ps1/bios.h> +#include <stdbool.h> + +bool gfx_ready(void) +{ + return TestEvent(gfx_vblank_ev); +} diff --git a/src/gfx/ps1/src/rect.c b/src/gfx/ps1/src/rect.c new file mode 100644 index 0000000..57b1b2a --- /dev/null +++ b/src/gfx/ps1/src/rect.c @@ -0,0 +1,25 @@ +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <psxgpu.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +static void common_init(struct gfx_rect *const r) +{ + memset(r, 0, sizeof *r); + r->sznext.f.sz = (sizeof *r - sizeof r->sznext) / sizeof (uint32_t); + r->common.f.cmd = DRAW_MODE; +} + +void gfx_rect_init(struct gfx_rect *const r) +{ + common_init(r); + r->cmd = 0x60; +} + +void semitrans_rect_init(struct gfx_rect *const r) +{ + common_init(r); + r->cmd = 0x62; +} diff --git a/src/gfx/ps1/src/sort.c b/src/gfx/ps1/src/sort.c new file mode 100644 index 0000000..5c1c278 --- /dev/null +++ b/src/gfx/ps1/src/sort.c @@ -0,0 +1,73 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <drv/ps1/bios.h> +#include <stddef.h> +#include <stdint.h> + +static union gfx_sznext *first, *last; + +static void add_to_list(union gfx_sznext *const p) +{ + if (!first) + first = p; + else if (last) + last->f.next = (uint32_t)p; + + last = p; +} + +void sprite_sort(struct gfx_sprite *const s) +{ + add_to_list(&s->sznext); +} + +void quad_sort(struct quad *const q) +{ + add_to_list(&q->sznext); +} + +void gfx_rect_sort(struct gfx_rect *const r) +{ + add_to_list(&r->sznext); +} + +void stp_4line_sort(struct stp_4line *const l) +{ + add_to_list(&l->sznext); +} + +int gfx_draw(void) +{ + static union gfx_sznext term = {.cmd_next = 0xffffff}; + + add_to_list(&term); + + void gpu_ctrl(unsigned int command, unsigned int param); + + gfx_swapbuffers(); + gfx_swapheap(); + gpu_ctrl(4, 2); + D2_MADR = (uint32_t)first; + D2_BCR = 0; + D2_CHCR = (1 << 0xa) | 1 | (1 << 0x18); + first = NULL; + return 0; +} diff --git a/src/gfx/ps1/src/sprite/CMakeLists.txt b/src/gfx/ps1/src/sprite/CMakeLists.txt new file mode 100644 index 0000000..b42d699 --- /dev/null +++ b/src/gfx/ps1/src/sprite/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 + clone.c + free.c + load.c + sort.c +) diff --git a/src/gfx/ps1/src/sprite/clone.c b/src/gfx/ps1/src/sprite/clone.c new file mode 100644 index 0000000..30d0d32 --- /dev/null +++ b/src/gfx/ps1/src/sprite/clone.c @@ -0,0 +1,26 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> + +int gfx_sprite_clone(const struct gfx_sprite *const src, + struct gfx_sprite *const dst) +{ + *dst = *src; + return 0; +} diff --git a/src/gfx/ps1/src/sprite/free.c b/src/gfx/ps1/src/sprite/free.c new file mode 100644 index 0000000..3b3d984 --- /dev/null +++ b/src/gfx/ps1/src/sprite/free.c @@ -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/>. + */ + +#include <gfx/gfx.h> + +void sprite_free(struct gfx_sprite *const src) +{ +} diff --git a/src/gfx/ps1/src/sprite/load.c b/src/gfx/ps1/src/sprite/load.c new file mode 100644 index 0000000..7664017 --- /dev/null +++ b/src/gfx/ps1/src/sprite/load.c @@ -0,0 +1,191 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/sprite.h> +#include <gfx/private.h> +#include <drv/ps1/gpu.h> +#include <stdint.h> + +static void init(struct gfx_sprite *const s) +{ + *s = (const struct gfx_sprite){0}; + s->sznext.f.sz = (sizeof *s - sizeof s->sznext) / sizeof (uint32_t); + s->common.f.cmd = GP0_DRAW_MODE; + s->cmd = GP0_TEXTRECT_VARSZ_OPAQ_RAW; +} + +struct tim_pos +{ + uint16_t x, y, w, h; +}; + +static void transfer_init(const struct tim_pos *const p) +{ + while (!GPUSTAT->bits.ready_cmd) + ; + + GP0->mask = (const union drv_ps1_gpu_gp0) + {.copy_rect.cmd = GP0_COPY_RECT_CPU_VRAM}.mask; + GP0->mask = (const union drv_ps1_gpu_gp0) + {.coord = {.x = p->x, .y = p->y}}.mask; + GP0->mask = (const union drv_ps1_gpu_gp0) + {.size = {.w = p->w, .h = p->h}}.mask; +} + +static int transfer(const size_t sz, const gfx_read r, void *const args) +{ + const size_t rem = sz % sizeof (uint32_t); + + if (sz >= sizeof (uint32_t)) + { + for (size_t i = 0; i < sz / sizeof (uint32_t); i++) + { + uint32_t pix; + + if (r(&pix, sizeof pix, args)) + return -1; + + GP0->mask = pix; + } + } + + if (rem) + { + uint32_t pix = 0; + + if (r(&pix, rem, args)) + return -1; + + GP0->mask = pix; + } + + return 0; +} + +struct header +{ + uint32_t sz; + struct tim_pos pos; +}; + +static short get_clutid(const short x, const short y) +{ + return (x & 0x3ff) >> 4 | (y & 0x1ff) << 6; +} + +static int upload_clut(struct gfx_sprite *const s, const gfx_read r, + void *const args) +{ + struct header clut; + + if (r(&clut, sizeof clut, args)) + return -1; + + transfer_init(&clut.pos); + + const size_t sz = clut.sz - sizeof clut; + + if (transfer(sz, r, args)) + return -1; + + s->clutid = get_clutid(clut.pos.x, clut.pos.y); + return 0; +} + +enum bpp +{ + BPP_4 = 0, + BPP_8 = 1, + BPP_16 = 2, + BPP_24 = 4 +}; + +static int upload_img(struct gfx_sprite *const s, const enum bpp bpp, + const gfx_read r, void *const args) +{ + struct header img; + + if (r(&img, sizeof img, args)) + return -1; + + transfer_init(&img.pos); + + const size_t sz = img.sz - sizeof img; + + if (transfer(sz, r, args)) + return -1; + + enum + { + VRAM_X = 1024, + VRAM_Y = 512, + TPAGE_WIDTH = 64 + }; + + s->common.f.tpagex = img.pos.x / TPAGE_WIDTH; + s->common.f.tpagey = img.pos.y / (VRAM_Y / 2); + s->u = img.pos.x % TPAGE_WIDTH; + s->v = img.pos.y % (VRAM_Y / 2); + + switch (bpp) + { + case BPP_4: + s->w = img.pos.w * 4; + s->u <<= 2; + break; + + case BPP_8: + s->w = img.pos.w * 2; + s->u <<= 1; + break; + + case BPP_16: + s->w = img.pos.w; + break; + + case BPP_24: + s->w = img.pos.w + (img.pos.w / 2); + break; + } + + s->h = img.pos.h; + return 0; +} + +int gfx_sprite_load(struct gfx_sprite *s, const gfx_read r, void *const args) +{ + init(s); + + struct + { + uint32_t version, bpp :3, has_clut :1, :28; + } h; + + enum {VERSION_ID = 0x10}; + + if (r(&h, sizeof h, args) + || h.version != VERSION_ID + || h.bpp == BPP_24 + || (h.has_clut && upload_clut(s, r, args)) + || upload_img(s, h.bpp, r, args)) + return -1; + + s->common.f.bpp = h.bpp ? __builtin_ctz(h.bpp) + 1 : 0; + return 0; +} diff --git a/src/gfx/ps1/src/sprite/sort.c b/src/gfx/ps1/src/sprite/sort.c new file mode 100644 index 0000000..76fc214 --- /dev/null +++ b/src/gfx/ps1/src/sprite/sort.c @@ -0,0 +1,26 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/port.h> + +int gfx_sprite_sort(struct gfx_sprite *const s) +{ + gfx_add_to_list(&s->sznext); + return 0; +} diff --git a/src/gfx/ps1/src/swapenvs.c b/src/gfx/ps1/src/swapenvs.c new file mode 100644 index 0000000..9e120ad --- /dev/null +++ b/src/gfx/ps1/src/swapenvs.c @@ -0,0 +1,58 @@ +/* + * 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/>. + */ + +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <drv/ps1/gpu.h> + +void gfx_swapenvs(void) +{ + static short dispenv, drawenv = 256; + const short y = dispenv; + + dispenv = drawenv; + drawenv = y; + + GP0->mask = (const union drv_ps1_gpu_gp0) + { + .draw_area_tl = + { + .cmd = GP0_DRAW_AREA_TOP_LEFT, + .y = drawenv + } + }.mask; + + GP0->mask = (const union drv_ps1_gpu_gp0) + { + .draw_area_br = + { + .cmd = GP0_DRAW_AREA_BOTTOM_RIGHT, + .x = SCREEN_W - 1, + .y = drawenv + SCREEN_H - 1, + } + }.mask; + + GP1->mask = (const union drv_ps1_gpu_gp1) + { + .disparea = + { + .cmd = GP1_START_DISPLAY_AREA, + .y = dispenv + } + }.mask; +} diff --git a/src/gfx/ps1/src/vblank.c b/src/gfx/ps1/src/vblank.c new file mode 100644 index 0000000..cc445c7 --- /dev/null +++ b/src/gfx/ps1/src/vblank.c @@ -0,0 +1,21 @@ +/* + * 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/>. + */ + +#include <gfx/private.h> + +int gfx_vblank_ev; 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()); +} diff --git a/src/gfx/src/CMakeLists.txt b/src/gfx/src/CMakeLists.txt new file mode 100644 index 0000000..3b3cac2 --- /dev/null +++ b/src/gfx/src/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/>. + +target_sources(gfx PRIVATE + dim.c +) diff --git a/src/gfx/src/dim.c b/src/gfx/src/dim.c new file mode 100644 index 0000000..674da9c --- /dev/null +++ b/src/gfx/src/dim.c @@ -0,0 +1,21 @@ +/* + * 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/>. + */ + +#include <gfx/private.h> + +int screen_w = SCREEN_W, screen_h = SCREEN_H; |
