aboutsummaryrefslogtreecommitdiff
path: root/src/3ds
diff options
context:
space:
mode:
authorptitSeb2017-11-30 22:49:38 +0100
committerptitSeb2017-11-30 22:49:38 +0100
commitde29b11a88dbdd3af0824e59b51528b91ee73c54 (patch)
treee1aabf8752043998663279fae4359a18c4b4af07 /src/3ds
parentd87f450f51372ddf013e6bac09f1ef588e6f8bea (diff)
downloadhydracastlelabyrinth-de29b11a88dbdd3af0824e59b51528b91ee73c54.tar.gz
hydracastlelabyrinth-de29b11a88dbdd3af0824e59b51528b91ee73c54.tar.bz2
hydracastlelabyrinth-de29b11a88dbdd3af0824e59b51528b91ee73c54.zip
First commit. Version works on Linux (keyboard only, not configurable)
Diffstat (limited to 'src/3ds')
-rw-r--r--src/3ds/audio.c316
-rw-r--r--src/3ds/audio.h51
-rw-r--r--src/3ds/graphics.c435
-rw-r--r--src/3ds/graphics.h67
-rw-r--r--src/3ds/input.c56
-rw-r--r--src/3ds/input.h25
-rw-r--r--src/3ds/system.c48
-rw-r--r--src/3ds/system.h12
8 files changed, 1010 insertions, 0 deletions
diff --git a/src/3ds/audio.c b/src/3ds/audio.c
new file mode 100644
index 0000000..a63c88e
--- /dev/null
+++ b/src/3ds/audio.c
@@ -0,0 +1,316 @@
+#include "audio.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const int MODE_NDSP = 1,
+ MODE_CSND = 2;
+
+int audioMode = 0;
+
+PHL_Sound loadWav(char* fname);
+PHL_Music loadRaw(char* fname, u32 sampleRate, u32 bitsPerSample, u16 numChannels, u8 loop);
+
+void PHL_AudioInit()
+{
+ int loadMode = 0;
+
+ Result rdsp = ndspInit();
+ if (rdsp) {
+ //printf("\nNDSP Failed: %08lX\n", rdsp);
+ //loadMode = MODE_CSND;
+ loadMode = 0; //DSP or no sound for you! CSND a shit.
+ }else{
+ loadMode = MODE_NDSP;
+ }
+
+ if (loadMode == MODE_NDSP) {
+ //printf("\nNDSP Audio Mode");
+
+ ndspSetOutputMode(NDSP_OUTPUT_STEREO);
+ ndspSetOutputCount(1);
+
+ audioMode = MODE_NDSP;
+ }
+
+ else if (loadMode == MODE_CSND) {
+ //printf("\nCSND Audio Mode");
+
+ csndInit();
+ audioMode = MODE_CSND;
+ }
+}
+
+void PHL_AudioClose()
+{
+ if (audioMode == MODE_NDSP) {
+ ndspExit();
+ }
+
+ else if (audioMode == MODE_CSND) {
+ csndExit();
+ }
+}
+
+//Each system can use a custom music file format
+PHL_Music PHL_LoadMusic(char* fname, int loop)
+{
+ return loadRaw(fname, 32000, 16, 1, loop);
+}
+
+PHL_Music loadRaw(char* fname, u32 sampleRate, u32 bitsPerSample, u16 numChannels, u8 loop)
+{
+ PHL_Music result;
+
+ char fullPath[128];
+ strcpy(fullPath, "romfs:/");
+ strcat(fullPath, fname);
+ strcat(fullPath, ".raw");
+
+ FILE* file;
+ if ((file = fopen(fullPath, "rb")))
+ {
+ u32 size;
+
+ fseek(file, 0, SEEK_END);
+ size = ftell(file);
+
+ fseek(file, 0, SEEK_SET);
+
+ result.sampleRate = sampleRate;
+ result.dataSize = size;
+ result.bitsPerSample = bitsPerSample;
+ result.numChannels = numChannels;
+
+ if(bitsPerSample == 8) {
+ result.ndspFormat = (numChannels == 1) ?
+ NDSP_FORMAT_MONO_PCM8 :
+ NDSP_FORMAT_STEREO_PCM8;
+ }
+ else {
+ result.ndspFormat = (numChannels == 1) ?
+ NDSP_FORMAT_MONO_PCM16 :
+ NDSP_FORMAT_STEREO_PCM16;
+ }
+
+ result.loop = loop;
+
+ result.data = linearAlloc(size);
+ fread(result.data, 1, size, file);
+
+ fclose(file);
+ }
+
+ return result;
+
+}
+
+PHL_Sound PHL_LoadSound(char* fname)
+{
+ return loadWav(fname);
+}
+
+PHL_Sound loadWav(char* fname)
+{
+ PHL_Sound snd;
+
+ char fullPath[128];
+ strcpy(fullPath, "romfs:/");
+ strcat(fullPath, fname);
+
+ FILE* f;
+ if ( (f = fopen(fullPath, "rb")) )
+ {
+ //Check for valid fileName
+ u32 sig;
+ fread(&sig, 4, 1, f);
+
+ if (sig == 0x46464952) //RIFF
+ {
+ u32 chunkSize;
+ u32 format;
+
+ fread(&chunkSize, 4, 1, f);
+ fread(&format, 4, 1, f);
+
+ if (format == 0x45564157) //WAVE
+ {
+ u32 subchunk1ID;
+ fread(&subchunk1ID, 4, 1, f);
+
+ if (subchunk1ID == 0x20746D66) //fmt
+ {
+ u32 subchunk1Size;
+ u16 audioFormat;
+ u16 numChannels;
+ u32 sampleRate;
+ u32 byteRate;
+ u16 blockAlign;
+ u16 bitsPerSample;
+
+ fread(&subchunk1Size, 4, 1, f);
+ fread(&audioFormat, 2, 1, f);
+ fread(&numChannels, 2, 1, f);
+ fread(&sampleRate, 4, 1, f);
+ fread(&byteRate, 4, 1, f);
+ fread(&blockAlign, 2, 1, f);
+ fread(&bitsPerSample, 2, 1, f);
+
+ //Search for 'data'
+ for (int i = 0; i < 100; i++) {
+ u8 c;
+ fread(&c, 1, 1, f);
+ if (c == 0x64) { //'d'
+ fread(&c, 1, 1, f);
+ if (c == 0x61) { //'a'
+ fread(&c, 1, 1, f);
+ if (c == 0x74) { //'t'
+ fread(&c, 1, 1, f);
+ if (c == 0x61) { //'a'
+ i = 100;
+ }
+ }
+ }
+ }
+ }
+
+ u32 subchunk2Size;
+ fread(&subchunk2Size, 4, 1, f);
+
+ snd.numChannels = numChannels;
+
+ if(bitsPerSample == 8)
+ {
+ snd.ndspFormat = (numChannels == 1) ?
+ NDSP_FORMAT_MONO_PCM8 :
+ NDSP_FORMAT_STEREO_PCM8;
+ }
+ else
+ {
+ snd.ndspFormat = (numChannels == 1) ?
+ NDSP_FORMAT_MONO_PCM16 :
+ NDSP_FORMAT_STEREO_PCM16;
+ }
+
+ snd.sampleRate = sampleRate;
+ snd.dataSize = subchunk2Size;
+ snd.bitsPerSample = bitsPerSample;
+
+ snd.data = (u8*)(linearAlloc(subchunk2Size));
+ fread(snd.data, 1, subchunk2Size, f);
+ }
+ }
+ }
+
+ fclose(f);
+ }
+
+ return snd;
+}
+
+void PHL_PlayMusic(PHL_Music snd)
+{
+ if (snd.data != NULL) {
+ if (audioMode == MODE_NDSP)
+ {
+ ndspChnReset(0);
+ ndspChnSetInterp(0, NDSP_INTERP_NONE);
+ ndspChnSetRate(0, (float)snd.sampleRate);
+ ndspChnSetFormat(0, snd.ndspFormat);
+
+
+ memset(&waveBuf[0], 0, sizeof(ndspWaveBuf));
+ waveBuf[0].data_vaddr = (u32)(snd.data);
+ waveBuf[0].nsamples = snd.dataSize / (snd.bitsPerSample >> 3) / snd.numChannels;
+ waveBuf[0].looping = snd.loop;
+ waveBuf[0].status = NDSP_WBUF_FREE;
+
+ DSP_FlushDataCache(snd.data, snd.dataSize);
+ ndspChnWaveBufAdd(0, &waveBuf[0]);
+ }
+
+ else if (audioMode == MODE_CSND)
+ {
+ u32 flags = SOUND_FORMAT_16BIT;
+
+ if (snd.loop == 1) {
+ flags = SOUND_FORMAT_16BIT | SOUND_REPEAT;
+ }
+
+ int channel = (0 + 1) * 8;
+ csndPlaySound(channel, flags, snd.sampleRate, 1, 0, snd.data, snd.data, snd.dataSize);
+ }
+ }
+}
+
+void PHL_PlaySound(PHL_Sound snd, int channel)
+{
+ if (snd.data != NULL) {
+ if (audioMode == MODE_NDSP)
+ {
+ ndspChnReset(channel);
+ ndspChnSetInterp(channel, NDSP_INTERP_NONE);
+ ndspChnSetRate(channel, (float)snd.sampleRate);
+ ndspChnSetFormat(channel, snd.ndspFormat);
+
+
+ memset(&waveBuf[channel], 0, sizeof(ndspWaveBuf));
+ waveBuf[channel].data_vaddr = (u32)(snd.data);
+ waveBuf[channel].nsamples = snd.dataSize / (snd.bitsPerSample >> 3) / snd.numChannels;
+ waveBuf[channel].looping = false;
+ waveBuf[channel].status = NDSP_WBUF_FREE;
+
+ DSP_FlushDataCache(snd.data, snd.dataSize);
+ ndspChnWaveBufAdd(channel, &waveBuf[channel]);
+ }
+
+ else if (audioMode == MODE_CSND)
+ {
+ channel = (channel + 1) * 8;
+ csndPlaySound(channel, SOUND_FORMAT_16BIT, snd.sampleRate, 1, 0, snd.data, snd.data, snd.dataSize);
+ }
+ }
+}
+
+void PHL_StopMusic()
+{
+ if (audioMode == MODE_NDSP)
+ {
+ ndspChnWaveBufClear(0);
+ }
+
+ else if (audioMode == MODE_CSND)
+ {
+ CSND_SetPlayState(8, 0);
+ }
+}
+
+void PHL_StopSound(PHL_Sound snd, int channel)
+{
+ if (audioMode == MODE_NDSP)
+ {
+ ndspChnWaveBufClear(channel);
+ }
+
+ else if (audioMode == MODE_CSND)
+ {
+ channel = (channel + 1) * 8;
+ CSND_SetPlayState(channel, 0);
+ }
+}
+
+void PHL_FreeMusic(PHL_Music snd)
+{
+ if (snd.data != NULL) {
+ linearFree(snd.data);
+ snd.data = NULL;
+ }
+}
+
+void PHL_FreeSound(PHL_Sound snd)
+{
+ if (snd.data != NULL) {
+ linearFree(snd.data);
+ snd.data = NULL;
+ }
+} \ No newline at end of file
diff --git a/src/3ds/audio.h b/src/3ds/audio.h
new file mode 100644
index 0000000..28b615c
--- /dev/null
+++ b/src/3ds/audio.h
@@ -0,0 +1,51 @@
+#ifndef AUDIO_H
+#define AUDIO_H
+
+#include <3ds.h>
+
+typedef struct {
+ u16 sampleRate;
+ u32 dataSize;
+ u16 bitsPerSample;
+ u16 ndspFormat;
+ u16 numChannels;
+ u8 loop;
+ u8* data;
+ //int used;
+} PHL_Music;
+
+typedef struct{
+ u32 sampleRate;
+ u32 dataSize;
+ u16 bitsPerSample;
+ u16 ndspFormat;
+ u16 numChannels;
+ u8* data;
+} PHL_Sound;
+
+ndspWaveBuf waveBuf[6]; //One for each channel?
+
+void PHL_AudioInit();
+void PHL_AudioClose();
+
+PHL_Music PHL_LoadMusic(char* fname, int loop); //Same as PHL_LoadSound, but expects a file name without extension
+PHL_Sound PHL_LoadSound(char* fname);
+
+void PHL_PlayMusic(PHL_Music snd);
+void PHL_PlaySound(PHL_Sound snd, int channel);
+
+void PHL_StopMusic();
+void PHL_StopSound(PHL_Sound snd, int channel);
+
+/*
+PHL_Music PHL_LoadMusic(char* fname, int channel); //Same as PHL_LoadSound, but expects a file name without extension
+PHL_Sound PHL_LoadSound(char* fname, int loop, int stream, int channel);
+
+void PHL_PlayMusic(PHL_Music snd);
+void PHL_PlaySound(PHL_Sound snd);
+*/
+
+void PHL_FreeMusic(PHL_Music snd);
+void PHL_FreeSound(PHL_Sound snd);
+
+#endif \ No newline at end of file
diff --git a/src/3ds/graphics.c b/src/3ds/graphics.c
new file mode 100644
index 0000000..dd82955
--- /dev/null
+++ b/src/3ds/graphics.c
@@ -0,0 +1,435 @@
+//3DS graphics.c
+#include "graphics.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../game.h"
+#include "../qda.h"
+#include "../hero.h"
+
+Screen scrnTop = { GFX_TOP,
+ GFX_LEFT,
+ 400,
+ 240 };
+
+Screen scrnBottom = { GFX_BOTTOM,
+ GFX_LEFT,
+ 320,
+ 240 };
+
+PHL_Rect offset/*, crop*/;
+
+//One time graphics setup
+void PHL_GraphicsInit()
+{
+ gfxInitDefault();
+
+ activeScreen = &scrnTop;
+ /*
+ offset.w = 320;
+ offset.h = 240;
+ offset.x = (activeScreen->width - offset.w) / 2;
+ offset.y = (activeScreen->height - offset.h) / 2;
+
+ crop.w = 320;
+ crop.h = 320;
+ crop.x = 0;
+ crop.y = 0;
+
+ db.width = activeScreen->width;
+ db.height = activeScreen->height;
+ */
+ PHL_ResetDrawbuffer();
+
+ //Create background image
+ backBuffer = PHL_NewSurface(640, 480);
+
+ //consoleInit(GFX_BOTTOM, NULL);
+ //printf("Console Init");
+}
+
+void PHL_GraphicsExit()
+{
+ gfxExit();
+}
+
+void PHL_StartDrawing()
+{
+ PHL_ResetDrawbuffer();
+
+ gfxFlushBuffers();
+}
+
+void PHL_EndDrawing()
+{
+ gfxSwapBuffers();
+ gspWaitForVBlank();
+}
+
+void PHL_ForceScreenUpdate()
+{
+ //Draw black borders on sides of top screen
+ /*
+ PHL_DrawRect(-80, 0, 80, 480, PHL_NewRGB(0, 0, 0));
+ PHL_DrawRect(640, 0, 80, 480, PHL_NewRGB(0, 0, 0));
+
+ gspWaitForVBlank();
+ gfxSwapBuffers();
+
+ gfxFlushBuffers();
+ swapScreen(GFX_TOP, GFX_LEFT);
+ */
+
+ //PHL_DrawRect(0, 0, 640, 48, PHL_NewRGB(0, 0, 0));
+ //gfxSwapBuffers();
+}
+
+void PHL_SetDrawbuffer(PHL_Surface surf)
+{
+ db = surf;
+
+ offset.w = db.width;
+ offset.h = db.height;
+ offset.x = 0;
+ offset.y = 0;
+ /*
+ crop.w = db.width;
+ crop.h = db.height;
+ crop.x = 0;
+ crop.y = 0;
+ */
+}
+
+void PHL_ResetDrawbuffer()
+{
+ db.width = activeScreen->width;
+ db.height = activeScreen->height;
+ db.pxdata = gfxGetFramebuffer(activeScreen->screen, activeScreen->side, NULL, NULL);
+
+ offset.w = 320;
+ offset.h = 240;
+ offset.x = (activeScreen->width - offset.w) / 2;
+ offset.y = (activeScreen->height - offset.h) / 2;
+ /*
+ crop.w = 320;
+ crop.h = 240;
+ crop.x = 0;
+ crop.y = 0;*/
+}
+
+PHL_RGB PHL_NewRGB(u8 r, u8 g, u8 b)
+{
+ PHL_RGB c = { r, g, b };
+ return c;
+}
+
+void PHL_SetColorKey(PHL_Surface surf, u8 r, u8 g, u8 b)
+{
+ PHL_RGB key = { r, g, b };
+ surf.colorKey = key;
+}
+
+PHL_Surface PHL_NewSurface(u16 w, u16 h)
+{
+ PHL_Surface surf;
+
+ surf.width = w / 2;
+ surf.height = h / 2;
+ //printf("\nWidth: %d", surf.width);
+ surf.pxdata = malloc(surf.width * surf.height * 3 * sizeof(u8));
+ surf.colorKey = PHL_NewRGB(0xFF, 0x00, 0xFF);
+
+ return surf;
+}
+
+void PHL_FreeSurface(PHL_Surface surf)
+{
+ if (surf.pxdata != NULL) {
+ free(surf.pxdata);
+ surf.pxdata = NULL;
+ }
+}
+
+PHL_Surface PHL_LoadBMP(int index)
+{
+ PHL_Surface surf;
+
+ FILE* f;
+ if ( (f = fopen("romfs:/bmp.qda", "rb")) )
+ {
+ //Save bmp data
+ u8* bmpFile = malloc(headers[index].size * sizeof(u8));
+
+ fseek(f, headers[index].offset, SEEK_SET);
+ fread(bmpFile, headers[index].size, 1, f);
+ fclose(f);
+
+ //Create surface
+ u16 w, h;
+ memcpy(&w, &bmpFile[18], 2);
+ memcpy(&h, &bmpFile[22], 2);
+
+ surf = PHL_NewSurface(w * 2, h * 2);
+
+ //Load Palette
+ PHL_RGB palette[20][18];
+
+ int count = 0;
+ for (int dx = 0; dx < 20; dx++)
+ {
+ for (int dy = 0; dy < 16; dy++)
+ {
+ palette[dx][dy].b = bmpFile[54 + count];
+ palette[dx][dy].g = bmpFile[54 + count + 1];
+ palette[dx][dy].r = bmpFile[54 + count + 2];
+
+ count += 4;
+ }
+ }
+
+ //Fill pixels
+ count = 0;
+ for (int dx = w; dx > 0; dx--)
+ {
+ for (int dy = 0; dy < h; dy++)
+ {
+ int pix = w - dx + w * dy;
+ int px = bmpFile[1078 + pix] / 16;
+ int py = bmpFile[1078 + pix] % 16;
+
+ //Get transparency from first palette color
+ if (dx == w && dy == 0) {
+ //Darkness special case
+ if (index == 27) {
+ surf.colorKey = PHL_NewRGB(0x00, 0x00, 0x00);
+ }else{
+ surf.colorKey = palette[0][0];
+ }
+ }
+
+ PHL_RGB c = palette[px][py];
+ surf.pxdata[count] = c.b;
+ surf.pxdata[count+1] = c.g;
+ surf.pxdata[count+2] = c.r;
+
+ count += 3;
+ }
+ }
+
+ //Cleanup
+ free(bmpFile);
+ }
+
+ return surf;
+}
+
+void PHL_DrawRect(s16 x, s16 y, u16 w, u16 h, PHL_RGB col)
+{
+ //Quake Shake
+ if (quakeTimer > 0) {
+ int val = quakeTimer % 4;
+ if (val == 0) {
+ y -= 2;
+ }else if (val == 2) {
+ y += 2;
+ }
+ }
+
+ //Shrink values for small 3ds screen
+ x /= 2;
+ y /= 2;
+
+ x += offset.x;
+ y += offset.y;
+
+ w /= 2;
+ h /= 2;
+
+ s16 x2 = x + w;
+ s16 y2 = y + h;
+
+ //Keep drawing within screen
+ if (x < offset.x) { x = offset.x; }
+ if (y < offset.y) { y = offset.y; }
+ if (x2 > offset.x + offset.w) { x2 = offset.x + offset.w; }
+ if (y2 > offset.y + offset.h) { y2 = offset.y + offset.h; }
+
+ w = x2 - x;
+ h = y2 - y;
+
+ u32 p = ((db.height - h - y) + (x * db.height)) * 3;
+
+ for (int i = 0; i < w; i++)
+ {
+ for (int a = 0; a < h; a++)
+ {
+ db.pxdata[p] = col.b;
+ db.pxdata[p+1] = col.g;
+ db.pxdata[p+2] = col.r;
+
+ p += 3;
+ }
+ p += (db.height - h) * 3;
+ }
+}
+
+void PHL_DrawSurface(s16 x, s16 y, PHL_Surface surf)
+{
+ PHL_DrawSurfacePart(x, y, 0, 0, surf.width * 2, surf.height * 2, surf);
+}
+
+void PHL_DrawSurfacePart(s16 x, s16 y, s16 cropx, s16 cropy, s16 cropw, s16 croph, PHL_Surface surf)
+{
+ if (surf.pxdata != NULL)
+ {
+ //Quake Shake
+ if (quakeTimer > 0) {
+ int val = quakeTimer % 4;
+ if (val == 0) {
+ y -= 2;
+ }else if (val == 2) {
+ y += 2;
+ }
+ }
+
+ //Shrink values for small 3ds screen
+ x = (int)x / 2;
+ y = (int)y / 2;
+
+ cropx = cropx / 2;
+ cropy = cropy / 2;
+ cropw /= 2;
+ croph /= 2;
+
+ if (x > offset.w || y > offset.h || x + cropw < 0 || y + croph < 0) {
+ //image is outside of screen, so don't bother drawing
+ }
+ else{
+ //Crop pixels that are outside of screen
+ if (x < 0) {
+ cropx += -(x);
+ cropw -= -(x);
+ x = 0;
+ }
+ if (y < 0) {
+ cropy += -(y);
+ croph -= -(y);
+ y = 0;
+ }
+
+ //3DS exclusive optimization
+ if (roomDarkness == 1) {
+ //if (1) {
+ int cornerX = (herox / 2) - 80;
+ int cornerY = (heroy / 2) + 10 - 80;
+
+ if (x < cornerX) {
+ cropx += cornerX - x;
+ cropw -= cornerX - x;
+ x = cornerX;
+ }
+ if (y < cornerY) {
+ cropy += cornerY - y;
+ croph -= cornerY - y;
+ y = cornerY;
+ }
+ if (x + cropw > cornerX + 160) {
+ cropw -= (x + cropw) - (cornerX + 160);
+ }
+ if (y + croph > cornerY + 160) {
+ croph -= (y + croph) - (cornerY + 160);
+ }
+ }
+
+ if (x + cropw > offset.w) {
+ cropw -= (x + cropw) - (offset.w);
+ }
+ if (y + croph > offset.h) {
+ croph -= (y + croph) - (offset.h);
+ }
+
+ x += offset.x;
+ y += offset.y;
+
+ u32 p = ((offset.h - croph - y) + (x * offset.h)) * 3;
+ u32 c = ((surf.height - cropy - croph) + surf.height * cropx) * 3;
+
+ for (int i = 0; i < cropw; i++)
+ {
+ for (int a = 0; a < croph; a++)
+ {
+ if (surf.colorKey.r != surf.pxdata[c+2] ||
+ surf.colorKey.g != surf.pxdata[c+1] ||
+ surf.colorKey.b != surf.pxdata[c] )
+ {
+
+ db.pxdata[p] = surf.pxdata[c];
+ db.pxdata[p+1] = surf.pxdata[c+1];
+ db.pxdata[p+2] = surf.pxdata[c+2];
+ }
+
+ c += 3;
+ p += 3;
+ }
+
+ p += (offset.h - croph) * 3;
+ c += (surf.height - croph) * 3;
+ }
+ }
+ }
+}
+
+void PHL_DrawBackground(PHL_Background back, PHL_Background fore)
+{
+ PHL_DrawSurface(0, 0, backBuffer);
+}
+
+void PHL_UpdateBackground(PHL_Background back, PHL_Background fore)
+{
+ int tempDarkness = roomDarkness;
+ roomDarkness = 0;
+
+ PHL_SetDrawbuffer(backBuffer);
+
+ int xx, yy;
+
+ for (yy = 0; yy < 12; yy++)
+ {
+ for (xx = 0; xx < 16; xx++)
+ {
+ //Draw Background tiles
+ PHL_DrawSurfacePart(xx * 40, yy * 40, back.tileX[xx][yy] * 40, back.tileY[xx][yy] * 40, 40, 40, images[imgTiles]);
+
+ //Only draw foreground tile if not a blank tile
+ if (fore.tileX[xx][yy] != 0 || fore.tileY[xx][yy] != 0) {
+ PHL_DrawSurfacePart(xx * 40, yy * 40, fore.tileX[xx][yy] * 40, fore.tileY[xx][yy] * 40, 40, 40, images[imgTiles]);
+ }
+ }
+ }
+
+ PHL_ResetDrawbuffer();
+
+ roomDarkness = tempDarkness;
+}
+
+//3DS exclusive. Changes which screen to draw on
+void swapScreen(gfxScreen_t screen, gfx3dSide_t side)
+{
+ //Clear old screen
+ PHL_StartDrawing();
+ PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0));
+ PHL_EndDrawing();
+ PHL_StartDrawing();
+ PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0));
+ PHL_EndDrawing();
+
+ if (screen == GFX_TOP)
+ {
+ activeScreen = &scrnTop;
+ }
+ else{
+ activeScreen = &scrnBottom;
+ }
+
+ PHL_ResetDrawbuffer();
+} \ No newline at end of file
diff --git a/src/3ds/graphics.h b/src/3ds/graphics.h
new file mode 100644
index 0000000..badd898
--- /dev/null
+++ b/src/3ds/graphics.h
@@ -0,0 +1,67 @@
+//3DS graphics.h
+#ifndef GRAPHICS_H
+#define GRAPHICS_H
+
+#include <3ds.h>
+
+typedef struct {
+ u8 r;
+ u8 g;
+ u8 b;
+} PHL_RGB;
+
+typedef struct {
+ u8* pxdata;
+ u16 width;
+ u16 height;
+ PHL_RGB colorKey;
+} PHL_Surface;
+
+typedef struct {
+ gfxScreen_t screen;
+ gfx3dSide_t side;
+ u16 width;
+ u16 height;
+} Screen;
+
+typedef struct {
+ int tileX[16][12];
+ int tileY[16][12];
+} PHL_Background;
+
+PHL_Surface db;
+Screen* activeScreen;
+
+PHL_Surface backBuffer;
+
+void PHL_GraphicsInit();
+void PHL_GraphicsExit();
+
+void PHL_StartDrawing();
+void PHL_EndDrawing();
+
+void PHL_ForceScreenUpdate();
+
+void PHL_SetDrawbuffer(PHL_Surface surf);
+void PHL_ResetDrawbuffer();
+
+PHL_RGB PHL_NewRGB(u8 r, u8 g, u8 b);
+void PHL_SetColorKey(PHL_Surface surf, u8 r, u8 g, u8 b);
+
+PHL_Surface PHL_NewSurface(u16 w, u16 h);
+void PHL_FreeSurface(PHL_Surface surf);
+
+PHL_Surface PHL_LoadBMP_Debug(int index);
+PHL_Surface PHL_LoadBMP(int index);
+
+void PHL_DrawRect(s16 x, s16 y, u16 w, u16 h, PHL_RGB col);
+
+void PHL_DrawSurface(s16 x, s16 y, PHL_Surface surf);
+void PHL_DrawSurfacePart(s16 x, s16 y, s16 cropx, s16 cropy, s16 cropw, s16 croph, PHL_Surface surf);
+
+void PHL_DrawBackground(PHL_Background back, PHL_Background fore);
+void PHL_UpdateBackground(PHL_Background back, PHL_Background fore);
+
+void swapScreen(gfxScreen_t screen, gfx3dSide_t side);
+
+#endif \ No newline at end of file
diff --git a/src/3ds/input.c b/src/3ds/input.c
new file mode 100644
index 0000000..0d99b24
--- /dev/null
+++ b/src/3ds/input.c
@@ -0,0 +1,56 @@
+#include "input.h"
+
+void updateKey(Button* btn, int state);
+
+void PHL_ScanInput()
+{
+ hidScanInput();
+ u32 kDown = hidKeysHeld();
+
+ updateKey(&btnUp, kDown & KEY_UP);
+ updateKey(&btnDown, kDown & KEY_DOWN);
+ updateKey(&btnLeft, kDown & KEY_LEFT);
+ updateKey(&btnRight, kDown & KEY_RIGHT);
+
+ updateKey(&btnStart, kDown & KEY_START);
+ updateKey(&btnSelect, kDown & KEY_SELECT);
+
+ updateKey(&btnFaceRight, kDown & KEY_A);
+ updateKey(&btnFaceDown, kDown & KEY_B);
+ updateKey(&btnFaceLeft, kDown & KEY_Y);
+
+ updateKey(&btnL, kDown & KEY_L);
+ updateKey(&btnR, kDown & KEY_R);
+
+ updateKey(&btnAccept, kDown & KEY_A);
+ updateKey(&btnDecline, kDown & KEY_B);
+ /*
+ //Start button
+ if (kDown & KEY_START) {
+ btnStart.pressed = 1;
+ }else{
+ btnStart.pressed = 0;
+ }
+ */
+}
+
+void updateKey(Button* btn, int state)
+{
+ if (state) {
+ if (btn->held == 1) {
+ btn->pressed = 0;
+ }else{
+ btn->pressed = 1;
+ }
+ btn->held = 1;
+ btn->released = 0;
+ }else{
+ if (btn->held == 1) {
+ btn->released = 1;
+ }else{
+ btn->released = 0;
+ }
+ btn->held = 0;
+ btn->pressed = 0;
+ }
+} \ No newline at end of file
diff --git a/src/3ds/input.h b/src/3ds/input.h
new file mode 100644
index 0000000..7b7076e
--- /dev/null
+++ b/src/3ds/input.h
@@ -0,0 +1,25 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <3ds.h>
+
+typedef struct {
+ int pressed,
+ held,
+ released;
+} Button;
+
+Button btnUp, btnDown, btnLeft, btnRight;
+Button btnFaceUp, btnFaceDown, btnFaceLeft, btnFaceRight;
+
+Button btnL, btnR;
+Button btnStart, btnSelect;
+
+Button btnAccept;
+Button btnDecline;
+
+int axisX, axisY;
+
+void PHL_ScanInput();
+
+#endif \ No newline at end of file
diff --git a/src/3ds/system.c b/src/3ds/system.c
new file mode 100644
index 0000000..9b824cb
--- /dev/null
+++ b/src/3ds/system.c
@@ -0,0 +1,48 @@
+#include "system.h"
+#include <3ds.h>
+#include "../PHL.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+int quitGame = 0;
+
+int PHL_MainLoop()
+{
+ if (quitGame == 1) {
+ return 0;
+ }
+
+ return aptMainLoop();
+}
+
+void PHL_ConsoleInit()
+{
+ consoleInit(activeScreen->screen, NULL);
+}
+
+void PHL_GameQuit()
+{
+ quitGame = 1;
+}
+
+void PHL_ErrorScreen(char* message)
+{
+ consoleInit(GFX_TOP, NULL);
+
+ printf(message);
+ printf("\n\nPress START to close");
+
+ u32 kDown;
+ while (PHL_MainLoop()) {
+ //gfxFlushBuffers();
+ //gfxSwapBuffers();
+ hidScanInput();
+ kDown = hidKeysHeld();
+
+ if (kDown & KEY_START) { break; }
+
+ gspWaitForVBlank();
+ }
+
+ exit(1);
+} \ No newline at end of file
diff --git a/src/3ds/system.h b/src/3ds/system.h
new file mode 100644
index 0000000..c29d25f
--- /dev/null
+++ b/src/3ds/system.h
@@ -0,0 +1,12 @@
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+//int quitGame;
+
+int PHL_MainLoop();
+void PHL_ConsoleInit();
+void PHL_GameQuit();
+
+void PHL_ErrorScreen(char* message);
+
+#endif \ No newline at end of file