diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 80c535f75..858b0da19 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2011 DeSmuME team + Copyright (C) 2008-2012 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,11 +29,10 @@ #include "debug.h" #define VERT_INDEX_BUFFER_SIZE 8192 -CACHE_ALIGN float material_8bit_to_float[255] = {0}; -bool (*oglrender_init)() = 0; -bool (*oglrender_beginOpenGL)() = 0; -void (*oglrender_endOpenGL)() = 0; +bool (*oglrender_init)() = NULL; +bool (*oglrender_beginOpenGL)() = NULL; +void (*oglrender_endOpenGL)() = NULL; static bool BEGINGL() { if(oglrender_beginOpenGL) @@ -79,38 +78,61 @@ static void ENDGL() { static DS_ALIGN(16) u8 GPU_screen3D [256*192*4]; -static const unsigned short map3d_cull[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; -static const int texEnv[4] = { GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE }; -static const int depthFunc[2] = { GL_LESS, GL_EQUAL }; +static const GLenum map3d_cull[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; +static const GLint texEnv[4] = { GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE }; +static const GLenum depthFunc[2] = { GL_LESS, GL_EQUAL }; -//derived values extracted from polyattr etc -static bool wireframe=false, alpha31=false; -static unsigned int polyID=0; -static unsigned int depthFuncMode=0; -static unsigned int envMode=0; -static unsigned int lastEnvMode=0; -static unsigned int cullingMask=0; -static bool alphaDepthWrite; -static unsigned int lightMask=0; -static bool isTranslucent; +/// Polygon Info +static PolygonAttributes currentPolyAttr; +static PolygonTexParams currentTexParams; +static GLenum depthFuncMode = 0; +static unsigned int lastEnvMode = 0; +static GLenum cullingMode = 0; +static GLfloat polyAlpha = 1.0f; -static u32 textureFormat=0, texturePalette=0; +static u32 stencilStateSet = -1; static char *extString = NULL; + // ClearImage/Rear-plane (FBO) -GLenum oglClearImageTextureID[2] = {0}; // 0 - image, 1 - depth -GLuint oglClearImageBuffers = 0; -GLuint oglClearImageRender[1] = {0}; -bool oglFBOdisabled = false; -u32 *oglClearImageColor = NULL; -float *oglClearImageDepth = NULL; -u16 *oglClearImageColorTemp = NULL; -u16 *oglClearImageDepthTemp = NULL; -u32 oglClearImageScrollOld = 0; +static GLenum oglClearImageTextureID[2] = {0}; // 0 - image, 1 - depth +static GLuint oglClearImageBuffers = 0; +static bool oglFBOdisabled = false; +static u32 *oglClearImageColor = NULL; +static float *oglClearImageDepth = NULL; +static u16 *oglClearImageColorTemp = NULL; +static u16 *oglClearImageDepthTemp = NULL; +static u32 oglClearImageScrollOld = 0; + +// Shader states +static bool hasShaders = false; + +static GLuint vertexShaderID; +static GLuint fragmentShaderID; +static GLuint shaderProgram; + +static GLint uniformPolyAlpha; +static GLint uniformTexScale; +static GLint uniformHasTexture; +static GLint uniformTextureBlendingMode; +static GLint uniformWBuffer; + +static bool hasTexture = false; +static TexCacheItem* currTexture = NULL; static GLfloat *color4fBuffer = NULL; static GLushort *vertIndexBuffer = NULL; +static CACHE_ALIGN GLfloat material_8bit_to_float[255] = {0}; +static const GLfloat divide5bitBy31LUT[32] = {0.0, 0.03225806451613, 0.06451612903226, 0.09677419354839, + 0.1290322580645, 0.1612903225806, 0.1935483870968, 0.2258064516129, + 0.258064516129, 0.2903225806452, 0.3225806451613, 0.3548387096774, + 0.3870967741935, 0.4193548387097, 0.4516129032258, 0.4838709677419, + 0.5161290322581, 0.5483870967742, 0.5806451612903, 0.6129032258065, + 0.6451612903226, 0.6774193548387, 0.7096774193548, 0.741935483871, + 0.7741935483871, 0.8064516129032, 0.8387096774194, 0.8709677419355, + 0.9032258064516, 0.9354838709677, 0.9677419354839, 1.0}; + //------------------------------------------------------------ #define OGLEXT(x,y) x y = 0; @@ -277,19 +299,6 @@ GLenum oglToonTableTextureID; } \ } -bool hasShaders = false; - -GLuint vertexShaderID; -GLuint fragmentShaderID; -GLuint shaderProgram; - -static GLint hasTexLoc; -static GLint texBlendLoc; -static GLint oglWBuffer; -static bool hasTexture = false; - -static TexCacheItem* currTexture = NULL; - /* Shaders init */ static void createShaders() @@ -360,20 +369,25 @@ static void OGLReset() if(BEGINGL()) { - glUniform1i(hasTexLoc, 0); - glUniform1i(texBlendLoc, 0); - glUniform1i(oglWBuffer, 0); + glUniform1f(uniformPolyAlpha, 1.0f); + glUniform2f(uniformTexScale, 1.0f, 1.0f); + glUniform1i(uniformHasTexture, 0); + glUniform1i(uniformTextureBlendingMode, 0); + glUniform1i(uniformWBuffer, 0); ENDGL(); } } - + else + { + memset(color4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat)); + } + TexCache_Reset(); if (currTexture) delete currTexture; currTexture = NULL; -// memset(GPU_screenStencil,0,sizeof(GPU_screenStencil)); memset(GPU_screen3D,0,sizeof(GPU_screen3D)); if (!oglFBOdisabled) @@ -385,7 +399,6 @@ static void OGLReset() oglClearImageScrollOld = 0; } - memset(color4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat)); memset(vertIndexBuffer, 0, VERT_INDEX_BUFFER_SIZE * sizeof(GLushort)); } @@ -444,7 +457,7 @@ static char OGLInit(void) return 0; for (u8 i = 0; i < 255; i++) - material_8bit_to_float[i] = (float)(i<<2)/255.f; + material_8bit_to_float[i] = (GLfloat)(i<<2)/255.f; extString = (char*)glGetString(GL_EXTENSIONS); @@ -516,12 +529,12 @@ static char OGLInit(void) loc = glGetUniformLocation(shaderProgram, "toonTable"); glUniform1i(loc, 1); - - hasTexLoc = glGetUniformLocation(shaderProgram, "hasTexture"); - - texBlendLoc = glGetUniformLocation(shaderProgram, "texBlending"); - - oglWBuffer = glGetUniformLocation(shaderProgram, "oglWBuffer"); + + uniformPolyAlpha = glGetUniformLocation(shaderProgram, "polyAlpha"); + uniformTexScale = glGetUniformLocation(shaderProgram, "texScale"); + uniformHasTexture = glGetUniformLocation(shaderProgram, "hasTexture"); + uniformTextureBlendingMode = glGetUniformLocation(shaderProgram, "texBlending"); + uniformWBuffer = glGetUniformLocation(shaderProgram, "oglWBuffer"); } //we want to use alpha destination blending so we can track the last-rendered alpha value @@ -554,6 +567,14 @@ static char OGLInit(void) glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rgbToonTable[0]); gfx3d.state.invalidateToon = false; } + else + { + // Map the vertex list's colors with 4 floats per color. This is being done + // because OpenGL needs 4-colors per vertex to support translucency. (The DS + // uses 3-colors per vertex, and adds alpha through the poly, so we can't + // simply reference the colors+alpha from just the vertices themselves.) + color4fBuffer = new GLfloat[VERTLIST_SIZE * 4]; + } // FBO oglFBOdisabled = (strstr(extString, "GL_ARB_framebuffer_object") == NULL)?true:false; @@ -612,12 +633,6 @@ static char OGLInit(void) ENDGL(); - // Map the vertex list's colors with 4 floats per color. This is being done - // because OpenGL needs 4-colors per vertex to support translucency. (The DS - // uses 3-colors per vertex, and adds alpha through the poly, so we can't - // simply reference the colors+alpha from just the vertices themselves.) - color4fBuffer = new GLfloat[VERTLIST_SIZE * 4]; - // Make our own vertex index buffer for primitive conversions. This is // necessary since OpenGL deprecates primitives like GL_QUADS and // GL_QUAD_STRIP in later versions. (Maybe we can also use the buffer for @@ -631,9 +646,6 @@ static char OGLInit(void) static void OGLClose() { - delete [] color4fBuffer; - color4fBuffer = NULL; - delete [] vertIndexBuffer; vertIndexBuffer = NULL; @@ -653,6 +665,11 @@ static void OGLClose() hasShaders = false; } + else + { + delete [] color4fBuffer; + color4fBuffer = NULL; + } //kill the tex cache to free all the texture ids TexCache_Reset(); @@ -710,25 +727,15 @@ static void texDeleteCallback(TexCacheItem* item) static void setTexture(unsigned int format, unsigned int texpal) { - textureFormat = format; - texturePalette = texpal; - - u32 textureMode = (unsigned short)((format>>26)&0x07); - - if (format==0) + if (format == 0 || currentTexParams.texFormat == TEXMODE_NONE) { - if(hasShaders && hasTexture) { glUniform1i(hasTexLoc, 0); hasTexture = false; } - return; - } - if (textureMode==0) - { - if(hasShaders && hasTexture) { glUniform1i(hasTexLoc, 0); hasTexture = false; } + if(hasShaders && hasTexture) { glUniform1i(uniformHasTexture, 0); hasTexture = false; } return; } if(hasShaders) { - if(!hasTexture) { glUniform1i(hasTexLoc, 1); hasTexture = true; } + if(!hasTexture) { glUniform1i(uniformHasTexture, 1); hasTexture = true; } glActiveTexture(GL_TEXTURE0); } @@ -765,53 +772,69 @@ static void setTexture(unsigned int format, unsigned int texpal) } //in either case, we need to setup the tex mtx - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(currTexture->invSizeX, currTexture->invSizeY, 1.0f); - + if (hasShaders) + { + glUniform2f(uniformTexScale, currTexture->invSizeX, currTexture->invSizeY); + } + else + { + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glScalef(currTexture->invSizeX, currTexture->invSizeY, 1.0f); + } } } - - -//controls states: -//glStencilFunc -//glStencilOp -//glColorMask -static u32 stencilStateSet = -1; - -static u32 polyalpha=0; - -static void BeginRenderPoly() +static void SetupPolygonRender(POLY *thePoly) { bool enableDepthWrite = true; - + + // Get polygon info + currentPolyAttr = thePoly->getAttributes(); + + polyAlpha = 1.0f; + if (!currentPolyAttr.isWireframe && currentPolyAttr.isTranslucent) + { + polyAlpha = divide5bitBy31LUT[currentPolyAttr.alpha]; + } + + if (hasShaders) + { + glUniform1f(uniformPolyAlpha, polyAlpha); + } + + cullingMode = map3d_cull[currentPolyAttr.surfaceCullingMode]; + depthFuncMode = depthFunc[currentPolyAttr.enableDepthTest]; + + // Set up texture + if (gfx3d.renderState.enableTexturing) + { + currentTexParams = thePoly->getTexParams(); + setTexture(thePoly->texParam, thePoly->texPalette); + } + + // Set up rendering states xglDepthFunc (depthFuncMode); // Cull face - if (cullingMask == 0x03) + if (cullingMode == 0) { xglDisable(GL_CULL_FACE); } else { xglEnable(GL_CULL_FACE); - glCullFace(map3d_cull[cullingMask]); - } - - if (gfx3d.renderState.enableTexturing) - { - setTexture(textureFormat, texturePalette); + glCullFace(cullingMode); } - if(isTranslucent) - enableDepthWrite = alphaDepthWrite; + if(currentPolyAttr.isTranslucent) + enableDepthWrite = currentPolyAttr.enableAlphaDepthWrite; //handle shadow polys - if(envMode == 3) + if(currentPolyAttr.polygonMode == 3) { xglEnable(GL_STENCIL_TEST); - if(polyID == 0) { + if(currentPolyAttr.polygonID == 0) { enableDepthWrite = false; if(stencilStateSet!=0) { stencilStateSet = 0; @@ -836,10 +859,10 @@ static void BeginRenderPoly() } } else { xglEnable(GL_STENCIL_TEST); - if(isTranslucent) + if(currentPolyAttr.isTranslucent) { stencilStateSet = 3; - glStencilFunc(GL_NOTEQUAL,polyID,255); + glStencilFunc(GL_NOTEQUAL,currentPolyAttr.polygonID,255); glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE); glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); } @@ -851,58 +874,32 @@ static void BeginRenderPoly() glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); } } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv[envMode]); - - if(hasShaders) + + if(currentPolyAttr.polygonMode != lastEnvMode) { - if(envMode != lastEnvMode) + lastEnvMode = currentPolyAttr.polygonMode; + + if(hasShaders) { - lastEnvMode = envMode; - int _envModes[4] = {0, 1, (2 + gfx3d.renderState.shading), 0}; - glUniform1i(texBlendLoc, _envModes[envMode]); + glUniform1i(uniformTextureBlendingMode, _envModes[currentPolyAttr.polygonMode]); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv[currentPolyAttr.polygonMode]); } } xglDepthMask(enableDepthWrite?GL_TRUE:GL_FALSE); } -static void InstallPolygonAttrib(u32 val) -{ - // Light enable/disable - lightMask = (val&0xF); - - // texture environment - envMode = (val&0x30)>>4; - - // overwrite depth on alpha pass - alphaDepthWrite = BIT11(val)!=0; - - // depth test function - depthFuncMode = depthFunc[BIT14(val)]; - - // back face culling - cullingMask = (val >> 6) & 0x03; - - alpha31 = ((val>>16)&0x1F)==31; - - // Alpha value, actually not well handled, 0 should be wireframe - wireframe = ((val>>16)&0x1F)==0; - - polyalpha = ((val>>16)&0x1F); - - // polyID - polyID = (val>>24)&0x3F; -} - static void Control() { if (gfx3d.renderState.enableTexturing) { if (hasShaders) { - glUniform1i(hasTexLoc, 1); + glUniform1i(uniformHasTexture, 1); } else { @@ -913,7 +910,7 @@ static void Control() { if (hasShaders) { - glUniform1i(hasTexLoc, 0); + glUniform1i(uniformHasTexture, 0); } else { @@ -921,19 +918,22 @@ static void Control() } } - if(gfx3d.renderState.enableAlphaTest) - // FIXME: alpha test should pass gfx3d.alphaTestRef==poly->getAlpha - glAlphaFunc (GL_GREATER, gfx3d.renderState.alphaTestRef/31.f); - else - glAlphaFunc (GL_GREATER, 0); - - if(gfx3d.renderState.enableAlphaBlending) + if(gfx3d.renderState.enableAlphaTest && (gfx3d.renderState.alphaTestRef > 0)) { - glEnable (GL_BLEND); + glAlphaFunc(GL_GEQUAL, divide5bitBy31LUT[gfx3d.renderState.alphaTestRef]); } else { - glDisable (GL_BLEND); + glAlphaFunc(GL_GREATER, 0); + } + + if(gfx3d.renderState.enableAlphaBlending) + { + glEnable(GL_BLEND); + } + else + { + glDisable(GL_BLEND); } } @@ -941,8 +941,7 @@ static void Control() static void GL_ReadFramebuffer() { if(!BEGINGL()) return; -// glReadPixels(0,0,256,192,GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, GPU_screenStencil); - glReadPixels(0,0,256,192,GL_BGRA_EXT, GL_UNSIGNED_BYTE, GPU_screen3D); + glReadPixels(0, 0, 256, 192, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GPU_screen3D); ENDGL(); //convert the pixels to a different format which is more convenient @@ -1099,7 +1098,7 @@ static void OGLRender() gfx3d.state.invalidateToon = false; } - glUniform1i(oglWBuffer, gfx3d.renderState.wbuffer); + glUniform1i(uniformWBuffer, gfx3d.renderState.wbuffer); } xglDepthMask(GL_TRUE); @@ -1111,14 +1110,15 @@ static void OGLRender() oglClearImageFBO(); else { - float clearColor[4] = { - ((float)(gfx3d.renderState.clearColor&0x1F))/31.0f, - ((float)((gfx3d.renderState.clearColor>>5)&0x1F))/31.0f, - ((float)((gfx3d.renderState.clearColor>>10)&0x1F))/31.0f, - ((float)((gfx3d.renderState.clearColor>>16)&0x1F))/31.0f, + GLfloat clearColor[4] = { + divide5bitBy31LUT[gfx3d.renderState.clearColor & 0x1F], + divide5bitBy31LUT[(gfx3d.renderState.clearColor >> 5) & 0x1F], + divide5bitBy31LUT[(gfx3d.renderState.clearColor >> 10) & 0x1F], + divide5bitBy31LUT[(gfx3d.renderState.clearColor >> 16) & 0x1F] }; + glClearColor(clearColor[0],clearColor[1],clearColor[2],clearColor[3]); - glClearDepth((float)gfx3d.renderState.clearDepth / (float)0x00FFFFFF); + glClearDepth((GLfloat)gfx3d.renderState.clearDepth / (GLfloat)0x00FFFFFF); clearFlag |= GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; } @@ -1133,10 +1133,11 @@ static void OGLRender() //render display list //TODO - properly doublebuffer the display lists { - - u32 lastTextureFormat = 0, lastTexturePalette = 0, lastPolyAttr = 0, lastViewport = 0xFFFFFFFF; - // int lastProjIndex = -1; - + u32 lastTexParams = 0; + u32 lastTexPalette = 0; + u32 lastPolyAttr = 0; + u32 lastViewport = 0xFFFFFFFF; + unsigned int polyCount = gfx3d.polylist->count; unsigned int vertIndexCount = 0; GLenum polyPrimitive = 0; unsigned int polyType = 0; @@ -1145,25 +1146,33 @@ static void OGLRender() glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); + if (hasShaders) + { + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERT), &gfx3d.vertlist->list[0].color); + } + else + { + glColorPointer(4, GL_FLOAT, 0, color4fBuffer); + } + glTexCoordPointer(2, GL_FLOAT, sizeof(VERT), &gfx3d.vertlist->list[0].texcoord); - glColorPointer(4, GL_FLOAT, 0, color4fBuffer); glVertexPointer(4, GL_FLOAT, sizeof(VERT), &gfx3d.vertlist->list[0].coord); - - for(int i=0;icount;i++) { + + for(unsigned int i = 0; i < polyCount; i++) + { POLY *poly = &gfx3d.polylist->list[gfx3d.indexlist.list[i]]; polyPrimitive = frm[poly->vtxFormat]; polyType = poly->type; //a very macro-level state caching approach: //these are the only things which control the GPU rendering state. - if(i==0 || lastTextureFormat != poly->texParam || lastTexturePalette != poly->texPalette || lastPolyAttr != poly->polyAttr) + if(lastPolyAttr != poly->polyAttr || lastTexParams != poly->texParam || lastTexPalette != poly->texPalette || i == 0) { - isTranslucent = poly->isTranslucent(); - InstallPolygonAttrib(poly->polyAttr); - lastTextureFormat = textureFormat = poly->texParam; - lastTexturePalette = texturePalette = poly->texPalette; - lastPolyAttr = poly->polyAttr; - BeginRenderPoly(); + lastPolyAttr = poly->polyAttr; + lastTexParams = poly->texParam; + lastTexPalette = poly->texPalette; + + SetupPolygonRender(poly); } if(lastViewport != poly->viewport) @@ -1174,38 +1183,60 @@ static void OGLRender() lastViewport = poly->viewport; } - // Consolidate the vertex color and the poly alpha to our internal color buffer - // so that OpenGL can use it. - GLfloat alpha = 1.0f; - if (!wireframe && isTranslucent) + // Set up vertices + if (hasShaders) { - alpha = (GLfloat)(poly->getAlpha() / 31.0f); - } - - for(unsigned int j = 0; j < polyType; j++) - { - GLushort vertIndex = poly->vertIndexes[j]; - VERT *vert = &gfx3d.vertlist->list[vertIndex]; - - color4fBuffer[(4*vertIndex)+0] = material_8bit_to_float[vert->color[0]]; - color4fBuffer[(4*vertIndex)+1] = material_8bit_to_float[vert->color[1]]; - color4fBuffer[(4*vertIndex)+2] = material_8bit_to_float[vert->color[2]]; - color4fBuffer[(4*vertIndex)+3] = alpha; - - // While we're looping through our vertices, add each vertex index to - // a buffer. For GL_QUADS and GL_QUAD_STRIP, we also add additional vertices - // here to convert them to GL_TRIANGLES, which are much easier to work with - // and won't be deprecated in future OpenGL versions. - vertIndexBuffer[vertIndexCount++] = vertIndex; - if (polyPrimitive == GL_QUADS || polyPrimitive == GL_QUAD_STRIP) + for(unsigned int j = 0; j < polyType; j++) { - if (j == 2) + GLushort vertIndex = poly->vertIndexes[j]; + + // While we're looping through our vertices, add each vertex index to + // a buffer. For GL_QUADS and GL_QUAD_STRIP, we also add additional vertices + // here to convert them to GL_TRIANGLES, which are much easier to work with + // and won't be deprecated in future OpenGL versions. + vertIndexBuffer[vertIndexCount++] = vertIndex; + if (polyPrimitive == GL_QUADS || polyPrimitive == GL_QUAD_STRIP) { - vertIndexBuffer[vertIndexCount++] = vertIndex; + if (j == 2) + { + vertIndexBuffer[vertIndexCount++] = vertIndex; + } + else if (j == 3) + { + vertIndexBuffer[vertIndexCount++] = poly->vertIndexes[0]; + } } - else if (j == 3) + } + } + else + { + for(unsigned int j = 0; j < polyType; j++) + { + GLushort vertIndex = poly->vertIndexes[j]; + + // Consolidate the vertex color and the poly alpha to our internal color buffer + // so that OpenGL can use it. + VERT *vert = &gfx3d.vertlist->list[vertIndex]; + color4fBuffer[(4*vertIndex)+0] = material_8bit_to_float[vert->color[0]]; + color4fBuffer[(4*vertIndex)+1] = material_8bit_to_float[vert->color[1]]; + color4fBuffer[(4*vertIndex)+2] = material_8bit_to_float[vert->color[2]]; + color4fBuffer[(4*vertIndex)+3] = polyAlpha; + + // While we're looping through our vertices, add each vertex index to + // a buffer. For GL_QUADS and GL_QUAD_STRIP, we also add additional vertices + // here to convert them to GL_TRIANGLES, which are much easier to work with + // and won't be deprecated in future OpenGL versions. + vertIndexBuffer[vertIndexCount++] = vertIndex; + if (polyPrimitive == GL_QUADS || polyPrimitive == GL_QUAD_STRIP) { - vertIndexBuffer[vertIndexCount++] = poly->vertIndexes[0]; + if (j == 2) + { + vertIndexBuffer[vertIndexCount++] = vertIndex; + } + else if (j == 3) + { + vertIndexBuffer[vertIndexCount++] = poly->vertIndexes[0]; + } } } } @@ -1215,7 +1246,7 @@ static void OGLRender() // drawing more accurate this way, but it also allows GL_QUADS and // GL_QUAD_STRIP primitives to properly draw as wireframe without the // extra diagonal line. - if (wireframe) + if (currentPolyAttr.isWireframe) { polyPrimitive = GL_LINE_LOOP; } diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 90b64f241..06f9017ff 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2008-2011 DeSmuME team + Copyright (C) 2008-2012 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -119,14 +119,89 @@ inline u32 gfx3d_extendDepth_15_to_24(u32 depth) else return depth<<9; } -#define TEXMODE_NONE 0 -#define TEXMODE_A3I5 1 -#define TEXMODE_I2 2 -#define TEXMODE_I4 3 -#define TEXMODE_I8 4 -#define TEXMODE_4X4 5 -#define TEXMODE_A5I3 6 -#define TEXMODE_16BPP 7 +// POLYGON ATTRIBUTES - BIT LOCATIONS +enum +{ + POLYGON_ATTR_ENABLE_LIGHT0_BIT = 0, + POLYGON_ATTR_ENABLE_LIGHT1_BIT = 1, + POLYGON_ATTR_ENABLE_LIGHT2_BIT = 2, + POLYGON_ATTR_ENABLE_LIGHT3_BIT = 3, + POLYGON_ATTR_MODE_BIT = 4, // Bits 4 - 5 + POLYGON_ATTR_ENABLE_BACK_SURFACE_BIT = 6, + POLYGON_ATTR_ENABLE_FRONT_SURFACE_BIT = 7, + // Bits 8 - 10 unused + POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT = 11, + POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT = 12, + POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT = 13, + POLYGON_ATTR_ENABLE_DEPTH_TEST_BIT = 14, + POLYGON_ATTR_ENABLE_FOG_BIT = 15, + POLYGON_ATTR_ALPHA_BIT = 16, // Bits 16 - 20 + // Bits 21 - 23 unused + POLYGON_ATTR_POLYGON_ID_BIT = 24, // Bits 24 - 29 + // Bits 30 - 31 unused +}; + +// POLYGON ATTRIBUTES - BIT MASKS +enum +{ + POLYGON_ATTR_ENABLE_LIGHT0_MASK = 0x01 << POLYGON_ATTR_ENABLE_LIGHT0_BIT, + POLYGON_ATTR_ENABLE_LIGHT1_MASK = 0x01 << POLYGON_ATTR_ENABLE_LIGHT1_BIT, + POLYGON_ATTR_ENABLE_LIGHT2_MASK = 0x01 << POLYGON_ATTR_ENABLE_LIGHT2_BIT, + POLYGON_ATTR_ENABLE_LIGHT3_MASK = 0x01 << POLYGON_ATTR_ENABLE_LIGHT3_BIT, + POLYGON_ATTR_MODE_MASK = 0x03 << POLYGON_ATTR_MODE_BIT, + POLYGON_ATTR_ENABLE_BACK_SURFACE_MASK = 0x01 << POLYGON_ATTR_ENABLE_BACK_SURFACE_BIT, + POLYGON_ATTR_ENABLE_FRONT_SURFACE_MASK = 0x01 << POLYGON_ATTR_ENABLE_FRONT_SURFACE_BIT, + POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_MASK = 0x01 << POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_BIT, + POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_MASK = 0x01 << POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_BIT, + POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK = 0x01 << POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_BIT, + POLYGON_ATTR_ENABLE_DEPTH_TEST_MASK = 0x01 << POLYGON_ATTR_ENABLE_DEPTH_TEST_BIT, + POLYGON_ATTR_ENABLE_FOG_MASK = 0x01 << POLYGON_ATTR_ENABLE_FOG_BIT, + POLYGON_ATTR_ALPHA_MASK = 0x1F << POLYGON_ATTR_ALPHA_BIT, + POLYGON_ATTR_POLYGON_ID_MASK = 0x3F << POLYGON_ATTR_POLYGON_ID_BIT +}; + +// TEXTURE PARAMETERS - BIT LOCATIONS +enum +{ + TEXTURE_PARAM_VRAM_OFFSET_BIT = 0, // Bits 0 - 15 + TEXTURE_PARAM_ENABLE_REPEAT_S_BIT = 16, + TEXTURE_PARAM_ENABLE_REPEAT_T_BIT = 17, + TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_S_BIT = 18, + TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_T_BIT = 19, + TEXTURE_PARAM_SIZE_S_BIT = 20, // Bits 20 - 22 + TEXTURE_PARAM_SIZE_T_BIT = 23, // Bits 23 - 25 + TEXTURE_PARAM_FORMAT_BIT = 26, // Bits 26 - 28 + TEXTURE_PARAM_ENABLE_TRANSPARENT_COLOR0_BIT = 29, + TEXTURE_PARAM_COORD_TRANSFORM_MODE_BIT = 30 // Bits 30 - 31 +}; + +// TEXTURE PARAMETERS - BIT MASKS +enum +{ + TEXTURE_PARAM_VRAM_OFFSET_MASK = 0xFFFF << TEXTURE_PARAM_VRAM_OFFSET_BIT, + TEXTURE_PARAM_ENABLE_REPEAT_S_MASK = 0x01 << TEXTURE_PARAM_ENABLE_REPEAT_S_BIT, + TEXTURE_PARAM_ENABLE_REPEAT_T_MASK = 0x01 << TEXTURE_PARAM_ENABLE_REPEAT_T_BIT, + TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_S_MASK = 0x01 << TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_S_BIT, + TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_T_MASK = 0x01 << TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_T_BIT, + TEXTURE_PARAM_SIZE_S_MASK = 0x07 << TEXTURE_PARAM_SIZE_S_BIT, + TEXTURE_PARAM_SIZE_T_MASK = 0x07 << TEXTURE_PARAM_SIZE_T_BIT, + TEXTURE_PARAM_FORMAT_MASK = 0x07 << TEXTURE_PARAM_FORMAT_BIT, + TEXTURE_PARAM_ENABLE_TRANSPARENT_COLOR0_MASK = 0x01 << TEXTURE_PARAM_ENABLE_TRANSPARENT_COLOR0_BIT, + TEXTURE_PARAM_COORD_TRANSFORM_MODE_MASK = 0x03 << TEXTURE_PARAM_COORD_TRANSFORM_MODE_BIT +}; + +// TEXTURE PARAMETERS - FORMAT ID +enum +{ + TEXMODE_NONE = 0, + TEXMODE_A3I5 = 1, + TEXMODE_I2 = 2, + TEXMODE_I4 = 3, + TEXMODE_I8 = 4, + TEXMODE_4X4 = 5, + TEXMODE_A5I3 = 6, + TEXMODE_16BPP = 7 +}; void gfx3d_init(); void gfx3d_reset(); @@ -134,6 +209,43 @@ void gfx3d_reset(); #define OSWRITE(x) os->fwrite((char*)&(x),sizeof((x))); #define OSREAD(x) is->fread((char*)&(x),sizeof((x))); +typedef struct +{ + u8 enableLightFlags; + bool enableLight0; + bool enableLight1; + bool enableLight2; + bool enableLight3; + u8 polygonMode; + u8 surfaceCullingMode; + bool enableRenderBackSurface; + bool enableRenderFrontSurface; + bool enableAlphaDepthWrite; + bool enableRenderOnFarPlaneIntersect; + bool enableRenderOneDot; + bool enableDepthTest; + bool enableRenderFog; + bool isWireframe; + bool isOpaque; + bool isTranslucent; + u8 alpha; + u8 polygonID; +} PolygonAttributes; + +typedef struct +{ + u16 VRAMOffset; + bool enableRepeatS; + bool enableRepeatT; + bool enableMirroredRepeatS; + bool enableMirroredRepeatT; + u8 sizeS; + u8 sizeT; + u8 texFormat; + bool enableTransparentColor0; + u8 coordTransformMode; +} PolygonTexParams; + struct POLY { int type; //tri or quad u8 vtxFormat; @@ -150,24 +262,215 @@ struct POLY { if(d != -1) { vertIndexes[3] = d; type = 4; } else type = 3; } - + + u8 getAttributeEnableLightFlags() + { + return ((polyAttr & (POLYGON_ATTR_ENABLE_LIGHT0_MASK | + POLYGON_ATTR_ENABLE_LIGHT1_MASK | + POLYGON_ATTR_ENABLE_LIGHT2_MASK | + POLYGON_ATTR_ENABLE_LIGHT3_MASK)) >> POLYGON_ATTR_ENABLE_LIGHT0_BIT); + } + + bool getAttributeEnableLight0() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT0_MASK) > 0); + } + + bool getAttributeEnableLight1() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT1_MASK) > 0); + } + + bool getAttributeEnableLight2() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT2_MASK) > 0); + } + + bool getAttributeEnableLight3() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_LIGHT3_MASK) > 0); + } + + u8 getAttributePolygonMode() + { + return ((polyAttr & POLYGON_ATTR_MODE_MASK) >> POLYGON_ATTR_MODE_BIT); + } + + u8 getAttributeEnableFaceCullingFlags() + { + return ((polyAttr & (POLYGON_ATTR_ENABLE_BACK_SURFACE_MASK | + POLYGON_ATTR_ENABLE_FRONT_SURFACE_MASK)) >> POLYGON_ATTR_ENABLE_BACK_SURFACE_BIT); + } + + bool getAttributeEnableBackSurface() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_BACK_SURFACE_MASK) > 0); + } + + bool getAttributeEnableFrontSurface() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_FRONT_SURFACE_MASK) > 0); + } + + bool getAttributeEnableAlphaDepthWrite() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_ALPHA_DEPTH_WRITE_MASK) > 0); + } + + bool getAttributeEnableRenderOnFarPlaneIntersect() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_RENDER_ON_FAR_PLANE_INTERSECT_MASK) > 0); + } + + bool getAttributeEnableOneDotRender() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_ONE_DOT_RENDER_MASK) > 0); + } + + bool getAttributeEnableDepthTest() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_DEPTH_TEST_MASK) > 0); + } + + bool getAttributeEnableFog() + { + return ((polyAttr & POLYGON_ATTR_ENABLE_FOG_MASK) > 0); + } + + u8 getAttributeAlpha() + { + return ((polyAttr & POLYGON_ATTR_ALPHA_MASK) >> POLYGON_ATTR_ALPHA_BIT); + } + + u8 getAttributePolygonID() + { + return ((polyAttr & POLYGON_ATTR_POLYGON_ID_MASK) >> POLYGON_ATTR_POLYGON_ID_BIT); + } + + PolygonAttributes getAttributes() + { + PolygonAttributes theAttr; + + theAttr.enableLightFlags = this->getAttributeEnableLightFlags(); + theAttr.enableLight0 = this->getAttributeEnableLight0(); + theAttr.enableLight1 = this->getAttributeEnableLight1(); + theAttr.enableLight2 = this->getAttributeEnableLight2(); + theAttr.enableLight3 = this->getAttributeEnableLight3(); + theAttr.polygonMode = this->getAttributePolygonMode(); + theAttr.surfaceCullingMode = this->getAttributeEnableFaceCullingFlags(); + theAttr.enableRenderBackSurface = this->getAttributeEnableBackSurface(); + theAttr.enableRenderFrontSurface = this->getAttributeEnableFrontSurface(); + theAttr.enableAlphaDepthWrite = this->getAttributeEnableAlphaDepthWrite(); + theAttr.enableRenderOnFarPlaneIntersect = this->getAttributeEnableRenderOnFarPlaneIntersect(); + theAttr.enableRenderOneDot = this->getAttributeEnableOneDotRender(); + theAttr.enableDepthTest = this->getAttributeEnableDepthTest(); + theAttr.enableRenderFog = this->getAttributeEnableFog(); + theAttr.alpha = this->getAttributeAlpha(); + theAttr.isWireframe = this->isWireframe(); + theAttr.isOpaque = this->isOpaque(); + theAttr.isTranslucent = this->isTranslucent(); + theAttr.polygonID = this->getAttributePolygonID(); + + return theAttr; + } + + u16 getTexParamVRAMOffset() + { + return ((texParam & TEXTURE_PARAM_VRAM_OFFSET_MASK) >> TEXTURE_PARAM_VRAM_OFFSET_BIT); + } + + bool getTexParamEnableRepeatS() + { + return ((texParam & TEXTURE_PARAM_ENABLE_REPEAT_S_MASK) > 0); + } + + bool getTexParamEnableRepeatT() + { + return ((texParam & TEXTURE_PARAM_ENABLE_REPEAT_T_MASK) > 0); + } + + bool getTexParamEnableMirroredRepeatS() + { + return ((texParam & TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_S_MASK) > 0); + } + + bool getTexParamEnableMirroredRepeatT() + { + return ((texParam & TEXTURE_PARAM_ENABLE_MIRRORED_REPEAT_T_MASK) > 0); + } + + u8 getTexParamSizeS() + { + return ((texParam & TEXTURE_PARAM_SIZE_S_MASK) >> TEXTURE_PARAM_SIZE_S_BIT); + } + + u8 getTexParamSizeT() + { + return ((texParam & TEXTURE_PARAM_SIZE_T_MASK) >> TEXTURE_PARAM_SIZE_T_BIT); + } + + u8 getTexParamTexFormat() + { + return ((texParam & TEXTURE_PARAM_FORMAT_MASK) >> TEXTURE_PARAM_FORMAT_BIT); + } + + bool getTexParamEnableTransparentColor0() + { + return ((texParam & TEXTURE_PARAM_ENABLE_TRANSPARENT_COLOR0_MASK) > 0); + } + + u8 getTexParamCoordTransformMode() + { + return ((texParam & TEXTURE_PARAM_COORD_TRANSFORM_MODE_MASK) >> TEXTURE_PARAM_COORD_TRANSFORM_MODE_BIT); + } + + PolygonTexParams getTexParams() + { + PolygonTexParams theTexParams; + + theTexParams.VRAMOffset = this->getTexParamVRAMOffset(); + theTexParams.enableRepeatS = this->getTexParamEnableRepeatS(); + theTexParams.enableRepeatT = this->getTexParamEnableRepeatT(); + theTexParams.enableMirroredRepeatS = this->getTexParamEnableMirroredRepeatS(); + theTexParams.enableMirroredRepeatT = this->getTexParamEnableMirroredRepeatT(); + theTexParams.sizeS = this->getTexParamSizeS(); + theTexParams.sizeT = this->getTexParamSizeT(); + theTexParams.texFormat = this->getTexParamTexFormat(); + theTexParams.enableTransparentColor0 = this->getTexParamEnableTransparentColor0(); + theTexParams.coordTransformMode = this->getTexParamCoordTransformMode(); + + return theTexParams; + } + + bool isWireframe() + { + return (this->getAttributeAlpha() == 0); + } + + bool isOpaque() + { + return (this->getAttributeAlpha() == 31); + } + bool isTranslucent() { - //alpha != 31 -> translucent - //except for alpha 0 which is wireframe (unless it has a translucent tex) - if((polyAttr&0x001F0000) != 0x001F0000 && (polyAttr&0x001F0000) != 0) + // First, check if the polygon is wireframe or opaque. + // If neither, then it must be translucent. + if (!this->isWireframe() && !this->isOpaque()) + { return true; - int texFormat = (texParam>>26)&7; - + } + + // Also check for translucent texture format. + u8 texFormat = this->getTexParamTexFormat(); + //a5i3 or a3i5 -> translucent - if(texFormat==1 || texFormat==6) + if(texFormat == TEXMODE_A3I5 || texFormat == TEXMODE_A5I3) return true; return false; } - int getAlpha() { return (polyAttr>>16)&0x1F; } - void save(EMUFILE* os) { OSWRITE(type); diff --git a/desmume/src/shaders.h b/desmume/src/shaders.h index 3d89d3a93..f60f10d9a 100644 --- a/desmume/src/shaders.h +++ b/desmume/src/shaders.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2008-2011 DeSmuME team + Copyright (C) 2008-2012 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,12 +19,26 @@ /* Vertex shader */ const char *vertexShader = {"\ + uniform float polyAlpha; \n\ + uniform vec2 texScale; \n\ varying vec4 pos; \n\ + varying vec4 vtxColor; \n\ void main() \n\ { \n\ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n\ - gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; \n\ - gl_FrontColor = gl_Color; \n\ + mat4 projectionMtx = mat4( vec4(1.0, 0.0, 0.0, 0.0), \n\ + vec4(0.0, 1.0, 0.0, 0.0), \n\ + vec4(0.0, 0.0, 1.0, 0.0), \n\ + vec4(0.0, 0.0, 0.0, 1.0));\n\ + \n\ + mat4 texScaleMtx = mat4( vec4(texScale.x, 0.0, 0.0, 0.0), \n\ + vec4( 0.0, texScale.y, 0.0, 0.0), \n\ + vec4( 0.0, 0.0, 1.0, 0.0), \n\ + vec4( 0.0, 0.0, 0.0, 1.0)); \n\ + \n\ + vtxColor = vec4(gl_Color.rgb * 4.0, polyAlpha); \n\ + gl_Position = projectionMtx * gl_Vertex; \n\ + gl_TexCoord[0] = texScaleMtx * gl_MultiTexCoord0; \n\ + gl_FrontColor = vtxColor; \n\ pos = gl_Position; \n\ } \n\ "}; @@ -37,6 +51,7 @@ const char *fragmentShader = {"\ uniform int texBlending; \n\ uniform int oglWBuffer; \n\ varying vec4 pos; \n\ + varying vec4 vtxColor; \n\ void main() \n\ { \n\ vec4 texColor = vec4(1.0, 1.0, 1.0, 1.0); \n\ @@ -49,33 +64,33 @@ const char *fragmentShader = {"\ flagColor = texColor; \n\ if(texBlending == 0) \n\ { \n\ - flagColor = gl_Color * texColor; \n\ + flagColor = vtxColor * texColor; \n\ } \n\ else \n\ if(texBlending == 1) \n\ { \n\ if (texColor.a == 0.0 || hasTexture == 0) \n\ - flagColor.rgb = gl_Color.rgb;\n\ + flagColor.rgb = vtxColor.rgb;\n\ else \n\ if (texColor.a == 1.0) \n\ flagColor.rgb = texColor.rgb;\n\ else \n\ - flagColor.rgb = texColor.rgb * (1.0-texColor.a) + gl_Color.rgb * texColor.a;\n\ - flagColor.a = gl_Color.a; \n\ + flagColor.rgb = texColor.rgb * (1.0-texColor.a) + vtxColor.rgb * texColor.a;\n\ + flagColor.a = vtxColor.a; \n\ } \n\ else \n\ if(texBlending == 2) \n\ { \n\ - vec3 toonColor = vec3(texture1D(toonTable, gl_Color.r).rgb); \n\ + vec3 toonColor = vec3(texture1D(toonTable, vtxColor.r).rgb); \n\ flagColor.rgb = texColor.rgb * toonColor.rgb;\n\ - flagColor.a = texColor.a * gl_Color.a;\n\ + flagColor.a = texColor.a * vtxColor.a;\n\ } \n\ else \n\ if(texBlending == 3) \n\ { \n\ - vec3 toonColor = vec3(texture1D(toonTable, gl_Color.r).rgb); \n\ - flagColor.rgb = texColor.rgb * gl_Color.rgb + toonColor.rgb; \n\ - flagColor.a = texColor.a * gl_Color.a; \n\ + vec3 toonColor = vec3(texture1D(toonTable, vtxColor.r).rgb); \n\ + flagColor.rgb = texColor.rgb * vtxColor.rgb + toonColor.rgb; \n\ + flagColor.a = texColor.a * vtxColor.a; \n\ } \n\ if (oglWBuffer == 1) \n\ // TODO \n\