#define PPU_CTRL_BG_TILE_SELECT 0x10 #define PPU_CTRL_SPRITE_TILE_SELECT 0x08 // Define constants for PPU control and mask bits #define PPU_CTRL_NMI 0x80 #define PPU_CTRL_SPRITE_HEIGHT 0x20 #define PPU_CTRL_SPRITE_TILE 0x08 #define PPU_CTRL_VRAM_INCREMENT 0x04 #define PPU_MASK_SHOW_BG 0x08 #define PPU_MASK_SHOW_SPRITES 0x10 // Define mirroring modes #define MIRROR_HORIZONTAL 0 #define MIRROR_VERTICAL 1 #define MIRROR_FOURSCREEN 2 struct ppu_state { uint16_t bg_shift_pattern_low; // 0 uint16_t bg_shift_pattern_high; // 2 uint16_t bg_shift_attrib_low; // 4 uint16_t bg_shift_attrib_high; // 6 uint16_t scanline; // 8 uint16_t dot; // 10 uint16_t vram_addr; // 12 uint16_t temp_addr; // 14 uint8_t fine_x; // 16 uint8_t bg_next_tile_id; // 17 uint8_t bg_next_tile_attrib; // 18 uint8_t bg_next_tile_lsb; // 19 uint8_t bg_next_tile_msb; // 20 uint8_t oam_addr; // 21 uint8_t oam_data; // 22 uint8_t even_frame; // 23 uint8_t reg_ctrl; // 24 uint8_t reg_mask; // 25 uint8_t reg_status; // 26 uint8_t write_latch; // 27 uint8_t vram_read_buffer; // 28 uint8_t open_bus; // 29 uint8_t sprite_count; // 30 uint8_t overflow_scheduled_dot; // 31 uint8_t palette[32]; // 32 // NOTE(peter): CACHELINE 2 uint8_t secondary_oam[32] __attribute__((aligned(64))); uint8_t temp_secondary_oam[32]; // NOTE(peter): CACHELINE 3 struct sprite_data { uint8_t shift_lo; uint8_t shift_hi; uint8_t position; uint8_t priority; uint8_t palette; } __attribute__((packed, aligned(64))) sprites[8]; uint8_t input[2]; // 40 - Controller 1 & 2 uint8_t input_latch[2]; // 42 - Latched inputs after strobe uint8_t input_bit[2]; // 44 - Current bit position being shifted out uint8_t input_strobe; // 46 - Control bit (0 or 1) uint8_t frame_ready; // 47 uint8_t sprite_zero_in_range; // 48 - Boolean: is sprite 0 in range (will always be slot 0 if true) uint8_t sprite_count_next; // 49 - Sprite count for next scanline // 15 bytes left. // NOTE(peter): CACHELINE 4 uint8_t oam[256] __attribute__((aligned(64))); } __attribute__((packed)); struct apu_state { uint32_t frame_cycle; uint16_t dmc_current_addr; uint16_t dmc_bytes_remaining; uint16_t dmc_sample_timer; uint8_t mode; uint8_t irq_inhibit; uint8_t irq_pending; uint8_t dmc_irq_enable; uint8_t dmc_loop_flag; uint8_t dmc_dma_enabled; uint8_t dmc_freq_index; uint8_t dmc_sample_addr; uint8_t dmc_sample_len; } __attribute__((packed)); struct cpu_state { size_t cycles; uint16_t pc; // Program Counter uint8_t sp; // Stack Pointer uint8_t a; // Accumulator uint8_t x; // X Register uint8_t y; // Y Register uint8_t p; // Processor Status Flags (this can be expanded with separate flags if needed) uint8_t n; // Negative Flag uint8_t v; // Overflow Flag // uint8_t b; // Break Flag (Set by BRK instruction) -- does not exist outside the stack uint8_t d; // Decimal Flag (exists but ignored on NES) uint8_t i; // Interrupt Disable Flag uint8_t z; // Zero Flag uint8_t c; // Carry Flag // -- uint8_t irq_pending; uint8_t nmi_pending; }; struct ines_state { uint8_t mapper; uint8_t submapper; uint8_t mirroring; // 0 = H, 1 = V, 2 = 4-screen uint32_t prg_size; uint32_t chr_size; }; struct nes_state { struct ppu_state ppu __attribute__((aligned(4096))); struct mapper_functions mapper_function __attribute__((aligned(64))); union mapper_data mapper_data __attribute__((aligned(64))); struct cpu_state cpu __attribute__((aligned(64))); struct ines_state ines __attribute__((aligned(64))); struct apu_state apu __attribute__((aligned(64))); uint8_t ram[RAM_SIZE] __attribute__((aligned(4096))); uint8_t ciram[CIRAM_SIZE] __attribute__((aligned(4096))); uint8_t prg_rom[PRG_ROM_SIZE] __attribute__((aligned(4096))); uint8_t chr_rom[CHR_ROM_SIZE] __attribute__((aligned(4096))); uint8_t chr_ram[CHR_RAM_SIZE] __attribute__((aligned(4096))); uint8_t pixels[PIXELS_SIZE] __attribute__((aligned(4096))); uint8_t sram[SRAM_SIZE] __attribute__((aligned(4096))); }; __attribute__((aligned(4096))) static uint32_t nes_palette[65] = { 0x585858ff, 0x00237cff, 0x0d1099ff, 0x300092ff, 0x4f006cff, 0x600035ff, 0x5c0500ff, 0x461800ff, 0x272d00ff, 0x093e00ff, 0x004500ff, 0x004106ff, 0x003545ff, 0x000000ff, 0x000000ff, 0x000000ff, 0xa1a1a1ff, 0x0b53d7ff, 0x3337feff, 0x6621f7ff, 0x9515beff, 0xac166eff, 0xa62721ff, 0x864300ff, 0x596200ff, 0x2d7a00ff, 0x0c8500ff, 0x007f2aff, 0x006d85ff, 0x000000ff, 0x000000ff, 0x000000ff, 0xffffffff, 0x51a5feff, 0x8084feff, 0xbc6afeff, 0xf15bfeff, 0xfe5ec4ff, 0xfe7269ff, 0xe19321ff, 0xadb600ff, 0x79d300ff, 0x51df21ff, 0x3ad974ff, 0x39c3dfff, 0x424242ff, 0x000000ff, 0x000000ff, 0xffffffff, 0xb5d9feff, 0xcacafeff, 0xe3befeff, 0xf9b8feff, 0xfebae7ff, 0xfec3bcff, 0xf4d199ff, 0xdee086ff, 0xc6ec87ff, 0xb2f29dff, 0xa7f0c3ff, 0xa8e7f0ff, 0xacacacff, 0x000000ff, 0x000000ff, 0xffffffff // one extra for debug-coloring... }; struct remake_state { struct { int32_t x, y, w, h; } viewport; int32_t mouse_dx; int32_t mouse_dy; float contrast; float saturation; float brightness; float tone_data[4]; // OpenGL Objects GLuint shader_program; GLuint persistence_program; // GLuint upscale_program; GLuint upscale_warp_program; GLuint bloom_extract_program; GLuint bloom_blur_program; GLuint bloom_warp_program; GLuint bloom_composite_program; GLuint texture; GLuint persistence_texture; GLuint persistence_output_texture; GLuint crt_output_texture; GLuint bloom_texture; GLuint bloom_temp_texture; GLuint bloom_warped_texture; GLuint upscaled_source_texture; GLuint persistence_fbo; GLuint upscaled_source_fbo; GLuint crt_fbo; GLuint bloom_fbo; GLuint bloom_temp_fbo; GLuint bloom_warp_fbo; GLuint vao; GLuint vbo; GLuint ebo; // CRT Shader Uniforms GLuint uniform_resolution; GLuint uniform_src_image_size; GLuint uniform_brightness; GLuint uniform_tone; GLuint uniform_crt_emulation; GLuint uniform_apply_mask; GLuint uniform_sampler_location; // Bloom Shader Uniforms GLuint bloom_uniform_threshold; GLuint bloom_uniform_sampler; GLuint blur_uniform_horizontal; GLuint blur_uniform_sampler; GLuint composite_uniform_bloom_strength; GLuint composite_uniform_crt_sampler; GLuint composite_uniform_bloom_sampler; // Bloom settings float bloom_threshold; float bloom_strength; uint32_t bloom_width; uint32_t bloom_height; // Phosphor persistence float persistence_decay; // Rendering & Dynamic Resolution uint32_t render_width; // The actual remake resolution (e.g., 360) uint32_t render_height; // The actual remake resolution (e.g., 270) uint32_t frame_number; uint8_t running; uint8_t toggle_crt_emulation; uint8_t toggle_bloom; uint8_t fullscreen; uint8_t viewport_changed; // Flag to signal render thread to recreate FBOs }; // static struct remake_state state;