3DS: Now stuff sorta renders

This commit is contained in:
UnknownShadow200 2023-04-17 22:38:15 +10:00
parent 00b0af1a5e
commit 5a4e4756f0
4 changed files with 218 additions and 60 deletions

View file

@ -8,11 +8,16 @@ struct Stream;
/* Represents a packed 32 bit RGBA colour, suitable for native graphics API texture pixels. */
typedef cc_uint32 BitmapCol;
#if defined CC_BUILD_WEB || defined CC_BUILD_ANDROID || defined CC_BUILD_PSP
#if defined CC_BUILD_WEB || defined CC_BUILD_ANDROID || defined CC_BUILD_PSP // TODO not 3DS?
#define BITMAPCOLOR_R_SHIFT 0
#define BITMAPCOLOR_G_SHIFT 8
#define BITMAPCOLOR_B_SHIFT 16
#define BITMAPCOLOR_A_SHIFT 24
#elif defined CC_BUILD_3DS
#define BITMAPCOLOR_R_SHIFT 24
#define BITMAPCOLOR_G_SHIFT 16
#define BITMAPCOLOR_B_SHIFT 8
#define BITMAPCOLOR_A_SHIFT 0
#else
#define BITMAPCOLOR_B_SHIFT 0
#define BITMAPCOLOR_G_SHIFT 8

View file

