mirror of https://github.com/mgba-emu/mgba.git
3DS: Implement adjustable filtering and sprite rotation
This commit is contained in:
parent
39230ca9ac
commit
526f86d085
1
CHANGES
1
CHANGES
|
@ -66,6 +66,7 @@ Misc:
|
|||
- Util: Add Vector GetConstPointer
|
||||
- Util: Add rtrim
|
||||
- GBA Memory: Optimize Load-/StoreMultiple
|
||||
- 3DS: Adjustable filering
|
||||
|
||||
0.4.1: (2016-07-11)
|
||||
Bugfixes:
|
||||
|
|
|
@ -30,12 +30,9 @@ set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE)
|
|||
|
||||
list(APPEND GUI_SRC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.c
|
||||
|
@ -43,12 +40,9 @@ list(APPEND GUI_SRC
|
|||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
PROPERTIES GENERATED ON)
|
||||
|
||||
add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c)
|
||||
|
@ -68,36 +62,21 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
|||
DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica ${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica
|
||||
COMMAND ${PICASSO}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin
|
||||
-h ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica
|
||||
COMMENT "picasso uishader.g.pica")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin
|
||||
COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "raw2c uishader.g.shbin")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica
|
||||
COMMAND ${PICASSO}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin
|
||||
-h ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
-h ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica
|
||||
COMMENT "picasso uishader.v.pica")
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica
|
||||
COMMENT "picasso uishader.shbin")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin
|
||||
COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "raw2c uishader.v.shbin")
|
||||
COMMENT "raw2c uishader.shbin")
|
||||
|
||||
add_custom_command(OUTPUT ${BINARY_NAME}.3dsx
|
||||
COMMAND ${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx --smdh=${BINARY_NAME}.smdh
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
#include "ctr-gpu.h"
|
||||
|
||||
#include "uishader_v.h"
|
||||
#include "uishader_v.shbin.h"
|
||||
#include "uishader_g.h"
|
||||
#include "uishader_g.shbin.h"
|
||||
#include "uishader.h"
|
||||
#include "uishader.shbin.h"
|
||||
|
||||
struct ctrUIVertex {
|
||||
short x, y;
|
||||
|
@ -25,6 +23,7 @@ struct ctrUIVertex {
|
|||
short u, v;
|
||||
short uw, vh;
|
||||
u32 abgr;
|
||||
float rotate[2];
|
||||
};
|
||||
|
||||
#define MAX_NUM_QUADS 256
|
||||
|
@ -36,34 +35,31 @@ static int ctrVertStart = 0;
|
|||
|
||||
static C3D_Tex* activeTexture = NULL;
|
||||
|
||||
static shaderProgram_s gpuShader;
|
||||
static DVLB_s* vertexShader = NULL;
|
||||
static DVLB_s* geometryShader = NULL;
|
||||
static shaderProgram_s uiProgram;
|
||||
static DVLB_s* uiShader = NULL;
|
||||
static int GSH_FVEC_projectionMtx;
|
||||
static int GSH_FVEC_textureMtx;
|
||||
|
||||
bool ctrInitGpu() {
|
||||
// Load vertex shader binary
|
||||
vertexShader = DVLB_ParseFile((u32*) uishader_v, uishader_v_size);
|
||||
if (vertexShader == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load geometry shader binary
|
||||
geometryShader = DVLB_ParseFile((u32*) uishader_g, uishader_g_size);
|
||||
if (geometryShader == NULL) {
|
||||
uiShader = DVLB_ParseFile((u32*) uishader, uishader_size);
|
||||
if (uiShader == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create shader
|
||||
shaderProgramInit(&gpuShader);
|
||||
Result res = shaderProgramSetVsh(&gpuShader, &vertexShader->DVLE[0]);
|
||||
shaderProgramInit(&uiProgram);
|
||||
Result res = shaderProgramSetVsh(&uiProgram, &uiShader->DVLE[0]);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
res = shaderProgramSetGsh(&gpuShader, &geometryShader->DVLE[0], 3);
|
||||
res = shaderProgramSetGsh(&uiProgram, &uiShader->DVLE[1], 4);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
C3D_BindProgram(&gpuShader);
|
||||
C3D_BindProgram(&uiProgram);
|
||||
GSH_FVEC_projectionMtx = shaderInstanceGetUniformLocation(uiProgram.geometryShader, "projectionMtx");
|
||||
GSH_FVEC_textureMtx = shaderInstanceGetUniformLocation(uiProgram.geometryShader, "textureMtx");
|
||||
|
||||
// Allocate buffers
|
||||
ctrVertexBuffer = linearAlloc(VERTEX_BUFFER_SIZE);
|
||||
|
@ -82,6 +78,7 @@ bool ctrInitGpu() {
|
|||
AttrInfo_AddLoader(attrInfo, 0, GPU_SHORT, 4); // in_pos
|
||||
AttrInfo_AddLoader(attrInfo, 1, GPU_SHORT, 4); // in_tc0
|
||||
AttrInfo_AddLoader(attrInfo, 2, GPU_UNSIGNED_BYTE, 4); // in_col
|
||||
AttrInfo_AddLoader(attrInfo, 3, GPU_FLOAT, 2); // in_rot
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -92,23 +89,22 @@ void ctrDeinitGpu() {
|
|||
ctrVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
shaderProgramFree(&gpuShader);
|
||||
shaderProgramFree(&uiProgram);
|
||||
|
||||
if (vertexShader) {
|
||||
DVLB_Free(vertexShader);
|
||||
vertexShader = NULL;
|
||||
}
|
||||
|
||||
if (geometryShader) {
|
||||
DVLB_Free(geometryShader);
|
||||
geometryShader = NULL;
|
||||
if (uiShader) {
|
||||
DVLB_Free(uiShader);
|
||||
uiShader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h) {
|
||||
void ctrSetViewportSize(s16 w, s16 h, bool tilt) {
|
||||
C3D_SetViewport(0, 0, h, w);
|
||||
C3D_Mtx projectionMtx;
|
||||
Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0);
|
||||
if (tilt) {
|
||||
Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0, true);
|
||||
} else {
|
||||
Mtx_Ortho(&projectionMtx, 0.0, w, 0.0, h, 0.0, 1.0, true);
|
||||
}
|
||||
C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx);
|
||||
}
|
||||
|
||||
|
@ -145,7 +141,7 @@ void ctrActivateTexture(C3D_Tex* texture) {
|
|||
C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx);
|
||||
}
|
||||
|
||||
void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh) {
|
||||
void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate) {
|
||||
if (x >= 400 && w >= 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -170,12 +166,14 @@ void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 u
|
|||
vtx->uw = uw;
|
||||
vtx->vh = vh;
|
||||
vtx->abgr = color;
|
||||
vtx->rotate[0] = cosf(rotate);
|
||||
vtx->rotate[1] = sinf(rotate);
|
||||
|
||||
++ctrNumVerts;
|
||||
}
|
||||
|
||||
void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) {
|
||||
ctrAddRectScaled(color, x, y, w, h, u, v, w, h);
|
||||
ctrAddRectEx(color, x, y, w, h, u, v, w, h, 0);
|
||||
}
|
||||
|
||||
void ctrFlushBatch(void) {
|
||||
|
@ -185,7 +183,7 @@ void ctrFlushBatch(void) {
|
|||
|
||||
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
|
||||
BufInfo_Init(bufInfo);
|
||||
BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 3, 0x210);
|
||||
BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 4, 0x3210);
|
||||
|
||||
GSPGPU_FlushDataCache(&ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex) * ctrNumVerts);
|
||||
C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumVerts);
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
bool ctrInitGpu(void);
|
||||
void ctrDeinitGpu(void);
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h);
|
||||
void ctrSetViewportSize(s16 w, s16 h, bool tilt);
|
||||
|
||||
void ctrActivateTexture(C3D_Tex* texture);
|
||||
void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh);
|
||||
void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate);
|
||||
void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h);
|
||||
void ctrFlushBatch(void);
|
||||
void ctrFinalize(void);
|
||||
|
|
|
@ -107,7 +107,9 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int glyph_x, int glyph_y, uint
|
|||
u16 u = tex->width * data.texcoord.left;
|
||||
u16 v = tex->height * data.texcoord.bottom;
|
||||
|
||||
ctrAddRectScaled(color, x, y, tex->width * width * FONT_SIZE, tex->height * height * -FONT_SIZE, u, v, tex->width * width, tex->height * height);
|
||||
ctrAddRectEx(color, x, y,
|
||||
tex->width * width * FONT_SIZE, tex->height * height * -FONT_SIZE,
|
||||
u, v, tex->width * width, tex->height * height, 0);
|
||||
}
|
||||
|
||||
void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) {
|
||||
|
@ -136,10 +138,16 @@ void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment
|
|||
}
|
||||
switch (orient) {
|
||||
case GUI_ORIENT_HMIRROR:
|
||||
ctrAddRectScaled(color, x + metric.width, y, -metric.width, metric.height, metric.x, metric.y, metric.width, metric.height);
|
||||
ctrAddRectEx(color, x + metric.width, y,
|
||||
-metric.width, metric.height,
|
||||
metric.x, metric.y,
|
||||
metric.width, metric.height, 0);
|
||||
break;
|
||||
case GUI_ORIENT_VMIRROR:
|
||||
ctrAddRectScaled(color, x, y + metric.height, metric.width, -metric.height, metric.x, metric.y, metric.width, metric.height);
|
||||
ctrAddRectEx(color, x, y + metric.height,
|
||||
metric.width, -metric.height,
|
||||
metric.x, metric.y,
|
||||
metric.width, metric.height, 0);
|
||||
break;
|
||||
case GUI_ORIENT_0:
|
||||
default:
|
||||
|
@ -157,5 +165,9 @@ void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h,
|
|||
}
|
||||
|
||||
struct GUIIconMetric metric = defaultIconMetrics[icon];
|
||||
ctrAddRectScaled(color, x, y, w ? w : metric.width, h ? h : metric.height, metric.x, metric.y, metric.width, metric.height);
|
||||
ctrAddRectEx(color, x, y,
|
||||
w ? w : metric.width,
|
||||
h ? h : metric.height,
|
||||
metric.x, metric.y,
|
||||
metric.width, metric.height, 0);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,13 @@ static enum ScreenMode {
|
|||
SM_MAX
|
||||
} screenMode = SM_PA_TOP;
|
||||
|
||||
static enum FilterMode {
|
||||
FM_NEAREST,
|
||||
FM_LINEAR_1x,
|
||||
FM_LINEAR_2x,
|
||||
FM_MAX
|
||||
} filterMode = FM_LINEAR_2x;
|
||||
|
||||
#define _3DS_INPUT 0x3344534B
|
||||
|
||||
#define AUDIO_SAMPLES 384
|
||||
|
@ -68,6 +75,7 @@ static bool frameLimiter = true;
|
|||
|
||||
static C3D_RenderBuf bottomScreen;
|
||||
static C3D_RenderBuf topScreen;
|
||||
static C3D_RenderBuf upscaleBuffer;
|
||||
|
||||
static aptHookCookie cookie;
|
||||
|
||||
|
@ -78,7 +86,7 @@ static bool _initGpu(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!C3D_RenderBufInit(&topScreen, 240, 400, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&bottomScreen, 240, 320, GPU_RB_RGB8, 0)) {
|
||||
if (!C3D_RenderBufInit(&topScreen, 240, 400, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&bottomScreen, 240, 320, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&upscaleBuffer, 512, 512, GPU_RB_RGB565, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -94,6 +102,7 @@ static void _cleanup(void) {
|
|||
|
||||
C3D_RenderBufDelete(&topScreen);
|
||||
C3D_RenderBufDelete(&bottomScreen);
|
||||
C3D_RenderBufDelete(&upscaleBuffer);
|
||||
C3D_Fini();
|
||||
|
||||
gfxExit();
|
||||
|
@ -210,7 +219,7 @@ static void _guiPrepare(void) {
|
|||
}
|
||||
|
||||
C3D_RenderBufBind(&bottomScreen);
|
||||
ctrSetViewportSize(320, 240);
|
||||
ctrSetViewportSize(320, 240, true);
|
||||
}
|
||||
|
||||
static void _guiFinish(void) {
|
||||
|
@ -248,6 +257,14 @@ static void _setup(struct mGUIRunner* runner) {
|
|||
if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) {
|
||||
screenMode = mode;
|
||||
}
|
||||
if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) {
|
||||
filterMode = mode;
|
||||
if (filterMode == FM_NEAREST) {
|
||||
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_NEAREST, GPU_NEAREST);
|
||||
} else {
|
||||
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR);
|
||||
}
|
||||
}
|
||||
frameLimiter = true;
|
||||
|
||||
runner->core->setAudioBufferSize(runner->core, AUDIO_SAMPLES);
|
||||
|
@ -292,9 +309,17 @@ static void _gameLoaded(struct mGUIRunner* runner) {
|
|||
memset(audioLeft, 0, AUDIO_SAMPLE_BUFFER * 2 * sizeof(int16_t));
|
||||
}
|
||||
unsigned mode;
|
||||
if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode != screenMode) {
|
||||
if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) {
|
||||
screenMode = mode;
|
||||
}
|
||||
if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) {
|
||||
filterMode = mode;
|
||||
if (filterMode == FM_NEAREST) {
|
||||
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_NEAREST, GPU_NEAREST);
|
||||
} else {
|
||||
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _gameUnloaded(struct mGUIRunner* runner) {
|
||||
|
@ -330,20 +355,27 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
|
|||
}
|
||||
|
||||
static void _drawTex(struct mCore* core, bool faded) {
|
||||
if (screenMode < SM_PA_TOP) {
|
||||
unsigned screen_w, screen_h;
|
||||
switch (screenMode) {
|
||||
case SM_PA_TOP:
|
||||
C3D_RenderBufBind(&bottomScreen);
|
||||
ctrSetViewportSize(320, 240);
|
||||
} else {
|
||||
screen_w = 320;
|
||||
screen_h = 240;
|
||||
break;
|
||||
case SM_PA_BOTTOM:
|
||||
C3D_RenderBufBind(&topScreen);
|
||||
ctrSetViewportSize(400, 240);
|
||||
screen_w = 400;
|
||||
screen_h = 240;
|
||||
break;
|
||||
default:
|
||||
C3D_RenderBufBind(&upscaleBuffer);
|
||||
screen_w = upscaleBuffer.colorBuf.width;
|
||||
screen_h = upscaleBuffer.colorBuf.height;
|
||||
break;
|
||||
}
|
||||
ctrActivateTexture(&outputTexture);
|
||||
|
||||
u32 color = faded ? 0x3FFFFFFF : 0xFFFFFFFF;
|
||||
|
||||
int screen_w = screenMode < SM_PA_TOP ? 320 : 400;
|
||||
int screen_h = 240;
|
||||
|
||||
unsigned corew, coreh;
|
||||
core->desiredVideoDimensions(core, &corew, &coreh);
|
||||
|
||||
|
@ -356,17 +388,57 @@ static void _drawTex(struct mCore* core, bool faded) {
|
|||
w = temp;
|
||||
}
|
||||
int gcd = h;
|
||||
int aspectw = corew / gcd;
|
||||
int aspecth = coreh / gcd;
|
||||
unsigned aspectw = corew / gcd;
|
||||
unsigned aspecth = coreh / gcd;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
switch (screenMode) {
|
||||
case SM_PA_TOP:
|
||||
case SM_PA_BOTTOM:
|
||||
default:
|
||||
w = corew;
|
||||
h = coreh;
|
||||
x = (screen_w - w) / 2;
|
||||
y = (screen_h - h) / 2;
|
||||
ctrSetViewportSize(screen_w, screen_h, true);
|
||||
ctrActivateTexture(&outputTexture);
|
||||
break;
|
||||
case SM_AF_TOP:
|
||||
case SM_AF_BOTTOM:
|
||||
case SM_SF_TOP:
|
||||
case SM_SF_BOTTOM:
|
||||
default:
|
||||
if (filterMode == FM_LINEAR_1x) {
|
||||
w = corew;
|
||||
h = coreh;
|
||||
} else {
|
||||
w = corew * 2;
|
||||
h = coreh * 2;
|
||||
}
|
||||
ctrSetViewportSize(screen_w, screen_h, false);
|
||||
ctrActivateTexture(&outputTexture);
|
||||
break;
|
||||
}
|
||||
|
||||
ctrAddRectEx(color, x, y, w, h, 0, 0, corew, coreh, 0);
|
||||
ctrFlushBatch();
|
||||
|
||||
corew = w;
|
||||
coreh = h;
|
||||
screen_h = 240;
|
||||
if (screenMode < SM_PA_TOP) {
|
||||
C3D_RenderBufBind(&bottomScreen);
|
||||
screen_w = 320;
|
||||
} else {
|
||||
C3D_RenderBufBind(&topScreen);
|
||||
screen_w = 400;
|
||||
}
|
||||
ctrSetViewportSize(screen_w, screen_h, true);
|
||||
|
||||
switch (screenMode) {
|
||||
default:
|
||||
return;
|
||||
case SM_AF_TOP:
|
||||
case SM_AF_BOTTOM:
|
||||
w = screen_w / aspectw;
|
||||
h = screen_h / aspecth;
|
||||
|
@ -385,10 +457,10 @@ static void _drawTex(struct mCore* core, bool faded) {
|
|||
break;
|
||||
}
|
||||
|
||||
int x = (screen_w - w) / 2;
|
||||
int y = (screen_h - h) / 2;
|
||||
|
||||
ctrAddRectScaled(color, x, y, w, h, 0, 0, corew, coreh);
|
||||
x = (screen_w - w) / 2;
|
||||
y = (screen_h - h) / 2;
|
||||
ctrActivateTexture(&upscaleBuffer.colorBuf);
|
||||
ctrAddRectEx(color, x, y, w, h, 0, 0, corew, coreh, 0);
|
||||
ctrFlushBatch();
|
||||
}
|
||||
|
||||
|
@ -604,7 +676,8 @@ int main() {
|
|||
return 1;
|
||||
}
|
||||
C3D_TexSetWrap(&outputTexture, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE);
|
||||
C3D_TexSetFilter(&outputTexture, GPU_LINEAR, GPU_LINEAR);
|
||||
C3D_TexSetFilter(&outputTexture, GPU_NEAREST, GPU_NEAREST);
|
||||
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR);
|
||||
void* outputTextureEnd = (u8*)outputTexture.data + 256 * 256 * 2;
|
||||
|
||||
// Zero texture data to make sure no garbage around the border interferes with filtering
|
||||
|
@ -686,9 +759,21 @@ int main() {
|
|||
"Stretched/Top",
|
||||
},
|
||||
.nStates = 6
|
||||
},
|
||||
{
|
||||
.title = "Filtering",
|
||||
.data = "filterMode",
|
||||
.submenu = 0,
|
||||
.state = FM_LINEAR_2x,
|
||||
.validStates = (const char*[]) {
|
||||
NULL, // Disable choosing nearest neighbor; it always looks bad
|
||||
"Bilinear (smooter)",
|
||||
"Bilinear (pixelated)",
|
||||
},
|
||||
.nStates = 3
|
||||
}
|
||||
},
|
||||
.nConfigExtra = 1,
|
||||
.nConfigExtra = 2,
|
||||
.setup = _setup,
|
||||
.teardown = 0,
|
||||
.gameLoaded = _gameLoaded,
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
; 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/.
|
||||
|
||||
; Inputs
|
||||
.alias in_pos v0 ; [x, y, w, h]
|
||||
.alias in_tc0 v1 ; [u, v, uw, vh]
|
||||
.alias in_col v2
|
||||
.alias in_rot v3
|
||||
|
||||
.gsh point c0
|
||||
|
||||
; Uniforms
|
||||
.fvec projectionMtx[4]
|
||||
.fvec textureMtx[2]
|
||||
|
@ -12,59 +20,77 @@
|
|||
; Constants
|
||||
.constf consts1(0.0, 1.0, -0.5, -1.0)
|
||||
|
||||
; Outputs : here only position and color
|
||||
; Outputs
|
||||
.out out_pos position
|
||||
.out out_tc0 texcoord0
|
||||
.out out_col color
|
||||
|
||||
; Inputs : here we have only vertices
|
||||
.alias in_pos v0
|
||||
.alias in_tc0 v1
|
||||
.alias in_col v2
|
||||
|
||||
.gsh
|
||||
.proc main
|
||||
.entry gshMain
|
||||
.proc gshMain
|
||||
; Set up the vertex endpoints
|
||||
mov r0.xy, in_pos.xy
|
||||
mov r0.zw, consts1.zy
|
||||
add r1.xy, r0.xy, in_pos.zw
|
||||
mov r0.xy, in_pos.zw
|
||||
mov r0.zw, consts1.xx
|
||||
mov r4.xy, in_pos.xy
|
||||
add r5, r4.xyzw, r0.xwww
|
||||
add r6, r4.xyzw, r0.xyww
|
||||
add r7, r4.xyzw, r0.wyww
|
||||
|
||||
dp4 r2.x, projectionMtx[0], r0
|
||||
dp4 r2.y, projectionMtx[1], r0
|
||||
dp4 r2.z, projectionMtx[2], r0
|
||||
dp4 r2.w, projectionMtx[3], r0
|
||||
; Create rotation matrix
|
||||
mov r8, in_rot.xzww
|
||||
mov r9, in_rot.yxww
|
||||
mov r10.zw, consts1.zy
|
||||
|
||||
dp4 r3.x, projectionMtx[0], r1
|
||||
dp4 r3.y, projectionMtx[1], r1
|
||||
dp4 r3.z, projectionMtx[2], r1
|
||||
dp4 r3.w, projectionMtx[3], r1
|
||||
; Transform coordinates
|
||||
dp4 r10.x, r8, r4
|
||||
dp4 r10.y, r9, r4
|
||||
dp4 r0.x, projectionMtx[0], r10
|
||||
dp4 r0.y, projectionMtx[1], r10
|
||||
dp4 r0.z, projectionMtx[2], r10
|
||||
dp4 r0.w, projectionMtx[3], r10
|
||||
|
||||
dp4 r10.x, r8, r5
|
||||
dp4 r10.y, r9, r5
|
||||
dp4 r1.x, projectionMtx[0], r10
|
||||
dp4 r1.y, projectionMtx[1], r10
|
||||
dp4 r1.z, projectionMtx[2], r10
|
||||
dp4 r1.w, projectionMtx[3], r10
|
||||
|
||||
dp4 r10.x, r8, r6
|
||||
dp4 r10.y, r9, r6
|
||||
dp4 r2.x, projectionMtx[0], r10
|
||||
dp4 r2.y, projectionMtx[1], r10
|
||||
dp4 r2.z, projectionMtx[2], r10
|
||||
dp4 r2.w, projectionMtx[3], r10
|
||||
|
||||
dp4 r10.x, r8, r7
|
||||
dp4 r10.y, r9, r7
|
||||
dp4 r3.x, projectionMtx[0], r10
|
||||
dp4 r3.y, projectionMtx[1], r10
|
||||
dp4 r3.z, projectionMtx[2], r10
|
||||
dp4 r3.w, projectionMtx[3], r10
|
||||
|
||||
; Set up the texture endpoints
|
||||
mov r0.xy, in_tc0.xy
|
||||
mov r0.zw, consts1.xy
|
||||
add r1.xy, r0.xy, in_tc0.zw
|
||||
mov r6.xy, in_tc0.xy
|
||||
add r7.xy, r6.xy, in_tc0.zw
|
||||
|
||||
dp4 r4.x, textureMtx[0], r0
|
||||
dp4 r4.y, textureMtx[1], r0
|
||||
dp4 r4.x, textureMtx[0], r6
|
||||
dp4 r4.y, textureMtx[1], r6
|
||||
mov r4.zw, consts1.xy
|
||||
|
||||
dp4 r5.x, textureMtx[0], r1
|
||||
dp4 r5.y, textureMtx[1], r1
|
||||
dp4 r5.x, textureMtx[0], r7
|
||||
dp4 r5.y, textureMtx[1], r7
|
||||
mov r5.zw, consts1.xy
|
||||
|
||||
; Emit top-left
|
||||
setemit 0
|
||||
mov out_pos.xyzw, r2.xyzw
|
||||
mov out_pos, r0
|
||||
mov out_tc0.xyzw, r4.xyzw
|
||||
mov out_col, in_col
|
||||
emit
|
||||
|
||||
; Emit bottom-left
|
||||
setemit 1
|
||||
mov out_pos.x, r2.x
|
||||
mov out_pos.y, r3.y
|
||||
mov out_pos.z, consts1.z
|
||||
mov out_pos.w, consts1.y
|
||||
mov out_pos, r1
|
||||
mov out_tc0.x, r5.x
|
||||
mov out_tc0.y, r4.y
|
||||
mov out_tc0.z, consts1.x
|
||||
|
@ -74,17 +100,14 @@
|
|||
|
||||
; Emit bottom-right
|
||||
setemit 2, prim
|
||||
mov out_pos.xyzw, r3.xyzw
|
||||
mov out_pos, r2
|
||||
mov out_tc0.xyzw, r5.xyzw
|
||||
mov out_col, in_col
|
||||
emit
|
||||
|
||||
; Emit top-right
|
||||
setemit 1, prim inv
|
||||
mov out_pos.x, r3.x
|
||||
mov out_pos.y, r2.y
|
||||
mov out_pos.z, consts1.z
|
||||
mov out_pos.w, consts1.y
|
||||
mov out_pos, r3
|
||||
mov out_tc0.x, r4.x
|
||||
mov out_tc0.y, r5.y
|
||||
mov out_tc0.z, consts1.x
|
||||
|
|
|
@ -18,15 +18,19 @@
|
|||
.out out_pos position
|
||||
.out out_tc0 texcoord0
|
||||
.out out_col color
|
||||
.out out_rot dummy
|
||||
|
||||
; Inputs
|
||||
.alias in_pos v0
|
||||
.alias in_tc0 v1
|
||||
.alias in_col v2
|
||||
.alias in_rot v3
|
||||
|
||||
.proc main
|
||||
.entry vshMain
|
||||
.proc vshMain
|
||||
mov out_pos, in_pos
|
||||
mov out_tc0, in_tc0
|
||||
mul out_rot, consts1.ywyx, in_rot.xyy
|
||||
|
||||
; Normalize color by multiplying by 1 / 255
|
||||
mul out_col, consts1.z, in_col
|
||||
|
|
Loading…
Reference in New Issue