From 3597e45bbc6a7986658a305c8a2e78bd5b6b42c8 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Mon, 12 Apr 2004 03:07:44 +0000 Subject: [PATCH] add hardware vertex buffers for OpenGL renderer --- stepmania/src/Model.cpp | 2 + stepmania/src/RageDisplay.h | 3 +- stepmania/src/RageDisplay_D3D.cpp | 8 +- stepmania/src/RageDisplay_OGL.cpp | 161 +++++++++++++++++++++++++--- stepmania/src/RageModelGeometry.cpp | 10 ++ 5 files changed, 169 insertions(+), 15 deletions(-) diff --git a/stepmania/src/Model.cpp b/stepmania/src/Model.cpp index c435c9f50b..835dd3c360 100644 --- a/stepmania/src/Model.cpp +++ b/stepmania/src/Model.cpp @@ -864,6 +864,8 @@ void Model::Update( float fDelta ) RageVec3TransformCoord( &tempPos, &originalPos, &m_vpBones[bone].mFinal ); } } + + pTempVertices->OnChanged(); // send the new vertices to the graphics card } } } diff --git a/stepmania/src/RageDisplay.h b/stepmania/src/RageDisplay.h index 1c4cfb23a2..cd4d2f1468 100644 --- a/stepmania/src/RageDisplay.h +++ b/stepmania/src/RageDisplay.h @@ -39,7 +39,8 @@ public: virtual msTriangle& Triangle( int index ) = 0; - virtual void SendVertices() const = 0; + virtual void OnChanged() const = 0; // call this to re-send data to the video card + virtual void Draw() const = 0; // call this to make the video card draw the vertices }; diff --git a/stepmania/src/RageDisplay_D3D.cpp b/stepmania/src/RageDisplay_D3D.cpp index bfdb3bccda..1180471390 100644 --- a/stepmania/src/RageDisplay_D3D.cpp +++ b/stepmania/src/RageDisplay_D3D.cpp @@ -783,7 +783,11 @@ public: Sint8& Bone ( int index ) { return m_pVertex[index].bone; } msTriangle& Triangle ( int index ) { return m_pTriangles[index]; } - void SendVertices() const + void OnChanged() const + { + // nothing to do. We send all of the vertices every time we draw. + } + void Draw() const { g_pd3dDevice->SetVertexShader( D3DFVF_RageModelVertex ); g_pd3dDevice->DrawIndexedPrimitiveUP( @@ -912,7 +916,7 @@ void RageDisplay_D3D::DrawIndexedTriangles( const RageModelVertexArray *p ) { SEND_CURRENT_MATRICES; - p->SendVertices(); + p->Draw(); StatsAddVerts( p->sizeTriangles()*3 ); } diff --git a/stepmania/src/RageDisplay_OGL.cpp b/stepmania/src/RageDisplay_OGL.cpp index e8c29f35fa..a40193b10e 100644 --- a/stepmania/src/RageDisplay_OGL.cpp +++ b/stepmania/src/RageDisplay_OGL.cpp @@ -47,6 +47,10 @@ namespace GLExt { extern PFNGLCOLORTABLEPROC glColorTableEXT; extern PFNGLCOLORTABLEPARAMETERIVPROC glGetColorTableParameterivEXT; extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; + extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; + extern PFNGLBINDBUFFERARBPROC glBindBufferARB; + extern PFNGLBUFFERDATAARBPROC glBufferDataARB; + extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; }; #if defined(DARWIN) @@ -84,6 +88,10 @@ PWSWAPINTERVALEXTPROC GLExt::wglSwapIntervalEXT = NULL; PFNGLCOLORTABLEPROC GLExt::glColorTableEXT = NULL; PFNGLCOLORTABLEPARAMETERIVPROC GLExt::glGetColorTableParameterivEXT = NULL; PFNGLACTIVETEXTUREARBPROC GLExt::glActiveTextureARB = NULL; +PFNGLGENBUFFERSARBPROC GLExt::glGenBuffersARB = NULL; +PFNGLBINDBUFFERARBPROC GLExt::glBindBufferARB = NULL; +PFNGLBUFFERDATAARBPROC GLExt::glBufferDataARB = NULL; +PFNGLDELETEBUFFERSARBPROC GLExt::glDeleteBuffersARB = NULL; static bool g_bEXT_texture_env_combine = true; static bool g_bGL_EXT_bgra = true; @@ -308,6 +316,17 @@ static void FlushGLErrors() ; } +static AssertNoGLError() +{ + GLenum error = glGetError(); + if( error != GL_NO_ERROR ) + { + LOG->Trace( GLToString(error) ); + ASSERT(0); + } +} + + #if defined(__unix__) && !defined(unix) #define unix #endif @@ -636,6 +655,10 @@ void SetupExtensions() GLExt::glColorTableEXT = (PFNGLCOLORTABLEPROC) wind->GetProcAddress("glColorTableEXT"); GLExt::glGetColorTableParameterivEXT = (PFNGLCOLORTABLEPARAMETERIVPROC) wind->GetProcAddress("glGetColorTableParameterivEXT"); GLExt::glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wind->GetProcAddress("glActiveTextureARB"); + GLExt::glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wind->GetProcAddress("glGenBuffersARB"); + GLExt::glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wind->GetProcAddress("glBindBufferARB"); + GLExt::glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wind->GetProcAddress("glBufferDataARB"); + GLExt::glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wind->GetProcAddress("glDeleteBuffersARB"); g_bEXT_texture_env_combine = HasExtension("GL_EXT_texture_env_combine"); g_bGL_EXT_bgra = HasExtension("GL_EXT_bgra"); CheckPalettedTextures( false ); @@ -955,7 +978,11 @@ public: Sint8& Bone ( int index ) { return m_pBone[index]; } msTriangle& Triangle ( int index ) { return m_pTriangles[index]; } - void SendVertices() const + void OnChanged() const + { + // nothing to do. We send all of the vertices every time we draw. + } + void Draw() const { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, m_pPosition); @@ -980,9 +1007,127 @@ protected: msTriangle *m_pTriangles; }; +class RageModelVertexArrayHWOGL : public RageModelVertexArraySWOGL +{ +protected: + // vertex buffer object names + GLuint m_nPositions; + GLuint m_nTextureCoords; + GLuint m_nNormals; + GLuint m_nTriangles; +public: + RageModelVertexArrayHWOGL() + { + m_nPositions = 0; + m_nTextureCoords = 0; + m_nNormals = 0; + m_nTriangles = 0; + + FlushGLErrors(); + + GLExt::glGenBuffersARB( 1, &m_nPositions ); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nPositions ); + AssertNoGLError(); + + GLExt::glGenBuffersARB( 1, &m_nTextureCoords ); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureCoords ); + AssertNoGLError(); + + GLExt::glGenBuffersARB( 1, &m_nNormals ); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nNormals ); + AssertNoGLError(); + + GLExt::glGenBuffersARB( 1, &m_nTriangles ); + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nTriangles ); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, NULL ); + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, NULL ); + } + + ~RageModelVertexArrayHWOGL() + { + FlushGLErrors(); + + GLExt::glDeleteBuffersARB( 1, &m_nPositions ); + AssertNoGLError(); + GLExt::glDeleteBuffersARB( 1, &m_nTextureCoords ); + AssertNoGLError(); + GLExt::glDeleteBuffersARB( 1, &m_nNormals ); + AssertNoGLError(); + GLExt::glDeleteBuffersARB( 1, &m_nTriangles ); + AssertNoGLError(); + } + + void OnChanged() const + { + // some implementations don't handle buffers of size 0. + if( m_sizeVerts == 0 || m_nTriangles == 0 ) + return; + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nPositions ); + GLExt::glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_sizeVerts*sizeof(RageVector3), m_pPosition, GL_STATIC_DRAW_ARB ); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureCoords ); + GLExt::glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_sizeVerts*sizeof(RageVector2), m_pTexture, GL_STATIC_DRAW_ARB ); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nNormals ); + GLExt::glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_sizeVerts*sizeof(RageVector3), m_pNormal, GL_STATIC_DRAW_ARB ); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nTriangles ); + GLExt::glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_sizeTriangles*sizeof(msTriangle), m_pTriangles, GL_STATIC_DRAW_ARB ); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, NULL ); + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, NULL ); + } + void Draw() const + { + if( m_sizeVerts == 0 || m_nTriangles == 0 ) + return; + + FlushGLErrors(); + + glEnableClientState(GL_VERTEX_ARRAY); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nPositions ); + AssertNoGLError(); + glVertexPointer(3, GL_FLOAT, 0, NULL ); + AssertNoGLError(); + + glDisableClientState(GL_COLOR_ARRAY); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureCoords ); + AssertNoGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + AssertNoGLError(); + + glEnableClientState(GL_NORMAL_ARRAY); + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nNormals ); + AssertNoGLError(); + glNormalPointer(GL_FLOAT, 0, NULL); + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nTriangles ); + AssertNoGLError(); + + glDrawElements( GL_TRIANGLES, m_sizeTriangles*3, GL_UNSIGNED_SHORT, 0 ); //last 0 is offset in element-array + AssertNoGLError(); + + GLExt::glBindBufferARB( GL_ARRAY_BUFFER_ARB, NULL ); + GLExt::glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, NULL ); + } +}; + RageModelVertexArray* RageDisplay_OGL::CreateRageModelVertexArray() { - return new RageModelVertexArraySWOGL; + if( GLExt::glGenBuffersARB ) + return new RageModelVertexArraySWOGL; + else + return new RageModelVertexArraySWOGL; } void RageDisplay_OGL::DeleteRageModelVertexArray( RageModelVertexArray* p ) @@ -1045,7 +1190,7 @@ void RageDisplay_OGL::DrawIndexedTriangles( const RageModelVertexArray *p ) { SendCurrentMatrices(); - p->SendVertices(); + p->Draw(); StatsAddVerts( p->sizeTriangles()*3 ); } @@ -1345,7 +1490,6 @@ const RageDisplay::PixelFormatDesc *RageDisplay_OGL::GetPixelFormatDesc(PixelFor return &PIXEL_FORMAT_DESC[pf]; } - void RageDisplay_OGL::DeleteTexture( unsigned uTexHandle ) { unsigned int uTexID = uTexHandle; @@ -1353,14 +1497,7 @@ void RageDisplay_OGL::DeleteTexture( unsigned uTexHandle ) FlushGLErrors(); glDeleteTextures(1,reinterpret_cast(&uTexID)); - GLenum error = glGetError(); - if( error != GL_NO_ERROR ) - { - ostringstream s; - s << "glDeleteTextures(): " << GLToString(error); - LOG->Trace( s.str().c_str() ); - ASSERT(0); - } + AssertNoGLError(); } diff --git a/stepmania/src/RageModelGeometry.cpp b/stepmania/src/RageModelGeometry.cpp index 236eb266c4..fdb1296585 100644 --- a/stepmania/src/RageModelGeometry.cpp +++ b/stepmania/src/RageModelGeometry.cpp @@ -240,6 +240,16 @@ void RageModelGeometry::LoadMilkshapeAscii( CString sPath ) OptimizeBones(); + // send the finalized vertices to the graphics card + { + for( unsigned i = 0; i < m_Meshes.size(); i++ ) + { + msMesh& mesh = m_Meshes[i]; + RageModelVertexArray *&pVertices = mesh.Vertices; + pVertices->OnChanged(); + } + } + f.Close(); }