From ee1c1ba2c70b6d802fe8949e16083032acc37633 Mon Sep 17 00:00:00 2001 From: rmn20 Date: Fri, 17 Jan 2025 03:22:35 +0300 Subject: [PATCH] Fog, DMA call lists, texture color indexation, texture offsets fixed and disabled, textureless polys fix, far plane intersecting polys fix --- src/Graphics_NDS.c | 300 ++++++++++++++++++++++++++++++++------------- 1 file changed, 218 insertions(+), 82 deletions(-) diff --git a/src/Graphics_NDS.c b/src/Graphics_NDS.c index 542368159..f7371b9e1 100644 --- a/src/Graphics_NDS.c +++ b/src/Graphics_NDS.c @@ -23,6 +23,9 @@ void Gfx_Create(void) { glClearColor(0, 15, 10, 31); glClearPolyID(63); glAlphaFunc(7); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_FOG); glClearDepth(GL_MAX_DEPTH); Gfx_SetViewport(0, 0, 256, 192); @@ -31,8 +34,14 @@ void Gfx_Create(void) { vramSetBankB(VRAM_B_TEXTURE); vramSetBankC(VRAM_C_TEXTURE); vramSetBankD(VRAM_D_TEXTURE); + vramSetBankE(VRAM_E_TEX_PALETTE); Gfx_SetFaceCulling(false); + + // Set texture matrix to identity + MATRIX_CONTROL = 3; + MATRIX_IDENTITY = 0; + MATRIX_CONTROL = 0; } cc_bool Gfx_TryRestoreContext(void) { @@ -45,6 +54,7 @@ void Gfx_Free(void) { vramSetBankB(VRAM_B_LCD); vramSetBankC(VRAM_C_LCD); vramSetBankD(VRAM_D_LCD); + vramSetBankE(VRAM_E_LCD); } @@ -90,7 +100,8 @@ void Gfx_ClearColor(PackedCol color) { } void Gfx_EndFrame(void) { - glFlush(0); + // W buffering is used for fog + glFlush(GL_WBUFFERING); // TODO not needed? swiWaitForVBlank(); } @@ -101,34 +112,94 @@ void Gfx_EndFrame(void) { *#########################################################################################################################*/ static int tex_width, tex_height; -GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { - vramSetBankA(VRAM_A_TEXTURE); +static int FindColorInPalette(cc_uint16* pal, int pal_size, cc_uint16 col) { + if ((col >> 15) == 0) return 0; + + for (int i = 1; i < pal_size; i++) { + if(pal[i] == col) return i; + } + + return -1; +} +GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { cc_uint16* tmp = Mem_TryAlloc(bmp->width * bmp->height, 2); if (!tmp) return 0; // TODO: Only copy when rowWidth != bmp->width - for (int y = 0; y < bmp->height; y++) - { + for (int y = 0; y < bmp->height; y++) { cc_uint16* src = bmp->scan0 + y * rowWidth; cc_uint16* dst = tmp + y * bmp->width; - for (int x = 0; x < bmp->width; x++) - { + for (int x = 0; x < bmp->width; x++) { dst[x] = src[x]; } } - + + // Palettize texture if possible + int pal_size = 1; + cc_uint16* tmp_palette = Mem_TryAlloc(256, 2); + if (!tmp_palette) return 0; + tmp_palette[0] = 0; + + for (int i = 0; i < bmp->width * bmp->height; i++) { + cc_uint16 col = tmp[i]; + + int idx = FindColorInPalette(tmp_palette, pal_size, col); + + if (idx == -1) { + pal_size++; + if (pal_size > 256) break; + tmp_palette[pal_size - 1] = col; + } + } + + int texFormat = GL_RGBA; + if(pal_size <= 4) texFormat = GL_RGB4; + else if(pal_size <= 16) texFormat = GL_RGB16; + else if(pal_size <= 256) texFormat = GL_RGB256; + + if(texFormat != GL_RGBA) { + char* tmp_chr = (char*) tmp; + + for (int i = 0; i < bmp->width * bmp->height; i++) { + cc_uint16 col = tmp[i]; + int idx = FindColorInPalette(tmp_palette, pal_size, col); + + if(texFormat == GL_RGB256) { + tmp_chr[i] = idx; + } else if(texFormat == GL_RGB16) { + if((i & 1) == 0) { + tmp_chr[i >> 1] = idx; + } else { + tmp_chr[i >> 1] |= idx << 4; + } + } else { + if((i & 3) == 0) { + tmp_chr[i >> 2] = idx; + } else { + tmp_chr[i >> 2] |= idx << (2 * (i & 3)); + } + } + } + } + + Platform_Log4("Texformat %i %i %i %i", &texFormat, &bmp->width, &bmp->height, &pal_size); + + // Load texture in vram int textureID; glGenTextures(1, &textureID); glBindTexture(0, textureID); - glTexImage2D(0, 0, GL_RGBA, bmp->width, bmp->height, 0, TEXGEN_TEXCOORD, tmp); - glTexParameter(0, GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T); + glTexImage2D(0, 0, texFormat, bmp->width, bmp->height, 0, 0, tmp); + if (texFormat != GL_RGBA) glColorTableEXT(0, 0, 256, 0, 0, tmp_palette); + + glTexParameter(0, GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T | TEXGEN_TEXCOORD | GL_TEXTURE_COLOR0_TRANSPARENT); cc_uint16* vram_ptr = glGetTexturePointer(textureID); if (!vram_ptr) Platform_Log2("No VRAM for %i x %i texture", &bmp->width, &bmp->height); Mem_Free(tmp); + Mem_Free(tmp_palette); return (void*)textureID; } @@ -151,7 +222,7 @@ void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, i return; // TODO doesn't work without VRAM bank changing to LCD and back maybe?? // (see what glTeximage2D does ??) - + for (int yy = 0; yy < part->height; yy++) { cc_uint16* dst = vram_ptr + width * (y + yy) + x; @@ -177,23 +248,6 @@ void Gfx_DisableMipmaps(void) { } /*########################################################################################################################* *-----------------------------------------------------State management----------------------------------------------------* *#########################################################################################################################*/ -void Gfx_SetFaceCulling(cc_bool enabled) { - glPolyFmt(POLY_ALPHA(31) | (enabled ? POLY_CULL_BACK : POLY_CULL_NONE)); -} - -static void SetAlphaBlend(cc_bool enabled) { - /*if (enabled) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - }*/ -} - -void Gfx_SetAlphaArgBlend(cc_bool enabled) { } - -static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { - // TODO -} void Gfx_SetDepthWrite(cc_bool enabled) { } void Gfx_SetDepthTest(cc_bool enabled) { } @@ -256,13 +310,16 @@ static int buf_count; static void* gfx_vertices; struct DSTexturedVertex { - vu32 xy; v16 z; + vu32 command; vu32 rgb; - int u, v; + vu32 uv; + vu32 xy; vu32 z; }; + struct DSColouredVertex { - vu32 xy; v16 z; + vu32 command; vu32 rgb; + vu32 xy; vu32 z; }; // Precalculate all the expensive vertex data conversion, @@ -274,20 +331,31 @@ static void PreprocessTexturedVertices(void) { for (int i = 0; i < buf_count; i++, src++, dst++) { struct VertexTextured v = *src; + v16 x = floattov16(v.x / 64.0f); v16 y = floattov16(v.y / 64.0f); v16 z = floattov16(v.z / 64.0f); - dst->xy = (y << 16) | (x & 0xFFFF); - dst->z = z; - dst->u = floattof32(v.U); - dst->v = floattof32(v.V); + /*int uvX = (v.U * 256.0f + 0.5f); // 0.5f for rounding + int uvY = (v.V * 256.0f + 0.5f);*/ + int uvX = ((int) (v.U * 4096.0f)) - 32768; + int uvY = ((int) (v.V * 4096.0f)) - 32768; int r = PackedCol_R(v.Col); int g = PackedCol_G(v.Col); int b = PackedCol_B(v.Col); - dst->rgb = RGB15(r >> 3, g >> 3, b >> 3); + + dst->command = FIFO_COMMAND_PACK(FIFO_NOP, FIFO_COLOR, FIFO_TEX_COORD, FIFO_VERTEX16); + + dst->rgb = ARGB16(1, r >> 3, g >> 3, b >> 3); + + dst->uv = TEXTURE_PACK(uvX, uvY); + + dst->xy = (y << 16) | (x & 0xFFFF); + dst->z = z; } + + DC_FlushRange(gfx_vertices, buf_count * sizeof(struct DSTexturedVertex)); } static void PreprocessColouredVertices(void) { @@ -297,17 +365,24 @@ static void PreprocessColouredVertices(void) { for (int i = 0; i < buf_count; i++, src++, dst++) { struct VertexColoured v = *src; + v16 x = floattov16(v.x / 64.0f); v16 y = floattov16(v.y / 64.0f); v16 z = floattov16(v.z / 64.0f); - dst->xy = (y << 16) | (x & 0xFFFF); - dst->z = z; int r = PackedCol_R(v.Col); int g = PackedCol_G(v.Col); int b = PackedCol_B(v.Col); - dst->rgb = RGB15(r >> 3, g >> 3, b >> 3); + + dst->command = FIFO_COMMAND_PACK(FIFO_NOP, FIFO_NOP, FIFO_COLOR, FIFO_VERTEX16); + + dst->rgb = ARGB16(1, r >> 3, g >> 3, b >> 3); + + dst->xy = (y << 16) | (x & 0xFFFF); + dst->z = z; } + + DC_FlushRange(gfx_vertices, buf_count * sizeof(struct DSColouredVertex)); } GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) { @@ -367,19 +442,97 @@ void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); } *#########################################################################################################################*/ static cc_bool skipRendering; +static cc_bool backfaceCullEnabled; + +static cc_bool fogEnabled; +static FogFunc fogMode; +static float fogDensityEnd; + +static void SetPolygonMode() { + glPolyFmt( + POLY_ALPHA(31) | + (backfaceCullEnabled ? POLY_CULL_BACK : POLY_CULL_NONE) | + (fogEnabled ? POLY_FOG : 0) | + POLY_RENDER_FAR_POLYS | + POLY_RENDER_1DOT_POLYS + ); +} + +void Gfx_SetFaceCulling(cc_bool enabled) { + backfaceCullEnabled = enabled; + SetPolygonMode(); +} + +static void SetAlphaBlend(cc_bool enabled) { + /*if (enabled) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + }*/ +} + +void Gfx_SetAlphaArgBlend(cc_bool enabled) { } + +static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { + // TODO +} + +static void RecalculateFog() { + if (fogMode == FOG_LINEAR) { + int fogEnd = floattof32(fogDensityEnd); + + // Find shift value so that our fog end is + // inside maximum distance covered by fog table + int shift = 10; + while (shift > 0) { + // why * 512? I dont know + if (32 * (0x400 >> shift) * 512 >= fogEnd) break; + shift--; + } + + glFogShift(shift); + glFogOffset(0); + + for (int i = 0; i < 32; i++) { + int distance = (i * 512 + 256) * (0x400 >> shift); + int intensity = distance * 127 / fogEnd; + if(intensity > 127) intensity = 127; + + glFogDensity(i, intensity); + } + + glFogDensity(31, 127); + } else { + // TODO? + } +} + void Gfx_SetFog(cc_bool enabled) { + fogEnabled = enabled; + SetPolygonMode(); } void Gfx_SetFogCol(PackedCol color) { + int r = PackedCol_R(color); + int g = PackedCol_G(color); + int b = PackedCol_B(color); + + glFogColor(r >> 3, g >> 3, b >> 3, 31); } void Gfx_SetFogDensity(float value) { + fogDensityEnd = value; + RecalculateFog(); } void Gfx_SetFogEnd(float value) { + fogDensityEnd = value; + RecalculateFog(); } void Gfx_SetFogMode(FogFunc func) { + fogMode = func; + RecalculateFog(); } static void SetAlphaTest(cc_bool enabled) { @@ -435,18 +588,17 @@ void Gfx_LoadMVP(const struct Matrix* view, const struct Matrix* proj, struct Ma Matrix_Mul(mvp, view, proj); } -static struct Matrix texMatrix; -void Gfx_EnableTextureOffset(float x, float y) { - texMatrix.row1.x = x; texMatrix.row2.y = y; - Gfx_LoadMatrix(2, &texMatrix); - //glTexParameter(0, TEXGEN_NORMAL | GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T); +static struct Matrix texMatrix = Matrix_IdentityValue; +void Gfx_EnableTextureOffset(float x, float y) { + // Looks bad due to low uvm precision + /*texMatrix.row4.x = x * 4096; texMatrix.row4.y = y * 4096; + Gfx_LoadMatrix(2, &texMatrix);*/ } void Gfx_DisableTextureOffset(void) { - texMatrix.row1.x = 0; texMatrix.row1.y = 0; - Gfx_LoadMatrix(2, &texMatrix); - //glTexParameter(0, TEXGEN_TEXCOORD | GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T); + /*texMatrix.row4.x = 0; texMatrix.row4.y = 0; + Gfx_LoadMatrix(2, &texMatrix);*/ } @@ -456,55 +608,39 @@ void Gfx_DisableTextureOffset(void) { void Gfx_SetVertexFormat(VertexFormat fmt) { gfx_format = fmt; gfx_stride = strideSizes[fmt]; - - if (fmt == VERTEX_FORMAT_TEXTURED) { - glEnable(GL_TEXTURE_2D); - } else { - glDisable(GL_TEXTURE_2D); - } } void Gfx_DrawVb_Lines(int verticesCount) { } +static void CallDrawList(void* list, u32 listSize) { + // Based on libnds glCallList + while (dmaBusy(0) || dmaBusy(1) || dmaBusy(2) || dmaBusy(3)); + dmaSetParams(0, list, (void*) &GFX_FIFO, DMA_FIFO | listSize); + while (dmaBusy(0)); +} static void Draw_ColouredTriangles(int verticesCount, int startVertex) { + glBindTexture(0, 0); // Disable texture GFX_BEGIN = GL_QUADS; - for (int i = 0; i < verticesCount; i++) - { - struct DSColouredVertex* v = (struct DSColouredVertex*)gfx_vertices + startVertex + i; - - GFX_COLOR = v->rgb; - GFX_VERTEX16 = v->xy; - GFX_VERTEX16 = v->z; - } + CallDrawList(&((struct DSColouredVertex*) gfx_vertices)[startVertex], verticesCount * 4); GFX_END = 0; } static void Draw_TexturedTriangles(int verticesCount, int startVertex) { - GFX_BEGIN = GL_QUADS; int width = tex_width, height = tex_height; - - // Original code used was - // U = mulf32(v->u, inttof32(width)) - // which behind the scenes expands to - // W = width << 12 - // U = ((int64)v->u * W) >> 12; - // and in this case, the bit shifts can be cancelled out - // to avoid calling __aeabi_lmul to perform the 64 bit multiplication - // therefore the code can be simplified to - // U = v->u * width - - for (int i = 0; i < verticesCount; i++) - { - struct DSTexturedVertex* v = (struct DSTexturedVertex*)gfx_vertices + startVertex + i; - - GFX_COLOR = v->rgb; - GFX_TEX_COORD = TEXTURE_PACK(f32tot16(v->u * width), f32tot16(v->v * height)); - GFX_VERTEX16 = v->xy; - GFX_VERTEX16 = v->z; - } + + // Scale uvm to fit into texture size + MATRIX_CONTROL = 3; + MATRIX_PUSH = 0; + glScalef32(width << 4, height << 4, 0); + + GFX_BEGIN = GL_QUADS; + CallDrawList(&((struct DSTexturedVertex*) gfx_vertices)[startVertex], verticesCount * 5); GFX_END = 0; + + MATRIX_POP = 1; + MATRIX_CONTROL = matrix_modes[lastMatrix]; } void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {