Fog, DMA call lists, texture color indexation, texture offsets fixed and disabled, textureless polys fix, far plane intersecting polys fix

This commit is contained in:
rmn20 2025-01-17 03:22:35 +03:00
parent df49656b25
commit ee1c1ba2c7

View file

@ -23,6 +23,9 @@ void Gfx_Create(void) {
glClearColor(0, 15, 10, 31); glClearColor(0, 15, 10, 31);
glClearPolyID(63); glClearPolyID(63);
glAlphaFunc(7); glAlphaFunc(7);
glEnable(GL_TEXTURE_2D);
glEnable(GL_FOG);
glClearDepth(GL_MAX_DEPTH); glClearDepth(GL_MAX_DEPTH);
Gfx_SetViewport(0, 0, 256, 192); Gfx_SetViewport(0, 0, 256, 192);
@ -31,8 +34,14 @@ void Gfx_Create(void) {
vramSetBankB(VRAM_B_TEXTURE); vramSetBankB(VRAM_B_TEXTURE);
vramSetBankC(VRAM_C_TEXTURE); vramSetBankC(VRAM_C_TEXTURE);
vramSetBankD(VRAM_D_TEXTURE); vramSetBankD(VRAM_D_TEXTURE);
vramSetBankE(VRAM_E_TEX_PALETTE);
Gfx_SetFaceCulling(false); Gfx_SetFaceCulling(false);
// Set texture matrix to identity
MATRIX_CONTROL = 3;
MATRIX_IDENTITY = 0;
MATRIX_CONTROL = 0;
} }
cc_bool Gfx_TryRestoreContext(void) { cc_bool Gfx_TryRestoreContext(void) {
@ -45,6 +54,7 @@ void Gfx_Free(void) {
vramSetBankB(VRAM_B_LCD); vramSetBankB(VRAM_B_LCD);
vramSetBankC(VRAM_C_LCD); vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_LCD); vramSetBankD(VRAM_D_LCD);
vramSetBankE(VRAM_E_LCD);
} }
@ -90,7 +100,8 @@ void Gfx_ClearColor(PackedCol color) {
} }
void Gfx_EndFrame(void) { void Gfx_EndFrame(void) {
glFlush(0); // W buffering is used for fog
glFlush(GL_WBUFFERING);
// TODO not needed? // TODO not needed?
swiWaitForVBlank(); swiWaitForVBlank();
} }
@ -101,34 +112,94 @@ void Gfx_EndFrame(void) {
*#########################################################################################################################*/ *#########################################################################################################################*/
static int tex_width, tex_height; static int tex_width, tex_height;
GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { static int FindColorInPalette(cc_uint16* pal, int pal_size, cc_uint16 col) {
vramSetBankA(VRAM_A_TEXTURE); 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); cc_uint16* tmp = Mem_TryAlloc(bmp->width * bmp->height, 2);
if (!tmp) return 0; if (!tmp) return 0;
// TODO: Only copy when rowWidth != bmp->width // 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* src = bmp->scan0 + y * rowWidth;
cc_uint16* dst = tmp + y * bmp->width; 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]; 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; int textureID;
glGenTextures(1, &textureID); glGenTextures(1, &textureID);
glBindTexture(0, textureID); glBindTexture(0, textureID);
glTexImage2D(0, 0, GL_RGBA, bmp->width, bmp->height, 0, TEXGEN_TEXCOORD, tmp); glTexImage2D(0, 0, texFormat, bmp->width, bmp->height, 0, 0, tmp);
glTexParameter(0, GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T); 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); cc_uint16* vram_ptr = glGetTexturePointer(textureID);
if (!vram_ptr) Platform_Log2("No VRAM for %i x %i texture", &bmp->width, &bmp->height); if (!vram_ptr) Platform_Log2("No VRAM for %i x %i texture", &bmp->width, &bmp->height);
Mem_Free(tmp); Mem_Free(tmp);
Mem_Free(tmp_palette);
return (void*)textureID; return (void*)textureID;
} }
@ -151,7 +222,7 @@ void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, i
return; return;
// TODO doesn't work without VRAM bank changing to LCD and back maybe?? // TODO doesn't work without VRAM bank changing to LCD and back maybe??
// (see what glTeximage2D does ??) // (see what glTeximage2D does ??)
for (int yy = 0; yy < part->height; yy++) for (int yy = 0; yy < part->height; yy++)
{ {
cc_uint16* dst = vram_ptr + width * (y + yy) + x; cc_uint16* dst = vram_ptr + width * (y + yy) + x;
@ -177,23 +248,6 @@ void Gfx_DisableMipmaps(void) { }
/*########################################################################################################################* /*########################################################################################################################*
*-----------------------------------------------------State management----------------------------------------------------* *-----------------------------------------------------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_SetDepthWrite(cc_bool enabled) { }
void Gfx_SetDepthTest(cc_bool enabled) { } void Gfx_SetDepthTest(cc_bool enabled) { }
@ -256,13 +310,16 @@ static int buf_count;
static void* gfx_vertices; static void* gfx_vertices;
struct DSTexturedVertex { struct DSTexturedVertex {
vu32 xy; v16 z; vu32 command;
vu32 rgb; vu32 rgb;
int u, v; vu32 uv;
vu32 xy; vu32 z;
}; };
struct DSColouredVertex { struct DSColouredVertex {
vu32 xy; v16 z; vu32 command;
vu32 rgb; vu32 rgb;
vu32 xy; vu32 z;
}; };
// Precalculate all the expensive vertex data conversion, // 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++) for (int i = 0; i < buf_count; i++, src++, dst++)
{ {
struct VertexTextured v = *src; struct VertexTextured v = *src;
v16 x = floattov16(v.x / 64.0f); v16 x = floattov16(v.x / 64.0f);
v16 y = floattov16(v.y / 64.0f); v16 y = floattov16(v.y / 64.0f);
v16 z = floattov16(v.z / 64.0f); v16 z = floattov16(v.z / 64.0f);
dst->xy = (y << 16) | (x & 0xFFFF);
dst->z = z;
dst->u = floattof32(v.U); /*int uvX = (v.U * 256.0f + 0.5f); // 0.5f for rounding
dst->v = floattof32(v.V); 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 r = PackedCol_R(v.Col);
int g = PackedCol_G(v.Col); int g = PackedCol_G(v.Col);
int b = PackedCol_B(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) { static void PreprocessColouredVertices(void) {
@ -297,17 +365,24 @@ static void PreprocessColouredVertices(void) {
for (int i = 0; i < buf_count; i++, src++, dst++) for (int i = 0; i < buf_count; i++, src++, dst++)
{ {
struct VertexColoured v = *src; struct VertexColoured v = *src;
v16 x = floattov16(v.x / 64.0f); v16 x = floattov16(v.x / 64.0f);
v16 y = floattov16(v.y / 64.0f); v16 y = floattov16(v.y / 64.0f);
v16 z = floattov16(v.z / 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 r = PackedCol_R(v.Col);
int g = PackedCol_G(v.Col); int g = PackedCol_G(v.Col);
int b = PackedCol_B(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) { 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 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) { void Gfx_SetFog(cc_bool enabled) {
fogEnabled = enabled;
SetPolygonMode();
} }
void Gfx_SetFogCol(PackedCol color) { 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) { void Gfx_SetFogDensity(float value) {
fogDensityEnd = value;
RecalculateFog();
} }
void Gfx_SetFogEnd(float value) { void Gfx_SetFogEnd(float value) {
fogDensityEnd = value;
RecalculateFog();
} }
void Gfx_SetFogMode(FogFunc func) { void Gfx_SetFogMode(FogFunc func) {
fogMode = func;
RecalculateFog();
} }
static void SetAlphaTest(cc_bool enabled) { 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); Matrix_Mul(mvp, view, proj);
} }
static struct Matrix texMatrix; static struct Matrix texMatrix = Matrix_IdentityValue;
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);
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) { void Gfx_DisableTextureOffset(void) {
texMatrix.row1.x = 0; texMatrix.row1.y = 0; /*texMatrix.row4.x = 0; texMatrix.row4.y = 0;
Gfx_LoadMatrix(2, &texMatrix); Gfx_LoadMatrix(2, &texMatrix);*/
//glTexParameter(0, TEXGEN_TEXCOORD | GL_TEXTURE_WRAP_S | GL_TEXTURE_WRAP_T);
} }
@ -456,55 +608,39 @@ void Gfx_DisableTextureOffset(void) {
void Gfx_SetVertexFormat(VertexFormat fmt) { void Gfx_SetVertexFormat(VertexFormat fmt) {
gfx_format = fmt; gfx_format = fmt;
gfx_stride = strideSizes[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) { 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) { static void Draw_ColouredTriangles(int verticesCount, int startVertex) {
glBindTexture(0, 0); // Disable texture
GFX_BEGIN = GL_QUADS; GFX_BEGIN = GL_QUADS;
for (int i = 0; i < verticesCount; i++) CallDrawList(&((struct DSColouredVertex*) gfx_vertices)[startVertex], verticesCount * 4);
{
struct DSColouredVertex* v = (struct DSColouredVertex*)gfx_vertices + startVertex + i;
GFX_COLOR = v->rgb;
GFX_VERTEX16 = v->xy;
GFX_VERTEX16 = v->z;
}
GFX_END = 0; GFX_END = 0;
} }
static void Draw_TexturedTriangles(int verticesCount, int startVertex) { static void Draw_TexturedTriangles(int verticesCount, int startVertex) {
GFX_BEGIN = GL_QUADS;
int width = tex_width, height = tex_height; int width = tex_width, height = tex_height;
// Original code used was // Scale uvm to fit into texture size
// U = mulf32(v->u, inttof32(width)) MATRIX_CONTROL = 3;
// which behind the scenes expands to MATRIX_PUSH = 0;
// W = width << 12 glScalef32(width << 4, height << 4, 0);
// U = ((int64)v->u * W) >> 12;
// and in this case, the bit shifts can be cancelled out GFX_BEGIN = GL_QUADS;
// to avoid calling __aeabi_lmul to perform the 64 bit multiplication CallDrawList(&((struct DSTexturedVertex*) gfx_vertices)[startVertex], verticesCount * 5);
// 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;
}
GFX_END = 0; GFX_END = 0;
MATRIX_POP = 1;
MATRIX_CONTROL = matrix_modes[lastMatrix];
} }
void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {