GB: Start work on video rendering

This commit is contained in:
Jeffrey Pfau 2016-01-18 21:03:50 -08:00
parent 23ca81708d
commit 3158db06c2
12 changed files with 491 additions and 113 deletions

View File

@ -13,6 +13,8 @@ set(USE_ZLIB ON CACHE BOOL "Whether or not to enable zlib support")
set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support")
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support")
set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core")
set(USE_BLIP ON CACHE BOOL "Whether or not to enable blip_buf support")
set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support")
set(BUILD_QT ON CACHE BOOL "Build Qt frontend")
@ -40,17 +42,18 @@ file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)
file(GLOB GBA_CTX_SRC ${CMAKE_SOURCE_DIR}/src/gba/context/*.c)
file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs])
file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_SOURCE_DIR}/src/gba/gui/*.c)
file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)
file(GLOB GBA_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)
file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c)
file(GLOB GB_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gb/renderers/*.c)
file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c)
list(APPEND GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c)
set(VFS_SRC)
source_group("ARM core" FILES ${ARM_SRC})
source_group("LR35902 core" FILES ${LR35902_SRC})
source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC})
source_group("GBA board" FILES ${GBA_SRC} ${GBA_RENDERER_SRC} ${SIO_SRC})
source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_CTX_SRC} ${GBA_SV_SRC} ${GBA_RR_SRC})
source_group("GB board" FILES ${GBA_SRC})
source_group("GB board" FILES ${GB_SRC})
source_group("Utilities" FILES ${UTIL_SRC})
include_directories(${CMAKE_SOURCE_DIR}/src/arm)
include_directories(${CMAKE_SOURCE_DIR}/src)
@ -494,30 +497,42 @@ if(PSP2)
endif()
# Binaries
set(CORE_SRC
${ARM_SRC}
${LR35902_SRC}
${GBA_SRC}
${GB_SRC}
${GBA_CHEATS_SRC}
${GBA_CTX_SRC}
${DEBUGGER_SRC}
${RENDERER_SRC}
set(CORE_SRC)
if(M_CORE_GB)
add_definitions(-DM_CORE_GB)
list(APPEND CORE_SRC
${LR35902_SRC}
${GB_SRC}
${GB_RENDERER_SRC})
endif()
if(M_CORE_GBA)
add_definitions(-DM_CORE_GBA)
list(APPEND CORE_SRC
${ARM_SRC}
${GBA_SRC}
${GBA_CHEATS_SRC}
${GBA_CTX_SRC}
${DEBUGGER_SRC}
${GBA_RENDERER_SRC})
endif()
list(APPEND CORE_SRC
${UTIL_SRC}
${CORE_VFS_SRC}
${OS_SRC}
${THIRD_PARTY_SRC})
set(SRC ${CORE_SRC} ${VFS_SRC})
if(NOT MINIMAL_CORE)
set(SRC
${CORE_SRC}
${GBA_RR_SRC}
${GBA_SV_SRC}
${SIO_SRC}
${FEATURE_SRC}
${VFS_SRC})
else()
set(SRC ${CORE_SRC} ${VFS_SRC})
if(M_CORE_GBA)
list(APPEND SRC
${GBA_RR_SRC}
${GBA_SV_SRC}
${SIO_SRC})
endif()
list(APPEND SRC
${FEATURE_SRC})
endif()
if(NOT SKIP_LIBRARY)
@ -680,6 +695,9 @@ else()
set(SUMMARY_ZIP OFF)
endif()
message(STATUS "Platforms:")
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
message(STATUS " Game Boy: ${M_CORE_GB}")
message(STATUS "Features:")
message(STATUS " CLI debugger: ${USE_CLI_DEBUGGER}")
message(STATUS " GDB stub: ${USE_GDB_STUB}")

View File

@ -183,3 +183,17 @@ void GBHitStub(struct LR35902Core* cpu) {
// TODO
//printf("Hit stub at address %04X\n", cpu->pc);
}
bool GBIsROM(struct VFile* vf) {
vf->seek(vf, 0x104, SEEK_SET);
uint8_t header[4];
static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
return false;
}
if (memcmp(header, knownHeader, sizeof(header))) {
return false;
}
return true;
}

108
src/gb/renderers/software.c Normal file
View File

@ -0,0 +1,108 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "software.h"
#include "util/memory.h"
static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
static const color_t GB_PALETTE[4] = { 0xFFFF, 0x39C7, 0x18C3, 0x0000};
#else
static const color_t GB_PALETTE[4] = { 0x7FFF, 0x1DE7, 0x0C63, 0x0000};
#endif
#else
static const color_t GB_PALETTE[4] = { 0xFFFFFF, 0x808080, 0x404040, 0x000000};
#endif
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
renderer->d.init = GBVideoSoftwareRendererInit;
renderer->d.reset = GBVideoSoftwareRendererReset;
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline;
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
renderer->d.getPixels = 0;
renderer->d.putPixels = 0;
renderer->temporaryBuffer = 0;
}
static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer) {
GBVideoSoftwareRendererReset(renderer);
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
int y;
for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) {
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
int x;
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
row[x] = GB_PALETTE[0];
}
}
}
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
int i;
// TODO
}
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
UNUSED(softwareRenderer);
}
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
// TODO
}
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
// TODO
return value;
}
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
// TODO
size_t x;
#ifdef COLOR_16_BIT
#if defined(__ARM_NEON) && !defined(__APPLE__)
_to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS);
#else
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
row[x] = softwareRenderer->row[x];
}
#endif
#else
memcpy(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS * sizeof(*row));
#endif
}
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
if (softwareRenderer->temporaryBuffer) {
mappedMemoryFree(softwareRenderer->temporaryBuffer, GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * 4);
softwareRenderer->temporaryBuffer = 0;
}
}

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2013-2016 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GB_RENDERER_SOFTWARE_H
#define GB_RENDERER_SOFTWARE_H
#include "util/common.h"
#include "gb/video.h"
#ifdef COLOR_16_BIT
typedef uint16_t color_t;
#else
typedef uint32_t color_t;
#endif
struct GBVideoSoftwareRenderer {
struct GBVideoRenderer d;
color_t* outputBuffer;
int outputBufferStride;
uint32_t row[GB_VIDEO_HORIZONTAL_PIXELS];
uint32_t* temporaryBuffer;
};
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
#endif

View File

@ -64,7 +64,10 @@ void GBVideoDeinit(struct GBVideo* video) {
}
void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) {
// TODO
video->renderer->deinit(video->renderer);
video->renderer = renderer;
renderer->vram = video->vram;
video->renderer->init(video->renderer);
}
int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
@ -79,11 +82,15 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
if (video->nextMode <= 0) {
switch (video->mode) {
case 0:
if (video->ly < GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
video->renderer->drawScanline(video->renderer, video->ly);
}
++video->ly;
video->p->memory.io[REG_LY] = video->ly;
if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
video->ly = 0;
++video->frameCounter;
video->renderer->finishFrame(video->renderer);
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH;
video->mode = 1;
if (GBRegisterSTATIsVblankIRQ(video->stat)) {

View File

@ -5,8 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "main.h"
void GBASDLGLCommonSwap(struct VideoBackend* context) {
struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user;
void mSDLGLCommonSwap(struct VideoBackend* context) {
struct mSDLRenderer* renderer = (struct mSDLRenderer*) context->user;
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_SwapWindow(renderer->window);
#else
@ -15,7 +15,7 @@ void GBASDLGLCommonSwap(struct VideoBackend* context) {
#endif
}
void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer) {
void mSDLGLCommonInit(struct mSDLRenderer* renderer) {
#ifndef COLOR_16_BIT
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);

View File

@ -7,7 +7,7 @@
#define SDL_GL_COMMON_H
#include "main.h"
void GBASDLGLCommonSwap(struct VideoBackend* context);
void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer);
void mSDLGLCommonSwap(struct VideoBackend* context);
void mSDLGLCommonInit(struct mSDLRenderer* renderer);
#endif

View File

@ -8,6 +8,9 @@
#include "gl-common.h"
#include "gba/supervisor/thread.h"
#ifdef M_CORE_GB
#include "gb/gb.h"
#endif
#include "platform/opengl/gl.h"
static void _doViewport(int w, int h, struct VideoBackend* v) {
@ -17,18 +20,25 @@ static void _doViewport(int w, int h, struct VideoBackend* v) {
v->clear(v);
}
static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);
static void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
static void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer);
#ifdef M_CORE_GBA
static bool mSDLGLInitGBA(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user);
#endif
#ifdef M_CORE_GB
static bool mSDLGLInitGB(struct mSDLRenderer* renderer);
static void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user);
#endif
static void mSDLGLDeinit(struct mSDLRenderer* renderer);
void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) {
renderer->init = GBASDLGLInit;
renderer->deinit = GBASDLGLDeinit;
renderer->runloop = GBASDLGLRunloop;
#ifdef M_CORE_GBA
void mSDLGLCreate(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGBA;
renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloopGBA;
}
bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
GBASDLGLCommonInit(renderer);
bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
@ -37,14 +47,15 @@ bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
renderer->gl.d.user = renderer;
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = GBASDLGLCommonSwap;
renderer->gl.d.swap = mSDLGLCommonSwap;
renderer->gl.d.init(&renderer->gl.d, 0);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true;
}
void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
void mSDLGLRunloopGBA(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
@ -69,8 +80,62 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
v->swap(v);
}
}
#endif
void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) {
#ifdef M_CORE_GB
void mSDLGLCreateGB(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLInitGB;
renderer->deinit = mSDLGLDeinit;
renderer->runloop = mSDLGLRunloopGB;
}
bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
// TODO: Pass texture size along
renderer->gb.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->gb.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
GBAGLContextCreate(&renderer->gl);
renderer->gl.d.user = renderer;
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = mSDLGLCommonSwap;
renderer->gl.d.init(&renderer->gl.d, 0);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true;
}
void mSDLGLRunloopGB(struct mSDLRenderer* renderer, void* user) {
struct GB* gb = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl.d;
while (true) {
int64_t frameCounter = gb->video.frameCounter;
while (gb->video.frameCounter == frameCounter) {
LR35902Tick(gb->cpu);
}
while (SDL_PollEvent(&event)) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Event handling can change the size of the screen
if (renderer->player.windowUpdated) {
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
renderer->player.windowUpdated = 0;
}
#endif
}
v->postFrame(v, renderer->gb.outputBuffer);
v->drawFrame(v);
v->swap(v);
}
}
#endif
void mSDLGLDeinit(struct mSDLRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}

View File

@ -9,17 +9,17 @@
#include <malloc.h>
static bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer);
static void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
static void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer);
static bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer);
static void mSDLGLES2RunloopGBA(struct SDLSoftwareRenderer* renderer, void* user);
static void mSDLGLES2Deinit(struct SDLSoftwareRenderer* renderer);
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer) {
renderer->init = GBASDLGLES2Init;
renderer->deinit = GBASDLGLES2Deinit;
renderer->runloop = GBASDLGLES2Runloop;
void mSDLGLES2Create(struct mSDLRenderer* renderer) {
renderer->init = mSDLGLES2Init;
renderer->deinit = mSDLGLES2Deinit;
renderer->runloop = mSDLGLES2RunloopGBA;
}
bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
#ifdef BUILD_RASPI
bcm_host_init();
renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@ -90,7 +90,7 @@ bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
return false;
}
#else
GBASDLGLCommonInit(renderer);
mSDLGLCommonInit(renderer);
#endif
renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
@ -100,12 +100,13 @@ bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
renderer->gl2.d.user = renderer;
renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl2.d.filter = renderer->filter;
renderer->gl2.d.swap = GBASDLGLCommonSwap;
renderer->gl2.d.swap = mSDLGLCommonSwap;
renderer->gl2.d.init(&renderer->gl2.d, 0);
return true;
}
void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
SDL_Event event;
struct VideoBackend* v = &renderer->gl2.d;
@ -127,7 +128,7 @@ void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* r
}
}
void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) {
void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
if (renderer->gl2.d.deinit) {
renderer->gl2.d.deinit(&renderer->gl2.d);
}

View File

@ -13,12 +13,19 @@
#include "debugger/gdb-stub.h"
#endif
#ifdef M_CORE_GBA
#include "gba/gba.h"
#include "gba/context/config.h"
#include "gba/supervisor/thread.h"
#include "gba/video.h"
#endif
#ifdef M_CORE_GB
#include "gb/gb.h"
#include "gb/video.h"
#endif
#include "platform/commandline.h"
#include "util/configuration.h"
#include "util/vfs.h"
#include <SDL.h>
@ -28,12 +35,27 @@
#define PORT "sdl"
static bool GBASDLInit(struct SDLSoftwareRenderer* renderer);
static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer);
// TODO: Move somewhere
enum mPlatform {
PLATFORM_NONE = -1,
PLATFORM_GBA,
PLATFORM_GB
};
static bool mSDLInit(struct mSDLRenderer* renderer);
static void mSDLDeinit(struct mSDLRenderer* renderer);
// TODO: Clean up signatures
#ifdef M_CORE_GBA
static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap);
#endif
#ifdef M_CORE_GB
static int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args);
#endif
int main(int argc, char** argv) {
struct SDLSoftwareRenderer renderer;
GBAVideoSoftwareRendererCreate(&renderer.d);
struct mSDLRenderer renderer;
struct GBAInputMap inputMap;
GBAInputMapInit(&inputMap);
@ -43,15 +65,14 @@ int main(int argc, char** argv) {
GBAConfigLoad(&config);
struct GBAOptions opts = {
.width = VIDEO_HORIZONTAL_PIXELS,
.height = VIDEO_VERTICAL_PIXELS,
.width = 0,
.height = 0,
.useBios = true,
.rewindEnable = true,
.audioBuffers = 512,
.videoSync = false,
.audioSync = true,
};
GBAConfigLoadDefaults(&config, &opts);
struct GBAArguments args;
struct GraphicsOpts graphicsOpts;
@ -75,6 +96,49 @@ int main(int argc, char** argv) {
return 0;
}
enum mPlatform platform = PLATFORM_NONE;
if (args.fname) {
struct VFile* vf = VFileOpen(args.fname, O_RDONLY);
if (!vf) {
printf("Could not open game. Are you sure the file exists?\n");
freeArguments(&args);
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
return 1;
}
#ifdef M_CORE_GBA
else if (GBAIsROM(vf)) {
platform = PLATFORM_GBA;
if (!opts.width) {
opts.width = VIDEO_HORIZONTAL_PIXELS;
}
if (!opts.height) {
opts.height = VIDEO_VERTICAL_PIXELS;
}
}
#endif
#ifdef M_CORE_GB
else if (GBIsROM(vf)) {
platform = PLATFORM_GB;
if (!opts.width) {
opts.width = /*GB_*/VIDEO_HORIZONTAL_PIXELS;
}
if (!opts.height) {
opts.height = /*GB_*/VIDEO_VERTICAL_PIXELS;
}
}
#endif
else {
printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n");
freeArguments(&args);
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
return 1;
}
}
GBAConfigLoadDefaults(&config, &opts);
GBAConfigMap(&config, &opts);
renderer.viewportWidth = opts.width;
@ -93,57 +157,78 @@ int main(int argc, char** argv) {
renderer.lockAspectRatio = opts.lockAspectRatio;
renderer.filter = opts.resampleVideo;
int ret;
switch (platform) {
case PLATFORM_GBA:
ret = mSDLRunGBA(&renderer, &args, &opts, &config, &inputMap);
break;
case PLATFORM_GB:
ret = mSDLRunGB(&renderer, &args);
break;
default:
ret = 1;
break;
}
freeArguments(&args);
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
return ret;
}
#ifdef M_CORE_GBA
int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap) {
GBAVideoSoftwareRendererCreate(&renderer->d);
#ifdef BUILD_GL
GBASDLGLCreate(&renderer);
mSDLGLCreate(renderer);
#elif defined(BUILD_GLES2) || defined(USE_EPOXY)
GBASDLGLES2Create(&renderer);
mSDLGLES2Create(renderer);
#else
GBASDLSWCreate(&renderer);
mSDLSWCreate(renderer);
#endif
if (!GBASDLInit(&renderer)) {
freeArguments(&args);
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
if (!mSDLInit(renderer)) {
return 1;
}
struct GBAThread context = {
.renderer = &renderer.d.d,
.userData = &renderer
.renderer = &renderer->d.d,
.userData = renderer
};
context.debugger = createDebugger(&args, &context);
context.debugger = createDebugger(args, &context);
GBAMapOptionsToContext(&opts, &context);
GBAMapArgumentsToContext(&args, &context);
GBAMapOptionsToContext(opts, &context);
GBAMapArgumentsToContext(args, &context);
bool didFail = false;
renderer.audio.samples = context.audioBuffers;
renderer.audio.sampleRate = 44100;
if (opts.sampleRate) {
renderer.audio.sampleRate = opts.sampleRate;
renderer->audio.samples = context.audioBuffers;
renderer->audio.sampleRate = 44100;
if (opts->sampleRate) {
renderer->audio.sampleRate = opts->sampleRate;
}
if (!GBASDLInitAudio(&renderer.audio, &context)) {
if (!GBASDLInitAudio(&renderer->audio, &context)) {
didFail = true;
}
renderer.player.bindings = &inputMap;
GBASDLInitBindings(&inputMap);
GBASDLInitEvents(&renderer.events);
GBASDLEventsLoadConfig(&renderer.events, GBAConfigGetInput(&config));
GBASDLAttachPlayer(&renderer.events, &renderer.player);
GBASDLPlayerLoadConfig(&renderer.player, GBAConfigGetInput(&config));
context.overrides = GBAConfigGetOverrides(&config);
renderer->player.bindings = inputMap;
GBASDLInitBindings(inputMap);
GBASDLInitEvents(&renderer->events);
GBASDLEventsLoadConfig(&renderer->events, GBAConfigGetInput(config));
GBASDLAttachPlayer(&renderer->events, &renderer->player);
GBASDLPlayerLoadConfig(&renderer->player, GBAConfigGetInput(config));
context.overrides = GBAConfigGetOverrides(config);
if (!didFail) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBASDLSetScreensaverSuspendable(&renderer.events, opts.suspendScreensaver);
GBASDLSuspendScreensaver(&renderer.events);
GBASDLSetScreensaverSuspendable(&renderer->events, opts->suspendScreensaver);
GBASDLSuspendScreensaver(&renderer->events);
#endif
if (GBAThreadStart(&context)) {
renderer.runloop(&context, &renderer);
renderer->runloop(renderer, &context);
GBAThreadJoin(&context);
} else {
didFail = true;
@ -151,8 +236,8 @@ int main(int argc, char** argv) {
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBASDLResumeScreensaver(&renderer.events);
GBASDLSetScreensaverSuspendable(&renderer.events, false);
GBASDLResumeScreensaver(&renderer->events);
GBASDLSetScreensaverSuspendable(&renderer->events, false);
#endif
if (GBAThreadHasCrashed(&context)) {
@ -160,20 +245,53 @@ int main(int argc, char** argv) {
printf("The game crashed!\n");
}
}
freeArguments(&args);
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
free(context.debugger);
GBADirectorySetDeinit(&context.dirs);
GBASDLDetachPlayer(&renderer.events, &renderer.player);
GBAInputMapDeinit(&inputMap);
GBASDLDetachPlayer(&renderer->events, &renderer->player);
GBAInputMapDeinit(inputMap);
GBASDLDeinit(&renderer);
mSDLDeinit(renderer);
return didFail;
}
#endif
static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
#ifdef M_CORE_GB
int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
GBVideoSoftwareRendererCreate(&renderer->gb);
#ifdef BUILD_GL
mSDLGLCreateGB(renderer);
#elif defined(BUILD_GLES2)
mSDLGLES2CreateGB(renderer);
#else
mSDLSWCreateGB(renderer);
#endif
if (!mSDLInit(renderer)) {
return 1;
}
struct LR35902Core cpu;
struct GB gb;
GBCreate(&gb);
LR35902SetComponents(&cpu, &gb.d, 0, 0);
LR35902Init(&cpu);
GBVideoAssociateRenderer(&gb.video, &renderer->gb.d);
struct VFile* vf = VFileOpen(args->fname, O_RDONLY);
GBLoadROM(&gb, vf, 0, args->fname);
LR35902Reset(&cpu);
renderer->runloop(renderer, &gb);
vf->close(vf);
mSDLDeinit(renderer);
return 0;
}
#endif
static bool mSDLInit(struct mSDLRenderer* renderer) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Could not initialize video: %s\n", SDL_GetError());
return false;
@ -182,7 +300,7 @@ static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
return renderer->init(renderer);
}
static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
static void mSDLDeinit(struct mSDLRenderer* renderer) {
GBASDLDeinitEvents(&renderer->events);
GBASDLDeinitAudio(&renderer->audio);
#if SDL_VERSION_ATLEAST(2, 0, 0)

View File

@ -6,7 +6,13 @@
#ifndef SDL_MAIN_H
#define SDL_MAIN_H
#ifdef M_CORE_GBA
#include "gba/renderers/video-software.h"
#endif
#ifdef M_CORE_GB
#include "gb/renderers/software.h"
#endif
#include "sdl-audio.h"
#include "sdl-events.h"
@ -34,15 +40,22 @@
#include <pixman.h>
#endif
struct SDLSoftwareRenderer {
struct GBAVideoSoftwareRenderer d;
struct mSDLRenderer {
union {
#ifdef M_CORE_GBA
struct GBAVideoSoftwareRenderer d;
#endif
#ifdef M_CORE_GB
struct GBVideoSoftwareRenderer gb;
#endif
};
struct GBASDLAudio audio;
struct GBASDLEvents events;
struct GBASDLPlayer player;
bool (*init)(struct SDLSoftwareRenderer* renderer);
void (*runloop)(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
void (*deinit)(struct SDLSoftwareRenderer* renderer);
bool (*init)(struct mSDLRenderer* renderer);
void (*runloop)(struct mSDLRenderer* renderer, void* user);
void (*deinit)(struct mSDLRenderer* renderer);
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Window* window;
@ -86,13 +99,14 @@ struct SDLSoftwareRenderer {
#endif
};
void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer);
void mSDLSWCreate(struct mSDLRenderer* renderer);
#ifdef BUILD_GL
void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer);
void mSDLGLCreate(struct mSDLRenderer* renderer);
void mSDLGLCreateGB(struct mSDLRenderer* renderer);
#endif
#if defined(BUILD_GLES2) || defined(USE_EPOXY)
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer);
void mSDLGLES2Create(struct mSDLRenderer* renderer);
#endif
#endif

View File

@ -8,17 +8,17 @@
#include "gba/supervisor/thread.h"
#include "util/arm-algo.h"
static bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer);
static void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
static void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer);
static bool mSDLSWInit(struct mSDLRenderer* renderer);
static void mSDLSWRunloopGBA(struct mSDLRenderer* renderer, void* user);
static void mSDLSWDeinit(struct mSDLRenderer* renderer);
void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer) {
renderer->init = GBASDLSWInit;
renderer->deinit = GBASDLSWDeinit;
renderer->runloop = GBASDLSWRunloop;
void mSDLSWCreate(struct mSDLRenderer* renderer) {
renderer->init = mSDLSWInit;
renderer->deinit = mSDLSWDeinit;
renderer->runloop = mSDLSWRunloopGBA;
}
bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer) {
bool mSDLSWInit(struct mSDLRenderer* renderer) {
#if !SDL_VERSION_ATLEAST(2, 0, 0)
#ifdef COLOR_16_BIT
SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);
@ -82,7 +82,8 @@ bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer) {
return true;
}
void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
void mSDLSWRunloopGBA(struct mSDLRenderer* renderer, void* user) {
struct GBAThread* context = user;
SDL_Event event;
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Surface* surface = SDL_GetVideoSurface();
@ -132,7 +133,7 @@ void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
}
}
void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer) {
void mSDLSWDeinit(struct mSDLRenderer* renderer) {
if (renderer->ratio > 1) {
free(renderer->d.outputBuffer);
}