From 23a7356fb8c335fa5c9fd647ad8063b37fa7d1ef Mon Sep 17 00:00:00 2001 From: Jens Hemprich <31758696+jenshemprich@users.noreply.github.com> Date: Mon, 4 Jun 2007 11:13:28 +0000 Subject: [PATCH] Cleanup, refactoring, state update, optimisations --- MacGLide/OpenGLide/Framebuffer.cpp | 2 +- MacGLide/OpenGLide/Framebuffer.h | 15 +- MacGLide/OpenGLide/GLExtensions.cpp | 11 +- MacGLide/OpenGLide/GLRender.cpp | 2 +- MacGLide/OpenGLide/GLRenderUpdateState.cpp | 712 +-------------------- MacGLide/OpenGLide/GLRenderUpdateState.h | 6 - MacGLide/OpenGLide/GlOgl.h | 67 +- MacGLide/OpenGLide/GlideFramebuffer.cpp | 45 +- MacGLide/OpenGLide/GlideFramebuffer.h | 2 +- MacGLide/OpenGLide/PGTexture.cpp | 168 +++-- MacGLide/OpenGLide/PGUTexture.cpp | 22 +- MacGLide/OpenGLide/grguBuffer.cpp | 4 + MacGLide/OpenGLide/grguTex.cpp | 54 +- 13 files changed, 189 insertions(+), 921 deletions(-) diff --git a/MacGLide/OpenGLide/Framebuffer.cpp b/MacGLide/OpenGLide/Framebuffer.cpp index 633622d..37d38fe 100644 --- a/MacGLide/OpenGLide/Framebuffer.cpp +++ b/MacGLide/OpenGLide/Framebuffer.cpp @@ -1 +1 @@ -//************************************************************** //* OpenGLide - Glide to OpenGL Wrapper //* http://openglide.sourceforge.net //* //* framebuffer emulation //* //* OpenGLide is OpenSource under LGPL license //* Mac version and additional features by Jens-Olaf Hemprich //************************************************************** #include "Framebuffer.h" #include "Glide.h" #include "GlideApplication.h" #include "GlideSettings.h" #include "GLRender.h" #include "GLRenderUpdateState.h" #include "GLColorAlphaCombineEnvTables.h" // check if tile needs to be displayed #define CHECK_RENDER_TILE // Display small dots at opposite corners of rendered framebuffer tiles //#define DEBUG_TILE_RENDERING Framebuffer::Framebuffer() : m_x_step_start(0) , m_y_step_start(0) , m_x_step_start_opaque(0) , m_y_step_start_opaque(0) , m_width(0) , m_height(0) , m_framebuffer(NULL) , m_texbuffer(NULL) , m_origin(GR_ORIGIN_UPPER_LEFT) , m_glInternalFormat(-1) , m_glFormat(-1) , m_glType(-1) , m_glDepth(1.0f) , m_format_valid(false) , m_useRectangleARB(false) , m_must_clear_buffer(true) , m_custom_tilesizes(NULL) { } Framebuffer::~Framebuffer() { } inline int Framebuffer::getTileCount() const { return InternalConfig.EXT_compiled_vertex_array ? m_tilesizesCount + m_customtilesizesCount : s_maxTiles; } bool Framebuffer::initialise_buffers(BufferStruct* framebuffer, BufferStruct* texbuffer, FxU32 width, FxU32 height, const tilesize* tilesizetable) { #ifdef OGL_FRAMEBUFFER GlideMsg( "GlideFrameBuffer::initialise_buffers(---, ---, %d, %d, ---)\n", width, height); #endif m_custom_tilesizes = tilesizetable; return initialise_buffers(framebuffer, texbuffer, width, height, 0, 0); } bool Framebuffer::initialise_buffers(BufferStruct* framebuffer, BufferStruct* texbuffer, FxU32 width, FxU32 height, FxU32 x_tile, FxU32 y_tile) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::initialise_buffers(---, ---, %d, %d, %d, %d)\n", width, height, x_tile, y_tile); #endif m_framebuffer = framebuffer; m_texbuffer = texbuffer; m_framebuffer->WriteMode = m_texbuffer->WriteMode = GR_LFBWRITEMODE_UNUSED; m_width = width; m_height = height; // find out largest texture size GLint tile_size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &tile_size); m_x_step_start_opaque = tile_size; m_y_step_start_opaque = tile_size; m_x_step_start = min(tile_size, x_tile); m_y_step_start = min(tile_size, y_tile); m_x_step_start = max(16, m_x_step_start); m_y_step_start = max(16, m_y_step_start); m_useRectangleARB = InternalConfig.ARB_texture_rectangle && InternalConfig.EXT_compiled_vertex_array; // If a game has its own tilesize table, use // the largest tiles for opaque renderings GLint y_step = y_tile == 0 ? m_y_step_start_opaque : m_y_step_start; // init default/opaque tilesize table int w = 0; for(FxU32 y = 0; y < m_height && w < MaxTiles ; y += y_step, w++) { while (m_height - y < y_step) { y_step = y_step >> 1; } m_tilesizes[w].y = y_step; GLint x_step = x_tile == 0 ? m_x_step_start_opaque : m_x_step_start; int v = 0; for(FxU32 x = 0; x < m_width && v < MaxTiles; x += x_step, v++ ) { while (m_width - x < x_step) { x_step = x_step >> 1; } m_tilesizes[w].x[v] = x_step; } } if (InternalConfig.EXT_compiled_vertex_array) { // Generate tile coordinate arrays m_tilesizesVertexArrayIndex = OGLRender.FrameBufferStartIndex; m_tilesizesCount = buildVertexArrays(&m_tilesizes[0], m_tilesizesVertexArrayIndex); if (m_custom_tilesizes) { m_customtilesizesVertexArrayIndex = m_tilesizesVertexArrayIndex + m_tilesizesCount * 2; m_customtilesizesCount = buildVertexArrays(m_custom_tilesizes, m_customtilesizesVertexArrayIndex); } else { m_customtilesizesCount = 0; } } // The texture priority is set to maximum // because of the altivec checksum feature const GLfloat priority = 1.0f; const int tileCount = getTileCount(); glGenTextures(tileCount, &m_textureNames[0]); glPrioritizeTextures(tileCount, &m_textureNames[0], &priority); for(int i = 0; i < tileCount; i++) { const GLenum textureTarget = m_useRectangleARB ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; glBindTexture(textureTarget, m_textureNames[i]); glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } // Don't set the checksum to 0, as this would cause white screen in Carmageddon // because fully black tiles also have a 0 checksum and no texture data would be // downloaded at all (and the tile would be rendered as if TEXTURE_2D was disabled) memset(m_tileChecksums, 0xff, sizeof(vector unsigned long) * tileCount); return m_width > 0 && m_height > 0 && m_x_step_start > 0 && m_y_step_start > 0 && m_format_valid; } void Framebuffer::free_buffers() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::free_buffers()\n"); #endif if (m_tilesizes) FreeObject(m_tilesizes); glDeleteTextures(getTileCount(), &m_textureNames[0]); } void Framebuffer::initialise_format(GrLfbWriteMode_t writemode) { #if defined(OGL_PART_DONE) || defined(OGL_FRAMEBUFFER) GlideMsg("Framebuffer::initialise_format(0x%x)\n", writemode); #endif // Enlarge buffer? if (writemode >= GR_LFBWRITEMODE_888 && (m_framebuffer->WriteMode < GR_LFBWRITEMODE_888 || m_framebuffer->WriteMode == GR_LFBWRITEMODE_UNUSED) && m_framebuffer->Address) { // Delete existing buffer FreeFrameBuffer(m_framebuffer->Address); m_framebuffer->Address = NULL; m_texbuffer->Address = NULL; } // Allocate 32-bit buffer (16bit buffer has been allocated in grSstWinOpen() if (m_framebuffer->Address == NULL) { const unsigned long openglpixels = OpenGL.WindowWidth * OpenGL.WindowHeight; // Framebuffer can be written to with 16bit or 32bit data const unsigned long buffertypesize = (writemode >= GR_LFBWRITEMODE_888) ? sizeof(FxU32) : sizeof(FxU16); Glide.FrameBuffer.Address = (FxU16*) AllocFrameBuffer(Glide.WindowTotalPixels * buffertypesize + openglpixels * sizeof(FxU32), 1); Glide.TempBuffer.Address = &Glide.FrameBuffer.Address[Glide.WindowTotalPixels * buffertypesize >> 1]; memset(Glide.FrameBuffer.Address, 0, Glide.WindowTotalPixels * buffertypesize); memset(Glide.TempBuffer.Address, 0, openglpixels * sizeof(FxU32)); } m_framebuffer->WriteMode = writemode; m_glInternalFormat = 4; m_glFormat = GL_RGBA; m_glType = GL_UNSIGNED_BYTE; FxU16 chromakeyvalue; switch (writemode) { case GR_LFBWRITEMODE_565: chromakeyvalue = s_GlideApplication.GetType() == GlideApplication::Carmageddon ? 0x1f1f : 0x07ff; m_format_valid = true; break; case GR_LFBWRITEMODE_1555: chromakeyvalue = 0x03ff; m_format_valid = true; break; case GR_LFBWRITEMODE_888: chromakeyvalue = 0x7ffdfeff; m_format_valid = true; break; default: chromakeyvalue = 0x0; m_format_valid = false; break; } // When the chromakeyvalue changes, the buffer has to be cleared if (chromakeyvalue != m_ChromaKey.Scalar) { SetChromaKeyValue(chromakeyvalue); m_must_clear_buffer = true; } } bool Framebuffer::begin_write() { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::begin_write()\n"); #endif if (m_must_clear_buffer) { Clear(); m_must_clear_buffer = false; } return true; } void Framebuffer::Clear() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::Clear()\n"); #endif const FxU16 chromakey = GetChromaKeyValue(); const FxU32 count = m_width * m_height ; FxU16* framebuffer = m_framebuffer->Address; for ( int i = 0; i < count; i++) { framebuffer[i] = chromakey; } } bool Framebuffer::end_write(FxU32 alpha, GLfloat depth, bool pixelpipeline) { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::end_write(%d, %f, %d)\n", alpha, depth, pixelpipeline); #endif m_glDepth = depth; #ifdef __ALTIVEC__ for(int i = 0; i < 4; i++) { (&m_glAlpha.Scalar)[i] = alpha; } #else m_glAlpha.Scalar = alpha; #endif // if all pixels are invisible, nothing must be rendered. // The pixel conversion functions assume alpha is != 0 in order // to determine if a tile contains any pixels to be rendered. if (m_glAlpha.Scalar == 0) return false; set_gl_state(pixelpipeline); if (InternalConfig.EXT_compiled_vertex_array) { if (m_custom_tilesizes) { drawCompiledVertexArrays(m_custom_tilesizes, m_customtilesizesVertexArrayIndex, m_customtilesizesCount, pixelpipeline); } else { drawCompiledVertexArrays(m_tilesizes, m_tilesizesVertexArrayIndex, m_tilesizesCount, pixelpipeline); } } else { const tilesize* tilesizes = m_custom_tilesizes ? m_custom_tilesizes : m_tilesizes; draw(tilesizes, pixelpipeline); } restore_gl_state(pixelpipeline); return true; } bool Framebuffer::end_write(FxU32 alpha) { #ifdef OGL_DONE GlideMsg("Framebuffer::end_write(%d)\n", alpha); #endif // draw frame buffer // @todo: Depth should OpenGL.ZNear, but that breaks overlays in Myth FxBool result = end_write(alpha, 0.0, false); return result; } bool Framebuffer::end_write() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::end_write( )\n" ); #endif return end_write(0x000000ff); } bool Framebuffer::end_write_opaque() { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::end_write_opaque()\n"); #endif // @todo: Depth should OpenGL.ZNear, but that breaks overlays in Myth return end_write(0x000000ff, 0.0, false); } void Framebuffer::set_gl_state(bool pixelpipeline) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::set_gl_state(%d)\n", pixelpipeline); #endif glReportErrors("Framebuffer::set_gl_state"); VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); // Disable the cull mode glDisable(GL_CULL_FACE); // Disable clip volume hint manually to avoid recursion if (InternalConfig.EXT_clip_volume_hint && OpenGL.ClipVerticesEnabledState) { glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); } if (pixelpipeline) { if (OpenGL.ColorAlphaUnit2) { // Pixelpipeline support for env cobine based rendering: // Framebuffer pixels must be routed through the coloralpha unit // as if they were produced by the vertex iterators without an // additional GL texture unit -> source must be changed accordingly m_bRestoreColorCombine = false; if (Glide.State.ColorCombineLocal == GR_COMBINE_LOCAL_ITERATED) { Glide.State.ColorCombineLocal = GR_COMBINE_LOCAL_PIXELPIPELINE; m_bRestoreColorCombine = true; } if (Glide.State.ColorCombineOther == GR_COMBINE_OTHER_ITERATED) { Glide.State.ColorCombineOther = GR_COMBINE_OTHER_PIXELPIPELINE; m_bRestoreColorCombine = true; } if (m_bRestoreColorCombine) SetColorCombineState(); m_bRestoreAlphaCombine = false; if (Glide.State.AlphaLocal == GR_COMBINE_LOCAL_ITERATED) { Glide.State.AlphaLocal = GR_COMBINE_LOCAL_PIXELPIPELINE; m_bRestoreAlphaCombine = true; } if (Glide.State.AlphaOther == GR_COMBINE_OTHER_ITERATED) { Glide.State.AlphaOther = GR_COMBINE_OTHER_PIXELPIPELINE; m_bRestoreAlphaCombine = true; } if (m_bRestoreAlphaCombine) SetAlphaCombineState(); // Update the opengl state for the pixel pipeline RenderUpdateState(); // If the write mode doesn't provide alpha then m_glAlpha is used // as the constant alpha value, and we can use the alpha test // to mask out chromakey pixels switch (m_framebuffer->WriteMode) { case GR_LFBWRITEMODE_565: case GR_LFBWRITEMODE_888: glEnable(GL_ALPHA_TEST); const GLenum alphaTestFunction = GL_EQUAL; const GLfloat alphaTestReferenceValue= m_glAlpha.Scalar * D1OVER255; OpenGL.AlphaTestFunction = alphaTestFunction; OpenGL.AlphaReferenceValue = alphaTestReferenceValue; glAlphaFunc(alphaTestFunction, alphaTestReferenceValue); glReportError(); break; } if (m_useRectangleARB) { // The client texture state is already setup correctly since we just // have to enable the texture rectangle state according to the texture_2D state // (the texture_2d state is not changed when the pixelpipeline mode is active) const GLenum textureTarget = GL_TEXTURE_RECTANGLE_ARB; const bool enableColoralphaTextureUnit1 = OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0]; if (enableColoralphaTextureUnit1) { // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D glEnable(textureTarget); } if (OpenGL.ColorAlphaUnit2) { const bool enableColoralphaTextureUnit2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (enableColoralphaTextureUnit2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glEnable(textureTarget); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } } glReportError(); } } else // simple render mode { if (InternalConfig.EXT_secondary_color) { glDisable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 0, NULL); } glReportError(); } // @todo: should be here but causes overlay not to be rendered // but commenting out helps neither - framebuffer tiles show // 3D view data and are never updated again - looks weird // -> pixelpipeline in simple render mode broken - sorry folks // if (OpenGL.Texture == false) { // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } } if (m_useRectangleARB) { glEnable(GL_TEXTURE_RECTANGLE_ARB); } } // Set the origin with clipping glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (m_origin == GR_ORIGIN_LOWER_LEFT) { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMinY, Glide.State.ClipMaxY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.ClipMinY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } else { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMaxY, Glide.State.ClipMinY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.WindowHeight - OpenGL.ClipMaxY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } // The scissor rectangle is not reset, because scissor mode // is only enabled when clearing the buffer glMatrixMode(GL_MODELVIEW); glReportError(); } else { // disable blend glDisable(GL_BLEND); // disable depth buffer glDepthMask(false); // Enable colormask glColorMask( true, true, true, false); // Needed for displaying in-game menus if (Glide.State.DepthBufferMode != GR_DEPTHBUFFER_DISABLE) { glDisable(GL_DEPTH_TEST); } glEnable(GL_ALPHA_TEST); // Update state as we're calling update triggers on restore const GLenum alphaTestFunction = GL_GREATER; const GLfloat alphaTestReferenceValue= 0.0; OpenGL.AlphaTestFunction = alphaTestFunction; OpenGL.AlphaReferenceValue = alphaTestReferenceValue; glAlphaFunc(alphaTestFunction, alphaTestReferenceValue); glReportError(); // Reset the clipping window // and set the origin glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (m_origin == GR_ORIGIN_LOWER_LEFT) { glOrtho(0, Glide.WindowWidth, 0, Glide.WindowHeight, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX, OpenGL.OriginY, OpenGL.WindowWidth, OpenGL.WindowHeight); } else { glOrtho(0, Glide.WindowWidth, Glide.WindowHeight, 0, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX, OpenGL.OriginY, OpenGL.WindowWidth, OpenGL.WindowHeight); } // The scissor rectangle is not changed, because scissor mode // is only enabled when clearing the buffer glMatrixMode(GL_MODELVIEW); glReportError(); // enable framebuffer texture unit if (OpenGL.ColorAlphaUnit2) { const bool disable_coloralpha_texture_unit_2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (disable_coloralpha_texture_unit_2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.ColorAlphaUnit2); glDisableClientState(GL_TEXTURE_COORD_ARRAY); // On MacOS9 (Classic?) the texcoord pointer needs to be reset // to the default value when glLockArrays/glUnlockArrays is used glTexCoordPointer(4, GL_FLOAT, 0, NULL); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glDisable(GL_TEXTURE_2D); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } if (!(OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0])) { if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } } } else { if (InternalConfig.EXT_secondary_color) { glDisable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 0, NULL); glReportError(); } glReportError(); } if (OpenGL.Texture == false) { // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } } } if (m_useRectangleARB) { glEnable(GL_TEXTURE_RECTANGLE_ARB); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glReportError(); } // Turn off fog (unsupported for normal writes, undefined for pixelpipelined writes) if (OpenGL.FogTextureUnit) { // @todo To be tested and reviewed // Todo: Pixelpipeline needs activated texture unit because of the color/alpha inverters // so we have to leave the unit enabled and provide fog coords of 0.0 // Otherwise the unit has to be turned off if (OpenGL.Fog || Glide.State.ColorCombineInvert || Glide.State.AlphaInvert) { glActiveTextureARB(OpenGL.FogTextureUnit); if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.FogTextureUnit); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glDisable(GL_TEXTURE_2D); glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } } if (OpenGL.Fog && InternalConfig.FogMode != OpenGLideFogEmulation_None && InternalConfig.FogMode != OpenGLideFogEmulation_EnvCombine) { glDisable(GL_FOG); glReportError(); } } void Framebuffer::restore_gl_state(bool pixelpipeline) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::restore_gl_state(%d)\n", pixelpipeline); #endif glReportErrors("Framebuffer::restore_gl_state"); // Restore the cull mode switch (Glide.State.CullMode) { case GR_CULL_DISABLE: break; case GR_CULL_NEGATIVE: case GR_CULL_POSITIVE: glEnable(GL_CULL_FACE); break; } if (InternalConfig.EXT_clip_volume_hint && OpenGL.ClipVerticesEnabledState) { glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST); } // Restore the clipping window glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( Glide.State.OriginInformation == GR_ORIGIN_LOWER_LEFT ) { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMinY, Glide.State.ClipMaxY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.ClipMinY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } else { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMaxY, Glide.State.ClipMinY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.WindowHeight - OpenGL.ClipMaxY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } // The scissor rectangle is not reset, because scissor mode // is only enabled when clearing the buffer glMatrixMode( GL_MODELVIEW ); glReportError(); // Restore fog const bool enable_fog_texture_unit = OpenGL.FogTextureUnit && ((OpenGL.Fog && InternalConfig.FogMode == OpenGLideFogEmulation_EnvCombine) || Glide.State.ColorCombineInvert || Glide.State.AlphaInvert); if (enable_fog_texture_unit) { glActiveTextureARB(OpenGL.FogTextureUnit); glEnable(GL_TEXTURE_2D); // We're not using glDrawArrays to render the frame buffer, // but without disabling the client state the next texture drawn // by RenderDrawTriangles would get the wrong coordinates. // Can be observed in Carmageddon: The sky texture is rendered "too high" if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.FogTextureUnit); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(1, GL_FLOAT, 0, &OGLRender.TFog[0]); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } if (OpenGL.Fog && InternalConfig.FogMode != OpenGLideFogEmulation_None && InternalConfig.FogMode != OpenGLideFogEmulation_EnvCombine) { glEnable(GL_FOG); glReportError(); } if (pixelpipeline) { if (OpenGL.ColorAlphaUnit2) { // restore current values if (m_bRestoreColorCombine) { if (Glide.State.ColorCombineLocal == GR_COMBINE_LOCAL_PIXELPIPELINE) Glide.State.ColorCombineLocal = GR_COMBINE_LOCAL_ITERATED; if (Glide.State.ColorCombineOther == GR_COMBINE_OTHER_PIXELPIPELINE) Glide.State.ColorCombineOther = GR_COMBINE_OTHER_ITERATED; SetColorCombineState(); } if(m_bRestoreAlphaCombine) { if (Glide.State.AlphaLocal == GR_COMBINE_LOCAL_PIXELPIPELINE) Glide.State.AlphaLocal = GR_COMBINE_LOCAL_ITERATED; if (Glide.State.AlphaOther == GR_COMBINE_OTHER_PIXELPIPELINE) Glide.State.AlphaOther = GR_COMBINE_LOCAL_ITERATED; SetAlphaCombineState(); } // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D if (m_useRectangleARB) { // Disable texture rectangle (for those units it has been enabled) const GLenum textureTarget = GL_TEXTURE_RECTANGLE_ARB; const bool disableColorAlphaTextureUnit1 = OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0]; if (disableColorAlphaTextureUnit1) { glDisable(textureTarget); } if (OpenGL.ColorAlphaUnit2) { const bool disableColorAlphaTextureUnit2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (disableColorAlphaTextureUnit2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glDisable(textureTarget); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } } glReportError(); // The client texture state is already setup correctly since we just // have to adjust the texture rectangle state to the texture_2d state } switch (m_framebuffer->WriteMode) { case GR_LFBWRITEMODE_565: case GR_LFBWRITEMODE_888: SetChromaKeyAndAlphaState(); break; } } else // simple render mode { if (InternalConfig.EXT_secondary_color) { glEnable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 4 * sizeof(GLfloat), &OGLRender.TColor2[0]); } glReportError(); } if (OpenGL.Texture == false) { // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (InternalConfig.EXT_compiled_vertex_array) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); } if (!m_useRectangleARB) glDisable(GL_TEXTURE_2D); } if (m_useRectangleARB) { glDisable(GL_TEXTURE_RECTANGLE_ARB); } // Restore the previous texture environment SetColorCombineState(); } } else { // restore depth state if (OpenGL.DepthBufferWritting) { glDepthMask(true); } if (Glide.State.DepthBufferMode != GR_DEPTHBUFFER_DISABLE) { glEnable(GL_DEPTH_TEST); } // Restore colormask const bool rgb = Glide.State.ColorMask; glColorMask(rgb, rgb, rgb, Glide.State.AlphaMask); // Blend if (OpenGL.Blend) { glEnable(GL_BLEND); } glReportError(); // texture units if (OpenGL.ColorAlphaUnit2) { const bool enable_coloralpha_texture_unit_2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (enable_coloralpha_texture_unit_2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.ColorAlphaUnit2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glActiveTextureARB(OpenGL.ColorAlphaUnit1); } if (!(OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0])) { if (InternalConfig.EXT_compiled_vertex_array) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer( 4, GL_FLOAT, 0, NULL ); } if (!m_useRectangleARB) glDisable(GL_TEXTURE_2D); } // Restore the previous texture environment glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); } else { if (InternalConfig.EXT_secondary_color) { glEnable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 4 * sizeof(GLfloat), &OGLRender.TColor2[0]); } glReportError(); } if (OpenGL.Texture == false) { if (InternalConfig.EXT_compiled_vertex_array) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); } // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D and this // has already been skipped in setState if (!m_useRectangleARB) glDisable(GL_TEXTURE_2D); } // Restore the previous texture environment SetColorCombineState(); } // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D if (m_useRectangleARB) { glDisable(GL_TEXTURE_RECTANGLE_ARB); } glReportError(); // This must be a forced update because GlideState changes of ChromaKeyMode // that don't change the corresponding GL-state are filtered out ForceChromaKeyAndAlphaStateUpdate(); } glReportError(); VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); VERIFY_TEXTURE_ENABLED_STATE(); } bool Framebuffer::draw(const tilesize* tilesizetable, bool pixelpipeline) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::draw(---, %d)\n", pixelpipeline); #endif glReportErrors("Framebuffer::draw()"); bool init_second_textureunit = pixelpipeline && OpenGL.ColorAlphaUnit2; FxU32* texbuffer = reinterpret_cast(m_texbuffer->Address); // Render the tiles GLint n = 0; GLint x; GLint y = 0; GLint y_step; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; // Use unique (but always the same) name for each texture in order // to maintain the size and avoid vram memory reallocation GLint texturename = m_textureNames[n]; const TileUpdateState updateState = createTextureData(texbuffer, x, y, x_step, y_step, n); if (updateState != TileUpdateState_TileEmpty) { #ifdef DEBUG_TILE_RENDERING unsigned int color; if (updateState == TileUpdateState_TileDownloadToGPU) // edges of downloaded tiles are red color = 0xff0000ff; else // edges of rendered tiles are cyan color = 0x00ffffff; ((long*) texbuffer)[0] = ((long*) texbuffer)[1] = ((long*) texbuffer)[x_step] = ((long*) texbuffer)[x_step -1] = ((long*) texbuffer)[x_step -2] = ((long*) texbuffer)[2 * x_step -1] = ((long*) texbuffer)[(x_step - 1) * y_step] = ((long*) texbuffer)[(x_step - 1) * y_step + 1] = ((long*) texbuffer)[(x_step - 2) * y_step] = ((long*) texbuffer)[x_step * y_step - 1] = ((long*) texbuffer)[x_step * y_step - 2] = ((long*) texbuffer)[x_step * (y_step - 1) - 1] = color; #endif glBindTexture(GL_TEXTURE_2D, texturename); if (init_second_textureunit) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glBindTexture(GL_TEXTURE_2D, texturename); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } #ifndef DEBUG_TILE_RENDERING if (updateState == TileUpdateState_TileDownloadToGPU // || InternalConfig.APPLE_client_storage == false ) { glTexImage2D(GL_TEXTURE_2D, 0, m_glInternalFormat, x_step, y_step, 0, m_glFormat, m_glType, texbuffer); glReportError(); } #endif static struct { const GLfloat bl[4]; const GLfloat br[4]; const GLfloat tr[4]; const GLfloat tl[4]; } texcoords = { {0.0, 0.0, 1.0, 1.0}, {1.0, 0.0, 1.0, 1.0}, {1.0, 1.0, 1.0, 1.0}, {0.0, 1.0, 1.0, 1.0} }; glBegin(GL_QUADS); // counter clockwise glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.bl[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.bl[0]); } glVertex3f(x, y, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.br[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.br[0]); } glVertex3f(x + x_step, y, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.tr[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.tr[0]); } glVertex3f(x + x_step, y + y_step, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.tl[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.tl[0]); } glVertex3f(x, y + y_step , m_glDepth); glEnd(); glReportError(); // Advance to the next texbuffer location texbuffer += x_step * y_step; } n ++; } } s_Framebuffer.SetRenderBufferChanged(); return y == m_height && x == m_width; } bool Framebuffer::drawCompiledVertexArrays(const tilesize* tilesizetable, int vertexarrayindex, int tilecount, bool pixelpipeline) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::draw(---, %d)\n", pixelpipeline); #endif glReportErrors("Framebuffer::drawCompiledVertexArrays()"); RenderUnlockArrays(); glLockArraysEXT(vertexarrayindex * 3, tilecount * 6); glReportError(); OGLRender.BufferLocked = true; const bool init_second_textureunit = pixelpipeline && (OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]); FxU32* texbuffer = reinterpret_cast(m_texbuffer->Address); // Render the tiles GLint n = 0; GLint x; GLint y = 0; GLint y_step; const GLenum textureTarget = m_useRectangleARB ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; const TileUpdateState updateState = createTextureData(texbuffer, x, y, x_step, y_step, n); if (updateState != TileUpdateState_TileEmpty) { #ifdef DEBUG_TILE_RENDERING unsigned int color; if (updateState == TileUpdateState_TileDownloadToGPU) // edges of downloaded tiles are red color = 0xff0000ff; else // edges of rendered tiles are cyan color = 0x00ffffff; ((long*) texbuffer)[0] = ((long*) texbuffer)[1] = ((long*) texbuffer)[x_step] = ((long*) texbuffer)[x_step -1] = ((long*) texbuffer)[x_step -2] = ((long*) texbuffer)[2 * x_step -1] = ((long*) texbuffer)[x_step * (y_step - 2)] = ((long*) texbuffer)[x_step * (y_step - 1)] = ((long*) texbuffer)[x_step * (y_step - 1) + 1] = ((long*) texbuffer)[x_step * y_step - 1] = ((long*) texbuffer)[x_step * y_step - 2] = ((long*) texbuffer)[x_step * (y_step - 1) - 1] = color; #endif // Use unique (but always the same) name for each // texture in order to be able to reuse tile data const GLint texturename = m_textureNames[n]; // The texture rectangle is better suited for video, // which is close to a framebuffer if (init_second_textureunit) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glReportError(); glBindTexture(textureTarget, texturename); glReportError(); glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } glBindTexture(textureTarget, texturename); glReportError(); #ifndef DEBUG_TILE_RENDERING if (updateState == TileUpdateState_TileDownloadToGPU // || InternalConfig.APPLE_client_storage == false ) #endif { glTexImage2D(textureTarget, 0, m_glInternalFormat, x_step, y_step, 0, m_glFormat, m_glType, texbuffer); glReportError(); } // Draw the tile glDrawArrays(GL_TRIANGLES, vertexarrayindex * 3 + n * 6, 6); glReportError(); // Advance to the next texbuffer location texbuffer += x_step * y_step; } n++; } } s_Framebuffer.SetRenderBufferChanged(); return y == m_height && x == m_width; } int Framebuffer::buildVertexArrays(const tilesize* tilesizetable, int vertexarrayindex) { // Compute coordinates for compiled vertex arrays TColorStruct* pC = &OGLRender.TColor[vertexarrayindex]; TVertexStruct* pV = &OGLRender.TVertex[vertexarrayindex]; TTextureStruct* pTS = &OGLRender.TTexture[vertexarrayindex]; int n = 0; GLint y = 0; GLint y_step; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; GLint x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; // Write coordinates counter clockwise into render buffers pC->ar = pC->ag = pC->ab = pC->br = pC->bg = pC->bb = pC->cr = pC->cg = pC->cb = pC->aa = pC->ba = pC->ca = 1.0f; pV->ax = x; pV->ay = y; pV->bx = x + x_step; pV->by = y; pV->cx = x + x_step; pV->cy = y + y_step; pV->az = pV->bz = pV->cz = m_glDepth; pTS->as = 0.0; pTS->at = 0.0; pTS->bs = m_useRectangleARB ? x_step : 1.0f; pTS->bt = 0.0; pTS->cs = m_useRectangleARB ? x_step : 1.0f; pTS->ct = m_useRectangleARB ? y_step : 1.0f; pTS->aq = pTS->bq = pTS->cq = 0.0f; pTS->aoow = pTS->boow = pTS->coow = 1.0f; pC++; pV++; pTS++; pC->ar = pC->ag = pC->ab = pC->br = pC->bg = pC->bb = pC->cr = pC->cg = pC->cb = pC->aa = pC->ba = pC->ca = 1.0f; pV->ax = x + x_step; pV->ay = y + y_step; pV->bx = x; pV->by = y + y_step; pV->cx = x; pV->cy = y; pV->az = pV->bz = pV->cz = m_glDepth; pTS->as = m_useRectangleARB ? x_step : 1.0f; pTS->at = m_useRectangleARB ? y_step : 1.0f; pTS->bs = 0.0; pTS->bt = m_useRectangleARB ? y_step : 1.0f; pTS->cs = 0.0; pTS->ct = 0.0; pTS->aq = pTS->bq = pTS->cq = 0.0f; pTS->aoow = pTS->boow = pTS->coow = 1.0f; pC++; pV++; pTS++; n++; } } return n; } #ifdef __ALTIVEC__ // altivec code inline Framebuffer::TileUpdateState Framebuffer::Convert565Kto8888_AV(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride, int checksumIndex) { const vector bool short chromakey_565_av = m_ChromaKey.Vector; const int width_av = width >> 3; // 8 16-bit words const int stride_av = stride >> 3; // 8 16-bit words const int jump_av = width_av + stride_av; vector bool short* src_av = (vector bool short*) buffer1; // Setup channel 0 for reading one row of 565 ushorts from src into the L1 cache // This isn't read again soon, just written back once so we can bypass L2 cache const int src_control = (((width_av >> 4) & 0x1f) << 3) + (1 << 8) + (stride_av << 16); vec_dstt(src_av, src_control, 0); int h = height; // loop through the src to check whether anything has to be copied at all vector bool short* stop_zero_av = &src_av[width_av]; do { do { const vector bool short pixels_565_av = *src_av; if (!vec_all_eq(pixels_565_av, chromakey_565_av)) goto create_8888_texture_1_av; // Test clear first before jumping to create_8888_texture_1_av src_av++; } while (src_av != stop_zero_av); src_av += stride_av; // Update channel 0 to prefetch the next row into the L1 cache vec_dstt(src_av, src_control, 0); stop_zero_av += jump_av; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture_1_av: // Delete dst up to the last chromakey entry in src stop_zero_av = src_av; src_av = (vector bool short*) buffer1; vector unsigned long* dst_av = (vector unsigned long*) buffer2; const vector unsigned long null_av = vec_splat_u32(0); // We're just writing to dst, no reading must occur, and starting a prefetch is a bad idea h = height; vector bool short* stop_av = &src_av[width_av]; do { do { if (src_av == stop_zero_av) goto create_8888_texture_2_av; // Test clear first // clear cacheline to prevent it from being read-in (32 bytes = 2 altivec writes) // we're just clearing the cache line since we're going to write zeros anyway __dcbz(dst_av, 0); dst_av += 2; src_av++; } while (src_av != stop_av); src_av += stride_av; stop_av += jump_av; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture_2_av: // Build permute vector for storing high/lo 565 pixels into RgbxA // - results in R = r565+ggg, G = gggbbbbb, B = 0, A = glAlpha // -> good for comparison, green and blue are converted afterwards const vector unsigned char permute_hi_av = {0x00, 0x01, 0x12, 0x13, 0x02, 0x03, 0x16, 0x17, 0x04, 0x05, 0x1a, 0x1b, 0x06, 0x07, 0x1e, 0x1f}; // Computing the permute table just takes 2 instructions instead of 1 instruction + 4 memory reads const vector unsigned char permute_lo_av = vec_or(permute_hi_av, vec_splat_u8(8)); // const vector unsigned long alpha_8888_av = {m_glAlpha, m_glAlpha, m_glAlpha, m_glAlpha}; const vector unsigned long alpha_8888_av = m_glAlpha.Vector; // Build chromakey and alpha RgbxA vector const vector unsigned long chromakey_RgbxA_av = vec_perm((const vector unsigned long) chromakey_565_av, alpha_8888_av, permute_lo_av); // Constants const vector unsigned long const_3_av = vec_splat_u32(3); const vector unsigned long const_5_av = vec_splat_u32(5); // R5G6B500AA color masks const vector unsigned long mask_8888_ra = {0xf80000ff, 0xf80000ff, 0xf80000ff, 0xf80000ff}; const vector unsigned long mask_8888_g = {0x07e00000, 0x07e00000, 0x07e00000, 0x07e00000}; // Computing the mask just takes 2 instructions instead of 1 instruction + 4 memory reads const vector unsigned long mask_8888_b = vec_sr(mask_8888_ra, vec_splat_u32(11)); vector unsigned long pixels_8888_src_av; vector bool long mask; vector unsigned long p; vector unsigned long q; vector unsigned long pixels_8888_dst_av; // Checksum the tile vector unsigned long c = null_av; vector unsigned long d; // Continue the loop and convert pixels from 565 to 8888 vec_dstt(src_av, src_control, 0); do { do { const vector unsigned long pixels_565_av = (const vector unsigned long) (*src_av); // tile checksum part 1 d = vec_sr(c, const_5_av); c = vec_add(c, pixels_565_av); // restore chroma key for next update *src_av++ = chromakey_565_av; // hi-word pixels pixels_8888_src_av = vec_perm(pixels_565_av, alpha_8888_av, permute_hi_av); mask = vec_cmpeq(pixels_8888_src_av, chromakey_RgbxA_av); // Keep red and alpha component pixels_8888_dst_av = vec_and(pixels_8888_src_av, mask_8888_ra); // add green component p = vec_and(pixels_8888_src_av, mask_8888_g); q = vec_sr(p, const_3_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // add blue component p = vec_and(pixels_8888_src_av, mask_8888_b); q = vec_sr(p, const_5_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // We're just writing to dst and thus can clear the cacheline in order // to avoid the read-in from system memory (32 bytes = 2 altivec writes) // Note: This is a G4 hack, but on a G5 the code will be fast enough anyway __dcbz(dst_av, 0); // Select between pixels and chromakey *dst_av++ = vec_sel(pixels_8888_dst_av, null_av, mask); // tile checksum part 2 c = vec_xor(c, d); // lo-word pixels pixels_8888_src_av = vec_perm(pixels_565_av, alpha_8888_av, permute_lo_av); mask = vec_cmpeq(pixels_8888_src_av, chromakey_RgbxA_av); // Keep red and alpha component pixels_8888_dst_av = vec_and(pixels_8888_src_av, mask_8888_ra); // add green component p = vec_and(pixels_8888_src_av, mask_8888_g); q = vec_sr(p, const_3_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // add blue component p = vec_and(pixels_8888_src_av, mask_8888_b); q = vec_sr(p, const_5_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // Select between pixels and chromakey *dst_av++ = vec_sel(pixels_8888_dst_av, null_av, mask); } while (src_av != stop_av); src_av += stride_av; vec_dstt(src_av, src_control, 0); stop_av += jump_av; } while (--h); // Skip downloading tile data to the gpu if the content hasn't changed if (vec_all_eq(c, m_tileChecksums[checksumIndex])) return TileUpdateState_TileDrawOnly; // The tile has been converted, been changed and must be downloaded to the gpu m_tileChecksums[checksumIndex] = c; return TileUpdateState_TileDownloadToGPU; } #endif // Non-Altivec-code inline Framebuffer::TileUpdateState Framebuffer::Convert565Kto8888(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once const register unsigned long chromakey1 = m_ChromaKey.Scalar << 16; const register unsigned long chromakey2 = m_ChromaKey.Scalar; const register unsigned long chromakey12 = chromakey1 | chromakey2; width = width >> 1; stride = stride >> 1; register unsigned long pixel; register unsigned long* stop; register unsigned long jump = width + stride; register unsigned long* src = reinterpret_cast(buffer1); // check if tile must be processed in advance // to avoid useless writes to main memory // The tile should at least fit into the second level cache // so reading it again wouldn't hurt as much as doing needless writes register unsigned long h = height; stop = &src[width]; do { do { pixel = *src++; if (pixel != chromakey12) goto create_8888_texture; } while (src != stop); src += stride; stop += jump; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture: const register unsigned long alpha = m_glAlpha.Scalar; const register unsigned long null = 0x00000000; const register unsigned long mask_pixel1 = 0xffff0000; const register unsigned long mask_pixel2 = 0x0000ffff; const register unsigned long mask_pixel1_r = 0xf8000000; const register unsigned long mask_pixel1_g = 0x07e00000; const register unsigned long mask_pixel1_b = 0x001f0000; const register unsigned long mask_pixel2_r = 0x0000f800; const register unsigned long mask_pixel2_g = 0x000007e0; const register unsigned long mask_pixel2_b = 0x0000001f; src = reinterpret_cast(buffer1); stop = &src[width]; do { do { // GL_RGBA pixel = *src; if (pixel == chromakey12) { *buffer2++ = null; *buffer2++ = null; } else { *src = chromakey12; if ( (pixel & mask_pixel1) == chromakey1) { *buffer2++ = null; } else { *buffer2++ = ( alpha | // A ( pixel & mask_pixel1_b ) >> 5 | // B ( pixel & mask_pixel1_g ) >> 3 | // G ( pixel & mask_pixel1_r )); // R } if ( (pixel & mask_pixel2) == chromakey2) { *buffer2++ = null; } else { *buffer2++ = ( alpha | // A ( pixel & mask_pixel2_b ) << 11 | // B ( pixel & mask_pixel2_g ) << 13 | // G ( pixel & mask_pixel2_r ) << 16); // R } } src++; } while (src != stop); src += stride; stop += jump; } while (--height); return TileUpdateState_TileDownloadToGPU; } inline Framebuffer::TileUpdateState Framebuffer::Convert1555Kto8888(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once register unsigned long pixel; register unsigned long x; register unsigned long* src = reinterpret_cast(buffer1); const unsigned long null = 0x00000000; register unsigned long dstpixel = null; const register unsigned long chromakey1 = m_ChromaKey.Scalar << 16; const register unsigned long chromakey2 = m_ChromaKey.Scalar; const register unsigned long chromakey12 = chromakey1 | chromakey2; const register unsigned long alpha = m_glAlpha.Scalar; const register unsigned long mask_pixel1 = 0xffff0000; const register unsigned long mask_pixel2 = 0x0000ffff; const register unsigned long mask_pixel1_r = 0x7c000000; const register unsigned long mask_pixel1_g = 0x03e00000; const register unsigned long mask_pixel1_b = 0x001f0000; const register unsigned long mask_pixel2_r = 0x00007c00; const register unsigned long mask_pixel2_g = 0x000003e0; const register unsigned long mask_pixel2_b = 0x0000001f; width >>= 1; stride >>= 1; do { x = width; do { // GL_RGBA pixel = *src; if (pixel == chromakey12) { *buffer2++ = null; *buffer2++ = null; } else { *src = chromakey12; if ( (pixel & mask_pixel1) == chromakey1) { *buffer2++ = null; } else { dstpixel = ( alpha | // A ( pixel & mask_pixel1_b ) >> 5 | // B ( pixel & mask_pixel1_g ) >> 2 | // G ( pixel & mask_pixel1_r ) << 1); // R *buffer2++ = dstpixel; } if ( (pixel & mask_pixel2) == chromakey2) { *buffer2++ = null; } else { dstpixel = ( alpha | // A ( pixel & mask_pixel2_b ) << 11 | // B ( pixel & mask_pixel2_g ) << 14 | // G ( pixel & mask_pixel2_r ) << 17); // R *buffer2++ = dstpixel; } } src++; } while (--x); src += stride; } while (--height); return dstpixel != null ? TileUpdateState_TileDownloadToGPU : TileUpdateState_TileEmpty; } inline Framebuffer::TileUpdateState Framebuffer::ConvertARGB8888Kto8888(FxU32* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once const register unsigned long chromakey = m_ChromaKey.Scalar || (m_ChromaKey.Scalar << 16); register unsigned long pixel; register unsigned long* stop; register unsigned jump = width + stride; register unsigned long* src = buffer1; // check if tile must be processed in advance // to avoid useless writes to main memory // The tile should at least fit into the second level cache // so reading it again wouldn't hurt as much as doing needless writes register unsigned long h = height; stop = &src[width]; do { do { pixel = *src++; if (pixel != chromakey) goto create_8888_texture; } while (src != stop); src += stride; stop += jump; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture: const register unsigned long alpha = m_glAlpha.Scalar; src = buffer1; stop = &src[width]; do { do { // GL_RGBA pixel = *src; if (pixel == chromakey) { *buffer2++ = 0; } else { *src = chromakey; *buffer2++ = (pixel << 8) | alpha; } src++; } while (src != stop); src += stride; stop += jump; } while (--height); return TileUpdateState_TileDownloadToGPU; } inline Framebuffer::TileUpdateState Framebuffer::createTextureData(FxU32* texbuffer, FxU32 x, FxU32 y, FxU32 x_step, FxU32 y_step, int checksumIndex) { FxU32 stride = (m_width - x_step); FxU32 index = x + y * m_width; if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_565) { #ifdef __ALTIVEC__ if (UserConfig.VectorUnitType == OpenGLideVectorUnitType_Altivec) { #ifdef OGL_FRAMEBUFFER const vector unsigned long c = m_tileChecksums[checksumIndex]; #endif TileUpdateState state = Convert565Kto8888_AV(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride, checksumIndex); #ifdef OGL_FRAMEBUFFER GlideMsg("Tile %d (%d,%d)-(%d,%d) update state is %s (%vlx)->(%vlx)\n", checksumIndex, x, y, x_step, y_step, (state ==TileUpdateState_TileDownloadToGPU) ? "DownLoadToGPU" : ((state == TileUpdateState_TileDrawOnly) ? "DrawOnly" : "TileEmpty"), c, m_tileChecksums[checksumIndex]); #endif return state; } else #endif return Convert565Kto8888(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride); } else if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_1555) { return Convert1555Kto8888(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride); } else if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_888) { FxU32* framebuffer = &reinterpret_cast(m_framebuffer->Address)[index]; return ConvertARGB8888Kto8888(framebuffer, texbuffer, x_step, y_step, stride); } else { return TileUpdateState_TileEmpty; } } \ No newline at end of file +//************************************************************** //* OpenGLide - Glide to OpenGL Wrapper //* http://openglide.sourceforge.net //* //* framebuffer emulation //* //* OpenGLide is OpenSource under LGPL license //* Mac version and additional features by Jens-Olaf Hemprich //************************************************************** #include "Framebuffer.h" #include "Glide.h" #include "GlideApplication.h" #include "GlideSettings.h" #include "GLRender.h" #include "GLRenderUpdateState.h" #include "GLColorAlphaCombineEnvTables.h" // check if tile needs to be displayed #define CHECK_RENDER_TILE // Display small dots at opposite corners of rendered framebuffer tiles //#define DEBUG_TILE_RENDERING Framebuffer::Framebuffer() : m_x_step_start(0) , m_y_step_start(0) , m_x_step_start_opaque(0) , m_y_step_start_opaque(0) , m_width(0) , m_height(0) , m_framebuffer(NULL) , m_texbuffer(NULL) , m_origin(GR_ORIGIN_UPPER_LEFT) , m_glInternalFormat(-1) , m_glFormat(-1) , m_glType(-1) , m_glDepth(1.0f) , m_format_valid(false) , m_useRectangleARB(false) , m_must_clear_buffer(true) , m_custom_tilesizes(NULL) { } Framebuffer::~Framebuffer() { } inline int Framebuffer::getTileCount() const { return InternalConfig.EXT_compiled_vertex_array ? m_tilesizesCount + m_customtilesizesCount : s_maxTiles; } bool Framebuffer::initialise_buffers(BufferStruct* framebuffer, BufferStruct* texbuffer, FxU32 width, FxU32 height, const tilesize* tilesizetable) { #ifdef OGL_FRAMEBUFFER GlideMsg( "GlideFrameBuffer::initialise_buffers(---, ---, %d, %d, ---)\n", width, height); #endif m_custom_tilesizes = tilesizetable; return initialise_buffers(framebuffer, texbuffer, width, height, 0, 0); } bool Framebuffer::initialise_buffers(BufferStruct* framebuffer, BufferStruct* texbuffer, FxU32 width, FxU32 height, FxU32 x_tile, FxU32 y_tile) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::initialise_buffers(---, ---, %d, %d, %d, %d)\n", width, height, x_tile, y_tile); #endif m_framebuffer = framebuffer; m_texbuffer = texbuffer; m_framebuffer->WriteMode = m_texbuffer->WriteMode = GR_LFBWRITEMODE_UNUSED; m_width = width; m_height = height; // find out largest texture size GLint tile_size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &tile_size); m_x_step_start_opaque = tile_size; m_y_step_start_opaque = tile_size; m_x_step_start = min(tile_size, x_tile); m_y_step_start = min(tile_size, y_tile); m_x_step_start = max(16, m_x_step_start); m_y_step_start = max(16, m_y_step_start); m_useRectangleARB = InternalConfig.ARB_texture_rectangle && InternalConfig.EXT_compiled_vertex_array; // If a game has its own tilesize table, use // the largest tiles for opaque renderings GLint y_step = y_tile == 0 ? m_y_step_start_opaque : m_y_step_start; // init default/opaque tilesize table int w = 0; for(FxU32 y = 0; y < m_height && w < MaxTiles ; y += y_step, w++) { while (m_height - y < y_step) { y_step = y_step >> 1; } m_tilesizes[w].y = y_step; GLint x_step = x_tile == 0 ? m_x_step_start_opaque : m_x_step_start; int v = 0; for(FxU32 x = 0; x < m_width && v < MaxTiles; x += x_step, v++ ) { while (m_width - x < x_step) { x_step = x_step >> 1; } m_tilesizes[w].x[v] = x_step; } } if (InternalConfig.EXT_compiled_vertex_array) { // Generate tile coordinate arrays m_tilesizesVertexArrayIndex = OGLRender.FrameBufferStartIndex; m_tilesizesCount = buildVertexArrays(&m_tilesizes[0], m_tilesizesVertexArrayIndex); if (m_custom_tilesizes) { m_customtilesizesVertexArrayIndex = m_tilesizesVertexArrayIndex + m_tilesizesCount * 2; m_customtilesizesCount = buildVertexArrays(m_custom_tilesizes, m_customtilesizesVertexArrayIndex); } else { m_customtilesizesCount = 0; } } // The texture priority is set to maximum // because of the altivec checksum feature const GLfloat priority = 1.0f; const int tileCount = getTileCount(); glGenTextures(tileCount, &m_textureNames[0]); glPrioritizeTextures(tileCount, &m_textureNames[0], &priority); for(int i = 0; i < tileCount; i++) { const GLenum textureTarget = m_useRectangleARB ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; glBindTexture(textureTarget, m_textureNames[i]); glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } // Don't set the checksum to 0, as this would cause white screen in Carmageddon // because fully black tiles also have a 0 checksum and no texture data would be // downloaded at all (and the tile would be rendered as if TEXTURE_2D was disabled) memset(m_tileChecksums, 0xff, sizeof(vector unsigned long) * tileCount); return m_width > 0 && m_height > 0 && m_x_step_start > 0 && m_y_step_start > 0 && m_format_valid; } void Framebuffer::free_buffers() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::free_buffers()\n"); #endif if (m_tilesizes) FreeObject(m_tilesizes); glDeleteTextures(getTileCount(), &m_textureNames[0]); } void Framebuffer::initialise_format(GrLfbWriteMode_t writemode) { #if defined(OGL_PART_DONE) || defined(OGL_FRAMEBUFFER) GlideMsg("Framebuffer::initialise_format(0x%x)\n", writemode); #endif // Enlarge buffer? if (writemode >= GR_LFBWRITEMODE_888 && (m_framebuffer->WriteMode < GR_LFBWRITEMODE_888 || m_framebuffer->WriteMode == GR_LFBWRITEMODE_UNUSED) && m_framebuffer->Address) { // Delete existing buffer FreeFrameBuffer(m_framebuffer->Address); m_framebuffer->Address = NULL; m_texbuffer->Address = NULL; } // Allocate 32-bit buffer (16bit buffer has been allocated in grSstWinOpen() if (m_framebuffer->Address == NULL) { const unsigned long openglpixels = OpenGL.WindowWidth * OpenGL.WindowHeight; // Framebuffer can be written to with 16bit or 32bit data const unsigned long buffertypesize = (writemode >= GR_LFBWRITEMODE_888) ? sizeof(FxU32) : sizeof(FxU16); Glide.FrameBuffer.Address = (FxU16*) AllocFrameBuffer(Glide.WindowTotalPixels * buffertypesize + openglpixels * sizeof(FxU32), 1); Glide.TempBuffer.Address = &Glide.FrameBuffer.Address[Glide.WindowTotalPixels * buffertypesize >> 1]; memset(Glide.FrameBuffer.Address, 0, Glide.WindowTotalPixels * buffertypesize); memset(Glide.TempBuffer.Address, 0, openglpixels * sizeof(FxU32)); } m_framebuffer->WriteMode = writemode; m_glInternalFormat = 4; m_glFormat = GL_RGBA; m_glType = GL_UNSIGNED_BYTE; FxU16 chromakeyvalue; switch (writemode) { case GR_LFBWRITEMODE_565: chromakeyvalue = s_GlideApplication.GetType() == GlideApplication::Carmageddon ? 0x1f1f : 0x07ff; m_format_valid = true; break; case GR_LFBWRITEMODE_1555: chromakeyvalue = 0x03ff; m_format_valid = true; break; case GR_LFBWRITEMODE_888: chromakeyvalue = 0x7ffdfeff; m_format_valid = true; break; default: chromakeyvalue = 0x0; m_format_valid = false; break; } // When the chromakeyvalue changes, the buffer has to be cleared if (chromakeyvalue != m_ChromaKey.Scalar) { SetChromaKeyValue(chromakeyvalue); m_must_clear_buffer = true; } } bool Framebuffer::begin_write() { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::begin_write()\n"); #endif if (m_must_clear_buffer) { Clear(); m_must_clear_buffer = false; } return true; } void Framebuffer::Clear() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::Clear()\n"); #endif const FxU16 chromakey = GetChromaKeyValue(); const FxU32 count = m_width * m_height ; FxU16* framebuffer = m_framebuffer->Address; for ( int i = 0; i < count; i++) { framebuffer[i] = chromakey; } } void Framebuffer::end_write(FxU32 alpha, GLfloat depth) { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::end_write(%d, %f, %d)\n", alpha, depth); #endif m_glDepth = depth; #ifdef __ALTIVEC__ for(int i = 0; i < 4; i++) { (&m_glAlpha.Scalar)[i] = alpha; } #else m_glAlpha.Scalar = alpha; #endif // if all pixels are invisible, nothing must be rendered. // The pixel conversion functions assume alpha is != 0 in order // to determine if a tile contains any pixels to be rendered. if (m_glAlpha.Scalar != 0) { set_gl_state(); if (InternalConfig.EXT_compiled_vertex_array) { if (m_custom_tilesizes) { drawCompiledVertexArrays(m_custom_tilesizes, m_customtilesizesVertexArrayIndex, m_customtilesizesCount); } else { drawCompiledVertexArrays(m_tilesizes, m_tilesizesVertexArrayIndex, m_tilesizesCount); } } else { const tilesize* tilesizes = m_custom_tilesizes ? m_custom_tilesizes : m_tilesizes; draw(tilesizes); } restore_gl_state(); } } void Framebuffer::end_write() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::end_write( )\n" ); #endif end_write(0x000000ff, OpenGL.ZNear); } void Framebuffer::end_write_opaque() { #ifdef OGL_FRAMEBUFFER GlideMsg("Framebuffer::end_write_opaque()\n"); #endif end_write(0x000000ff, OpenGL.ZNear); } void Framebuffer::set_gl_state() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::set_gl_state()\n"); #endif glReportErrors("Framebuffer::set_gl_state"); VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); // Disable culling if (Glide.State.CullMode != GR_CULL_DISABLE) { glDisable(GL_CULL_FACE); } if (Glide.State.DitherMode != GR_DITHER_DISABLE) { // GR_DITHER_2x2 or GR_DITHER_4x4 glDisable(GL_DITHER); } // Disable clip volume hint manually to avoid recursion if (InternalConfig.EXT_clip_volume_hint && OpenGL.ClipVerticesEnabledState) { glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); glReportError(); } if (InternalConfig.FullSceneAntiAliasing > 0) { glDisable(GL_MULTISAMPLE_ARB); glReportError(); } if (m_framebuffer->PixelPipeline) { if (OpenGL.ColorAlphaUnit2) { // Pixelpipeline support for env cobine based rendering: // Framebuffer pixels must be routed through the coloralpha unit // as if they were produced by the vertex iterators without an // additional GL texture unit -> source must be changed accordingly m_bRestoreColorCombine = false; if (Glide.State.ColorCombineLocal == GR_COMBINE_LOCAL_ITERATED) { Glide.State.ColorCombineLocal = GR_COMBINE_LOCAL_PIXELPIPELINE; m_bRestoreColorCombine = true; } if (Glide.State.ColorCombineOther == GR_COMBINE_OTHER_ITERATED) { Glide.State.ColorCombineOther = GR_COMBINE_OTHER_PIXELPIPELINE; m_bRestoreColorCombine = true; } if (m_bRestoreColorCombine) SetColorCombineState(); m_bRestoreAlphaCombine = false; if (Glide.State.AlphaLocal == GR_COMBINE_LOCAL_ITERATED) { Glide.State.AlphaLocal = GR_COMBINE_LOCAL_PIXELPIPELINE; m_bRestoreAlphaCombine = true; } if (Glide.State.AlphaOther == GR_COMBINE_OTHER_ITERATED) { Glide.State.AlphaOther = GR_COMBINE_OTHER_PIXELPIPELINE; m_bRestoreAlphaCombine = true; } if (m_bRestoreAlphaCombine) SetAlphaCombineState(); // Update the opengl state for the pixel pipeline RenderUpdateState(); // If the write mode doesn't provide alpha then m_glAlpha is used // as the constant alpha value, and we can use the alpha test // to mask out chromakey pixels switch (m_framebuffer->WriteMode) { case GR_LFBWRITEMODE_565: case GR_LFBWRITEMODE_888: glEnable(GL_ALPHA_TEST); const GLenum alphaTestFunction = GL_EQUAL; const GLfloat alphaTestReferenceValue= m_glAlpha.Scalar * D1OVER255; OpenGL.AlphaTestFunction = alphaTestFunction; OpenGL.AlphaReferenceValue = alphaTestReferenceValue; glAlphaFunc(alphaTestFunction, alphaTestReferenceValue); glReportError(); break; } if (m_useRectangleARB) { // The client texture state is already setup correctly since we just // have to enable the texture rectangle state according to the texture_2D state // (the texture_2d state is not changed when the pixelpipeline mode is active) const GLenum textureTarget = GL_TEXTURE_RECTANGLE_ARB; const bool enableColoralphaTextureUnit1 = OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0]; if (enableColoralphaTextureUnit1) { // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D glEnable(textureTarget); } if (OpenGL.ColorAlphaUnit2) { const bool enableColoralphaTextureUnit2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (enableColoralphaTextureUnit2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glEnable(textureTarget); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } } glReportError(); } } else // simple render mode { if (InternalConfig.EXT_secondary_color) { glDisable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 0, NULL); } glReportError(); } // @todo: framebuffer tiles show 3D view data instead of HUD/cockpit // and are never updated - looks weird // -> pixelpipeline in simple render mode broken - sorry folks // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } if (m_useRectangleARB) { glEnable(GL_TEXTURE_RECTANGLE_ARB); } } // Set the origin with clipping glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (m_origin == GR_ORIGIN_LOWER_LEFT) { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMinY, Glide.State.ClipMaxY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.ClipMinY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } else { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMaxY, Glide.State.ClipMinY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.WindowHeight - OpenGL.ClipMaxY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } // The scissor rectangle is not reset, because scissor mode // is only enabled when clearing the buffer glMatrixMode(GL_MODELVIEW); glReportError(); } else { // disable blend glDisable(GL_BLEND); // disable depth buffer if (OpenGL.DepthBufferWritting) { glDepthMask(false); } // Needed for displaying in-game menus if (Glide.State.DepthBufferMode != GR_DEPTHBUFFER_DISABLE) { glDisable(GL_DEPTH_TEST); } // Enable colormask // @todo: check whether disabling is necessary glColorMask(true, true, true, false); // @todo: check whether enabling is necessary glEnable(GL_ALPHA_TEST); // Update GL state as we're calling update triggers on restore const GLenum alphaTestFunction = GL_GREATER; const GLfloat alphaTestReferenceValue= 0.0; OpenGL.AlphaTestFunction = alphaTestFunction; OpenGL.AlphaReferenceValue = alphaTestReferenceValue; glAlphaFunc(alphaTestFunction, alphaTestReferenceValue); glReportError(); // Reset the clipping window // and set the origin glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (m_origin == GR_ORIGIN_LOWER_LEFT) { glOrtho(0, Glide.WindowWidth, 0, Glide.WindowHeight, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX, OpenGL.OriginY, OpenGL.WindowWidth, OpenGL.WindowHeight); } else { glOrtho(0, Glide.WindowWidth, Glide.WindowHeight, 0, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX, OpenGL.OriginY, OpenGL.WindowWidth, OpenGL.WindowHeight); } // The scissor rectangle is not changed, because scissor mode // is only enabled when clearing the buffer glMatrixMode(GL_MODELVIEW); glReportError(); // enable framebuffer texture unit if (OpenGL.ColorAlphaUnit2) { const bool disable_coloralpha_texture_unit_2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (disable_coloralpha_texture_unit_2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.ColorAlphaUnit2); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glDisable(GL_TEXTURE_2D); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } if (!(OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0])) { if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } } } else { if (InternalConfig.EXT_secondary_color) { glDisable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 0, NULL); glReportError(); } glReportError(); } // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (!m_useRectangleARB) glEnable(GL_TEXTURE_2D); if (InternalConfig.EXT_compiled_vertex_array) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, &OGLRender.TTexture[0]); } glReportError(); } if (m_useRectangleARB) { glEnable(GL_TEXTURE_RECTANGLE_ARB); glReportError(); } // Select environment mode glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // Turn off fog and alpha combiners if (OpenGL.FogTextureUnit) { // @todo To be tested and reviewed glActiveTextureARB(OpenGL.FogTextureUnit); if (InternalConfig.EXT_compiled_vertex_array) { glClientActiveTextureARB(OpenGL.FogTextureUnit); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); } glDisable(GL_TEXTURE_2D); glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } if (InternalConfig.FogMode != OpenGLideFogEmulation_None && InternalConfig.FogMode != OpenGLideFogEmulation_EnvCombine) { glDisable(GL_FOG); glReportError(); } } } void Framebuffer::restore_gl_state() { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::restore_gl_state()\n"); #endif glReportErrors("Framebuffer::restore_gl_state"); // Restore the cull mode switch (Glide.State.CullMode) { case GR_CULL_DISABLE: break; case GR_CULL_NEGATIVE: case GR_CULL_POSITIVE: glEnable(GL_CULL_FACE); break; } if (Glide.State.DitherMode != GR_DITHER_DISABLE) { // GR_DITHER_2x2 or GR_DITHER_4x4 glEnable(GL_DITHER); } if (InternalConfig.EXT_clip_volume_hint && OpenGL.ClipVerticesEnabledState) { glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST); glReportError(); } if (InternalConfig.FullSceneAntiAliasing > 0) { glEnable(GL_MULTISAMPLE_ARB); glReportError(); } // Restore the clipping window glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( Glide.State.OriginInformation == GR_ORIGIN_LOWER_LEFT ) { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMinY, Glide.State.ClipMaxY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.ClipMinY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } else { glOrtho(Glide.State.ClipMinX, Glide.State.ClipMaxX, Glide.State.ClipMaxY, Glide.State.ClipMinY, OpenGL.ZNear, OpenGL.ZFar); glViewport(OpenGL.OriginX + OpenGL.ClipMinX, OpenGL.OriginY + OpenGL.WindowHeight - OpenGL.ClipMaxY, OpenGL.ClipMaxX - OpenGL.ClipMinX, OpenGL.ClipMaxY - OpenGL.ClipMinY); } // The scissor rectangle is not reset, because scissor mode // is only enabled when clearing the buffer glMatrixMode(GL_MODELVIEW); glReportError(); if (m_framebuffer->PixelPipeline) { if (OpenGL.ColorAlphaUnit2) { // restore current values if (m_bRestoreColorCombine) { if (Glide.State.ColorCombineLocal == GR_COMBINE_LOCAL_PIXELPIPELINE) Glide.State.ColorCombineLocal = GR_COMBINE_LOCAL_ITERATED; if (Glide.State.ColorCombineOther == GR_COMBINE_OTHER_PIXELPIPELINE) Glide.State.ColorCombineOther = GR_COMBINE_OTHER_ITERATED; SetColorCombineState(); } if(m_bRestoreAlphaCombine) { if (Glide.State.AlphaLocal == GR_COMBINE_LOCAL_PIXELPIPELINE) Glide.State.AlphaLocal = GR_COMBINE_LOCAL_ITERATED; if (Glide.State.AlphaOther == GR_COMBINE_OTHER_PIXELPIPELINE) Glide.State.AlphaOther = GR_COMBINE_LOCAL_ITERATED; SetAlphaCombineState(); } // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D if (m_useRectangleARB) { // Disable texture rectangle (for those units it has been enabled) const GLenum textureTarget = GL_TEXTURE_RECTANGLE_ARB; const bool disableColorAlphaTextureUnit1 = OpenGL.ColorAlphaUnitColorEnabledState[0] || OpenGL.ColorAlphaUnitAlphaEnabledState[0]; if (disableColorAlphaTextureUnit1) { glDisable(textureTarget); } if (OpenGL.ColorAlphaUnit2) { const bool disableColorAlphaTextureUnit2 = OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]; if (disableColorAlphaTextureUnit2) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glDisable(textureTarget); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } } glReportError(); // The client texture state is already setup correctly since we just // have to adjust the texture rectangle state to the texture_2d state } switch (m_framebuffer->WriteMode) { case GR_LFBWRITEMODE_565: case GR_LFBWRITEMODE_888: SetChromaKeyAndAlphaState(); break; } } else // simple render mode { if (InternalConfig.EXT_secondary_color) { glEnable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 4 * sizeof(GLfloat), &OGLRender.TColor2[0]); } glReportError(); } if (OpenGL.Texture == false) { // GL_RECTANGLE_ARB overrides GL_RECTANGLE_2D if (InternalConfig.EXT_compiled_vertex_array) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(4, GL_FLOAT, 0, NULL); } if (!m_useRectangleARB) glDisable(GL_TEXTURE_2D); } if (m_useRectangleARB) { glDisable(GL_TEXTURE_RECTANGLE_ARB); } // Restore the previous texture environment SetColorCombineState(); } } else { // restore depth state if (OpenGL.DepthBufferWritting) { glDepthMask(true); } if (Glide.State.DepthBufferMode != GR_DEPTHBUFFER_DISABLE) { glEnable(GL_DEPTH_TEST); } // Restore colormask const bool rgb = Glide.State.ColorMask; glColorMask(rgb, rgb, rgb, Glide.State.AlphaMask); // Also sets glBlendFunc so restoring manually might be more performant SetBlendState(); // Restore fog // @todo: This probably calls a lot more gl functions than just // enabling the texture unit so FogTextureUnitEnabledState should be used SetFogModeState(); // texture color alpha if (OpenGL.ColorAlphaUnit2) { // Restore the previous texture environment glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); SetTextureState(); } else { if (InternalConfig.EXT_secondary_color) { glEnable(GL_COLOR_SUM_EXT); if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == NULL) { glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); glSecondaryColorPointerEXT(3, GL_FLOAT, 4 * sizeof(GLfloat), &OGLRender.TColor2[0]); } glReportError(); } // Restore the previous texture environment SetTextureState(); SetColorCombineState(); } // GL_RECTANGLE_ARB overrides GL_TEXTURE_2D if (m_useRectangleARB) { glDisable(GL_TEXTURE_RECTANGLE_ARB); } glReportError(); // This must be a forced update because GlideState changes of ChromaKeyMode // that don't change the corresponding GL-state are filtered out ForceChromaKeyAndAlphaStateUpdate(); } glReportError(); VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); VERIFY_TEXTURE_ENABLED_STATE(); } void Framebuffer::draw(const tilesize* tilesizetable) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::draw(---)\n"); #endif glReportErrors("Framebuffer::draw()"); bool init_second_textureunit = m_framebuffer->PixelPipeline && OpenGL.ColorAlphaUnit2; FxU32* texbuffer = reinterpret_cast(m_texbuffer->Address); // Render the tiles GLint n = 0; GLint x; GLint y = 0; GLint y_step; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; // Use unique (but always the same) name for each texture in order // to maintain the size and avoid vram memory reallocation GLint texturename = m_textureNames[n]; const TileUpdateState updateState = createTextureData(texbuffer, x, y, x_step, y_step, n); if (updateState != TileUpdateState_TileEmpty) { #ifdef DEBUG_TILE_RENDERING unsigned int color; if (updateState == TileUpdateState_TileDownloadToGPU) // edges of downloaded tiles are red color = 0xff0000ff; else // edges of rendered tiles are cyan color = 0x00ffffff; ((long*) texbuffer)[0] = ((long*) texbuffer)[1] = ((long*) texbuffer)[x_step] = ((long*) texbuffer)[x_step -1] = ((long*) texbuffer)[x_step -2] = ((long*) texbuffer)[2 * x_step -1] = ((long*) texbuffer)[(x_step - 1) * y_step] = ((long*) texbuffer)[(x_step - 1) * y_step + 1] = ((long*) texbuffer)[(x_step - 2) * y_step] = ((long*) texbuffer)[x_step * y_step - 1] = ((long*) texbuffer)[x_step * y_step - 2] = ((long*) texbuffer)[x_step * (y_step - 1) - 1] = color; #endif glBindTexture(GL_TEXTURE_2D, texturename); if (init_second_textureunit) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glBindTexture(GL_TEXTURE_2D, texturename); glActiveTextureARB(OpenGL.ColorAlphaUnit1); } #ifndef DEBUG_TILE_RENDERING if (updateState == TileUpdateState_TileDownloadToGPU // || InternalConfig.APPLE_client_storage == false ) { glTexImage2D(GL_TEXTURE_2D, 0, m_glInternalFormat, x_step, y_step, 0, m_glFormat, m_glType, texbuffer); glReportError(); } #endif static struct { const GLfloat bl[4]; const GLfloat br[4]; const GLfloat tr[4]; const GLfloat tl[4]; } texcoords = { {0.0, 0.0, 1.0, 1.0}, {1.0, 0.0, 1.0, 1.0}, {1.0, 1.0, 1.0, 1.0}, {0.0, 1.0, 1.0, 1.0} }; // Preset fog coords to turn off fog, but leave coloralpha inverter enabled // TODO: Set only if texture unit is active if (OpenGL.FogTextureUnit) { glMultiTexCoord4fARB(OpenGL.FogTextureUnit, 0.0, 0.0, 0.0, 0.0); } glBegin(GL_QUADS); // counter clockwise glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.bl[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.bl[0]); } glVertex3f(x, y, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.br[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.br[0]); } glVertex3f(x + x_step, y, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.tr[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.tr[0]); } glVertex3f(x + x_step, y + y_step, m_glDepth); glColor3f(1.0, 1.0, 1.0); glTexCoord4fv(&texcoords.tl[0]); if (init_second_textureunit) { glMultiTexCoord4fvARB(OpenGL.ColorAlphaUnit2, &texcoords.tl[0]); } glVertex3f(x, y + y_step , m_glDepth); glEnd(); glReportError(); // Advance to the next texbuffer location texbuffer += x_step * y_step; } n ++; } } s_Framebuffer.SetRenderBufferChanged(); } void Framebuffer::drawCompiledVertexArrays(const tilesize* tilesizetable, int vertexarrayindex, int tilecount) { #ifdef OGL_FRAMEBUFFER GlideMsg( "Framebuffer::draw(---)\n"); #endif glReportErrors("Framebuffer::drawCompiledVertexArrays()"); RenderUnlockArrays(); glLockArraysEXT(vertexarrayindex * 3, tilecount * 6); glReportError(); OGLRender.BufferLocked = true; const bool init_second_textureunit = m_framebuffer->PixelPipeline && (OpenGL.ColorAlphaUnitColorEnabledState[1] || OpenGL.ColorAlphaUnitAlphaEnabledState[1]); FxU32* texbuffer = reinterpret_cast(m_texbuffer->Address); // Render the tiles GLint n = 0; GLint x; GLint y = 0; GLint y_step; const GLenum textureTarget = m_useRectangleARB ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; const TileUpdateState updateState = createTextureData(texbuffer, x, y, x_step, y_step, n); if (updateState != TileUpdateState_TileEmpty) { #ifdef DEBUG_TILE_RENDERING unsigned int color; if (updateState == TileUpdateState_TileDownloadToGPU) // edges of downloaded tiles are red color = 0xff0000ff; else // edges of rendered tiles are cyan color = 0x00ffffff; ((long*) texbuffer)[0] = ((long*) texbuffer)[1] = ((long*) texbuffer)[x_step] = ((long*) texbuffer)[x_step -1] = ((long*) texbuffer)[x_step -2] = ((long*) texbuffer)[2 * x_step -1] = ((long*) texbuffer)[x_step * (y_step - 2)] = ((long*) texbuffer)[x_step * (y_step - 1)] = ((long*) texbuffer)[x_step * (y_step - 1) + 1] = ((long*) texbuffer)[x_step * y_step - 1] = ((long*) texbuffer)[x_step * y_step - 2] = ((long*) texbuffer)[x_step * (y_step - 1) - 1] = color; #endif // Use unique (but always the same) name for each // texture in order to be able to reuse tile data const GLint texturename = m_textureNames[n]; // The texture rectangle is better suited for video, // which is close to a framebuffer if (init_second_textureunit) { glActiveTextureARB(OpenGL.ColorAlphaUnit2); glReportError(); glBindTexture(textureTarget, texturename); glReportError(); glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } glBindTexture(textureTarget, texturename); glReportError(); #ifndef DEBUG_TILE_RENDERING if (updateState == TileUpdateState_TileDownloadToGPU // || InternalConfig.APPLE_client_storage == false ) #endif { glTexImage2D(textureTarget, 0, m_glInternalFormat, x_step, y_step, 0, m_glFormat, m_glType, texbuffer); glReportError(); } // Draw the tile glDrawArrays(GL_TRIANGLES, vertexarrayindex * 3 + n * 6, 6); glReportError(); // Advance to the next texbuffer location texbuffer += x_step * y_step; } n++; } } s_Framebuffer.SetRenderBufferChanged(); } int Framebuffer::buildVertexArrays(const tilesize* tilesizetable, int vertexarrayindex) { // Compute coordinates for compiled vertex arrays TColorStruct* pC = &OGLRender.TColor[vertexarrayindex]; TVertexStruct* pV = &OGLRender.TVertex[vertexarrayindex]; TTextureStruct* pTS = &OGLRender.TTexture[vertexarrayindex]; TFogStruct* pF = &OGLRender.TFog[vertexarrayindex]; int n = 0; GLint y = 0; GLint y_step; for(int w = 0; y < m_height && w < MaxTiles; w++, y += y_step) { y_step = tilesizetable[w].y; GLint x = 0; GLint x_step; for(int v = 0; x < m_width && v < MaxTiles; v++, x += x_step) { x_step = tilesizetable[w].x[v]; // Write coordinates counter clockwise into render buffers pC->ar = pC->ag = pC->ab = pC->br = pC->bg = pC->bb = pC->cr = pC->cg = pC->cb = pC->aa = pC->ba = pC->ca = 1.0f; pV->ax = x; pV->ay = y; pV->bx = x + x_step; pV->by = y; pV->cx = x + x_step; pV->cy = y + y_step; pV->az = pV->bz = pV->cz = m_glDepth; pTS->as = 0.0; pTS->at = 0.0; pTS->bs = m_useRectangleARB ? x_step : 1.0f; pTS->bt = 0.0; pTS->cs = m_useRectangleARB ? x_step : 1.0f; pTS->ct = m_useRectangleARB ? y_step : 1.0f; pTS->aq = pTS->bq = pTS->cq = 0.0f; pTS->aoow = pTS->boow = pTS->coow = 1.0f; pF->af = pF->bf = pF->cf = 0.0f; pC++; pV++; pTS++; pF++; pC->ar = pC->ag = pC->ab = pC->br = pC->bg = pC->bb = pC->cr = pC->cg = pC->cb = pC->aa = pC->ba = pC->ca = 1.0f; pV->ax = x + x_step; pV->ay = y + y_step; pV->bx = x; pV->by = y + y_step; pV->cx = x; pV->cy = y; pV->az = pV->bz = pV->cz = m_glDepth; pTS->as = m_useRectangleARB ? x_step : 1.0f; pTS->at = m_useRectangleARB ? y_step : 1.0f; pTS->bs = 0.0; pTS->bt = m_useRectangleARB ? y_step : 1.0f; pTS->cs = 0.0; pTS->ct = 0.0; pTS->aq = pTS->bq = pTS->cq = 0.0f; pTS->aoow = pTS->boow = pTS->coow = 1.0f; pF->af = pF->bf = pF->cf = 0.0f; pC++; pV++; pTS++; pF++; n++; } } return n; } #ifdef __ALTIVEC__ // altivec code inline Framebuffer::TileUpdateState Framebuffer::Convert565Kto8888_AV(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride, int checksumIndex) { const vector bool short chromakey_565_av = m_ChromaKey.Vector; const int width_av = width >> 3; // 8 16-bit words const int stride_av = stride >> 3; // 8 16-bit words const int jump_av = width_av + stride_av; vector bool short* src_av = (vector bool short*) buffer1; // Setup channel 0 for reading one row of 565 ushorts from src into the L1 cache // This isn't read again soon, just written back once so we can bypass L2 cache const int src_control = (((width_av >> 4) & 0x1f) << 3) + (1 << 8) + (stride_av << 16); vec_dstt(src_av, src_control, 0); int h = height; // loop through the src to check whether anything has to be copied at all vector bool short* stop_zero_av = &src_av[width_av]; do { do { const vector bool short pixels_565_av = *src_av; if (!vec_all_eq(pixels_565_av, chromakey_565_av)) goto create_8888_texture_1_av; // Test clear first before jumping to create_8888_texture_1_av src_av++; } while (src_av != stop_zero_av); src_av += stride_av; // Update channel 0 to prefetch the next row into the L1 cache vec_dstt(src_av, src_control, 0); stop_zero_av += jump_av; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture_1_av: // Delete dst up to the last chromakey entry in src stop_zero_av = src_av; src_av = (vector bool short*) buffer1; vector unsigned long* dst_av = (vector unsigned long*) buffer2; const vector unsigned long null_av = vec_splat_u32(0); // We're just writing to dst, no reading must occur, and starting a prefetch is a bad idea h = height; vector bool short* stop_av = &src_av[width_av]; do { do { if (src_av == stop_zero_av) goto create_8888_texture_2_av; // Test clear first // clear cacheline to prevent it from being read-in (32 bytes = 2 altivec writes) // we're just clearing the cache line since we're going to write zeros anyway __dcbz(dst_av, 0); dst_av += 2; src_av++; } while (src_av != stop_av); src_av += stride_av; stop_av += jump_av; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture_2_av: // Build permute vector for storing high/lo 565 pixels into RgbxA // - results in R = r565+ggg, G = gggbbbbb, B = 0, A = glAlpha // -> good for comparison, green and blue are converted afterwards const vector unsigned char permute_hi_av = {0x00, 0x01, 0x12, 0x13, 0x02, 0x03, 0x16, 0x17, 0x04, 0x05, 0x1a, 0x1b, 0x06, 0x07, 0x1e, 0x1f}; // Computing the permute table just takes 2 instructions instead of 1 instruction + 4 memory reads const vector unsigned char permute_lo_av = vec_or(permute_hi_av, vec_splat_u8(8)); // const vector unsigned long alpha_8888_av = {m_glAlpha, m_glAlpha, m_glAlpha, m_glAlpha}; const vector unsigned long alpha_8888_av = m_glAlpha.Vector; // Build chromakey and alpha RgbxA vector const vector unsigned long chromakey_RgbxA_av = vec_perm((const vector unsigned long) chromakey_565_av, alpha_8888_av, permute_lo_av); // Constants const vector unsigned long const_3_av = vec_splat_u32(3); const vector unsigned long const_5_av = vec_splat_u32(5); // R5G6B500AA color masks const vector unsigned long mask_8888_ra = {0xf80000ff, 0xf80000ff, 0xf80000ff, 0xf80000ff}; const vector unsigned long mask_8888_g = {0x07e00000, 0x07e00000, 0x07e00000, 0x07e00000}; // Computing the mask just takes 2 instructions instead of 1 instruction + 4 memory reads const vector unsigned long mask_8888_b = vec_sr(mask_8888_ra, vec_splat_u32(11)); vector unsigned long pixels_8888_src_av; vector bool long mask; vector unsigned long p; vector unsigned long q; vector unsigned long pixels_8888_dst_av; // Checksum the tile vector unsigned long c = null_av; vector unsigned long d; // Continue the loop and convert pixels from 565 to 8888 vec_dstt(src_av, src_control, 0); do { do { const vector unsigned long pixels_565_av = (const vector unsigned long) (*src_av); // tile checksum part 1 d = vec_sr(c, const_5_av); c = vec_add(c, pixels_565_av); // restore chroma key for next update *src_av++ = chromakey_565_av; // hi-word pixels pixels_8888_src_av = vec_perm(pixels_565_av, alpha_8888_av, permute_hi_av); mask = vec_cmpeq(pixels_8888_src_av, chromakey_RgbxA_av); // Keep red and alpha component pixels_8888_dst_av = vec_and(pixels_8888_src_av, mask_8888_ra); // add green component p = vec_and(pixels_8888_src_av, mask_8888_g); q = vec_sr(p, const_3_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // add blue component p = vec_and(pixels_8888_src_av, mask_8888_b); q = vec_sr(p, const_5_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // We're just writing to dst and thus can clear the cacheline in order // to avoid the read-in from system memory (32 bytes = 2 altivec writes) // Note: This is a G4 hack, but on a G5 the code will be fast enough anyway __dcbz(dst_av, 0); // Select between pixels and chromakey *dst_av++ = vec_sel(pixels_8888_dst_av, null_av, mask); // tile checksum part 2 c = vec_xor(c, d); // lo-word pixels pixels_8888_src_av = vec_perm(pixels_565_av, alpha_8888_av, permute_lo_av); mask = vec_cmpeq(pixels_8888_src_av, chromakey_RgbxA_av); // Keep red and alpha component pixels_8888_dst_av = vec_and(pixels_8888_src_av, mask_8888_ra); // add green component p = vec_and(pixels_8888_src_av, mask_8888_g); q = vec_sr(p, const_3_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // add blue component p = vec_and(pixels_8888_src_av, mask_8888_b); q = vec_sr(p, const_5_av); pixels_8888_dst_av = vec_or(pixels_8888_dst_av, q); // Select between pixels and chromakey *dst_av++ = vec_sel(pixels_8888_dst_av, null_av, mask); } while (src_av != stop_av); src_av += stride_av; vec_dstt(src_av, src_control, 0); stop_av += jump_av; } while (--h); // Skip downloading tile data to the gpu if the content hasn't changed if (vec_all_eq(c, m_tileChecksums[checksumIndex])) return TileUpdateState_TileDrawOnly; // The tile has been converted, been changed and must be downloaded to the gpu m_tileChecksums[checksumIndex] = c; return TileUpdateState_TileDownloadToGPU; } #endif // Non-Altivec-code inline Framebuffer::TileUpdateState Framebuffer::Convert565Kto8888(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once const register unsigned long chromakey1 = m_ChromaKey.Scalar << 16; const register unsigned long chromakey2 = m_ChromaKey.Scalar; const register unsigned long chromakey12 = chromakey1 | chromakey2; width = width >> 1; stride = stride >> 1; register unsigned long pixel; register unsigned long* stop; register unsigned long jump = width + stride; register unsigned long* src = reinterpret_cast(buffer1); // check if tile must be processed in advance // to avoid useless writes to main memory // The tile should at least fit into the second level cache // so reading it again wouldn't hurt as much as doing needless writes register unsigned long h = height; stop = &src[width]; do { do { pixel = *src++; if (pixel != chromakey12) goto create_8888_texture; } while (src != stop); src += stride; stop += jump; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture: const register unsigned long alpha = m_glAlpha.Scalar; const register unsigned long null = 0x00000000; const register unsigned long mask_pixel1 = 0xffff0000; const register unsigned long mask_pixel2 = 0x0000ffff; const register unsigned long mask_pixel1_r = 0xf8000000; const register unsigned long mask_pixel1_g = 0x07e00000; const register unsigned long mask_pixel1_b = 0x001f0000; const register unsigned long mask_pixel2_r = 0x0000f800; const register unsigned long mask_pixel2_g = 0x000007e0; const register unsigned long mask_pixel2_b = 0x0000001f; src = reinterpret_cast(buffer1); stop = &src[width]; do { do { // GL_RGBA pixel = *src; if (pixel == chromakey12) { *buffer2++ = null; *buffer2++ = null; } else { *src = chromakey12; if ( (pixel & mask_pixel1) == chromakey1) { *buffer2++ = null; } else { *buffer2++ = ( alpha | // A ( pixel & mask_pixel1_b ) >> 5 | // B ( pixel & mask_pixel1_g ) >> 3 | // G ( pixel & mask_pixel1_r )); // R } if ( (pixel & mask_pixel2) == chromakey2) { *buffer2++ = null; } else { *buffer2++ = ( alpha | // A ( pixel & mask_pixel2_b ) << 11 | // B ( pixel & mask_pixel2_g ) << 13 | // G ( pixel & mask_pixel2_r ) << 16); // R } } src++; } while (src != stop); src += stride; stop += jump; } while (--height); return TileUpdateState_TileDownloadToGPU; } inline Framebuffer::TileUpdateState Framebuffer::Convert1555Kto8888(FxU16* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once register unsigned long pixel; register unsigned long x; register unsigned long* src = reinterpret_cast(buffer1); const unsigned long null = 0x00000000; register unsigned long dstpixel = null; const register unsigned long chromakey1 = m_ChromaKey.Scalar << 16; const register unsigned long chromakey2 = m_ChromaKey.Scalar; const register unsigned long chromakey12 = chromakey1 | chromakey2; const register unsigned long alpha = m_glAlpha.Scalar; const register unsigned long mask_pixel1 = 0xffff0000; const register unsigned long mask_pixel2 = 0x0000ffff; const register unsigned long mask_pixel1_r = 0x7c000000; const register unsigned long mask_pixel1_g = 0x03e00000; const register unsigned long mask_pixel1_b = 0x001f0000; const register unsigned long mask_pixel2_r = 0x00007c00; const register unsigned long mask_pixel2_g = 0x000003e0; const register unsigned long mask_pixel2_b = 0x0000001f; width >>= 1; stride >>= 1; do { x = width; do { // GL_RGBA pixel = *src; if (pixel == chromakey12) { *buffer2++ = null; *buffer2++ = null; } else { *src = chromakey12; if ( (pixel & mask_pixel1) == chromakey1) { *buffer2++ = null; } else { dstpixel = ( alpha | // A ( pixel & mask_pixel1_b ) >> 5 | // B ( pixel & mask_pixel1_g ) >> 2 | // G ( pixel & mask_pixel1_r ) << 1); // R *buffer2++ = dstpixel; } if ( (pixel & mask_pixel2) == chromakey2) { *buffer2++ = null; } else { dstpixel = ( alpha | // A ( pixel & mask_pixel2_b ) << 11 | // B ( pixel & mask_pixel2_g ) << 14 | // G ( pixel & mask_pixel2_r ) << 17); // R *buffer2++ = dstpixel; } } src++; } while (--x); src += stride; } while (--height); return dstpixel != null ? TileUpdateState_TileDownloadToGPU : TileUpdateState_TileEmpty; } inline Framebuffer::TileUpdateState Framebuffer::ConvertARGB8888Kto8888(FxU32* buffer1, register FxU32* buffer2, register FxU32 width, register FxU32 height, register FxU32 stride) { // Process two pixels at once const register unsigned long chromakey = m_ChromaKey.Scalar || (m_ChromaKey.Scalar << 16); register unsigned long pixel; register unsigned long* stop; register unsigned jump = width + stride; register unsigned long* src = buffer1; // check if tile must be processed in advance // to avoid useless writes to main memory // The tile should at least fit into the second level cache // so reading it again wouldn't hurt as much as doing needless writes register unsigned long h = height; stop = &src[width]; do { do { pixel = *src++; if (pixel != chromakey) goto create_8888_texture; } while (src != stop); src += stride; stop += jump; } while (--h); return TileUpdateState_TileEmpty; create_8888_texture: const register unsigned long alpha = m_glAlpha.Scalar; src = buffer1; stop = &src[width]; do { do { // GL_RGBA pixel = *src; if (pixel == chromakey) { *buffer2++ = 0; } else { *src = chromakey; *buffer2++ = (pixel << 8) | alpha; } src++; } while (src != stop); src += stride; stop += jump; } while (--height); return TileUpdateState_TileDownloadToGPU; } inline Framebuffer::TileUpdateState Framebuffer::createTextureData(FxU32* texbuffer, FxU32 x, FxU32 y, FxU32 x_step, FxU32 y_step, int checksumIndex) { FxU32 stride = (m_width - x_step); FxU32 index = x + y * m_width; if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_565) { #ifdef __ALTIVEC__ if (UserConfig.VectorUnitType == OpenGLideVectorUnitType_Altivec) { #ifdef OGL_FRAMEBUFFER const vector unsigned long c = m_tileChecksums[checksumIndex]; #endif TileUpdateState state = Convert565Kto8888_AV(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride, checksumIndex); #ifdef OGL_FRAMEBUFFER GlideMsg("Tile %d (%d,%d)-(%d,%d) update state is %s (%vlx)->(%vlx)\n", checksumIndex, x, y, x_step, y_step, (state ==TileUpdateState_TileDownloadToGPU) ? "DownLoadToGPU" : ((state == TileUpdateState_TileDrawOnly) ? "DrawOnly" : "TileEmpty"), c, m_tileChecksums[checksumIndex]); #endif return state; } else #endif return Convert565Kto8888(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride); } else if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_1555) { return Convert1555Kto8888(&m_framebuffer->Address[index], texbuffer, x_step, y_step, stride); } else if (m_framebuffer->WriteMode == GR_LFBWRITEMODE_888) { FxU32* framebuffer = &reinterpret_cast(m_framebuffer->Address)[index]; return ConvertARGB8888Kto8888(framebuffer, texbuffer, x_step, y_step, stride); } else { return TileUpdateState_TileEmpty; } } \ No newline at end of file diff --git a/MacGLide/OpenGLide/Framebuffer.h b/MacGLide/OpenGLide/Framebuffer.h index 8ba2982..431a23b 100644 --- a/MacGLide/OpenGLide/Framebuffer.h +++ b/MacGLide/OpenGLide/Framebuffer.h @@ -23,10 +23,9 @@ public: void free_buffers(); void initialise_format(GrLfbWriteMode_t format); bool begin_write(); - bool end_write(); - bool end_write(FxU32 alpha); - bool end_write(FxU32 alpha, GLfloat depth, bool pixelpipeline); - bool end_write_opaque(); + void end_write(); + void end_write(FxU32 alpha, GLfloat depth); + void end_write_opaque(); inline FxU16 GetChromaKeyValue() {return m_ChromaKey.Scalar;}; inline void SetChromaKeyValue(FxU16 chromakey) { @@ -41,11 +40,11 @@ public: } protected: void Clear(); - bool draw(const tilesize* tilesizetable, bool pixelpipeline); - bool drawCompiledVertexArrays(const tilesize* tilesizetable, int vertexarrayindex, int tilecount, bool pixelpipeline); + void draw(const tilesize* tilesizetable); + void drawCompiledVertexArrays(const tilesize* tilesizetable, int vertexarrayindex, int tilecount); int buildVertexArrays(const tilesize* tilesizetable, int vertexarrayindex); - void set_gl_state(bool pixelpipeline); - void restore_gl_state(bool pixelpipeline); + void set_gl_state(); + void restore_gl_state(); // Pixel conversion enum TileUpdateState { diff --git a/MacGLide/OpenGLide/GLExtensions.cpp b/MacGLide/OpenGLide/GLExtensions.cpp index 0c00d1b..617948a 100644 --- a/MacGLide/OpenGLide/GLExtensions.cpp +++ b/MacGLide/OpenGLide/GLExtensions.cpp @@ -357,21 +357,20 @@ void GLExtensions(void) { OpenGL.ColorAlphaUnit2 = GL_TEXTURE1_ARB; OpenGL.FogTextureUnit = GL_TEXTURE2_ARB; - // All texture units are enabled all the time + // env combine glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glActiveTextureARB(OpenGL.ColorAlphaUnit2); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glReportError(); - // Secondary color not neded in the enhanced color alpha rendering model + // Secondary color not needed in the enhanced color alpha rendering model InternalConfig.EXT_secondary_color = false; if (InternalConfig.ColorAlphaRenderMode == OpenGLideColorAlphaRenderMode_Automatic) { if (InternalConfig.ATI_texture_env_combine3) { - // With GL_ATI_texture_env_combine3, more combine functions can be modeled as - // exactly as the original combine functions. They can also be rendered more + // With GL_ATI_texture_env_combine3, more combine functions can be modeled + // equivalently to the Glide combine functions. They can also be rendered more // often with one texture unit, which leaves more space for correct rendering // of textures that use both chromakeying and alpha blending together. InternalConfig.ColorAlphaRenderMode = OpenGLideColorAlphaRenderMode_EnvCombine3_ATI; @@ -437,7 +436,7 @@ void GLExtensions(void) InternalConfig.FogMode = OpenGLideFogEmulation_Simple; } - if (InternalConfig.EXT_secondary_color && OpenGL.ColorAlphaUnit2 == 0) + if (InternalConfig.EXT_secondary_color) { glEnable(GL_COLOR_SUM_EXT); glReportError(); diff --git a/MacGLide/OpenGLide/GLRender.cpp b/MacGLide/OpenGLide/GLRender.cpp index 162c714..c28b2bb 100644 --- a/MacGLide/OpenGLide/GLRender.cpp +++ b/MacGLide/OpenGLide/GLRender.cpp @@ -105,7 +105,7 @@ void RenderInitialize(void) pTS->aq = pTS->bq = pTS->cq = 0.0f; } OGLRender.TVertex = (TVertexStruct*) AllocBuffer(triangles, sizeof(TVertexStruct)); - OGLRender.TFog = (TFogStruct*) AllocBuffer(OGLRender.FrameBufferStartIndex, sizeof(TFogStruct)); + OGLRender.TFog = (TFogStruct*) AllocBuffer(triangles, sizeof(TFogStruct)); // Initialise compiled vertex arrays OGLRender.BufferLocked = false; OGLRender.BufferStart = 0; diff --git a/MacGLide/OpenGLide/GLRenderUpdateState.cpp b/MacGLide/OpenGLide/GLRenderUpdateState.cpp index 30c9b1d..6708724 100644 --- a/MacGLide/OpenGLide/GLRenderUpdateState.cpp +++ b/MacGLide/OpenGLide/GLRenderUpdateState.cpp @@ -32,373 +32,9 @@ bool s_bUpdateColorInvertState = false; bool s_bUpdateAlphaInvertState = false; bool s_bUpdateConstantColorValueState = false; bool s_bUpdateConstantColorValue4State = false; -//bool s_bUpdateClipVerticesState = false; bool s_bForceChromaKeyAndAlphaStateUpdate = false; -/* -inline void SetTextureState_update() -{ - glReportErrors("SetTextureState_update"); - - if (OpenGL.ColorAlphaUnit2 == 0) - { - if (OpenGL.Texture) - { - glEnable(GL_TEXTURE_2D); - if (InternalConfig.EXT_compiled_vertex_array) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - } - else - { - if (InternalConfig.EXT_compiled_vertex_array) - { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - glDisable(GL_TEXTURE_2D); - } - glReportError(); - } - else - { - // If no texture is used, TMU0 provides 0 - for(long unit_index = 1; unit_index >= 0; unit_index--) - { - glActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glReportError(); - if (OpenGL.Texture == false) - { - glBindTexture(GL_TEXTURE_2D, OpenGL.DummyTextureName); - glReportError(); - } - if (OpenGL.ColorAlphaUnitColorEnabledState[unit_index] || OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]) - { - glEnable(GL_TEXTURE_2D); - if (InternalConfig.EXT_compiled_vertex_array) - { - glClientActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glReportError(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - glReportError(); - } - else - { - if (InternalConfig.EXT_compiled_vertex_array) - { - glClientActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glReportError(); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - glDisable(GL_TEXTURE_2D); - glReportError(); - } - } -#ifdef OPENGL_DEBUG - for(long unit_index = 0; unit_index < 2; unit_index++) - { - GlideMsg( "OpenGL.ColorAlphaUnitColorEnabledState[%d] = %d\n", unit_index, OpenGL.ColorAlphaUnitColorEnabledState[unit_index]); - GlideMsg( "OpenGL.ColorAlphaUnitAlphaEnabledState[%d] = %d\n", unit_index, OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]); - GlideMsg("Texture unit GL_TEXTURE%d_ARB ", unit_index, GL_TEXTURE0_ARB + unit_index); - if (OpenGL.ColorAlphaUnitColorEnabledState[unit_index] || OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]) - { - GlideMsg("enabled\n"); - } - else - { - GlideMsg("disabled\n"); - } - } -#endif - } -} -*/ - -/* -// Setup color combine for extended color alpha model -inline void SetColorCombineState_update() -{ - glReportErrors("SetColorCombine_update"); - - GrCombineFunction_t function = Glide.State.ColorCombineFunction; - GrCombineFactor_t factor = Glide.State.ColorCombineFactor; - GrCombineLocal_t local = Glide.State.ColorCombineLocal; - GrCombineOther_t other = Glide.State.ColorCombineOther; - - if (OpenGL.ColorAlphaUnit2 == 0) - { - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - if ( ( Glide.State.ColorCombineFactor == GR_COMBINE_FACTOR_TEXTURE_ALPHA ) && - ( Glide.State.ColorCombineOther == GR_COMBINE_OTHER_TEXTURE ) ) - { - glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - } - else - if ( ( Glide.State.ColorCombineFactor == GR_COMBINE_FACTOR_TEXTURE_RGB ) && - ( Glide.State.ColorCombineOther == GR_COMBINE_OTHER_TEXTURE ) ) - { - glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND ); - } - else - if (InternalConfig.EXT_texture_env_add && - ( Glide.State.ColorCombineFactor == GR_COMBINE_FACTOR_ONE ) && - ( Glide.State.ColorCombineOther == GR_COMBINE_OTHER_TEXTURE ) && - ( ( Glide.State.ColorCombineFunction == GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL_ALPHA ) || - ( Glide.State.ColorCombineFunction == GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL ) ) ) - { - glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); - } - else - { - glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - } - glReportError(); - } - else - { - // Reduce function for constant factors? - if (factor == GR_COMBINE_FACTOR_ZERO) - { - function = ColorCombineFunctionsFactorZero[function].ReducedTerm; - } - else if (factor == GR_COMBINE_FACTOR_ONE) - { - function = ColorCombineFunctionsFactorOne[function].ReducedTerm; - } - const CombineArgument** combine_argument = &OpenGL.ColorCombineArguments[0]; - combine_argument[CFARG_Local] = &ColorCombineLocals[local]; - combine_argument[CFARG_Other] = Glide.State.TextureCombineRGBInvert ? &ColorCombineOthersInverted[other] : &ColorCombineOthers[other]; - combine_argument[CFARG_LocalAlpha] = &AlphaCombineLocals[Glide.State.AlphaLocal]; - combine_argument[CFARG_OtherAlpha] = Glide.State.TextureCombineAInvert ? &AlphaCombineOthersInverted[Glide.State.AlphaOther] : &AlphaCombineOthers[Glide.State.AlphaOther]; - combine_argument[CFARG_Factor] = Glide.State.TextureCombineRGBInvert ? &ColorCombineFactorsInverted[factor] : &ColorCombineFactors[factor]; - GLint source; - GLint operand; - CombineFunctionColorAlphaArg arg; - for(long unit_index = 1; unit_index >= 0; unit_index--) - { - // unit 2 has to be the next one after unit 1 - glActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glReportError(); - const CombineFunctionGLTextureUnit& unit = OpenGL.ColorCombineFunctions[function].ColorAlphaUnit[unit_index]; - if (unit.Function == CF_Unused) - { - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); - glReportError(); - OpenGL.ColorAlphaUnitColorEnabledState[unit_index] = false; - } - else - { - OpenGL.ColorAlphaUnitColorEnabledState[unit_index] = true; - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, unit.Function); - glReportError(); - for(unsigned long arg_index = 0; arg_index < 3; arg_index++) - { - arg = unit.CombineArg[arg_index]; - if (arg < CFARG_None) - { - if (arg == CFARG_Factor); // || arg == CFARG_FactorAlpha) - { - if (combine_argument[arg]->Source < CFARG_None) - { - // Resolve factor to local/other: - // The factor source references to the local/other, - // which can be retrieved via the combine_argument[] array - source = combine_argument[combine_argument[arg]->Source]->Source; - // but the operand of the factor specifies already the - // correct component of the pixel (rgb or alpha) to be used. - // Example: if factor == GR_COMBINE_FACTOR_ONE_MINUS_OTHER_ALPHA - // then the other alpha in AlphaCombineOthers is GL_SRC_ALPHA - // but the factor operand is correctly GL_ONE_MINUS_SRC_ALPHA. - operand = combine_argument[arg]->Operand; - // operand = combine_argument[combine_argument[arg]->Source]->Operand; // No - } - else - { - source = combine_argument[arg]->Source; - operand = combine_argument[arg]->Operand; - } - } - else - { - // combinearg = local or other (alpha) - source = combine_argument[arg]->Source; - operand = combine_argument[arg]->Operand; - } - } - else if (arg > CFARG_None) - { - source = unit.CombineArg[arg_index]; - operand = GL_SRC_COLOR; - } - else - { - // arg == CFARG_None -> argument not used - continue; - } - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + arg_index, source); - glReportError(); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + arg_index, operand); - glReportError(); - } - } - } - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - -/* -// Setup alpha combine for extended color alpha model -inline void SetAlphaCombineState_update() -{ - glReportErrors("SetAlphaCombine_update"); - - if (OpenGL.ColorAlphaUnit2 == 0) - { - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - } - else - { - // Handle chromakey special case - if (OpenGL.ChromaKey && OpenGL.Texture && !OpenGL.Blend) - { - // need to disable alpha combining until an additional - // texture unit can be used to mask out the chroma key color. - // Note that the second unit must be setup because the - // texture unit might be turned on due to the color setup. - glActiveTextureARB(OpenGL.ColorAlphaUnit1 + 1); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - glReportError(); - OpenGL.ColorAlphaUnitAlphaEnabledState[0] = true; - OpenGL.ColorAlphaUnitAlphaEnabledState[1] = false; - } - else - { - GrCombineFunction_t function = Glide.State.AlphaFunction; - GrCombineFactor_t factor = Glide.State.AlphaFactor; - GrCombineLocal_t local = Glide.State.AlphaLocal; - GrCombineOther_t other = Glide.State.AlphaOther; - // Reduce function for constant factors? - if (factor == GR_COMBINE_FACTOR_ZERO) - { - function = AlphaCombineFunctionsFactorZero[function].ReducedTerm; - } - else if (factor == GR_COMBINE_FACTOR_ONE) - { - function = AlphaCombineFunctionsFactorOne[function].ReducedTerm; - } - const CombineArgument** combine_argument = &OpenGL.AlphaCombineArguments[0]; - // @todo: colors are unused, aren't they? - combine_argument[CFARG_Local] = &ColorCombineLocals[local]; - combine_argument[CFARG_Other] = Glide.State.TextureCombineAInvert ? &ColorCombineOthersInverted[other] : &ColorCombineOthers[other]; - combine_argument[CFARG_LocalAlpha] = &AlphaCombineLocals[local]; - combine_argument[CFARG_OtherAlpha] = Glide.State.TextureCombineAInvert ? &AlphaCombineOthersInverted[other] : &AlphaCombineOthers[other]; - combine_argument[CFARG_Factor] = Glide.State.TextureCombineAInvert ? &AlphaCombineFactorsInverted[factor] : &AlphaCombineFactors[factor]; - GLint source; - GLint operand; - CombineFunctionColorAlphaArg arg; - for(long unit_index = 1; unit_index >= 0; unit_index--) - { - // unit 2 must be the next one after unit 1 - glActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glReportError(); - CombineFunctionGLTextureUnit unit = OpenGL.AlphaCombineFunctions[function].ColorAlphaUnit[unit_index]; - if (unit.Function == CF_Unused) - { - if (OpenGL.ChromaKey && OpenGL.Texture && OpenGL.Blend) - { - // Modulate the alpha mask with the output of the previous unit - // to make chromakey-colored pixels invisible (so they wouldn't pass the alpha test) - // (chromakey-colored pixels have an alpha value of 0.0, the others 1.0) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); - glReportError(); - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = true; - } - else - { - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); - glReportError(); - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = false; - } - } - else - { - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, unit.Function); - glReportError(); - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = true; - for(unsigned long arg_index = 0; arg_index < 3; arg_index++) - { - arg = unit.CombineArg[arg_index]; - if (arg < CFARG_None) - { - if (arg == CFARG_Factor); // Alpha) - { - if (combine_argument[arg]->Source < CFARG_None) - { - // Resolve factor to local/other: - // The factor source references to local/other, - // which can be retrieved via the combine_argument[] array. - source = combine_argument[combine_argument[arg]->Source]->Source; - // but the operand of the factor specifies already which - // component of the pixel and how it should be used. - // Example: if factor == GR_COMBINE_FACTOR_ONE_MINUS_OTHER_ALPHA - // then the other alpha in AlphaCombineOthers is GL_SRC_ALPHA - // but the factor operand is correctly GL_ONE_MINUS_SRC_ALPHA. - operand = combine_argument[arg]->Operand; - } - else - { - source = combine_argument[arg]->Source; - operand = combine_argument[arg]->Operand; - } - } - else - { - source = combine_argument[arg]->Source; - operand = combine_argument[arg]->Operand; - } - } - else if (arg > CFARG_None) - { - source = unit.CombineArg[arg_index]; - operand = GL_SRC_ALPHA; - } - else - { - // arg == CFARG_None -> argument not used - continue; - } - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + arg_index, source); - glReportError(); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + arg_index, operand); - glReportError(); - } - } - } - } - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - /************************************************* * Avoid setting blending, alpha and chromakeying * each time triangles are rendered, May cause @@ -478,153 +114,6 @@ inline void SetChromaKeyAndAlphaState_update() VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); } -/* -static const GLfloat ZeroColor[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; -inline void SetFogModeState_update() -{ - glReportErrors("SetFogMode_update"); - - if (InternalConfig.FogMode == OpenGLideFogEmulation_EnvCombine) - { - if (InternalConfig.EXT_compiled_vertex_array) - { - glClientActiveTextureARB(OpenGL.FogTextureUnit); - glReportError(); - } - glActiveTextureARB(OpenGL.FogTextureUnit); - glReportError(); - if (Glide.State.FogMode & (GR_FOG_WITH_ITERATED_ALPHA | GR_FOG_WITH_TABLE)) - { - glEnable(GL_TEXTURE_2D); - if (InternalConfig.EXT_compiled_vertex_array) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(1, GL_FLOAT, 0, &OGLRender.TFog[0]); - glReportError(); - } - OGLRender.UseEnvCombineFog = true; - // Now set the fog function - GrFogMode_t modeAdd = Glide.State.FogMode & (GR_FOG_MULT2 | GR_FOG_ADD2); - switch (modeAdd) - { - case GR_FOG_ADD2: - // Cout = (1 - f) * Cin - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR); - break; - case GR_FOG_MULT2: - // Cout = f * Cfog - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - break; - default: - // The usual blending - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); - break; - } - glReportError(); - } - else if (Glide.State.ColorCombineInvert || Glide.State.AlphaInvert) - { - // If the texture unit is turned on to invert color or alpha then we need to supply - // fog coords anyway and the combine function can still be GL_INTERPOLATE_EXT - // because the minimal fog value is chosen. However, choosing replace might - // save some vram memory access cycles - glEnable(GL_TEXTURE_2D); - if (InternalConfig.EXT_compiled_vertex_array) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(1, GL_FLOAT, 0, &OGLRender.TFog[0]); - glReportError(); - } - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); - glReportError(); - OGLRender.UseEnvCombineFog = true; - } - else - { - if (InternalConfig.EXT_compiled_vertex_array) - { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - // On MacOS9 (Classic?) the texcoord pointer needs to be reset - // to the default value when glLockArrays/glUnlockArrays is used - glTexCoordPointer( 4, GL_FLOAT, 0, NULL ); - glReportError(); - } - glDisable(GL_TEXTURE_2D); - // If the texture unit is disabled, the combine env function doesn't matter - OGLRender.UseEnvCombineFog = false; - } - if (InternalConfig.EXT_compiled_vertex_array) - { - glClientActiveTextureARB(OpenGL.ColorAlphaUnit1); - } - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glReportError(); - } - else if (InternalConfig.FogMode != OpenGLideFogEmulation_None) - { - if (Glide.State.FogMode & (GR_FOG_WITH_ITERATED_ALPHA | GR_FOG_WITH_TABLE)) - { - glEnable(GL_FOG); - } - else - { - glDisable(GL_FOG); - } - glReportError(); - // Change the fog color in order to emulate the correct fog equation - // (Imperfect emulation) - GrFogMode_t modeAdd = Glide.State.FogMode & (GR_FOG_MULT2 | GR_FOG_ADD2); - switch (modeAdd) - { - case GR_FOG_MULT2: - case GR_FOG_ADD2: - glFogfv( GL_FOG_COLOR, &ZeroColor[0]); - glReportError(); - break; - default: - SetFogColorState(); - break; - } - glReportError(); - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - -/* -inline void SetFogColorState_update() -{ - glReportErrors("SetFogColor_update"); - - if (Glide.State.FogMode < GR_FOG_MULT2) - { - if (InternalConfig.FogMode == OpenGLideFogEmulation_EnvCombine) - { - glActiveTextureARB(OpenGL.FogTextureUnit); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &OpenGL.FogColor[0]); - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glReportError(); - } - else if (InternalConfig.FogMode != OpenGLideFogEmulation_None ) - { - glFogfv( GL_FOG_COLOR, &OpenGL.FogColor[0] ); - glReportError(); - } - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - inline void SetBlendState_update() { glReportErrors("SetBlendState_update"); @@ -643,7 +132,7 @@ inline void SetBlendState_update() } #endif - if ( OpenGL.Blend ) + if (OpenGL.Blend) { #ifdef OPENGL_DEBUG GlideMsg("Changing Blend state to enabled\n"); @@ -677,175 +166,6 @@ inline void SetBlendState_update() VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); } -/* -void SetColorInvertState_update() -{ - glReportErrors("SetColorInvert_update"); - - // Setup color inversion on fog texture unit - if (OpenGL.FogTextureUnit) - { - FxBool invert = Glide.State.ColorCombineInvert; - glActiveTextureARB(OpenGL.FogTextureUnit); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, invert ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR); - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glReportError(); - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - -/* -void SetAlphaInvertState_update() -{ - glReportErrors("SetAlphaInvert_update"); - - // Setup alpha inversion on fog texture unit - if (OpenGL.FogTextureUnit) - { - FxBool invert = Glide.State.AlphaInvert; - glActiveTextureARB(OpenGL.FogTextureUnit); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, invert ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA); - glActiveTextureARB(OpenGL.ColorAlphaUnit1); - glReportError(); - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - -/* -void SetConstantColorValueState_update() -{ - glReportErrors("SetConstantColorState_update"); - - GLfloat* color; - if (Glide.State.Delta0Mode) - { - color = &OpenGL.Delta0Color[0]; - s_bUpdateConstantColorValue4State = false; - } - else - { - color = &OpenGL.ConstantColor[0]; - s_bUpdateConstantColorValueState = false; - } - -#ifdef OPENGL_DEBUG - GlideMsg("OpenGL.ConstantColor=(%g, %g, %g, %g)\n", - color[0], - color[1], - color[2], - color[3]); -#endif - - if (OpenGL.ColorAlphaUnit2) - { - for(long unit_index = 1; unit_index >= 0; unit_index--) - { - glActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &color[0]); - } - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); -} -*/ - -/* -void RenderUpdateState_old() -{ - glReportErrors("RenderUpdateState"); - - // This filters out a few state changes in Carmageddon - // (changing chromakey mode is expensive) - if (OldGlideState.ChromaKeyMode != Glide.State.ChromaKeyMode) - { - OldGlideState.ChromaKeyMode = Glide.State.ChromaKeyMode; -#ifdef OPTIMISE_OPENGL_STATE_CHANGES - if (!OpenGL.Blend) -#endif - SetChromaKeyAndAlphaState(); - } - else - { -#ifdef OPENGL_DEBUG - GlideMsg( "Calls to grChromakeyMode() didn't change ChromaKeyAndAlphaState\n"); -#endif - } - - // Triggered by the frambuffer - if (s_bForceChromaKeyAndAlphaStateUpdate) - { - s_bForceChromaKeyAndAlphaStateUpdate = false; - SetChromaKeyAndAlphaState(); - } - - if (s_bUpdateFogModeState) - { - s_bUpdateFogModeState = false; - SetFogModeState_update(); - } - - if (s_bUpdateFogColorState) - { - s_bUpdateFogColorState = false; - SetFogColorState_update(); - } - - if (s_bUpdateBlendState) - { - s_bUpdateBlendState = false; - SetBlendState_update(); - } - - if (s_bUpdateChromaKeyAndAlphaState) - { - s_bUpdateChromaKeyAndAlphaState = false; - SetChromaKeyAndAlphaState_update(); - } - - if (s_bUpdateAlphaCombineState) - { - s_bUpdateAlphaCombineState = false; - SetAlphaCombineState_update(); - } - - if (s_bUpdateColorCombineState) - { - s_bUpdateColorCombineState = false; - SetColorCombineState_update(); - } - - if (s_bUpdateColorInvertState) - { - s_bUpdateColorInvertState = false; - SetColorInvertState_update(); - } - - if (s_bUpdateAlphaInvertState) - { - s_bUpdateAlphaInvertState = false; - SetAlphaInvertState_update(); - } - - if (s_bUpdateTextureState) - { - s_bUpdateTextureState = false; - SetTextureState_update(); - } - - if (s_bUpdateConstantColorValueState || s_bUpdateConstantColorValue4State) - { - SetConstantColorValueState_update(); - } - - VERIFY_ACTIVE_TEXTURE_UNIT(OpenGL.ColorAlphaUnit1); - VERIFY_TEXTURE_ENABLED_STATE(); -} -*/ - void RenderUpdateState() { glReportErrors("RenderUpdateState"); @@ -1102,15 +422,9 @@ void RenderUpdateState() { // Remember last state because if a unit gets enabled, we have to update it's whole state previously_enabled_texture_unit[unit_index] = OpenGL.ColorAlphaUnitColorEnabledState[unit_index] || - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]; - if (OpenGL.ColorCombineFunctions[c_function].ColorAlphaUnit[unit_index].Function == CF_Unused) - { - OpenGL.ColorAlphaUnitColorEnabledState[unit_index] = false; - } - else - { - OpenGL.ColorAlphaUnitColorEnabledState[unit_index] = true; - } + OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]; + OpenGL.ColorAlphaUnitColorEnabledState[unit_index] = + OpenGL.ColorCombineFunctions[c_function].ColorAlphaUnit[unit_index].Function != CF_Unused; // AlphaCombine if (OpenGL.ChromaKey && OpenGL.Texture && !OpenGL.Blend) { @@ -1120,17 +434,11 @@ void RenderUpdateState() { if (OpenGL.AlphaCombineFunctions[a_function].ColorAlphaUnit[unit_index].Function == CF_Unused) { - if (OpenGL.ChromaKey && OpenGL.Texture && OpenGL.Blend) - { - // Modulate the alpha mask with the output of the previous unit - // to make chromakey-colored pixels invisible (so they wouldn't pass the alpha test) - // (chromakey-colored pixels have an alpha value of 0.0, the others 1.0) - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = true; - } - else - { - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = false; - } + // Modulate the alpha mask with the output of the previous unit + // to make chromakey-colored pixels invisible (so they wouldn't pass the alpha test) + // (chromakey-colored pixels have an alpha value of 0.0, the others 1.0) + OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index] = + OpenGL.ChromaKey && OpenGL.Texture && OpenGL.Blend; } else { @@ -1138,7 +446,7 @@ void RenderUpdateState() } } enable_texture_unit[unit_index] = OpenGL.ColorAlphaUnitColorEnabledState[unit_index] || - OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]; + OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]; } #ifdef OPENGL_DEBUG for(long unit_index = 0; unit_index < 2; unit_index++) diff --git a/MacGLide/OpenGLide/GLRenderUpdateState.h b/MacGLide/OpenGLide/GLRenderUpdateState.h index d86aa17..86c4452 100644 --- a/MacGLide/OpenGLide/GLRenderUpdateState.h +++ b/MacGLide/OpenGLide/GLRenderUpdateState.h @@ -22,7 +22,6 @@ extern bool s_bUpdateColorInvertState; extern bool s_bUpdateAlphaInvertState; extern bool s_bUpdateConstantColorValueState; extern bool s_bUpdateConstantColorValue4State; -//extern bool s_bUpdateClipVerticesState; extern bool s_bForceChromaKeyAndAlphaStateUpdate; @@ -179,11 +178,6 @@ inline void SetConstantColorValue4State() s_bUpdateConstantColorValue4State = true; } -//inline void SetClipVerticesState() -//{ -// s_bUpdateClipVerticesState = true; -//} - // Also called from FrameBuffer class extern void SetClipVerticesState_Update(bool clip_vertices); diff --git a/MacGLide/OpenGLide/GlOgl.h b/MacGLide/OpenGLide/GlOgl.h index 00f8559..a6aa477 100644 --- a/MacGLide/OpenGLide/GlOgl.h +++ b/MacGLide/OpenGLide/GlOgl.h @@ -81,6 +81,7 @@ union OGLByteColor struct CombineFunction; struct CombineArgument; +// The current glide state, valid anytime struct GlideState { GrBuffer_t RenderBuffer; @@ -140,6 +141,7 @@ struct GlideState FxFloat Gamma; }; +// Additional internal Glide state information struct GlideStruct { int ActiveVoodoo; @@ -165,62 +167,73 @@ struct GlideStruct FxU32 TextureMemory; }; +// The current OpenGL state +// Vadility of members: +// - session static - these don't change during the lifetime of the OpenGL context +// - up to date - they are always up to date +// - forthcoming up to date on the next call to RenderUpdateState() +// +// @todo: Some state variables are considered not until the next call to RenderUpdateState +// while the others reflect the actual state struct OpenGLStruct { + // Session static bool GlideInit; bool WinOpen; - unsigned long WindowWidth; - unsigned long WindowHeight; FxU32 OriginX; FxU32 OriginY; + unsigned long WindowWidth; + unsigned long WindowHeight; + GLint ColorAlphaUnit1; + GLint ColorAlphaUnit2; + GLuint DummyTextureName; + GLint FogTextureUnit; + int MultiTextureTMUs; + GLuint Refresh; + FxU32 WaitSignal; + // up to date on the next call to RenderUpdateState() + bool Blend; + bool ChromaKey; + bool ClipVerticesEnabledState; + bool Fog; + GLfloat FogColor[4]; + const CombineFunction* ColorCombineFunctions; + const CombineFunction* AlphaCombineFunctions; + const CombineArgument* ColorCombineArguments[5]; + const CombineArgument* AlphaCombineArguments[5]; + GLenum SrcBlend; + GLenum DstBlend; + GLenum SrcAlphaBlend; + GLenum DstAlphaBlend; + // always up to date FxU32 ClipMinX; FxU32 ClipMaxX; FxU32 ClipMinY; FxU32 ClipMaxY; - GLfloat Gamma; + bool Clipping; GLfloat AlphaReferenceValue; GLenum AlphaTestFunction; GLboolean DepthBufferWritting; GLfloat DepthBiasLevel; GLenum DepthFunction; int DepthBufferType; + GLfloat ZNear; + GLfloat ZFar; GLenum RenderBuffer; GLenum SClampMode; GLenum TClampMode; GLenum MinFilterMode; GLenum MagFilterMode; - GLenum SrcBlend; - GLenum DstBlend; - GLenum SrcAlphaBlend; - GLenum DstAlphaBlend; - GLuint Refresh; + GLfloat Gamma; GLfloat ConstantColor[4]; GLfloat Delta0Color[4]; - GLfloat ZNear; - GLfloat ZFar; - GLint ColorAlphaUnit1; - GLint ColorAlphaUnit2; bool ColorAlphaUnitColorEnabledState[2]; bool ColorAlphaUnitAlphaEnabledState[2]; - GLuint DummyTextureName; - GLint FogTextureUnit; - bool FogTextureUnitEnabledState; - GLfloat FogColor[4]; OGLByteColor ChromaColor; - bool Fog; bool ColorTexture; bool AlphaTexture; - bool Blend; bool Texture; - bool ChromaKey; - bool Clipping; - bool ClipVerticesEnabledState; - int MultiTextureTMUs; - const CombineFunction* ColorCombineFunctions; - const CombineFunction* AlphaCombineFunctions; - const CombineArgument* ColorCombineArguments[5]; - const CombineArgument* AlphaCombineArguments[5]; - FxU32 WaitSignal; + bool FogTextureUnitEnabledState; // @todo: currently not used FxU8 FogTable[OPENGLFOGTABLESIZE]; }; diff --git a/MacGLide/OpenGLide/GlideFramebuffer.cpp b/MacGLide/OpenGLide/GlideFramebuffer.cpp index a436c84..648172f 100644 --- a/MacGLide/OpenGLide/GlideFramebuffer.cpp +++ b/MacGLide/OpenGLide/GlideFramebuffer.cpp @@ -200,7 +200,7 @@ void GlideFramebuffer::OnBufferLockStartWrite(GrLock_t dwType, GrBuffer_t dwBuff // would appear twice or at unexpected places. This suggests there // might be a bug in here (in conjunction with clipping??). // Also be careful regarding performance issues. - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); m_must_write = false; } // Change format? @@ -263,7 +263,7 @@ void GlideFramebuffer::OnBufferUnlockEndWrite(GrBuffer_t dwBuffer) // pixel pipeline state before the buffer will eventtually be written out. if (m_framebuffer->PixelPipeline) { - WriteFrameBuffer(true); + WriteFrameBuffer(); // This write is finished m_must_write = false; } @@ -328,7 +328,7 @@ void GlideFramebuffer::OnClipWindow() // @todo: This must be reconsidered because it triggers all the time if (m_framebuffer->PixelPipeline) { - WriteFrameBuffer(true); + WriteFrameBuffer(); // Keep writing as the frame buffer may still be locked m_must_write = m_framebuffer->Lock; // @todo: Think this is obsolete as the case is catched by OnChromaKeyValueChanged() @@ -448,7 +448,7 @@ void GlideFramebuffer::OnRenderDrawTriangles() } else if (InternalConfig.PedanticFrameBufferEmulation || m_must_write) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); } // Need to start a new write if (InternalConfig.PedanticFrameBufferEmulation) @@ -489,24 +489,24 @@ void GlideFramebuffer::OnBeforeBufferSwap() } else if (m_must_write) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); } else if (BackBufferIsLocked()) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); } m_must_write = false; // optionally render the 3Dfx powerfield logo overlay on top of the frame if (InternalConfig.ShamelessPlug) { // @todo: For apps that lock the frame buffer accross buffer swaps - // (for instance Carmageddon) the current state must be saved... + // (for instance Carmageddon) the current lock state must be saved... _grShamelessPlug(); if (m_must_write) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); } - // ... and restored after rendering the shameless plug + // @todo: ... and restored after rendering the shameless plug } } else @@ -530,10 +530,10 @@ void GlideFramebuffer::OnAfterBufferSwap() begin_write(); } -void GlideFramebuffer::WriteFrameBuffer(bool pixelpipeline) +void GlideFramebuffer::WriteFrameBuffer() { #ifdef OGL_FRAMEBUFFER - GlideMsg( "GlideFrameBuffer::WriteFrameBuffer(%d)\n", pixelpipeline); + GlideMsg( "GlideFrameBuffer::WriteFrameBuffer()\n"); #endif // apply the framebuffer changes? @@ -541,16 +541,19 @@ void GlideFramebuffer::WriteFrameBuffer(bool pixelpipeline) { // Only the back buffer is supported because games like Carmageddon // temporarily lock and unlock the front buffer while holding the lock - // to the back buffer. Becasue he current implementation of the framebuffer + // to the back buffer. Because he current implementation of the framebuffer // emulation doesn't support locks to multiple buffers, data is written to // the current buffer (which is usally the back buffer). - if (pixelpipeline) + if (m_framebuffer->PixelPipeline) { - end_write(m_alpha, m_depth, pixelpipeline); + end_write(m_alpha, m_depth); } else { end_write(); + // @todo: it would be nice to eleminate the condition,but + // m_alpha is always applied to the write and depth never + // end_write(m_alpha, m_depth); } } else @@ -614,7 +617,7 @@ void GlideFramebuffer::OnChromaKeyValueChanged() if (m_chromakeyvalue_changed && m_framebuffer->PixelPipeline) { // Flush the current contents of the framebuffer - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); SetChromaKeyValue(m_chromakeyvalue_new); m_chromakeyvalue_changed = false; // Fill the framebuffer with the new chromakey value @@ -626,18 +629,18 @@ void GlideFramebuffer::OnChromaKeyValueChanged() void GlideFramebuffer::SetAlpha(FxU32 alpha) { - if (m_must_write && (m_framebuffer->PixelPipeline & m_alpha) != alpha) + if (m_must_write && m_framebuffer->PixelPipeline && m_alpha != alpha) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); + m_alpha = alpha; } - m_alpha = alpha; }; void GlideFramebuffer::SetDepth(GLfloat depth) { - if (m_must_write && (m_framebuffer->PixelPipeline && m_depth) != depth) + if (m_must_write && m_framebuffer->PixelPipeline && m_depth != depth) { - WriteFrameBuffer(m_framebuffer->PixelPipeline); + WriteFrameBuffer(); + m_depth = depth; } - m_depth = depth; }; diff --git a/MacGLide/OpenGLide/GlideFramebuffer.h b/MacGLide/OpenGLide/GlideFramebuffer.h index 0772c29..4d9776f 100644 --- a/MacGLide/OpenGLide/GlideFramebuffer.h +++ b/MacGLide/OpenGLide/GlideFramebuffer.h @@ -59,6 +59,6 @@ public: void CopyFrameBuffer(FxU16* targetbuffer); inline FxU16 GetChromaKeyValue() {return Framebuffer::GetChromaKeyValue();}; protected: - void WriteFrameBuffer(bool pixelpipline); + void WriteFrameBuffer(); inline bool BackBufferIsLocked() {return m_grLfbLockWriteMode[GR_BUFFER_BACKBUFFER] != GR_LFBWRITEMODE_UNUSED;}; }; diff --git a/MacGLide/OpenGLide/PGTexture.cpp b/MacGLide/OpenGLide/PGTexture.cpp index f3a4352..29c689e 100644 --- a/MacGLide/OpenGLide/PGTexture.cpp +++ b/MacGLide/OpenGLide/PGTexture.cpp @@ -22,42 +22,28 @@ void PGTexture::genPaletteMipmaps( FxU32 width, FxU32 height, const FxU8 *data ) { - FxU8 buf[ 128 * 128 ]; - FxU32 mmwidth; - FxU32 mmheight; - FxU32 lod; - FxU32 skip; - - mmwidth = width; - mmheight = height; - lod = 0; - skip = 1; - - while ( ( mmwidth > 1 ) || ( mmheight > 1 ) ) - { - FxU32 x, - y; - - mmwidth = mmwidth > 1 ? mmwidth / 2 : 1; - mmheight = mmheight > 1 ? mmheight / 2 : 1; - lod += 1; - skip *= 2; - - for ( y = 0; y < mmheight; y++ ) - { - const FxU8* in; - FxU8* out; - - in = data + width * y * skip; - out = buf + mmwidth * y; - for ( x = 0; x < mmwidth; x++ ) - { - out[ x ] = in[ x * skip ]; - } - } - - glTexImage2D( GL_TEXTURE_2D, lod, GL_COLOR_INDEX8_EXT, mmwidth, mmheight, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buf ); - } + FxU8 buf[128 * 128]; + FxU32 mmwidth = width; + FxU32 mmheight = height; + FxU32 lod = 0; + FxU32 skip = 1; + while ((mmwidth > 1) || (mmheight > 1)) + { + mmwidth = mmwidth > 1 ? mmwidth / 2 : 1; + mmheight = mmheight > 1 ? mmheight / 2 : 1; + lod += 1; + skip *= 2; + for (FxU32 y = 0; y < mmheight; y++) + { + const FxU8* in = data + width * y * skip; + FxU8* out = buf + mmwidth * y; + for (FxU32 x = 0; x < mmwidth; x++) + { + out[x] = in[x * skip]; + } + } + glTexImage2D( GL_TEXTURE_2D, lod, GL_COLOR_INDEX8_EXT, mmwidth, mmheight, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buf ); + } } PGTexture::PGTexture(int mem_size) @@ -634,7 +620,7 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr if (subtexcoords) { - // APPLE_client_storage doesn't explicitely forbid to adjust pixel unpack :^) + // APPLE_client_storage doesn't explicitly forbid to adjust pixel unpack :^) glPixelStorei(GL_UNPACK_SKIP_PIXELS, subtexcoords->left); glPixelStorei(GL_UNPACK_SKIP_ROWS, subtexcoords->top); glPixelStorei(GL_UNPACK_ROW_LENGTH, texVals.width); @@ -684,7 +670,7 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr break; case GR_TEXFMT_P_8: // Read about anisotropy and chromakey issues in macFormatConversions.cpp - if ( InternalConfig.EXT_paletted_texture && InternalConfig.AnisotropylLevel < 2) + if (InternalConfig.EXT_paletted_texture && InternalConfig.AnisotropylLevel < 2) { glColorTable(GL_TEXTURE_2D, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, m_palette); glTexImage2D( GL_TEXTURE_2D, texVals.lod, GL_COLOR_INDEX8_EXT, @@ -712,7 +698,7 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr } break; case GR_TEXFMT_AP_88: - if ( use_two_textures ) + if (use_two_textures) { FxU32 *texBuffer2 = texBuffer + 256 * 128; glColorTable(GL_TEXTURE_2D, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, m_palette); @@ -725,7 +711,7 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr genPaletteMipmaps(texVals.width, texVals.height, (FxU8*) texBuffer); } glActiveTextureARB(OpenGL.ColorAlphaUnit1 + 1); - DownloadMipmapsToOpenGL( GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, texBuffer2, texVals, !use_mipmap_ext); + DownloadMipmapsToOpenGL(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, texBuffer2, texVals, !use_mipmap_ext); glActiveTextureARB(OpenGL.ColorAlphaUnit1); glReportError(); } @@ -736,11 +722,9 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr } break; case GR_TEXFMT_ALPHA_8: + // the alpha value is used for red, green, and blue as well (see glide24pgm.pdf) ConvertA8toAP88((FxU8*)data, (FxU16*) texBuffer, texVals.nPixels); DownloadMipmapsToOpenGL(2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texBuffer, texVals, !use_mipmap_ext); - // @todo: The statement below breaks the overlay texts in Myth TFL. - // As a result, this optimsation has been undone for now - // DownloadMipmapsToOpenGL(1, GL_ALPHA, GL_UNSIGNED_BYTE, data, texVals, !use_mipmap_ext); break; case GR_TEXFMT_ALPHA_INTENSITY_88: DownloadMipmapsToOpenGL(2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data, texVals, !use_mipmap_ext); @@ -810,28 +794,24 @@ bool PGTexture::MakeReady(TTextureStruct* tex_coords, unsigned long number_of_tr FxU32 PGTexture::LodOffset( FxU32 evenOdd, const GrTexInfo *info ) { - FxU32 total = 0; - GrLOD_t i; - - for( i = info->largeLod; i < info->smallLod; i++ ) - { - total += MipMapMemRequired( i, info->aspectRatio, info->format ); - } - - total = ( total + 7 ) & ~7; - - return total; + FxU32 total = 0; + for(GrLOD_t i = info->largeLod; i < info->smallLod; i++) + { + total += MipMapMemRequired( i, info->aspectRatio, info->format); + } + total = (total + 7) & ~7; + return total; } FxU32 PGTexture::TextureMemRequired( FxU32 evenOdd, const GrTexInfo *info ) { - // - // If the format is one of these: - // GR_TEXFMT_RGB_332, GR_TEXFMT_YIQ_422, GR_TEXFMT_ALPHA_8 - // GR_TEXFMT_INTENSITY_8, GR_TEXFMT_ALPHA_INTENSITY_44, GR_TEXFMT_P_8 - // Reduces the size by 2 - // - return nSquareTexLod[ info->format < GR_TEXFMT_16BIT ][ info->aspectRatio ][ info->largeLod ][ info->smallLod ]; + // + // If the format is one of these: + // GR_TEXFMT_RGB_332, GR_TEXFMT_YIQ_422, GR_TEXFMT_ALPHA_8 + // GR_TEXFMT_INTENSITY_8, GR_TEXFMT_ALPHA_INTENSITY_44, GR_TEXFMT_P_8 + // Reduces the size by 2 + // + return nSquareTexLod[ info->format < GR_TEXFMT_16BIT ][ info->aspectRatio ][ info->largeLod ][ info->smallLod ]; } FxU32 PGTexture::MipMapMemRequired( GrLOD_t lod, GrAspectRatio_t aspectRatio, GrTextureFormat_t format ) @@ -842,7 +822,7 @@ FxU32 PGTexture::MipMapMemRequired( GrLOD_t lod, GrAspectRatio_t aspectRatio, Gr // GR_TEXFMT_INTENSITY_8, GR_TEXFMT_ALPHA_INTENSITY_44, GR_TEXFMT_P_8 // Reduces the size by 2 // - return nSquareLod[ format >= GR_TEXFMT_16BIT ][ aspectRatio ][ lod ]; + return nSquareLod[format >= GR_TEXFMT_16BIT][aspectRatio][lod]; } void PGTexture::GetTexValues( TexValues * tval ) const @@ -867,53 +847,51 @@ void PGTexture::ChromakeyValue( GrColor_t value ) void PGTexture::ChromakeyMode( GrChromakeyMode_t mode ) { - m_chromakey_mode = mode; - m_palette_dirty = true; + m_chromakey_mode = mode; + m_palette_dirty = true; } void PGTexture::ApplyKeyToPalette( void ) { - FxU32 hash; - int i; - if ( m_palette_dirty ) + if (m_palette_dirty) { - hash = 0; - { - for ( i = 0; i < 256; i++ ) - { - if ( ( m_chromakey_mode ) - && ( ( m_palette[i] & 0xffffff00 ) == m_chromakey_value_8888)) - { - m_palette[i] &= 0xffffff00; - } - else - { - m_palette[i] |= 0x000000ff; - } - hash = ( ( hash << 5 ) | ( hash >> 27 ) ); - hash += ( InternalConfig.IgnorePaletteChange - ? ( m_palette[ i ] & 0x000000ff ) - : m_palette[ i ]); - } - } - m_palette_hash = hash; - m_palette_dirty = false; + FxU32 hash = 0; + { + for (int i = 0; i < 256; i++) + { + if ((m_chromakey_mode) && + ((m_palette[i] & 0xffffff00) == m_chromakey_value_8888)) + { + m_palette[i] &= 0xffffff00; + } + else + { + m_palette[i] |= 0x000000ff; + } + hash = ((hash << 5) | (hash >> 27)); + hash += (InternalConfig.IgnorePaletteChange + ? (m_palette[i] & 0x000000ff) + : m_palette[i]); + } + } + m_palette_hash = hash; + m_palette_dirty = false; } } void PGTexture::NCCTable( GrNCCTable_t tab ) { - switch ( tab ) - { - case GR_NCCTABLE_NCC0: - case GR_NCCTABLE_NCC1: - m_ncc_select = tab; - } + switch ( tab ) + { + case GR_NCCTABLE_NCC0: + case GR_NCCTABLE_NCC1: + m_ncc_select = tab; + } } FxU32 PGTexture::GetMemorySize( void ) const { - return m_tex_memory_size; + return m_tex_memory_size; } unsigned int PGTexture::PowerOfTwoCeiling(unsigned int x) diff --git a/MacGLide/OpenGLide/PGUTexture.cpp b/MacGLide/OpenGLide/PGUTexture.cpp index 8b8dac2..65d4802 100644 --- a/MacGLide/OpenGLide/PGUTexture.cpp +++ b/MacGLide/OpenGLide/PGUTexture.cpp @@ -177,9 +177,25 @@ void PGUTexture::Source( GrMipMapId_t id ) grTexClampMode( tmu, mm_info[ id ].s_clamp_mode, mm_info[ id ].t_clamp_mode ); grTexLodBiasValue( tmu, mm_info[ id ].lod_bias ); // Download the ncc table - // @todo: the linux driver utilises both tables and optimises download - // -> No download, no texture recreation - grTexDownloadTable(tmu, GR_NCCTABLE_NCC0, &mm_info[ id ].ncc_table); + // @todo: only necessary when the format uses the table? + if ((info.format == GR_TEXFMT_YIQ_422) || + (info.format == GR_TEXFMT_AYIQ_8422)) + { + // @todo: the linux driver utilises both tables and optimises downloads + // MacGLide only uses gr* functions whereas + // the linux driver has extra internal state for gu* functions + // -> No download, no texture recreation (see gutex.c) + // /* Which table should we use? */ + // table = gc->tmu_state[tmu].next_ncc_table; + // /* Download NCC table */ // using internal function + // _grTexDownloadNccTable( tmu, table, &mminfo->ncc_table, 0, 11 ); + // /* Set the mmid so we known it's down there */ + // gc->tmu_state[tmu].ncc_mmids[table] = mmid; + // /* Set the state to know which table was the LRA */ + // gc->tmu_state[tmu].next_ncc_table = + // (table == 0 ? 1 : 0); + grTexDownloadTable(tmu, GR_NCCTABLE_NCC0, &mm_info[ id ].ncc_table); + } m_current_id = id; } #ifdef OGL_UTEX diff --git a/MacGLide/OpenGLide/grguBuffer.cpp b/MacGLide/OpenGLide/grguBuffer.cpp index fefd864..132572c 100644 --- a/MacGLide/OpenGLide/grguBuffer.cpp +++ b/MacGLide/OpenGLide/grguBuffer.cpp @@ -20,6 +20,8 @@ // Write colored pixels only void gapfixSetSimpleColorState() { + glReportErrors("gapfixSetSimpleColorState"); + // Disable the cull mode glDisable(GL_CULL_FACE); // Disable clip volume hint manually to avoid recursion @@ -82,6 +84,8 @@ void gapfixSetSimpleColorState() void gapfixRestoreFromSimpleColorState() { + glReportErrors("gapfixRestoreFromSimpleColorState"); + // Restore state switch (Glide.State.CullMode) { diff --git a/MacGLide/OpenGLide/grguTex.cpp b/MacGLide/OpenGLide/grguTex.cpp index 7ae8b85..7b1bcfd 100644 --- a/MacGLide/OpenGLide/grguTex.cpp +++ b/MacGLide/OpenGLide/grguTex.cpp @@ -648,56 +648,10 @@ guTexCombineFunction( GrChipID_t tmu, GrTextureCombineFnc_t func ) #if defined( OGL_PARTDONE ) || defined( OGL_COMBINE ) GlideMsg( "guTexCombineFunction( %d, %d )\n", tmu, func ); #endif - - // Ignoring TMU as we are only emulating Glide and assuming a well behaviored program - if ( tmu != GR_TMU0 ) - { - return; - } - - switch ( func ) - { - case GR_TEXTURECOMBINE_ZERO: // 0x00 per component - grTexCombine( tmu, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_ZERO, - GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_ZERO, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_DECAL: // Clocal decal texture - grTexCombine( tmu, GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, - GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_OTHER: // Cother pass through - grTexCombine( tmu, GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, - GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_ADD: // Cother + Clocal additive texture - grTexCombine( tmu, GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL, GR_COMBINE_FACTOR_ONE, - GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL, GR_COMBINE_FACTOR_ONE, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_MULTIPLY: // Cother * Clocal modulated texture - grTexCombine( tmu, GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_LOCAL, - GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_LOCAL, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_SUBTRACT: // Cother – Clocal subtractive texture - grTexCombine( tmu, GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL, GR_COMBINE_FACTOR_ONE, - GR_COMBINE_FUNCTION_SCALE_OTHER_MINUS_LOCAL, GR_COMBINE_FACTOR_ONE, FXFALSE, FXFALSE ); - break; - - case GR_TEXTURECOMBINE_ONE: // 255 0xFF per component - grTexCombine( tmu, GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_ZERO, - GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_ZERO, FXTRUE, FXTRUE ); - break; - -// case GR_TEXTURECOMBINE_DETAIL: // blend (Cother, Clocal) detail textures with detail on selected TMU -// case GR_TEXTURECOMBINE_DETAIL_OTHER: // blend (Cother, Clocal) detail textures with detail on neighboring TMU -// case GR_TEXTURECOMBINE_TRILINEAR_ODD: // blend (Cother, Clocal) LOD blended textures with odd levels on selected TMU -// case GR_TEXTURECOMBINE_TRILINEAR_EVEN: // blend (Cother, Clocal) LOD blended textures with even levels on selected TMU -// break; - } + // @todo: guTexCombineFunction() also keeps track of which TMUs + // require texture coordinates for the rendering routines. + // (see glide24pgm page 139) + grTexCombineFunction(tmu, func); } //*************************************************