X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=plugins%2Fmodel%2Fmodel.cpp;h=defa472aa0fd56503aea26bb1216fab8044062be;hb=e4287c28bb2dafedc81c66e63951d947cfbeb225;hp=fb8139cb1d202ffe6da99f127e10f2393c4e26be;hpb=203343b01a7ad87cb3d136689c9936ff5bc23c01;p=xonotic%2Fnetradiant.git diff --git a/plugins/model/model.cpp b/plugins/model/model.cpp index fb8139cb..defa472a 100644 --- a/plugins/model/model.cpp +++ b/plugins/model/model.cpp @@ -1,23 +1,23 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant 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 General Public License for more details. + GtkRadiant 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 General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "model.h" @@ -44,293 +44,269 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA class VectorLightList : public LightList { - typedef std::vector Lights; - Lights m_lights; +typedef std::vector Lights; +Lights m_lights; public: - void addLight(const RendererLight& light) - { - m_lights.push_back(&light); - } - void clear() - { - m_lights.clear(); - } - void evaluateLights() const - { - } - void lightsChanged() const - { - } - void forEachLight(const RendererLightCallback& callback) const - { - for(Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) - { - callback(*(*i)); - } - } +void addLight( const RendererLight& light ){ + m_lights.push_back( &light ); +} +void clear(){ + m_lights.clear(); +} +void evaluateLights() const { +} +void lightsChanged() const { +} +void forEachLight( const RendererLightCallback& callback ) const { + for ( Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i ) + { + callback( *( *i ) ); + } +} }; -class PicoSurface : -public OpenGLRenderable +class PicoSurface : + public OpenGLRenderable { - AABB m_aabb_local; - CopiedString m_shader; - Shader* m_state; +AABB m_aabb_local; +CopiedString m_shader; +Shader* m_state; - Array m_vertices; - Array m_indices; +Array m_vertices; +Array m_indices; public: - PicoSurface() - { - constructNull(); - CaptureShader(); - } - PicoSurface(picoSurface_t* surface) - { - CopyPicoSurface(surface); - CaptureShader(); - } - ~PicoSurface() - { - ReleaseShader(); - } - - void render(RenderStateFlags state) const - { - if((state & RENDER_BUMP) != 0) - { - if(GlobalShaderCache().useShaderLanguage()) - { - glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal); - glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord); - glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent); - glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent); - } - else - { - glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal); - glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord); - glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent); - glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent); - } - } - else - { - glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal); - glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord); - } - glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex); - glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data()); - -#if defined(_DEBUG) +PicoSurface(){ + constructNull(); + CaptureShader(); +} +PicoSurface( picoSurface_t* surface ){ + CopyPicoSurface( surface ); + CaptureShader(); +} +~PicoSurface(){ + ReleaseShader(); +} + +void render( RenderStateFlags state ) const { + if ( ( state & RENDER_BUMP ) != 0 ) { + if ( GlobalShaderCache().useShaderLanguage() ) { + glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->normal ); + glVertexAttribPointerARB( c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->texcoord ); + glVertexAttribPointerARB( c_attr_Tangent, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->tangent ); + glVertexAttribPointerARB( c_attr_Binormal, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->bitangent ); + } + else + { + glVertexAttribPointerARB( 11, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->normal ); + glVertexAttribPointerARB( 8, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->texcoord ); + glVertexAttribPointerARB( 9, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->tangent ); + glVertexAttribPointerARB( 10, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->bitangent ); + } + } + else + { + glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->normal ); + glTexCoordPointer( 2, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->texcoord ); + } + glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_vertices.data()->vertex ); + glDrawElements( GL_TRIANGLES, GLsizei( m_indices.size() ), RenderIndexTypeID, m_indices.data() ); + +#if defined( _DEBUG ) GLfloat modelview[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // I know this is slow as hell, but hey - we're in _DEBUG + glGetFloatv( GL_MODELVIEW_MATRIX, modelview ); // I know this is slow as hell, but hey - we're in _DEBUG Matrix4 modelview_inv( modelview[0], modelview[1], modelview[2], modelview[3], modelview[4], modelview[5], modelview[6], modelview[7], modelview[8], modelview[9], modelview[10], modelview[11], - modelview[12], modelview[13], modelview[14], modelview[15]); - matrix4_full_invert(modelview_inv); - Matrix4 modelview_inv_transposed = matrix4_transposed(modelview_inv); - - glBegin(GL_LINES); - - for(Array::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) - { - Vector3 normal = normal3f_to_vector3((*i).normal); - normal = matrix4_transformed_direction(modelview_inv, vector3_normalised(matrix4_transformed_direction(modelview_inv_transposed, normal))); // do some magic - Vector3 normalTransformed = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal, 8)); - glVertex3fv(vertex3f_to_array((*i).vertex)); - glVertex3fv(vector3_to_array(normalTransformed)); - } - glEnd(); + modelview[12], modelview[13], modelview[14], modelview[15] ); + matrix4_full_invert( modelview_inv ); + Matrix4 modelview_inv_transposed = matrix4_transposed( modelview_inv ); + + glBegin( GL_LINES ); + + for ( Array::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i ) + { + Vector3 normal = normal3f_to_vector3( ( *i ).normal ); + normal = matrix4_transformed_direction( modelview_inv, vector3_normalised( matrix4_transformed_direction( modelview_inv_transposed, normal ) ) ); // do some magic + Vector3 normalTransformed = vector3_added( vertex3f_to_vector3( ( *i ).vertex ), vector3_scaled( normal, 8 ) ); + glVertex3fv( vertex3f_to_array( ( *i ).vertex ) ); + glVertex3fv( vector3_to_array( normalTransformed ) ); + } + glEnd(); #endif - } - - VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const - { - return test.TestAABB(m_aabb_local, localToWorld); - } - - const AABB& localAABB() const - { - return m_aabb_local; - } - - void render(Renderer& renderer, const Matrix4& localToWorld, Shader* state) const - { - renderer.SetState(state, Renderer::eFullMaterials); - renderer.addRenderable(*this, localToWorld); - } - - void render(Renderer& renderer, const Matrix4& localToWorld) const - { - render(renderer, localToWorld, m_state); - } - - void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld) - { - test.BeginMesh(localToWorld); - - SelectionIntersection best; - testSelect(test, best); - if(best.valid()) - { - selector.addIntersection(best); - } - } - - const char* getShader() const - { - return m_shader.c_str(); - } - Shader* getState() const - { - return m_state; - } +} + +VolumeIntersectionValue intersectVolume( const VolumeTest& test, const Matrix4& localToWorld ) const { + return test.TestAABB( m_aabb_local, localToWorld ); +} + +const AABB& localAABB() const { + return m_aabb_local; +} + +void render( Renderer& renderer, const Matrix4& localToWorld, Shader* state ) const { + renderer.SetState( state, Renderer::eFullMaterials ); + renderer.addRenderable( *this, localToWorld ); +} + +void render( Renderer& renderer, const Matrix4& localToWorld ) const { + render( renderer, localToWorld, m_state ); +} + +void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ + test.BeginMesh( localToWorld ); + + SelectionIntersection best; + testSelect( test, best ); + if ( best.valid() ) { + selector.addIntersection( best ); + } +} + +const char* getShader() const { + return m_shader.c_str(); +} +Shader* getState() const { + return m_state; +} private: - void CaptureShader() - { - m_state = GlobalShaderCache().capture(m_shader.c_str()); - } - void ReleaseShader() - { - GlobalShaderCache().release(m_shader.c_str()); - } - - void UpdateAABB() - { - m_aabb_local = AABB(); - for(std::size_t i = 0; i < m_vertices.size(); ++i ) - aabb_extend_by_point_safe(m_aabb_local, reinterpret_cast(m_vertices[i].vertex)); - - - for(Array::iterator i = m_indices.begin(); i != m_indices.end(); i += 3) - { - ArbitraryMeshVertex& a = m_vertices[*(i + 0)]; - ArbitraryMeshVertex& b = m_vertices[*(i + 1)]; - ArbitraryMeshVertex& c = m_vertices[*(i + 2)]; - - ArbitraryMeshTriangle_sumTangents(a, b, c); - } - - for(Array::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) - { - vector3_normalise(reinterpret_cast((*i).tangent)); - vector3_normalise(reinterpret_cast((*i).bitangent)); - } - } - - void testSelect(SelectionTest& test, SelectionIntersection& best) - { - test.TestTriangles( - VertexPointer(VertexPointer::pointer(&m_vertices.data()->vertex), sizeof(ArbitraryMeshVertex)), - IndexPointer(m_indices.data(), IndexPointer::index_type(m_indices.size())), - best - ); - } - - void CopyPicoSurface(picoSurface_t* surface) - { - picoShader_t* shader = PicoGetSurfaceShader( surface ); - if( shader == 0 ) - m_shader = ""; - else - m_shader = PicoGetShaderName( shader ); - - m_vertices.resize( PicoGetSurfaceNumVertexes( surface ) ); - m_indices.resize( PicoGetSurfaceNumIndexes( surface ) ); - - for(std::size_t i = 0; i < m_vertices.size(); ++i ) - { - picoVec_t* xyz = PicoGetSurfaceXYZ( surface, int(i) ); - m_vertices[i].vertex = vertex3f_from_array(xyz); - - picoVec_t* normal = PicoGetSurfaceNormal( surface, int(i) ); - m_vertices[i].normal = normal3f_from_array(normal); - - picoVec_t* st = PicoGetSurfaceST( surface, 0, int(i) ); - m_vertices[i].texcoord = TexCoord2f(st[0], st[1]); - +void CaptureShader(){ + m_state = GlobalShaderCache().capture( m_shader.c_str() ); +} +void ReleaseShader(){ + GlobalShaderCache().release( m_shader.c_str() ); +} + +void UpdateAABB(){ + m_aabb_local = AABB(); + for ( std::size_t i = 0; i < m_vertices.size(); ++i ) + aabb_extend_by_point_safe( m_aabb_local, reinterpret_cast( m_vertices[i].vertex ) ); + + + for ( Array::iterator i = m_indices.begin(); i != m_indices.end(); i += 3 ) + { + ArbitraryMeshVertex& a = m_vertices[*( i + 0 )]; + ArbitraryMeshVertex& b = m_vertices[*( i + 1 )]; + ArbitraryMeshVertex& c = m_vertices[*( i + 2 )]; + + ArbitraryMeshTriangle_sumTangents( a, b, c ); + } + + for ( Array::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i ) + { + vector3_normalise( reinterpret_cast( ( *i ).tangent ) ); + vector3_normalise( reinterpret_cast( ( *i ).bitangent ) ); + } +} + +void testSelect( SelectionTest& test, SelectionIntersection& best ){ + test.TestTriangles( + VertexPointer( VertexPointer::pointer( &m_vertices.data()->vertex ), sizeof( ArbitraryMeshVertex ) ), + IndexPointer( m_indices.data(), IndexPointer::index_type( m_indices.size() ) ), + best + ); +} + +void CopyPicoSurface( picoSurface_t* surface ){ + picoShader_t* shader = PicoGetSurfaceShader( surface ); + if ( shader == 0 ) { + m_shader = ""; + } + else{ + m_shader = PicoGetShaderName( shader ); + } + + m_vertices.resize( PicoGetSurfaceNumVertexes( surface ) ); + m_indices.resize( PicoGetSurfaceNumIndexes( surface ) ); + + for ( std::size_t i = 0; i < m_vertices.size(); ++i ) + { + picoVec_t* xyz = PicoGetSurfaceXYZ( surface, int(i) ); + m_vertices[i].vertex = vertex3f_from_array( xyz ); + + picoVec_t* normal = PicoGetSurfaceNormal( surface, int(i) ); + m_vertices[i].normal = normal3f_from_array( normal ); + + picoVec_t* st = PicoGetSurfaceST( surface, 0, int(i) ); + m_vertices[i].texcoord = TexCoord2f( st[0], st[1] ); + #if 0 - picoVec_t* color = PicoGetSurfaceColor( surface, 0, int(i) ); - m_vertices[i].colour = Colour4b(color[0], color[1], color[2], color[3]); + picoVec_t* color = PicoGetSurfaceColor( surface, 0, int(i) ); + m_vertices[i].colour = Colour4b( color[0], color[1], color[2], color[3] ); #endif - } - - picoIndex_t* indexes = PicoGetSurfaceIndexes( surface, 0 ); - for(std::size_t j = 0; j < m_indices.size(); ++j ) - m_indices[ j ] = indexes[ j ]; - - UpdateAABB(); - } - - void constructQuad(std::size_t index, const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d, const Vector3& normal) - { - m_vertices[index * 4 + 0] = ArbitraryMeshVertex( - vertex3f_for_vector3(a), - normal3f_for_vector3(normal), - texcoord2f_from_array(aabb_texcoord_topleft) - ); - m_vertices[index * 4 + 1] = ArbitraryMeshVertex( - vertex3f_for_vector3(b), - normal3f_for_vector3(normal), - texcoord2f_from_array(aabb_texcoord_topright) - ); - m_vertices[index * 4 + 2] = ArbitraryMeshVertex( - vertex3f_for_vector3(c), - normal3f_for_vector3(normal), - texcoord2f_from_array(aabb_texcoord_botright) - ); - m_vertices[index * 4 + 3] = ArbitraryMeshVertex( - vertex3f_for_vector3(d), - normal3f_for_vector3(normal), - texcoord2f_from_array(aabb_texcoord_botleft) - ); - } - - void constructNull() - { - AABB aabb(Vector3(0, 0, 0), Vector3(8, 8, 8)); - - Vector3 points[8]; - aabb_corners(aabb, points); - - m_vertices.resize(24); - - constructQuad(0, points[2], points[1], points[5], points[6], aabb_normals[0]); - constructQuad(1, points[1], points[0], points[4], points[5], aabb_normals[1]); - constructQuad(2, points[0], points[1], points[2], points[3], aabb_normals[2]); - constructQuad(3, points[0], points[3], points[7], points[4], aabb_normals[3]); - constructQuad(4, points[3], points[2], points[6], points[7], aabb_normals[4]); - constructQuad(5, points[7], points[6], points[5], points[4], aabb_normals[5]); - - m_indices.resize(36); - - RenderIndex indices[36] = { - 0, 1, 2, 0, 2, 3, - 4, 5, 6, 4, 6, 7, - 8, 9, 10, 8, 10, 11, - 12, 13, 14, 12, 14, 15, - 16, 17, 18, 16, 18, 19, - 20, 21, 22, 10, 22, 23, - }; - - - Array::iterator j = m_indices.begin(); - for(RenderIndex* i = indices; i != indices+(sizeof(indices)/sizeof(RenderIndex)); ++i) - { - *j++ = *i; - } - - m_shader = ""; - - UpdateAABB(); - } + } + + picoIndex_t* indexes = PicoGetSurfaceIndexes( surface, 0 ); + for ( std::size_t j = 0; j < m_indices.size(); ++j ) + m_indices[ j ] = indexes[ j ]; + + UpdateAABB(); +} + +void constructQuad( std::size_t index, const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d, const Vector3& normal ){ + m_vertices[index * 4 + 0] = ArbitraryMeshVertex( + vertex3f_for_vector3( a ), + normal3f_for_vector3( normal ), + texcoord2f_from_array( aabb_texcoord_topleft ) + ); + m_vertices[index * 4 + 1] = ArbitraryMeshVertex( + vertex3f_for_vector3( b ), + normal3f_for_vector3( normal ), + texcoord2f_from_array( aabb_texcoord_topright ) + ); + m_vertices[index * 4 + 2] = ArbitraryMeshVertex( + vertex3f_for_vector3( c ), + normal3f_for_vector3( normal ), + texcoord2f_from_array( aabb_texcoord_botright ) + ); + m_vertices[index * 4 + 3] = ArbitraryMeshVertex( + vertex3f_for_vector3( d ), + normal3f_for_vector3( normal ), + texcoord2f_from_array( aabb_texcoord_botleft ) + ); +} + +void constructNull(){ + AABB aabb( Vector3( 0, 0, 0 ), Vector3( 8, 8, 8 ) ); + + Vector3 points[8]; + aabb_corners( aabb, points ); + + m_vertices.resize( 24 ); + + constructQuad( 0, points[2], points[1], points[5], points[6], aabb_normals[0] ); + constructQuad( 1, points[1], points[0], points[4], points[5], aabb_normals[1] ); + constructQuad( 2, points[0], points[1], points[2], points[3], aabb_normals[2] ); + constructQuad( 3, points[0], points[3], points[7], points[4], aabb_normals[3] ); + constructQuad( 4, points[3], points[2], points[6], points[7], aabb_normals[4] ); + constructQuad( 5, points[7], points[6], points[5], points[4], aabb_normals[5] ); + + m_indices.resize( 36 ); + + RenderIndex indices[36] = { + 0, 1, 2, 0, 2, 3, + 4, 5, 6, 4, 6, 7, + 8, 9, 10, 8, 10, 11, + 12, 13, 14, 12, 14, 15, + 16, 17, 18, 16, 18, 19, + 20, 21, 22, 10, 22, 23, + }; + + + Array::iterator j = m_indices.begin(); + for ( RenderIndex* i = indices; i != indices + ( sizeof( indices ) / sizeof( RenderIndex ) ); ++i ) + { + *j++ = *i; + } + + m_shader = ""; + + UpdateAABB(); +} }; @@ -338,357 +314,311 @@ typedef std::pair PicoModelKey; class PicoModel : -public Cullable, -public Bounded + public Cullable, + public Bounded { - typedef std::vector surfaces_t; - surfaces_t m_surfaces; +typedef std::vector surfaces_t; +surfaces_t m_surfaces; - AABB m_aabb_local; +AABB m_aabb_local; public: - Callback m_lightsChanged; - - PicoModel() - { - constructNull(); - } - PicoModel(picoModel_t* model) - { - CopyPicoModel(model); - } - ~PicoModel() - { - for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) - delete *i; - } - - typedef surfaces_t::const_iterator const_iterator; - - const_iterator begin() const - { - return m_surfaces.begin(); - } - const_iterator end() const - { - return m_surfaces.end(); - } - std::size_t size() const - { - return m_surfaces.size(); - } - - VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const - { - return test.TestAABB(m_aabb_local, localToWorld); - } - - virtual const AABB& localAABB() const - { - return m_aabb_local; - } - - void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, std::vector states) const - { - for(surfaces_t::const_iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) - { - if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside) - { - (*i)->render(renderer, localToWorld, states[i - m_surfaces.begin()]); - } - } - } - - void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld) - { - for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) - { - if((*i)->intersectVolume(test.getVolume(), localToWorld) != c_volumeOutside) - { - (*i)->testSelect(selector, test, localToWorld); - } - } - } +Callback m_lightsChanged; + +PicoModel(){ + constructNull(); +} +PicoModel( picoModel_t* model ){ + CopyPicoModel( model ); +} +~PicoModel(){ + for ( surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i ) + delete *i; +} + +typedef surfaces_t::const_iterator const_iterator; + +const_iterator begin() const { + return m_surfaces.begin(); +} +const_iterator end() const { + return m_surfaces.end(); +} +std::size_t size() const { + return m_surfaces.size(); +} + +VolumeIntersectionValue intersectVolume( const VolumeTest& test, const Matrix4& localToWorld ) const { + return test.TestAABB( m_aabb_local, localToWorld ); +} + +virtual const AABB& localAABB() const { + return m_aabb_local; +} + +void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, std::vector states ) const { + for ( surfaces_t::const_iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i ) + { + if ( ( *i )->intersectVolume( volume, localToWorld ) != c_volumeOutside ) { + ( *i )->render( renderer, localToWorld, states[i - m_surfaces.begin()] ); + } + } +} + +void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ + for ( surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i ) + { + if ( ( *i )->intersectVolume( test.getVolume(), localToWorld ) != c_volumeOutside ) { + ( *i )->testSelect( selector, test, localToWorld ); + } + } +} private: - void CopyPicoModel(picoModel_t* model) - { - m_aabb_local = AABB(); - - /* each surface on the model will become a new map drawsurface */ - int numSurfaces = PicoGetModelNumSurfaces( model ); - //% SYs_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces ); - for(int s = 0; s < numSurfaces; ++s) - { - /* get surface */ - picoSurface_t* surface = PicoGetModelSurface( model, s ); - if( surface == 0 ) - continue; - - /* only handle triangle surfaces initially (fixme: support patches) */ - if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) - continue; - - /* fix the surface's normals */ - PicoFixSurfaceNormals( surface ); - - PicoSurface* picosurface = new PicoSurface(surface); - aabb_extend_by_aabb_safe(m_aabb_local, picosurface->localAABB()); - m_surfaces.push_back(picosurface); - } - } - void constructNull() - { - PicoSurface* picosurface = new PicoSurface(); - m_aabb_local = picosurface->localAABB(); - m_surfaces.push_back(picosurface); - } +void CopyPicoModel( picoModel_t* model ){ + m_aabb_local = AABB(); + + /* each surface on the model will become a new map drawsurface */ + int numSurfaces = PicoGetModelNumSurfaces( model ); + //% SYs_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces ); + for ( int s = 0; s < numSurfaces; ++s ) + { + /* get surface */ + picoSurface_t* surface = PicoGetModelSurface( model, s ); + if ( surface == 0 ) { + continue; + } + + /* only handle triangle surfaces initially (fixme: support patches) */ + if ( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) { + continue; + } + + /* fix the surface's normals */ + PicoFixSurfaceNormals( surface ); + + PicoSurface* picosurface = new PicoSurface( surface ); + aabb_extend_by_aabb_safe( m_aabb_local, picosurface->localAABB() ); + m_surfaces.push_back( picosurface ); + } +} +void constructNull(){ + PicoSurface* picosurface = new PicoSurface(); + m_aabb_local = picosurface->localAABB(); + m_surfaces.push_back( picosurface ); +} }; -inline void Surface_addLight(PicoSurface& surface, VectorLightList& lights, const Matrix4& localToWorld, const RendererLight& light) -{ - if(light.testAABB(aabb_for_oriented_aabb(surface.localAABB(), localToWorld))) - { - lights.addLight(light); - } +inline void Surface_addLight( PicoSurface& surface, VectorLightList& lights, const Matrix4& localToWorld, const RendererLight& light ){ + if ( light.testAABB( aabb_for_oriented_aabb( surface.localAABB(), localToWorld ) ) ) { + lights.addLight( light ); + } } class PicoModelInstance : - public scene::Instance, - public Renderable, - public SelectionTestable, - public LightCullable, - public SkinnedModel + public scene::Instance, + public Renderable, + public SelectionTestable, + public LightCullable, + public SkinnedModel +{ +class TypeCasts +{ +InstanceTypeCastTable m_casts; +public: +TypeCasts(){ + InstanceContainedCast::install( m_casts ); + InstanceContainedCast::install( m_casts ); + InstanceStaticCast::install( m_casts ); + InstanceStaticCast::install( m_casts ); + InstanceStaticCast::install( m_casts ); +} +InstanceTypeCastTable& get(){ + return m_casts; +} +}; + +PicoModel& m_picomodel; + +const LightList* m_lightList; +typedef Array SurfaceLightLists; +SurfaceLightLists m_surfaceLightLists; + +class Remap { - class TypeCasts - { - InstanceTypeCastTable m_casts; - public: - TypeCasts() - { - InstanceContainedCast::install(m_casts); - InstanceContainedCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - } - InstanceTypeCastTable& get() - { - return m_casts; - } - }; - - PicoModel& m_picomodel; - - const LightList* m_lightList; - typedef Array SurfaceLightLists; - SurfaceLightLists m_surfaceLightLists; - - class Remap - { - public: - CopiedString first; - Shader* second; - Remap() : second(0) - { - } - }; - typedef Array SurfaceRemaps; - SurfaceRemaps m_skins; - - PicoModelInstance(const PicoModelInstance&); - PicoModelInstance operator=(const PicoModelInstance&); public: - typedef LazyStatic StaticTypeCasts; - - void* m_test; - - Bounded& get(NullType) - { - return m_picomodel; - } - Cullable& get(NullType) - { - return m_picomodel; - } - - void lightsChanged() - { - m_lightList->lightsChanged(); - } - typedef MemberCaller LightsChangedCaller; - - void constructRemaps() - { - ASSERT_MESSAGE(m_skins.size() == m_picomodel.size(), "ERROR"); - ModelSkin* skin = NodeTypeCast::cast(path().parent()); - if(skin != 0 && skin->realised()) - { - SurfaceRemaps::iterator j = m_skins.begin(); - for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j) - { - const char* remap = skin->getRemap((*i)->getShader()); - if(!string_empty(remap)) - { - (*j).first = remap; - (*j).second = GlobalShaderCache().capture(remap); - } - else - { - (*j).second = 0; - } - } - SceneChangeNotify(); - } - } - void destroyRemaps() - { - ASSERT_MESSAGE(m_skins.size() == m_picomodel.size(), "ERROR"); - for(SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i) - { - if((*i).second != 0) - { - GlobalShaderCache().release((*i).first.c_str()); - (*i).second = 0; - } - } - } - void skinChanged() - { - destroyRemaps(); - constructRemaps(); - } - - PicoModelInstance(const scene::Path& path, scene::Instance* parent, PicoModel& picomodel) : - Instance(path, parent, this, StaticTypeCasts::instance().get()), - m_picomodel(picomodel), - m_surfaceLightLists(m_picomodel.size()), - m_skins(m_picomodel.size()) - { - m_lightList = &GlobalShaderCache().attach(*this); - m_picomodel.m_lightsChanged = LightsChangedCaller(*this); - - Instance::setTransformChangedCallback(LightsChangedCaller(*this)); - - constructRemaps(); - } - ~PicoModelInstance() - { - destroyRemaps(); - - Instance::setTransformChangedCallback(Callback()); - - m_picomodel.m_lightsChanged = Callback(); - GlobalShaderCache().detach(*this); - } - - void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin(); - SurfaceRemaps::const_iterator k = m_skins.begin(); - for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j, ++k) - { - if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside) - { - renderer.setLights(*j); - (*i)->render(renderer, localToWorld, (*k).second != 0 ? (*k).second : (*i)->getState()); - } - } - } - - void renderSolid(Renderer& renderer, const VolumeTest& volume) const - { - m_lightList->evaluateLights(); - - render(renderer, volume, Instance::localToWorld()); - } - void renderWireframe(Renderer& renderer, const VolumeTest& volume) const - { - renderSolid(renderer, volume); - } - - void testSelect(Selector& selector, SelectionTest& test) - { - m_picomodel.testSelect(selector, test, Instance::localToWorld()); - } - - bool testLight(const RendererLight& light) const - { - return light.testAABB(worldAABB()); - } - void insertLight(const RendererLight& light) - { - const Matrix4& localToWorld = Instance::localToWorld(); - SurfaceLightLists::iterator j = m_surfaceLightLists.begin(); - for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i) - { - Surface_addLight(*(*i), *j++, localToWorld, light); - } - } - void clearLights() - { - for(SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i) - { - (*i).clear(); - } - } +CopiedString first; +Shader* second; +Remap() : second( 0 ){ +} +}; +typedef Array SurfaceRemaps; +SurfaceRemaps m_skins; + +PicoModelInstance( const PicoModelInstance& ); +PicoModelInstance operator=( const PicoModelInstance& ); +public: +typedef LazyStatic StaticTypeCasts; + +void* m_test; + +Bounded& get( NullType){ + return m_picomodel; +} +Cullable& get( NullType){ + return m_picomodel; +} + +void lightsChanged(){ + m_lightList->lightsChanged(); +} +typedef MemberCaller LightsChangedCaller; + +void constructRemaps(){ + ASSERT_MESSAGE( m_skins.size() == m_picomodel.size(), "ERROR" ); + ModelSkin* skin = NodeTypeCast::cast( path().parent() ); + if ( skin != 0 && skin->realised() ) { + SurfaceRemaps::iterator j = m_skins.begin(); + for ( PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j ) + { + const char* remap = skin->getRemap( ( *i )->getShader() ); + if ( !string_empty( remap ) ) { + ( *j ).first = remap; + ( *j ).second = GlobalShaderCache().capture( remap ); + } + else + { + ( *j ).second = 0; + } + } + SceneChangeNotify(); + } +} +void destroyRemaps(){ + ASSERT_MESSAGE( m_skins.size() == m_picomodel.size(), "ERROR" ); + for ( SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i ) + { + if ( ( *i ).second != 0 ) { + GlobalShaderCache().release( ( *i ).first.c_str() ); + ( *i ).second = 0; + } + } +} +void skinChanged(){ + destroyRemaps(); + constructRemaps(); +} + +PicoModelInstance( const scene::Path& path, scene::Instance* parent, PicoModel& picomodel ) : + Instance( path, parent, this, StaticTypeCasts::instance().get() ), + m_picomodel( picomodel ), + m_surfaceLightLists( m_picomodel.size() ), + m_skins( m_picomodel.size() ){ + m_lightList = &GlobalShaderCache().attach( *this ); + m_picomodel.m_lightsChanged = LightsChangedCaller( *this ); + + Instance::setTransformChangedCallback( LightsChangedCaller( *this ) ); + + constructRemaps(); +} +~PicoModelInstance(){ + destroyRemaps(); + + Instance::setTransformChangedCallback( Callback() ); + + m_picomodel.m_lightsChanged = Callback(); + GlobalShaderCache().detach( *this ); +} + +void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { + SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin(); + SurfaceRemaps::const_iterator k = m_skins.begin(); + for ( PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j, ++k ) + { + if ( ( *i )->intersectVolume( volume, localToWorld ) != c_volumeOutside ) { + renderer.setLights( *j ); + ( *i )->render( renderer, localToWorld, ( *k ).second != 0 ? ( *k ).second : ( *i )->getState() ); + } + } +} + +void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { + m_lightList->evaluateLights(); + + render( renderer, volume, Instance::localToWorld() ); +} +void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { + renderSolid( renderer, volume ); +} + +void testSelect( Selector& selector, SelectionTest& test ){ + m_picomodel.testSelect( selector, test, Instance::localToWorld() ); +} + +bool testLight( const RendererLight& light ) const { + return light.testAABB( worldAABB() ); +} +void insertLight( const RendererLight& light ){ + const Matrix4& localToWorld = Instance::localToWorld(); + SurfaceLightLists::iterator j = m_surfaceLightLists.begin(); + for ( PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i ) + { + Surface_addLight( *( *i ), *j++, localToWorld, light ); + } +} +void clearLights(){ + for ( SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i ) + { + ( *i ).clear(); + } +} }; class PicoModelNode : public scene::Node::Symbiot, public scene::Instantiable { - class TypeCasts - { - NodeTypeCastTable m_casts; - public: - TypeCasts() - { - NodeStaticCast::install(m_casts); - } - NodeTypeCastTable& get() - { - return m_casts; - } - }; - - - scene::Node m_node; - InstanceSet m_instances; - PicoModel m_picomodel; +class TypeCasts +{ +NodeTypeCastTable m_casts; +public: +TypeCasts(){ + NodeStaticCast::install( m_casts ); +} +NodeTypeCastTable& get(){ + return m_casts; +} +}; + + +scene::Node m_node; +InstanceSet m_instances; +PicoModel m_picomodel; public: - typedef LazyStatic StaticTypeCasts; - - PicoModelNode() : m_node(this, this, StaticTypeCasts::instance().get()) - { - } - PicoModelNode(picoModel_t* model) : m_node(this, this, StaticTypeCasts::instance().get()), m_picomodel(model) - { - } - - void release() - { - delete this; - } - scene::Node& node() - { - return m_node; - } - - scene::Instance* create(const scene::Path& path, scene::Instance* parent) - { - return new PicoModelInstance(path, parent, m_picomodel); - } - void forEachInstance(const scene::Instantiable::Visitor& visitor) - { - m_instances.forEachInstance(visitor); - } - void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance) - { - m_instances.insert(observer, path, instance); - } - scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path) - { - return m_instances.erase(observer, path); - } +typedef LazyStatic StaticTypeCasts; + +PicoModelNode() : m_node( this, this, StaticTypeCasts::instance().get() ){ +} +PicoModelNode( picoModel_t* model ) : m_node( this, this, StaticTypeCasts::instance().get() ), m_picomodel( model ){ +} + +void release(){ + delete this; +} +scene::Node& node(){ + return m_node; +} + +scene::Instance* create( const scene::Path& path, scene::Instance* parent ){ + return new PicoModelInstance( path, parent, m_picomodel ); +} +void forEachInstance( const scene::Instantiable::Visitor& visitor ){ + m_instances.forEachInstance( visitor ); +} +void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){ + m_instances.insert( observer, path, instance ); +} +scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){ + return m_instances.erase( observer, path ); +} }; @@ -698,101 +628,91 @@ template class create_new { public: - static Type* construct(const Key& key) - { - return new Type(key); - } - static void destroy(Type* value) - { - delete value; - } +static Type* construct( const Key& key ){ + return new Type( key ); +} +static void destroy( Type* value ){ + delete value; +} }; template > class cache_element : public creation_policy { public: - inline cache_element() : m_count(0), m_value(0) {} - inline ~cache_element() - { - ASSERT_MESSAGE(m_count == 0 , "destroyed a reference before it was released\n"); - if(m_count > 0) - destroy(); - } - inline Type* capture(const Key& key) - { - if(++m_count == 1) - construct(key); - return m_value; - } - inline void release() - { - ASSERT_MESSAGE(!empty(), "failed to release reference - not found in cache\n"); - if(--m_count == 0) - destroy(); - } - inline bool empty() - { - return m_count == 0; - } - inline void refresh(const Key& key) - { - m_value->refresh(key); - } +inline cache_element() : m_count( 0 ), m_value( 0 ) {} +inline ~cache_element(){ + ASSERT_MESSAGE( m_count == 0, "destroyed a reference before it was released\n" ); + if ( m_count > 0 ) { + destroy(); + } +} +inline Type* capture( const Key& key ){ + if ( ++m_count == 1 ) { + construct( key ); + } + return m_value; +} +inline void release(){ + ASSERT_MESSAGE( !empty(), "failed to release reference - not found in cache\n" ); + if ( --m_count == 0 ) { + destroy(); + } +} +inline bool empty(){ + return m_count == 0; +} +inline void refresh( const Key& key ){ + m_value->refresh( key ); +} private: - inline void construct(const Key& key) - { - m_value = creation_policy::construct(key); - } - inline void destroy() - { - creation_policy::destroy(m_value); - } - - std::size_t m_count; - Type* m_value; +inline void construct( const Key& key ){ + m_value = creation_policy::construct( key ); +} +inline void destroy(){ + creation_policy::destroy( m_value ); +} + +std::size_t m_count; +Type* m_value; }; class create_picomodel { - typedef PicoModelKey key_type; - typedef PicoModel value_type; +typedef PicoModelKey key_type; +typedef PicoModel value_type; public: - static value_type* construct(const key_type& key) - { - picoModel_t* picomodel = PicoLoadModel(const_cast(key.first.c_str()), key.second); - value_type* value = new value_type(picomodel); - PicoFreeModel(picomodel); - return value; - } - static void destroy(value_type* value) - { - delete value; - } +static value_type* construct( const key_type& key ){ + picoModel_t* picomodel = PicoLoadModel( const_cast( key.first.c_str() ), key.second ); + value_type* value = new value_type( picomodel ); + PicoFreeModel( picomodel ); + return value; +} +static void destroy( value_type* value ){ + delete value; +} }; #include class ModelCache { - typedef PicoModel value_type; - +typedef PicoModel value_type; + public: - typedef PicoModelKey key_type; - typedef cache_element elem_type; - typedef std::map cache_type; - - value_type* capture(const key_type& key) - { - return m_cache[key].capture(key); - } - void release(const key_type& key) - { - m_cache[key].release(); - } +typedef PicoModelKey key_type; +typedef cache_element elem_type; +typedef std::map cache_type; + +value_type* capture( const key_type& key ){ + return m_cache[key].capture( key ); +} +void release( const key_type& key ){ + m_cache[key].release(); +} private: - cache_type m_cache; +cache_type m_cache; }; ModelCache g_model_cache; @@ -800,249 +720,223 @@ ModelCache g_model_cache; typedef struct remap_s { - char m_remapbuff[64+1024]; - char *original; - char *remap; + char m_remapbuff[64 + 1024]; + char *original; + char *remap; } remap_t; class RemapWrapper : -public Cullable, -public Bounded + public Cullable, + public Bounded { public: - RemapWrapper(const char* name) - { - parse_namestr(name); - - m_model = g_model_cache.capture(ModelCache::key_type(m_name, m_frame)); - - construct_shaders(); - } - virtual ~RemapWrapper() - { - g_model_cache.release(ModelCache::key_type(m_name, m_frame)); - - for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) - { - GlobalShaderCache().release((*i).c_str()); - } - - for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j) - { - delete (*j); - } - } - - VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const - { - return m_model->intersectVolume(test, localToWorld); - } - - virtual const AABB& localAABB() const - { - return m_model->localAABB(); - } - - void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - m_model->render(renderer, volume, localToWorld, m_states); - } - - void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld) - { - m_model->testSelect(selector, test, localToWorld); - } +RemapWrapper( const char* name ){ + parse_namestr( name ); + + m_model = g_model_cache.capture( ModelCache::key_type( m_name, m_frame ) ); + + construct_shaders(); +} +virtual ~RemapWrapper(){ + g_model_cache.release( ModelCache::key_type( m_name, m_frame ) ); + + for ( shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i ) + { + GlobalShaderCache().release( ( *i ).c_str() ); + } + + for ( remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j ) + { + delete ( *j ); + } +} + +VolumeIntersectionValue intersectVolume( const VolumeTest& test, const Matrix4& localToWorld ) const { + return m_model->intersectVolume( test, localToWorld ); +} + +virtual const AABB& localAABB() const { + return m_model->localAABB(); +} + +void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { + m_model->render( renderer, volume, localToWorld, m_states ); +} + +void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){ + m_model->testSelect( selector, test, localToWorld ); +} private: - void add_remap(const char *remap) - { - const char *ch; - remap_t *pRemap; - - ch = remap; - - while( *ch && *ch != ';' ) - ch++; - - if( *ch == '\0' ) { - // bad remap - globalErrorStream() << "WARNING: Shader _remap key found in a model entity without a ; character\n"; - } else { - pRemap = new remap_t; - - strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) ); - - pRemap->m_remapbuff[ch - remap] = '\0'; - - pRemap->original = pRemap->m_remapbuff; - pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1; - - m_remaps.push_back( pRemap ); - } - } - - void parse_namestr(const char *name) - { - const char *ptr, *s; - bool hasName, hasFrame; - - hasName = hasFrame = false; - - m_frame = 0; - - for( s = ptr = name; ; ++ptr ) - { - if( !hasName && (*ptr == ':' || *ptr == '\0')) - { - // model name - hasName = true; - m_name = CopiedString(s, ptr); - s = ptr + 1; - } - else if(*ptr == '?' || *ptr == '\0') - { - // model frame - hasFrame = true; - m_frame = atoi(CopiedString(s, ptr).c_str()); - s = ptr + 1; - } - else if(*ptr == '&' || *ptr == '\0') - { - // a remap - add_remap(CopiedString(s, ptr).c_str()); - s = ptr + 1; - } - - if(*ptr == '\0') - break; - } - } - - void construct_shaders() - { - const char* global_shader = shader_for_remap("*"); - - m_shaders.reserve(m_model->size()); - m_states.reserve(m_model->size()); - for(PicoModel::iterator i = m_model->begin(); i != m_model->end(); ++i) - { - const char* shader = shader_for_remap((*i)->getShader()); - m_shaders.push_back( - (shader[0] != '\0') - ? shader - : (global_shader[0] != '\0') - ? global_shader - : (*i)->getShader()); - m_states.push_back(GlobalShaderCache().capture(m_shaders.back().c_str())); - } - } - - inline const char* shader_for_remap(const char* remap) - { - for(remaps_t::iterator i = m_remaps.begin(); i != m_remaps.end(); ++i) - { - if(shader_equal(remap, (*i)->original)) - { - return (*i)->remap; - } - } - return ""; - } - - CopiedString m_name; - int m_frame; - PicoModel* m_model; - - typedef std::vector remaps_t; - remaps_t m_remaps; - typedef std::vector shaders_t; - shaders_t m_shaders; - typedef std::vector states_t; - states_t m_states; +void add_remap( const char *remap ){ + const char *ch; + remap_t *pRemap; + + ch = remap; + + while ( *ch && *ch != ';' ) + ch++; + + if ( *ch == '\0' ) { + // bad remap + globalErrorStream() << "WARNING: Shader _remap key found in a model entity without a ; character\n"; + } + else { + pRemap = new remap_t; + + strncpy( pRemap->m_remapbuff, remap, sizeof( pRemap->m_remapbuff ) ); + + pRemap->m_remapbuff[ch - remap] = '\0'; + + pRemap->original = pRemap->m_remapbuff; + pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1; + + m_remaps.push_back( pRemap ); + } +} + +void parse_namestr( const char *name ){ + const char *ptr, *s; + bool hasName, hasFrame; + + hasName = hasFrame = false; + + m_frame = 0; + + for ( s = ptr = name; ; ++ptr ) + { + if ( !hasName && ( *ptr == ':' || *ptr == '\0' ) ) { + // model name + hasName = true; + m_name = CopiedString( s, ptr ); + s = ptr + 1; + } + else if ( *ptr == '?' || *ptr == '\0' ) { + // model frame + hasFrame = true; + m_frame = atoi( CopiedString( s, ptr ).c_str() ); + s = ptr + 1; + } + else if ( *ptr == '&' || *ptr == '\0' ) { + // a remap + add_remap( CopiedString( s, ptr ).c_str() ); + s = ptr + 1; + } + + if ( *ptr == '\0' ) { + break; + } + } +} + +void construct_shaders(){ + const char* global_shader = shader_for_remap( "*" ); + + m_shaders.reserve( m_model->size() ); + m_states.reserve( m_model->size() ); + for ( PicoModel::iterator i = m_model->begin(); i != m_model->end(); ++i ) + { + const char* shader = shader_for_remap( ( *i )->getShader() ); + m_shaders.push_back( + ( shader[0] != '\0' ) + ? shader + : ( global_shader[0] != '\0' ) + ? global_shader + : ( *i )->getShader() ); + m_states.push_back( GlobalShaderCache().capture( m_shaders.back().c_str() ) ); + } +} + +inline const char* shader_for_remap( const char* remap ){ + for ( remaps_t::iterator i = m_remaps.begin(); i != m_remaps.end(); ++i ) + { + if ( shader_equal( remap, ( *i )->original ) ) { + return ( *i )->remap; + } + } + return ""; +} + +CopiedString m_name; +int m_frame; +PicoModel* m_model; + +typedef std::vector remaps_t; +remaps_t m_remaps; +typedef std::vector shaders_t; +shaders_t m_shaders; +typedef std::vector states_t; +states_t m_states; }; class RemapWrapperInstance : public scene::Instance, public Renderable, public SelectionTestable { - RemapWrapper& m_remapwrapper; +RemapWrapper& m_remapwrapper; public: - RemapWrapperInstance(const scene::Path& path, scene::Instance* parent, RemapWrapper& remapwrapper) : Instance(path, parent), m_remapwrapper(remapwrapper) - { - scene::Instance::m_cullable = &m_remapwrapper; - scene::Instance::m_render = this; - scene::Instance::m_select = this; - } - - void renderSolid(Renderer& renderer, const VolumeTest& volume) const - { - m_remapwrapper.render(renderer, volume, Instance::localToWorld()); - } - void renderWireframe(Renderer& renderer, const VolumeTest& volume) const - { - renderSolid(renderer, volume); - } - - void testSelect(Selector& selector, SelectionTest& test) - { - m_remapwrapper.testSelect(selector, test, Instance::localToWorld()); - } +RemapWrapperInstance( const scene::Path& path, scene::Instance* parent, RemapWrapper& remapwrapper ) : Instance( path, parent ), m_remapwrapper( remapwrapper ){ + scene::Instance::m_cullable = &m_remapwrapper; + scene::Instance::m_render = this; + scene::Instance::m_select = this; +} + +void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { + m_remapwrapper.render( renderer, volume, Instance::localToWorld() ); +} +void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { + renderSolid( renderer, volume ); +} + +void testSelect( Selector& selector, SelectionTest& test ){ + m_remapwrapper.testSelect( selector, test, Instance::localToWorld() ); +} }; class RemapWrapperNode : public scene::Node::Symbiot, public scene::Instantiable { - scene::Node m_node; - typedef RemapWrapperInstance instance_type; - InstanceSet m_instances; - RemapWrapper m_remapwrapper; +scene::Node m_node; +typedef RemapWrapperInstance instance_type; +InstanceSet m_instances; +RemapWrapper m_remapwrapper; public: - RemapWrapperNode(const char* name) : m_node(this), m_remapwrapper(name) - { - m_node.m_instance = this; - } - - void release() - { - delete this; - } - scene::Node& node() - { - return m_node; - } - - scene::Instance* create(const scene::Path& path, scene::Instance* parent) - { - return new instance_type(path, parent, m_remapwrapper); - } - void forEachInstance(const scene::Instantiable::Visitor& visitor) - { - m_instances.forEachInstance(visitor); - } - void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance) - { - m_instances.insert(observer, path, instance); - } - scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path) - { - return m_instances.erase(observer, path); - } +RemapWrapperNode( const char* name ) : m_node( this ), m_remapwrapper( name ){ + m_node.m_instance = this; +} + +void release(){ + delete this; +} +scene::Node& node(){ + return m_node; +} + +scene::Instance* create( const scene::Path& path, scene::Instance* parent ){ + return new instance_type( path, parent, m_remapwrapper ); +} +void forEachInstance( const scene::Instantiable::Visitor& visitor ){ + m_instances.forEachInstance( visitor ); +} +void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){ + m_instances.insert( observer, path, instance ); +} +scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){ + return m_instances.erase( observer, path ); +} }; -scene::Node& LoadRemapModel(const char* name) -{ - return (new RemapWrapperNode(name))->node(); +scene::Node& LoadRemapModel( const char* name ){ + return ( new RemapWrapperNode( name ) )->node(); } #endif -size_t picoInputStreamReam(void* inputStream, unsigned char* buffer, size_t length) -{ - return reinterpret_cast(inputStream)->read(buffer, length); +size_t picoInputStreamReam( void* inputStream, unsigned char* buffer, size_t length ){ + return reinterpret_cast( inputStream )->read( buffer, length ); } -scene::Node& loadPicoModel(const picoModule_t* module, ArchiveFile& file) -{ - picoModel_t* model = PicoModuleLoadModelStream(module, &file.getInputStream(), picoInputStreamReam, file.size(), 0, file.getName()); - PicoModelNode* modelNode = new PicoModelNode(model); - PicoFreeModel(model); - return modelNode->node(); +scene::Node& loadPicoModel( const picoModule_t* module, ArchiveFile& file ){ + picoModel_t* model = PicoModuleLoadModelStream( module, &file.getInputStream(), picoInputStreamReam, file.size(), 0, file.getName() ); + PicoModelNode* modelNode = new PicoModelNode( model ); + PicoFreeModel( model ); + return modelNode->node(); }