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 int fmt;
49#ifdef COLOR_16_BIT
50#ifdef COLOR_5_6_5
51 fmt = GX_PF_RGB565_Z16;
52#else
53#error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5
54#endif
55#else
56#error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5
57#endif
58
59 mode = VIDEO_GetPreferredMode(0);
60 framebuffer[0] = SYS_AllocateFramebuffer(mode);
61 framebuffer[1] = SYS_AllocateFramebuffer(mode);
62
63 VIDEO_Configure(mode);
64 VIDEO_SetNextFramebuffer(framebuffer[whichFb]);
65 VIDEO_SetBlack(FALSE);
66 VIDEO_Flush();
67 VIDEO_WaitVSync();
68 if (mode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
69
70 GXColor bg = { 0, 0, 0, 0xFF };
71 void* fifo = memalign(32, 0x40000);
72 memset(fifo, 0, 0x40000);
73 GX_Init(fifo, 0x40000);
74 GX_SetPixelFmt(fmt, GX_ZC_LINEAR);
75 GX_SetCopyClear(bg, 0x00FFFFFF);
76 GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1);
77
78 GX_SetCullMode(GX_CULL_NONE);
79 GX_CopyDisp(framebuffer[whichFb], GX_TRUE);
80 GX_SetDispCopyGamma(GX_GM_1_0);
81
82 GX_ClearVtxDesc();
83 GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
84 GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
85
86 GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0);
87 GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
88
89 GX_SetNumChans(1);
90 GX_SetNumTexGens(1);
91 GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
92 GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
93
94 GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
95 GX_InvVtxCache();
96 GX_InvalidateTexAll();
97
98 Mtx44 proj;
99 guOrtho(proj, 0, VIDEO_VERTICAL_PIXELS, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300);
100 GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC);
101
102 guVector cam = { 0.0f, 0.0f, 0.0f };
103 guVector up = { 0.0f, 1.0f, 0.0f };
104 guVector look = { 0.0f, 0.0f, -1.0f };
105 guLookAt(view, &cam, &up, &look);
106 GX_LoadPosMtxImm(view, GX_PNMTX0);
107
108 guMtxIdentity(model);
109 guMtxTransApply(model, model, 0.0f, 0.0f, -6.0f);
110 guMtxConcat(view, model, modelview);
111 GX_LoadPosMtxImm(modelview, GX_PNMTX0);
112
113 texmem = memalign(32, 256 * 256 * BYTES_PER_PIXEL);
114 GX_InitTexObj(&tex, texmem, 256, 256, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
115
116 fatInitDefault();
117
118 logfile = fopen("/mgba.log", "w");
119
120 stream.postAudioFrame = 0;
121 stream.postAudioBuffer = 0;
122 stream.postVideoFrame = _postVideoFrame;
123
124 GBACreate(&gba);
125 ARMSetComponents(&cpu, &gba.d, 0, 0);
126 ARMInit(&cpu);
127 gba.logLevel = 0; // TODO: Settings
128 gba.logHandler = GBAWiiLog;
129 gba.stream = &stream;
130 gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings
131 rom = 0;
132
133 GBAVideoSoftwareRendererCreate(&renderer);
134 renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL);
135 renderer.outputBufferStride = 256;
136 GBAVideoAssociateRenderer(&gba.video, &renderer.d);
137
138 GBAAudioResizeBuffer(&gba.audio, SAMPLES);
139
140#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF
141 blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 44100);
142 blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 44100);
143#endif
144
145 if (!GBAWiiLoadGame("/rom.gba")) {
146 return 1;
147 }
148
149 while (true) {
150 PAD_ScanPads();
151 u16 padkeys = PAD_ButtonsDown(0);
152 int keys = 0;
153 gba.keySource = &keys;
154 if (padkeys & PAD_BUTTON_A) {
155 keys |= 1 << GBA_KEY_A;
156 }
157 if (padkeys & PAD_BUTTON_B) {
158 keys |= 1 << GBA_KEY_B;
159 }
160 if (padkeys & PAD_TRIGGER_L) {
161 keys |= 1 << GBA_KEY_L;
162 }
163 if (padkeys & PAD_TRIGGER_R) {
164 keys |= 1 << GBA_KEY_R;
165 }
166 if (padkeys & PAD_BUTTON_START) {
167 keys |= 1 << GBA_KEY_START;
168 }
169 if (padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) {
170 keys |= 1 << GBA_KEY_SELECT;
171 }
172 if (padkeys & PAD_BUTTON_LEFT) {
173 keys |= 1 << GBA_KEY_LEFT;
174 }
175 if (padkeys & PAD_BUTTON_RIGHT) {
176 keys |= 1 << GBA_KEY_RIGHT;
177 }
178 if (padkeys & PAD_BUTTON_UP) {
179 keys |= 1 << GBA_KEY_UP;
180 }
181 if (padkeys & PAD_BUTTON_DOWN) {
182 keys |= 1 << GBA_KEY_DOWN;
183 }
184 if (padkeys & PAD_TRIGGER_Z) {
185 break;
186 }
187 int frameCount = gba.video.frameCounter;
188 while (gba.video.frameCounter == frameCount) {
189 ARMRunLoop(&cpu);
190 }
191 }
192
193 fclose(logfile);
194 free(fifo);
195
196 rom->close(rom);
197 save->close(save);
198
199 return 0;
200}
201
202static void GBAWiiFrame(void) {
203 size_t x, y;
204 uint64_t* texdest = (uint64_t*) texmem;
205 uint64_t* texsrc = (uint64_t*) renderer.outputBuffer;
206 for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) {
207 for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) {
208 texdest[0 + x * 4 + y * 64] = texsrc[0 + x + y * 64];
209 texdest[1 + x * 4 + y * 64] = texsrc[64 + x + y * 64];
210 texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64];
211 texdest[3 + x * 4 + y * 64] = texsrc[192 + x + y * 64];
212 }
213 }
214 DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL);
215
216 GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1);
217 GX_InvalidateTexAll();
218 GX_LoadTexObj(&tex, GX_TEXMAP0);
219
220 GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
221 GX_Position2s16(0, 256);
222 GX_TexCoord2s16(0, 1);
223
224 GX_Position2s16(256, 256);
225 GX_TexCoord2s16(1, 1);
226
227 GX_Position2s16(256, 0);
228 GX_TexCoord2s16(1, 0);
229
230 GX_Position2s16(0, 0);
231 GX_TexCoord2s16(0, 0);
232 GX_End();
233
234 GX_DrawDone();
235
236 whichFb = !whichFb;
237
238 GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
239 GX_SetColorUpdate(GX_TRUE);
240 GX_CopyDisp(framebuffer[whichFb], GX_TRUE);
241 VIDEO_SetNextFramebuffer(framebuffer[whichFb]);
242 VIDEO_Flush();
243 VIDEO_WaitVSync();
244}
245
246bool GBAWiiLoadGame(const char* path) {
247 rom = VFileFOpen(path, "rb");
248
249 if (!rom) {
250 return false;
251 }
252 if (!GBAIsROM(rom)) {
253 return false;
254 }
255
256 save = VFileFOpen("test.sav", "w+b");
257
258 GBALoadROM(&gba, rom, save, path);
259
260 struct GBACartridgeOverride override;
261 const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom;
262 memcpy(override.id, &cart->id, sizeof(override.id));
263 if (GBAOverrideFind(0, &override)) {
264 GBAOverrideApply(&gba, &override);
265 }
266
267 ARMReset(&cpu);
268 return true;
269}
270
271void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) {
272 UNUSED(thread);
273 UNUSED(level);
274 vfprintf(logfile, format, args);
275 fprintf(logfile, "\n");
276 fflush(logfile);
277}
278
279static void _postVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) {
280 UNUSED(stream);
281 UNUSED(renderer);
282 GBAWiiFrame();
283}