| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "BatchRender.h"
- #ifndef _SCENE_OBJECT_H_
- #include "2d/sceneobject/SceneObject.h"
- #endif
- // Debug Profiling.
- #include "debug/profiler.h"
- //-----------------------------------------------------------------------------
- BatchRender::BatchRender() :
- mQuadCount( 0 ),
- mVertexCount( 0 ),
- mTextureResidentCount( 0 ),
- mIndexCount( 0 ),
- mColorCount( 0 ),
- NoColor( -1.0f, -1.0f, -1.0f ),
- mStrictOrderMode( false ),
- mpDebugStats( NULL ),
- mBlendMode( true ),
- mSrcBlendFactor( GL_SRC_ALPHA ),
- mDstBlendFactor( GL_ONE_MINUS_SRC_ALPHA ),
- mBlendColor( ColorF(1.0f,1.0f,1.0f,1.0f) ),
- mAlphaTestMode( -1.0f ),
- mWireframeMode( false ),
- mBatchEnabled( true )
- {
- }
- //-----------------------------------------------------------------------------
- BatchRender::~BatchRender()
- {
- // Destroy index vectors in texture batch map.
- for ( textureBatchType::iterator itr = mTextureBatchMap.begin(); itr != mTextureBatchMap.end(); ++itr )
- {
- delete itr->value;
- }
- mTextureBatchMap.clear();
- // Destroy index vectors in index vector pool.
- for ( VectorPtr< indexVectorType* >::iterator itr = mIndexVectorPool.begin(); itr != mIndexVectorPool.end(); ++itr )
- {
- delete (*itr);
- }
- mIndexVectorPool.clear();
- }
- //-----------------------------------------------------------------------------
- void BatchRender::setBlendMode( const SceneRenderRequest* pSceneRenderRequest )
- {
- // Are we blending?
- if ( pSceneRenderRequest->mBlendMode )
- {
- // Yes, so set blending to standard alpha-blending.
- setBlendMode(
- pSceneRenderRequest->mSrcBlendFactor,
- pSceneRenderRequest->mDstBlendFactor,
- pSceneRenderRequest->mBlendColor );
- }
- else
- {
- // No, so turn-off blending.
- setBlendOff();
- }
- }
- //-----------------------------------------------------------------------------
- void BatchRender::setAlphaTestMode( const SceneRenderRequest* pSceneRenderRequest )
- {
- // Set alpha-test mode.
- setAlphaTestMode( pSceneRenderRequest->mAlphaTest );
- }
- //-----------------------------------------------------------------------------
- void BatchRender::SubmitQuad(
- const Vector2& vertexPos0,
- const Vector2& vertexPos1,
- const Vector2& vertexPos2,
- const Vector2& vertexPos3,
- const Vector2& texturePos0,
- const Vector2& texturePos1,
- const Vector2& texturePos2,
- const Vector2& texturePos3,
- TextureHandle& texture,
- const ColorF& color )
- {
- // Sanity!
- AssertFatal( mpDebugStats != NULL, "Debug stats have not been configured." );
- PROFILE_START(BatchRender_SubmitQuad);
- // Do we have anything batched?
- if ( mQuadCount > 0 )
- {
- // Yes, so do we have any existing colors?
- if ( mColorCount == 0 )
- {
- // No, so flush if color is specified.
- if ( color != NoColor )
- flush( mpDebugStats->batchColorStateFlush );
- }
- else
- {
- // Yes, so flush if color is not specified.
- if ( color == NoColor )
- flush( mpDebugStats->batchColorStateFlush );
- }
- }
- // Is a color specified?
- if ( color != NoColor )
- {
- // Yes, so add colors.
- mColorBuffer[mColorCount++] = color;
- mColorBuffer[mColorCount++] = color;
- mColorBuffer[mColorCount++] = color;
- mColorBuffer[mColorCount++] = color;
- }
- // Strict order mode?
- if ( mStrictOrderMode )
- {
- // Is there is a texture change.
- if ( texture != mStrictOrderTextureHandle )
- {
- // Yes, so flush.
- flush( mpDebugStats->batchTextureChangeFlush );
- }
- // Add new indices.
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
- mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
- // Set strict order mode texture handle.
- mStrictOrderTextureHandle = texture;
- }
- else
- {
- // No, so fetch texture binding.
- const U32 textureBinding = texture.getGLName();
- indexVectorType* pIndexVector = NULL;
- // Find texture binding.
- textureBatchType::iterator itr = mTextureBatchMap.find( textureBinding );
- // Did we find a texture binding?
- if ( itr == mTextureBatchMap.end() )
- {
- // No, so fetch index vector pool count.
- const U32 indexVectorPoolCount = mIndexVectorPool.size();
- // Do we have any in the index vector pool?
- if ( indexVectorPoolCount > 0 )
- {
- // Yes, so use it.
- pIndexVector = mIndexVectorPool[indexVectorPoolCount-1];
- mIndexVectorPool.pop_back();
- }
- else
- {
- // No, so generate one.
- pIndexVector = new indexVectorType( 6 * 6 );
- }
- // Insert into texture batch map.
- mTextureBatchMap.insert( textureBinding, pIndexVector );
- }
- else
- {
- // Yes, so fetch it.
- pIndexVector = itr->value;
- }
- // Add vertex start.
- pIndexVector->push_back( mVertexCount );
- }
- // Add textured vertices.
- // NOTE: We swap #2/#3 here.
- mVertexBuffer[mVertexCount++] = vertexPos0;
- mVertexBuffer[mVertexCount++] = vertexPos1;
- mVertexBuffer[mVertexCount++] = vertexPos3;
- mVertexBuffer[mVertexCount++] = vertexPos2;
- mTextureBuffer[mTextureResidentCount++] = texturePos0;
- mTextureBuffer[mTextureResidentCount++] = texturePos1;
- mTextureBuffer[mTextureResidentCount++] = texturePos3;
- mTextureBuffer[mTextureResidentCount++] = texturePos2;
- // Stats.
- mpDebugStats->batchTrianglesSubmitted+=2;
- // Increase quad count.
- mQuadCount++;
- // Have we reached the buffer limit?
- if ( mQuadCount == BATCHRENDER_MAXQUADS )
- {
- // Yes, so flush.
- flush( mpDebugStats->batchBufferFullFlush );
- }
- // Is batching enabled?
- if ( !mBatchEnabled )
- {
- // No, so flush immediately.
- // NOTE: Technically this is still batching but will still revert to using
- // more draw calls therefore can be used in comparison.
- flushInternal();
- }
- PROFILE_END(); // BatchRender_SubmitQuad
- }
- //-----------------------------------------------------------------------------
- void BatchRender::flush( U32& reasonMetric )
- {
- // Finish if no quads to flush.
- if ( mQuadCount == 0 )
- return;
- // Increase reason metric.
- reasonMetric++;
- // Flush.
- flushInternal();
- }
- //-----------------------------------------------------------------------------
- void BatchRender::flush( void )
- {
- // Finish if no quads to flush.
- if ( mQuadCount == 0 )
- return;
- // Increase reason metric.
- mpDebugStats->batchAnonymousFlush++;
- // Flush.
- flushInternal();
- }
- //-----------------------------------------------------------------------------
- void BatchRender::flushInternal( void )
- {
- // Finish if no quads to flush.
- if ( mQuadCount == 0 )
- return;
- PROFILE_START(T2D_BatchRender_flush);
- // Stats.
- mpDebugStats->batchFlushes++;
- if ( mWireframeMode )
- {
- // Disable texturing.
- glDisable( GL_TEXTURE_2D );
- // Set the polygon mode to line.
- glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
- }
- else
- {
- // Enable texturing.
- glEnable( GL_TEXTURE_2D );
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- // Set the polygon mode to fill.
- glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
- // Set blend mode.
- if ( mBlendMode )
- {
- glEnable( GL_BLEND );
- glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
- glColor4f(mBlendColor.red, mBlendColor.green, mBlendColor.blue, mBlendColor.alpha );
- }
- else
- {
- glDisable( GL_BLEND );
- glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
- }
- // Set alpha-blend mode.
- if ( mAlphaTestMode >= 0.0f )
- {
- glEnable( GL_ALPHA_TEST );
- glAlphaFunc( GL_GREATER, mAlphaTestMode );
- }
- else
- {
- glDisable( GL_ALPHA_TEST );
- }
- // Enable vertex and texture arrays.
- glEnableClientState( GL_VERTEX_ARRAY );
- glVertexPointer( 2, GL_FLOAT, 0, mVertexBuffer );
- glTexCoordPointer( 2, GL_FLOAT, 0, mTextureBuffer );
- // Use the texture coordinates if not in wireframe mode.
- if ( !mWireframeMode )
- glEnableClientState( GL_TEXTURE_COORD_ARRAY );
- // Do we have any colors?
- if ( mColorCount > 0 )
- {
- // Yes, so enable color array.
- glEnableClientState( GL_COLOR_ARRAY );
- glColorPointer( 4, GL_FLOAT, 0, mColorBuffer );
- }
- // Strict order mode?
- if ( mStrictOrderMode )
- {
- // Bind the texture if not in wireframe mode.
- if ( !mWireframeMode )
- glBindTexture( GL_TEXTURE_2D, mStrictOrderTextureHandle.getGLName() );
- // Yes, so do we have a single quad?
- if ( mQuadCount == 1 )
- {
- // Yes, so draw the quad using a triangle-strip with indexes.
- glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
- // Stats.
- mpDebugStats->batchDrawCallsStrictSingle++;
- // Stats.
- if ( mpDebugStats->batchMaxTriangleDrawn < 2 )
- mpDebugStats->batchMaxTriangleDrawn = 2;
- }
- else
- {
- // Draw the quads using triangles with indexes.
- glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
- // Stats.
- mpDebugStats->batchDrawCallsStrictMultiple++;
- // Stats.
- const U32 trianglesDrawn = mIndexCount / 3;
- if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
- mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
- }
- // Stats.
- if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
- mpDebugStats->batchMaxVertexBuffer = mVertexCount;
- }
- else
- {
- // No, so iterate texture batch map.
- for( textureBatchType::iterator batchItr = mTextureBatchMap.begin(); batchItr != mTextureBatchMap.end(); ++batchItr )
- {
- // Fetch texture binding.
- const U32 textureBinding = batchItr->key;
- // Fetch index vector.
- indexVectorType* pIndexVector = batchItr->value;
- // Reset index count.
- mIndexCount = 0;
- // Iterate indexes.
- for( indexVectorType::iterator indexItr = pIndexVector->begin(); indexItr != pIndexVector->end(); ++indexItr )
- {
- // Fetch quad index.
- U32 quadIndex = (*indexItr);
- // Add new indices.
- mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
- mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
- mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
- mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
- mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
- mIndexBuffer[mIndexCount++] = (U16)quadIndex;
- }
- // Sanity!
- AssertFatal( mIndexCount > 0, "No batching indexes are present." );
- // Bind the texture if not in wireframe mode.
- if ( !mWireframeMode )
- glBindTexture( GL_TEXTURE_2D, textureBinding );
- // Draw the quads using triangles with indexes.
- glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
- // Stats.
- mpDebugStats->batchDrawCallsSorted++;
- // Stats.
- if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
- mpDebugStats->batchMaxVertexBuffer = mVertexCount;
- // Stats.
- const U32 trianglesDrawn = mIndexCount / 3;
- if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
- mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
- // Return index vector to pool.
- pIndexVector->clear();
- mIndexVectorPool.push_back( pIndexVector );
- }
- // Clear texture batch map.
- mTextureBatchMap.clear();
- }
- // Reset common render state.
- glDisableClientState( GL_VERTEX_ARRAY );
- glDisableClientState( GL_TEXTURE_COORD_ARRAY );
- glDisableClientState( GL_COLOR_ARRAY );
- glDisable( GL_ALPHA_TEST );
- glDisable( GL_BLEND );
- glDisable( GL_TEXTURE_2D );
- glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- // Reset batch state.
- mQuadCount = 0;
- mVertexCount = 0;
- mTextureResidentCount = 0;
- mIndexCount = 0;
- mColorCount = 0;
- PROFILE_END(); // T2D_BatchRender_flush
- }
- //-----------------------------------------------------------------------------
- void BatchRender::RenderQuad(
- const Vector2& vertexPos0,
- const Vector2& vertexPos1,
- const Vector2& vertexPos2,
- const Vector2& vertexPos3,
- const Vector2& texturePos0,
- const Vector2& texturePos1,
- const Vector2& texturePos2,
- const Vector2& texturePos3 )
- {
- glBegin( GL_TRIANGLE_STRIP );
- glTexCoord2f( texturePos0.x, texturePos0.y );
- glVertex2f( vertexPos0.x, vertexPos0.y );
- glTexCoord2f( texturePos1.x, texturePos1.y );
- glVertex2f( vertexPos1.x, vertexPos1.y );
- glTexCoord2f( texturePos3.x, texturePos3.y );
- glVertex2f( vertexPos3.x, vertexPos3.y );
- glTexCoord2f( texturePos2.x, texturePos2.y );
- glVertex2f( vertexPos2.x, vertexPos2.y );
- glEnd();
- }
|