3DS: Implement adjustable filtering and sprite rotation

This commit is contained in:
Jeffrey Pfau 2016-08-21 03:16:00 -07:00
parent 39230ca9ac
commit 526f86d085
8 changed files with 235 additions and 133 deletions

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View File

@ -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

View File

@ -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