mirror of https://github.com/mgba-emu/mgba.git
Switch: Add audio, key mapping, fast-forward, bugfixes
This commit is contained in:
parent
af03ad75be
commit
21626502bb
BIN
res/font-new.png
BIN
res/font-new.png
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -31,12 +31,13 @@ static const char* const _vertexShader =
|
|||
"uniform vec3 origin;\n"
|
||||
"uniform vec2 glyph;\n"
|
||||
"uniform vec2 dims;\n"
|
||||
"uniform mat2 transform;\n"
|
||||
"varying vec2 texCoord;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" vec2 scaledOffset = offset * dims;\n"
|
||||
" gl_Position = vec4((origin.x + scaledOffset.x) / 640.0 - 1.0, -(origin.y + scaledOffset.y) / 384.0 + 1.0, origin.z, 1.0);\n"
|
||||
" texCoord = (glyph + scaledOffset) / 512.0;\n"
|
||||
" texCoord = (glyph + offset * dims) / 512.0;\n"
|
||||
" vec2 scaledOffset = (transform * (offset * 2.0 - vec2(1.0)) + vec2(1.0)) / 2.0 * dims;\n"
|
||||
" gl_Position = vec4((origin.x + scaledOffset.x) / 640.0 - 1.0, -(origin.y + scaledOffset.y) / 360.0 + 1.0, origin.z, 1.0);\n"
|
||||
"}";
|
||||
|
||||
static const char* const _fragmentShader =
|
||||
|
@ -46,9 +47,10 @@ static const char* const _fragmentShader =
|
|||
"uniform float cutoff;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" vec4 texColor = color;\n"
|
||||
" texColor.a *= texture2D(tex, texCoord).a;\n"
|
||||
" texColor.a = clamp((texColor.a - cutoff) / (1.0 - cutoff), 0.0, 1.0);\n"
|
||||
" vec4 texColor = texture2D(tex, texCoord);\n"
|
||||
" texColor.a = clamp((texColor.a - cutoff) / (1.0 - cutoff), 0.0, 1.0);\n"
|
||||
" texColor.rgb = color.rgb;\n"
|
||||
" texColor.a *= color.a;\n"
|
||||
" gl_FragColor = texColor;\n"
|
||||
"}";
|
||||
|
||||
|
@ -59,6 +61,7 @@ struct GUIFont {
|
|||
GLuint offsetLocation;
|
||||
GLuint texLocation;
|
||||
GLuint dimsLocation;
|
||||
GLuint transformLocation;
|
||||
GLuint colorLocation;
|
||||
GLuint originLocation;
|
||||
GLuint glyphLocation;
|
||||
|
@ -159,6 +162,7 @@ struct GUIFont* GUIFontCreate(void) {
|
|||
font->texLocation = glGetUniformLocation(font->program, "tex");
|
||||
font->colorLocation = glGetUniformLocation(font->program, "color");
|
||||
font->dimsLocation = glGetUniformLocation(font->program, "dims");
|
||||
font->transformLocation = glGetUniformLocation(font->program, "transform");
|
||||
font->originLocation = glGetUniformLocation(font->program, "origin");
|
||||
font->glyphLocation = glGetUniformLocation(font->program, "glyph");
|
||||
font->cutoffLocation = glGetUniformLocation(font->program, "cutoff");
|
||||
|
@ -229,6 +233,7 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color,
|
|||
glUniform2f(font->glyphLocation, (glyph & 15) * CELL_WIDTH + metric.padding.left * 2, (glyph >> 4) * CELL_HEIGHT + metric.padding.top * 2);
|
||||
glUniform2f(font->dimsLocation, CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2, CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2);
|
||||
glUniform3f(font->originLocation, x, y - GLYPH_HEIGHT + metric.padding.top * 2, 0);
|
||||
glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {1.0, 0.0, 0.0, 1.0});
|
||||
|
||||
glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glEnableVertexAttribArray(font->offsetLocation);
|
||||
|
@ -251,6 +256,9 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment
|
|||
return;
|
||||
}
|
||||
struct GUIIconMetric metric = defaultIconMetrics[icon];
|
||||
|
||||
float hFlip = 1.0f;
|
||||
float vFlip = 1.0f;
|
||||
switch (align & GUI_ALIGN_HCENTER) {
|
||||
case GUI_ALIGN_HCENTER:
|
||||
x -= metric.width;
|
||||
|
@ -271,10 +279,10 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment
|
|||
glUseProgram(font->program);
|
||||
switch (orient) {
|
||||
case GUI_ORIENT_HMIRROR:
|
||||
// TODO
|
||||
hFlip = -1.0;
|
||||
break;
|
||||
case GUI_ORIENT_VMIRROR:
|
||||
// TODO
|
||||
vFlip = -1.0;
|
||||
break;
|
||||
case GUI_ORIENT_0:
|
||||
default:
|
||||
|
@ -294,6 +302,7 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment
|
|||
glUniform2f(font->glyphLocation, metric.x * 2, metric.y * 2 + 256);
|
||||
glUniform2f(font->dimsLocation, metric.width * 2, metric.height * 2);
|
||||
glUniform3f(font->originLocation, x, y, 0);
|
||||
glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {hFlip, 0.0, 0.0, vFlip});
|
||||
|
||||
glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glEnableVertexAttribArray(font->offsetLocation);
|
||||
|
@ -316,5 +325,40 @@ void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h,
|
|||
return;
|
||||
}
|
||||
struct GUIIconMetric metric = defaultIconMetrics[icon];
|
||||
//
|
||||
|
||||
if (!w) {
|
||||
w = metric.width * 2;
|
||||
}
|
||||
if (!h) {
|
||||
h = metric.height * 2;
|
||||
}
|
||||
|
||||
glUseProgram(font->program);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, font->font);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, font->vbo);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glUniform1i(font->texLocation, 0);
|
||||
glUniform2f(font->glyphLocation, metric.x * 2, metric.y * 2 + 256);
|
||||
glUniform2f(font->dimsLocation, metric.width * 2, metric.height * 2);
|
||||
glUniform3f(font->originLocation, x + w / 2 - metric.width, y + h / 2 - metric.height, 0);
|
||||
glUniformMatrix2fv(font->transformLocation, 1, GL_FALSE, (float[4]) {w * 0.5f / metric.width, 0.0, 0.0, h * 0.5f / metric.height});
|
||||
|
||||
glVertexAttribPointer(font->offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glEnableVertexAttribArray(font->offsetLocation);
|
||||
|
||||
glUniform1f(font->cutoffLocation, 0.1f);
|
||||
glUniform4f(font->colorLocation, 0.0, 0.0, 0.0, ((color >> 24) & 0xFF) / 128.0f);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glUniform1f(font->cutoffLocation, 0.7f);
|
||||
glUniform4f(font->colorLocation, ((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, (color & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(font->offsetLocation);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
* 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 "feature/gui/gui-runner.h"
|
||||
#include <mgba/core/blip_buf.h>
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/internal/gba/audio.h>
|
||||
#include <mgba/internal/gba/input.h>
|
||||
#include <mgba-util/gui.h>
|
||||
#include <mgba-util/gui/font.h>
|
||||
|
@ -14,6 +16,11 @@
|
|||
#include <GLES2/gl2.h>
|
||||
|
||||
#define AUTO_INPUT 0x4E585031
|
||||
#define SAMPLES 0x400
|
||||
#define BUFFER_SIZE 0x1000
|
||||
#define N_BUFFERS 3
|
||||
|
||||
TimeType __nx_time_type = TimeType_UserSystemClock;
|
||||
|
||||
static EGLDisplay s_display;
|
||||
static EGLContext s_context;
|
||||
|
@ -38,7 +45,7 @@ static const char* const _vertexShader =
|
|||
|
||||
"void main() {\n"
|
||||
" vec2 ratio = insize / 256.0;\n"
|
||||
" vec2 scaledOffset = offset * dims;\n"
|
||||
" vec2 scaledOffset = offset * dims;\n"
|
||||
" gl_Position = vec4(scaledOffset.x * 2.0 - dims.x, scaledOffset.y * -2.0 + dims.y, 0.0, 1.0);\n"
|
||||
" texCoord = offset * ratio;\n"
|
||||
"}";
|
||||
|
@ -64,6 +71,13 @@ static GLuint colorLocation;
|
|||
static GLuint tex;
|
||||
|
||||
static color_t frameBuffer[256 * 256];
|
||||
static struct mAVStream stream;
|
||||
static int audioBufferActive;
|
||||
static struct GBAStereoSample audioBuffer[N_BUFFERS][SAMPLES] __attribute__((__aligned__(0x1000)));
|
||||
static AudioOutBuffer audoutBuffer[N_BUFFERS];
|
||||
static int enqueuedBuffers;
|
||||
static bool frameLimiter = true;
|
||||
static int framecount = 0;
|
||||
|
||||
static bool initEgl() {
|
||||
s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
@ -91,6 +105,10 @@ static bool initEgl() {
|
|||
goto _fail1;
|
||||
}
|
||||
|
||||
//EGLint contextAttributeList[] = {
|
||||
// EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
// EGL_NONE
|
||||
//};
|
||||
s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, NULL);
|
||||
if (!s_context) {
|
||||
goto _fail2;
|
||||
|
@ -130,7 +148,9 @@ static void _drawStart(void) {
|
|||
}
|
||||
|
||||
static void _drawEnd(void) {
|
||||
eglSwapBuffers(s_display, s_surface);
|
||||
if (frameLimiter || (framecount & 2) == 0) {
|
||||
eglSwapBuffers(s_display, s_surface);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t _pollInput(const struct mInputMap* map) {
|
||||
|
@ -154,6 +174,15 @@ static void _setup(struct mGUIRunner* runner) {
|
|||
_mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_R, GBA_KEY_R);
|
||||
|
||||
runner->core->setVideoBuffer(runner->core, frameBuffer, 256);
|
||||
runner->core->setAVStream(runner->core, &stream);
|
||||
}
|
||||
|
||||
static void _gameLoaded(struct mGUIRunner* runner) {
|
||||
u32 samplerate = audoutGetSampleRate();
|
||||
|
||||
double ratio = GBAAudioCalculateRatio(1, 60.0, 1);
|
||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), samplerate * ratio);
|
||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), samplerate * ratio);
|
||||
}
|
||||
|
||||
static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded) {
|
||||
|
@ -202,6 +231,8 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) {
|
|||
unsigned width, height;
|
||||
runner->core->desiredVideoDimensions(runner->core, &width, &height);
|
||||
_drawTex(runner, width, height, faded);
|
||||
|
||||
++framecount;
|
||||
}
|
||||
|
||||
static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) {
|
||||
|
@ -222,18 +253,41 @@ static uint16_t _pollGameInput(struct mGUIRunner* runner) {
|
|||
|
||||
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
|
||||
UNUSED(runner);
|
||||
}
|
||||
frameLimiter = limit;
|
||||
}
|
||||
|
||||
static bool _running(struct mGUIRunner* runner) {
|
||||
UNUSED(runner);
|
||||
return appletMainLoop();
|
||||
}
|
||||
|
||||
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) {
|
||||
UNUSED(stream);
|
||||
static AudioOutBuffer* releasedBuffers;
|
||||
u32 audoutNReleasedBuffers;
|
||||
audoutGetReleasedAudioOutBuffer(&releasedBuffers, &audoutNReleasedBuffers);
|
||||
enqueuedBuffers -= audoutNReleasedBuffers;
|
||||
if (!frameLimiter && enqueuedBuffers == N_BUFFERS) {
|
||||
blip_clear(left);
|
||||
blip_clear(right);
|
||||
return;
|
||||
}
|
||||
|
||||
struct GBAStereoSample* samples = audioBuffer[audioBufferActive];
|
||||
blip_read_samples(left, &samples[0].left, SAMPLES, true);
|
||||
blip_read_samples(right, &samples[0].right, SAMPLES, true);
|
||||
audoutAppendAudioOutBuffer(&audoutBuffer[audioBufferActive]);
|
||||
audioBufferActive += 1;
|
||||
audioBufferActive %= N_BUFFERS;
|
||||
++enqueuedBuffers;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
initEgl();
|
||||
romfsInit();
|
||||
audoutInitialize();
|
||||
|
||||
struct GUIFont* font = GUIFontCreate();
|
||||
|
||||
|
@ -301,6 +355,23 @@ int main(int argc, char* argv[]) {
|
|||
glBufferData(GL_ARRAY_BUFFER, sizeof(_offsets), _offsets, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
stream.videoDimensionsChanged = NULL;
|
||||
stream.postVideoFrame = NULL;
|
||||
stream.postAudioFrame = NULL;
|
||||
stream.postAudioBuffer = _postAudioBuffer;
|
||||
|
||||
memset(audioBuffer, 0, sizeof(audioBuffer));
|
||||
audioBufferActive = 0;
|
||||
enqueuedBuffers = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < N_BUFFERS; ++i) {
|
||||
audoutBuffer[i].next = NULL;
|
||||
audoutBuffer[i].buffer = audioBuffer[i];
|
||||
audoutBuffer[i].buffer_size = BUFFER_SIZE;
|
||||
audoutBuffer[i].data_size = BUFFER_SIZE;
|
||||
audoutBuffer[i].data_offset = 0;
|
||||
}
|
||||
|
||||
struct mGUIRunner runner = {
|
||||
.params = {
|
||||
width, height,
|
||||
|
@ -310,16 +381,52 @@ int main(int argc, char* argv[]) {
|
|||
NULL,
|
||||
NULL, NULL,
|
||||
},
|
||||
.keySources = (struct GUIInputKeys[]) {
|
||||
{
|
||||
.name = "Controller Input",
|
||||
.id = AUTO_INPUT,
|
||||
.keyNames = (const char*[]) {
|
||||
"A",
|
||||
"B",
|
||||
"X",
|
||||
"Y",
|
||||
"L Stick",
|
||||
"R Stick",
|
||||
"L",
|
||||
"R",
|
||||
"ZL",
|
||||
"ZR",
|
||||
"+",
|
||||
"-",
|
||||
"Left",
|
||||
"Up",
|
||||
"Right",
|
||||
"Down",
|
||||
"L Left",
|
||||
"L Up",
|
||||
"L Right",
|
||||
"L Down",
|
||||
"R Left",
|
||||
"R Up",
|
||||
"R Right",
|
||||
"R Down",
|
||||
"SL",
|
||||
"SR"
|
||||
},
|
||||
.nKeys = 26
|
||||
},
|
||||
{ .id = 0 }
|
||||
},
|
||||
.nConfigExtra = 0,
|
||||
.setup = _setup,
|
||||
.teardown = NULL,
|
||||
.gameLoaded = NULL,
|
||||
.gameLoaded = _gameLoaded,
|
||||
.gameUnloaded = NULL,
|
||||
.prepareForFrame = NULL,
|
||||
.drawFrame = _drawFrame,
|
||||
.drawScreenshot = _drawScreenshot,
|
||||
.paused = NULL,
|
||||
.unpaused = NULL,
|
||||
.unpaused = _gameLoaded,
|
||||
.incrementScreenMode = NULL,
|
||||
.setFrameLimiter = _setFrameLimiter,
|
||||
.pollGameInput = _pollGameInput,
|
||||
|
@ -335,8 +442,10 @@ int main(int argc, char* argv[]) {
|
|||
_mapKey(&runner.params.keyMap, AUTO_INPUT, KEY_DLEFT, GUI_INPUT_LEFT);
|
||||
_mapKey(&runner.params.keyMap, AUTO_INPUT, KEY_DRIGHT, GUI_INPUT_RIGHT);
|
||||
|
||||
audoutStartAudioOut();
|
||||
mGUIRunloop(&runner);
|
||||
|
||||
audoutExit();
|
||||
deinitEgl();
|
||||
socketExit();
|
||||
return 0;
|
||||
|
|
|
@ -176,8 +176,8 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men
|
|||
GUIFontIconMetrics(params->font, GUI_ICON_SCROLLBAR_BUTTON, &right, 0);
|
||||
GUIFontIconMetrics(params->font, GUI_ICON_SCROLLBAR_TRACK, &w, 0);
|
||||
right = (right - w) / 2;
|
||||
GUIFontDrawIconSize(params->font, params->width - right - 8, top, 0, bottom - top, 0xA0FFFFFF, GUI_ICON_SCROLLBAR_TRACK);
|
||||
GUIFontDrawIcon(params->font, params->width - 8, top, GUI_ALIGN_HCENTER | GUI_ALIGN_BOTTOM, GUI_ORIENT_VMIRROR, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_BUTTON);
|
||||
GUIFontDrawIconSize(params->font, params->width - right - 8, top, 0, bottom - top, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_TRACK);
|
||||
GUIFontDrawIcon(params->font, params->width - 8, bottom, GUI_ALIGN_HCENTER | GUI_ALIGN_TOP, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_BUTTON);
|
||||
|
||||
y = menu->index * (bottom - top - 16) / GUIMenuItemListSize(&menu->items);
|
||||
|
|
Loading…
Reference in New Issue