From 6274071e3857c1640cc5aef804cb86509ab312f9 Mon Sep 17 00:00:00 2001 From: Peter Fors Date: Thu, 3 Apr 2025 20:02:00 +0200 Subject: Move to glfw --- mknes.c | 290 +++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 166 insertions(+), 124 deletions(-) (limited to 'mknes.c') diff --git a/mknes.c b/mknes.c index d94c868..54da663 100644 --- a/mknes.c +++ b/mknes.c @@ -1,6 +1,85 @@ -#include +#define GL_SILENCE_DEPRECATION +#define GLFW_INCLUDE_NONE +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_WIDTH 256 +#define BUFFER_HEIGHT 240 +#define WINDOW_WIDTH 320 * 3 +#define WINDOW_HEIGHT 240 * 3 + +#ifndef restrict +# if defined(__cplusplus) +# define restrict __restrict +# endif +#endif + + +struct main_state { + int32_t filter_override; + float filter_frequency; + + uint32_t screen_width; + uint32_t screen_height; + + uint32_t texture; + uint32_t render_width; + uint32_t render_height; + uint32_t shader_program; + + float contrast; + float saturation; + float brightness; + float tone_data[4]; + + int32_t uniform_resolution; + int32_t uniform_src_image_size; + int32_t uniform_brightness; + int32_t uniform_tone; + int32_t uniform_crt_emulation; + int32_t uniform_sampler_location; + + uint32_t vao; + uint32_t vbo; + uint32_t ebo; + + struct { + int32_t x; + int32_t y; + int32_t w; + int32_t h; + } viewport; + + uint8_t fullscreen; + uint8_t toggle_crt_emulation; +}; + +struct main_state state; + +uint32_t buffer[BUFFER_WIDTH * BUFFER_HEIGHT] __attribute__((section(".bss"), aligned(4096))); +uint32_t display_buffer[BUFFER_WIDTH * BUFFER_HEIGHT] __attribute__((section(".bss"), aligned(4096))); + +void audio_callback(int16_t *data, size_t frames) { -#include "base.c" +} + + +#define FRAME_INTERVAL_NS (1000000000ULL / 60.0988) + +static GLFWwindow *window; + +#define DEBUG_PRINT printf +#include "timer.c" +#include "opengl_loader.c" +#include "opengl.c" +#include "render.c" +#include "audio.c" +#include "callbacks.c" #include "mapper.h" @@ -12,65 +91,25 @@ #include "ines2.c" #include "mapper.c" - - struct nes_state nstate; static uint32_t frames; -static void render_callback(void) { - clear_buffer(); - while(!nstate.ppu.frame_ready) { - PROFILE_NAMED("nes emulator"); - cpu_tick(&nstate); - } - nstate.ppu.frame_ready = 0; - frames++; - - uint32_t *dst = RENDER_START(0,0); - uint8_t *src = nstate.ppu.pixels; - for(uint32_t y = 0; y < 240; ++y) { - for(uint32_t x = 0; x < 256; ++x) { - uint8_t val = *src++; - if(val >= 64) val = 0; - dst[x] = nes_palette[val]; - } - dst += BUFFER_WIDTH; - } -} - -static void shutdown_callback() { - printf("%d\n", frames); -} - -static void audio_callback(int16_t *buffer, size_t frames) { - -} - -#include -#include - -void protect_opcode_lut(void) { - uintptr_t addr = (uintptr_t)opcode_lut; - size_t page_size = getpagesize(); - uintptr_t page = addr & ~(page_size - 1); - - if(mprotect((void*)page, page_size, PROT_READ) != 0) { - perror("mprotect"); - abort(); - } -} +int main(int argc, char **argv) { +#ifdef _WIN32 + timeBeginPeriod(1); +#endif -static void init_callback(void) { + state.toggle_crt_emulation = 1; setbuf(stdout, 0); init_opcode_lut(); init_opcode_ud_lut(); // protect_opcode_lut(); ppu_reset(&nstate); // ines2_load(&nstate, "data/nrom/10-Yard Fight (USA, Europe).nes"); - // ines2_load(&nstate, "data/nrom/Balloon Fight (USA).nes"); - ines2_load(&nstate, "data/nrom/Excitebike (Japan, USA).nes"); + ines2_load(&nstate, "data/nrom/Balloon Fight (USA).nes"); + // ines2_load(&nstate, "data/nrom/Excitebike (Japan, USA).nes"); // ines2_load(&nstate, "data/nrom/Ice Climber (USA, Europe, Korea).nes"); // ines2_load(&nstate, "data/nrom/Kung Fu (Japan, USA).nes"); // ines2_load(&nstate, "data/nrom/Super Mario Bros. (World) (HVC-SM).nes"); @@ -93,82 +132,85 @@ static void init_callback(void) { uint32_t lo = nstate.mapper.read(&nstate, 0xfffc); uint32_t hi = nstate.mapper.read(&nstate, 0xfffd); nstate.cpu.pc = (hi << 8) | lo; -} - -// int main(void) { -// struct nes_state state = {0}; - -// init_opcode_lut(); -// init_opcode_ud_lut(); -// state.cpu.sp = 0xfd; - -// // FILE *f = fopen("nestest.nes", "rb"); -// // fseek(f, 16, SEEK_SET); -// // fread(&state.memory[0xc000], 1, 0x4000, f); -// // fclose(f); -// // state.cpu.pc = 0xc000; - -// FILE *f = fopen("6502_functional_test.bin", "rb"); -// fread(state.memory, 1, 0x10000, f); -// fclose(f); -// state.cpu.pc = 0x0400; - -// size_t i; -// for(i = 0; i < 70000000; ++i) { -// cpu_tick(&state); -// if(state.cpu.pc == 0x3469) break; -// } -// // printf("%lld", i); -// return 0; -// } - - - - -// bool running = true; -// uint64_t next_update = mkfw_gettime(); -// int64_t frame_duration_ns = 16666667; // NTSC ~60.0988 Hz - -// audio_sync_init(next_update); // Initialize sync base time -// while(running && !mkfw_should_close()) { -// mkfw_pump_messages(); -// if(key_pressed(MKS_KEY_ESCAPE)) { running = false; } - -// #ifdef PROFILER -// reset_profiling_data(); -// #endif - -// render_callback(); -// apply_phosphor_decay(); -// update_keyboard_state(); -// update_modifier_state(); -// update_mouse_state(); -// state.frame_number++; - -// #ifndef PERF_TEST -// render_frame(); -// #ifdef PROFILER -// debug_render(); -// #endif - -// audio_throttle_emulator(state.frame_number, &frame_duration_ns); - -// uint64_t now = mkfw_gettime(); -// int64_t remaining = next_update - now; - -// if(remaining > 0) { -// if(remaining > ONE_MILLISECOND_NS) { -// mkfw_sleep(remaining - ONE_MILLISECOND_NS); -// } -// while(mkfw_gettime() < next_update) { /**/ } -// } else { -// next_update = now; -// } + struct timer_handle *timer = timer_new(FRAME_INTERVAL_NS); + if(!timer) { + fprintf(stderr, "Failed to create timer\n"); + return 1; + } -// next_update += frame_duration_ns; + if(glfwInit()) { + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); + + window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "NES Emulator", 0, 0); + if(window) { + glfwSetWindowAspectRatio(window, 320, 240); + glfwSetWindowSizeLimits(window, 320*3, 240*3, GLFW_DONT_CARE, GLFW_DONT_CARE); + + glfwMakeContextCurrent(window); + opengl_setup(); + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_callback); + glfwSwapInterval(0); + + framebuffer_callback(window, WINDOW_WIDTH, WINDOW_HEIGHT); + + for(int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) { + if(glfwJoystickPresent(jid)) { + const char *name = glfwGetJoystickName(jid); + printf("Joystick %d detected: %s\n", jid, name); + break; + } + } + + set_decay(20); + + timer_start(timer); + + while(!glfwWindowShouldClose(window)) { + timer_wait(timer); + glfwPollEvents(); + +// // + while(!nstate.ppu.frame_ready) { + // PROFILE_NAMED("nes emulator"); + cpu_tick(&nstate); + } + nstate.ppu.frame_ready = 0; + frames++; + + uint32_t *dst = buffer; + uint8_t *src = nstate.ppu.pixels; + for(uint32_t y = 0; y < 240; ++y) { + for(uint32_t x = 0; x < 256; ++x) { + uint8_t val = *src++; + if(val >= 64) val = 0; + dst[x] = nes_palette[val]; + } + dst += BUFFER_WIDTH; + } +// + apply_phosphor_decay(); + render_frame(); + glfwSwapBuffers(window); + } + + glfwDestroyWindow(window); + } else { + fprintf(stderr, "Failed to create window\n"); + } + glfwTerminate(); -// mkfw_swap_buffers(); -// #endif -// } + } else { + fprintf(stderr, "Failed to initialize GLFW\n"); + } + timer_destroy(timer); +#ifdef _WIN32 + timeEndPeriod(1); +#endif + return 0; +} -- cgit v1.2.3