Advertisement
Guest User

Batch Render with Stencil

a guest
Apr 2nd, 2014
97
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22.  
  23. #include "BatchRender.h"
  24.  
  25. #ifndef _SCENE_OBJECT_H_
  26. #include "2d/sceneobject/SceneObject.h"
  27. #endif
  28.  
  29. // Debug Profiling.
  30. #include "debug/profiler.h"
  31.  
  32. //-----------------------------------------------------------------------------
  33.  
  34. BatchRender::BatchRender() :
  35.     mQuadCount( 0 ),
  36.     mVertexCount( 0 ),
  37.     mTextureResidentCount( 0 ),
  38.     mIndexCount( 0 ),
  39.     mColorCount( 0 ),
  40.     NoColor( -1.0f, -1.0f, -1.0f ),
  41.     mStrictOrderMode( false ),
  42.     mpDebugStats( NULL ),
  43.     mBlendMode( true ),
  44.     mSrcBlendFactor( GL_SRC_ALPHA ),
  45.     mDstBlendFactor( GL_ONE_MINUS_SRC_ALPHA ),
  46.     mBlendColor( ColorF(1.0f,1.0f,1.0f,1.0f) ),
  47.     mAlphaTestMode( -1.0f ),
  48.     mWireframeMode( false ),
  49.     mBatchEnabled( true ),
  50.     mLightIndex(0)
  51. {
  52. }
  53.  
  54. //-----------------------------------------------------------------------------
  55.  
  56. BatchRender::~BatchRender()
  57. {
  58.     // Destroy index vectors in texture batch map.
  59.     for ( textureBatchType::iterator itr = mTextureBatchMap.begin(); itr != mTextureBatchMap.end(); ++itr )
  60.     {
  61.         delete itr->value;
  62.     }
  63.     mTextureBatchMap.clear();
  64.  
  65.     // Destroy index vectors in index vector pool.
  66.     for ( VectorPtr< indexVectorType* >::iterator itr = mIndexVectorPool.begin(); itr != mIndexVectorPool.end(); ++itr )
  67.     {
  68.         delete (*itr);
  69.     }
  70.     mIndexVectorPool.clear();
  71. }
  72.  
  73. //-----------------------------------------------------------------------------
  74.  
  75. void BatchRender::setBlendMode( const SceneRenderRequest* pSceneRenderRequest )
  76. {
  77.     // Are we blending?
  78.     if ( pSceneRenderRequest->mBlendMode )
  79.     {
  80.         // Yes, so set blending to standard alpha-blending.
  81.         setBlendMode(
  82.             pSceneRenderRequest->mSrcBlendFactor,
  83.             pSceneRenderRequest->mDstBlendFactor,
  84.             pSceneRenderRequest->mBlendColor );                            
  85.     }
  86.     else
  87.     {
  88.         // No, so turn-off blending.
  89.         setBlendOff();
  90.     }
  91. }
  92.  
  93. //-----------------------------------------------------------------------------
  94.  
  95. void BatchRender::setAlphaTestMode( const SceneRenderRequest* pSceneRenderRequest )
  96. {
  97.     // Set alpha-test mode.
  98.     setAlphaTestMode( pSceneRenderRequest->mAlphaTest );
  99. }
  100.  
  101. //-----------------------------------------------------------------------------
  102.  
  103. void BatchRender::SubmitQuad(
  104.         const Vector2& vertexPos0,
  105.         const Vector2& vertexPos1,
  106.         const Vector2& vertexPos2,
  107.         const Vector2& vertexPos3,
  108.         const Vector2& texturePos0,
  109.         const Vector2& texturePos1,
  110.         const Vector2& texturePos2,
  111.         const Vector2& texturePos3,
  112.         TextureHandle& texture,
  113.         const ColorF& color )
  114. {
  115.     // Sanity!
  116.     AssertFatal( mpDebugStats != NULL, "Debug stats have not been configured." );
  117.  
  118.     PROFILE_START(BatchRender_SubmitQuad);
  119.  
  120.     // Do we have anything batched?
  121.     if ( mQuadCount > 0 )
  122.     {
  123.         // Yes, so do we have any existing colors?
  124.         if ( mColorCount == 0 )
  125.         {
  126.             // No, so flush if color is specified.
  127.             if ( color != NoColor  )
  128.                 flush( mpDebugStats->batchColorStateFlush );
  129.         }
  130.         else
  131.         {
  132.             // Yes, so flush if color is not specified.
  133.             if ( color == NoColor  )
  134.                 flush( mpDebugStats->batchColorStateFlush );
  135.         }
  136.     }
  137.  
  138.     // Is a color specified?
  139.     if ( color != NoColor )
  140.     {
  141.         // Yes, so add colors.
  142.         mColorBuffer[mColorCount++] = color;
  143.         mColorBuffer[mColorCount++] = color;
  144.         mColorBuffer[mColorCount++] = color;
  145.         mColorBuffer[mColorCount++] = color;
  146.     }
  147.  
  148.     // Strict order mode?
  149.     if ( mStrictOrderMode )
  150.     {
  151.         // Is there is a texture change.
  152.         if ( texture != mStrictOrderTextureHandle )
  153.         {
  154.             // Yes, so flush.
  155.             flush( mpDebugStats->batchTextureChangeFlush );
  156.         }
  157.  
  158.         // Add new indices.
  159.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  160.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  161.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  162.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  163.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  164.         mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  165.  
  166.         // find the GL name for our lightmap texture
  167.         if (strstr(texture.getTextureKey(), "lightmap.PNG") != NULL){
  168.             mLightIndex = texture.getGLName();
  169.         }
  170.  
  171.  
  172.         // Set strict order mode texture handle.
  173.         mStrictOrderTextureHandle = texture;
  174.     }
  175.     else
  176.     {
  177.         // No, so fetch texture binding.
  178.         const U32 textureBinding = texture.getGLName();
  179.  
  180.         indexVectorType* pIndexVector = NULL;
  181.  
  182.         // Find texture binding.
  183.         textureBatchType::iterator itr = mTextureBatchMap.find( textureBinding );
  184.  
  185.         // Did we find a texture binding?
  186.         if ( itr == mTextureBatchMap.end() )
  187.         {
  188.             // No, so fetch index vector pool count.
  189.             const U32 indexVectorPoolCount = mIndexVectorPool.size();
  190.  
  191.             // Do we have any in the index vector pool?
  192.             if ( indexVectorPoolCount > 0 )
  193.             {
  194.                 // Yes, so use it.
  195.                 pIndexVector = mIndexVectorPool[indexVectorPoolCount-1];
  196.                 mIndexVectorPool.pop_back();
  197.             }
  198.             else
  199.             {
  200.                 // No, so generate one.
  201.                 pIndexVector = new indexVectorType( 6 * 6 );
  202.             }
  203.  
  204.             // Insert into texture batch map.
  205.             mTextureBatchMap.insert( textureBinding, pIndexVector );
  206.         }
  207.         else
  208.         {
  209.             // Yes, so fetch it.
  210.             pIndexVector = itr->value;
  211.         }
  212.  
  213.         // Add vertex start.
  214.         pIndexVector->push_back( mVertexCount );      
  215.     }
  216.  
  217.     // Add textured vertices.
  218.     // NOTE: We swap #2/#3 here.
  219.     mVertexBuffer[mVertexCount++]   = vertexPos0;
  220.     mVertexBuffer[mVertexCount++]   = vertexPos1;
  221.     mVertexBuffer[mVertexCount++]   = vertexPos3;
  222.     mVertexBuffer[mVertexCount++]   = vertexPos2;
  223.     mTextureBuffer[mTextureResidentCount++] = texturePos0;
  224.     mTextureBuffer[mTextureResidentCount++] = texturePos1;
  225.     mTextureBuffer[mTextureResidentCount++] = texturePos3;
  226.     mTextureBuffer[mTextureResidentCount++] = texturePos2;
  227.  
  228.     // Stats.
  229.     mpDebugStats->batchTrianglesSubmitted+=2;
  230.  
  231.     // Increase quad count.
  232.     mQuadCount++;
  233.  
  234.     // Have we reached the buffer limit?
  235.     if ( mQuadCount == BATCHRENDER_MAXQUADS )
  236.     {
  237.         // Yes, so flush.
  238.         flush( mpDebugStats->batchBufferFullFlush );
  239.     }
  240.  
  241.     // Is batching enabled?
  242.     if ( !mBatchEnabled )
  243.     {
  244.         // No, so flush immediately.
  245.         // NOTE: Technically this is still batching but will still revert to using
  246.         // more draw calls therefore can be used in comparison.
  247.         flushInternal();
  248.     }
  249.  
  250.     PROFILE_END();   // BatchRender_SubmitQuad
  251. }
  252.  
  253. //-----------------------------------------------------------------------------
  254.  
  255. void BatchRender::flush( U32& reasonMetric )
  256. {
  257.     // Finish if no quads to flush.
  258.     if ( mQuadCount == 0 )
  259.         return;
  260.  
  261.     // Increase reason metric.
  262.     reasonMetric++;
  263.  
  264.     // Flush.
  265.     flushInternal();
  266. }
  267.  
  268. //-----------------------------------------------------------------------------
  269.  
  270. void BatchRender::flush( void )
  271. {
  272.     // Finish if no quads to flush.
  273.     if ( mQuadCount == 0 )
  274.         return;
  275.  
  276.     // Increase reason metric.
  277.     mpDebugStats->batchAnonymousFlush++;
  278.  
  279.     // Flush.
  280.     flushInternal();
  281. }
  282.  
  283. //-----------------------------------------------------------------------------
  284.  
  285. void BatchRender::flushInternal( void )
  286. {
  287.     // Finish if no quads to flush.
  288.     if ( mQuadCount == 0 )
  289.         return;
  290.  
  291.     PROFILE_START(T2D_BatchRender_flush);
  292.  
  293.     // Stats.
  294.     mpDebugStats->batchFlushes++;
  295.  
  296.     if ( mWireframeMode )
  297.     {
  298.         // Disable texturing.    
  299.         glDisable( GL_TEXTURE_2D );
  300.  
  301.         // Set the polygon mode to line.
  302.         glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  303.     }
  304.     else
  305.     {
  306.         // Enable texturing.    
  307.         glEnable( GL_TEXTURE_2D );
  308.         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  309.  
  310.         // Set the polygon mode to fill.
  311.         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  312.     }
  313.  
  314.     // Set blend mode.
  315.     if ( mBlendMode )
  316.     {
  317.         glEnable( GL_BLEND );
  318.         glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
  319.         glColor4f(mBlendColor.red, mBlendColor.green, mBlendColor.blue, mBlendColor.alpha );
  320.     }
  321.     else
  322.     {
  323.         glDisable( GL_BLEND );
  324.         glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
  325.     }
  326.  
  327.     // Set alpha-blend mode.
  328.     if ( mAlphaTestMode >= 0.0f )
  329.     {
  330.         glEnable( GL_ALPHA_TEST );
  331.         glAlphaFunc( GL_GREATER, mAlphaTestMode );
  332.     }
  333.     else
  334.     {
  335.         glDisable( GL_ALPHA_TEST );
  336.     }
  337.  
  338.     // Enable vertex and texture arrays.
  339.     glEnableClientState( GL_VERTEX_ARRAY );
  340.     glVertexPointer( 2, GL_FLOAT, 0, mVertexBuffer );
  341.     glTexCoordPointer( 2, GL_FLOAT, 0, mTextureBuffer );
  342.  
  343.     // Use the texture coordinates if not in wireframe mode.
  344.     if ( !mWireframeMode )
  345.         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
  346.  
  347.     // Do we have any colors?
  348.     if ( mColorCount > 0 )
  349.     {
  350.         // Yes, so enable color array.
  351.         glEnableClientState( GL_COLOR_ARRAY );
  352.         glColorPointer( 4, GL_FLOAT, 0, mColorBuffer );
  353.     }
  354.  
  355.     // Strict order mode?
  356.     if ( mStrictOrderMode )
  357.     {
  358.         // Bind the texture if not in wireframe mode.
  359.         if ( !mWireframeMode )
  360.             glBindTexture( GL_TEXTURE_2D, mStrictOrderTextureHandle.getGLName() );
  361.        
  362.         //enable stencil test for lighting effect
  363.         glEnable(GL_STENCIL_TEST);
  364.         glEnable(GL_ALPHA_TEST); //make sure the alpha is enabled
  365.  
  366.         // Identify lights
  367.         if (mStrictOrderTextureHandle.getGLName() == mLightIndex && mLightIndex != 0){
  368.             glClear(GL_DEPTH_BUFFER_BIT);
  369.            
  370.             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  371.             glDepthMask(GL_FALSE);
  372.             glStencilFunc(GL_NEVER, 1, 0xFF);
  373.             glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
  374.  
  375.             glAlphaFunc(GL_GREATER, 0);
  376.  
  377.             glStencilMask(0xFF);
  378.             glClear(GL_STENCIL_BUFFER_BIT);
  379.         }
  380.  
  381.         // Yes, so do we have a single quad?
  382.         if ( mQuadCount == 1 )
  383.         {
  384.             // Yes, so draw the quad using a triangle-strip with indexes.
  385.             glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );    
  386.  
  387.             // Stats.
  388.             mpDebugStats->batchDrawCallsStrictSingle++;
  389.  
  390.             // Stats.
  391.             if ( mpDebugStats->batchMaxTriangleDrawn < 2 )
  392.                 mpDebugStats->batchMaxTriangleDrawn = 2;
  393.         }
  394.         else
  395.         {
  396.             // Draw the quads using triangles with indexes.
  397.             glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  398.  
  399.             // Stats.
  400.             mpDebugStats->batchDrawCallsStrictMultiple++;
  401.  
  402.             // Stats.
  403.             const U32 trianglesDrawn = mIndexCount / 3;
  404.             if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  405.                 mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  406.         }
  407.  
  408.         // Stats.
  409.         if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  410.             mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  411.     }
  412.     else
  413.     {
  414.         // No, so iterate texture batch map.
  415.         for( textureBatchType::iterator batchItr = mTextureBatchMap.begin(); batchItr != mTextureBatchMap.end(); ++batchItr )
  416.         {
  417.             // Fetch texture binding.
  418.             const U32 textureBinding = batchItr->key;
  419.  
  420.             // Fetch index vector.
  421.             indexVectorType* pIndexVector = batchItr->value;
  422.  
  423.             // Reset index count.
  424.             mIndexCount = 0;
  425.  
  426.             // Iterate indexes.
  427.             for( indexVectorType::iterator indexItr = pIndexVector->begin(); indexItr != pIndexVector->end(); ++indexItr )
  428.             {
  429.                 // Fetch quad index.
  430.                 U32 quadIndex = (*indexItr);
  431.  
  432.                 // Add new indices.
  433.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  434.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  435.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  436.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
  437.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
  438.                 mIndexBuffer[mIndexCount++] = (U16)quadIndex;
  439.             }
  440.  
  441.             // Sanity!
  442.             AssertFatal( mIndexCount > 0, "No batching indexes are present." );
  443.  
  444.             // Bind the texture if not in wireframe mode.
  445.             if ( !mWireframeMode )
  446.                 glBindTexture( GL_TEXTURE_2D, textureBinding );
  447.  
  448.             // Draw the quads using triangles with indexes.
  449.             glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  450.  
  451.             // Stats.
  452.             mpDebugStats->batchDrawCallsSorted++;
  453.  
  454.             // Stats.
  455.             if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  456.                 mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  457.  
  458.             // Stats.
  459.             const U32 trianglesDrawn = mIndexCount / 3;
  460.             if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  461.                 mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  462.  
  463.             // Return index vector to pool.
  464.             pIndexVector->clear();
  465.             mIndexVectorPool.push_back( pIndexVector );
  466.         }
  467.  
  468.         // Clear texture batch map.
  469.         mTextureBatchMap.clear();
  470.     }
  471.  
  472.    
  473.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  474.     glDepthMask(GL_TRUE);
  475.     glStencilMask(0x00);
  476.  
  477.     glAlphaFunc(GL_LEQUAL, 1);
  478.  
  479.     glStencilFunc(GL_EQUAL, 0, 0xFF);
  480.  
  481.     glStencilFunc(GL_EQUAL, 1, 0xFF);
  482.  
  483.     // only disable stencil after other objects have been rendered
  484.     if (mStrictOrderTextureHandle.getGLName() != mLightIndex){
  485.         glDisable(GL_STENCIL_TEST);
  486.     }
  487.    
  488.  
  489.     // Reset common render state.
  490.     glDisableClientState( GL_VERTEX_ARRAY );
  491.     glDisableClientState( GL_TEXTURE_COORD_ARRAY );
  492.     glDisableClientState( GL_COLOR_ARRAY );
  493.     glDisable( GL_ALPHA_TEST );
  494.     glDisable( GL_BLEND );
  495.     glDisable( GL_TEXTURE_2D );
  496.     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  497.  
  498.     // Reset batch state.
  499.     mQuadCount = 0;
  500.     mVertexCount = 0;
  501.     mTextureResidentCount = 0;
  502.     mIndexCount = 0;
  503.     mColorCount = 0;
  504.  
  505.     PROFILE_END();   // T2D_BatchRender_flush
  506. }
  507.  
  508. //-----------------------------------------------------------------------------
  509.  
  510. void BatchRender::RenderQuad(
  511.         const Vector2& vertexPos0,
  512.         const Vector2& vertexPos1,
  513.         const Vector2& vertexPos2,
  514.         const Vector2& vertexPos3,
  515.         const Vector2& texturePos0,
  516.         const Vector2& texturePos1,
  517.         const Vector2& texturePos2,
  518.         const Vector2& texturePos3 )
  519. {
  520.     glBegin( GL_TRIANGLE_STRIP );
  521.         glTexCoord2f( texturePos0.x, texturePos0.y );
  522.         glVertex2f( vertexPos0.x, vertexPos0.y );
  523.         glTexCoord2f( texturePos1.x, texturePos1.y );
  524.         glVertex2f( vertexPos1.x, vertexPos1.y );
  525.         glTexCoord2f( texturePos3.x, texturePos3.y );
  526.         glVertex2f( vertexPos3.x, vertexPos3.y );
  527.         glTexCoord2f( texturePos2.x, texturePos2.y );
  528.         glVertex2f( vertexPos2.x, vertexPos2.y );
  529.     glEnd();
  530. }
Advertisement
RAW Paste Data Copied
Advertisement