mirror of
https://github.com/marian-m12l/game-and-watch-zelda3.git
synced 2025-12-17 07:16:05 +01:00
197 lines
4.5 KiB
C
197 lines
4.5 KiB
C
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "porting.h"
|
|
#include "zelda_assets.h"
|
|
|
|
#include "zelda3/assets.h"
|
|
#include "zelda3/config.h"
|
|
#include "zelda3/types.h"
|
|
#include "zelda3/zelda_rtl.h"
|
|
|
|
|
|
#define WIDTH 256 // FIXME 320
|
|
#define HEIGHT 224 // FIXME 240
|
|
#define BPP 4
|
|
#define SCALE 1
|
|
|
|
#define NES_SCREEN_WIDTH 256
|
|
#define NES_SCREEN_HEIGHT 240
|
|
|
|
|
|
#define APP_ID 30
|
|
|
|
// Framebuffer
|
|
uint16_t fb_data[WIDTH * HEIGHT * BPP];
|
|
|
|
// NES Screen framebuffers
|
|
/*static uint8_t bitmap_data[2][sizeof(bitmap_t) + (sizeof(uint8 *) * NES_SCREEN_HEIGHT)];
|
|
static bitmap_t *framebuffers[2];
|
|
framebuffers[0] = (bitmap_t*)bitmap_data[0];
|
|
framebuffers[1] = (bitmap_t*)bitmap_data[1];*/
|
|
|
|
|
|
static uint8 g_paused, g_turbo, g_replay_turbo = true, g_cursor = true;
|
|
static uint8 g_current_window_scale;
|
|
static uint8 g_gamepad_buttons;
|
|
static int g_input1_state;
|
|
static bool g_display_perf;
|
|
static int g_curr_fps;
|
|
static int g_ppu_render_flags = 0;
|
|
static int g_snes_width, g_snes_height;
|
|
//static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
|
|
//static struct RendererFuncs g_renderer_funcs;
|
|
static uint32 g_gamepad_modifiers;
|
|
static uint16 g_gamepad_last_cmd[kGamepadBtn_Count];
|
|
|
|
void NORETURN Die(const char *error) {
|
|
//#if defined(NDEBUG) && defined(_WIN32)
|
|
// SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, kWindowTitle, error, NULL);
|
|
//#endif
|
|
fprintf(stderr, "Error: %s\n", error);
|
|
exit(1);
|
|
}
|
|
|
|
const uint8 *g_asset_ptrs[kNumberOfAssets];
|
|
uint32 g_asset_sizes[kNumberOfAssets];
|
|
|
|
static void LoadAssets() {
|
|
// TODO static allocation --> direct flash access???
|
|
size_t length = zelda_assets_length;
|
|
uint8 *data = zelda_assets;
|
|
|
|
static const char kAssetsSig[] = { kAssets_Sig };
|
|
|
|
if (length < 16 + 32 + 32 + 8 + kNumberOfAssets * 4 ||
|
|
memcmp(data, kAssetsSig, 48) != 0 ||
|
|
*(uint32*)(data + 80) != kNumberOfAssets)
|
|
Die("Invalid assets file");
|
|
|
|
uint32 offset = 88 + kNumberOfAssets * 4 + *(uint32 *)(data + 84);
|
|
|
|
for (size_t i = 0; i < kNumberOfAssets; i++) {
|
|
uint32 size = *(uint32 *)(data + 88 + i * 4);
|
|
offset = (offset + 3) & ~3;
|
|
if ((uint64)offset + size > length)
|
|
Die("Assets file corruption");
|
|
g_asset_sizes[i] = size;
|
|
g_asset_ptrs[i] = data + offset;
|
|
offset += size;
|
|
}
|
|
}
|
|
|
|
|
|
static void DrawPpuFrameWithPerf() {
|
|
/*int render_scale = PpuGetCurrentRenderScale(g_zenv.ppu, g_ppu_render_flags);*/
|
|
uint8 *pixel_buffer = fb_data; //0;
|
|
int pitch = WIDTH * BPP; // FIXME 0;
|
|
|
|
ZeldaDrawPpuFrame(pixel_buffer, pitch, g_ppu_render_flags);
|
|
}
|
|
|
|
|
|
void ZeldaApuLock() {
|
|
}
|
|
|
|
void ZeldaApuUnlock() {
|
|
}
|
|
|
|
static void HandleCommand(uint32 j, bool pressed) {
|
|
if (j <= kKeys_Controls_Last) {
|
|
static const uint8 kKbdRemap[] = { 0, 4, 5, 6, 7, 2, 3, 8, 0, 9, 1, 10, 11 };
|
|
if (pressed)
|
|
g_input1_state |= 1 << kKbdRemap[j];
|
|
else
|
|
g_input1_state &= ~(1 << kKbdRemap[j]);
|
|
return;
|
|
}
|
|
|
|
if (j == kKeys_Turbo) {
|
|
g_turbo = pressed;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
printf("GNW Headless\n");
|
|
|
|
printf("To access in-memory framebuffer:\n");
|
|
printf(" sudo ./viewer %d %lx %lu\n", getpid(), (long unsigned int) fb_data, sizeof(fb_data));
|
|
|
|
LoadAssets();
|
|
ZeldaInitialize();
|
|
|
|
bool running = true;
|
|
uint32 lastTick = HAL_GetTick();
|
|
uint32 curTick = 0;
|
|
uint32 frameCtr = 0;
|
|
bool audiopaused = true;
|
|
|
|
while(running) {
|
|
|
|
if (g_paused != audiopaused) {
|
|
audiopaused = g_paused;
|
|
}
|
|
|
|
if (g_paused) {
|
|
continue;
|
|
}
|
|
|
|
// Clear gamepad inputs when joypad directional inputs to avoid wonkiness
|
|
int inputs = g_input1_state;
|
|
if (g_input1_state & 0xf0)
|
|
g_gamepad_buttons = 0;
|
|
inputs |= g_gamepad_buttons;
|
|
|
|
bool is_replay = ZeldaRunFrame(inputs);
|
|
|
|
frameCtr++;
|
|
|
|
if ((g_turbo ^ (is_replay & g_replay_turbo)) && (frameCtr & (g_turbo ? 0xf : 0x7f)) != 0) {
|
|
continue;
|
|
}
|
|
|
|
DrawPpuFrameWithPerf();
|
|
|
|
// if vsync isn't working, delay manually
|
|
curTick = HAL_GetTick();
|
|
|
|
if (!g_config.disable_frame_delay) {
|
|
static const uint8 delays[3] = { 17, 17, 16 }; // 60 fps
|
|
lastTick += delays[frameCtr % 3];
|
|
|
|
if (lastTick > curTick) {
|
|
uint32 delta = lastTick - curTick;
|
|
if (delta > 500) {
|
|
lastTick = curTick - 500;
|
|
delta = 500;
|
|
}
|
|
// printf("Sleeping %d\n", delta);
|
|
} else if (curTick - lastTick > 500) {
|
|
lastTick = curTick;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|