@ -24,7 +24,7 @@ unsigned int __stacksize__ = 256 * 1024;
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
/* Current format and size of vertices */
// Current format and size of vertices
static int gfx_stride, gfx_format = -1;
@ -32,15 +32,14 @@ static int gfx_stride, gfx_format = -1;
*------------------------------------------------------Vertex shaders-----------------------------------------------------*
*#########################################################################################################################*/
#define UNI_MVP_MATRIX (1 << 0)
/* cached uniforms (cached for multiple programs */
static struct Matrix _view, _proj, _mvp;
// cached uniforms (cached for multiple programs)
static C3D_Mtx _mvp;
static struct CCShader {
DVLB_s* dvlb;
shaderProgram_s program;
int uniforms; /* which associated uniforms need to be resent to GPU */
int locations[1]; /* location of uniforms (not constant) */
int uniforms; // which associated uniforms need to be resent to GPU
int locations[1]; // location of uniforms (not constant)
};
static struct CCShader* gfx_activeShader;
static struct CCShader shaders[2];
@ -58,27 +57,28 @@ static void Shader_Free(struct CCShader* shader) {
DVLB_Free(shader->dvlb);
}
/* Marks a uniform as changed on all programs */
// Marks a uniform as changed on all programs
static void DirtyUniform(int uniform) {
int i;
for (int i = 0; i < Array_Elems(shaders); i++) {
for (int i = 0; i < Array_Elems(shaders); i++)
{
shaders[i].uniforms |= uniform;
}
}
/* Sends changed uniforms to the GPU for current program */
// Sends changed uniforms to the GPU for current program
static void ReloadUniforms(void) {
struct CCShader* s = gfx_activeShader;
if (!s) return; /* NULL if context is lost */
if (!s) return; // NULL if context is lost
if (s->uniforms & UNI_MVP_MATRIX) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, s->locations[0], &_mvp);
s->uniforms &= ~UNI_MVP_MATRIX;
}
}
static void ReloadUniforms(void);
/* Switches program to one that can render current vertex format and state */
/* Compiles program and reloads uniforms if needed */
// Switches program to one that can render current vertex format and state
// Loads program and reloads uniforms if needed
static void SwitchProgram(void) {
struct CCShader* shader;
int index = 0;
@ -115,6 +115,7 @@ void Gfx_Create(void) {
Gfx.MaxTexWidth = 512;
Gfx.MaxTexHeight = 512;
Gfx.Created = true;
Gfx_SetFaceCulling(false);
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
@ -125,10 +126,18 @@ void Gfx_Create(void) {
// Configure the first fragment shading substage to just pass through the vertex color
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
//C3D_TexEnv* env = C3D_GetTexEnv(0);
//C3D_TexEnvInit(env);
//C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, 0, 0);
//C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
// Configure the first fragment shading substage to blend the texture color with
// the vertex color (calculated by the vertex shader using a lighting algorithm)
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, 0, 0);
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
}
cc_bool Gfx_TryRestoreContext(void) { return true; }
@ -137,11 +146,10 @@ void Gfx_Free(void) { FreeShaders(); }
void Gfx_RestoreState(void) { }
void Gfx_FreeState(void) { }
/*########################################################################################################################*
*---------------------------------------------------------Textures--------------------------------------------------------*
*#########################################################################################################################*/
static inline cc_uint32 CalcZOrder(cc_uint32 x, cc_uint32 y) {
/*static inline cc_uint32 CalcZOrder(cc_uint32 x, cc_uint32 y) {
// Simplified "Interleave bits by Binary Magic Numbers" from
// http://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableObvious
// TODO: Simplify to array lookup?
@ -152,15 +160,25 @@ static inline cc_uint32 CalcZOrder(cc_uint32 x, cc_uint32 y) {
y = (y | (y << 1)) & 0x55;
return x | (y << 1);
}*/
static inline cc_uint32 CalcZOrder(cc_uint32 a) {
// Simplified "Interleave bits by Binary Magic Numbers" from
// http://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableObvious
// TODO: Simplify to array lookup?
a = (a | (a << 2)) & 0x33;
a = (a | (a << 1)) & 0x55;
return a;
// equivalent to return (a & 1) | ((a & 2) << 1) | (a & 4) << 2;
// but compiles to less instructions
}
// Pixels are arranged in a recursive Z-order curve / Morton offset
// They are arranged into 8x8 tiles, where each 8x8 tile is composed of
// four 4x4 subtiles, which are in turn composed of four 2x2 subtiles
static void ToMortonTexture(C3D_Tex* tex, int originX, int originY,
struct Bitmap* bmp, int rowWidth) {
unsigned pixel, morton;
unsigned dstX, dstY, tileX, tileY;
struct Bitmap* bmp, int rowWidth) {
unsigned int pixel, mortonX, mortonY;
unsigned int dstX, dstY, tileX, tileY;
int width = bmp->width, height = bmp->height;
cc_uint32* dst = tex->data;
@ -168,17 +186,18 @@ static void ToMortonTexture(C3D_Tex* tex, int originX, int originY,
for (int y = 0; y < height; y++)
{
dstY = tex->height - 1 - (y + originY);
tileY = dstY & ~0x07;
dstY = tex->height - 1 - (y + originY);
tileY = dstY & ~0x07;
mortonY = CalcZOrder(dstY & 0x07) << 1;
for (int x = 0; x < width; x++)
{
dstX = x + originX;
tileX = dstX & ~0x07;
morton = CalcZOrder(dstX & 0x07, dstY & 0x07);
pixel = src[x + (y * rowWidth)];
dstX = x + originX;
tileX = dstX & ~0x07;
mortonX = CalcZOrder(dstX & 0x07);
pixel = src[x + (y * rowWidth)];
dst[morton + (tileX * 8) + (tileY * tex->width)] = pixel;
dst[(mortonX | mortonY) + (tileX * 8) + (tileY * tex->width)] = pixel;
}
}
}
@ -190,6 +209,7 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm
ToMortonTexture(tex, 0, 0, bmp, bmp->width);
C3D_TexSetFilter(tex, GPU_NEAREST, GPU_NEAREST);
C3D_TexSetWrap(tex, GPU_REPEAT, GPU_REPEAT);
return tex;
}
@ -223,35 +243,62 @@ void Gfx_BindTexture(GfxResourceID texId) {
/*########################################################################################################################*
*-----------------------------------------------------State management----------------------------------------------------*
*#########################################################################################################################*/
void Gfx_SetFaceCulling(cc_bool enabled) { }
void Gfx_SetAlphaBlending(cc_bool enabled) { }
void Gfx_SetFaceCulling(cc_bool enabled) {
C3D_CullFace(enabled ? GPU_CULL_FRONT_CCW : GPU_CULL_NONE);
}
void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
void Gfx_SetAlphaBlending(cc_bool enabled) {
if (enabled) {
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
} else {
C3D_ColorLogicOp(GPU_LOGICOP_COPY);
}
}
void Gfx_SetAlphaTest(cc_bool enabled) {
C3D_AlphaTest(enabled, GPU_GREATER, 0x7F);
}
void Gfx_DepthOnlyRendering(cc_bool depthOnly) {
cc_bool enabled = !depthOnly;
Gfx_SetColWriteMask(enabled, enabled, enabled, enabled);
}
static PackedCol clear_color;
void Gfx_ClearCol(PackedCol color) {
//clear_color = color;
void Gfx_ClearCol(PackedCol color) {
// TODO find better way?
clear_color = (PackedCol_R(color) << 24) | (PackedCol_G(color) << 16) | (PackedCol_B(color) << 8) | 0xFF;
}
static cc_bool depthTest, depthWrite;
static int colorWriteMask = GPU_WRITE_COLOR;
static void UpdateDepthWriteMask(void) {
//C3D_EarlyDepthTest(true, GPU_EARLYDEPTH_GREATER, 0);
//C3D_EarlyDepthTest(false, GPU_EARLYDEPTH_GREATER, 0);
int writeMask = colorWriteMask;
if (depthWrite) writeMask |= GPU_WRITE_DEPTH;
C3D_DepthTest(depthTest, GPU_GEQUAL, writeMask);
}
void Gfx_SetDepthWrite(cc_bool enabled) {
depthWrite = enabled;
UpdateDepthWriteMask();
}
void Gfx_SetDepthTest(cc_bool enabled) {
depthTest = enabled;
UpdateDepthWriteMask();
}
void Gfx_SetColWriteMask(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
}
void Gfx_SetDepthWrite(cc_bool enabled) { }
void Gfx_SetDepthTest(cc_bool enabled) { }
/*########################################################################################################################*
*---------------------------------------------------------Matrices--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) {
//Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR);
Mtx_Ortho(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR, false);
}
void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) {
float zNear = 0.1f;
//Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar);
Mtx_Persp(matrix, fov, aspect, 0.1f, zFar, false);
int mask = 0;
if (r) mask |= GPU_WRITE_RED;
if (g) mask |= GPU_WRITE_GREEN;
if (b) mask |= GPU_WRITE_BLUE;
if (a) mask |= GPU_WRITE_ALPHA;
colorWriteMask = mask;
}
@ -388,26 +435,62 @@ void Gfx_SetFogEnd(float value) {
void Gfx_SetFogMode(FogFunc func) {
}
void Gfx_SetAlphaTest(cc_bool enabled) {
C3D_AlphaTest(enabled, GPU_GREATER, 0x7F);
}
void Gfx_DepthOnlyRendering(cc_bool depthOnly) {
}
/*########################################################################################################################*
*---------------------------------------------------------Matrices--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
if (type == MATRIX_VIEW) _view = *matrix;
if (type == MATRIX_PROJECTION) _proj = *matrix;
static C3D_Mtx _view, _proj;
Matrix_Mul(&_mvp, &_view, &_proj);
void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) {
Mtx_OrthoTilt(matrix, 0.0f, width, height, 0.0f, ORTHO_NEAR, ORTHO_FAR, true);
}
void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) {
Mtx_PerspTilt(matrix, fov, aspect, 0.1f, zFar, true);
}
void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
if (type == MATRIX_VIEW) {
float* m = (float*)matrix;
// Transpose
for(int i = 0; i < 4; i++)
{
_view.r[i].x = m[0 + i];
_view.r[i].y = m[4 + i];
_view.r[i].z = m[8 + i];
_view.r[i].w = m[12 + i];
}
}
if (type == MATRIX_PROJECTION) _proj = *((C3D_Mtx*)matrix);
Mtx_Multiply(&_mvp, &_proj, &_view);
DirtyUniform(UNI_MVP_MATRIX);
ReloadUniforms();
}
/*void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
if (type == MATRIX_VIEW) _view = *matrix;
// Provided projection matrix assumes landscape display, but 3DS framebuffer
// is a rotated portrait display, so need to swap pixel X/Y values to correct that
//
// This can be done by rotating the projection matrix 90 degrees around Z axis
// https://open.gl/transformations
if (type == MATRIX_PROJECTION) {
struct Matrix rot = Matrix_Identity;
rot.row1.X = 0; rot.row1.Y = 1;
rot.row2.X = -1; rot.row2.Y = 0;
//Matrix_RotateZ(&rot, 90 * MATH_DEG2RAD);
//Matrix_Mul(&_proj, &_proj, &rot); // TODO avoid Matrix_Mul ??
Matrix_Mul(&_proj, matrix, &rot); // TODO avoid Matrix_Mul ?
}
UpdateMVP();
DirtyUniform(UNI_MVP_MATRIX);
ReloadUniforms();
}*/
void Gfx_LoadIdentityMatrix(MatrixType type) {
Gfx_LoadMatrix(type, &Matrix_Identity);
}

33
src/_3DS_coloured.v.pica Normal file
View file

@ -0,0 +1,33 @@
; Vertex shader for rendering coloured vertices for PICA200 GPU on the Nintendo 3DS
; ==================================================================================
; Uniforms
.fvec MVP[4];
; Constants
.constf ONES(1.0, 1.0, 1.0, 1.0)
.constf ONE_DIV_255(0.003921568627, 0.003921568627, 0.003921568627, 0.003921568627)
; Outputs
.out out_pos position
.out out_col color
; Inputs (defined as aliases for convenience)
.alias in_pos v0
.alias in_col v1
.proc main
; r0 = in_pos
mov r0, in_pos
; out_pos = MVP * r0
dp4 out_pos.x, MVP[0], r0
dp4 out_pos.y, MVP[1], r0
dp4 out_pos.z, MVP[2], r0
dp4 out_pos.w, MVP[3], r0
; out_col = in_col * ONE_DIV_255
mul out_col, ONE_DIV_255, in_col
end
.end

37
src/_3DS_textured.v.pica Normal file
View file

@ -0,0 +1,37 @@
; Vertex shader for rendering textured vertices for PICA200 GPU on the Nintendo 3DS
; ==================================================================================
; Uniforms
.fvec MVP[4];
; Constants
.constf ONES(1.0, 1.0, 1.0, 1.0)
.constf ONE_DIV_255(0.003921568627, 0.003921568627, 0.003921568627, 0.003921568627)
; Outputs
.out out_pos position
.out out_col color
.out out_tex texcoord0
; Inputs (defined as aliases for convenience)
.alias in_pos v0
.alias in_col v1
.alias in_tex v2
.proc main
; r0 = in_pos
mov r0, in_pos
; out_pos = MVP * r0
dp4 out_pos.x, MVP[0], r0
dp4 out_pos.y, MVP[1], r0
dp4 out_pos.z, MVP[2], r0
dp4 out_pos.w, MVP[3], r0
; out_tex = in_tex
mov out_tex, in_tex
; out_col = in_col * ONE_DIV_255
mul out_col, ONE_DIV_255, in_col
end
.end