#include "geometry_object.h" #include "common_hello.h" #include #include #include #include "chew.h" #include #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" GeometryObject::GeometryObject() : m_bTaintIAFlags( 0 ), m_iTaintVertFlag( 0 ), m_unVertVAO( 0 ), m_unTexture( 0 ), m_dTextureFileTime( 0 ), m_iTextureWidth( 0 ), m_iTextureHeight( 0 ), m_sGeoName( "Unnamed" ) { } GeometryObject::GeometryObject( const std::string & sGeoBaseName ) : GeometryObject() { m_sGeoName = sGeoBaseName; } GeometryObject::~GeometryObject() { unsigned i; for ( i = 0; i < m_unIndexBuffer.size(); i++ ) { if ( m_unIndexBuffer[i] ) { glDeleteBuffers( 1, &m_unIndexBuffer[i] ); } } if ( m_unVertVAO ) glDeleteVertexArrays( 1, &m_unVertVAO ); for ( i = 0; i < m_glVertBuffers.size(); i++ ) { if ( m_glVertBuffers[i] ) { glDeleteBuffers( 1, &m_glVertBuffers[i] ); } } if ( m_unTexture ) { glDeleteTextures( 1, &m_unTexture ); } } //Create from higher-level stuff int GeometryObject::CreateFromRenderModel( const vr::RenderModel_t * vrModel ) { if ( !vrModel ) return -1; SetArrayProps( 0, 0, 8 ); SetArrayPropsAdvanced( 0, 0, 3, 0 ); SetArrayPropsAdvanced( 0, 1, 3, 3 ); SetArrayPropsAdvanced( 0, 2, 2, 6 ); std::vector & verts = GetVertexArrayPtr( 0 ); float * rvdata = (float*)vrModel->rVertexData; for ( unsigned i = 0; i < vrModel->unVertexCount * 8; i++ ) { verts.push_back( rvdata[i] ); } std::vector< unsigned > indices; for ( unsigned i = 0; i < vrModel->unTriangleCount * 3; i++ ) { indices.push_back( vrModel->rIndexData[i] ); } SetIndexArray( 0, indices, GL_TRIANGLES ); Check(); return 0; } int GeometryObject::ApplyTextureRM( const vr::RenderModel_TextureMap_t * vrDiffuseTexture ) { if ( !vrDiffuseTexture ) return -1; ApplyTexture( vrDiffuseTexture->rubTextureMapData, vrDiffuseTexture->unWidth, vrDiffuseTexture->unHeight ); return 0; } void GeometryObject::ApplyTexture( const uint8_t * data, int width, int height, int channels ) { if( !m_unTexture ) glGenTextures( 1, &m_unTexture ); glBindTexture( GL_TEXTURE_2D, m_unTexture ); int channelmap[] = { 0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA }; glTexImage2D( GL_TEXTURE_2D, 0, channelmap[channels], width, height, 0, channelmap[channels], GL_UNSIGNED_BYTE, data ); m_iTextureWidth = width; m_iTextureHeight = height; glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); //Best not to be default. //GLfloat fLargest; //glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY, &fLargest ); //glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, fLargest ); glBindTexture( GL_TEXTURE_2D, 0 ); } void GeometryObject::Render( int index ) { if ( m_unTexture ) { glActiveTextureCHEW( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, m_unTexture ); } glBindVertexArray( m_unVertVAO ); if ( (int)m_unIndexBuffer.size() <= index ) { //Not an IBO, so it's a vertex-array draw. glDrawArrays( m_unRenderTypes[index], 0, (GLsizei)m_vertpos[index].size()/ m_vertstride[index] ); } else { //Regular IBO Draw. glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_unIndexBuffer[index] ); glDrawElements( m_unRenderTypes[index], (GLsizei)m_ia[index].size(), GL_UNSIGNED_INT, 0 ); } glBindVertexArray( 0 ); if ( m_unTexture ) { glBindTexture( GL_TEXTURE_2D, 0 ); } } void GeometryObject::SetRenderType( int index, unsigned int rendertype ) { if ( index >= (int)m_unRenderTypes.size() ) { m_unRenderTypes.resize( index + 1 ); } m_unRenderTypes[index] = rendertype; } void GeometryObject::LoadAsFile() { //XXX TODO } void GeometryObject::TackVertex( int index, int attribute, float x, float y, float z, float w ) { int elements = m_vertelements[index][attribute]; std::vector & vf = m_vertpos[index]; if ( elements > 0 ) vf.push_back( x ); if ( elements > 1 ) vf.push_back( y ); if ( elements > 2 ) vf.push_back( z ); if ( elements > 3 ) vf.push_back( w ); TaintVerts( index ); } void GeometryObject::TackIndex( int index, int idx ) { if ( m_ia.size() <= (unsigned)index ) m_ia.resize( index + 1 ); m_ia[index].push_back( idx ); TaintIndices( index ); } void GeometryObject::TackCube( int index, Matrix4 mat ) { //XXX This function is untested. Vector4 A = mat * Vector4( 0, 0, 0, 1 ); Vector4 B = mat * Vector4( 1, 0, 0, 1 ); Vector4 C = mat * Vector4( 1, 1, 0, 1 ); Vector4 D = mat * Vector4( 0, 1, 0, 1 ); Vector4 E = mat * Vector4( 0, 0, 1, 1 ); Vector4 F = mat * Vector4( 1, 0, 1, 1 ); Vector4 G = mat * Vector4( 1, 1, 1, 1 ); Vector4 H = mat * Vector4( 0, 1, 1, 1 ); float VertPosData[] = { E.x, E.y, E.z, F.x, F.y, F.z, G.x, G.y, G.z, G.x, G.y, G.z, H.x, H.y, H.z, E.x, E.y, E.z, //Front B.x, B.y, B.z, A.x, A.y, A.z, D.x, D.y, D.z, D.x, D.y, D.z, C.x, C.y, C.z, B.x, B.y, B.z, //Back H.x, H.y, H.z, G.x, G.y, G.z, C.x, C.y, C.z, C.x, C.y, C.z, D.x, D.y, D.z, H.x, H.y, H.z, //Top A.x, A.y, A.z, B.x, B.y, B.z, F.x, F.y, F.z, F.x, F.y, F.z, E.x, E.y, E.z, A.x, A.y, A.z, //Bottom A.x, A.y, A.z, E.x, E.y, E.z, H.x, H.y, H.z, H.x, H.y, H.z, D.x, D.y, D.z, A.x, A.y, A.z, //Left F.x, F.y, F.z, B.x, B.y, B.z, C.x, C.y, C.z, C.x, C.y, C.z, G.x, G.y, G.z, F.x, F.y, F.z, //Right }; float VertTCDataRep[] = { 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, }; int i, j; for ( i = 0; i < 6; i++ ) for ( j = 0; j < 6; j++ ) { TackVertex( 0, 0, VertPosData[(j + i * 6) * 3 + 0], VertPosData[(j + i * 6) * 3 + 1], VertPosData[(j + i * 6) * 3 + 2] ); TackVertex( 0, 1, VertTCDataRep[j * 2 + 0], VertTCDataRep[j * 2 + 1] ); } } void GeometryObject::MakeUnitSquare( int index ) { SetArrayProps( 0, 0, 4 ); SetArrayPropsAdvanced( 0, 0, 2, 0 ); SetArrayPropsAdvanced( 0, 1, 2, 2 ); SetRenderType( index, GL_TRIANGLES ); m_bTaintIAFlags |= 1 << index; TackVertex( 0, 0, -1, 1 ); TackVertex( 0, 1, 0, 1 ); TackVertex( 0, 0, 1, 1 ); TackVertex( 0, 1, 1, 1 ); TackVertex( 0, 0, -1, -1 ); TackVertex( 0, 1, 0, 0 ); TackVertex( 0, 0, 1, -1 ); TackVertex( 0, 1, 1, 0 ); TackIndex( 0, 0 ); TackIndex( 0, 1 ); TackIndex( 0, 3 ); TackIndex( 0, 0 ); TackIndex( 0, 3 ); TackIndex( 0, 2 ); } void GeometryObject::SetIndexArray( int index, std::vector & intarray, unsigned int render_type ) { if ( (int)m_ia.size() <= index ) m_ia.resize( index + 1 ); m_ia[index] = intarray; SetRenderType( index, render_type ); m_bTaintIAFlags |= 1< & GeometryObject::GetIndexArrayPtr( int index ) { if ( index >= (int)m_ia.size() ) { m_ia.resize( index + 1 ); } return m_ia[index]; } std::vector & GeometryObject::GetVertexArrayPtr( int index ) { return m_vertpos[index]; } void GeometryObject::Check() { if ( m_sTextureFile.length() && FileTimeCached( m_sTextureFile.c_str() ) != m_dTextureFileTime ) { //TODO: Load asychronously. if ( !m_unTexture ) glGenTextures( 1, &m_unTexture ); m_dTextureFileTime = FileTimeCached( m_sTextureFile.c_str() ); int width, height, channels; uint8_t * data = stbi_load( m_sTextureFile.c_str(), &width, &height, &channels, 0 ); if ( data ) { ApplyTexture( data, width, height, channels ); } free( data ); } if ( !m_iTaintVertFlag && !m_bTaintIAFlags ) return; if ( !m_unVertVAO ) { glGenVertexArrays( 1, &m_unVertVAO ); } glBindVertexArray( m_unVertVAO ); if ( m_bTaintIAFlags ) { unsigned i; for ( i = 0; i < m_ia.size(); i++ ) { if ( m_bTaintIAFlags & (1 << i) ) { if ( m_ia[i].size() ) { if ( m_unIndexBuffer.size() <= i ) { m_unIndexBuffer.resize( i + 1 ); } if ( !m_unIndexBuffer[i] ) { glGenBuffers( 1, &m_unIndexBuffer[i] ); } glGenBuffers( 1, &m_unIndexBuffer[i] ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_unIndexBuffer[i] ); glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_ia[i].size() * sizeof( unsigned int ), &m_ia[i][0], GL_STATIC_DRAW ); } } m_bTaintIAFlags &= ~(1 << i); } } if ( m_iTaintVertFlag ) { //Tricky: Make sure all bit flags outside of our valid buffer range are set to 0. for ( unsigned i = 0; i < (unsigned)m_vertpos.size(); i++ ) { m_iTaintVertFlag &= ~(1 << i); if ( m_glVertBuffers.size() <= i ) { m_glVertBuffers.resize( i + 1 ); } if ( !m_glVertBuffers[i] ) { glGenBuffers( 1, &m_glVertBuffers[i] ); } if ( i >= m_vertpos.size() ) { //Invalid array. continue; } int stride = (i < m_vertstride.size()) ? m_vertstride[i] : 4; int dynamic = (i < m_vertdynamic.size()) ? m_vertdynamic[i] : false; glBindBuffer( GL_ARRAY_BUFFER, m_glVertBuffers[i] ); glBufferData( GL_ARRAY_BUFFER, sizeof( float ) * m_vertpos[i].size(), &m_vertpos[i][0], dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW ); if ( m_vertoffset[i].size() == 1 ) { glEnableVertexAttribArray( i ); glVertexAttribPointer( i, stride, GL_FLOAT, GL_FALSE, stride * sizeof( float ), 0 ); } else { int j; for ( j = 0; j < (int)m_vertoffset[i].size(); j++ ) { glEnableVertexAttribArray( j ); int size = m_vertelements[i][j]; int istride = stride * sizeof( float ); void * ioffset = (void*)(m_vertoffset[i][j] * sizeof( float )); glVertexAttribPointer( j, size, GL_FLOAT, GL_FALSE, istride, ioffset ); } } } } glBindVertexArray( 0 ); }