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}