diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Graphics_NDS.c |
initial commit
Diffstat (limited to 'src/Graphics_NDS.c')
-rw-r--r-- | src/Graphics_NDS.c | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/src/Graphics_NDS.c b/src/Graphics_NDS.c new file mode 100644 index 0000000..8e7dcf1 --- /dev/null +++ b/src/Graphics_NDS.c @@ -0,0 +1,517 @@ +#include "Core.h" +#ifdef CC_BUILD_NDS +#include "_GraphicsBase.h" +#include "Errors.h" +#include "Logger.h" +#include "Window.h" +#include <nds.h> + +/*########################################################################################################################* +*---------------------------------------------------------General---------------------------------------------------------* +*#########################################################################################################################*/ +void Gfx_Create(void) { + Gfx_RestoreState(); + + Gfx.MinTexWidth = 8; + Gfx.MinTexHeight = 8; + Gfx.MaxTexWidth = 256; + Gfx.MaxTexHeight = 256; + //Gfx.MaxTexSize = 256 * 256; + Gfx.Created = true; + glInit(); + + glClearColor(0, 15, 10, 31); + glClearPolyID(63); + glAlphaFunc(7); + + glClearDepth(GL_MAX_DEPTH); + glViewport(0, 0, 255, 191); + + vramSetBankA(VRAM_A_TEXTURE); + vramSetBankB(VRAM_B_TEXTURE); + vramSetBankC(VRAM_C_TEXTURE); + vramSetBankD(VRAM_D_TEXTURE); + + glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE); +} + +cc_bool Gfx_TryRestoreContext(void) { + return true; +} + +void Gfx_Free(void) { + Gfx_FreeState(); + vramSetBankA(VRAM_A_LCD); + vramSetBankB(VRAM_B_LCD); + vramSetBankC(VRAM_C_LCD); + vramSetBankD(VRAM_D_LCD); +} + + +/*########################################################################################################################* +*-----------------------------------------------------------Misc----------------------------------------------------------* +*#########################################################################################################################*/ +cc_result Gfx_TakeScreenshot(struct Stream* output) { + return ERR_NOT_SUPPORTED; +} + +void Gfx_GetApiInfo(cc_string* info) { + String_AppendConst(info, "-- Using Nintendo DS --\n"); + PrintMaxTextureInfo(info); +} + +void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { + gfx_minFrameMs = minFrameMs; + gfx_vsync = vsync; +} + +void Gfx_OnWindowResize(void) { +} + +void Gfx_SetViewport(int x, int y, int w, int h) { } + +void Gfx_BeginFrame(void) { +} + +void Gfx_ClearBuffers(GfxBuffers buffers) { + // TODO +} + +void Gfx_ClearColor(PackedCol color) { + int R = PackedCol_R(color) >> 3; + int G = PackedCol_G(color) >> 3; + int B = PackedCol_B(color) >> 3; + glClearColor(R, G, B, 31); +} + +void Gfx_EndFrame(void) { + glFlush(0); + // TODO not needed? + swiWaitForVBlank(); + + if (gfx_minFrameMs) LimitFPS(); +} + + +/*########################################################################################################################* +*---------------------------------------------------------Textures--------------------------------------------------------* +*#########################################################################################################################*/ +// B8 G8 R8 A8 > R5 G5 B5 A1 +#define BGRA8_to_DS(src) \ + ((src[2] & 0xF8) >> 3) | ((src[1] & 0xF8) << 2) | ((src[0] & 0xF8) << 7) | ((src[3] & 0x80) << 8); + +static void ConvertTexture(cc_uint16* dst, struct Bitmap* bmp, int rowWidth) { + for (int y = 0; y < bmp->height; y++) + { + cc_uint8* src = (cc_uint8*)(bmp->scan0 + y * rowWidth); + + for (int x = 0; x < bmp->width; x++, src += 4) + { + *dst++ = BGRA8_to_DS(src); + } + } +} + +static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { + vramSetBankA(VRAM_A_TEXTURE); + + cc_uint16* tmp = Mem_TryAlloc(bmp->width * bmp->height, 2); + if (!tmp) return 0; + ConvertTexture(tmp, bmp, rowWidth); + + 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); + + 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); + return (void*)textureID; +} + +void Gfx_BindTexture(GfxResourceID texId) { + glBindTexture(0, (int)texId); +} + +void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) { + int texture = (int)texId; + glBindTexture(0, texture); + + int width = 0; + glGetInt(GL_GET_TEXTURE_WIDTH, &width); + cc_uint16* vram_ptr = glGetTexturePointer(texture); + 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; + cc_uint8* src = (cc_uint8*)(part->scan0 + rowWidth * yy); + + for (int xx = 0; xx < part->width; xx++, src += 4, dst++) + { + *dst = BGRA8_to_DS(src); + } + } +} + +void Gfx_DeleteTexture(GfxResourceID* texId) { + int texture = (int)(*texId); + if (texture) glDeleteTextures(1, &texture); + *texId = 0; +} + +void Gfx_EnableMipmaps(void) { } +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) { } + +static void Gfx_FreeState(void) { FreeDefaultResources(); } +static void Gfx_RestoreState(void) { + InitDefaultResources(); +} + +cc_bool Gfx_WarnIfNecessary(void) { return true; } + + +/*########################################################################################################################* +*---------------------------------------------------------Matrices--------------------------------------------------------* +*#########################################################################################################################*/ +void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) { + /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho */ + /* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */ + *matrix = Matrix_Identity; + width /= 64.0f; + height /= 64.0f; + + matrix->row1.x = 2.0f / width; + matrix->row2.y = -2.0f / height; + matrix->row3.z = -2.0f / (zFar - zNear); + + matrix->row4.x = -1.0f; + matrix->row4.y = 1.0f; + matrix->row4.z = -(zFar + zNear) / (zFar - zNear); +} + +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } +void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { + float zNear = 0.1f; + float c = Cotangent(0.5f * fov); + + /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ + /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ + /* left = -c * aspect, right = c * aspect, bottom = -c, top = c */ + /* Calculations are simplified because of left/right and top/bottom symmetry */ + *matrix = Matrix_Identity; + + matrix->row1.x = c / aspect; + matrix->row2.y = c; + matrix->row3.z = -(zFar + zNear) / (zFar - zNear); + matrix->row3.w = -1.0f; + matrix->row4.z = -(2.0f * zFar * zNear) / (zFar - zNear); + matrix->row4.w = 0.0f; +} + + +/*########################################################################################################################* +*----------------------------------------------------------Buffers--------------------------------------------------------* +*#########################################################################################################################*/ +// Preprocess vertex buffers into optimised layout for DS +static VertexFormat buf_fmt; +static int buf_count; + +static void* gfx_vertices; + +struct DSTexturedVertex { + vu32 xy; v16 z; + vu32 rgb; + int u, v; +}; +struct DSColouredVertex { + vu32 xy; v16 z; + vu32 rgb; +}; + +// Precalculate all the expensive vertex data conversion, +// so that actual drawing of them is as fast as possible +static void PreprocessTexturedVertices(void) { + struct VertexTextured* src = gfx_vertices; + struct DSTexturedVertex* dst = gfx_vertices; + + 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 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); + } +} + +static void PreprocessColouredVertices(void) { + struct VertexColoured* src = gfx_vertices; + struct DSColouredVertex* dst = gfx_vertices; + + 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); + } +} + +GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) { + return (void*)1; +} + +void Gfx_BindIb(GfxResourceID ib) { } +void Gfx_DeleteIb(GfxResourceID* ib) { } + + +static GfxResourceID Gfx_AllocStaticVb(VertexFormat fmt, int count) { + return Mem_TryAlloc(count, strideSizes[fmt]); +} + +void Gfx_BindVb(GfxResourceID vb) { gfx_vertices = vb; } + +void Gfx_DeleteVb(GfxResourceID* vb) { + GfxResourceID data = *vb; + if (data) Mem_Free(data); + *vb = 0; +} + +void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) { + buf_fmt = fmt; + buf_count = count; + return vb; +} + +void Gfx_UnlockVb(GfxResourceID vb) { + gfx_vertices = vb; + + if (buf_fmt == VERTEX_FORMAT_TEXTURED) { + PreprocessTexturedVertices(); + } else { + PreprocessColouredVertices(); + } +} + + +static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) { + return Mem_TryAlloc(maxVertices, strideSizes[fmt]); +} + +void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); } + +void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) { + return Gfx_LockVb(vb, fmt, count); +} + +void Gfx_UnlockDynamicVb(GfxResourceID vb) { Gfx_UnlockVb(vb); } + +void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); } + + +/*########################################################################################################################* +*-----------------------------------------------------State management----------------------------------------------------* +*#########################################################################################################################*/ +static cc_bool skipRendering; + +void Gfx_SetFog(cc_bool enabled) { +} + +void Gfx_SetFogCol(PackedCol color) { +} + +void Gfx_SetFogDensity(float value) { +} + +void Gfx_SetFogEnd(float value) { +} + +void Gfx_SetFogMode(FogFunc func) { +} + +static void SetAlphaTest(cc_bool enabled) { + if (enabled) { + //glEnable(GL_ALPHA_TEST); + } else { + //glDisable(GL_ALPHA_TEST); + } +} + +void Gfx_DepthOnlyRendering(cc_bool depthOnly) { + skipRendering = depthOnly; +} + + +/*########################################################################################################################* +*---------------------------------------------------------Matrices--------------------------------------------------------* +*#########################################################################################################################*/ +static int matrix_modes[] = { GL_PROJECTION, GL_MODELVIEW, GL_TEXTURE }; +static int lastMatrix; + +void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { + if (type != lastMatrix) { lastMatrix = type; glMatrixMode(matrix_modes[type]); } + + m4x4 m; + const float* src = (const float*)matrix; + + for (int i = 0; i < 4 * 4; i++) + { + m.m[i] = floattof32(src[i]); + } + glLoadMatrix4x4(&m); + + // Vertex commands are signed 16 bit values, with 12 bits fractional + // aka only from -8.0 to 8.0 + // That's way too small to be useful, so counteract that by scaling down + // vertices and then scaling up the matrix multiplication + if (type == MATRIX_VIEW) + glScalef32(floattof32(64.0f), floattof32(64.0f), floattof32(64.0f)); +} + +void Gfx_LoadIdentityMatrix(MatrixType type) { + if (type != lastMatrix) { lastMatrix = type; glMatrixMode(matrix_modes[type]); } + glLoadIdentity(); +} + +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); + +} + +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); +} + + +/*########################################################################################################################* +*--------------------------------------------------------Rendering--------------------------------------------------------* +*#########################################################################################################################*/ +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 Draw_ColouredTriangles(int verticesCount, int startVertex) { + glBegin(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; + } + glEnd(); +} + +static void Draw_TexturedTriangles(int verticesCount, int startVertex) { + glBegin(GL_QUADS); + int width = 0, height = 0; + glGetInt(GL_GET_TEXTURE_WIDTH, &width); + glGetInt(GL_GET_TEXTURE_HEIGHT, &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; + } + glEnd(); +} + +void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + Draw_TexturedTriangles(verticesCount, startVertex); + } else { + Draw_ColouredTriangles(verticesCount, startVertex); + } +} + +void Gfx_DrawVb_IndexedTris(int verticesCount) { + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + Draw_TexturedTriangles(verticesCount, 0); + } else { + Draw_ColouredTriangles(verticesCount, 0); + } +} + +void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { + if (skipRendering) return; + Draw_TexturedTriangles(verticesCount, startVertex); +} +#endif |