// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdopengl.h" #include "driver_opengl.h" #include "nel/3d/index_buffer.h" #include "driver_opengl_vertex_buffer_hard.h" using namespace std; using namespace NLMISC; // *************************************************************************** // Flags for software vertex skinning. #define NL3D_DRV_SOFTSKIN_VNEEDCOMPUTE 3 #define NL3D_DRV_SOFTSKIN_VMUSTCOMPUTE 1 #define NL3D_DRV_SOFTSKIN_VCOMPUTED 0 // 3 means "vertex may need compute". // 1 means "Primitive say vertex must be computed". // 0 means "vertex is computed". // 500K min. #define NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE (512*1024) namespace NL3D { #ifdef NL_STATIC #ifdef USE_OPENGLES namespace NLDRIVERGLES { #else namespace NLDRIVERGL { #endif #endif // *************************************************************************** CVBDrvInfosGL::CVBDrvInfosGL(CDriverGL *drv, ItVBDrvInfoPtrList it, CVertexBuffer *vb) : IVBDrvInfos(drv, it, vb) { H_AUTO_OGL(CVBDrvInfosGL_CVBDrvInfosGL) _DriverGL = drv; _VBHard = NULL; _SystemMemory = NULL; } // *************************************************************************** CVBDrvInfosGL::~CVBDrvInfosGL() { H_AUTO_OGL(CVBDrvInfosGL_CVBDrvInfosGLDtor) // Restore non resident memory if (VertexBufferPtr) { VertexBufferPtr->setLocation(CVertexBuffer::NotResident); VertexBufferPtr = NULL; } if (_VBHard) { _VBHard->disable(); _DriverGL->_VertexBufferHardSet.erase(_VBHard); } if (_SystemMemory) { delete [] _SystemMemory; } _SystemMemory = NULL; _VBHard = NULL; } // *************************************************************************** uint8 *CVBDrvInfosGL::lock (uint /* first */, uint /* last */, bool /* readOnly */) { H_AUTO_OGL(CVBDrvInfosGL_lock) if (_VBHard) { return (uint8*)_VBHard->lock (); } else { // Should be a system memory nlassert (_SystemMemory); return _SystemMemory; } } // *************************************************************************** void CVBDrvInfosGL::unlock (uint first, uint last) { H_AUTO_OGL(CVBDrvInfosGL_unlock) if (_VBHard) { _VBHard->unlock(first, last); } else { // Should be a system memory nlassert (_SystemMemory); } } // *************************************************************************** bool CDriverGL::setupVertexBuffer(CVertexBuffer& VB) { H_AUTO_OGL(CDriverGL_setupVertexBuffer) // 2. If necessary, do modifications. //================================== const bool touched = (VB.getTouchFlags() & (CVertexBuffer::TouchedReserve|CVertexBuffer::TouchedVertexFormat)) != 0; if( touched || (VB.DrvInfos == NULL)) { // delete first if(VB.DrvInfos) delete VB.DrvInfos; VB.DrvInfos = NULL; // create only if some vertices if(VB.getNumVertices()) { // 1. Retrieve/Create driver shader. //================================== // insert into driver list. (so it is deleted when driver is deleted). ItVBDrvInfoPtrList it= _VBDrvInfos.insert(_VBDrvInfos.end(), (NL3D::IVBDrvInfos*)NULL); // create and set iterator, for future deletion. CVBDrvInfosGL *info = new CVBDrvInfosGL(this, it, &VB); *it= VB.DrvInfos = info; // Preferred memory, AGPVolatile only goes through when ARBMapBufferRange is available CVertexBuffer::TPreferredMemory preferred = VB.getPreferredMemory (); if ((preferred == CVertexBuffer::RAMVolatile) || (preferred == CVertexBuffer::AGPVolatile && !_Extensions.ARBMapBufferRange)) preferred = CVertexBuffer::RAMPreferred; const uint size = VB.capacity()*VB.getVertexSize(); uint preferredMemory = _Extensions.DisableHardwareVertexArrayAGP ? CVertexBuffer::RAMPreferred : preferred; while (preferredMemory != CVertexBuffer::RAMPreferred) { // Vertex buffer hard info->_VBHard = createVertexBufferHard(size, VB.capacity(), (CVertexBuffer::TPreferredMemory)preferredMemory, &VB); if (info->_VBHard) break; if ((CVertexBuffer::TPreferredMemory)preferredMemory == CVertexBuffer::AGPVolatile) { preferredMemory = CVertexBuffer::RAMPreferred; break; } preferredMemory--; } // No memory found ? Use system memory if (info->_VBHard == NULL) { nlassert (info->_SystemMemory == NULL); info->_SystemMemory = new uint8[size]; } // Upload the data VB.setLocation(preferredMemory == CVertexBuffer::AGPVolatile ? CVertexBuffer::AGPResident : (CVertexBuffer::TLocation)preferredMemory); } } return true; } // *************************************************************************** bool CDriverGL::activeVertexBuffer(CVertexBuffer& VB) { H_AUTO_OGL(CDriverGL_activeVertexBuffer) // NB: must duplicate changes in activeVertexBufferHard() uint32 flags; // In any case, we'll erase any special vertex setup for Lightmap Material _LastVertexSetupIsLightMap= false; // setup if (!setupVertexBuffer(VB)) return false; if (VB.getNumVertices()==0) return true; // Fill the buffer if in local memory VB.fillBuffer (); // Get VB flags, to setup matrixes and arrays. flags=VB.getVertexFormat(); // 2. Setup Arrays. //=================== // For MultiPass Material. CVertexBufferInfo::TVBMode lastVBMode = _LastVB.VBMode; CVBDrvInfosGL *info= safe_cast((IVBDrvInfos*)VB.DrvInfos); if (!info->_VBHard || (info->_VBHard && !info->_VBHard->isInvalid())) { _LastVB.setupVertexBuffer(VB); if (lastVBMode == CVertexBufferInfo::HwARB && _LastVB.VBMode != CVertexBufferInfo::HwARB) { _DriverGLStates.bindARBVertexBuffer(0); // unbind ARB vertex buffer } } if (info->_VBHard == NULL) { // Fence mgt. fenceOnCurVBHardIfNeeded(NULL); // Disable the current vertexBufferHard if setuped. if(_CurrentVertexBufferHard) _CurrentVertexBufferHard->disable(); } else { // 2. Setup Arrays. //=================== // Fence mgt. fenceOnCurVBHardIfNeeded(info->_VBHard); // Enable the vertexArrayRange of this array. info->_VBHard->enable(); } if (!info->_VBHard || (info->_VBHard && !info->_VBHard->isInvalid())) { setupGlArrays(_LastVB); } return true; } // *************************************************************************** bool CDriverGL::activeIndexBuffer(CIndexBuffer& IB) { H_AUTO_OGL(CDriverGL_activeIndexBuffer) _LastIB.setupIndexBuffer(IB); return true; } // *************************************************************************** bool CDriverGL::renderLines(CMaterial& mat, uint32 firstIndex, uint32 nlines) { H_AUTO_OGL(CDriverGL_renderLines) // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) || _LastIB._Values == NULL ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderTriangles(CMaterial& mat, uint32 firstIndex, uint32 ntris) { H_AUTO_OGL(CDriverGL_renderTriangles); // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) || _LastIB._Values == NULL ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderSimpleTriangles(uint32 firstTri, uint32 ntris) { H_AUTO_OGL(CDriverGL_renderSimpleTriangles); nlassert(ntris>0); // update matrix and Light in OpenGL if needed refreshRenderSetup(); if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // Don't setup any material here. // render primitives. //============================== // NO MULTIPASS HERE!! // draw the primitives. (nb: ntris>0). if (_LastIB._Format == CIndexBuffer::Indices16) { glDrawElements(GL_TRIANGLES,3*ntris,GL_UNSIGNED_SHORT, ((uint16 *) _LastIB._Values)+firstTri); } else { #ifdef USE_OPENGLES nlerror("not available in OpenGL ES 1.0, only use 16 bits indices"); #else nlassert(_LastIB._Format == CIndexBuffer::Indices32); glDrawElements(GL_TRIANGLES,3*ntris,GL_UNSIGNED_INT, ((uint32 *) _LastIB._Values)+firstTri); #endif } // Profiling. _PrimitiveProfileIn.NTriangles+= ntris; _PrimitiveProfileOut.NTriangles+= ntris; // We have render some prims. inform the VBHard. if(_CurrentVertexBufferHard) _CurrentVertexBufferHard->GPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderRawPoints(CMaterial& mat, uint32 startIndex, uint32 numPoints) { H_AUTO_OGL(CDriverGL_renderRawPoints) // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderRawLines(CMaterial& mat, uint32 startIndex, uint32 numLines) { H_AUTO_OGL(CDriverGL_renderRawLines) // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderRawTriangles(CMaterial& mat, uint32 startIndex, uint32 numTris) { H_AUTO_OGL(CDriverGL_renderRawTriangles) // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** bool CDriverGL::renderRawQuads(CMaterial& mat, uint32 startIndex, uint32 numQuads) { H_AUTO_OGL(CDriverGL_renderRawQuads) if (!numQuads) return true; // update matrix and Light in OpenGL if needed refreshRenderSetup(); // setup material if ( !setupMaterial(mat) ) return false; if (_CurrentVertexBufferHard && _CurrentVertexBufferHard->isInvalid()) return true; const uint32 QUAD_BATCH_SIZE = 2048; static GLshort defaultIndices[QUAD_BATCH_SIZE * 6]; static bool init = false; if (!init) { // setup the base index buffer for(uint k = 0; k < QUAD_BATCH_SIZE; ++k) { // first tri defaultIndices[k * 6] = (GLshort) (k * 4); defaultIndices[k * 6 + 1] = (GLshort) (k * 4 + 1); defaultIndices[k * 6 + 2] = (GLshort) (k * 4 + 2); // second tri defaultIndices[k * 6 + 3] = (GLshort) (k * 4); defaultIndices[k * 6 + 4] = (GLshort) (k * 4 + 2); defaultIndices[k * 6 + 5] = (GLshort) (k * 4 + 3); } init = true; } // render primitives. //============================== // start multipass. uint nPass; nPass= beginMultiPass(); // draw all passes. for(uint pass=0;passGPURenderingAfterFence= true; return true; } // *************************************************************************** void CDriverGL::setupUVPtr(uint stage, CVertexBufferInfo &VB, uint uvId) { H_AUTO_OGL(CDriverGL_setupUVPtr) // sould not be called with vertex program Array setuped. nlassert(!_LastSetupGLArrayVertexProgram); _DriverGLStates.clientActiveTextureARB(stage); if (VB.VertexFormat & (CVertexBuffer::TexCoord0Flag< _MaxVerticesByVBHard) return NULL; // Create a CVertexBufferHardGL IVertexBufferHardGL *vbHard = NULL; // let the VAR create the vbhard. vbHard= vertexArrayRange->createVBHardGL(size, vb); // if fails if(!vbHard) { return NULL; } else { // insert in list. return _VertexBufferHardSet.insert(vbHard); } } } // *************************************************************************** const uint CDriverGL::NumCoordinatesType[CVertexBuffer::NumType]= { 1, // Double1 1, // Float1 1, // Short1 2, // Double2 2, // Float2 2, // Short2 3, // Double3 3, // Float3 3, // Short3 4, // Double4 4, // Float4 4, // Short4 4 // UChar4 }; // *************************************************************************** const uint CDriverGL::GLType[CVertexBuffer::NumType]= { #ifdef USE_OPENGLES GL_FLOAT, // Double1 GL_FLOAT, // Float1 GL_SHORT, // Short1 GL_FLOAT, // Double2 GL_FLOAT, // Float2 GL_SHORT, // Short2 GL_FLOAT, // Double3 GL_FLOAT, // Float3 GL_SHORT, // Short3 GL_FLOAT, // Double4 GL_FLOAT, // Float4 GL_SHORT, // Short4 GL_UNSIGNED_BYTE // UChar4 #else GL_DOUBLE, // Double1 GL_FLOAT, // Float1 GL_SHORT, // Short1 GL_DOUBLE, // Double2 GL_FLOAT, // Float2 GL_SHORT, // Short2 GL_DOUBLE, // Double3 GL_FLOAT, // Float3 GL_SHORT, // Short3 GL_DOUBLE, // Double4 GL_FLOAT, // Float4 GL_SHORT, // Short4 GL_UNSIGNED_BYTE // UChar4 #endif }; // *************************************************************************** const bool CDriverGL::GLTypeIsIntegral[CVertexBuffer::NumType] = { false, // Double1 false, // Float1 true, // Short1 false, // Double2 false, // Float2 true, // Short2 false, // Double3 false, // Float3 true, // Short3 false, // Double4 false, // Float4 true, // Short4 true // UChar4 }; // *************************************************************************** const uint CDriverGL::GLVertexAttribIndex[CVertexBuffer::NumValue]= { 0, // Position 2, // Normal 8, // TexCoord0 9, // TexCoord1 10, // TexCoord2 11, // TexCoord3 12, // TexCoord4 13, // TexCoord5 14, // TexCoord6 15, // TexCoord7 3, // PrimaryColor 4, // SecondaryColor 1, // Weight 6, // Empty (PaletteSkin) 5, // Fog 7, // Empty }; // *************************************************************************** void CDriverGL::setupGlArraysStd(CVertexBufferInfo &vb) { H_AUTO_OGL(CDriverGL_setupGlArraysStd) uint32 flags= vb.VertexFormat; if (vb.VBMode == CVertexBufferInfo::HwARB) { _DriverGLStates.bindARBVertexBuffer(vb.VertexObjectId); } switch(vb.VBMode) { case CVertexBufferInfo::SysMem: case CVertexBufferInfo::HwNVIDIA: case CVertexBufferInfo::HwARB: { // setup vertex ptr. //----------- uint numVertexCoord = CVertexBuffer::NumComponentsType[vb.Type[CVertexBuffer::Position]]; nlassert (numVertexCoord >= 2); _DriverGLStates.enableVertexArray(true); glVertexPointer(numVertexCoord, GL_FLOAT, vb.VertexSize, vb.ValuePtr[CVertexBuffer::Position]); // setup normal ptr. //----------- // Check for normal param in vertex buffer if (flags & CVertexBuffer::NormalFlag) { // Check type nlassert (vb.Type[CVertexBuffer::Normal]==CVertexBuffer::Float3); _DriverGLStates.enableNormalArray(true); glNormalPointer(GL_FLOAT, vb.VertexSize, vb.ValuePtr[CVertexBuffer::Normal]); } else { _DriverGLStates.enableNormalArray(false); } // Setup Color //----------- // Check for color param in vertex buffer if (flags & CVertexBuffer::PrimaryColorFlag) { // Check type nlassert (vb.Type[CVertexBuffer::PrimaryColor]==CVertexBuffer::UChar4); _DriverGLStates.enableColorArray(true); // Setup ATI VBHard or std ptr. glColorPointer(4,GL_UNSIGNED_BYTE, vb.VertexSize, vb.ValuePtr[CVertexBuffer::PrimaryColor]); } else { _DriverGLStates.enableColorArray(false); } } break; #ifndef USE_OPENGLES case CVertexBufferInfo::HwATI: { // setup vertex ptr. //----------- uint numVertexCoord = CVertexBuffer::NumComponentsType[vb.Type[CVertexBuffer::Position]]; nlassert (numVertexCoord >= 2); _DriverGLStates.enableVertexArray(true); nglArrayObjectATI(GL_VERTEX_ARRAY, numVertexCoord, GL_FLOAT, vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Position]); // setup normal ptr. //----------- // Check for normal param in vertex buffer if (flags & CVertexBuffer::NormalFlag) { // Check type nlassert (vb.Type[CVertexBuffer::Normal]==CVertexBuffer::Float3); _DriverGLStates.enableNormalArray(true); nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Normal]); } else { _DriverGLStates.enableNormalArray(false); } // Setup Color //----------- // Check for color param in vertex buffer if (flags & CVertexBuffer::PrimaryColorFlag) { // Check type nlassert (vb.Type[CVertexBuffer::PrimaryColor]==CVertexBuffer::UChar4); _DriverGLStates.enableColorArray(true); nglArrayObjectATI(GL_COLOR_ARRAY, 4, GL_UNSIGNED_BYTE, vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::PrimaryColor]); } else { _DriverGLStates.enableColorArray(false); } } break; #endif default: nlassert(0); break; } // Setup Uvs //----------- // Get the routing for(uint i=0; i((IProgramDrvInfos *) vp->m_DrvInfo); if (drvInfo) { // Disable all VertexAttribs. for (uint value=0; valueVariants); } } } // no more a vertex program setup. _LastSetupGLArrayVertexProgram= false; } // If last was a standard GL array setup, and now it is a VertexProgram setup. if( !_LastSetupGLArrayVertexProgram && isVertexProgramEnabled () ) { // Disable all standards ptrs. _DriverGLStates.enableVertexArray(false); _DriverGLStates.enableNormalArray(false); _DriverGLStates.enableColorArray(false); _DriverGLStates.enableSecondaryColorArray(false); for(uint i=0; i((IProgramDrvInfos *) vp->m_DrvInfo); if (!drvInfo) return; uint32 flags= vb.VertexFormat; if (vb.VBMode == CVertexBufferInfo::HwARB) { _DriverGLStates.bindARBVertexBuffer(vb.VertexObjectId); } // For each value for (uint value=0; valueUsedVertexComponents) { _DriverGLStates.enableVertexAttribArrayForEXTVertexShader(glIndex, true, drvInfo->Variants); #ifndef USE_OPENGLES // use variant or open gl standard array if (vb.VBMode == CVertexBufferInfo::HwATI) { switch(value) { case CVertexBuffer::Position: // position { nlassert(NumCoordinatesType[type] >= 2); nglArrayObjectATI(GL_VERTEX_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Position]); } break; case CVertexBuffer::Weight: // skin weight { nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSSkinWeightVariant], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Weight]); } break; case CVertexBuffer::Normal: // normal { nlassert(NumCoordinatesType[type] == 3); // must have 3 components for normals nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[value]); } break; case CVertexBuffer::PrimaryColor: // color { nlassert(NumCoordinatesType[type] >= 3); // must have 3 or 4 components for primary color nglArrayObjectATI(GL_COLOR_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::PrimaryColor]); } break; case CVertexBuffer::SecondaryColor: // secondary color { // implemented using a variant, as not available with EXTVertexShader nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSSecondaryColorVariant], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::SecondaryColor]); } break; case CVertexBuffer::Fog: // fog coordinate { // implemented using a variant nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSFogCoordsVariant], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Fog]); } break; case CVertexBuffer::PaletteSkin: // palette skin { // implemented using a variant nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSPaletteSkinVariant], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::PaletteSkin]); } break; case CVertexBuffer::Empty: // empty nlstop; break; case CVertexBuffer::TexCoord0: case CVertexBuffer::TexCoord1: case CVertexBuffer::TexCoord2: case CVertexBuffer::TexCoord3: case CVertexBuffer::TexCoord4: case CVertexBuffer::TexCoord5: case CVertexBuffer::TexCoord6: case CVertexBuffer::TexCoord7: { _DriverGLStates.clientActiveTextureARB(value - CVertexBuffer::TexCoord0); nglArrayObjectATI(GL_TEXTURE_COORD_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[value]); } break; default: nlstop; // invalid value break; } } else #endif { switch(value) { case CVertexBuffer::Position: // position { nlassert(NumCoordinatesType[type] >= 2); glVertexPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]); } break; case CVertexBuffer::Weight: // skin weight { nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported #ifndef USE_OPENGLES nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSSkinWeightVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]); #endif } break; case CVertexBuffer::Normal: // normal { nlassert(NumCoordinatesType[type] == 3); // must have 3 components for normals glNormalPointer(GLType[type], vb.VertexSize, vb.ValuePtr[CVertexBuffer::Normal]); } break; case CVertexBuffer::PrimaryColor: // color { nlassert(NumCoordinatesType[type] >= 3); // must have 3 or 4 components for primary color glColorPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]); } break; case CVertexBuffer::SecondaryColor: // secondary color { // implemented using a variant, as not available with EXTVertexShader nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported #ifndef USE_OPENGLES nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSSecondaryColorVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]); #endif } break; case CVertexBuffer::Fog: // fog coordinate { // implemented using a variant nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported #ifndef USE_OPENGLES nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSFogCoordsVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]); #endif } break; case CVertexBuffer::PaletteSkin: // palette skin { // implemented using a variant nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported #ifndef USE_OPENGLES nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSPaletteSkinVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]); #endif } break; case CVertexBuffer::Empty: // empty nlstop; break; case CVertexBuffer::TexCoord0: case CVertexBuffer::TexCoord1: case CVertexBuffer::TexCoord2: case CVertexBuffer::TexCoord3: case CVertexBuffer::TexCoord4: case CVertexBuffer::TexCoord5: case CVertexBuffer::TexCoord6: case CVertexBuffer::TexCoord7: { _DriverGLStates.clientActiveTextureARB(value - CVertexBuffer::TexCoord0); glTexCoordPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]); } break; default: nlstop; // invalid value break; } } } else { _DriverGLStates.enableVertexAttribArrayForEXTVertexShader(glIndex, false, drvInfo->Variants); } } } // *************************************************************************** void CDriverGL::setupGlArrays(CVertexBufferInfo &vb) { H_AUTO_OGL(CDriverGL_setupGlArrays) // Standard case (NVVertexProgram or no vertex program case) if (_Extensions.NVVertexProgram) { toggleGlArraysForNVVertexProgram(); // Use a vertex program ? if (!isVertexProgramEnabled ()) { setupGlArraysStd(vb); } else { setupGlArraysForNVVertexProgram(vb); } } else if (_Extensions.ARBVertexProgram) { toggleGlArraysForARBVertexProgram(); // Use a vertex program ? if (!isVertexProgramEnabled ()) { setupGlArraysStd(vb); } else { setupGlArraysForARBVertexProgram(vb); } } else if (_Extensions.EXTVertexShader) { toggleGlArraysForEXTVertexShader(); // Use a vertex program ? if (!isVertexProgramEnabled ()) { setupGlArraysStd(vb); } else { setupGlArraysForEXTVertexShader(vb); } } else { // no vertex programs setupGlArraysStd(vb); } } // *************************************************************************** void CVertexBufferInfo::setupVertexBuffer(CVertexBuffer &vb) { H_AUTO_OGL(CDriverGL_setupVertexBuffer) sint i; VertexFormat= vb.getVertexFormat(); VertexSize= vb.getVertexSize(); NumVertices= vb.getNumVertices(); // Lock the buffer CVertexBufferReadWrite access; uint8 *ptr; CVBDrvInfosGL *info= safe_cast((IVBDrvInfos*)vb.DrvInfos); nlassert (info); if (info->_VBHard) { ptr = (uint8*)info->_VBHard->getPointer(); info->_VBHard->setupVBInfos(*this); } else { nlassert (info->_SystemMemory); ptr = info->_SystemMemory; VBMode = SysMem; } // Get value pointer for (i=0; ilock(); _CurrentVertexBufferHard->unlock(); // disable it _CurrentVertexBufferHard->disable(); } // Clear any VertexBufferHard created. _VertexBufferHardSet.clear(); // After, Clear the 2 vertexArrayRange, if any. if(_AGPVertexArrayRange) _AGPVertexArrayRange->free(); if(_VRAMVertexArrayRange) _VRAMVertexArrayRange->free(); } // *************************************************************************** bool CDriverGL::initVertexBufferHard(uint agpMem, uint vramMem) { H_AUTO_OGL(CDriverGL_initVertexBufferHard) if(!supportVertexBufferHard()) return false; // must be supported if(!_AGPVertexArrayRange || !_VRAMVertexArrayRange) return false; // First, reset any VBHard created. resetVertexArrayRange(); bool ok= true; // Try to allocate AGPMemory. if(agpMem>0) { agpMem&= ~15; // ensure 16-bytes aligned mem count (maybe useful :) ). agpMem= max(agpMem, (uint)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE); while(agpMem>= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE) { if(_AGPVertexArrayRange->allocate(agpMem, CVertexBuffer::AGPPreferred)) { nlinfo("3D: %.u vertices supported", _MaxVerticesByVBHard); nlinfo("3D: Success to allocate %.1f Mo of AGP VAR Ram", agpMem / 1000000.f); break; } else { agpMem/=2; agpMem &=~15; } } if(agpMem< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE) { nlinfo("3D: %.u vertices supported", _MaxVerticesByVBHard); nlinfo("3D: Failed to allocate %.1f Mo of AGP VAR Ram", NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE / 1000000.f); ok= false; } } // Try to allocate VRAMMemory. if(vramMem>0) { vramMem&= ~15; // ensure 16-bytes aligned mem count (maybe useful :) ). vramMem= max(vramMem, (uint)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE); while(vramMem>= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE) { if(_VRAMVertexArrayRange->allocate(vramMem, CVertexBuffer::StaticPreferred)) break; else { vramMem/=2; vramMem &=~15; } } if(vramMem< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE) { ok= false; } } return ok; } // *************************************************************************** uint32 CDriverGL::getAvailableVertexAGPMemory () { H_AUTO_OGL(CDriverGL_getAvailableVertexAGPMemory ) if (_AGPVertexArrayRange) return _AGPVertexArrayRange->sizeAllocated(); else return 0; } // *************************************************************************** uint32 CDriverGL::getAvailableVertexVRAMMemory () { H_AUTO_OGL(CDriverGL_getAvailableVertexVRAMMemory ) if (_VRAMVertexArrayRange) return _VRAMVertexArrayRange->sizeAllocated(); else return 0; } // *************************************************************************** void CDriverGL::fenceOnCurVBHardIfNeeded(IVertexBufferHardGL *newVBHard) { H_AUTO_OGL(CDriverGL_fenceOnCurVBHardIfNeeded); #ifndef USE_OPENGLES // If old is not a VBHard, or if not a NVidia VBHard, no-op. if( _CurrentVertexBufferHard==NULL || _CurrentVertexBufferHard->VBType != IVertexBufferHardGL::NVidiaVB) return; // if we do not activate the same (NB: newVBHard==NULL if not a VBHard). if(_CurrentVertexBufferHard!=newVBHard) { // get NVidia interface CVertexBufferHardGLNVidia *vbHardNV= static_cast(_CurrentVertexBufferHard); // If some render() have been done with this VB. if( vbHardNV->GPURenderingAfterFence ) { /* Since we won't work with this VB for a long time, we set a fence. NB: if the fence was previously set. NV_Fence Specification says that the new ONE replaces it. This is EXACTLY what we wants, since the old one is no more interesting. NB: never insert a fence for said "Static Lock" VBHard. Those VBHard are said to be "static" therefore, user should never modify them (else lock() is much slower...) */ if( !vbHardNV->getLockHintStatic() ) vbHardNV->setFence(); // Since we have set a new Fence, we won't need to do it at next vbHardNV->lock() vbHardNV->GPURenderingAfterFence= false; } } #endif } // *************************************************************************** CIndexBufferInfo::CIndexBufferInfo() { H_AUTO_OGL(CIndexBufferInfo_CIndexBufferInfo) _Values = NULL; } // *************************************************************************** void CIndexBufferInfo::setupIndexBuffer(CIndexBuffer &ib) { H_AUTO_OGL(CIndexBufferInfo_setupIndexBuffer) CIndexBufferReadWrite access; ib.lock (access); _Values = access.getPtr(); _Format = access.getFormat(); } // *************************************************************************** #ifdef NL_STATIC } // NLDRIVERGL/ES #endif } // NL3D