From 6d171f55b8774a864d910f85d5afdd55a2a97c50 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:13:39 +0000 Subject: [PATCH 01/21] restore linux sdl1 for debuging purposes --- Makefile | 16 + src/sdl/sdl.c | 789 +++++++++++++++++++++++++++++++++++++++++++++++++ src/unix/osd.c | 310 +++++++++++++++++++ 3 files changed, 1115 insertions(+) create mode 100644 Makefile create mode 100644 src/sdl/sdl.c create mode 100644 src/unix/osd.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ffb004e --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +CC = gcc +CFLAGS = -m64 -Werror=implicit-function-declaration -fstack-protector-all -fstack-protector-strong -fstack-check -Wall -lm -lSDL -O0 -g3 -I $(shell realpath src) +SRC = $(shell find src -name "*.c" ) +OBJ = $(SRC:.c=.o) + +all: linux_nofrendo + +linux_nofrendo: $(OBJ) + $(CC) $(CFLAGS) -o $@ $(OBJ) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJ) linux_nofrendo + diff --git a/src/sdl/sdl.c b/src/sdl/sdl.c new file mode 100644 index 0000000..b6b9ca8 --- /dev/null +++ b/src/sdl/sdl.c @@ -0,0 +1,789 @@ +/* vim: set tabstop=3 expandtab: +** +** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** 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 +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** sdl.c +** +** $Id: sdl.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DEFAULT_SAMPLERATE 22050 +#define DEFAULT_BPS 8 +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_WIDTH 256 +#define NES_VISIBLE_HEIGHT 224 +#define DEFAULT_HEIGHT NES_VISIBLE_HEIGHT + +/* +** Timer +*/ + +static void (*timer_callback)(void) = NULL; +static int tick_ideal = 0; +static int tick_interval = 0; + +Uint32 mySDLTimer(Uint32 i) +{ + static int tickDiff = 0; + Uint32 tickLast; + + tickLast = SDL_GetTicks(); + + if (timer_callback) + timer_callback(); + + tickDiff += tick_interval - tick_ideal + tickLast - SDL_GetTicks(); + + if (tickDiff >= 10) + { + tickDiff -= 10; + return tick_interval - 10; + } + else + { + return tick_interval; + } +} +/* +static int round(double value) +{ + int upper, lower; + upper = (int) ceil(value); + lower = (int) floor(value); + + if (upper - value > value - lower) + return lower; + else + return upper; +} +*/ +int osd_installtimer(int frequency, void *func, int funcsize, void *counter, int countersize) +{ + double ideal = 1000 / frequency; + + /* these arguments are used only for djgpp, which needs to lock code/data */ + UNUSED(counter); + UNUSED(countersize); + UNUSED(funcsize); + + tick_ideal = round(ideal); + tick_interval = round(ideal / 10) * 10; + + SDL_SetTimer(tick_interval, mySDLTimer); + + timer_callback = func; + + return 0; +} +void *mem_alloc( int size, bool prefer_fast_memory){ + return malloc(size); +} +int main(int argc, char **argv){ + return nofrendo_main(argc, argv); +} + +/* +** Audio +*/ +static int sound_bps = DEFAULT_BPS; +static int sound_samplerate = DEFAULT_SAMPLERATE; +static int sound_fragsize = DEFAULT_FRAGSIZE; +static unsigned char *audioBuffer = NULL; +static void (*audio_callback)(void *buffer, int length) = NULL; + +/* this is the callback that SDL calls to obtain more audio data */ +static void sdl_audio_player(void *udata, unsigned char *stream, int len) +{ + /* SDL requests buffer fills in terms of bytes, not samples */ + if (16 == sound_bps) + len /= 2; + + if (audio_callback) + audio_callback(stream, len); +} + +void osd_setsound(void (*playfunc)(void *buffer, int length)) +{ + audio_callback = playfunc; +} + +static void osd_stopsound(void) +{ + audio_callback = NULL; + + SDL_CloseAudio(); + if (NULL != audioBuffer) + free(audioBuffer); +} + +static int osd_init_sound(void) +{ + SDL_AudioSpec wanted, obtained; + unsigned int bufferSize; + + sound_bps = config.read_int("sdlaudio", "sound_bps", DEFAULT_BPS); + sound_samplerate = config.read_int("sdlaudio", "sound_samplerate", DEFAULT_SAMPLERATE); + sound_fragsize = config.read_int("sdlaudio", "sound_fragsize", DEFAULT_FRAGSIZE); + + if (sound_bps != 8 && sound_bps != 16) + sound_bps = 8; + + if (sound_samplerate < 5000) + sound_samplerate = 5000; + else if (sound_samplerate > 48000) + sound_samplerate = 48000; + + if (sound_fragsize < 128) + sound_fragsize = 128; + else if (sound_fragsize > 32768) + sound_fragsize = 32768; + + audio_callback = NULL; + + /* set the audio format */ + wanted.freq = sound_samplerate; + wanted.format = (sound_bps == 8) ? AUDIO_U8 : AUDIO_S16; + wanted.channels = 1; /* 1 = mono, 2 = stereo */ + wanted.samples = sound_fragsize; + wanted.callback = sdl_audio_player; + wanted.userdata = NULL; + + if (SDL_OpenAudio (&wanted, &obtained) < 0) + { + nofrendo_log_printf("Couldn't open audio: %s\n", SDL_GetError()); + return -1; + } + + /* ensure we get U8 or S16 */ + if (AUDIO_U8 != obtained.format && AUDIO_S16 != obtained.format) + { + nofrendo_log_printf("Could not get correct audio output format\n"); + return -1; + } + + sound_bps = (obtained.format == AUDIO_U8) ? 8 : 16; + sound_samplerate = obtained.freq; + /* twice as big, to be on the safe side */ + bufferSize = (sound_bps / 8) * obtained.samples * 2; + + audioBuffer = malloc(bufferSize); + if (NULL == audioBuffer) + { + nofrendo_log_printf("error allocating audio buffer\n"); + return -1; + } + + SDL_PauseAudio(0); + return 0; +} + +void osd_getsoundinfo(sndinfo_t *info) +{ + info->sample_rate = sound_samplerate; + info->bps = sound_bps; +} + +/* +** Video +*/ + +static int init(int width, int height); +static void shutdown(void); +static int set_mode(int width, int height); +static void set_palette(rgb_t *pal); +static void clear(uint8 color); +static bitmap_t *lock_write(void); +static void free_write(int num_dirties, rect_t *dirty_rects); + +viddriver_t sdlDriver = +{ + "Simple DirectMedia Layer", /* name */ + init, /* init */ + shutdown, /* shutdown */ + set_mode, /* set_mode */ + set_palette, /* set_palette */ + clear, /* clear */ + lock_write, /* lock_write */ + free_write, /* free_write */ + NULL, /* custom_blit */ + false /* invalidate flag */ +}; + +void osd_getvideoinfo(vidinfo_t *info) +{ + info->default_width = DEFAULT_WIDTH; + info->default_height = DEFAULT_HEIGHT; + info->driver = &sdlDriver; +} + +/* Now that the driver declaration is out of the way, on to the SDL stuff */ +static SDL_Surface *mySurface = NULL; +static SDL_Color myPalette[256]; +static bitmap_t *myBitmap = NULL; +static bool fullscreen = false; + +/* flip between full screen and windowed */ +void osd_togglefullscreen(int code) +{ + bool pause; + nes_t *nes = nes_getcontextptr(); + + if (INP_STATE_MAKE != code) + return; + + ASSERT(nes); + + pause = nes->pause; + nes->pause = true; + + fullscreen ^= true; + + if (set_mode(mySurface->w, mySurface->h)) + ASSERT(0); + + sdlDriver.invalidate = true; + + nes->pause = pause; +} + +/* initialise SDL video */ +static int init(int width, int height) +{ + return set_mode(width, height); +} + +/* squash memory leaks */ +static void shutdown(void) +{ + if (NULL != mySurface) + { + SDL_FreeSurface(mySurface); + mySurface = NULL; + } + + if (NULL != myBitmap) + bmp_destroy(&myBitmap); +} + +/* set a video mode */ +static int set_mode(int width, int height) +{ + int flags; + bool restorePalette; + + if (NULL != mySurface) + { + SDL_FreeSurface(mySurface); + mySurface = NULL; + restorePalette = true; + } + + if (fullscreen) + { + flags = SDL_HWSURFACE | SDL_HWPALETTE | SDL_FULLSCREEN; + mySurface = SDL_SetVideoMode(width, height, 8, flags); + if (NULL == mySurface) + nofrendo_log_printf("Fullscreeen failed: %s\n", SDL_GetError()); + } + + if (NULL == mySurface) + { + fullscreen = false; + flags = SDL_HWSURFACE | SDL_HWPALETTE; + mySurface = SDL_SetVideoMode(width, height, 8, flags); + } + + if (NULL == mySurface) + { + nofrendo_log_printf("SDL Video failed: %s\n", SDL_GetError()); + return -1; + } + + if (restorePalette) + { + SDL_SetColors(mySurface, myPalette, 0, 256); + } + + SDL_ShowCursor(0); + return 0; +} + +/* copy nes palette over to hardware */ +static void set_palette(rgb_t *pal) +{ + int i; + + for (i = 0; i < 256; i++) + { + myPalette[i].r = pal[i].r; + myPalette[i].g = pal[i].g; + myPalette[i].b = pal[i].b; + } + + SDL_SetColors(mySurface, myPalette, 0, 256); +} + +/* clear all frames to a particular color */ +static void clear(uint8 color) +{ + SDL_FillRect(mySurface, 0, color); +} + +/* acquire the directbuffer for writing */ +static bitmap_t *lock_write(void) +{ + SDL_LockSurface(mySurface); + myBitmap = bmp_createhw(mySurface->pixels, mySurface->w, + mySurface->h, mySurface->pitch); + return myBitmap; +} + +/* release the resource */ +static void free_write(int num_dirties, rect_t *dirty_rects) +{ + bmp_destroy(&myBitmap); + SDL_UnlockSurface(mySurface); + + if (-1 == num_dirties) + { + SDL_UpdateRect(mySurface, 0, 0, 0, 0); + } + else if (num_dirties > 0) + { + /* loop through and modify the rects to be in terms of the screen */ + if (NES_SCREEN_WIDTH < mySurface->w || NES_VISIBLE_HEIGHT < mySurface->h) + { + int i, x_offset, y_offset; + + x_offset = (mySurface->w - NES_SCREEN_WIDTH) >> 1; + y_offset = (mySurface->h - NES_VISIBLE_HEIGHT) >> 1; + + for (i = 0; i < num_dirties; i++) + { + dirty_rects[i].x += x_offset; + dirty_rects[i].y += y_offset; + } + } + + SDL_UpdateRects(mySurface, num_dirties, (SDL_Rect *) dirty_rects); + } +} + +/* +** Input +*/ + +typedef struct joystick_s +{ + SDL_Joystick *js; + int *button_array; + int *axis_array; +} joystick_t; + +static joystick_t **joystick_array = 0; +static int joystick_count = 0; + +static int key_array[SDLK_LAST]; +#define LOAD_KEY(key, def_key) \ +key_array[key] = config.read_int("sdlkeys", #key, def_key) + +static void osd_initinput() +{ + int i, j; + SDL_Joystick *js; + char group[255]; + char key[255]; + + /* joystick */ + + joystick_count = SDL_NumJoysticks(); + joystick_array = malloc(joystick_count * sizeof(joystick_t *)); + + if (NULL == joystick_array) + { + nofrendo_log_printf("error allocating space for joystick array\n"); + joystick_count = 0; + } + + nofrendo_log_printf("joystick_count == %i\n", joystick_count); + + for (i = 0; i < joystick_count; i++) + { + sprintf(group, "sdljoystick%i", i); + js = SDL_JoystickOpen(i); + + if (js) + { + joystick_array[i] = malloc(sizeof(joystick_t)); + joystick_array[i]->js = js; + + nofrendo_log_printf("joystick %i is a %s\n", i, SDL_JoystickName(i)); + + /* load buttons */ + j = SDL_JoystickNumButtons(joystick_array[i]->js); + joystick_array[i]->button_array = malloc(j * sizeof(int)); + for (j--; j >= 0; j--) + { + sprintf(key, "button%i", j); + joystick_array[i]->button_array[j] = config.read_int(group, key, event_none); + } + + /* load axes */ + j = SDL_JoystickNumAxes(joystick_array[i]->js); + joystick_array[i]->axis_array = malloc(j * sizeof(int) * 2); + for (j--; j >= 0; j--) + { + sprintf(key, "positiveaxis%i", j); + joystick_array[i]->axis_array[(j << 1) + 1] = config.read_int(group, key, event_none); + + sprintf(key, "negativeaxis%i", j); + joystick_array[i]->axis_array[j << 1] = config.read_int(group, key, event_none); + } + } + else + { + joystick_array[i] = 0; + } + } + + SDL_JoystickEventState(SDL_ENABLE); + + /* keyboard */ + + LOAD_KEY(SDLK_ESCAPE, event_quit); + + LOAD_KEY(SDLK_F1, event_soft_reset); + LOAD_KEY(SDLK_F2, event_hard_reset); + LOAD_KEY(SDLK_F3, event_gui_toggle_fps); + LOAD_KEY(SDLK_F4, event_snapshot); + LOAD_KEY(SDLK_F5, event_state_save); + LOAD_KEY(SDLK_F6, event_toggle_sprites); + LOAD_KEY(SDLK_F7, event_state_load); + LOAD_KEY(SDLK_F8, event_none); + LOAD_KEY(SDLK_F9, event_none); + LOAD_KEY(SDLK_F10, event_osd_1); + LOAD_KEY(SDLK_F11, event_none); + LOAD_KEY(SDLK_F12, event_none); + + LOAD_KEY(SDLK_BACKQUOTE, event_none); + + LOAD_KEY(SDLK_1, event_state_slot_1); + LOAD_KEY(SDLK_EXCLAIM, event_state_slot_1); + LOAD_KEY(SDLK_2, event_state_slot_2); + LOAD_KEY(SDLK_AT, event_state_slot_2); + LOAD_KEY(SDLK_3, event_state_slot_3); + LOAD_KEY(SDLK_HASH, event_state_slot_3); + LOAD_KEY(SDLK_4, event_state_slot_4); + LOAD_KEY(SDLK_DOLLAR, event_state_slot_4); + LOAD_KEY(SDLK_5, event_state_slot_5); +/* LOAD_KEY(SDLK_PERCENT, event_state_slot_5);*/ + LOAD_KEY(SDLK_6, event_state_slot_6); + LOAD_KEY(SDLK_CARET, event_state_slot_6); + LOAD_KEY(SDLK_7, event_state_slot_7); + LOAD_KEY(SDLK_AMPERSAND, event_state_slot_7); + LOAD_KEY(SDLK_8, event_state_slot_8); + LOAD_KEY(SDLK_ASTERISK, event_state_slot_8); + LOAD_KEY(SDLK_9, event_state_slot_9); + LOAD_KEY(SDLK_LEFTPAREN, event_state_slot_9); + LOAD_KEY(SDLK_0, event_state_slot_0); + LOAD_KEY(SDLK_RIGHTPAREN, event_state_slot_0); + + LOAD_KEY(SDLK_MINUS, event_gui_pattern_color_down); + LOAD_KEY(SDLK_UNDERSCORE, event_gui_pattern_color_down); + LOAD_KEY(SDLK_EQUALS, event_gui_pattern_color_up); + LOAD_KEY(SDLK_PLUS, event_gui_pattern_color_up); + + LOAD_KEY(SDLK_BACKSPACE, event_gui_display_info); + + LOAD_KEY(SDLK_TAB, event_joypad1_select); + + LOAD_KEY(SDLK_q, event_toggle_channel_0); + LOAD_KEY(SDLK_w, event_toggle_channel_1); + LOAD_KEY(SDLK_e, event_toggle_channel_2); + LOAD_KEY(SDLK_r, event_toggle_channel_3); + LOAD_KEY(SDLK_t, event_toggle_channel_4); + LOAD_KEY(SDLK_y, event_toggle_channel_5); + LOAD_KEY(SDLK_u, event_palette_hue_down); + LOAD_KEY(SDLK_i, event_palette_hue_up); + LOAD_KEY(SDLK_o, event_gui_toggle_oam); + LOAD_KEY(SDLK_p, event_gui_toggle_pattern); + +/* LOAD_KEY(SDLK_LEFTBRACE, event_none); + LOAD_KEY(SDLK_RIGHTBRACE, event_none);*/ + LOAD_KEY(SDLK_LEFTBRACKET, event_none); + LOAD_KEY(SDLK_RIGHTBRACKET, event_none); + LOAD_KEY(SDLK_BACKSLASH, event_toggle_frameskip); +/* LOAD_KEY(SDLK_Bar, event_toggle_frameskip);*/ + + LOAD_KEY(SDLK_a, event_gui_toggle_wave); + LOAD_KEY(SDLK_s, event_set_filter_0); + LOAD_KEY(SDLK_d, event_set_filter_1); + LOAD_KEY(SDLK_f, event_set_filter_2); + LOAD_KEY(SDLK_g, event_none); + LOAD_KEY(SDLK_h, event_none); + LOAD_KEY(SDLK_j, event_palette_tint_down); + LOAD_KEY(SDLK_k, event_palette_tint_up); + LOAD_KEY(SDLK_l, event_palette_set_shady); + LOAD_KEY(SDLK_COLON, event_palette_set_default); + LOAD_KEY(SDLK_SEMICOLON, event_palette_set_default); + LOAD_KEY(SDLK_QUOTEDBL, event_none); + LOAD_KEY(SDLK_RETURN, event_joypad1_start); + LOAD_KEY(SDLK_PAUSE, event_togglepause); + + LOAD_KEY(SDLK_z, event_joypad1_b); + LOAD_KEY(SDLK_x, event_joypad1_a); + LOAD_KEY(SDLK_c, event_joypad1_select); + LOAD_KEY(SDLK_v, event_joypad1_start); + LOAD_KEY(SDLK_b, event_joypad2_b); + LOAD_KEY(SDLK_n, event_joypad2_a); + LOAD_KEY(SDLK_m, event_joypad2_select); + LOAD_KEY(SDLK_COMMA, event_joypad2_start); + LOAD_KEY(SDLK_LESS, event_none); + LOAD_KEY(SDLK_PERIOD, event_none); + LOAD_KEY(SDLK_GREATER, event_none); + LOAD_KEY(SDLK_QUESTION, event_none); + LOAD_KEY(SDLK_SLASH, event_none); + + LOAD_KEY(SDLK_SPACE, event_gui_toggle); + + LOAD_KEY(SDLK_LCTRL, event_joypad1_b); + LOAD_KEY(SDLK_RCTRL, event_joypad1_b); + LOAD_KEY(SDLK_LALT, event_joypad1_a); + LOAD_KEY(SDLK_RALT, event_joypad1_a); + LOAD_KEY(SDLK_LSHIFT, event_joypad1_a); + LOAD_KEY(SDLK_RSHIFT, event_joypad1_a); + + LOAD_KEY(SDLK_KP1, event_none); + LOAD_KEY(SDLK_KP2, event_joypad1_down); + LOAD_KEY(SDLK_KP3, event_none); + LOAD_KEY(SDLK_KP4, event_joypad1_left); + LOAD_KEY(SDLK_KP5, event_startsong); + LOAD_KEY(SDLK_KP6, event_joypad1_right); + LOAD_KEY(SDLK_KP7, event_songdown); + LOAD_KEY(SDLK_KP8, event_joypad1_up); + LOAD_KEY(SDLK_KP9, event_songup); + LOAD_KEY(SDLK_UP, event_joypad1_up); + LOAD_KEY(SDLK_DOWN, event_joypad1_down); + LOAD_KEY(SDLK_LEFT, event_joypad1_left); + LOAD_KEY(SDLK_RIGHT, event_joypad1_right); + LOAD_KEY(SDLK_HOME, event_none); + LOAD_KEY(SDLK_END, event_none); + LOAD_KEY(SDLK_PAGEUP, event_none); + LOAD_KEY(SDLK_PAGEDOWN, event_none); + LOAD_KEY(SDLK_KP_PLUS, event_toggle_frameskip); + + /* events */ + + event_set(event_osd_1, osd_togglefullscreen); +} + +void osd_getinput(void) +{ + int code, highval, lowval; + SDL_Event myEvent; + event_t func_event; + + while (SDL_PollEvent(&myEvent)) + { + switch(myEvent.type) + { + case SDL_KEYDOWN: + case SDL_KEYUP: + code = (myEvent.key.state == SDL_PRESSED) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get(key_array[myEvent.key.keysym.sym]); + if (func_event) + func_event(code); + break; + + case SDL_QUIT: + event_get(event_quit)(INP_STATE_MAKE); + break; + + case SDL_JOYAXISMOTION: + highval = (myEvent.jaxis.value > 0) ? INP_STATE_MAKE : INP_STATE_BREAK; + lowval = (myEvent.jaxis.value < 0) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get(joystick_array[myEvent.jaxis.which]->axis_array[myEvent.jaxis.axis << 1]); + if (func_event) + func_event(lowval); + + func_event = event_get(joystick_array[myEvent.jaxis.which]->axis_array[(myEvent.jaxis.axis << 1) + 1]); + if (func_event) + func_event(highval); + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + code = (myEvent.jbutton.state == SDL_PRESSED) ? INP_STATE_MAKE : INP_STATE_BREAK; + + func_event = event_get( joystick_array[myEvent.jbutton.which]->button_array[myEvent.jbutton.button] ); + if (func_event) + func_event(code); + break; + + default: + break; + } + } +} + +static void osd_freeinput(void) +{ + int i; + + for (i = 0; i < joystick_count; i++) + { + if (joystick_array[i]) + { + SDL_JoystickClose(joystick_array[i]->js); + free(joystick_array[i]->button_array); + free(joystick_array[i]->axis_array); + free(joystick_array[i]); + } + } + + free(joystick_array); +} + +void osd_getmouse(int *x, int *y, int *button) +{ + *button = SDL_GetMouseState(x, y); +} + +/* +** Shutdown +*/ + +/* this is at the bottom, to eliminate warnings */ +void osd_shutdown() +{ + osd_stopsound(); + osd_freeinput(); + SDL_Quit(); +} + +static int logprint(const char *string) +{ + return fprintf(stderr, "%s", string); +} + +/* +** Startup +*/ + +int osd_init() +{ + nofrendo_log_chain_logfunc(logprint); + + /* Initialize the SDL library */ + if (SDL_Init (SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_VIDEO + | SDL_INIT_JOYSTICK) < 0) + { + printf("Couldn't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + SDL_WM_SetCaption("Nofrendo", 0); + + if (osd_init_sound()) + return -1; + + osd_initinput(); + + return 0; +} + +/* +** $Log: sdl.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.16 2000/12/11 13:31:41 neil +** caption +** +** Revision 1.15 2000/11/25 20:29:42 matt +** tiny mod +** +** Revision 1.14 2000/11/09 14:06:31 matt +** state load fixed, state save mostly fixed +** +** Revision 1.13 2000/11/06 02:20:00 matt +** vid_drv / log api changes +** +** Revision 1.12 2000/11/05 16:36:06 matt +** thinlib round 2 +** +** Revision 1.11 2000/11/05 06:26:41 matt +** thinlib spawns changes +** +** Revision 1.10 2000/11/01 17:31:54 neil +** fixed some conflicting key assignments +** +** Revision 1.9 2000/11/01 14:17:16 matt +** multi-system event system, or whatever +** +** Revision 1.8 2000/10/23 15:54:15 matt +** suppressed warnings +** +** Revision 1.7 2000/10/22 20:37:33 neil +** restored proper timer correction, and added support for variable frequencies +** +** Revision 1.6 2000/10/22 19:17:06 matt +** more sane timer ISR / autoframeskip +** +** Revision 1.5 2000/10/21 19:34:03 matt +** many more cleanups +** +** Revision 1.4 2000/10/17 11:59:29 matt +** let me see why i can't go window->full->window +** +** Revision 1.3 2000/10/13 14:09:57 matt +** sound is configurable from config file +** +** Revision 1.2 2000/10/13 13:19:15 matt +** fixed a few minor bugs and 16-bit sound +** +** Revision 1.1 2000/10/10 14:24:25 matt +** initial revision +** +*/ diff --git a/src/unix/osd.c b/src/unix/osd.c new file mode 100644 index 0000000..f53b50b --- /dev/null +++ b/src/unix/osd.c @@ -0,0 +1,310 @@ +/* vim: set tabstop=3 expandtab: +** +** This file is in the public domain. +** +** osd.c +** +** $Id: osd.c,v 1.2 2001/04/27 14:37:11 neil Exp $ +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* path must be a valid path, and therefore no longer than PATH_MAX */ +static void addSlash(char *path) +{ + int len = strlen(path); + if(path[len - 1] != '/' && len + 1 <= PATH_MAX) + { + path[len] = '/'; + path[++len] = 0; + } +} + +/* filename must be a valid filename, and therefore no longer than PATH_MAX */ +static void removePath(char *filename) +{ + char temp[PATH_MAX + 1]; + int i; + + i = strlen(filename); + while(filename[--i] != '/' && i > 0); + + if(filename[i] == '/') + { + strncpy(temp, (filename + i + 1), PATH_MAX); + strncpy(filename, temp, PATH_MAX); + } +} + +/* if filename ends in extension, cut it off of filename */ +static void removeExtension(char *filename, const char *extension) +{ + int i = strlen(filename); + int j = strlen(extension); + + if(i <= j) return; + + while(i && j) + { + i--; + j--; + if(filename[i] != extension[j]) return; + } + filename[i] = 0; +} + +/* this determines where to store our data files */ +static const char *dataDirectory(void) +{ + static char dataPath[PATH_MAX + 1]; + static bool checked = false; + char cwd[PATH_MAX + 1]; + + if(!checked) + { + checked = true; + + /* fall back to using cwd */ + getcwd(cwd, PATH_MAX); + strncpy(dataPath, cwd, PATH_MAX); + + /* but default to using ~/.nofrendo/ if possible */ + if(getenv("HOME")) + { + char temp[PATH_MAX + 1]; + strncpy(temp, getenv("HOME"), PATH_MAX); + addSlash(temp); + strncat(temp, ".nofrendo", PATH_MAX - strlen(temp)); + + if(!mkdir(temp, 0755) || errno == EEXIST) + { + nofrendo_log_printf("Succeeded in choosing HOME-based homeDirectory.\n"); + strncpy(dataPath, temp, PATH_MAX); + } + } + + /* make sure either path ends in a slash */ + addSlash(dataPath); + nofrendo_log_printf("Storing data in %s\n", dataPath); + } + + return dataPath; +} + +/* This is os-specific part of main() */ +int osd_main(int argc, char *argv[]) +{ + static char configfilename[PATH_MAX + 1]; + + /* command-line parameters */ + if(argc < 2) + { + printf("usage: %s IMAGE\n\n", argv[0]); + printf("WHAP!\n"); + printf("WHAP!\n"); + printf("WHAP!\n"); + printf("Bad user!\n"); + printf("Run me correctly or you'll get more of the same!\n"); + return -1; + } + + /* config file */ + strncpy(configfilename, dataDirectory(), PATH_MAX); + strncat(configfilename, "config", PATH_MAX - strlen(configfilename)); + config.filename = configfilename; + + /* all done */ + return main_loop(argv[1], system_autodetect); +} + +/* File system interface */ +void osd_fullname(char *fullname, const char *shortname) +{ + strncpy(fullname, shortname, PATH_MAX); +} + +/* This gives filenames for storage of saves */ +char *osd_newextension(char *string, char *ext) +{ + char name[PATH_MAX + 1]; + + removePath(string); + removeExtension(string, ".gz"); + removeExtension(string, ".bz2"); + + strncpy(name, dataDirectory(), PATH_MAX); + strncat(name, string, PATH_MAX - strlen(name)); + strncat(name, ext, PATH_MAX - strlen(name)); + + strcpy(string, name); + + nofrendo_log_printf("osd_newextension: %s\n", string); + return string; +} + +/* This gives filenames for storage of PCX snapshots */ +int osd_makesnapname(char *filename, int len) +{ + char fullpath[PATH_MAX + 1]; + struct stat stat_data; + int pcx_num = -1; + + /* TODO: check if fullpath has %, \, or anything else special in it */ + strncpy(fullpath, dataDirectory(), PATH_MAX); + strncat(fullpath, "snap%04d.pcx", PATH_MAX - strlen(fullpath)); + + while (++pcx_num < 10000) + { + snprintf(filename, len, fullpath, pcx_num); + + if(stat(filename, &stat_data)) + return pcx_num; + } + + return -1; +} + +/* +** $Log: osd.c,v $ +** Revision 1.2 2001/04/27 14:37:11 neil +** wheeee +** +** Revision 1.1 2001/04/27 12:54:40 neil +** blah +** +** Revision 1.1.1.1 2001/04/27 07:03:54 neil +** initial +** +** Revision 1.38 2000/10/10 14:04:27 neil +** what's TRUE is not true +** +** Revision 1.37 2000/10/10 13:58:14 matt +** stroustrup squeezing his way in the door +** +** Revision 1.36 2000/10/10 13:05:20 matt +** Mr. Clean makes a guest appearance +** +** Revision 1.35 2000/07/31 04:29:04 matt +** one million cleanups +** +** Revision 1.34 2000/07/27 01:37:30 neil +** change of case in system enum +** +** Revision 1.33 2000/07/26 21:36:14 neil +** Big honkin' change -- see the mailing list +** +** Revision 1.32 2000/07/23 16:47:15 neil +** no more static charp[ in osd_newextension +** +** Revision 1.31 2000/07/21 18:08:43 neil +** Now we store our data files in ~/.nofrendo +** +** Revision 1.30 2000/07/21 14:35:58 neil +** Off by one on extension stripping +** +** Revision 1.29 2000/07/21 14:06:16 neil +** little convenience fixes +** +** Revision 1.28 2000/07/21 13:54:42 neil +** Fixed snapshot file generation +** +** Revision 1.27 2000/07/21 13:39:17 neil +** New main structure and new event structure +** +** Revision 1.26 2000/07/20 15:09:26 neil +** moving to SDL +** +** Revision 1.25 2000/07/19 15:59:40 neil +** PATH_MAX, strncpy, snprintf, and strncat are our friends +** +** Revision 1.24 2000/07/19 12:32:37 neil +** warning-free days are here again with PATH_MAX +** +** Revision 1.23 2000/07/18 09:24:07 neil +** Sound update... SDL works reasonably, but latent. OSS direct buffer access split out from OSS write() access. +** +** Revision 1.22 2000/07/16 06:47:23 neil +** Madly hacking at the sound, Desprately grabbing at whatever might work +** +** Revision 1.21 2000/07/14 05:40:31 neil +** Exploring options for making sound work +** +** Revision 1.20 2000/07/11 08:04:59 neil +** Moved the rom info display to osd.c from input.c +** +** Revision 1.19 2000/07/11 07:48:49 neil +** Replaced config.h with version.h, thanks to the config.h API +** +** Revision 1.18 2000/07/11 07:39:25 neil +** split input into input.c and ggiinput.c; swallowed bogoggi.h into linux.h +** +** Revision 1.17 2000/07/11 07:14:45 neil +** Headers merged +** +** Revision 1.16 2000/07/11 06:34:40 neil +** moved some files from input.c to (better?) places in osd.c and sound.c +** +** Revision 1.15 2000/07/09 19:39:13 bsittler +** Fixed timer interval (it was 17 us, not 17 ms) and added page-flipping. +** +** Revision 1.14 2000/07/09 18:36:38 neil +** bogoggi eliminates the uintx already defined warnings +** +** Revision 1.13 2000/07/09 06:42:06 neil +** Non-working attempt at GGI keyboard input +** +** Revision 1.12 2000/07/07 03:23:24 neil +** You can't see anything, but input and sound work impeccably +** +** Revision 1.11 2000/07/06 18:55:35 neil +** Pub-lic Do-main here I come... I don't need no GPL +** +** Revision 1.10 2000/07/06 16:41:42 matt +** removed dpp flag +** +** Revision 1.9 2000/07/06 16:40:14 neil +** copyright and/or log added +** +** Revision 1.8 2000/07/06 16:31:50 neil +** Now works, albeit lacking speed and input, on my desktop +** +** Revision 1.7 2000/07/06 05:38:38 neil +** read it and weep (I'm not sure if it's tears of joy +** +** Revision 1.6 2000/07/06 04:27:14 neil +** It's close enough to working that I can taste it +** +** Revision 1.5 2000/07/05 23:37:46 neil +** Muahahaha +** +** Revision 1.3 2000/07/05 19:57:36 neil +** __GNUC -> __DJGPP in nes.c +** +** Revision 1.2 2000/07/05 17:26:16 neil +** Moved the externs in nofrendo.c to osd.h +** +** Revision 1.1 2000/07/05 17:14:34 neil +** Linux: Act Two, Scene One +** +** +*/ From 834200813d828014980acec2c6bfd113936e486d Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 08:54:40 +0000 Subject: [PATCH 02/21] init gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be743c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.pch +.vscode* +vgcore.* \ No newline at end of file From 9dc5297e0686bda977d7ebf2eadfffdc97bd67e8 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 09:10:40 +0000 Subject: [PATCH 03/21] use after free in vid_findmode. trying to log dimensions of destroyed by driver->free_write() bitmap --- src/vid_drv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vid_drv.c b/src/vid_drv.c index 08e3e98..e13cf7d 100644 --- a/src/vid_drv.c +++ b/src/vid_drv.c @@ -448,12 +448,13 @@ static int vid_findmode(int width, int height, viddriver_t *osd_driver) else bmp_clear(screen, GUI_BLACK); + nofrendo_log_printf("video driver: %s at %dx%d\n", driver->name, + screen->width, screen->height); + /* release surface */ if (driver->free_write) driver->free_write(-1, NULL); - nofrendo_log_printf("video driver: %s at %dx%d\n", driver->name, - screen->width, screen->height); return 0; } From 797f9bf6354d86c76a09486553de35564d0a3aa3 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 09:12:58 +0000 Subject: [PATCH 04/21] missing include "osd.h" in memguard.c, implicit declaration(could become a real problem cause all reality casts to 32 bit, including 64 bit pointer :D) --- src/memguard.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/memguard.c b/src/memguard.c index e484188..90a5aa7 100644 --- a/src/memguard.c +++ b/src/memguard.c @@ -31,6 +31,7 @@ #include "noftypes.h" #include "memguard.h" #include "log.h" +#include "osd.h" /* Maximum number of allocated blocks at any one time */ #define MAX_BLOCKS 4096 From a0487a225cbb45df6f3203a30cfb99f4f150a874 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 09:24:34 +0000 Subject: [PATCH 05/21] few more uint32 pointer casts to uintptr_t --- src/bitmap.c | 2 +- src/memguard.c | 12 ++++++------ src/nofrendo.c | 2 +- src/noftypes.h | 4 ++-- src/vid_drv.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bitmap.c b/src/bitmap.c index 85ca5d7..ab48e33 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -62,7 +62,7 @@ static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width, if (false == bitmap->hardware) { bitmap->pitch = (bitmap->pitch + 3) & ~3; - bitmap->line[0] = (uint8 *)(((uint32)bitmap->data + overdraw + 3) & ~3); + bitmap->line[0] = (uint8 *)(((uintptr_t)bitmap->data + overdraw + 3) & ~3); } else { diff --git a/src/memguard.c b/src/memguard.c index 90a5aa7..1466494 100644 --- a/src/memguard.c +++ b/src/memguard.c @@ -225,8 +225,8 @@ static void mem_deleteblock(void *data, char *file, int line) { if (mem_checkguardblock(mem_record[i].block_addr, GUARD_LENGTH)) { - sprintf(fail, "mem_deleteblock 0x%08X at line %d of %s -- block corrupt", - (uint32)data, line, file); + sprintf(fail, "mem_deleteblock 0x%08lX at line %d of %s -- block corrupt", + (uintptr_t)data, line, file); ASSERT_MSG(fail); } @@ -235,8 +235,8 @@ static void mem_deleteblock(void *data, char *file, int line) } } - sprintf(fail, "mem_deleteblock 0x%08X at line %d of %s -- block not found", - (uint32)data, line, file); + sprintf(fail, "mem_deleteblock 0x%08lX at line %d of %s -- block not found", + (uintptr_t)data, line, file); ASSERT_MSG(fail); } #endif /* NOFRENDO_DEBUG */ @@ -397,7 +397,7 @@ void mem_checkleaks(void) if (mem_record[i].block_addr) { nofrendo_log_printf("addr: 0x%08X, size: %d, line %d of %s%s\n", - (uint32)mem_record[i].block_addr, + (uintptr_t)mem_record[i].block_addr, mem_record[i].block_size, mem_record[i].line_num, mem_record[i].file_name, @@ -427,7 +427,7 @@ void mem_checkblocks(void) if (mem_checkguardblock(mem_record[i].block_addr, GUARD_LENGTH)) { nofrendo_log_printf("addr: 0x%08X, size: %d, line %d of %s -- block corrupt\n", - (uint32)mem_record[i].block_addr, + (uintptr_t)mem_record[i].block_addr, mem_record[i].block_size, mem_record[i].line_num, mem_record[i].file_name); diff --git a/src/nofrendo.c b/src/nofrendo.c index 4026ab4..1e476dd 100644 --- a/src/nofrendo.c +++ b/src/nofrendo.c @@ -137,7 +137,7 @@ static system_t detect_systemtype(const char *filename) static int install_timer(int hertz) { return osd_installtimer(hertz, (void *)timer_isr, - (int)timer_isr_end - (int)timer_isr, + (uintptr_t)timer_isr_end - (uintptr_t)timer_isr, (void *)&nofrendo_ticks, sizeof(nofrendo_ticks)); } diff --git a/src/noftypes.h b/src/noftypes.h index c72ffa0..a9802c5 100644 --- a/src/noftypes.h +++ b/src/noftypes.h @@ -60,13 +60,13 @@ typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; - +#include #include "memguard.h" #include "log.h" #ifdef NOFRENDO_DEBUG -#define ASSERT(expr) nofrendo_log_assert((int)(expr), __LINE__, __FILE__, NULL) +#define ASSERT(expr) nofrendo_log_assert((uintptr_t)(expr), __LINE__, __FILE__, NULL) #define ASSERT_MSG(msg) nofrendo_log_assert(false, __LINE__, __FILE__, (msg)) #else /* !NOFRENDO_DEBUG */ diff --git a/src/vid_drv.c b/src/vid_drv.c index e13cf7d..4a59f06 100644 --- a/src/vid_drv.c +++ b/src/vid_drv.c @@ -92,7 +92,7 @@ static viddriver_t *driver = NULL; INLINE int vid_memcmp(const void *p1, const void *p2, int len) { /* check for 32-bit aligned data */ - if (0 == (((uint32)p1 & 3) | ((uint32)p2 & 3))) + if (0 == (((uintptr_t)p1 & 3) | ((uintptr_t)p2 & 3))) { uint32 *dw1 = (uint32 *)p1; uint32 *dw2 = (uint32 *)p2; @@ -140,7 +140,7 @@ INLINE void vid_memcpy(void *dest, const void *src, int len) uint32 *s = (uint32 *)src; uint32 *d = (uint32 *)dest; - ASSERT(0 == ((len & 3) | ((uint32)src & 3) | ((uint32)dest & 3))); + ASSERT(0 == ((len & 3) | ((uintptr_t)src & 3) | ((uintptr_t)dest & 3))); len >>= 2; DUFFS_DEVICE(*d++ = *s++, len); From 118caff79fe566d076e4e391e7bb9b89987312dd Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:29:59 +0000 Subject: [PATCH 06/21] make a whole struct aligned by 2, and packed(pcxheader_s) --- src/pcx.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/pcx.h b/src/pcx.h index c36d4b6..cff8850 100644 --- a/src/pcx.h +++ b/src/pcx.h @@ -32,25 +32,25 @@ /* Got these out of ZSoft's document */ typedef struct pcxheader_s { - uint8 Manufacturer __PACKED__; - uint8 Version __PACKED__; - uint8 Encoding __PACKED__; - uint8 BitsPerPixel __PACKED__; - uint16 Xmin __PACKED__; - uint16 Ymin __PACKED__; - uint16 Xmax __PACKED__; - uint16 Ymax __PACKED__; - uint16 HDpi __PACKED__; - uint16 VDpi __PACKED__; - uint8 Colormap[48] __PACKED__; - uint8 Reserved __PACKED__; - uint8 NPlanes __PACKED__; - uint16 BytesPerLine __PACKED__; - uint16 PaletteInfo __PACKED__; - uint16 HscreenSize __PACKED__; - uint16 VscreenSize __PACKED__; - uint8 Filler[54] __PACKED__; -} pcxheader_t; + uint8 Manufacturer; + uint8 Version; + uint8 Encoding; + uint8 BitsPerPixel; + uint16 Xmin; + uint16 Ymin; + uint16 Xmax; + uint16 Ymax; + uint16 HDpi; + uint16 VDpi; + uint8 Colormap[48]; + uint8 Reserved; + uint8 NPlanes; + uint16 BytesPerLine; + uint16 PaletteInfo; + uint16 HscreenSize; + uint16 VscreenSize; + uint8 Filler[54] ; +} __PACKED__ __attribute__((aligned(2))) pcxheader_t; extern int pcx_write(char *filename, bitmap_t *bmp, rgb_t *pal); From 26eea988005d04422229433f9d96485dcd67a1b3 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:00:20 +0000 Subject: [PATCH 07/21] use uint32 for nametab to avoid casting to int, same for color calculations --- src/nes/nes_ppu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 93b9a48..412ce3e 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -43,8 +43,8 @@ #define PPU_MEM(x) ppu.page[(x) >> 10][(x)] /* Background (color 0) and solid sprite pixel flags */ -#define BG_TRANS 0x80 -#define SP_PIXEL 0x40 +#define BG_TRANS 0x80U +#define SP_PIXEL 0x40U #define BG_CLEAR(V) ((V)&BG_TRANS) #define BG_SOLID(V) (0 == BG_CLEAR(V)) #define SP_CLEAR(V) (0 == ((V)&SP_PIXEL)) @@ -62,7 +62,7 @@ void ppu_displaysprites(bool display) void ppu_setcontext(ppu_t *src_ppu) { - int nametab[4]; + uint32 nametab[4]; ASSERT(src_ppu); ppu = *src_ppu; @@ -577,7 +577,6 @@ INLINE void draw_bgtile(uint8 *surface, uint8 pat1, uint8 pat2, const uint8 *colors) { uint32 pattern = ((pat2 & 0xAA) << 8) | ((pat2 & 0x55) << 1) | ((pat1 & 0xAA) << 7) | (pat1 & 0x55); - *surface++ = colors[(pattern >> 14) & 3]; *surface++ = colors[(pattern >> 6) & 3]; *surface++ = colors[(pattern >> 12) & 3]; From f7041153b7e7a650cf6e5022c56af8df0f1bf261 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:02:06 +0000 Subject: [PATCH 08/21] well it doesn't break something, but sanitizer more happy --- src/cpu/nes6502.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cpu/nes6502.c b/src/cpu/nes6502.c index 24bead4..767f3cb 100644 --- a/src/cpu/nes6502.c +++ b/src/cpu/nes6502.c @@ -1137,7 +1137,8 @@ static uint8 null_page[NES6502_BANKSIZE]; */ INLINE uint32 zp_readword(register uint8 address) { - return (uint32)(*(uint16 *)(ram + address)); + // return (uint32)(*(uint16 *)(ram + address)); + return ram[address] | (ram[address + 1] << 8); } INLINE uint32 bank_readword(register uint32 address) @@ -1147,7 +1148,10 @@ INLINE uint32 bank_readword(register uint32 address) ** be fetching a word across page boundaries, which only would ** make sense if the banks were physically consecutive. */ - return (uint32)(*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); + // return (uint32)(*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK))); + + uint8 *ptr = cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK); + return (uint32)ptr[0] | ((uint32)ptr[1] << 8); } #else /* !HOST_LITTLE_ENDIAN */ From 61e9941af731e32ced8e19338eba266f2dfcdaa3 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:51:16 +0000 Subject: [PATCH 09/21] write past allocated mem block while trying to render 33rd tile --- src/nes/nes_ppu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 412ce3e..3354fe9 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -717,9 +717,15 @@ static void ppu_renderbg(uint8 *vidbuf) col_high = ((attrib >> attrib_shift) & 3) << 2; /* ppu fetches 33 tiles */ - tile_count = 33; + tile_count = 32; + // ppu fetches 33, but screen is 32, additional one for smooth scrolling + // but our vidbuf bitmap wrongly allocates mem or something. + // anyways we just render 32 and no mem problem. + while (tile_count--) { + // printf("bmp_ptr = %p, vidbuf = %p, offset = %ld\n", + // (void*)bmp_ptr, (void*)vidbuf, bmp_ptr - vidbuf); /* Tile number from nametable */ tile_index = *tile_ptr++; data_ptr = &PPU_MEM(bg_offset + (tile_index << 4)); @@ -727,7 +733,7 @@ static void ppu_renderbg(uint8 *vidbuf) /* Handle $FD/$FE tile VROM switching (PunchOut) */ if (ppu.latchfunc) ppu.latchfunc(ppu.bg_base, tile_index); - + // Shit is happening here draw_bgtile(bmp_ptr, data_ptr[0], data_ptr[8], ppu.palette + col_high); bmp_ptr += 8; @@ -1172,7 +1178,6 @@ static void draw_sprite(bitmap_t *bmp, int x, int y, uint8 tile_num, uint8 attri vram_adr = ppu.obj_base + (tile_num << 4); data_ptr = &PPU_MEM(vram_adr); - for (line = 0; line < height; line++) { if (line == 8) @@ -1233,7 +1238,6 @@ void ppu_dumppattern(bitmap_t *bmp, int table_num, int x_loc, int y_loc, int col { data_ptr = &PPU_MEM((table_num << 12) + (tile_num << 4)); ptr = bmp_ptr; - for (line = 0; line < 8; line++) { draw_bgtile(ptr, data_ptr[0], data_ptr[8], ppu.palette + col_high); From ed4e3daf393441b571f2581dba7654dcb65631ce Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:51:54 +0000 Subject: [PATCH 10/21] make this stuff signed to be sure no int conversions on pointers would happen --- src/nes/nes_ppu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nes/nes_ppu.h b/src/nes/nes_ppu.h index ecaf48b..4c96a12 100644 --- a/src/nes/nes_ppu.h +++ b/src/nes/nes_ppu.h @@ -84,8 +84,8 @@ typedef struct ppu_s /* hardware registers */ uint8 ctrl0, ctrl1, stat, oam_addr; uint32 vaddr, vaddr_latch; - int tile_xofs, flipflop; - int vaddr_inc; + uint8 tile_xofs, flipflop; + uint32 vaddr_inc; uint32 tile_nametab; uint8 obj_height; From 62eeeca72584cb313a6177c6ca591324ca9adcfb Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:52:23 +0000 Subject: [PATCH 11/21] finally we could remove that excessive loggage --- src/noftypes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/noftypes.h b/src/noftypes.h index a9802c5..86cf9c4 100644 --- a/src/noftypes.h +++ b/src/noftypes.h @@ -28,8 +28,8 @@ #include -#define NOFRENDO_DEBUG -#define NOFRENDO_MEM_DEBUG +// #define NOFRENDO_DEBUG +// #define NOFRENDO_MEM_DEBUG // #define NOFRENDO_VRAM_DEBUG // #define NOFRENDO_LOG_TO_FILE /* For the ESP32, it costs too much memory to render to a separate buffer and blit that to the main buffer. From 77d68387ad3e0d72d78714a8cf29f8abe025f692 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 13:09:28 +0000 Subject: [PATCH 12/21] use NES_UNIX and NES_OSD defines to avoid buildage for linux sdl1 in keira --- Makefile | 2 +- src/sdl/sdl.c | 5 +++-- src/unix/osd.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ffb004e..7c95a47 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -m64 -Werror=implicit-function-declaration -fstack-protector-all -fstack-protector-strong -fstack-check -Wall -lm -lSDL -O0 -g3 -I $(shell realpath src) +CFLAGS = -m64 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Werror=implicit-function-declaration -Werror=format -Werror=pointer-to-int-cast -fsanitize=address,undefined -fstack-protector-all -fstack-protector-strong -fstack-check -Wall -lm -lSDL -O0 -g3 -DNES_UNIX -DNES_SDL -I $(shell realpath src) SRC = $(shell find src -name "*.c" ) OBJ = $(SRC:.c=.o) diff --git a/src/sdl/sdl.c b/src/sdl/sdl.c index b6b9ca8..713566b 100644 --- a/src/sdl/sdl.c +++ b/src/sdl/sdl.c @@ -23,7 +23,7 @@ ** $Id: sdl.c,v 1.2 2001/04/27 14:37:11 neil Exp $ ** */ - +#ifdef NES_SDL #include #include #include @@ -47,7 +47,7 @@ #define DEFAULT_FRAGSIZE 1024 #define DEFAULT_WIDTH 256 -#define NES_VISIBLE_HEIGHT 224 +#define NES_VISIBLE_HEIGHT NES_SCREEN_HEIGHT #define DEFAULT_HEIGHT NES_VISIBLE_HEIGHT /* @@ -787,3 +787,4 @@ int osd_init() ** initial revision ** */ +#endif \ No newline at end of file diff --git a/src/unix/osd.c b/src/unix/osd.c index f53b50b..38bf119 100644 --- a/src/unix/osd.c +++ b/src/unix/osd.c @@ -7,7 +7,7 @@ ** $Id: osd.c,v 1.2 2001/04/27 14:37:11 neil Exp $ ** */ - +#ifdef NES_UNIX #include #include #include @@ -308,3 +308,4 @@ int osd_makesnapname(char *filename, int len) ** ** */ +#endif \ No newline at end of file From 46ffe3508a7a7e981aadcc75c7a835bb27605b10 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 14:39:59 +0000 Subject: [PATCH 13/21] ignore xofs --- src/nes/nes_ppu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 3354fe9..fa9e9b5 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -701,8 +701,9 @@ static void ppu_renderbg(uint8 *vidbuf) memset(vidbuf, FULLBG, NES_SCREEN_WIDTH); return; } - - bmp_ptr = vidbuf - ppu.tile_xofs; /* scroll x */ + // completely ignore xofs, mem bug, need to dive into it more + bmp_ptr = vidbuf; + // bmp_ptr = vidbuf - ppu.tile_xofs; /* scroll x */ refresh_vaddr = 0x2000 + (ppu.vaddr & 0x0FE0); /* mask out x tile */ x_tile = ppu.vaddr & 0x1F; y_tile = (ppu.vaddr >> 5) & 0x1F; /* to simplify calculations */ From f814f847b0fe8f07b17e931d941a278248bf1d6a Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 15:31:12 +0000 Subject: [PATCH 14/21] add check on sprite_x sprite_y in ppu_renderoam. some of those want to be drawn outside of our memory --- src/nes/nes_ppu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index fa9e9b5..1ab28b1 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -832,6 +832,11 @@ static void ppu_renderoam(uint8 *vidbuf, int scanline) tile_index = sprite_ptr->tile; attrib = sprite_ptr->atr; + // check if sprite cords valid + if ((sprite_x > NES_SCREEN_WIDTH - 8)||(sprite_y > NES_SCREEN_HEIGHT - 8)) + continue; + + bmp_ptr = buf_ptr + sprite_x; /* Handle $FD/$FE tile VROM switching (PunchOut) */ From 98aea9664424344b03afac63c7e6d9b8de2be3d7 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 19:44:21 +0000 Subject: [PATCH 15/21] todo update --- src/nes/nes_ppu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 1ab28b1..48ca47e 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -831,7 +831,8 @@ static void ppu_renderoam(uint8 *vidbuf, int scanline) sprite_x = sprite_ptr->x_loc; tile_index = sprite_ptr->tile; attrib = sprite_ptr->atr; - + // TODO: clamp to NES_SCREEN_WIDTH && NES_SCREEN_HEIGHT and implement patitial draw for others + // there's a suspicious check on sprite_y above, though it doesn't fix our sprite_x problem // check if sprite cords valid if ((sprite_x > NES_SCREEN_WIDTH - 8)||(sprite_y > NES_SCREEN_HEIGHT - 8)) continue; From dfe6037e1ff507c1789a15579c37d298f75ab7cc Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sat, 11 Oct 2025 20:21:01 +0000 Subject: [PATCH 16/21] APU DMC Register treated wrong way --- src/sndhrdw/nes_apu.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sndhrdw/nes_apu.c b/src/sndhrdw/nes_apu.c index 9c53f5c..bc0001b 100644 --- a/src/sndhrdw/nes_apu.c +++ b/src/sndhrdw/nes_apu.c @@ -730,13 +730,11 @@ void apu_write(uint32 address, uint8 value) break; case APU_WRE1: /* 7-bit DAC */ - /* add the _delta_ between written value and - ** current output level of the volume reg - */ + // $4011 is a direct write + // https://www.nesdev.org/wiki/APU_DMC value &= 0x7F; /* bit 7 ignored */ - apu.dmc.output_vol += ((value - apu.dmc.regs[1]) << 8); + apu.dmc.output_vol = ((value) << 8); apu.dmc.regs[1] = value; - break; case APU_WRE2: apu.dmc.regs[2] = value; From 5f89c889d265bb0fe57aa4aab3b40fa0c6e2f59c Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Sun, 12 Oct 2025 01:52:53 +0000 Subject: [PATCH 17/21] ensure valid ptr before fwrite --- src/nes/nes_rom.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/nes/nes_rom.c b/src/nes/nes_rom.c index b2fbc4f..ca0cee1 100644 --- a/src/nes/nes_rom.c +++ b/src/nes/nes_rom.c @@ -94,9 +94,16 @@ static void rom_savesram(rominfo_t *rominfo) fp = fopen(fn, "wb"); if (NULL != fp) { - fwrite(rominfo->sram, SRAM_BANK_LENGTH, rominfo->sram_banks, fp); - fclose(fp); - nofrendo_log_printf("Wrote battery RAM to %s.\n", fn); + if (rominfo->sram){ + fwrite(rominfo->sram, SRAM_BANK_LENGTH, rominfo->sram_banks, fp); + fclose(fp); + nofrendo_log_printf("Wrote battery RAM to %s.\n", fn); + } + else + { + fclose(fp); + nofrendo_log_printf("Wrote battery RAM to %s failed.\n", fn); + } } } } From 7bec6718fcd92ebddce9f94fc672adbb0febe4a0 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Mon, 13 Oct 2025 13:00:23 +0000 Subject: [PATCH 18/21] fix overdraw issue. When we've only one framebuffer, we still need overdraw --- src/nes/nes_ppu.c | 5 +---- src/vid_drv.c | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 48ca47e..92847f0 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -831,10 +831,7 @@ static void ppu_renderoam(uint8 *vidbuf, int scanline) sprite_x = sprite_ptr->x_loc; tile_index = sprite_ptr->tile; attrib = sprite_ptr->atr; - // TODO: clamp to NES_SCREEN_WIDTH && NES_SCREEN_HEIGHT and implement patitial draw for others - // there's a suspicious check on sprite_y above, though it doesn't fix our sprite_x problem - // check if sprite cords valid - if ((sprite_x > NES_SCREEN_WIDTH - 8)||(sprite_y > NES_SCREEN_HEIGHT - 8)) + if (sprite_x > NES_SCREEN_WIDTH) continue; diff --git a/src/vid_drv.c b/src/vid_drv.c index 4a59f06..23bc5d2 100644 --- a/src/vid_drv.c +++ b/src/vid_drv.c @@ -405,7 +405,11 @@ int vid_setmode(int width, int height) bmp_destroy(&back_buffer); #endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ +#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER primary_buffer = bmp_create(width, height, 0); /* no overdraw */ +#else + primary_buffer = bmp_create(width, height, 8); /* overdraw 8 */ +#endif if (NULL == primary_buffer) return -1; From 5ba6da5407bd02262c5a1d8a6916298ff27bbf01 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Mon, 13 Oct 2025 13:18:28 +0000 Subject: [PATCH 19/21] elliminate NES_DOUBLE_FRAMEBUFFER completely --- src/gui.c | 6 ++---- src/nes/nes.c | 30 +----------------------------- src/nes/nes.h | 5 ----- src/noftypes.h | 2 +- src/vid_drv.c | 43 ++++--------------------------------------- 5 files changed, 8 insertions(+), 78 deletions(-) diff --git a/src/gui.c b/src/gui.c index 126c14b..61befd6 100644 --- a/src/gui.c +++ b/src/gui.c @@ -75,11 +75,9 @@ void gui_savesnap(void) if (osd_makesnapname(filename, PATH_MAX) < 0) return; -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - if (pcx_write(filename, nes->vidbuf, nes->ppu->curpal)) -#else /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ + if (pcx_write(filename, vid_getbuffer(), nes->ppu->curpal)) -#endif /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ + return; diff --git a/src/nes/nes.c b/src/nes/nes.c index b5efc83..bd13f2c 100644 --- a/src/nes/nes.c +++ b/src/nes/nes.c @@ -250,13 +250,6 @@ static void build_address_handlers(nes_t *machine) /* raise an IRQ */ void nes_irq(void) { -#ifdef NOFRENDO_DEBUG -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - if (nes.scanline <= NES_SCREEN_HEIGHT) - memset(nes.vidbuf->line[nes.scanline - 1], GUI_RED, NES_SCREEN_WIDTH); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ -#endif /* NOFRENDO_DEBUG */ - nes6502_irq(); } @@ -304,11 +297,8 @@ static void nes_renderframe(bool draw_flag) while (262 != nes.scanline) { -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - ppu_scanline(nes.vidbuf, nes.scanline, draw_flag); -#else /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ + ppu_scanline(vid_getbuffer(), nes.scanline, draw_flag); -#endif /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ if (241 == nes.scanline) { @@ -348,12 +338,6 @@ static void system_video(bool draw) return; } -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - /* blit the NES screen to our video surface */ - vid_blit(nes.vidbuf, 0, (NES_SCREEN_HEIGHT - NES_VISIBLE_HEIGHT) / 2, - 0, 0, NES_SCREEN_WIDTH, NES_VISIBLE_HEIGHT); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - /* overlay our GUI on top of it */ gui_frame(true); @@ -446,10 +430,6 @@ void nes_destroy(nes_t **machine) ppu_destroy(&(*machine)->ppu); apu_destroy(&(*machine)->apu); -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - bmp_destroy(&(*machine)->vidbuf); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - if ((*machine)->cpu) { if ((*machine)->cpu->mem_page[0]) @@ -525,14 +505,6 @@ nes_t *nes_create(void) memset(machine, 0, sizeof(nes_t)); - /* bitmap */ - /* 8 pixel overdraw */ -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - machine->vidbuf = bmp_create(NES_SCREEN_WIDTH, NES_SCREEN_HEIGHT, 8); - if (NULL == machine->vidbuf) - goto _fail; -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - machine->autoframeskip = true; /* cpu */ diff --git a/src/nes/nes.h b/src/nes/nes.h index b36d902..be12efb 100644 --- a/src/nes/nes.h +++ b/src/nes/nes.h @@ -64,11 +64,6 @@ typedef struct nes_s mmc_t *mmc; rominfo_t *rominfo; - /* video buffer */ -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - bitmap_t *vidbuf; -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - bool fiq_occurred; uint8 fiq_state; int fiq_cycles; diff --git a/src/noftypes.h b/src/noftypes.h index 86cf9c4..3a2dc03 100644 --- a/src/noftypes.h +++ b/src/noftypes.h @@ -35,7 +35,7 @@ /* For the ESP32, it costs too much memory to render to a separate buffer and blit that to the main buffer. Instead, the code has been modified to directly grab the primary buffer from the video subsystem and render there, saving us about 64K of memory. */ -// #define NOFRENDO_DOUBLE_FRAMEBUFFER + /* Define this if running on little-endian (x86) systems */ #define HOST_LITTLE_ENDIAN diff --git a/src/vid_drv.c b/src/vid_drv.c index 23bc5d2..e216de8 100644 --- a/src/vid_drv.c +++ b/src/vid_drv.c @@ -35,12 +35,10 @@ /* hardware surface */ static bitmap_t *screen = NULL; -/* primary / backbuffer surfaces */ -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER -static bitmap_t *primary_buffer = NULL, *back_buffer = NULL; -#else /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ +/* primary surface */ +// backbuffer_stuff should be done outside + static bitmap_t *primary_buffer = NULL; -#endif /* !NOFRENDO_DOUBLE_FRAMEBUFFER */ static viddriver_t *driver = NULL; @@ -386,13 +384,6 @@ void vid_flush(void) driver->custom_blit(primary_buffer, num_dirties, dirty_rects); else vid_blitscreen(num_dirties, dirty_rects); - -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - /* Swap pointers to the main/back buffers */ - temp = back_buffer; - back_buffer = primary_buffer; - primary_buffer = temp; -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ } /* emulated machine tells us which resolution it wants */ @@ -400,35 +391,14 @@ int vid_setmode(int width, int height) { if (NULL != primary_buffer) bmp_destroy(&primary_buffer); -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - if (NULL != back_buffer) - bmp_destroy(&back_buffer); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - primary_buffer = bmp_create(width, height, 0); /* no overdraw */ -#else + primary_buffer = bmp_create(width, height, 8); /* overdraw 8 */ -#endif if (NULL == primary_buffer) return -1; -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - /* Create our backbuffer */ - back_buffer = bmp_create(width, height, 0); /* no overdraw */ - if (NULL == back_buffer) - { - bmp_destroy(&primary_buffer); - return -1; - } -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ bmp_clear(primary_buffer, GUI_BLACK); -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - bmp_clear(back_buffer, GUI_BLACK); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - return 0; } @@ -484,11 +454,6 @@ void vid_shutdown(void) if (NULL != primary_buffer) bmp_destroy(&primary_buffer); -#ifdef NOFRENDO_DOUBLE_FRAMEBUFFER - if (NULL != back_buffer) - bmp_destroy(&back_buffer); -#endif /* NOFRENDO_DOUBLE_FRAMEBUFFER */ - if (driver && driver->shutdown) driver->shutdown(); } From c90e5242da412c70943125301d3ff44053afdf17 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Mon, 13 Oct 2025 14:00:13 +0000 Subject: [PATCH 20/21] Restore xoffs as well as 33 ppu tiles cause origin of mem problem was found --- src/nes/nes_ppu.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/nes/nes_ppu.c b/src/nes/nes_ppu.c index 92847f0..8aad653 100644 --- a/src/nes/nes_ppu.c +++ b/src/nes/nes_ppu.c @@ -701,9 +701,7 @@ static void ppu_renderbg(uint8 *vidbuf) memset(vidbuf, FULLBG, NES_SCREEN_WIDTH); return; } - // completely ignore xofs, mem bug, need to dive into it more - bmp_ptr = vidbuf; - // bmp_ptr = vidbuf - ppu.tile_xofs; /* scroll x */ + bmp_ptr = vidbuf - ppu.tile_xofs; /* scroll x */ refresh_vaddr = 0x2000 + (ppu.vaddr & 0x0FE0); /* mask out x tile */ x_tile = ppu.vaddr & 0x1F; y_tile = (ppu.vaddr >> 5) & 0x1F; /* to simplify calculations */ @@ -718,10 +716,7 @@ static void ppu_renderbg(uint8 *vidbuf) col_high = ((attrib >> attrib_shift) & 3) << 2; /* ppu fetches 33 tiles */ - tile_count = 32; - // ppu fetches 33, but screen is 32, additional one for smooth scrolling - // but our vidbuf bitmap wrongly allocates mem or something. - // anyways we just render 32 and no mem problem. + tile_count = 33; while (tile_count--) { From 5c2163ad6e87c491433262d2ef7e7de24173bde0 Mon Sep 17 00:00:00 2001 From: Alex <15167344+frostmorn@users.noreply.github.com> Date: Wed, 15 Oct 2025 21:58:21 +0000 Subject: [PATCH 21/21] allow driver not provide lock_write. this effectively removes 134 KB of mem usage --- src/vid_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vid_drv.c b/src/vid_drv.c index e216de8..1b10f6d 100644 --- a/src/vid_drv.c +++ b/src/vid_drv.c @@ -414,7 +414,8 @@ static int vid_findmode(int width, int height, viddriver_t *osd_driver) driver = osd_driver; /* re-assert dimensions, clear the surface */ - screen = driver->lock_write(); + if (driver->lock_write) + screen = driver->lock_write(); /* use custom pageclear, if necessary */ if (driver->clear) @@ -422,7 +423,8 @@ static int vid_findmode(int width, int height, viddriver_t *osd_driver) else bmp_clear(screen, GUI_BLACK); - nofrendo_log_printf("video driver: %s at %dx%d\n", driver->name, + if (screen) + nofrendo_log_printf("video driver: %s at %dx%d\n", driver->name, screen->width, screen->height); /* release surface */