Show render.cpp syntax highlighted
/***************************************************************************
render.cpp - Render primitive batching
-------------------
begin : Tue Apr 1 2003
copyright : (C) 2003 by Reality Rift Studios
email : mattias@realityrift.com
***************************************************************************
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is the NeoEngine, NeoDevOpenGL, render.cpp
The Initial Developer of the Original Code is Mattias Jansson.
Portions created by Mattias Jansson are Copyright (C) 2003
Reality Rift Studios. All Rights Reserved.
***************************************************************************/
#include "device.h"
#include "rendertarget.h"
#include "renderqueue.h"
#include "op.h"
#include <neoengine/vertex.h>
#include <neoengine/polygon.h>
#include <neoengine/logstream.h>
using namespace std;
using namespace NeoEngine;
namespace NeoOGL
{
inline uint64_t MakeStateBits( const MaterialPtr &pkMaterial, unsigned int uiPass );
void Device::SetPolygonOffset( float inFactor, float inUnit){
glPolygonOffset( inFactor, inUnit);
}
void Device::EnablePolygonOffset( ){
glEnable( GL_POLYGON_OFFSET_FILL );
}
void Device::DisablePolygonOffset( ){
glDisable( GL_POLYGON_OFFSET_FILL );
}
GLuint g_OclQuery = -1;
void Device::StartOccluderTest(){
neoglGenQueriesARB( 1, &g_OclQuery );
neoglBeginQueryARB( GL_SAMPLES_PASSED_ARB, g_OclQuery );
glColorMask(0, 0, 0, 0);
}
void Device::StopOccluderTest(){
GLint result = 0;
neoglEndQueryARB( GL_SAMPLES_PASSED_ARB );
neoglGetQueryObjectuivARB( g_OclQuery, GL_QUERY_RESULT_ARB, &result);
this->SetOclCounter((long) result + this->GetOclCounter() );
neoglDeleteQueriesARB( 1, &g_OclQuery );
glColorMask(1, 1, 1, 1);
}
void Device::Render( const RenderPrimitive &rkData, unsigned int uiFlags )
{
m_pkCurTarget->Queue( rkData, uiFlags );
}
RenderDevice::CULLMODE Device::SetCullMode( RenderDevice::CULLMODE eCullMode )
{
CULLMODE eLastMode = m_eCullMode;
m_eCullMode = eCullMode;
if( eCullMode == CULLNONE )
glDisable( GL_CULL_FACE );
else
{
if( !m_bIsRenderingTexture )
glCullFace( ( eCullMode == CULLFRONT ) ? GL_FRONT : ( ( eCullMode == CULLBACK ) ? GL_BACK : GL_FRONT_AND_BACK ) );
else
glCullFace( ( eCullMode == CULLFRONT ) ? GL_BACK : ( ( eCullMode == CULLBACK ) ? GL_FRONT : GL_FRONT_AND_BACK ) );
glEnable( GL_CULL_FACE );
}
return eLastMode;
}
ImageData *Device::ReadPixels()
{
ImageData *pkImage = new ImageData;
int iWidth = m_pkCurTarget->GetWidth();
int iHeight = m_pkCurTarget->GetHeight();
pkImage->m_pucData = new unsigned char[ iWidth * iHeight * 3 ];
pkImage->m_iWidth = iWidth;
pkImage->m_iHeight = iHeight;
pkImage->m_eFormat = NeoEngine::Texture::RGB;
pkImage->m_iChannels = 3;
pkImage->m_iBPP = 24;
glReadPixels( 0, 0, iWidth, iHeight, GL_RGB, GL_UNSIGNED_BYTE, pkImage->m_pucData );
return pkImage;
}
void RenderTarget::Queue( const RenderPrimitive &rkData, unsigned int uiFlags )
{
RenderQueue *pkQueue = ( uiFlags & RenderPrimitive::NOTRANSLATION ) ? m_pkNoTransQueue : m_pkNormalQueue;
unsigned int uiPasses = rkData.m_pkMaterial ? ( rkData.m_pkMaterial->m_vpkPasses.size() + 1 ) : 1;
RenderPrimitive *pkOp = 0;
for( unsigned int uiPass = 0; uiPass < uiPasses; ++uiPass )
{
if( pkQueue->m_iNumOps >= pkQueue->m_iMaxOps )
pkQueue->AllocArray();
int iOp = pkQueue->m_iNumOps++;
pkOp = &pkQueue->m_ppkOpArray[ iOp >> OpArray::ARRAYSHIFT ]->m_akOps[ iOp & OpArray::ARRAYMASK ];
pkOp->m_ePrimitive = rkData.m_ePrimitive;
pkOp->m_pkMaterial = ( (bool)rkData.m_pkMaterial && !m_pkDevice->m_bForceDefaultMaterial ) ? rkData.m_pkMaterial : m_pkDevice->m_pkDefaultMaterial;
pkOp->m_kModelMatrix = rkData.m_kModelMatrix;
pkOp->m_kInvModelMatrix = rkData.m_kInvModelMatrix;
pkOp->m_uiNumPrimitives = rkData.m_uiNumPrimitives;
pkOp->m_uiPass = uiPass;
switch( rkData.m_ePrimitive )
{
case RenderPrimitive::TRIANGLES:
{
pkOp->m_pkVertexBuffer = rkData.m_pkVertexBuffer;
pkOp->m_pkPolygonBuffer = rkData.m_pkPolygonBuffer;
pkOp->m_pkPolygonStripBuffer = 0;
pkQueue->m_puiOpSort[iOp] = MakeStateBits( pkOp->m_pkMaterial, uiPass );
break;
}
case RenderPrimitive::TRIANGLESTRIP:
{
pkOp->m_pkVertexBuffer = rkData.m_pkVertexBuffer;
pkOp->m_pkPolygonBuffer = 0;
pkOp->m_pkPolygonStripBuffer = rkData.m_pkPolygonStripBuffer;
pkQueue->m_puiOpSort[iOp] = MakeStateBits( pkOp->m_pkMaterial, uiPass );
break;
}
case RenderPrimitive::POINTSPRITES:
{
pkOp->m_fSize = ( rkData.m_fSize > 0.0f ) ? rkData.m_fSize : 1.0f;
pkOp->m_pkVertexBuffer = rkData.m_pkVertexBuffer;
pkOp->m_pkPolygonBuffer = 0;
pkOp->m_pkPolygonStripBuffer = 0;
pkQueue->m_puiOpSort[iOp] = MakeStateBits( pkOp->m_pkMaterial, uiPass );
break;
}
case RenderPrimitive::LINES:
case RenderPrimitive::LINESTRIP:
{
pkOp->m_fSize = ( rkData.m_fSize > 0.0f ) ? rkData.m_fSize : 1.0f; //Line width
pkOp->m_pkVertexBuffer = rkData.m_pkVertexBuffer;
pkOp->m_pkPolygonBuffer = 0;
pkOp->m_pkPolygonStripBuffer = 0;
//Sort after polygons but before points
pkQueue->m_puiOpSort[iOp] = 0xFFFFFFFE;
break;
}
case RenderPrimitive::POINTS:
{
pkOp->m_fSize = ( rkData.m_fSize > 0.0f ) ? rkData.m_fSize : 1.0f; //Point size
pkOp->m_pkVertexBuffer = rkData.m_pkVertexBuffer;
pkOp->m_pkPolygonBuffer = 0;
pkOp->m_pkPolygonStripBuffer = 0;
//Sort last
pkQueue->m_puiOpSort[iOp] = 0xFFFFFFFF;
break;
}
default:
{
assert( !"Invalid primitive" );
break;
}
}
}
if( Buffer::s_eUploadPolicy == Buffer::ONRENDER )
{
if( pkOp->m_pkVertexBuffer->IsDirty() )
pkOp->m_pkVertexBuffer->Upload();
if( pkOp->m_pkPolygonBuffer )
if( pkOp->m_pkPolygonBuffer->IsDirty() )
pkOp->m_pkPolygonBuffer->Upload();
if( pkOp->m_pkPolygonStripBuffer )
if( pkOp->m_pkPolygonStripBuffer->IsDirty() )
pkOp->m_pkPolygonStripBuffer->Upload();
}
}
//STATE BITFIELD LAYOUT
//
// F000 0000 0000 0000 - Blend on/off bit and z buffer bits
// 00FF F000 0000 0000 - Vertex shader identifier
// 0000 0FFF 0000 0000 - Fragment shader identifier
// 0000 0000 FFF0 0000 - Primary texture identifier
// 0000 0000 000F F000 - Secondary texture identifier
// 0000 0000 0000 00F0 - Destination framebuffer blend mode
// 0000 0000 0000 000F - Source framebuffer blend mode
//
// 0F00 0000 0000 0F00 - Unused
#ifndef __GNUC__
# define MAKE64BIT(x) x
#else
# define MAKE64BIT(x) x##LL
#endif
//State bits
#define NEOGL_BLEND_ENABLED MAKE64BIT( 0x8000000000000000 )
#define NEOGL_BLEND_DISABLED MAKE64BIT( 0x0000000000000000 )
#define NEOGL_BLENDBITS MAKE64BIT( 0x8000000000000000 )
#define NEOGL_BLENDBITS_SHIFT 63
#define NEOGL_ZTEST_GEQUAL MAKE64BIT( 0x0000000000000000 )
#define NEOGL_ZTEST_GREATER MAKE64BIT( 0x0000000000000000 )
#define NEOGL_ZTEST_LESS MAKE64BIT( 0x2000000000000000 )
#define NEOGL_ZTEST_LEQUAL MAKE64BIT( 0x2000000000000000 )
#define NEOGL_ZTEST_EQUAL MAKE64BIT( 0x4000000000000000 )
#define NEOGL_ZTEST_ALWAYS MAKE64BIT( 0x6000000000000000 )
#define NEOGL_ZTESTBITS MAKE64BIT( 0x6000000000000000 )
#define NEOGL_ZTESTBITS_SHIFT 61
#define NEOGL_ZWRITE_ENABLED MAKE64BIT( 0x0000000000000000 )
#define NEOGL_ZWRITE_DISABLED MAKE64BIT( 0x1000000000000000 )
#define NEOGL_ZWRITEBITS MAKE64BIT( 0x1000000000000000 )
#define NEOGL_ZWRITEBITS_SHIFT 60
#define NEOGL_VERTEXSHADERBITS MAKE64BIT( 0x00FFF00000000000 )
#define NEOGL_VERTEXSHADERBITS_SHIFT 44
#define NEOGL_FRAGMENTSHADERBITS MAKE64BIT( 0x00000FFF00000000 )
#define NEOGL_FRAGMENTSHADERBITS_SHIFT 32
#define NEOGL_TEXTUREBITS MAKE64BIT( 0x00000000FFF00000 )
#define NEOGL_TEXTUREBITS_SHIFT 20
#define NEOGL_SECTEXTUREBITS MAKE64BIT( 0x00000000000FF000 )
#define NEOGL_SECTEXTUREBITS_SHIFT 12
#define NEOGL_DSTBLENDBITS MAKE64BIT( 0x00000000000000F0 )
#define NEOGL_DSTBLENDBITS_SHIFT 4
#define NEOGL_SRCBLENDBITS MAKE64BIT( 0x000000000000000F )
#define NEOGL_SRCBLENDBITS_SHIFT 0
uint64_t MakeStateBits( const MaterialPtr &pkMaterial, unsigned int uiPass )
{
uint64_t uiStateBits = 0;
const MaterialPass *pkMat = !uiPass ? (const MaterialPass*)((const Material*)pkMaterial) : pkMaterial->m_vpkPasses[ uiPass - 1 ];
//Add blend bit
if( pkMat->m_kBlendMode.Get() != BlendMode::NORMAL )
uiStateBits |= NEOGL_BLEND_ENABLED;
//Add Z test / write bits
switch( pkMat->m_kZBufferMode.Get() )
{
case ZBufferMode::LESSWRITE:
uiStateBits |= ( NEOGL_ZTEST_LESS | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::LEQUALWRITE:
default:
uiStateBits |= ( NEOGL_ZTEST_LEQUAL | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::EQUALWRITE:
uiStateBits |= ( NEOGL_ZTEST_EQUAL | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::GEQUALWRITE:
uiStateBits |= ( NEOGL_ZTEST_GEQUAL | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::GREATERWRITE:
uiStateBits |= ( NEOGL_ZTEST_GREATER | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::ALWAYSWRITE:
uiStateBits |= ( NEOGL_ZTEST_ALWAYS | NEOGL_ZWRITE_ENABLED );
break;
case ZBufferMode::LESSNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_LESS | NEOGL_ZWRITE_DISABLED );
break;
case ZBufferMode::LEQUALNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_LEQUAL | NEOGL_ZWRITE_DISABLED );
break;
case ZBufferMode::EQUALNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_EQUAL | NEOGL_ZWRITE_DISABLED );
break;
case ZBufferMode::GEQUALNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_GEQUAL | NEOGL_ZWRITE_DISABLED );
break;
case ZBufferMode::GREATERNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_GREATER | NEOGL_ZWRITE_DISABLED );
break;
case ZBufferMode::ALWAYSNOWRITE:
uiStateBits |= ( NEOGL_ZTEST_ALWAYS | NEOGL_ZWRITE_DISABLED );
break;
}
if( ((TextureLayer*)pkMat)->GetTexture() )
{
uiStateBits |= ( ((TextureLayer*)pkMat)->GetTexture()->GetID() << NEOGL_TEXTUREBITS_SHIFT ) & NEOGL_TEXTUREBITS;
if( pkMat->m_vpkTextureLayers.size() && pkMat->m_vpkTextureLayers[0]->GetTexture() )
uiStateBits |= ( pkMat->m_vpkTextureLayers[0]->GetTexture()->GetID() << NEOGL_SECTEXTUREBITS_SHIFT ) & NEOGL_SECTEXTUREBITS;
}
if( pkMat->m_pkProgramShader )
uiStateBits |= ( (uint64_t)pkMat->m_pkProgramShader->GetID() << NEOGL_FRAGMENTSHADERBITS_SHIFT ) & NEOGL_FRAGMENTSHADERBITS;
//Add blend src/dst mode bits
uiStateBits |= ( pkMaterial->m_kBlendMode.Get() & BlendMode::SRCBITS ) & NEOGL_SRCBLENDBITS;
uiStateBits |= ( pkMaterial->m_kBlendMode.Get() & BlendMode::DESTBITS ) & NEOGL_DSTBLENDBITS;
return uiStateBits;
}
}; // namespace NeoOGL
See more files for this project here