all repos — mgba @ eb0366b61e6ab07bd036f55b8444f84690faebd8

mGBA Game Boy Advance Emulator

src/platform/wii/main.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#define asm __asm__
  7
  8#include <fat.h>
  9#include <gccore.h>
 10#include <malloc.h>
 11
 12#include "util/common.h"
 13
 14#include "gba/gba.h"
 15#include "gba/renderers/video-software.h"
 16#include "gba/serialize.h"
 17#include "gba/supervisor/overrides.h"
 18#include "gba/video.h"
 19#include "util/vfs.h"
 20
 21#define SAMPLES 1024
 22
 23static void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args);
 24static void GBAWiiFrame(void);
 25static bool GBAWiiLoadGame(const char* path);
 26
 27static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
 28
 29static struct GBA gba;
 30static struct ARMCore cpu;
 31static struct GBAVideoSoftwareRenderer renderer;
 32static struct VFile* rom;
 33static struct VFile* save;
 34static struct GBAAVStream stream;
 35static FILE* logfile;
 36static GXRModeObj* mode;
 37static Mtx model, view, modelview;
 38static uint16_t* texmem;
 39static GXTexObj tex;
 40
 41static void* framebuffer[2];
 42static int whichFb = 0;
 43
 44int main() {
 45	VIDEO_Init();
 46	PAD_Init();
 47
 48#if !defined(COLOR_16_BIT) && !defined(COLOR_5_6_5)
 49#error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5
 50#endif
 51
 52	mode = VIDEO_GetPreferredMode(0);
 53	framebuffer[0] = SYS_AllocateFramebuffer(mode);
 54	framebuffer[1] = SYS_AllocateFramebuffer(mode);
 55
 56	VIDEO_Configure(mode);
 57	VIDEO_SetNextFramebuffer(framebuffer[whichFb]);
 58	VIDEO_SetBlack(FALSE);
 59	VIDEO_Flush();
 60	VIDEO_WaitVSync();
 61	if (mode->viTVMode & VI_NON_INTERLACE) {
 62		VIDEO_WaitVSync();
 63	}
 64
 65	GXColor bg = { 0, 0, 0, 0xFF };
 66	void* fifo = memalign(32, 0x40000);
 67	memset(fifo, 0, 0x40000);
 68	GX_Init(fifo, 0x40000);
 69	GX_SetCopyClear(bg, 0x00FFFFFF);
 70	GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1);
 71
 72	f32 yscale = GX_GetYScaleFactor(mode->efbHeight, mode->xfbHeight);
 73	u32 xfbHeight = GX_SetDispCopyYScale(yscale);
 74	GX_SetScissor(0, 0, mode->viWidth, mode->viWidth);
 75	GX_SetDispCopySrc(0, 0, mode->fbWidth, mode->efbHeight);
 76	GX_SetDispCopyDst(mode->fbWidth, xfbHeight);
 77	GX_SetCopyFilter(mode->aa, mode->sample_pattern, GX_TRUE, mode->vfilter);
 78	GX_SetFieldMode(mode->field_rendering, ((mode->viHeight == 2 * mode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
 79
 80	GX_SetCullMode(GX_CULL_NONE);
 81	GX_CopyDisp(framebuffer[whichFb], GX_TRUE);
 82	GX_SetDispCopyGamma(GX_GM_1_0);
 83
 84	GX_ClearVtxDesc();
 85	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
 86	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
 87
 88	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0);
 89	GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
 90
 91	GX_SetNumChans(1);
 92	GX_SetNumTexGens(1);
 93	GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
 94	GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
 95
 96	GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
 97	GX_InvVtxCache();
 98	GX_InvalidateTexAll();
 99
100	Mtx44 proj;
101	guOrtho(proj, 0, VIDEO_VERTICAL_PIXELS, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300);
102	GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC);
103
104	guVector cam = { 0.0f, 0.0f, 0.0f };
105	guVector up = { 0.0f, 1.0f, 0.0f };
106	guVector look = { 0.0f, 0.0f, -1.0f };
107	guLookAt(view, &cam, &up, &look);
108
109	guMtxIdentity(model);
110	guMtxTransApply(model, model, 0.0f, 0.0f, -6.0f);
111	guMtxConcat(view, model, modelview);
112	GX_LoadPosMtxImm(modelview, GX_PNMTX0);
113
114	texmem = memalign(32, 256 * 256 * BYTES_PER_PIXEL);
115	memset(texmem, 0, 256 * 256 * BYTES_PER_PIXEL);
116	GX_InitTexObj(&tex, texmem, 256, 256, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
117
118	fatInitDefault();
119
120	logfile = fopen("/mgba.log", "w");
121
122	stream.postAudioFrame = 0;
123	stream.postAudioBuffer = 0;
124	stream.postVideoFrame = _postVideoFrame;
125
126	GBACreate(&gba);
127	ARMSetComponents(&cpu, &gba.d, 0, 0);
128	ARMInit(&cpu);
129	gba.logLevel = 0; // TODO: Settings
130	gba.logHandler = GBAWiiLog;
131	gba.stream = &stream;
132	gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings
133	rom = 0;
134
135	GBAVideoSoftwareRendererCreate(&renderer);
136	renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL);
137	renderer.outputBufferStride = 256;
138	GBAVideoAssociateRenderer(&gba.video, &renderer.d);
139
140	GBAAudioResizeBuffer(&gba.audio, SAMPLES);
141
142#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF
143	blip_set_rates(gba.audio.left,  GBA_ARM7TDMI_FREQUENCY, 44100);
144	blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 44100);
145#endif
146
147	if (!GBAWiiLoadGame("/rom.gba")) {
148		return 1;
149	}
150
151	while (true) {
152		PAD_ScanPads();
153		u16 padkeys = PAD_ButtonsHeld(0);
154		int keys = 0;
155		gba.keySource = &keys;
156		if (padkeys & PAD_BUTTON_A) {
157			keys |= 1 << GBA_KEY_A;
158		}
159		if (padkeys & PAD_BUTTON_B) {
160			keys |= 1 << GBA_KEY_B;
161		}
162		if (padkeys & PAD_TRIGGER_L) {
163			keys |= 1 << GBA_KEY_L;
164		}
165		if (padkeys & PAD_TRIGGER_R) {
166			keys |= 1 << GBA_KEY_R;
167		}
168		if (padkeys & PAD_BUTTON_START) {
169			keys |= 1 << GBA_KEY_START;
170		}
171		if (padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) {
172			keys |= 1 << GBA_KEY_SELECT;
173		}
174		if (padkeys & PAD_BUTTON_LEFT) {
175			keys |= 1 << GBA_KEY_LEFT;
176		}
177		if (padkeys & PAD_BUTTON_RIGHT) {
178			keys |= 1 << GBA_KEY_RIGHT;
179		}
180		if (padkeys & PAD_BUTTON_UP) {
181			keys |= 1 << GBA_KEY_UP;
182		}
183		if (padkeys & PAD_BUTTON_DOWN) {
184			keys |= 1 << GBA_KEY_DOWN;
185		}
186		if (padkeys & PAD_TRIGGER_Z) {
187			break;
188		}
189		int frameCount = gba.video.frameCounter;
190		while (gba.video.frameCounter == frameCount) {
191			ARMRunLoop(&cpu);
192		}
193	}
194
195	fclose(logfile);
196	free(fifo);
197
198	rom->close(rom);
199	save->close(save);
200
201	return 0;
202}
203
204static void GBAWiiFrame(void) {
205	size_t x, y;
206	uint64_t* texdest = (uint64_t*) texmem;
207	uint64_t* texsrc = (uint64_t*) renderer.outputBuffer;
208	for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) {
209		for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) {
210			texdest[0 + x * 4 + y * 64] = texsrc[0   + x + y * 64];
211			texdest[1 + x * 4 + y * 64] = texsrc[64  + x + y * 64];
212			texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64];
213			texdest[3 + x * 4 + y * 64] = texsrc[192 + x + y * 64];
214		}
215	}
216	DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL);
217
218	GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
219	GX_SetColorUpdate(GX_TRUE);
220
221	GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1);
222	GX_InvalidateTexAll();
223	GX_LoadTexObj(&tex, GX_TEXMAP0);
224
225	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
226	GX_Position2s16(0, 256);
227	GX_TexCoord2s16(0, 1);
228
229	GX_Position2s16(256, 256);
230	GX_TexCoord2s16(1, 1);
231
232	GX_Position2s16(256, 0);
233	GX_TexCoord2s16(1, 0);
234
235	GX_Position2s16(0, 0);
236	GX_TexCoord2s16(0, 0);
237	GX_End();
238
239	GX_DrawDone();
240
241	whichFb = !whichFb;
242
243	GX_CopyDisp(framebuffer[whichFb], GX_TRUE);
244	VIDEO_SetNextFramebuffer(framebuffer[whichFb]);
245	VIDEO_Flush();
246	VIDEO_WaitVSync();
247}
248
249bool GBAWiiLoadGame(const char* path) {
250	rom = VFileOpen(path, O_RDONLY);
251
252	if (!rom) {
253		return false;
254	}
255	if (!GBAIsROM(rom)) {
256		return false;
257	}
258
259	save = VFileOpen("test.sav", O_RDWR | O_CREAT);
260
261	GBALoadROM(&gba, rom, save, path);
262
263	struct GBACartridgeOverride override;
264	const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom;
265	memcpy(override.id, &cart->id, sizeof(override.id));
266	if (GBAOverrideFind(0, &override)) {
267		GBAOverrideApply(&gba, &override);
268	}
269
270	ARMReset(&cpu);
271	return true;
272}
273
274void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) {
275	UNUSED(thread);
276	UNUSED(level);
277	vfprintf(logfile, format, args);
278	fprintf(logfile, "\n");
279	fflush(logfile);
280}
281
282static void _postVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) {
283	UNUSED(stream);
284	UNUSED(renderer);
285	GBAWiiFrame();
286}