mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'feature/citro3d'
This commit is contained in:
commit
690346fd4e
2
CHANGES
2
CHANGES
|
@ -24,6 +24,8 @@ Misc:
|
|||
- GBA Audio: Force audio DMAs to not increment destination
|
||||
- Qt: Thread startup improvements
|
||||
- 3DS: Allow UTF-16 filenames
|
||||
- 3DS: Port to using citro3D
|
||||
- 3DS: Use system font for menus
|
||||
|
||||
0.4.1: (2016-07-11)
|
||||
Bugfixes:
|
||||
|
|
|
@ -13,7 +13,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format" PARENT_SCOPE)
|
|||
set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
list(APPEND OS_LIB ctru)
|
||||
list(APPEND OS_LIB citro3d ctru)
|
||||
file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c ${CMAKE_CURRENT_SOURCE_DIR}/ctru-heap.c ${CMAKE_CURRENT_SOURCE_DIR}/socket.c)
|
||||
set(OS_SRC ${OS_SRC} PARENT_SCOPE)
|
||||
set(OS_LIB ${OS_LIB} PARENT_SCOPE)
|
||||
|
@ -30,10 +30,12 @@ set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE)
|
|||
|
||||
list(APPEND GUI_SRC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/font.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
${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_SOURCE_DIR}/gui-font.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.c
|
||||
|
@ -41,11 +43,14 @@ list(APPEND GUI_SRC
|
|||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/font.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
${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
|
||||
PROPERTIES GENERATED ON)
|
||||
|
||||
add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c)
|
||||
set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
|
||||
target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB})
|
||||
|
@ -58,29 +63,41 @@ add_custom_command(OUTPUT ${BINARY_NAME}.bnr
|
|||
COMMAND ${BANNERTOOL} makebanner -i ${CMAKE_CURRENT_SOURCE_DIR}/logo.png -a ${CMAKE_CURRENT_SOURCE_DIR}/bios.wav -o ${BINARY_NAME}.bnr
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/logo.png ${CMAKE_CURRENT_SOURCE_DIR}/bios.wav)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c
|
||||
COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c
|
||||
COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw
|
||||
DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.vsh
|
||||
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
|
||||
COMMAND ${PICASSO}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
-h ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/uishader.vsh
|
||||
COMMENT "picasso uishader.vsh")
|
||||
-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.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.h
|
||||
MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin
|
||||
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.shbin")
|
||||
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
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica
|
||||
COMMENT "picasso uishader.v.pica")
|
||||
|
||||
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
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "raw2c uishader.v.shbin")
|
||||
|
||||
add_custom_target(${BINARY_NAME}.3dsx ALL
|
||||
${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx --smdh=${BINARY_NAME}.smdh
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2015 Yuri Kunde Schlesner
|
||||
* Copyright (c) 2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -13,407 +14,182 @@
|
|||
|
||||
#include "ctr-gpu.h"
|
||||
|
||||
#include "uishader.h"
|
||||
#include "uishader.shbin.h"
|
||||
#include "uishader_v.h"
|
||||
#include "uishader_v.shbin.h"
|
||||
#include "uishader_g.h"
|
||||
#include "uishader_g.shbin.h"
|
||||
|
||||
struct ctrUIVertex {
|
||||
s16 x,y;
|
||||
s16 u,v;
|
||||
short x, y;
|
||||
short w, h;
|
||||
short u, v;
|
||||
short uw, vh;
|
||||
u32 abgr;
|
||||
};
|
||||
|
||||
#define VRAM_BASE 0x18000000u
|
||||
|
||||
#define MAX_NUM_QUADS 1024
|
||||
#define COMMAND_LIST_LENGTH (16 * 1024)
|
||||
// Each quad requires 4 vertices and 2*3 indices for the two triangles used to draw it
|
||||
#define VERTEX_INDEX_BUFFER_SIZE (MAX_NUM_QUADS * (4 * sizeof(struct ctrUIVertex) + 6 * sizeof(u16)))
|
||||
#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex)
|
||||
|
||||
static struct ctrUIVertex* ctrVertexBuffer = NULL;
|
||||
static u16* ctrIndexBuffer = NULL;
|
||||
static u16 ctrNumQuads = 0;
|
||||
static int ctrNumVerts = 0;
|
||||
static int ctrVertStart = 0;
|
||||
|
||||
static void* gpuColorBuffer[2] = { NULL, NULL };
|
||||
static u32* gpuCommandList = NULL;
|
||||
static void* screenTexture = NULL;
|
||||
static C3D_Tex* activeTexture = NULL;
|
||||
|
||||
static shaderProgram_s gpuShader;
|
||||
static DVLB_s* passthroughShader = NULL;
|
||||
|
||||
static int pendingEvents = 0;
|
||||
|
||||
static const struct ctrTexture* activeTexture = NULL;
|
||||
|
||||
void ctrClearPending(int events) {
|
||||
int toClear = events & pendingEvents;
|
||||
if (toClear & (1 << GSPGPU_EVENT_PSC0)) {
|
||||
gspWaitForPSC0();
|
||||
}
|
||||
if (toClear & (1 << GSPGPU_EVENT_PPF)) {
|
||||
gspWaitForPPF();
|
||||
}
|
||||
pendingEvents ^= toClear;
|
||||
}
|
||||
|
||||
// Replacements for the limiting GPU_SetViewport function in ctrulib
|
||||
static void _GPU_SetFramebuffer(intptr_t colorBuffer, intptr_t depthBuffer, u16 w, u16 h) {
|
||||
u32 buf[4];
|
||||
|
||||
// Unknown
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||
|
||||
// Set depth/color buffer address and dimensions
|
||||
buf[0] = depthBuffer >> 3;
|
||||
buf[1] = colorBuffer >> 3;
|
||||
buf[2] = (0x01) << 24 | ((h-1) & 0xFFF) << 12 | (w & 0xFFF) << 0;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, buf, 3);
|
||||
GPUCMD_AddWrite(GPUREG_RENDERBUF_DIM, buf[2]);
|
||||
|
||||
// Set depth/color buffer pixel format
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, 3 /* D248S */ );
|
||||
GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, 0 /* RGBA8 */ << 16 | 2 /* Unknown */);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_BLOCK32, 0); // Unknown
|
||||
|
||||
// Enable color/depth buffers
|
||||
buf[0] = colorBuffer != 0 ? 0xF : 0x0;
|
||||
buf[1] = buf[0];
|
||||
buf[2] = depthBuffer != 0 ? 0x2 : 0x0;
|
||||
buf[3] = buf[2];
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_COLORBUFFER_READ, buf, 4);
|
||||
}
|
||||
|
||||
static void _GPU_SetViewportEx(u16 x, u16 y, u16 w, u16 h) {
|
||||
u32 buf[4];
|
||||
|
||||
buf[0] = f32tof24(w / 2.0f);
|
||||
buf[1] = f32tof31(2.0f / w) << 1;
|
||||
buf[2] = f32tof24(h / 2.0f);
|
||||
buf[3] = f32tof31(2.0f / h) << 1;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VIEWPORT_WIDTH, buf, 4);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VIEWPORT_XY, (y & 0xFFFF) << 16 | (x & 0xFFFF) << 0);
|
||||
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = ((h-1) & 0xFFFF) << 16 | ((w-1) & 0xFFFF) << 0;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, buf, 3);
|
||||
}
|
||||
|
||||
static void _setDummyTexEnv(int id) {
|
||||
GPU_SetTexEnv(id,
|
||||
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
|
||||
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
|
||||
GPU_TEVOPERANDS(0, 0, 0),
|
||||
GPU_TEVOPERANDS(0, 0, 0),
|
||||
GPU_REPLACE,
|
||||
GPU_REPLACE,
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
Result ctrInitGpu() {
|
||||
Result res = -1;
|
||||
|
||||
// Allocate buffers
|
||||
gpuColorBuffer[0] = vramAlloc(400 * 240 * 4);
|
||||
gpuColorBuffer[1] = vramAlloc(320 * 240 * 4);
|
||||
gpuCommandList = linearAlloc(COMMAND_LIST_LENGTH * sizeof(u32));
|
||||
ctrVertexBuffer = linearAlloc(VERTEX_INDEX_BUFFER_SIZE);
|
||||
if (gpuColorBuffer[0] == NULL || gpuColorBuffer[1] == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) {
|
||||
res = -1;
|
||||
goto error_allocs;
|
||||
}
|
||||
// Both buffers share the same allocation, index buffer follows the vertex buffer
|
||||
ctrIndexBuffer = (u16*)(ctrVertexBuffer + (4 * MAX_NUM_QUADS));
|
||||
static DVLB_s* vertexShader = NULL;
|
||||
static DVLB_s* geometryShader = NULL;
|
||||
|
||||
bool ctrInitGpu() {
|
||||
// Load vertex shader binary
|
||||
passthroughShader = DVLB_ParseFile((u32*)uishader, uishader_size);
|
||||
if (passthroughShader == NULL) {
|
||||
res = -1;
|
||||
goto error_dvlb;
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create shader
|
||||
shaderProgramInit(&gpuShader);
|
||||
res = shaderProgramSetVsh(&gpuShader, &passthroughShader->DVLE[0]);
|
||||
Result res = shaderProgramSetVsh(&gpuShader, &vertexShader->DVLE[0]);
|
||||
if (res < 0) {
|
||||
goto error_shader;
|
||||
return false;
|
||||
}
|
||||
res = shaderProgramSetGsh(&gpuShader, &geometryShader->DVLE[0], 3);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
}
|
||||
C3D_BindProgram(&gpuShader);
|
||||
|
||||
// Allocate buffers
|
||||
ctrVertexBuffer = linearAlloc(VERTEX_BUFFER_SIZE);
|
||||
if (ctrVertexBuffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the GPU in ctrulib and assign the command buffer to accept submission of commands
|
||||
GPU_Init(NULL);
|
||||
GPUCMD_SetBuffer(gpuCommandList, COMMAND_LIST_LENGTH, 0);
|
||||
C3D_CullFace(GPU_CULL_NONE);
|
||||
C3D_DepthTest(false, GPU_ALWAYS, GPU_WRITE_ALL);
|
||||
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
||||
C3D_AlphaTest(false, GPU_ALWAYS, 0);
|
||||
C3D_BlendingColor(0);
|
||||
|
||||
return 0;
|
||||
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
|
||||
AttrInfo_Init(attrInfo);
|
||||
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
|
||||
|
||||
error_shader:
|
||||
shaderProgramFree(&gpuShader);
|
||||
|
||||
error_dvlb:
|
||||
if (passthroughShader != NULL) {
|
||||
DVLB_Free(passthroughShader);
|
||||
passthroughShader = NULL;
|
||||
}
|
||||
|
||||
error_allocs:
|
||||
if (ctrVertexBuffer != NULL) {
|
||||
linearFree(ctrVertexBuffer);
|
||||
ctrVertexBuffer = NULL;
|
||||
ctrIndexBuffer = NULL;
|
||||
}
|
||||
|
||||
if (gpuCommandList != NULL) {
|
||||
GPUCMD_SetBuffer(NULL, 0, 0);
|
||||
linearFree(gpuCommandList);
|
||||
gpuCommandList = NULL;
|
||||
}
|
||||
|
||||
if (gpuColorBuffer[0] != NULL) {
|
||||
vramFree(gpuColorBuffer[0]);
|
||||
gpuColorBuffer[0] = NULL;
|
||||
}
|
||||
|
||||
if (gpuColorBuffer[1] != NULL) {
|
||||
vramFree(gpuColorBuffer[1]);
|
||||
gpuColorBuffer[1] = NULL;
|
||||
}
|
||||
return res;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ctrDeinitGpu() {
|
||||
if (ctrVertexBuffer) {
|
||||
linearFree(ctrVertexBuffer);
|
||||
ctrVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
shaderProgramFree(&gpuShader);
|
||||
|
||||
DVLB_Free(passthroughShader);
|
||||
passthroughShader = NULL;
|
||||
|
||||
linearFree(screenTexture);
|
||||
screenTexture = NULL;
|
||||
|
||||
linearFree(ctrVertexBuffer);
|
||||
ctrVertexBuffer = NULL;
|
||||
ctrIndexBuffer = NULL;
|
||||
|
||||
GPUCMD_SetBuffer(NULL, 0, 0);
|
||||
linearFree(gpuCommandList);
|
||||
gpuCommandList = NULL;
|
||||
|
||||
vramFree(gpuColorBuffer[0]);
|
||||
gpuColorBuffer[0] = NULL;
|
||||
|
||||
vramFree(gpuColorBuffer[1]);
|
||||
gpuColorBuffer[1] = NULL;
|
||||
}
|
||||
|
||||
void ctrGpuBeginFrame(int screen) {
|
||||
if (screen > 1) {
|
||||
return;
|
||||
if (vertexShader) {
|
||||
DVLB_Free(vertexShader);
|
||||
vertexShader = NULL;
|
||||
}
|
||||
|
||||
int fw;
|
||||
if (screen == 0) {
|
||||
fw = 400;
|
||||
} else {
|
||||
fw = 320;
|
||||
if (geometryShader) {
|
||||
DVLB_Free(geometryShader);
|
||||
geometryShader = NULL;
|
||||
}
|
||||
|
||||
_GPU_SetFramebuffer(osConvertVirtToPhys(gpuColorBuffer[screen]), 0, 240, fw);
|
||||
}
|
||||
|
||||
void ctrGpuBeginDrawing(void) {
|
||||
shaderProgramUse(&gpuShader);
|
||||
|
||||
// Disable depth and stencil testing
|
||||
GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR);
|
||||
GPU_SetStencilTest(false, GPU_ALWAYS, 0, 0xFF, 0);
|
||||
GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
||||
GPU_DepthMap(-1.0f, 0.0f);
|
||||
|
||||
// Enable alpha blending
|
||||
GPU_SetAlphaBlending(
|
||||
GPU_BLEND_ADD, GPU_BLEND_ADD, // Operation RGB, Alpha
|
||||
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, // Color src, dst
|
||||
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); // Alpha src, dst
|
||||
GPU_SetBlendingColor(0, 0, 0, 0);
|
||||
|
||||
// Disable alpha testing
|
||||
GPU_SetAlphaTest(false, GPU_ALWAYS, 0);
|
||||
|
||||
// Unknown
|
||||
GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 0x1, 0);
|
||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0);
|
||||
|
||||
GPU_SetTexEnv(0,
|
||||
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), // RGB
|
||||
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), // Alpha
|
||||
GPU_TEVOPERANDS(0, 0, 0), // RGB
|
||||
GPU_TEVOPERANDS(0, 0, 0), // Alpha
|
||||
GPU_MODULATE, GPU_MODULATE, // Operation RGB, Alpha
|
||||
0x00000000); // Constant color
|
||||
_setDummyTexEnv(1);
|
||||
_setDummyTexEnv(2);
|
||||
_setDummyTexEnv(3);
|
||||
_setDummyTexEnv(4);
|
||||
_setDummyTexEnv(5);
|
||||
|
||||
// Configure vertex attribute format
|
||||
u32 bufferOffsets[] = { osConvertVirtToPhys(ctrVertexBuffer) - VRAM_BASE };
|
||||
u64 arrayTargetAttributes[] = { 0x210 };
|
||||
u8 numAttributesInArray[] = { 3 };
|
||||
GPU_SetAttributeBuffers(
|
||||
3, // Number of attributes
|
||||
(u32*)VRAM_BASE, // Base address
|
||||
GPU_ATTRIBFMT(0, 2, GPU_SHORT) | // Attribute format
|
||||
GPU_ATTRIBFMT(1, 2, GPU_SHORT) |
|
||||
GPU_ATTRIBFMT(2, 4, GPU_UNSIGNED_BYTE),
|
||||
0xFF8, // Non-fixed vertex inputs
|
||||
0x210, // Vertex shader input map
|
||||
1, // Use 1 vertex array
|
||||
bufferOffsets, arrayTargetAttributes, numAttributesInArray);
|
||||
}
|
||||
|
||||
void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h) {
|
||||
if (screen > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fw;
|
||||
if (screen == 0) {
|
||||
fw = 400;
|
||||
} else {
|
||||
fw = 320;
|
||||
}
|
||||
|
||||
ctrFlushBatch();
|
||||
|
||||
void* colorBuffer = (u8*)gpuColorBuffer[screen] + ((fw - w) * 240 * 4);
|
||||
|
||||
const u32 GX_CROP_INPUT_LINES = (1 << 2);
|
||||
|
||||
ctrClearPending(1 << GSPGPU_EVENT_PSC0);
|
||||
ctrClearPending(1 << GSPGPU_EVENT_PPF);
|
||||
|
||||
GX_DisplayTransfer(
|
||||
colorBuffer, GX_BUFFER_DIM(240, fw),
|
||||
outputFramebuffer, GX_BUFFER_DIM(h, w),
|
||||
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
|
||||
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) |
|
||||
GX_CROP_INPUT_LINES);
|
||||
pendingEvents |= (1 << GSPGPU_EVENT_PPF);
|
||||
}
|
||||
|
||||
void ctrGpuEndDrawing(void) {
|
||||
ctrClearPending(1 << GSPGPU_EVENT_PPF);
|
||||
gfxSwapBuffersGpu();
|
||||
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false);
|
||||
|
||||
void* gpuColorBuffer0End = (char*)gpuColorBuffer[0] + 240 * 400 * 4;
|
||||
void* gpuColorBuffer1End = (char*)gpuColorBuffer[1] + 240 * 320 * 4;
|
||||
GX_MemoryFill(
|
||||
gpuColorBuffer[0], 0x00000000, gpuColorBuffer0End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER,
|
||||
gpuColorBuffer[1], 0x00000000, gpuColorBuffer1End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER);
|
||||
pendingEvents |= 1 << GSPGPU_EVENT_PSC0;
|
||||
}
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h) {
|
||||
// Set up projection matrix mapping (0,0) to the top-left and (w,h) to the
|
||||
// bottom-right, taking into account the 3DS' screens' portrait
|
||||
// orientation.
|
||||
float projectionMtx[4 * 4] = {
|
||||
// Rows are in the order w z y x, because ctrulib
|
||||
1.0f, 0.0f, -2.0f / h, 0.0f,
|
||||
1.0f, 0.0f, 0.0f, -2.0f / w,
|
||||
-0.5f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
};
|
||||
|
||||
GPU_SetFloatUniform(GPU_VERTEX_SHADER, VSH_FVEC_projectionMtx, (u32*)&projectionMtx, 4);
|
||||
_GPU_SetViewportEx(0, 0, h, w);
|
||||
C3D_SetViewport(0, 0, h, w);
|
||||
C3D_Mtx projectionMtx;
|
||||
Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0);
|
||||
C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx);
|
||||
}
|
||||
|
||||
void ctrActivateTexture(const struct ctrTexture* texture) {
|
||||
if (activeTexture == texture) {
|
||||
void ctrActivateTexture(C3D_Tex* texture) {
|
||||
if (texture == activeTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrFlushBatch();
|
||||
|
||||
GPU_SetTextureEnable(GPU_TEXUNIT0);
|
||||
GPU_SetTexture(
|
||||
GPU_TEXUNIT0, (u32*)osConvertVirtToPhys(texture->data),
|
||||
texture->width, texture->height,
|
||||
GPU_TEXTURE_MAG_FILTER(texture->filter) | GPU_TEXTURE_MIN_FILTER(texture->filter) |
|
||||
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_BORDER) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_BORDER),
|
||||
texture->format);
|
||||
GPU_SetTextureBorderColor(GPU_TEXUNIT0, 0x00000000);
|
||||
|
||||
float textureMtx[2 * 4] = {
|
||||
// Rows are in the order w z y x, because ctrulib
|
||||
0.0f, 0.0f, 0.0f, 1.0f / texture->width,
|
||||
0.0f, 0.0f, 1.0f / texture->height, 0.0f,
|
||||
};
|
||||
|
||||
GPU_SetFloatUniform(GPU_VERTEX_SHADER, VSH_FVEC_textureMtx, (u32*)&textureMtx, 2);
|
||||
|
||||
activeTexture = texture;
|
||||
}
|
||||
|
||||
void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh) {
|
||||
if (ctrNumQuads == MAX_NUM_QUADS) {
|
||||
if (activeTexture) {
|
||||
ctrFlushBatch();
|
||||
}
|
||||
|
||||
u16 index = ctrNumQuads * 4;
|
||||
struct ctrUIVertex* vtx = &ctrVertexBuffer[index];
|
||||
vtx->x = x; vtx->y = y;
|
||||
vtx->u = u; vtx->v = v;
|
||||
vtx->abgr = color;
|
||||
vtx++;
|
||||
activeTexture = texture;
|
||||
C3D_TexBind(0, activeTexture);
|
||||
|
||||
vtx->x = x + w; vtx->y = y;
|
||||
vtx->u = u + uw; vtx->v = v;
|
||||
vtx->abgr = color;
|
||||
vtx++;
|
||||
C3D_TexEnv* env = C3D_GetTexEnv(0);
|
||||
C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
|
||||
if (texture->fmt < GPU_LA8) {
|
||||
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
|
||||
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
|
||||
} else {
|
||||
C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR, 0, 0);
|
||||
C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
|
||||
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
|
||||
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
|
||||
}
|
||||
|
||||
vtx->x = x; vtx->y = y + h;
|
||||
vtx->u = u; vtx->v = v + vh;
|
||||
vtx->abgr = color;
|
||||
vtx++;
|
||||
C3D_Mtx textureMtx = {
|
||||
.m = {
|
||||
// Rows are in the order w z y x, because ctrulib
|
||||
0.0f, 0.0f, 0.0f, 1.0f / activeTexture->width,
|
||||
0.0f, 0.0f, 1.0f / activeTexture->height, 0.0f
|
||||
}
|
||||
};
|
||||
C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx);
|
||||
}
|
||||
|
||||
vtx->x = x + w; vtx->y = y + h;
|
||||
vtx->u = u + uw; vtx->v = v + vh;
|
||||
void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh) {
|
||||
if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) {
|
||||
ctrFlushBatch();
|
||||
C3D_Flush();
|
||||
ctrNumVerts = 0;
|
||||
ctrVertStart = 0;
|
||||
}
|
||||
|
||||
struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts];
|
||||
vtx->x = x;
|
||||
vtx->y = y;
|
||||
vtx->w = w;
|
||||
vtx->h = h;
|
||||
vtx->u = u;
|
||||
vtx->v = v;
|
||||
vtx->uw = uw;
|
||||
vtx->vh = vh;
|
||||
vtx->abgr = color;
|
||||
|
||||
u16* i = &ctrIndexBuffer[ctrNumQuads * 6];
|
||||
i[0] = index + 0; i[1] = index + 1; i[2] = index + 2;
|
||||
i[3] = index + 2; i[4] = index + 1; i[5] = index + 3;
|
||||
|
||||
ctrNumQuads += 1;
|
||||
++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);
|
||||
ctrAddRectScaled(color, x, y, w, h, u, v, w, h);
|
||||
}
|
||||
|
||||
void ctrFlushBatch(void) {
|
||||
if (ctrNumQuads == 0) {
|
||||
if (ctrNumVerts == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrClearPending((1 << GSPGPU_EVENT_PSC0));
|
||||
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
|
||||
BufInfo_Init(bufInfo);
|
||||
BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 3, 0x210);
|
||||
|
||||
GSPGPU_FlushDataCache(ctrVertexBuffer, VERTEX_INDEX_BUFFER_SIZE);
|
||||
GPU_DrawElements(GPU_GEOMETRY_PRIM, (u32*)(osConvertVirtToPhys(ctrIndexBuffer) - VRAM_BASE), ctrNumQuads * 6);
|
||||
GSPGPU_FlushDataCache(&ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex) * ctrNumVerts);
|
||||
C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumVerts);
|
||||
|
||||
GPU_FinishDrawing();
|
||||
GPUCMD_Finalize();
|
||||
GSPGPU_FlushDataCache((u8*)gpuCommandList, COMMAND_LIST_LENGTH * sizeof(u32));
|
||||
GPUCMD_FlushAndRun();
|
||||
|
||||
gspWaitForP3D();
|
||||
|
||||
GPUCMD_SetBufferOffset(0);
|
||||
|
||||
ctrNumQuads = 0;
|
||||
ctrVertStart += ctrNumVerts;
|
||||
ctrNumVerts = 0;
|
||||
}
|
||||
|
||||
void ctrFinalize(void) {
|
||||
ctrFlushBatch();
|
||||
C3D_Flush();
|
||||
ctrNumVerts = 0;
|
||||
ctrVertStart = 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2015 Yuri Kunde Schlesner
|
||||
* Copyright (c) 2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -8,36 +9,17 @@
|
|||
#define GUI_GPU_H
|
||||
|
||||
#include <3ds.h>
|
||||
#include <citro3d.h>
|
||||
|
||||
struct ctrTexture {
|
||||
void* data;
|
||||
u32 format;
|
||||
u32 filter;
|
||||
u16 width;
|
||||
u16 height;
|
||||
};
|
||||
|
||||
static inline void ctrTexture_Init(struct ctrTexture* tex) {
|
||||
tex->data = NULL;
|
||||
tex->format = GPU_RGB565;
|
||||
tex->filter = GPU_NEAREST;
|
||||
tex->width = 0;
|
||||
tex->height = 0;
|
||||
}
|
||||
|
||||
Result ctrInitGpu(void);
|
||||
bool ctrInitGpu(void);
|
||||
void ctrDeinitGpu(void);
|
||||
|
||||
void ctrGpuBeginDrawing(void);
|
||||
void ctrGpuBeginFrame(int screen);
|
||||
void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h);
|
||||
void ctrGpuEndDrawing(void);
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h);
|
||||
|
||||
void ctrActivateTexture(const struct ctrTexture* texture);
|
||||
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 ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h);
|
||||
void ctrFlushBatch(void);
|
||||
void ctrFinalize(void);
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
|
@ -7,42 +7,43 @@
|
|||
#include "util/gui/font-metrics.h"
|
||||
#include "util/png-io.h"
|
||||
#include "util/vfs.h"
|
||||
#include "platform/3ds/ctr-gpu.h"
|
||||
#include "icons.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "ctr-gpu.h"
|
||||
|
||||
#define CELL_HEIGHT 16
|
||||
#define CELL_WIDTH 16
|
||||
#define GLYPH_HEIGHT 12
|
||||
#define FONT_SIZE 0.52f
|
||||
|
||||
struct GUIFont {
|
||||
struct ctrTexture texture;
|
||||
struct ctrTexture icons;
|
||||
C3D_Tex* sheets;
|
||||
C3D_Tex icons;
|
||||
};
|
||||
|
||||
struct GUIFont* GUIFontCreate(void) {
|
||||
fontEnsureMapped();
|
||||
struct GUIFont* guiFont = malloc(sizeof(struct GUIFont));
|
||||
if (!guiFont) {
|
||||
return 0;
|
||||
}
|
||||
C3D_Tex* tex;
|
||||
|
||||
struct ctrTexture* tex = &guiFont->texture;
|
||||
ctrTexture_Init(tex);
|
||||
tex->data = vramAlloc(256 * 128 * 2);
|
||||
tex->format = GPU_RGBA5551;
|
||||
tex->width = 256;
|
||||
tex->height = 128;
|
||||
TGLP_s* glyphInfo = fontGetGlyphInfo();
|
||||
guiFont->sheets = malloc(sizeof(*guiFont->sheets) * glyphInfo->nSheets);
|
||||
|
||||
GSPGPU_FlushDataCache(font, font_size);
|
||||
GX_RequestDma((u32*) font, tex->data, font_size);
|
||||
gspWaitForDMA();
|
||||
int i;
|
||||
for (i = 0; i < glyphInfo->nSheets; ++i) {
|
||||
tex = &guiFont->sheets[i];
|
||||
tex->data = fontGetGlyphSheetTex(i);
|
||||
tex->fmt = glyphInfo->sheetFmt;
|
||||
tex->size = glyphInfo->sheetSize;
|
||||
tex->width = glyphInfo->sheetWidth;
|
||||
tex->height = glyphInfo->sheetHeight;
|
||||
tex->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
tex = &guiFont->icons;
|
||||
ctrTexture_Init(tex);
|
||||
tex->data = vramAlloc(256 * 64 * 2);
|
||||
tex->format = GPU_RGBA5551;
|
||||
tex->width = 256;
|
||||
tex->height = 64;
|
||||
C3D_TexInitVRAM(tex, 256, 64, GPU_RGBA5551);
|
||||
|
||||
GSPGPU_FlushDataCache(icons, icons_size);
|
||||
GX_RequestDma((u32*) icons, tex->data, icons_size);
|
||||
|
@ -52,22 +53,24 @@ struct GUIFont* GUIFontCreate(void) {
|
|||
}
|
||||
|
||||
void GUIFontDestroy(struct GUIFont* font) {
|
||||
vramFree(font->texture.data);
|
||||
vramFree(font->icons.data);
|
||||
free(font->sheets);
|
||||
C3D_TexDelete(&font->icons);
|
||||
free(font);
|
||||
}
|
||||
|
||||
unsigned GUIFontHeight(const struct GUIFont* font) {
|
||||
UNUSED(font);
|
||||
return GLYPH_HEIGHT;
|
||||
return fontGetInfo()->lineFeed * FONT_SIZE;
|
||||
}
|
||||
|
||||
unsigned GUIFontGlyphWidth(const struct GUIFont* font, uint32_t glyph) {
|
||||
UNUSED(font);
|
||||
if (glyph > 0x7F) {
|
||||
glyph = 0;
|
||||
int index = fontGlyphIndexFromCodePoint(glyph);
|
||||
charWidthInfo_s* info = fontGetCharWidthInfo(index);
|
||||
if (info) {
|
||||
return info->charWidth * FONT_SIZE;
|
||||
}
|
||||
return defaultFontMetrics[glyph].width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned* w, unsigned* h) {
|
||||
|
@ -90,19 +93,21 @@ void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned*
|
|||
}
|
||||
|
||||
void GUIFontDrawGlyph(const struct GUIFont* font, int glyph_x, int glyph_y, uint32_t color, uint32_t glyph) {
|
||||
ctrActivateTexture(&font->texture);
|
||||
int index = fontGlyphIndexFromCodePoint(glyph);
|
||||
fontGlyphPos_s data;
|
||||
fontCalcGlyphPos(&data, index, GLYPH_POS_CALC_VTXCOORD, 1.0, 1.0);
|
||||
|
||||
if (glyph > 0x7F) {
|
||||
glyph = '?';
|
||||
}
|
||||
C3D_Tex* tex = &font->sheets[data.sheetIndex];
|
||||
ctrActivateTexture(tex);
|
||||
|
||||
struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph];
|
||||
u16 x = glyph_x - metric.padding.left;
|
||||
u16 y = glyph_y - GLYPH_HEIGHT;
|
||||
u16 u = (glyph % 16u) * CELL_WIDTH;
|
||||
u16 v = (glyph / 16u) * CELL_HEIGHT;
|
||||
float width = data.texcoord.right - data.texcoord.left;
|
||||
float height = data.texcoord.top - data.texcoord.bottom;
|
||||
u16 x = glyph_x;
|
||||
u16 y = glyph_y + tex->height * height / 8;
|
||||
u16 u = tex->width * data.texcoord.left;
|
||||
u16 v = tex->height * data.texcoord.bottom;
|
||||
|
||||
ctrAddRect(color, x, y, u, v, CELL_WIDTH, CELL_HEIGHT);
|
||||
ctrAddRectScaled(color, x, y, tex->width * width * FONT_SIZE, tex->height * height * -FONT_SIZE, u, v, tex->width * width, tex->height * height);
|
||||
}
|
||||
|
||||
void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) {
|
||||
|
|
|
@ -61,39 +61,39 @@ static struct mAVStream stream;
|
|||
static int16_t* audioLeft = 0;
|
||||
static int16_t* audioRight = 0;
|
||||
static size_t audioPos = 0;
|
||||
static struct ctrTexture gbaOutputTexture;
|
||||
static int guiDrawn;
|
||||
static int screenCleanup;
|
||||
static C3D_Tex outputTexture;
|
||||
static ndspWaveBuf dspBuffer[DSP_BUFFERS];
|
||||
static int bufferId = 0;
|
||||
|
||||
static C3D_RenderBuf bottomScreen;
|
||||
static C3D_RenderBuf topScreen;
|
||||
|
||||
static aptHookCookie cookie;
|
||||
|
||||
enum {
|
||||
GUI_ACTIVE = 1,
|
||||
GUI_THIS_FRAME = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
SCREEN_CLEANUP_TOP_1 = 1,
|
||||
SCREEN_CLEANUP_TOP_2 = 2,
|
||||
SCREEN_CLEANUP_TOP = SCREEN_CLEANUP_TOP_1 | SCREEN_CLEANUP_TOP_2,
|
||||
SCREEN_CLEANUP_BOTTOM_1 = 4,
|
||||
SCREEN_CLEANUP_BOTTOM_2 = 8,
|
||||
SCREEN_CLEANUP_BOTTOM = SCREEN_CLEANUP_BOTTOM_1 | SCREEN_CLEANUP_BOTTOM_2,
|
||||
};
|
||||
|
||||
extern bool allocateRomBuffer(void);
|
||||
|
||||
static bool _initGpu(void) {
|
||||
if (!C3D_Init(C3D_DEFAULT_CMDBUF_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!C3D_RenderBufInit(&topScreen, 240, 400, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&bottomScreen, 240, 320, GPU_RB_RGB8, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ctrInitGpu();
|
||||
}
|
||||
|
||||
static void _cleanup(void) {
|
||||
ctrDeinitGpu();
|
||||
|
||||
if (outputBuffer) {
|
||||
linearFree(outputBuffer);
|
||||
}
|
||||
|
||||
if (gbaOutputTexture.data) {
|
||||
ctrDeinitGpu();
|
||||
vramFree(gbaOutputTexture.data);
|
||||
}
|
||||
C3D_RenderBufDelete(&topScreen);
|
||||
C3D_RenderBufDelete(&bottomScreen);
|
||||
C3D_Fini();
|
||||
|
||||
gfxExit();
|
||||
|
||||
|
@ -173,52 +173,16 @@ static void _csndPlaySound(u32 flags, u32 sampleRate, float vol, void* left, voi
|
|||
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right);
|
||||
|
||||
static void _drawStart(void) {
|
||||
ctrGpuBeginDrawing();
|
||||
if (screenMode < SM_PA_TOP || (guiDrawn & GUI_ACTIVE)) {
|
||||
ctrGpuBeginFrame(GFX_BOTTOM);
|
||||
ctrSetViewportSize(320, 240);
|
||||
} else {
|
||||
ctrGpuBeginFrame(GFX_TOP);
|
||||
ctrSetViewportSize(400, 240);
|
||||
}
|
||||
guiDrawn &= ~GUI_THIS_FRAME;
|
||||
C3D_RenderBufClear(&bottomScreen);
|
||||
C3D_RenderBufClear(&topScreen);
|
||||
}
|
||||
|
||||
static void _drawEnd(void) {
|
||||
int screen = screenMode < SM_PA_TOP ? GFX_BOTTOM : GFX_TOP;
|
||||
u16 width = 0, height = 0;
|
||||
|
||||
void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(screen, outputFramebuffer, width, height);
|
||||
|
||||
if (screen != GFX_BOTTOM) {
|
||||
if (guiDrawn & (GUI_THIS_FRAME | GUI_ACTIVE)) {
|
||||
void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height);
|
||||
} else if (screenCleanup & SCREEN_CLEANUP_BOTTOM) {
|
||||
ctrGpuBeginFrame(GFX_BOTTOM);
|
||||
if (screenCleanup & SCREEN_CLEANUP_BOTTOM_1) {
|
||||
screenCleanup &= ~SCREEN_CLEANUP_BOTTOM_1;
|
||||
} else if (screenCleanup & SCREEN_CLEANUP_BOTTOM_2) {
|
||||
screenCleanup &= ~SCREEN_CLEANUP_BOTTOM_2;
|
||||
}
|
||||
void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
if ((screenCleanup & SCREEN_CLEANUP_TOP) && screen != GFX_TOP) {
|
||||
ctrGpuBeginFrame(GFX_TOP);
|
||||
if (screenCleanup & SCREEN_CLEANUP_TOP_1) {
|
||||
screenCleanup &= ~SCREEN_CLEANUP_TOP_1;
|
||||
} else if (screenCleanup & SCREEN_CLEANUP_TOP_2) {
|
||||
screenCleanup &= ~SCREEN_CLEANUP_TOP_2;
|
||||
}
|
||||
void* outputFramebuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(GFX_TOP, outputFramebuffer, width, height);
|
||||
}
|
||||
|
||||
ctrGpuEndDrawing();
|
||||
ctrFinalize();
|
||||
C3D_RenderBufTransfer(&topScreen, (u32*) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
|
||||
C3D_RenderBufTransfer(&bottomScreen, (u32*) gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
|
||||
gfxSwapBuffersGpu();
|
||||
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false);
|
||||
}
|
||||
|
||||
static int _batteryState(void) {
|
||||
|
@ -237,20 +201,17 @@ static int _batteryState(void) {
|
|||
}
|
||||
|
||||
static void _guiPrepare(void) {
|
||||
guiDrawn = GUI_ACTIVE | GUI_THIS_FRAME;
|
||||
int screen = screenMode < SM_PA_TOP ? GFX_BOTTOM : GFX_TOP;
|
||||
if (screen == GFX_BOTTOM) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrFlushBatch();
|
||||
ctrGpuBeginFrame(GFX_BOTTOM);
|
||||
C3D_RenderBufBind(&bottomScreen);
|
||||
ctrSetViewportSize(320, 240);
|
||||
}
|
||||
|
||||
static void _guiFinish(void) {
|
||||
guiDrawn &= ~GUI_ACTIVE;
|
||||
screenCleanup |= SCREEN_CLEANUP_BOTTOM;
|
||||
ctrFlushBatch();
|
||||
}
|
||||
|
||||
static void _setup(struct mGUIRunner* runner) {
|
||||
|
@ -322,7 +283,6 @@ static void _gameLoaded(struct mGUIRunner* runner) {
|
|||
unsigned mode;
|
||||
if (mCoreConfigGetUIntValue(&runner->core->config, "screenMode", &mode) && mode != screenMode) {
|
||||
screenMode = mode;
|
||||
screenCleanup |= SCREEN_CLEANUP_BOTTOM | SCREEN_CLEANUP_TOP;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,6 +318,15 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
|
|||
}
|
||||
|
||||
static void _drawTex(struct mCore* core, bool faded) {
|
||||
if (screenMode < SM_PA_TOP) {
|
||||
C3D_RenderBufBind(&bottomScreen);
|
||||
ctrSetViewportSize(320, 240);
|
||||
} else {
|
||||
C3D_RenderBufBind(&topScreen);
|
||||
ctrSetViewportSize(400, 240);
|
||||
}
|
||||
ctrActivateTexture(&outputTexture);
|
||||
|
||||
u32 color = faded ? 0x3FFFFFFF : 0xFFFFFFFF;
|
||||
|
||||
int screen_w = screenMode < SM_PA_TOP ? 320 : 400;
|
||||
|
@ -408,15 +377,16 @@ static void _drawTex(struct mCore* core, bool faded) {
|
|||
int y = (screen_h - h) / 2;
|
||||
|
||||
ctrAddRectScaled(color, x, y, w, h, 0, 0, corew, coreh);
|
||||
ctrFlushBatch();
|
||||
}
|
||||
|
||||
static void _drawFrame(struct mGUIRunner* runner, bool faded) {
|
||||
UNUSED(runner);
|
||||
|
||||
struct ctrTexture* tex = &gbaOutputTexture;
|
||||
C3D_Tex* tex = &outputTexture;
|
||||
|
||||
GSPGPU_FlushDataCache(outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2);
|
||||
GX_DisplayTransfer(
|
||||
C3D_SafeDisplayTransfer(
|
||||
outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS),
|
||||
tex->data, GX_BUFFER_DIM(256, 256),
|
||||
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB565) |
|
||||
|
@ -429,14 +399,13 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) {
|
|||
}
|
||||
|
||||
gspWaitForPPF();
|
||||
ctrActivateTexture(tex);
|
||||
_drawTex(runner->core, faded);
|
||||
}
|
||||
|
||||
static void _drawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, bool faded) {
|
||||
UNUSED(runner);
|
||||
|
||||
struct ctrTexture* tex = &gbaOutputTexture;
|
||||
C3D_Tex* tex = &outputTexture;
|
||||
|
||||
u16* newPixels = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * sizeof(u32), 0x100);
|
||||
|
||||
|
@ -454,7 +423,7 @@ static void _drawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, b
|
|||
}
|
||||
|
||||
GSPGPU_FlushDataCache(newPixels, 256 * VIDEO_VERTICAL_PIXELS * sizeof(u32));
|
||||
GX_DisplayTransfer(
|
||||
C3D_SafeDisplayTransfer(
|
||||
(u32*) newPixels, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS),
|
||||
tex->data, GX_BUFFER_DIM(256, 256),
|
||||
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB565) |
|
||||
|
@ -463,7 +432,6 @@ static void _drawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, b
|
|||
gspWaitForPPF();
|
||||
linearFree(newPixels);
|
||||
|
||||
ctrActivateTexture(tex);
|
||||
_drawTex(runner->core, faded);
|
||||
}
|
||||
|
||||
|
@ -479,9 +447,11 @@ static uint16_t _pollGameInput(struct mGUIRunner* runner) {
|
|||
|
||||
static void _incrementScreenMode(struct mGUIRunner* runner) {
|
||||
UNUSED(runner);
|
||||
screenCleanup |= SCREEN_CLEANUP_TOP | SCREEN_CLEANUP_BOTTOM;
|
||||
screenMode = (screenMode + 1) % SM_MAX;
|
||||
mCoreConfigSetUIntValue(&runner->core->config, "screenMode", screenMode);
|
||||
|
||||
C3D_RenderBufClear(&bottomScreen);
|
||||
C3D_RenderBufClear(&topScreen);
|
||||
}
|
||||
|
||||
static uint32_t _pollInput(void) {
|
||||
|
@ -636,39 +606,29 @@ int main() {
|
|||
audioRight = linearMemAlign(AUDIO_SAMPLE_BUFFER * sizeof(int16_t), 0x80);
|
||||
}
|
||||
|
||||
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
|
||||
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, true);
|
||||
|
||||
if (ctrInitGpu() < 0) {
|
||||
gbaOutputTexture.data = 0;
|
||||
if (!_initGpu()) {
|
||||
outputTexture.data = 0;
|
||||
_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctrTexture_Init(&gbaOutputTexture);
|
||||
gbaOutputTexture.format = GPU_RGB565;
|
||||
gbaOutputTexture.filter = GPU_LINEAR;
|
||||
gbaOutputTexture.width = 256;
|
||||
gbaOutputTexture.height = 256;
|
||||
gbaOutputTexture.data = vramAlloc(256 * 256 * 2);
|
||||
void* outputTextureEnd = (u8*)gbaOutputTexture.data + 256 * 256 * 2;
|
||||
|
||||
if (!gbaOutputTexture.data) {
|
||||
if (!C3D_TexInitVRAM(&outputTexture, 256, 256, GPU_RGB565)) {
|
||||
_cleanup();
|
||||
return 1;
|
||||
}
|
||||
C3D_TexSetWrap(&outputTexture, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE);
|
||||
C3D_TexSetFilter(&outputTexture, 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
|
||||
GX_MemoryFill(
|
||||
gbaOutputTexture.data, 0x0000, outputTextureEnd, GX_FILL_16BIT_DEPTH | GX_FILL_TRIGGER,
|
||||
outputTexture.data, 0x0000, outputTextureEnd, GX_FILL_16BIT_DEPTH | GX_FILL_TRIGGER,
|
||||
NULL, 0, NULL, 0);
|
||||
gspWaitForPSC0();
|
||||
|
||||
sdmcArchive = (FS_Archive) {
|
||||
ARCHIVE_SDMC,
|
||||
(FS_Path) { PATH_EMPTY, 1, "" },
|
||||
0
|
||||
};
|
||||
FSUSER_OpenArchive(&sdmcArchive);
|
||||
FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""));
|
||||
|
||||
struct GUIFont* font = GUIFontCreate();
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
; Copyright (c) 2015 Yuri Kunde Schlesner
|
||||
; Copyright (c) 2016 Jeffrey Pfau
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; 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/.
|
||||
|
||||
; Uniforms
|
||||
.fvec projectionMtx[4]
|
||||
.fvec textureMtx[2]
|
||||
|
||||
; Constants
|
||||
.constf consts1(0.0, 1.0, -0.5, -1.0)
|
||||
|
||||
; Outputs : here only position and color
|
||||
.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
|
||||
; Set up the vertex endpoints
|
||||
mov r0.xy, in_pos.xy
|
||||
mov r0.zw, consts1.zy
|
||||
add r1.xy, r0.xy, in_pos.zw
|
||||
|
||||
dp4 r2.x, projectionMtx[0], r0
|
||||
dp4 r2.y, projectionMtx[1], r0
|
||||
dp4 r2.z, projectionMtx[2], r0
|
||||
dp4 r2.w, projectionMtx[3], r0
|
||||
|
||||
dp4 r3.x, projectionMtx[0], r1
|
||||
dp4 r3.y, projectionMtx[1], r1
|
||||
dp4 r3.z, projectionMtx[2], r1
|
||||
dp4 r3.w, projectionMtx[3], r1
|
||||
|
||||
; Set up the texture endpoints
|
||||
mov r0.xy, in_tc0.xy
|
||||
mov r0.zw, consts1.xy
|
||||
add r1.xy, r0.xy, in_tc0.zw
|
||||
|
||||
dp4 r4.x, textureMtx[0], r0
|
||||
dp4 r4.y, textureMtx[1], r0
|
||||
mov r4.zw, consts1.xy
|
||||
|
||||
dp4 r5.x, textureMtx[0], r1
|
||||
dp4 r5.y, textureMtx[1], r1
|
||||
mov r5.zw, consts1.xy
|
||||
|
||||
; Emit top-left
|
||||
setemit 0
|
||||
mov out_pos.xyzw, r2.xyzw
|
||||
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_tc0.x, r5.x
|
||||
mov out_tc0.y, r4.y
|
||||
mov out_tc0.z, consts1.x
|
||||
mov out_tc0.w, consts1.y
|
||||
mov out_col, in_col
|
||||
emit
|
||||
|
||||
; Emit bottom-right
|
||||
setemit 2, prim
|
||||
mov out_pos.xyzw, r3.xyzw
|
||||
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_tc0.x, r4.x
|
||||
mov out_tc0.y, r5.y
|
||||
mov out_tc0.z, consts1.x
|
||||
mov out_tc0.w, consts1.y
|
||||
mov out_col, in_col
|
||||
emit
|
||||
|
||||
end
|
||||
.end
|
|
@ -1,4 +1,6 @@
|
|||
; Copyright (c) 2015 Yuri Kunde Schlesner
|
||||
; Copyright (c) 2016 Jeffrey Pfau
|
||||
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -8,31 +10,23 @@
|
|||
; corresponding matrices before outputting
|
||||
|
||||
; Uniforms
|
||||
.fvec projectionMtx[4]
|
||||
.fvec textureMtx[2]
|
||||
|
||||
; Constants
|
||||
.constf consts1(0.0, 1.0, 0.0039215686, 0.0)
|
||||
.constf consts1(0.0, 1.0, 0.0039215686, -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
|
||||
; Inputs
|
||||
.alias in_pos v0
|
||||
.alias in_tc0 v1
|
||||
.alias in_col v2
|
||||
|
||||
.proc main
|
||||
dp4 out_pos.x, projectionMtx[0], in_pos
|
||||
dp4 out_pos.y, projectionMtx[1], in_pos
|
||||
dp4 out_pos.z, projectionMtx[2], in_pos
|
||||
dp4 out_pos.w, projectionMtx[3], in_pos
|
||||
|
||||
dp4 out_tc0.x, textureMtx[0], in_tc0
|
||||
dp4 out_tc0.y, textureMtx[1], in_tc0
|
||||
mov out_tc0.zw, consts1.xxxy
|
||||
mov out_pos, in_pos
|
||||
mov out_tc0, in_tc0
|
||||
|
||||
; Normalize color by multiplying by 1 / 255
|
||||
mul out_col, consts1.z, in_col
|
Loading…
Reference in New Issue