--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <3ds.h>
+
+#include "gs.h"
+#include "math.h"
+
+#define BUFFERMATRIXLIST_SIZE (GS_MATRIXSTACK_SIZE*4)
+
+static void gsInitMatrixStack();
+
+Handle linearAllocMutex;
+
+static u32 gsMatrixStackRegisters[GS_MATRIXTYPES];
+
+typedef struct
+{
+ u32 offset;
+ mtx44 data;
+}bufferMatrix_s;
+
+bufferMatrix_s bufferMatrixList[BUFFERMATRIXLIST_SIZE];
+int bufferMatrixListLength;
+
+//----------------------
+// GS SYSTEM STUFF
+//----------------------
+
+void initBufferMatrixList()
+{
+ bufferMatrixListLength=0;
+}
+
+void gsInit(DVLB_s* shader)
+{
+ gsInitMatrixStack();
+ initBufferMatrixList();
+ svcCreateMutex(&linearAllocMutex, false);
+ if(shader)
+ {
+ gsMatrixStackRegisters[0]=SHDR_GetUniformRegister(shader, "projection", 0);
+ gsMatrixStackRegisters[1]=SHDR_GetUniformRegister(shader, "modelview", 0);
+ }
+}
+
+void gsExit(void)
+{
+ svcCloseHandle(linearAllocMutex);
+}
+
+void gsStartFrame(void)
+{
+ GPUCMD_SetBufferOffset(0);
+ initBufferMatrixList();
+}
+
+void* gsLinearAlloc(size_t size)
+{
+ void* ret=NULL;
+
+ svcWaitSynchronization(linearAllocMutex, U64_MAX);
+ ret=linearAlloc(size);
+ svcReleaseMutex(linearAllocMutex);
+
+ return ret;
+}
+
+void gsLinearFree(void* mem)
+{
+ svcWaitSynchronization(linearAllocMutex, U64_MAX);
+ linearFree(mem);
+ svcReleaseMutex(linearAllocMutex);
+}
+
+//----------------------
+// MATRIX STACK STUFF
+//----------------------
+
+static mtx44 gsMatrixStacks[GS_MATRIXTYPES][GS_MATRIXSTACK_SIZE];
+static u32 gsMatrixStackRegisters[GS_MATRIXTYPES]={0x00, 0x04};
+static u8 gsMatrixStackOffsets[GS_MATRIXTYPES];
+static bool gsMatrixStackUpdated[GS_MATRIXTYPES];
+static GS_MATRIX gsCurrentMatrixType;
+
+static void gsInitMatrixStack()
+{
+ int i;
+ for(i=0; i<GS_MATRIXTYPES; i++)
+ {
+ gsMatrixStackOffsets[i]=0;
+ gsMatrixStackUpdated[i]=true;
+ loadIdentity44((float*)gsMatrixStacks[i][0]);
+ }
+ gsCurrentMatrixType=GS_PROJECTION;
+}
+
+float* gsGetMatrix(GS_MATRIX m)
+{
+ if(m<0 || m>=GS_MATRIXTYPES)return NULL;
+
+ return (float*)gsMatrixStacks[m][gsMatrixStackOffsets[m]];
+}
+
+int gsLoadMatrix(GS_MATRIX m, float* data)
+{
+ if(m<0 || m>=GS_MATRIXTYPES || !data)return -1;
+
+ memcpy(gsGetMatrix(m), data, sizeof(mtx44));
+
+ gsMatrixStackUpdated[m]=true;
+
+ return 0;
+}
+
+int gsPushMatrix()
+{
+ const GS_MATRIX m=gsCurrentMatrixType;
+ if(m<0 || m>=GS_MATRIXTYPES)return -1;
+ if(gsMatrixStackOffsets[m]<0 || gsMatrixStackOffsets[m]>=GS_MATRIXSTACK_SIZE-1)return -1;
+
+ float* cur=gsGetMatrix(m);
+ gsMatrixStackOffsets[m]++;
+ memcpy(gsGetMatrix(m), cur, sizeof(mtx44));
+
+ return 0;
+}
+
+int gsPopMatrix()
+{
+ const GS_MATRIX m=gsCurrentMatrixType;
+ if(m<0 || m>=GS_MATRIXTYPES)return -1;
+ if(gsMatrixStackOffsets[m]<1 || gsMatrixStackOffsets[m]>=GS_MATRIXSTACK_SIZE)return -1;
+
+ gsMatrixStackOffsets[m]--;
+
+ gsMatrixStackUpdated[m]=true;
+
+ return 0;
+}
+
+int gsMatrixMode(GS_MATRIX m)
+{
+ if(m<0 || m>=GS_MATRIXTYPES)return -1;
+
+ gsCurrentMatrixType=m;
+
+ return 0;
+}
+
+//------------------------
+// MATRIX TRANSFORM STUFF
+//------------------------
+
+int gsMultMatrix(float* data)
+{
+ if(!data)return -1;
+
+ mtx44 tmp;
+ multMatrix44(gsGetMatrix(gsCurrentMatrixType), data, (float*)tmp);
+ memcpy(gsGetMatrix(gsCurrentMatrixType), (float*)tmp, sizeof(mtx44));
+
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+
+ return 0;
+}
+
+void gsLoadIdentity()
+{
+ loadIdentity44(gsGetMatrix(gsCurrentMatrixType));
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsProjectionMatrix(float fovy, float aspect, float near, float far)
+{
+ initProjectionMatrix(gsGetMatrix(gsCurrentMatrixType), fovy, aspect, near, far);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsRotateX(float x)
+{
+ rotateMatrixX(gsGetMatrix(gsCurrentMatrixType), x, false);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsRotateY(float y)
+{
+ rotateMatrixY(gsGetMatrix(gsCurrentMatrixType), y, false);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsRotateZ(float z)
+{
+ rotateMatrixZ(gsGetMatrix(gsCurrentMatrixType), z, false);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsScale(float x, float y, float z)
+{
+ scaleMatrix(gsGetMatrix(gsCurrentMatrixType), x, y, z);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+void gsTranslate(float x, float y, float z)
+{
+ translateMatrix(gsGetMatrix(gsCurrentMatrixType), x, y, z);
+ gsMatrixStackUpdated[gsCurrentMatrixType]=true;
+}
+
+//----------------------
+// MATRIX RENDER STUFF
+//----------------------
+
+static void gsSetUniformMatrix(u32 startreg, float* m)
+{
+ float param[16];
+
+ param[0x0]=m[3]; //w
+ param[0x1]=m[2]; //z
+ param[0x2]=m[1]; //y
+ param[0x3]=m[0]; //x
+
+ param[0x4]=m[7];
+ param[0x5]=m[6];
+ param[0x6]=m[5];
+ param[0x7]=m[4];
+
+ param[0x8]=m[11];
+ param[0x9]=m[10];
+ param[0xa]=m[9];
+ param[0xb]=m[8];
+
+ param[0xc]=m[15];
+ param[0xd]=m[14];
+ param[0xe]=m[13];
+ param[0xf]=m[12];
+
+ GPU_SetUniform(startreg, (u32*)param, 4);
+}
+
+static int gsUpdateTransformation()
+{
+ GS_MATRIX m;
+ for(m=0; m<GS_MATRIXTYPES; m++)
+ {
+ if(gsMatrixStackUpdated[m])
+ {
+ if(m==GS_PROJECTION && bufferMatrixListLength<BUFFERMATRIXLIST_SIZE)
+ {
+ GPUCMD_GetBuffer(NULL, NULL, &bufferMatrixList[bufferMatrixListLength].offset);
+ memcpy(bufferMatrixList[bufferMatrixListLength].data, gsGetMatrix(m), sizeof(mtx44));
+ bufferMatrixListLength++;
+ }
+ gsSetUniformMatrix(gsMatrixStackRegisters[m], gsGetMatrix(m));
+ gsMatrixStackUpdated[m]=false;
+ }
+ }
+ return 0;
+}
+
+void gsAdjustBufferMatrices(mtx44 transformation)
+{
+ int i;
+ u32* buffer;
+ u32 offset;
+ GPUCMD_GetBuffer(&buffer, NULL, &offset);
+ for(i=0; i<bufferMatrixListLength; i++)
+ {
+ u32 o=bufferMatrixList[i].offset;
+ if(o+2<offset) //TODO : better check, need to account for param size
+ {
+ mtx44 newMatrix;
+ GPUCMD_SetBufferOffset(o);
+ multMatrix44((float*)bufferMatrixList[i].data, (float*)transformation, (float*)newMatrix);
+ gsSetUniformMatrix(gsMatrixStackRegisters[GS_PROJECTION], (float*)newMatrix);
+ }
+ }
+ GPUCMD_SetBufferOffset(offset);
+}
+
+//----------------------
+// VBO STUFF
+//----------------------
+
+int gsVboInit(gsVbo_s* vbo)
+{
+ if(!vbo)return -1;
+
+ vbo->data=NULL;
+ vbo->currentSize=0;
+ vbo->maxSize=0;
+ vbo->commands=NULL;
+ vbo->commandsSize=0;
+
+ return 0;
+}
+
+int gsVboCreate(gsVbo_s* vbo, u32 size)
+{
+ if(!vbo)return -1;
+
+ vbo->data=gsLinearAlloc(size);
+ vbo->numVertices=0;
+ vbo->currentSize=0;
+ vbo->maxSize=size;
+
+ return 0;
+}
+
+void* gsVboGetOffset(gsVbo_s* vbo)
+{
+ if(!vbo)return NULL;
+
+ return (void*)(&((u8*)vbo->data)[vbo->currentSize]);
+}
+
+int gsVboAddData(gsVbo_s* vbo, void* data, u32 size, u32 units)
+{
+ if(!vbo || !data || !size)return -1;
+ if(((s32)vbo->maxSize)-((s32)vbo->currentSize) < size)return -1;
+
+ memcpy(gsVboGetOffset(vbo), data, size);
+ vbo->currentSize+=size;
+ vbo->numVertices+=units;
+
+ return 0;
+}
+
+int gsVboFlushData(gsVbo_s* vbo)
+{
+ if(!vbo)return -1;
+
+ //unnecessary if we use flushAndRun
+ // GSPGPU_FlushDataCache(NULL, vbo->data, vbo->currentSize);
+
+ return 0;
+}
+
+int gsVboDestroy(gsVbo_s* vbo)
+{
+ if(!vbo)return -1;
+
+ if(vbo->commands)free(vbo->commands);
+ if(vbo->data)gsLinearFree(vbo->data);
+ gsVboInit(vbo);
+
+ return 0;
+}
+
+extern u32 debugValue[];
+
+void GPU_DrawArrayDirectly(GPU_Primitive_t primitive, u8* data, u32 n)
+{
+ //set attribute buffer address
+ GPUCMD_AddSingleParam(0x000F0200, (osConvertVirtToPhys((u32)data))>>3);
+ //set primitive type
+ GPUCMD_AddSingleParam(0x0002025E, primitive);
+ GPUCMD_AddSingleParam(0x0002025F, 0x00000001);
+ //index buffer not used for drawArrays but 0x000F0227 still required
+ GPUCMD_AddSingleParam(0x000F0227, 0x80000000);
+ //pass number of vertices
+ GPUCMD_AddSingleParam(0x000F0228, n);
+
+ GPUCMD_AddSingleParam(0x00010253, 0x00000001);
+
+ GPUCMD_AddSingleParam(0x00010245, 0x00000000);
+ GPUCMD_AddSingleParam(0x000F022E, 0x00000001);
+ GPUCMD_AddSingleParam(0x00010245, 0x00000001);
+ GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
+
+ // GPUCMD_AddSingleParam(0x000F0111, 0x00000001); //breaks stuff
+}
+
+//not thread safe
+int gsVboPrecomputeCommands(gsVbo_s* vbo)
+{
+ if(!vbo || vbo->commands)return -1;
+
+ static u32 tmpBuffer[128];
+
+ u32* savedAdr; u32 savedSize, savedOffset;
+ GPUCMD_GetBuffer(&savedAdr, &savedSize, &savedOffset);
+ GPUCMD_SetBuffer(tmpBuffer, 128, 0);
+
+ GPU_DrawArrayDirectly(GPU_TRIANGLES, vbo->data, vbo->numVertices);
+
+ GPUCMD_GetBuffer(NULL, NULL, &vbo->commandsSize);
+ vbo->commands=memalign(0x4, vbo->commandsSize*4);
+ if(!vbo->commands)return -1;
+ memcpy(vbo->commands, tmpBuffer, vbo->commandsSize*4);
+
+ GPUCMD_SetBuffer(savedAdr, savedSize, savedOffset);
+
+ return 0;
+}
+
+extern u32* gpuCmdBuf;
+extern u32 gpuCmdBufSize;
+extern u32 gpuCmdBufOffset;
+
+void _vboMemcpy50(u32* dst, u32* src);
+
+void _GPUCMD_AddRawCommands(u32* cmd, u32 size)
+{
+ if(!cmd || !size)return;
+
+ if(size*4==0x50)_vboMemcpy50(&gpuCmdBuf[gpuCmdBufOffset], cmd);
+ else memcpy(&gpuCmdBuf[gpuCmdBufOffset], cmd, size*4);
+ gpuCmdBufOffset+=size;
+}
+
+int gsVboDraw(gsVbo_s* vbo)
+{
+ if(!vbo || !vbo->data || !vbo->currentSize || !vbo->maxSize)return -1;
+
+ gsUpdateTransformation();
+
+ gsVboPrecomputeCommands(vbo);
+
+ // u64 val=svcGetSystemTick();
+ if(vbo->commands)
+ {
+ _GPUCMD_AddRawCommands(vbo->commands, vbo->commandsSize);
+ }else{
+ GPU_DrawArrayDirectly(GPU_TRIANGLES, vbo->data, vbo->numVertices);
+ }
+ // debugValue[5]+=(u32)(svcGetSystemTick()-val);
+ // debugValue[6]++;
+
+ return 0;
+}
+///////////////////////////////////////
+// GPU example //
+///////////////////////////////////////
+
+//this example is meant to show how to use the GPU to render a 3D object
+//it also shows how to do stereoscopic 3D
+//it uses GS which is a WIP GPU abstraction layer that's currently part of 3DScraft
+//keep in mind GPU reverse engineering is an ongoing effort and our understanding of it is still fairly limited.
+
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
-#include <string.h>
#include <3ds.h>
+
#include "math.h"
+#include "gs.h"
+
#include "test_vsh_shbin.h"
-#include "test_png_bin.h"
-#include "mdl.h"
+#include "texture_bin.h"
-DVLB_s* shader;
-float* vertArray;
-u32* texData;
+//will be moved into ctrulib at some point
+#define CONFIG_3D_SLIDERSTATE (*(float*)0x1FF81080)
-void setUniformMatrix(u32 startreg, float* m)
-{
- float param[16];
+#define RGBA8(r,g,b,a) ((((r)&0xFF)<<24) | (((g)&0xFF)<<16) | (((b)&0xFF)<<8) | (((a)&0xFF)<<0))
- param[0x0]=m[3]; //w
- param[0x1]=m[2]; //z
- param[0x2]=m[1]; //y
- param[0x3]=m[0]; //x
+//shader structure
+DVLB_s* shader;
+//texture data pointer
+u32* texData;
+//vbo structure
+gsVbo_s vbo;
- param[0x4]=m[7];
- param[0x5]=m[6];
- param[0x6]=m[5];
- param[0x7]=m[4];
-
- param[0x8]=m[11];
- param[0x9]=m[10];
- param[0xa]=m[9];
- param[0xb]=m[8];
+//GPU framebuffer address
+u32* gpuOut=(u32*)0x1F119400;
+//GPU depth buffer address
+u32* gpuDOut=(u32*)0x1F370800;
- param[0xc]=m[15];
- param[0xd]=m[14];
- param[0xe]=m[13];
- param[0xf]=m[12];
+//angle for the vertex lighting (cf test.vsh)
+float lightAngle;
+//object position and rotation angle
+vect3Df_s position, angle;
- GPU_SetUniform(startreg, (u32*)param, 4);
+//vertex structure
+typedef struct
+{
+ vect3Df_s position;
+ float texcoord[2];
+ vect3Df_s normal;
+}vertex_s;
+
+//object data (cube)
+//obviously this doesn't have to be defined manually, but we will here for the purposes of the example
+//each line is a vertex : {position.x, position.y, position.z}, {texcoord.t, texcoord.s}, {normal.x, normal.y, normal.z}
+//we're drawing triangles so three lines = one triangle
+const vertex_s modelVboData[]=
+{
+ //first face (PZ)
+ //first triangle
+ {(vect3Df_s){-0.5f, -0.5f, +0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, +0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ //second triangle
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, +0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, +0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, +1.0f}},
+ //second face (MZ)
+ //first triangle
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, -0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, -0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ //second triangle
+ {(vect3Df_s){+0.5f, +0.5f, -0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, -0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, 0.0f, -1.0f}},
+ //third face (PX)
+ //first triangle
+ {(vect3Df_s){+0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, -0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ //second triangle
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, +0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){+1.0f, 0.0f, 0.0f}},
+ //fourth face (MX)
+ //first triangle
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, +0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ //second triangle
+ {(vect3Df_s){-0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, -0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){-1.0f, 0.0f, 0.0f}},
+ //fifth face (PY)
+ //first triangle
+ {(vect3Df_s){-0.5f, +0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, +0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ //second triangle
+ {(vect3Df_s){+0.5f, +0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, +0.5f, -0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, +0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, +1.0f, 0.0f}},
+ //sixth face (MY)
+ //first triangle
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, -0.5f}, (float[]){1.0f, 1.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+ {(vect3Df_s){+0.5f, -0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+ //second triangle
+ {(vect3Df_s){+0.5f, -0.5f, +0.5f}, (float[]){1.0f, 0.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, +0.5f}, (float[]){0.0f, 0.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+ {(vect3Df_s){-0.5f, -0.5f, -0.5f}, (float[]){0.0f, 1.0f}, (vect3Df_s){0.0f, -1.0f, 0.0f}},
+};
+
+//stolen from staplebutt
+void GPU_SetDummyTexEnv(u8 num)
+{
+ GPU_SetTexEnv(num,
+ 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,
+ 0xFFFFFFFF);
}
-float angle=0.0f;
-float angleZ=0.0f;
-float tx, ty, tz;
-
-u32* gpuOut=(u32*)0x1F119400;
-u32* gpuDOut=(u32*)0x1F370800;
-
// topscreen
-void doFrame1()
+void renderFrame()
{
- //general setup
- GPU_SetViewport((u32*)osConvertVirtToPhys((u32)gpuDOut),(u32*)osConvertVirtToPhys((u32)gpuOut),0,0,240*2,400);
-
- GPU_DepthRange(-1.0f, 0.0f);
-
- GPU_SetFaceCulling(GPU_CULL_BACK_CCW);
- GPU_SetStencilTest(false, GPU_ALWAYS, 0x00);
- GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL);
-
- // ?
- GPUCMD_AddSingleParam(0x00010062, 0x00000000); //param always 0x0 according to code
- GPUCMD_AddSingleParam(0x000F0118, 0x00000000);
-
+ GPU_SetViewport((u32*)osConvertVirtToPhys((u32)gpuDOut),(u32*)osConvertVirtToPhys((u32)gpuOut),0,0,240*2,400);
+
+ GPU_DepthRange(-1.0f, 0.0f);
+ GPU_SetFaceCulling(GPU_CULL_BACK_CCW);
+ GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
+ GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP);
+ GPU_SetBlendingColor(0,0,0,0);
+ GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL);
+
+ GPUCMD_AddSingleParam(0x00010062, 0);
+ GPUCMD_AddSingleParam(0x000F0118, 0);
+
//setup shader
- SHDR_UseProgram(shader, 0);
-
- //attribute buffers
- GPU_SetAttributeBuffers(3, (u32*)osConvertVirtToPhys((u32)vertArray),
- GPU_ATTRIBFMT(0, 3, GPU_FLOAT)|GPU_ATTRIBFMT(1, 2, GPU_FLOAT)|GPU_ATTRIBFMT(2, 3, GPU_FLOAT),
- 0xFFC, 0x210, 1, (u32[]){0x00000000}, (u64[]){0x210}, (u8[]){3});
-
- //?
- GPUCMD_AddSingleParam(0x000F0100, 0x00E40100);
- GPUCMD_AddSingleParam(0x000F0101, 0x01010000);
- GPUCMD_AddSingleParam(0x000F0104, 0x00000010);
+ SHDR_UseProgram(shader, 0);
- //texturing stuff
- GPUCMD_AddSingleParam(0x0002006F, 0x00000100);
- GPUCMD_AddSingleParam(0x000F0080, 0x00011001); //enables/disables texturing
+ GPU_SetAlphaBlending(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00);
+
+ GPU_SetTextureEnable(GPU_TEXUNIT0);
- //texenv
- GPU_SetTexEnv(3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00000000);
- GPU_SetTexEnv(4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00000000);
- GPU_SetTexEnv(5, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR), GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
- GPU_TEVOPERANDS(0,0,0), GPU_TEVOPERANDS(0,0,0), GPU_MODULATE, GPU_MODULATE, 0xFFFFFFFF);
+ GPU_SetTexEnv(0,
+ GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
+ GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
+ GPU_TEVOPERANDS(0,0,0),
+ GPU_TEVOPERANDS(0,0,0),
+ GPU_MODULATE, GPU_MODULATE,
+ 0xFFFFFFFF);
+ GPU_SetDummyTexEnv(1);
+ GPU_SetDummyTexEnv(2);
+ GPU_SetDummyTexEnv(3);
+ GPU_SetDummyTexEnv(4);
+ GPU_SetDummyTexEnv(5);
//texturing stuff
- GPU_SetTexture((u32*)osConvertVirtToPhys((u32)texData),256,256,0x6,GPU_RGBA8);
-
- //setup matrices
- float modelView[16];
- float projection[16];
-
- loadIdentity44(modelView);
- loadIdentity44(projection);
-
- translateMatrix(modelView, tx, ty, tz);
- rotateMatrixX(modelView, angle);
- rotateMatrixZ(modelView, angleZ);
-
- initProjectionMatrix(projection, 1.3962634f, 240.0f/400.0f, 0.01f, 10.0f);
-
- setUniformMatrix(0x24, modelView);
- setUniformMatrix(0x20, projection);
-
- //draw first model
- GPU_DrawArray(GPU_TRIANGLES, mdlFaces*3);
- // GPU_DrawElements(GPU_TRIANGLES, (u32*)(((u32)((void*)indArray-(void*)gspHeap))+0x20000000-base), 6);
-
- //setup matrices
- loadIdentity44(modelView);
- loadIdentity44(projection);
-
- translateMatrix(modelView, tx, -ty, tz);
- rotateMatrixX(modelView, -angle);
- rotateMatrixZ(modelView, -angleZ);
-
- setUniformMatrix(0x24, modelView);
-
- //draw second
- GPU_DrawArray(GPU_TRIANGLES, mdlFaces*3);
-
- //finalize stuff ?
- GPU_FinishDrawing();
-}
-
-void demoControls(void)
-{
- hidScanInput();
- u32 PAD=hidKeysHeld();
-
- if(PAD&KEY_UP)tx+=0.1f;
- if(PAD&KEY_DOWN)tx-=0.1f;
-
- if(PAD&KEY_LEFT)ty+=0.1f;
- if(PAD&KEY_RIGHT)ty-=0.1f;
-
- if(PAD&KEY_R)tz+=0.1f;
- if(PAD&KEY_L)tz-=0.1f;
-
- if(PAD&KEY_A)angle+=0.1f;
- if(PAD&KEY_Y)angle-=0.1f;
+ GPU_SetTexture(GPU_TEXUNIT0, (u32*)osConvertVirtToPhys((u32)texData),128,128,GPU_TEXTURE_MAG_FILTER(GPU_NEAREST)|GPU_TEXTURE_MIN_FILTER(GPU_NEAREST),GPU_RGBA8);
+ GPU_SetAttributeBuffers(3, (u32*)osConvertVirtToPhys((u32)texData),
+ GPU_ATTRIBFMT(0, 3, GPU_FLOAT)|GPU_ATTRIBFMT(1, 2, GPU_FLOAT)|GPU_ATTRIBFMT(2, 3, GPU_FLOAT),
+ 0xFFC, 0x210, 1, (u32[]){0x00000000}, (u64[]){0x210}, (u8[]){3});
- if(PAD&KEY_X)angleZ+=0.1f;
- if(PAD&KEY_B)angleZ-=0.1f;
+ //setup lighting (this is specific to our shader)
+ vect3Df_s lightDir=vnormf(vect3Df(cos(lightAngle), -1.0f, sin(lightAngle)));
+ GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightDirection", 0), (u32*)(float[]){0.0f, -lightDir.z, -lightDir.y, -lightDir.x}, 4);
+ GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightAmbient", 0), (u32*)(float[]){0.7f, 0.4f, 0.4f, 0.4f}, 4);
+
+ //initialize projection matrix to standard perspective stuff
+ gsMatrixMode(GS_PROJECTION);
+ gsProjectionMatrix(80.0f*M_PI/180.0f, 240.0f/400.0f, 0.01f, 100.0f);
+ gsRotateZ(M_PI/2); //because framebuffer is sideways...
+
+ //draw object
+ gsMatrixMode(GS_MODELVIEW);
+ gsPushMatrix();
+ gsTranslate(position.x, position.y, position.z);
+ gsRotateX(angle.x);
+ gsRotateY(angle.y);
+ gsVboDraw(&vbo);
+ gsPopMatrix();
+ GPU_FinishDrawing();
}
-extern u32* gxCmdBuf;
-
-int main()
+int main(int argc, char** argv)
{
+ //setup services
srvInit();
aptInit();
gfxInit();
hidInit(NULL);
-
+
+ //initialize GPU
GPU_Init(NULL);
+ //let GFX know we're ok with doing stereoscopic 3D rendering
+ gfxSet3D(true);
+
+ //load our vertex shader binary
+ shader=SHDR_ParseSHBIN((u32*)test_vsh_shbin, test_vsh_shbin_size);
+
+ //initialize GS
+ gsInit(shader);
+
+ //allocate our GPU command buffers
+ //they *have* to be on the linear heap
u32 gpuCmdSize=0x40000;
u32* gpuCmd=(u32*)linearAlloc(gpuCmdSize*4);
+ u32* gpuCmdRight=(u32*)linearAlloc(gpuCmdSize*4);
- GPU_Reset(gxCmdBuf, gpuCmd, gpuCmdSize);
+ //actually reset the GPU
+ GPU_Reset(NULL, gpuCmd, gpuCmdSize);
- vertArray=(float*)linearAlloc(0x100000);
- texData=(u32*)linearAlloc(0x100000);
+ //create texture
+ texData=(u32*)linearMemAlign(texture_bin_size, 0x80); //textures need to be 0x80-byte aligned
+ memcpy(texData, texture_bin, texture_bin_size);
- memcpy(texData, test_png_bin, test_png_bin_size);
- memcpy(vertArray, mdlData, sizeof(mdlData));
- GSPGPU_FlushDataCache(NULL, mdlData, sizeof(mdlData));
- GSPGPU_FlushDataCache(NULL, test_png_bin, test_png_bin_size);
+ //create VBO
+ gsVboInit(&vbo);
+ gsVboCreate(&vbo, sizeof(modelVboData));
+ gsVboAddData(&vbo, (void*)modelVboData, sizeof(modelVboData), sizeof(modelVboData)/sizeof(vertex_s));
+ gsVboFlushData(&vbo);
- tx=ty=0.0f; tz=-0.1f;
- shader=SHDR_ParseSHBIN((u32*)test_vsh_shbin,test_vsh_shbin_size);
+ //initialize object position and angle
+ position=vect3Df(0.0f, 0.0f, -2.0f);
+ angle=vect3Df(M_PI/4, M_PI/4, 0.0f);
- GX_SetMemoryFill(gxCmdBuf, (u32*)gpuOut, 0x404040FF, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201);
- gspWaitForPSC0();
- gfxSwapBuffersGpu();
+ //background color (blue)
+ u32 backgroundColor=RGBA8(0x68, 0xB0, 0xD8, 0xFF);
while(aptMainLoop())
{
- demoControls();
-
- GX_SetMemoryFill(gxCmdBuf, (u32*)gpuOut, 0x404040FF, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201);
- gspWaitForPSC0();
-
- GPUCMD_SetBuffer(gpuCmd, gpuCmdSize, 0);
- doFrame1();
+ //get current 3D slider state
+ float slider=CONFIG_3D_SLIDERSTATE;
+
+ //controls
+ hidScanInput();
+ //START to exit to hbmenu
+ if(keysDown()&KEY_START)break;
+
+ //A/B to change vertex lighting angle
+ if(keysHeld()&KEY_A)lightAngle+=0.1f;
+ if(keysHeld()&KEY_B)lightAngle-=0.1f;
+
+ //D-PAD to rotate object
+ if(keysHeld()&KEY_RIGHT)angle.x+=0.05f;
+ if(keysHeld()&KEY_LEFT)angle.x-=0.05f;
+ if(keysHeld()&KEY_UP)angle.y+=0.05f;
+ if(keysHeld()&KEY_DOWN)angle.y-=0.05f;
+
+ //R/L to bring object closer to or move it further from the camera
+ if(keysHeld()&KEY_R)position.z+=0.1f;
+ if(keysHeld()&KEY_L)position.z-=0.1f;
+
+ //generate our GPU command buffer for this frame
+ gsStartFrame();
+ renderFrame();
GPUCMD_Finalize();
- GPUCMD_Run(gxCmdBuf);
- gspWaitForP3D();
+ if(slider>0.0f)
+ {
+ //new and exciting 3D !
+ //make a copy of left gpu buffer
+ u32 offset; GPUCMD_GetBuffer(NULL, NULL, &offset);
+ memcpy(gpuCmdRight, gpuCmd, offset*4);
+
+ //setup interaxial
+ float interaxial=slider*0.12f;
+
+ //adjust left gpu buffer fo 3D !
+ {mtx44 m; loadIdentity44((float*)m); translateMatrix((float*)m, -interaxial*0.5f, 0.0f, 0.0f); gsAdjustBufferMatrices(m);}
+
+ //draw left framebuffer
+ GPUCMD_FlushAndRun(NULL);
+
+ //while GPU starts drawing the left buffer, adjust right one for 3D !
+ GPUCMD_SetBuffer(gpuCmdRight, gpuCmdSize, offset);
+ {mtx44 m; loadIdentity44((float*)m); translateMatrix((float*)m, interaxial*0.5f, 0.0f, 0.0f); gsAdjustBufferMatrices(m);}
+
+ //we wait for the left buffer to finish drawing
+ gspWaitForP3D();
+ GX_SetDisplayTransfer(NULL, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000);
+ gspWaitForPPF();
+
+ //we draw the right buffer, wait for it to finish and then switch back to left one
+ //clear the screen
+ GX_SetMemoryFill(NULL, (u32*)gpuOut, backgroundColor, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201);
+ gspWaitForPSC0();
+
+ //draw the right framebuffer
+ GPUCMD_FlushAndRun(NULL);
+ gspWaitForP3D();
+
+ //transfer from GPU output buffer to actual framebuffer
+ GX_SetDisplayTransfer(NULL, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), 0x019001E0, 0x01001000);
+ gspWaitForPPF();
+ GPUCMD_SetBuffer(gpuCmd, gpuCmdSize, 0);
+ }else{
+ //boring old 2D !
+
+ //draw the frame
+ GPUCMD_FlushAndRun(NULL);
+ gspWaitForP3D();
+
+ //clear the screen
+ GX_SetDisplayTransfer(NULL, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000);
+ gspWaitForPPF();
+ }
+
+ //clear the screen
+ GX_SetMemoryFill(NULL, (u32*)gpuOut, backgroundColor, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201);
+ gspWaitForPSC0();
gfxSwapBuffersGpu();
- GX_SetDisplayTransfer(gxCmdBuf, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000);
- gspWaitForPPF();
- gspWaitForVBlank();
+
+ gspWaitForEvent(GSPEVENT_VBlank0, true);
}
+ gsExit();
hidExit();
gfxExit();
aptExit();