Path: blob/main/RSDKv4/Renderer.cpp
817 views
#include "RetroEngine.hpp"12#define STB_IMAGE_IMPLEMENTATION3#include "stb_image.h"45float retroVertexList[40];6float screenBufferVertexList[40];78int vertexListSize = 0;9DrawVertex drawVertexList[DRAWVERTEX_COUNT];10ushort drawIndexList[DRAWINDEX_COUNT];1112byte vertexR = 0xFF;13byte vertexG = 0xFF;14byte vertexB = 0xFF;1516TextureInfo textureList[TEXTURE_COUNT];17MeshInfo meshList[MESH_COUNT];1819int renderStateCount = 0;20RenderState renderStateList[RENDERSTATE_COUNT];21RenderState currentRenderState;2223void SetIdentityMatrixF(MatrixF *matrix)24{25matrix->values[0][0] = 1.0f;26matrix->values[0][1] = 0.0f;27matrix->values[0][2] = 0.0f;28matrix->values[0][3] = 0.0f;29matrix->values[1][0] = 0.0f;30matrix->values[1][1] = 1.0f;31matrix->values[1][2] = 0.0f;32matrix->values[1][3] = 0.0f;33matrix->values[2][0] = 0.0f;34matrix->values[2][1] = 0.0f;35matrix->values[2][2] = 1.0f;36matrix->values[2][3] = 0.0f;37matrix->values[3][0] = 0.0f;38matrix->values[3][1] = 0.0f;39matrix->values[3][2] = 0.0f;40matrix->values[3][3] = 1.0f;41}42void MatrixMultiplyF(MatrixF *matrixA, MatrixF *matrixB)43{44float output[16];4546for (int i = 0; i < 0x10; ++i) {47uint rowA = i / 4;48uint rowB = i % 4;49output[i] = (matrixA->values[rowA][3] * matrixB->values[3][rowB]) + (matrixA->values[rowA][2] * matrixB->values[2][rowB])50+ (matrixA->values[rowA][1] * matrixB->values[1][rowB]) + (matrixA->values[rowA][0] * matrixB->values[0][rowB]);51}5253for (int i = 0; i < 0x10; ++i) matrixA->values[i / 4][i % 4] = output[i];54}55void MatrixTranslateXYZF(MatrixF *matrix, float x, float y, float z)56{57matrix->values[0][0] = 1.0f;58matrix->values[0][1] = 0.0f;59matrix->values[0][2] = 0.0f;60matrix->values[0][3] = 0.0f;61matrix->values[1][0] = 0.0f;62matrix->values[1][1] = 1.0f;63matrix->values[1][2] = 0.0f;64matrix->values[1][3] = 0.0f;65matrix->values[2][0] = 0.0f;66matrix->values[2][1] = 0.0f;67matrix->values[2][2] = 1.0f;68matrix->values[2][3] = 0.0f;69matrix->values[3][0] = x;70matrix->values[3][1] = y;71matrix->values[3][2] = z;72matrix->values[3][3] = 1.0f;73}74void MatrixScaleXYZF(MatrixF *matrix, float scaleX, float scaleY, float scaleZ)75{76matrix->values[0][0] = scaleX;77matrix->values[0][1] = 0.0f;78matrix->values[0][2] = 0.0f;79matrix->values[0][3] = 0.0f;80matrix->values[1][0] = 0.0f;81matrix->values[1][1] = scaleY;82matrix->values[1][2] = 0.0f;83matrix->values[1][3] = 0.0f;84matrix->values[2][0] = 0.0f;85matrix->values[2][1] = 0.0f;86matrix->values[2][2] = scaleZ;87matrix->values[2][3] = 0.0f;88matrix->values[3][0] = 0.0f;89matrix->values[3][1] = 0.0f;90matrix->values[3][2] = 0.0f;91matrix->values[3][3] = 1.0f;92}93void MatrixRotateXF(MatrixF *matrix, float angle)94{95float sine = sinf(angle);96float cosine = cosf(angle);97matrix->values[0][0] = 1.0f;98matrix->values[0][1] = 0.0f;99matrix->values[0][2] = 0.0f;100matrix->values[0][3] = 0.0f;101matrix->values[1][0] = 0.0f;102matrix->values[1][1] = cosine;103matrix->values[1][2] = sine;104matrix->values[1][3] = 0.0f;105matrix->values[2][0] = 0.0f;106matrix->values[2][1] = -sine;107matrix->values[2][2] = cosine;108matrix->values[2][3] = 0.0f;109matrix->values[3][0] = 0.0f;110matrix->values[3][1] = 0.0f;111matrix->values[3][2] = 0.0f;112matrix->values[3][3] = 1.0f;113}114void MatrixRotateYF(MatrixF *matrix, float angle)115{116float sine = sinf(angle);117float cosine = cosf(angle);118matrix->values[0][0] = cosine;119matrix->values[0][1] = 0.0f;120matrix->values[0][2] = sine;121matrix->values[0][3] = 0.0f;122matrix->values[1][0] = 0.0f;123matrix->values[1][1] = 1.0f;124matrix->values[1][2] = 0.0f;125matrix->values[1][3] = 0.0f;126matrix->values[2][0] = -sine;127matrix->values[2][1] = 0.0f;128matrix->values[2][2] = cosine;129matrix->values[2][3] = 0.0f;130matrix->values[3][0] = 0.0f;131matrix->values[3][1] = 0.0f;132matrix->values[3][2] = 0.0f;133matrix->values[3][3] = 1.0f;134}135void MatrixRotateZF(MatrixF *matrix, float angle)136{137float sine = sinf(angle);138float cosine = cosf(angle);139140matrix->values[0][0] = cosine;141matrix->values[0][1] = -sine;142matrix->values[0][2] = 0.0;143matrix->values[0][3] = 0.0;144matrix->values[1][0] = sine;145matrix->values[1][1] = cosine;146matrix->values[1][2] = 0;147matrix->values[1][3] = 0;148matrix->values[2][0] = 0.0;149matrix->values[2][1] = 0.0;150matrix->values[2][2] = 1.0;151matrix->values[2][3] = 0.0;152matrix->values[3][0] = 0.0;153matrix->values[3][1] = 0.0;154matrix->values[3][3] = 1.0;155matrix->values[3][2] = 0.0;156}157void MatrixRotateXYZF(MatrixF *matrix, float angleX, float angleY, float angleZ)158{159float sinX = sinf(angleX);160float cosX = cosf(angleX);161float sinY = sinf(angleY);162float cosY = cosf(angleY);163float sinZ = sinf(angleZ);164float cosZ = cosf(angleZ);165166matrix->values[0][0] = (cosZ * cosY) + (sinZ * (sinY * sinX));167matrix->values[0][1] = (sinZ * cosY) - (cosZ * (sinY * sinX));168matrix->values[0][2] = sinY * cosX;169matrix->values[0][3] = 0.0f;170matrix->values[1][0] = sinZ * -cosX;171matrix->values[1][1] = cosZ * cosX;172matrix->values[1][2] = sinX;173matrix->values[1][3] = 0.0f;174matrix->values[2][0] = (sinZ * (cosY * sinX)) - (cosZ * sinY);175matrix->values[2][1] = (sinZ * -sinY) - (cosZ * (cosY * sinX));176matrix->values[2][2] = cosY * cosX;177matrix->values[2][3] = 0.0f;178matrix->values[3][0] = 0.0f;179matrix->values[3][1] = 0.0f;180matrix->values[3][2] = 0.0f;181matrix->values[3][3] = 1.0f;182}183184void MatrixInvertF(MatrixF *dstMatrix, MatrixF *matrix)185{186double inv[16], det;187double m[16];188for (int y = 0; y < 4; ++y) {189for (int x = 0; x < 4; ++x) {190m[(y << 2) + x] = matrix->values[y][x];191}192}193194inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];195196inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];197198inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];199200inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];201202inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];203204inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];205206inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];207208inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];209210inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];211212inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];213214inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];215216inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];217218inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];219220inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];221222inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];223224inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];225226det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];227228if (det == 0)229return;230231det = 1.0 / det;232233for (int i = 0; i < 0x10; ++i) dstMatrix->values[i / 4][i % 4] = inv[i] * det;234}235236// Render States237void ResetRenderStates()238{239currentRenderState.renderMatrix = NULL;240currentRenderState.vertPtr = drawVertexList;241currentRenderState.indexCount = 0;242currentRenderState.id = 0;243currentRenderState.blendMode = 0;244currentRenderState.useColors = false;245currentRenderState.useTexture = false;246currentRenderState.depthTest = false;247currentRenderState.useNormals = false;248currentRenderState.useFilter = false;249currentRenderState.indexPtr = drawIndexList;250renderStateCount = -1;251vertexListSize = 0;252vertexR = 0xFF;253vertexG = 0xFF;254vertexB = 0xFF;255}256void SetRenderBlendMode(byte mode)257{258if (currentRenderState.blendMode != mode && currentRenderState.indexCount) {259RenderState *state = &renderStateList[renderStateCount++];260memcpy(state, ¤tRenderState, sizeof(RenderState));261262currentRenderState.indexCount = 0;263currentRenderState.id = 0;264currentRenderState.vertPtr = &drawVertexList[vertexListSize];265}266currentRenderState.blendMode = mode;267}268void SetRenderVertexColor(byte r, byte g, byte b)269{270vertexR = r;271vertexG = g;272vertexB = b;273}274275#undef near276#undef far277void SetPerspectiveMatrix(float w, float h, float near, float far)278{279float m[19];280281float val = tanf((float)(0.017453292f * w) * 0.5f);282m[11] = 1.0;283m[0] = 1.0 / val;284m[1] = 0.0;285m[2] = 0.0;286m[3] = 0.0;287m[4] = 0.0;288m[6] = 0.0;289m[7] = 0.0;290m[8] = 0.0;291m[9] = 0.0;292m[12] = 0.0;293m[13] = 0.0;294m[15] = 0.0;295m[5] = 1.0 / (val * h);296m[10] = (far + near) / (far - near);297m[14] = -((far + far) * near) / (far - near);298#if RETRO_USING_OPENGL299glMultMatrixf(m);300#endif301}302void SetupDrawIndexList()303{304int index = 0;305for (int i = 0; i < DRAWINDEX_COUNT;) {306drawIndexList[i + 2] = index + 0;307drawIndexList[i + 1] = index + 1;308drawIndexList[i + 0] = index + 2;309drawIndexList[i + 5] = index + 1;310drawIndexList[i + 4] = index + 3;311drawIndexList[i + 3] = index + 2;312index += 4;313i += 6;314}315}316void SetRenderMatrix(MatrixF *matrix) { currentRenderState.renderMatrix = matrix; }317void NewRenderState()318{319if (renderStateCount < RENDERSTATE_COUNT) {320if (currentRenderState.indexCount) {321RenderState *state = &renderStateList[renderStateCount];322memcpy(state, ¤tRenderState, sizeof(RenderState));323324currentRenderState.id = 0;325currentRenderState.indexCount = 0;326currentRenderState.vertPtr = &drawVertexList[vertexListSize];327currentRenderState.indexPtr = drawIndexList;328renderStateCount++;329}330}331}332void RenderScene()333{334#if RETRO_USING_OPENGL335glDisable(GL_TEXTURE_2D);336glDisable(GL_DEPTH_TEST);337glDisable(GL_LIGHTING);338glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);339glDisable(GL_BLEND);340glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);341#endif342if (renderStateCount == -1)343return;344345#if !RETRO_USE_ORIGINAL_CODE346float dimAmount = 1.0;347if ((!Engine.masterPaused || Engine.frameStep) && !drawStageGFXHQ) {348if (Engine.dimTimer < Engine.dimLimit) {349if (Engine.dimPercent < 1.0) {350Engine.dimPercent += 0.05;351if (Engine.dimPercent > 1.0)352Engine.dimPercent = 1.0;353}354}355else if (Engine.dimPercent > 0.25 && Engine.dimLimit >= 0) {356Engine.dimPercent *= 0.9;357}358359dimAmount = Engine.dimMax * Engine.dimPercent;360}361362if (dimAmount < 1.0) {363SetRenderBlendMode(RENDER_BLEND_ALPHA);364RenderRect(-SCREEN_CENTERX_F, SCREEN_CENTERY_F, 160.0, SCREEN_XSIZE_F, SCREEN_YSIZE_F, 0, 0, 0, 0xFF - (dimAmount * 0xFF));365SetRenderBlendMode(RENDER_BLEND_NONE);366}367#endif368369#if RETRO_USING_OPENGL370glEnableClientState(GL_VERTEX_ARRAY);371glLoadIdentity();372#endif373if (currentRenderState.indexCount) {374RenderState *state = &renderStateList[renderStateCount];375memcpy(state, ¤tRenderState, sizeof(RenderState));376377currentRenderState.indexCount = 0;378currentRenderState.id = 0;379currentRenderState.vertPtr = &drawVertexList[vertexListSize];380renderStateCount++;381}382383MatrixF *prevMat = NULL;384bool prevTextures = false;385uint prevTexID = 0;386bool prevColors = false;387bool prevNormals = false;388bool prevDepth = false;389byte prevBlendMode = 0;390391for (int i = 0; i < renderStateCount; ++i) {392RenderState *state = &renderStateList[i];393394if (state->renderMatrix != prevMat) {395if (state->renderMatrix) {396#if RETRO_USING_OPENGL397glLoadMatrixf((const GLfloat *)state->renderMatrix);398#endif399prevMat = state->renderMatrix;400}401else {402#if RETRO_USING_OPENGL403glLoadIdentity();404#endif405prevMat = NULL;406}407}408409#if RETRO_USING_OPENGL410glVertexPointer(3, GL_FLOAT, sizeof(DrawVertex), &state->vertPtr->vertX);411#endif412if (state->useTexture) {413if (!prevTextures) {414#if RETRO_USING_OPENGL415glEnable(GL_TEXTURE_2D);416glEnableClientState(GL_TEXTURE_COORD_ARRAY);417#endif418}419#if RETRO_USING_OPENGL420glTexCoordPointer(2, GL_FLOAT, sizeof(DrawVertex), &state->vertPtr->texCoordX);421#endif422prevTextures = true;423if (state->id != prevTexID) {424#if RETRO_USING_OPENGL425glBindTexture(GL_TEXTURE_2D, state->id);426#endif427prevTexID = state->id;428}429}430else {431if (prevTextures) {432#if RETRO_USING_OPENGL433glDisable(GL_TEXTURE_2D);434glDisableClientState(GL_TEXTURE_COORD_ARRAY);435#endif436}437prevTextures = false;438}439440if (state->useColors) {441#if RETRO_USING_OPENGL442if (!prevColors)443glEnableClientState(GL_COLOR_ARRAY);444glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(DrawVertex), &state->vertPtr->r);445#endif446prevColors = true;447}448else {449#if RETRO_USING_OPENGL450if (prevColors)451glDisableClientState(GL_COLOR_ARRAY);452#endif453prevColors = false;454}455456if (state->useNormals) {457if (!prevNormals) {458#if RETRO_USING_OPENGL459glEnableClientState(GL_NORMAL_ARRAY);460glEnable(GL_LIGHTING);461#endif462}463#if RETRO_USING_OPENGL464glNormalPointer(GL_FLOAT, sizeof(DrawVertex), &state->vertPtr->normalX);465#endif466prevNormals = true;467}468else {469if (prevNormals) {470#if RETRO_USING_OPENGL471glDisableClientState(GL_NORMAL_ARRAY);472glDisable(GL_LIGHTING);473#endif474}475prevNormals = false;476}477478if (state->depthTest) {479#if RETRO_USING_OPENGL480if (!prevDepth)481glEnable(GL_DEPTH_TEST);482#endif483prevDepth = true;484}485else {486#if RETRO_USING_OPENGL487if (prevDepth)488glDisable(GL_DEPTH_TEST);489#endif490prevDepth = false;491}492493if (state->blendMode != prevBlendMode) {494switch (state->blendMode) {495default: prevBlendMode = state->blendMode; break;496case 0:497#if RETRO_USING_OPENGL498glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);499glDisable(GL_BLEND);500#endif501prevBlendMode = 0;502break;503case 1:504#if RETRO_USING_OPENGL505glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);506glEnable(GL_BLEND);507#endif508prevBlendMode = 1;509break;510case 2:511#if RETRO_USING_OPENGL512glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);513glEnable(GL_BLEND);514#endif515prevBlendMode = 2;516break;517case 3:518#if RETRO_USING_OPENGL519glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);520glEnable(GL_BLEND);521#endif522prevBlendMode = 3;523break;524}525}526527if (state->useFilter && mixFiltersOnJekyll) {528#if RETRO_USING_OPENGL529glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFramebuffer);530glBindFramebuffer(GL_FRAMEBUFFER, framebufferHiRes);531glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);532glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);533glVertexPointer(3, GL_FLOAT, sizeof(DrawVertex), screenBufferVertexList);534glTexCoordPointer(2, GL_FLOAT, sizeof(DrawVertex), &screenBufferVertexList[6]);535glViewport(0, 0, GFX_LINESIZE_DOUBLE, SCREEN_YSIZE * 2);536glPushMatrix();537glLoadIdentity();538glMatrixMode(GL_PROJECTION);539glPushMatrix();540glLoadIdentity();541glDrawElements(GL_TRIANGLES, state->indexCount, GL_UNSIGNED_SHORT, state->indexPtr);542543glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);544glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);545glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);546glBindTexture(GL_TEXTURE_2D, renderbufferHiRes);547glVertexPointer(3, GL_FLOAT, sizeof(DrawVertex), state->vertPtr);548glTexCoordPointer(2, GL_FLOAT, sizeof(DrawVertex), &state->vertPtr->texCoordX);549glViewport(displaySettings.offsetX, 0, displaySettings.width, displaySettings.height);550glPopMatrix();551glMatrixMode(GL_MODELVIEW);552glPopMatrix();553#endif554}555556#if RETRO_USING_OPENGL557glDrawElements(GL_TRIANGLES, state->indexCount, GL_UNSIGNED_SHORT, state->indexPtr);558#endif559}560561#if RETRO_USING_OPENGL562glDisableClientState(GL_VERTEX_ARRAY);563if (prevTextures)564glDisableClientState(GL_TEXTURE_COORD_ARRAY);565if (prevColors)566glDisableClientState(GL_COLOR_ARRAY);567#endif568}569570int stb_read_cb(void *user, char *data, int size)571{572FileRead(data, size);573return size;574}575void stb_skip_cb(void *user, int n) { FileSkip(n); }576int stb_eof_cb(void *user) { return ReachedEndOfFile(); }577578// Textures579int LoadTexture(const char *filePath, int format)580{581int texID = 0;582for (int i = 0; i < TEXTURE_COUNT; ++i) {583if (StrComp(textureList[texID].fileName, filePath))584return texID;585if (!StrLength(textureList[texID].fileName))586break;587texID++;588}589if (texID == TEXTURE_COUNT)590return 0;591592FileInfo info;593if (LoadFile(filePath, &info)) {594595stbi_io_callbacks callbacks;596callbacks.read = stb_read_cb;597callbacks.skip = stb_skip_cb;598callbacks.eof = stb_eof_cb;599600int width = 0;601int height = 0;602int channels = 0;603stbi_uc *data = stbi_load_from_callbacks(&callbacks, NULL, &width, &height, &channels, 4);604605if (width > 0 && height > 0) {606TextureInfo *texture = &textureList[texID];607texture->width = width;608texture->height = height;609texture->format = format;610StrCopy(texture->fileName, filePath);611612float normalize = 0;613if (FindStringToken(fileName, "@2", 1) > 0)614normalize = 2.0;615else if (FindStringToken(fileName, "@1", 1) > 0)616normalize = 0.5;617else618normalize = 1.0;619texture->widthN = normalize / width;620texture->heightN = normalize / height;621622#if RETRO_USING_OPENGL623glGenTextures(1, &texture->id);624glBindTexture(GL_TEXTURE_2D, texture->id);625#endif626627int id = 0;628switch (format) {629default: break;630case TEXFMT_RGBA4444: {631ushort *pixels = (ushort *)malloc(width * height * sizeof(ushort));632633for (int y = 0; y < height; ++y) {634for (int x = 0; x < width; ++x) {635int r = (data[id++] >> 4) << 12;636int g = (data[id++] >> 4) << 8;637int b = (data[id++]) & 0xF0;638int a = (data[id++] >> 4);639pixels[x + (y * width)] = a | r | g | b;640}641}642643#if RETRO_USING_OPENGL644glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);645glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);646glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);647glBindTexture(GL_TEXTURE_2D, 0);648#endif649650free(pixels);651break;652}653case TEXFMT_RGBA5551: {654ushort *pixels = (ushort *)malloc(width * height * sizeof(ushort));655656for (int y = 0; y < height; ++y) {657for (int x = 0; x < width; ++x) {658int r = data[id++];659int g = data[id++];660int b = data[id++];661int a = data[id++];662pixels[x + (y * width)] = RGB888_TO_RGB5551(r, g, b) | (a ? 1 : 0);663}664}665666#if RETRO_USING_OPENGL667glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);668glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);669glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);670glBindTexture(GL_TEXTURE_2D, 0);671#endif672673free(pixels);674break;675}676case TEXFMT_RGBA8888: {677uint *pixels = (uint *)malloc(width * height * sizeof(uint));678679for (int y = 0; y < height; ++y) {680for (int x = 0; x < width; ++x) {681int r = data[id++];682int g = data[id++];683int b = data[id++];684int a = data[id++];685pixels[x + (y * width)] = (a << 24) | (b << 16) | (g << 8) | (r << 0);686}687}688689#if RETRO_USING_OPENGL690glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);691glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);692glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);693glBindTexture(GL_TEXTURE_2D, 0);694#endif695696free(pixels);697break;698}699}700}701702CloseFile();703stbi_image_free(data);704705return texID;706}707return 0;708}709void ReplaceTexture(const char *filePath, int texID)710{711FileInfo info;712if (LoadFile(filePath, &info)) {713714stbi_io_callbacks callbacks;715callbacks.read = stb_read_cb;716callbacks.skip = stb_skip_cb;717callbacks.eof = stb_eof_cb;718719int width = 0;720int height = 0;721int channels = 0;722stbi_uc *data = stbi_load_from_callbacks(&callbacks, NULL, &width, &height, &channels, 4);723724if (width > 0 && height > 0) {725TextureInfo *texture = &textureList[texID];726StrCopy(texture->fileName, filePath);727728float normalize = 0;729if (FindStringToken(fileName, "@2", 1) > 0)730normalize = 2.0;731else if (FindStringToken(fileName, "@1", 1) > 0)732normalize = 0.5;733else734normalize = 1.0;735texture->widthN = normalize / width;736texture->heightN = normalize / height;737738#if RETRO_USING_OPENGL739glBindTexture(GL_TEXTURE_2D, texture->id);740#endif741742int id = 0;743switch (texture->format) {744default: break;745case TEXFMT_RGBA4444: {746ushort *pixels = (ushort *)malloc(width * height * sizeof(ushort));747748for (int y = 0; y < height; ++y) {749for (int x = 0; x < width; ++x) {750int r = (data[id++] >> 4) << 12;751int g = (data[id++] >> 4) << 8;752int b = (data[id++]) & 0xF0;753int a = (data[id++] >> 4);754pixels[x + (y * width)] = a | r | g | b;755}756}757758#if RETRO_USING_OPENGL759glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);760glBindTexture(GL_TEXTURE_2D, 0);761#endif762763free(pixels);764break;765}766case TEXFMT_RGBA5551: {767ushort *pixels = (ushort *)malloc(width * height * sizeof(ushort));768769for (int y = 0; y < height; ++y) {770for (int x = 0; x < width; ++x) {771int r = data[id++];772int g = data[id++];773int b = data[id++];774int a = data[id++];775pixels[x + (y * width)] = RGB888_TO_RGB5551(r, g, b) | (a ? 1 : 0);776}777}778#if RETRO_USING_OPENGL779glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);780glBindTexture(GL_TEXTURE_2D, 0);781#endif782783free(pixels);784break;785}786case TEXFMT_RGBA8888: {787uint *pixels = (uint *)malloc(width * height * sizeof(uint));788789for (int y = 0; y < height; ++y) {790for (int x = 0; x < width; ++x) {791int r = data[id++];792int g = data[id++];793int b = data[id++];794int a = data[id++];795pixels[x + (y * width)] = (a << 24) | (b << 16) | (g << 8) | (r << 0);796}797}798799#if RETRO_USING_OPENGL800glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);801glBindTexture(GL_TEXTURE_2D, 0);802#endif803804free(pixels);805break;806}807}808}809810CloseFile();811stbi_image_free(data);812}813}814void ClearTextures(bool keepBuffer)815{816for (int i = (keepBuffer ? 1 : 0); i < TEXTURE_COUNT; ++i) {817#if RETRO_USING_OPENGL818glDeleteTextures(1, &textureList[i].id);819#endif820StrCopy(textureList[i].fileName, "");821}822}823824// Meshes825MeshInfo *LoadMesh(const char *filePath, byte textureID)826{827int meshID = 0;828for (int i = 0; i < MESH_COUNT; ++i) {829if (StrComp(meshList[meshID].fileName, filePath) && meshList[meshID].textureID == textureID)830return &meshList[meshID];831if (!StrLength(meshList[meshID].fileName))832break;833meshID++;834}835if (meshID == MESH_COUNT)836return 0;837838FileInfo info;839if (LoadFile(filePath, &info)) {840byte buffer[4];841FileRead(buffer, 4 * sizeof(byte));842if (buffer[0] == 'R' && buffer[1] == '3' && buffer[2] == 'D' && buffer[3] == '\0') {843MeshInfo *mesh = &meshList[meshID];844845StrCopy(mesh->fileName, filePath);846mesh->textureID = textureID;847848FileRead(buffer, sizeof(ushort));849mesh->vertexCount = buffer[0] + (buffer[1] << 8);850mesh->vertices = (DrawVertex *)malloc(sizeof(DrawVertex) * mesh->vertexCount);851852for (int v = 0; v < mesh->vertexCount; ++v) {853float buf = 0;854FileRead(&buf, sizeof(float));855mesh->vertices[v].texCoordX = buf;856857FileRead(&buf, sizeof(float));858mesh->vertices[v].texCoordY = buf;859860mesh->vertices[v].r = 0xFF;861mesh->vertices[v].g = 0xFF;862mesh->vertices[v].b = 0xFF;863mesh->vertices[v].a = 0xFF;864}865866FileRead(buffer, sizeof(ushort));867mesh->indexCount = buffer[0] + (buffer[1] << 8);868mesh->indices = (ushort *)malloc(sizeof(ushort) * (3 * mesh->indexCount));869870int id = 0;871for (int i = 0; i < mesh->indexCount; ++i) {872FileRead(buffer, sizeof(ushort));873mesh->indices[id + 2] = buffer[0] + (buffer[1] << 8);874875FileRead(buffer, sizeof(ushort));876mesh->indices[id + 1] = buffer[0] + (buffer[1] << 8);877878FileRead(buffer, sizeof(ushort));879mesh->indices[id + 0] = buffer[0] + (buffer[1] << 8);880881id += 3;882}883884FileRead(buffer, sizeof(ushort));885mesh->frameCount = buffer[0] + (buffer[1] << 8);886887if (mesh->frameCount <= 1) {888for (int v = 0; v < mesh->vertexCount; ++v) {889float buf = 0;890FileRead(&buf, sizeof(float));891mesh->vertices[v].vertX = buf;892893FileRead(&buf, sizeof(float));894mesh->vertices[v].vertY = buf;895896FileRead(&buf, sizeof(float));897mesh->vertices[v].vertZ = buf;898899FileRead(&buf, sizeof(float));900mesh->vertices[v].normalX = buf;901902FileRead(&buf, sizeof(float));903mesh->vertices[v].normalY = buf;904905FileRead(&buf, sizeof(float));906mesh->vertices[v].normalZ = buf;907}908}909else {910mesh->frames = (MeshVertex *)malloc(mesh->frameCount * mesh->vertexCount * sizeof(MeshVertex));911for (int f = 0; f < mesh->frameCount; ++f) {912int frameOff = (f * mesh->vertexCount);913for (int v = 0; v < mesh->vertexCount; ++v) {914float buf = 0;915FileRead(&buf, sizeof(float));916mesh->frames[frameOff + v].vertX = buf;917918FileRead(&buf, sizeof(float));919mesh->frames[frameOff + v].vertY = buf;920921FileRead(&buf, sizeof(float));922mesh->frames[frameOff + v].vertZ = buf;923924FileRead(&buf, sizeof(float));925mesh->frames[frameOff + v].normalX = buf;926927FileRead(&buf, sizeof(float));928mesh->frames[frameOff + v].normalY = buf;929930FileRead(&buf, sizeof(float));931mesh->frames[frameOff + v].normalZ = buf;932}933}934}935CloseFile();936937return mesh;938}939else {940CloseFile();941}942}943return NULL;944}945void ClearMeshData()946{947for (int i = 0; i < MESH_COUNT; ++i) {948MeshInfo *mesh = &meshList[i];949if (StrLength(mesh->fileName)) {950if (mesh->frameCount > 1)951free(mesh->frames);952if (mesh->indexCount)953free(mesh->indices);954if (mesh->vertexCount)955free(mesh->vertices);956957mesh->frameCount = 0;958mesh->indexCount = 0;959mesh->vertexCount = 0;960961StrCopy(meshList[i].fileName, "");962}963}964}965void SetMeshAnimation(MeshInfo *mesh, MeshAnimator *animator, ushort frameID, ushort frameCount, float speed)966{967animator->frameCount = frameCount;968if (frameCount >= mesh->frameCount)969animator->frameCount = mesh->frameCount - 1;970if (frameID < mesh->frameCount) {971animator->loopIndex = frameID;972animator->frameID = frameID;973}974else {975animator->loopIndex = 0;976animator->frameID = 0;977}978animator->animationSpeed = speed;979}980void AnimateMesh(MeshInfo *mesh, MeshAnimator *animator)981{982if (mesh->frameCount > 1) {983if (!animator->animationFinished) {984animator->animationTimer += animator->animationSpeed;985986while (animator->animationTimer > 1.0f) { // new frame (forwards)987animator->animationTimer -= 1.0f;988animator->frameID++;989990if (animator->loopAnimation) {991if (animator->frameID >= animator->frameCount)992animator->frameID = animator->loopIndex;993}994else if (animator->frameID >= animator->frameCount) {995animator->frameID = animator->frameCount;996animator->animationFinished = true;997animator->animationTimer = 0.0f;998}999}1000while (animator->animationTimer < 0.0f) { // new frame (backwards)1001animator->animationTimer += 1.0f;1002animator->frameID--;10031004if (animator->frameID < animator->loopIndex || animator->frameID >= animator->frameCount) {1005if (animator->loopAnimation) {1006animator->frameID = animator->frameCount;1007}1008else {1009animator->frameID = animator->loopIndex;1010animator->animationTimer = 0.0f;1011animator->animationFinished = true;1012}1013}1014}10151016ushort frameID = animator->frameID;1017ushort nextFrame = animator->frameID + 1;1018if (nextFrame >= animator->frameCount && animator->animationSpeed >= 0)1019nextFrame = animator->loopIndex;1020if (frameID >= animator->frameCount && animator->animationSpeed < 0)1021frameID = animator->loopIndex;10221023float interp2 = animator->animationTimer;1024float interp = 1.0 - animator->animationTimer;10251026MeshVertex *vert = &mesh->frames[frameID * mesh->vertexCount];1027MeshVertex *nextVert = &mesh->frames[nextFrame * mesh->vertexCount];1028for (int v = 0; v < mesh->vertexCount; ++v) {1029mesh->vertices[v].vertX = (vert->vertX * interp) + (nextVert->vertX * interp2);1030mesh->vertices[v].vertY = (vert->vertY * interp) + (nextVert->vertY * interp2);1031mesh->vertices[v].vertZ = (vert->vertZ * interp) + (nextVert->vertZ * interp2);1032mesh->vertices[v].normalX = (vert->normalX * interp) + (nextVert->normalX * interp2);1033mesh->vertices[v].normalY = (vert->normalY * interp) + (nextVert->normalY * interp2);1034mesh->vertices[v].normalZ = (vert->normalZ * interp) + (nextVert->normalZ * interp2);10351036vert++;1037nextVert++;1038}1039}1040else if (animator->loopAnimation)1041animator->animationFinished = false;1042}1043}10441045void SetMeshVertexColors(MeshInfo *mesh, byte r, byte g, byte b, byte a)1046{1047for (int v = 0; v < mesh->vertexCount; ++v) {1048mesh->vertices[v].r = r;1049mesh->vertices[v].g = g;1050mesh->vertices[v].b = b;1051mesh->vertices[v].a = a;1052}1053}10541055// Rendering1056void TransferRetroBuffer()1057{1058#if RETRO_USING_OPENGL1059glBindTexture(GL_TEXTURE_2D, textureList[0].id);1060if (convertTo32Bit) {1061ushort *frameBufferPtr = Engine.frameBuffer;1062uint *texBufferPtr = Engine.texBuffer;1063for (int y = 0; y < SCREEN_YSIZE; ++y) {1064for (int x = 0; x < GFX_LINESIZE; ++x) {1065texBufferPtr[x] = gfxPalette16to32[frameBufferPtr[x]];1066}1067texBufferPtr += GFX_LINESIZE;1068frameBufferPtr += GFX_LINESIZE;1069}10701071glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX_LINESIZE, SCREEN_YSIZE, GL_RGBA, GL_UNSIGNED_BYTE, Engine.texBuffer);1072}1073else {1074glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX_LINESIZE, SCREEN_YSIZE, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, Engine.frameBuffer);1075}1076glBindTexture(GL_TEXTURE_2D, 0);1077#endif1078}1079void RenderRetroBuffer(int alpha, float z)1080{1081if (vertexListSize < DRAWVERTEX_COUNT && textureList[0].format) {1082if (renderStateCount < 0 || currentRenderState.id != textureList[0].id) {1083if (renderStateCount >= 0) {1084RenderState *state = &renderStateList[renderStateCount];1085memcpy(state, ¤tRenderState, sizeof(RenderState));1086}1087currentRenderState.indexCount = 0;1088currentRenderState.id = textureList[0].id;1089currentRenderState.useColors = true;1090currentRenderState.useTexture = true;1091currentRenderState.useFilter = true;1092currentRenderState.vertPtr = &drawVertexList[vertexListSize];1093currentRenderState.indexPtr = drawIndexList;1094renderStateCount++;1095}10961097if (renderStateCount < RENDERSTATE_COUNT) {1098int a = 0;1099if (alpha >= 0)1100a = alpha;1101if (a > 0xFF)1102a = 0xFF;11031104DrawVertex *vertex1 = &drawVertexList[vertexListSize];1105vertex1->vertX = retroVertexList[0];1106vertex1->vertY = retroVertexList[1];1107vertex1->vertZ = z;1108vertex1->texCoordX = retroVertexList[6];1109vertex1->texCoordY = retroVertexList[7];1110vertex1->r = vertexR;1111vertex1->g = vertexG;1112vertex1->b = vertexB;1113vertex1->a = a;11141115DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1116vertex2->vertX = retroVertexList[9];1117vertex2->vertY = retroVertexList[10];1118vertex2->vertZ = z;1119vertex2->texCoordX = retroVertexList[15];1120vertex2->texCoordY = retroVertexList[16];1121vertex2->r = vertexR;1122vertex2->g = vertexG;1123vertex2->b = vertexB;1124vertex2->a = a;11251126DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1127vertex3->vertX = retroVertexList[18];1128vertex3->vertY = retroVertexList[19];1129vertex3->vertZ = z;1130vertex3->texCoordX = retroVertexList[24];1131vertex3->texCoordY = retroVertexList[25];1132vertex3->r = vertexR;1133vertex3->b = vertexB;1134vertex3->g = vertexG;1135vertex3->a = a;11361137DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1138vertex4->vertX = retroVertexList[27];1139vertex4->vertY = retroVertexList[28];1140vertex4->vertZ = z;1141vertex4->texCoordX = retroVertexList[33];1142vertex4->texCoordY = retroVertexList[34];1143vertex4->r = vertexR;1144vertex4->g = vertexG;1145vertex4->b = vertexB;1146vertex4->a = a;11471148currentRenderState.indexCount += 6;1149vertexListSize += 4;1150}1151}1152}11531154void RenderImage(float x, float y, float z, float scaleX, float scaleY, float pivotX, float pivotY, float sprW, float sprH, float sprX, float sprY,1155int alpha, byte texture)1156{1157if (vertexListSize < DRAWVERTEX_COUNT && textureList[texture].format) {1158if (renderStateCount < 0) {1159currentRenderState.indexCount = 0;1160currentRenderState.id = textureList[texture].id;1161currentRenderState.useColors = true;1162currentRenderState.useTexture = true;1163currentRenderState.useFilter = false;1164currentRenderState.vertPtr = &drawVertexList[vertexListSize];1165currentRenderState.indexPtr = drawIndexList;1166renderStateCount++;1167}1168else {1169bool flag = false;1170if (currentRenderState.useTexture)1171flag = currentRenderState.id == textureList[texture].id;11721173if (!flag) {1174RenderState *state = &renderStateList[renderStateCount];1175memcpy(state, ¤tRenderState, sizeof(RenderState));11761177currentRenderState.indexCount = 0;1178currentRenderState.id = textureList[texture].id;1179currentRenderState.useColors = true;1180currentRenderState.useTexture = true;1181currentRenderState.useFilter = false;1182currentRenderState.vertPtr = &drawVertexList[vertexListSize];1183currentRenderState.indexPtr = drawIndexList;1184renderStateCount++;1185}1186}11871188if (renderStateCount < RENDERSTATE_COUNT) {1189int a = 0;1190if (alpha >= 0)1191a = alpha;1192if (a > 0xFF)1193a = 0xFF;11941195DrawVertex *vertex1 = &drawVertexList[vertexListSize];1196vertex1->vertX = x - (pivotX * scaleX);1197vertex1->vertY = (pivotY * scaleY) + y;1198vertex1->vertZ = z;1199vertex1->texCoordX = sprX * textureList[texture].widthN;1200vertex1->texCoordY = sprY * textureList[texture].heightN;1201vertex1->r = vertexR;1202vertex1->g = vertexG;1203vertex1->b = vertexB;1204vertex1->a = a;12051206DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1207vertex2->vertX = ((sprW - pivotX) * scaleX) + x;1208vertex2->vertY = vertex1->vertY;1209vertex2->vertZ = z;1210vertex2->texCoordX = (sprX + sprW) * textureList[texture].widthN;1211vertex2->texCoordY = vertex1->texCoordY;1212vertex2->r = vertexR;1213vertex2->g = vertexG;1214vertex2->b = vertexB;1215vertex2->a = a;12161217DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1218vertex3->vertX = vertex1->vertX;1219vertex3->vertY = y - ((sprH - pivotY) * scaleY);1220vertex3->vertZ = z;1221vertex3->texCoordX = vertex1->texCoordX;1222vertex3->texCoordY = (sprY + sprH) * textureList[texture].heightN;1223vertex3->r = vertexR;1224vertex3->g = vertexG;1225vertex3->b = vertexB;1226vertex3->a = a;12271228DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1229vertex4->vertX = vertex2->vertX;1230vertex4->vertY = vertex3->vertY;1231vertex4->vertZ = z;1232vertex4->texCoordX = vertex2->texCoordX;1233vertex4->texCoordY = vertex3->texCoordY;1234vertex4->r = vertexR;1235vertex4->g = vertexG;1236vertex4->b = vertexB;1237vertex4->a = a;1238vertexListSize += 4;1239currentRenderState.indexCount += 6;1240}1241}1242}1243void RenderImageClipped(float x, float y, float z, float scaleX, float scaleY, float pivotX, float pivotY, float sprW, float sprH, float sprX,1244float sprY, int alpha, byte texture)1245{1246if (vertexListSize < DRAWVERTEX_COUNT && textureList[texture].format) {1247if (renderStateCount < 0) {1248currentRenderState.indexCount = 0;1249currentRenderState.id = textureList[texture].id;1250currentRenderState.useColors = true;1251currentRenderState.useTexture = true;1252currentRenderState.useFilter = false;1253currentRenderState.vertPtr = &drawVertexList[vertexListSize];1254currentRenderState.indexPtr = drawIndexList;1255renderStateCount++;1256}1257else {1258bool flag = false;1259if (currentRenderState.useTexture)1260flag = currentRenderState.id == textureList[texture].id;12611262if (!flag) {1263RenderState *state = &renderStateList[renderStateCount];1264memcpy(state, ¤tRenderState, sizeof(RenderState));12651266currentRenderState.indexCount = 0;1267currentRenderState.id = textureList[texture].id;1268currentRenderState.useColors = true;1269currentRenderState.useTexture = true;1270currentRenderState.useFilter = false;1271currentRenderState.vertPtr = &drawVertexList[vertexListSize];1272currentRenderState.indexPtr = drawIndexList;1273renderStateCount++;1274}1275}12761277if (renderStateCount < RENDERSTATE_COUNT) {1278int a = 0;1279if (alpha >= 0)1280a = alpha;1281if (a > 0xFF)1282a = 0xFF;12831284DrawVertex *vertex1 = &drawVertexList[vertexListSize];1285vertex1->vertX = x - (pivotX * scaleX);1286vertex1->vertY = (pivotY * scaleY) + y;1287vertex1->vertZ = z;1288vertex1->texCoordX = sprX * textureList[texture].widthN;1289vertex1->texCoordY = sprY * textureList[texture].heightN;1290vertex1->r = vertexR;1291vertex1->g = vertexG;1292vertex1->b = vertexB;1293vertex1->a = a;1294if (vertex1->vertY > 76.0) {1295vertex1->texCoordY = (((vertex1->vertY - 76.0) / scaleY) + sprY) * textureList[texture].heightN;1296vertex1->vertY = 76.0;1297}12981299DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1300vertex2->vertX = ((sprW - pivotX) * scaleX) + x;1301vertex2->vertY = vertex1->vertY;1302vertex2->vertZ = z;1303vertex2->texCoordX = (sprX + sprW) * textureList[texture].widthN;1304vertex2->texCoordY = vertex1->texCoordY;1305vertex2->r = vertexR;1306vertex2->g = vertexG;1307vertex2->b = vertexB;1308vertex2->a = a;13091310DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1311vertex3->vertX = vertex1->vertX;1312vertex3->vertY = y - ((sprH - pivotY) * scaleY);1313vertex3->vertZ = z;1314vertex3->texCoordX = vertex1->texCoordX;1315vertex3->texCoordY = (sprY + sprH) * textureList[texture].heightN;1316vertex3->r = vertexR;1317vertex3->g = vertexG;1318vertex3->b = vertexB;1319vertex3->a = a;1320if (vertex3->vertY < -76.0) {1321vertex3->texCoordY = (((vertex3->vertY + 76.0) / scaleY) + (sprY + sprH)) * textureList[texture].heightN;1322vertex3->vertY = -76.0;1323}13241325DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1326vertex4->vertX = vertex2->vertX;1327vertex4->vertY = vertex3->vertY;1328vertex4->vertZ = z;1329vertex4->texCoordX = vertex2->texCoordX;1330vertex4->texCoordY = vertex3->texCoordY;1331vertex4->r = vertexR;1332vertex4->g = vertexG;1333vertex4->b = vertexB;1334vertex4->a = a;1335vertexListSize += 4;1336currentRenderState.indexCount += 6;1337}1338}1339}13401341void RenderImageFlipH(float x, float y, float z, float scaleX, float scaleY, float pivotX, float pivotY, float sprW, float sprH, float sprX,1342float sprY, int alpha, byte texture)1343{1344if (vertexListSize < DRAWVERTEX_COUNT && textureList[texture].format) {1345if (renderStateCount < 0) {1346currentRenderState.indexCount = 0;1347currentRenderState.id = textureList[texture].id;1348currentRenderState.useColors = true;1349currentRenderState.useTexture = true;1350currentRenderState.useFilter = false;1351currentRenderState.vertPtr = &drawVertexList[vertexListSize];1352currentRenderState.indexPtr = drawIndexList;1353renderStateCount++;1354}1355else {1356bool flag = false;1357if (currentRenderState.useTexture)1358flag = currentRenderState.id == textureList[texture].id;13591360if (!flag) {1361RenderState *state = &renderStateList[renderStateCount];1362memcpy(state, ¤tRenderState, sizeof(RenderState));13631364currentRenderState.indexCount = 0;1365currentRenderState.id = textureList[texture].id;1366currentRenderState.useColors = true;1367currentRenderState.useTexture = true;1368currentRenderState.useFilter = false;1369currentRenderState.vertPtr = &drawVertexList[vertexListSize];1370currentRenderState.indexPtr = drawIndexList;1371renderStateCount++;1372}1373}13741375if (renderStateCount < RENDERSTATE_COUNT) {1376int a = 0;1377if (alpha >= 0)1378a = alpha;1379if (a > 0xFF)1380a = 0xFF;13811382DrawVertex *vertex1 = &drawVertexList[vertexListSize];1383vertex1->vertX = x - (pivotX * scaleX);1384vertex1->vertY = (pivotY * scaleY) + y;1385vertex1->vertZ = z;1386vertex1->texCoordX = (sprX + sprW) * textureList[texture].widthN;1387vertex1->texCoordY = sprY * textureList[texture].heightN;1388vertex1->r = vertexR;1389vertex1->g = vertexG;1390vertex1->b = vertexB;1391vertex1->a = a;13921393DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1394vertex2->vertX = ((sprW - pivotX) * scaleX) + x;1395vertex2->vertY = vertex1->vertY;1396vertex2->vertZ = z;1397vertex2->texCoordX = sprX * textureList[texture].widthN;1398vertex2->texCoordY = vertex1->texCoordY;1399vertex2->r = vertexR;1400vertex2->g = vertexG;1401vertex2->b = vertexB;1402vertex2->a = a;14031404DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1405vertex3->vertX = vertex1->vertX;1406vertex3->vertY = y - ((sprH - pivotY) * scaleY);1407vertex3->vertZ = z;1408vertex3->texCoordX = vertex1->texCoordX;1409vertex3->texCoordY = (sprY + sprH) * textureList[texture].heightN;1410vertex3->r = vertexR;1411vertex3->g = vertexG;1412vertex3->b = vertexB;1413vertex3->a = a;14141415DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1416vertex4->vertX = vertex2->vertX;1417vertex4->vertY = vertex3->vertY;1418vertex4->vertZ = z;1419vertex4->texCoordX = vertex2->texCoordX;1420vertex4->texCoordY = vertex3->texCoordY;1421vertex4->r = vertexR;1422vertex4->g = vertexG;1423vertex4->b = vertexB;1424vertex4->a = a;1425vertexListSize += 4;1426currentRenderState.indexCount += 6;1427}1428}1429}14301431void RenderText(ushort *text, int fontID, float x, float y, int z, float scale, int alpha)1432{1433BitmapFont *font = &fontList[fontID];1434float posX = x;1435float posY = (font->base * scale) + y;14361437if (vertexListSize < DRAWVERTEX_COUNT) {1438if (renderStateCount < 0 || (!currentRenderState.useTexture || currentRenderState.useColors)) {1439if (renderStateCount >= 0) {1440RenderState *state = &renderStateList[renderStateCount];1441memcpy(state, ¤tRenderState, sizeof(RenderState));1442}1443currentRenderState.indexCount = 0;1444currentRenderState.id = textureList[font->characters[*text].textureID].id;1445currentRenderState.useColors = true;1446currentRenderState.useTexture = true;1447currentRenderState.useFilter = false;1448currentRenderState.vertPtr = &drawVertexList[vertexListSize];1449currentRenderState.indexPtr = drawIndexList;1450renderStateCount++;1451}14521453if (renderStateCount < RENDERSTATE_COUNT) {1454int a = 0;1455if (alpha >= 0)1456a = alpha;1457if (a > 0xFF)1458a = 0xFF;14591460ushort character = *text++;1461while (character && vertexListSize < DRAWVERTEX_COUNT) {1462BitmapFontCharacter *fontChar = &font->characters[character];1463TextureInfo *texture = &textureList[fontChar->textureID];14641465if (texture->format) {1466if (character == 1) {1467posX = x;1468posY -= (font->lineHeight * scale);1469}1470else {1471if (currentRenderState.id != texture->id && renderStateCount < RENDERSTATE_COUNT) {1472currentRenderState.indexCount = 0;1473memcpy(&renderStateList[renderStateCount++], ¤tRenderState, sizeof(RenderState));1474currentRenderState.vertPtr = &drawVertexList[vertexListSize];1475currentRenderState.indexPtr = drawIndexList;1476currentRenderState.id = texture->id;1477}14781479DrawVertex *vertex1 = &drawVertexList[vertexListSize];1480vertex1->vertX = posX + (fontChar->xOffset * scale);1481vertex1->vertY = posY - (fontChar->yOffset * scale);1482vertex1->vertZ = z;1483vertex1->texCoordX = fontChar->x * texture->widthN;1484vertex1->texCoordY = fontChar->y * texture->heightN;1485vertex1->r = vertexR;1486vertex1->g = vertexG;1487vertex1->b = vertexB;1488vertex1->a = a;14891490DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1491vertex2->vertX = posX + ((fontChar->width + fontChar->xOffset) * scale);1492vertex2->vertY = vertex1->vertY;1493vertex2->vertZ = z;1494vertex2->texCoordX = (fontChar->x + fontChar->width) * texture->widthN;1495vertex2->texCoordY = vertex1->texCoordY;1496vertex2->r = vertexR;1497vertex2->g = vertexG;1498vertex2->b = vertexB;1499vertex2->a = a;15001501DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1502vertex3->vertX = vertex1->vertX;1503vertex3->vertY = posY - ((fontChar->height + fontChar->yOffset) * scale);1504vertex3->vertZ = z;1505vertex3->texCoordX = vertex1->texCoordX;1506vertex3->texCoordY = (fontChar->y + fontChar->height) * texture->heightN;1507vertex3->r = vertexR;1508vertex3->g = vertexG;1509vertex3->b = vertexB;1510vertex3->a = a;15111512DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1513vertex4->vertX = vertex2->vertX;1514vertex4->vertY = vertex3->vertY;1515vertex4->vertZ = z;1516vertex4->texCoordX = vertex2->texCoordX;1517vertex4->texCoordY = vertex3->texCoordY;1518vertex4->r = vertexR;1519vertex4->g = vertexG;1520vertex4->b = vertexB;1521vertex4->a = a;1522vertexListSize += 4;1523currentRenderState.indexCount += 6;1524}1525}1526posX += (fontChar->xAdvance * scale);1527character = *text++;1528}1529}1530}1531}1532void RenderTextClipped(ushort *text, int fontID, float x, float y, int z, float scale, int alpha)1533{1534BitmapFont *font = &fontList[fontID];1535float posX = x;1536float posY = (font->base * scale) + y;15371538if (vertexListSize < DRAWVERTEX_COUNT) {1539if (renderStateCount < 0 || (!currentRenderState.useTexture || currentRenderState.useColors)) {1540if (renderStateCount >= 0) {1541RenderState *state = &renderStateList[renderStateCount];1542memcpy(state, ¤tRenderState, sizeof(RenderState));1543}1544currentRenderState.indexCount = 0;1545currentRenderState.id = textureList[font->characters[*text].textureID].id;1546currentRenderState.useColors = true;1547currentRenderState.useTexture = true;1548currentRenderState.useFilter = false;1549currentRenderState.vertPtr = &drawVertexList[vertexListSize];1550currentRenderState.indexPtr = drawIndexList;1551renderStateCount++;1552}15531554if (renderStateCount < RENDERSTATE_COUNT) {1555int a = 0;1556if (alpha >= 0)1557a = alpha;1558if (a > 0xFF)1559a = 0xFF;15601561ushort character = *text++;1562while (character && vertexListSize < DRAWVERTEX_COUNT) {1563BitmapFontCharacter *fontChar = &font->characters[character];1564TextureInfo *texture = &textureList[fontChar->textureID];15651566if (texture->format) {1567if (character == 1) {1568posX = x;1569posY -= (font->lineHeight * scale);1570}1571else {1572if (currentRenderState.id != texture->id && renderStateCount < RENDERSTATE_COUNT) {1573currentRenderState.indexCount = 0;1574memcpy(&renderStateList[renderStateCount++], ¤tRenderState, sizeof(RenderState));1575currentRenderState.vertPtr = &drawVertexList[vertexListSize];1576currentRenderState.indexPtr = drawIndexList;1577currentRenderState.id = texture->id;1578}15791580DrawVertex *vertex1 = &drawVertexList[vertexListSize];1581vertex1->vertX = posX + (fontChar->xOffset * scale);1582vertex1->vertY = posY - (fontChar->yOffset * scale);1583vertex1->vertZ = z;1584vertex1->texCoordX = fontChar->x * texture->widthN;1585vertex1->texCoordY = fontChar->y * texture->heightN;1586vertex1->r = vertexR;1587vertex1->g = vertexG;1588vertex1->b = vertexB;1589vertex1->a = a;1590if (vertex1->vertY > 76.0) {1591vertex1->texCoordY = (((vertex1->vertY - 76.0) / scale) + fontChar->y) * texture->heightN;1592vertex1->vertY = 76.0;1593}15941595DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1596vertex2->vertX = posX + ((fontChar->width + fontChar->xOffset) * scale);1597vertex2->vertY = vertex1->vertY;1598vertex2->vertZ = z;1599vertex2->texCoordX = (fontChar->x + fontChar->width) * texture->widthN;1600vertex2->texCoordY = vertex1->texCoordY;1601vertex2->r = vertexR;1602vertex2->g = vertexG;1603vertex2->b = vertexB;1604vertex2->a = a;16051606DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1607vertex3->vertX = vertex1->vertX;1608vertex3->vertY = posY - ((fontChar->height + fontChar->yOffset) * scale);1609vertex3->vertZ = z;1610vertex3->texCoordX = vertex1->texCoordX;1611vertex3->texCoordY = (fontChar->y + fontChar->height) * texture->heightN;1612vertex3->r = vertexR;1613vertex3->g = vertexG;1614vertex3->b = vertexB;1615vertex3->a = a;1616if (vertex3->vertY < -76.0) {1617vertex3->texCoordY = (((vertex3->vertY + 76.0) / scale) + (fontChar->y + fontChar->height)) * texture->heightN;1618vertex3->vertY = -76.0;1619}16201621DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1622vertex4->vertX = vertex2->vertX;1623vertex4->vertY = vertex3->vertY;1624vertex4->vertZ = z;1625vertex4->texCoordX = vertex2->texCoordX;1626vertex4->texCoordY = vertex3->texCoordY;1627vertex4->r = vertexR;1628vertex4->g = vertexG;1629vertex4->b = vertexB;1630vertex4->a = a;1631vertexListSize += 4;1632currentRenderState.indexCount += 6;1633}1634}1635posX += (fontChar->xAdvance * scale);1636character = *text++;1637}1638}1639}1640}16411642void RenderRect(float x, float y, float z, float w, float h, byte r, byte g, byte b, int alpha)1643{1644if (vertexListSize < DRAWVERTEX_COUNT) {1645if (renderStateCount < 0 || (currentRenderState.useTexture || !currentRenderState.useColors)) {1646if (renderStateCount >= 0) {1647RenderState *state = &renderStateList[renderStateCount];1648memcpy(state, ¤tRenderState, sizeof(RenderState));1649}16501651currentRenderState.indexCount = 0;1652currentRenderState.id = 0;1653currentRenderState.useColors = true;1654currentRenderState.useTexture = false;1655currentRenderState.useFilter = false;1656currentRenderState.vertPtr = &drawVertexList[vertexListSize];1657currentRenderState.indexPtr = drawIndexList;1658renderStateCount++;1659}16601661if (renderStateCount < RENDERSTATE_COUNT) {1662int a = 0;1663if (alpha >= 0)1664a = alpha;1665if (a > 0xFF)1666a = 0xFF;16671668DrawVertex *vertex1 = &drawVertexList[vertexListSize];1669vertex1->vertX = x;1670vertex1->vertY = y;1671vertex1->vertZ = z;1672vertex1->r = r;1673vertex1->g = g;1674vertex1->b = b;1675vertex1->a = a;16761677DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1678vertex2->vertX = w + x;1679vertex2->vertY = y;1680vertex2->vertZ = z;1681vertex2->r = r;1682vertex2->g = g;1683vertex2->b = b;1684vertex2->a = a;16851686DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1687vertex3->vertX = x;1688vertex3->vertY = y - h;1689vertex3->vertZ = z;1690vertex3->r = r;1691vertex3->g = g;1692vertex3->b = b;1693vertex3->a = a;16941695DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1696vertex4->vertX = vertex2->vertX;1697vertex4->vertY = y - h;1698vertex4->vertZ = z;1699vertex4->r = r;1700vertex4->g = g;1701vertex4->b = b;1702vertex4->a = a;17031704vertexListSize += 4;1705currentRenderState.indexCount += 6;1706}1707}1708}17091710#if !RETRO_USE_ORIGINAL_CODE1711void RenderRectClipped(float x, float y, float z, float w, float h, byte r, byte g, byte b, int alpha)1712{1713if (vertexListSize < DRAWVERTEX_COUNT) {1714if (renderStateCount < 0 || (currentRenderState.useTexture || !currentRenderState.useColors)) {1715if (renderStateCount >= 0) {1716RenderState *state = &renderStateList[renderStateCount];1717memcpy(state, ¤tRenderState, sizeof(RenderState));1718}17191720currentRenderState.indexCount = 0;1721currentRenderState.id = 0;1722currentRenderState.useColors = true;1723currentRenderState.useTexture = false;1724currentRenderState.useFilter = false;1725currentRenderState.vertPtr = &drawVertexList[vertexListSize];1726currentRenderState.indexPtr = drawIndexList;1727renderStateCount++;1728}17291730if (renderStateCount < RENDERSTATE_COUNT) {1731int a = 0;1732if (alpha >= 0)1733a = alpha;1734if (a > 0xFF)1735a = 0xFF;17361737DrawVertex *vertex1 = &drawVertexList[vertexListSize];1738vertex1->vertX = x;1739vertex1->vertY = y;1740vertex1->vertZ = z;1741vertex1->r = r;1742vertex1->g = g;1743vertex1->b = b;1744vertex1->a = a;1745if (vertex1->vertY > 76.0)1746vertex1->vertY = 76.0;17471748DrawVertex *vertex2 = &drawVertexList[vertexListSize + 1];1749vertex2->vertX = w + x;1750vertex2->vertY = y;1751vertex2->vertZ = z;1752vertex2->r = r;1753vertex2->g = g;1754vertex2->b = b;1755vertex2->a = a;1756if (vertex2->vertY > 76.0)1757vertex2->vertY = 76.0;17581759DrawVertex *vertex3 = &drawVertexList[vertexListSize + 2];1760vertex3->vertX = x;1761vertex3->vertY = y - h;1762vertex3->vertZ = z;1763vertex3->r = r;1764vertex3->g = g;1765vertex3->b = b;1766vertex3->a = a;1767if (vertex3->vertY < -76.0)1768vertex3->vertY = -76.0;17691770DrawVertex *vertex4 = &drawVertexList[vertexListSize + 3];1771vertex4->vertX = vertex2->vertX;1772vertex4->vertY = y - h;1773vertex4->vertZ = z;1774vertex4->r = r;1775vertex4->g = g;1776vertex4->b = b;1777vertex4->a = a;1778if (vertex4->vertY < -76.0)1779vertex4->vertY = -76.0;17801781vertexListSize += 4;1782currentRenderState.indexCount += 6;1783}1784}1785}1786#endif17871788void RenderMesh(MeshInfo *mesh, byte type, byte depthTest)1789{1790if (!mesh)1791return;17921793if (renderStateCount < RENDERSTATE_COUNT) {1794if (currentRenderState.indexCount) {1795RenderState *state = &renderStateList[renderStateCount++];1796memcpy(state, ¤tRenderState, sizeof(RenderState));1797}17981799currentRenderState.vertPtr = mesh->vertices;1800currentRenderState.indexPtr = mesh->indices;1801currentRenderState.indexCount = mesh->indexCount * 3;1802if (mesh->textureID >= TEXTURE_COUNT) {1803currentRenderState.useTexture = false;1804currentRenderState.id = 0;1805}1806else {1807currentRenderState.useTexture = true;1808currentRenderState.id = textureList[mesh->textureID].id;1809}18101811switch (type) {1812case MESH_COLORS:1813currentRenderState.useColors = true;1814currentRenderState.useNormals = false;1815break;1816case MESH_NORMALS:1817currentRenderState.useColors = false;1818currentRenderState.useNormals = true;1819break;1820case MESH_COLORS_NORMALS:1821currentRenderState.useColors = true;1822currentRenderState.useNormals = true;1823break;1824}1825currentRenderState.depthTest = depthTest;18261827RenderState *state = &renderStateList[renderStateCount];1828memcpy(state, ¤tRenderState, sizeof(RenderState));18291830currentRenderState.indexCount = 0;1831currentRenderState.id = 0;1832currentRenderState.useColors = true;1833currentRenderState.useTexture = false;1834currentRenderState.useNormals = false;1835currentRenderState.depthTest = false;1836currentRenderState.useFilter = false;1837currentRenderState.vertPtr = &drawVertexList[vertexListSize];1838currentRenderState.indexPtr = drawIndexList;18391840renderStateCount++;1841}1842}18431844