-\r
-#include "cpicomodel.h"\r
-#include "qertypes.h"\r
-\r
-#include <map>\r
-#include <vector>\r
-\r
-#define RADIANT_ASSERT(condition, message) if(!(condition)) { Sys_Printf("ASSERTION FAILURE: " message "\n"); } else\r
-\r
-template<class key_type, class value_type>\r
-class cache_element\r
-{\r
-public:\r
- inline cache_element() : m_count(0), m_value(NULL) {}\r
- inline ~cache_element()\r
- {\r
- RADIANT_ASSERT(m_count == 0 , "destroyed a reference before it was released\n");\r
- if(m_count > 0)\r
- destroy();\r
- }\r
- inline value_type* capture(const key_type& key)\r
- {\r
- if(++m_count == 1)\r
- construct(key);\r
- return m_value;\r
- }\r
- inline void release()\r
- {\r
- RADIANT_ASSERT(!empty(), "failed to release reference - not found in cache\n");\r
- if(--m_count == 0)\r
- destroy();\r
- }\r
- inline bool empty()\r
- {\r
- return m_count == 0;\r
- }\r
- inline void refresh(const key_type& key)\r
- {\r
- m_value->refresh(key);\r
- }\r
-private:\r
- inline void construct(const key_type& key)\r
- {\r
- m_value = new value_type(key);\r
- }\r
- inline void destroy()\r
- {\r
- delete m_value;\r
- }\r
-\r
- unsigned int m_count;\r
- value_type* m_value;\r
-};\r
-\r
-class ModelCache\r
-{\r
- typedef CPicoModel value_type;\r
- \r
-public:\r
- typedef PicoModelKey key_type;\r
- typedef cache_element<key_type, value_type> elem_type;\r
- typedef map<key_type, elem_type> cache_type;\r
- \r
- value_type* capture(const key_type& key)\r
- {\r
- return m_cache[key].capture(key);\r
- }\r
- void release(const key_type& key)\r
- {\r
- m_cache[key].release();\r
- }\r
-\r
-private:\r
- cache_type m_cache;\r
-};\r
-\r
-ModelCache g_model_cache;\r
-\r
-\r
-\r
-typedef struct remap_s {\r
- char m_remapbuff[64+1024];\r
- char *original;\r
- char *remap;\r
-} remap_t;\r
-\r
-class RemapWrapper : public IRender, public ISelect\r
-{\r
- unsigned int m_refcount;\r
-public:\r
- RemapWrapper(entity_interfaces_t* model, const char* name)\r
- : m_refcount(1)\r
- {\r
- parse_namestr(name);\r
-\r
- m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), m_frame));\r
-\r
- model->pRender = this;\r
- model->pRender->IncRef();\r
- model->pEdit = NULL;\r
- model->pSelect = this;\r
- model->pSelect->IncRef();\r
-\r
- construct_shaders();\r
- }\r
- virtual ~RemapWrapper()\r
- {\r
- g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), m_frame));\r
-\r
- for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) {\r
- (*i)->DecRef();\r
- }\r
-\r
- for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j)\r
- {\r
- remap_t *pRemap = (*j);\r
- delete pRemap;\r
- }\r
- m_remaps.clear();\r
- }\r
- virtual void IncRef()\r
- {\r
- ++m_refcount;\r
- }\r
- virtual void DecRef()\r
- {\r
- if(--m_refcount == 0)\r
- delete this;\r
- }\r
- virtual void Draw(int state, int rflags) const\r
- {\r
- m_model->Draw(state, m_shaders, rflags);\r
- }\r
- virtual const aabb_t *GetAABB() const \r
- {\r
- return m_model->GetAABB();\r
- }\r
- virtual bool TestRay(const ray_t *ray, vec_t *dist) const\r
- {\r
- return m_model->TestRay(ray, dist);\r
- }\r
-private:\r
- void add_remap(const char *remap)\r
- {\r
- const char *ch;\r
- remap_t *pRemap;\r
-\r
- ch = remap;\r
-\r
- while( *ch && *ch != ';' )\r
- ch++;\r
-\r
- if( *ch == '\0' ) {\r
- // bad remap\r
- Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in a model entity without a ; character\n" );\r
- } else {\r
- pRemap = new remap_t;\r
-\r
- strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) );\r
-\r
- pRemap->m_remapbuff[ch - remap] = '\0';\r
-\r
- pRemap->original = pRemap->m_remapbuff;\r
- pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1;\r
-\r
- m_remaps.push_back( pRemap );\r
- }\r
- }\r
-\r
- void parse_namestr(const char *name)\r
- {\r
- const char *ptr, *s;\r
- char buf[1024];\r
- bool hasName, hasFrame;\r
-\r
- hasName = hasFrame = false;\r
-\r
- for( s = ptr = name; *ptr; ptr++ ) {\r
- if( !hasName && *ptr == ':' ) {\r
- // model name\r
- hasName = true;\r
- strncpy( buf, s, ptr - s );\r
- buf[ptr - s] = '\0';\r
- m_name = buf;\r
- s = ptr + 1;\r
- } else if( *ptr == '?' ) {\r
- // model frame\r
- hasFrame = true;\r
- strncpy( buf, s, ptr - s );\r
- buf[ptr - s] = '\0';\r
- m_frame = atoi(buf);\r
- s = ptr + 1;\r
- } else if( *ptr == '&' ) {\r
- // a remap\r
- strncpy( buf, s, ptr - s );\r
- buf[ptr - s] = '\0';\r
- add_remap( buf );\r
- s = ptr + 1;\r
- }\r
- }\r
-\r
- if( !hasFrame ) {\r
- // model frame\r
- strncpy( buf, s, ptr - s );\r
- buf[ptr - s] = '\0';\r
- m_frame = atoi(buf);\r
- } else {\r
- // a remap\r
- strncpy( buf, s, ptr - s );\r
- buf[ptr - s] = '\0';\r
- add_remap( buf );\r
- }\r
- }\r
-\r
- void construct_shaders()\r
- {\r
- IShader* global_shader = shader_for_remap("*");\r
-\r
- unsigned int numSurfaces = m_model->GetNumSurfaces();\r
- m_shaders.reserve(numSurfaces);\r
- // now go through our surface and find our shaders, remap if needed\r
- for(unsigned int j = 0; j < numSurfaces; j++ )\r
- {\r
- const char* surfShaderName = m_model->GetShaderNameForSurface(j);\r
- IShader* shader = shader_for_remap(surfShaderName);\r
-// m_shaders.push_back((shader) ? shader : (global_shader) ? global_shader : QERApp_Shader_ForName(surfShaderName));\r
- if( shader ) {\r
- m_shaders.push_back(shader);\r
- } else if( global_shader ) {\r
- m_shaders.push_back(global_shader);\r
- } else {\r
- m_shaders.push_back(QERApp_Shader_ForName(surfShaderName));\r
- }\r
- }\r
- }\r
- \r
- inline IShader* shader_for_remap(const char* remap)\r
- {\r
- remap_t *pRemap;\r
- remaps_t::iterator i;\r
- for(i = m_remaps.begin(); i != m_remaps.end(); ++i)\r
- {\r
- pRemap = (*i);\r
- if( stricmp( remap, pRemap->original ) == 0 )\r
- break;\r
- }\r
- return (i != m_remaps.end()) ? QERApp_Shader_ForName(pRemap->remap) : NULL;\r
- }\r
-\r
- Str m_name;\r
- int m_frame;\r
- CPicoModel* m_model;\r
-\r
- typedef vector<remap_t *> remaps_t;\r
- remaps_t m_remaps;\r
- typedef vector<IShader*> shaders_t;\r
- shaders_t m_shaders;\r
-};\r
-\r
-class ModelWrapper : public IRender, public ISelect\r
-{\r
- unsigned int m_refcount;\r
-public:\r
- ModelWrapper(entity_interfaces_t* model, const char* name)\r
- : m_refcount(1), m_name(name)\r
- {\r
- m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), 0));\r
-\r
- model->pRender = this;\r
- model->pRender->IncRef();\r
- model->pEdit = NULL;\r
- model->pSelect = this;\r
- model->pSelect->IncRef();\r
- }\r
- virtual ~ModelWrapper()\r
- {\r
- g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), 0));\r
- }\r
-\r
- virtual void IncRef()\r
- {\r
- ++m_refcount;\r
- }\r
- virtual void DecRef()\r
- {\r
- if(--m_refcount == 0)\r
- delete this;\r
- }\r
- virtual void Draw(int state, int rflags) const\r
- {\r
- m_model->Draw(state, rflags);\r
- }\r
- virtual const aabb_t *GetAABB() const \r
- {\r
- return m_model->GetAABB();\r
- }\r
- virtual bool TestRay(const ray_t *ray, vec_t *dist) const\r
- {\r
- return m_model->TestRay(ray, dist);\r
- }\r
-\r
- Str m_name;\r
- CPicoModel* m_model;\r
-};\r
-\r
-void LoadModel(entity_interfaces_t* model, const char* name)\r
-{\r
- if(strchr(name, ':') != NULL || strchr(name, '?') != NULL || strchr(name, '&') != NULL)\r
- {\r
- RemapWrapper* wrapper = new RemapWrapper(model, name);\r
- wrapper->DecRef();\r
- }\r
- else\r
- {\r
- ModelWrapper* wrapper = new ModelWrapper(model, name);\r
- wrapper->DecRef();\r
- }\r
-}\r
+
+#include "cpicomodel.h"
+#include "qertypes.h"
+
+#include <map>
+#include <vector>
+
+#define RADIANT_ASSERT( condition, message ) if ( !( condition ) ) { Sys_Printf( "ASSERTION FAILURE: " message "\n" ); } else
+
+template<class key_type, class value_type>
+class cache_element
+{
+public:
+inline cache_element() : m_count( 0 ), m_value( NULL ) {}
+inline ~cache_element(){
+ RADIANT_ASSERT( m_count == 0, "destroyed a reference before it was released\n" );
+ if ( m_count > 0 ) {
+ destroy();
+ }
+}
+inline value_type* capture( const key_type& key ){
+ if ( ++m_count == 1 ) {
+ construct( key );
+ }
+ return m_value;
+}
+inline void release(){
+ RADIANT_ASSERT( !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_type& key ){
+ m_value->refresh( key );
+}
+private:
+inline void construct( const key_type& key ){
+ m_value = new value_type( key );
+}
+inline void destroy(){
+ delete m_value;
+}
+
+unsigned int m_count;
+value_type* m_value;
+};
+
+class ModelCache
+{
+typedef CPicoModel value_type;
+
+public:
+typedef PicoModelKey key_type;
+typedef cache_element<key_type, value_type> elem_type;
+typedef map<key_type, elem_type> 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;
+};
+
+ModelCache g_model_cache;
+
+
+
+typedef struct remap_s {
+ char m_remapbuff[64 + 1024];
+ char *original;
+ char *remap;
+} remap_t;
+
+class RemapWrapper : public IRender, public ISelect
+{
+unsigned int m_refcount;
+public:
+RemapWrapper( entity_interfaces_t* model, const char* name )
+ : m_refcount( 1 ){
+ parse_namestr( name );
+
+ m_model = g_model_cache.capture( ModelCache::key_type( m_name.GetBuffer(), m_frame ) );
+
+ model->pRender = this;
+ model->pRender->IncRef();
+ model->pEdit = NULL;
+ model->pSelect = this;
+ model->pSelect->IncRef();
+
+ construct_shaders();
+}
+virtual ~RemapWrapper(){
+ g_model_cache.release( ModelCache::key_type( m_name.GetBuffer(), m_frame ) );
+
+ for ( shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i ) {
+ ( *i )->DecRef();
+ }
+
+ for ( remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j )
+ {
+ remap_t *pRemap = ( *j );
+ delete pRemap;
+ }
+ m_remaps.clear();
+}
+virtual void IncRef(){
+ ++m_refcount;
+}
+virtual void DecRef(){
+ if ( --m_refcount == 0 ) {
+ delete this;
+ }
+}
+virtual void Draw( int state, int rflags ) const {
+ m_model->Draw( state, m_shaders, rflags );
+}
+virtual const aabb_t *GetAABB() const {
+ return m_model->GetAABB();
+}
+virtual bool TestRay( const ray_t *ray, vec_t *dist ) const {
+ return m_model->TestRay( ray, dist );
+}
+private:
+void add_remap( const char *remap ){
+ const char *ch;
+ remap_t *pRemap;
+
+ ch = remap;
+
+ while ( *ch && *ch != ';' )
+ ch++;
+
+ if ( *ch == '\0' ) {
+ // bad remap
+ Sys_FPrintf( SYS_WRN, "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;
+ char buf[1024];
+ bool hasName, hasFrame;
+
+ hasName = hasFrame = false;
+
+ for ( s = ptr = name; *ptr; ptr++ ) {
+ if ( !hasName && *ptr == ':' ) {
+ // model name
+ hasName = true;
+ strncpy( buf, s, ptr - s );
+ buf[ptr - s] = '\0';
+ m_name = buf;
+ s = ptr + 1;
+ }
+ else if ( *ptr == '?' ) {
+ // model frame
+ hasFrame = true;
+ strncpy( buf, s, ptr - s );
+ buf[ptr - s] = '\0';
+ m_frame = atoi( buf );
+ s = ptr + 1;
+ }
+ else if ( *ptr == '&' ) {
+ // a remap
+ strncpy( buf, s, ptr - s );
+ buf[ptr - s] = '\0';
+ add_remap( buf );
+ s = ptr + 1;
+ }
+ }
+
+ if ( !hasFrame ) {
+ // model frame
+ strncpy( buf, s, ptr - s );
+ buf[ptr - s] = '\0';
+ m_frame = atoi( buf );
+ }
+ else {
+ // a remap
+ strncpy( buf, s, ptr - s );
+ buf[ptr - s] = '\0';
+ add_remap( buf );
+ }
+}
+
+void construct_shaders(){
+ IShader* global_shader = shader_for_remap( "*" );
+
+ unsigned int numSurfaces = m_model->GetNumSurfaces();
+ m_shaders.reserve( numSurfaces );
+ // now go through our surface and find our shaders, remap if needed
+ for ( unsigned int j = 0; j < numSurfaces; j++ )
+ {
+ const char* surfShaderName = m_model->GetShaderNameForSurface( j );
+ IShader* shader = shader_for_remap( surfShaderName );
+ // Determine which shader it is going to be
+ if ( !shader ) {
+ if ( global_shader ) {
+ shader = global_shader;
+ }
+ else {
+ shader = QERApp_Shader_ForName( surfShaderName );
+ }
+ }
+ // Add reference
+ shader->IncRef();
+ // Done, continue
+ m_shaders.push_back( shader );
+ }
+}
+
+inline IShader* shader_for_remap( const char* remap ){
+ remap_t *pRemap;
+ remaps_t::iterator i;
+ for ( i = m_remaps.begin(); i != m_remaps.end(); ++i )
+ {
+ pRemap = ( *i );
+ if ( stricmp( remap, pRemap->original ) == 0 ) {
+ break;
+ }
+ }
+ return ( i != m_remaps.end() ) ? QERApp_Shader_ForName( pRemap->remap ) : NULL;
+}
+
+Str m_name;
+int m_frame;
+CPicoModel* m_model;
+
+typedef vector<remap_t *> remaps_t;
+remaps_t m_remaps;
+typedef vector<IShader*> shaders_t;
+shaders_t m_shaders;
+};
+
+class ModelWrapper : public IRender, public ISelect
+{
+unsigned int m_refcount;
+public:
+ModelWrapper( entity_interfaces_t* model, const char* name )
+ : m_refcount( 1 ), m_name( name ){
+ m_model = g_model_cache.capture( ModelCache::key_type( m_name.GetBuffer(), 0 ) );
+
+ model->pRender = this;
+ model->pRender->IncRef();
+ model->pEdit = NULL;
+ model->pSelect = this;
+ model->pSelect->IncRef();
+}
+virtual ~ModelWrapper(){
+ g_model_cache.release( ModelCache::key_type( m_name.GetBuffer(), 0 ) );
+}
+
+virtual void IncRef(){
+ ++m_refcount;
+}
+virtual void DecRef(){
+ if ( --m_refcount == 0 ) {
+ delete this;
+ }
+}
+virtual void Draw( int state, int rflags ) const {
+ m_model->Draw( state, rflags );
+}
+virtual const aabb_t *GetAABB() const {
+ return m_model->GetAABB();
+}
+virtual bool TestRay( const ray_t *ray, vec_t *dist ) const {
+ return m_model->TestRay( ray, dist );
+}
+
+Str m_name;
+CPicoModel* m_model;
+};
+
+void LoadModel( entity_interfaces_t* model, const char* name ){
+ if ( strchr( name, ':' ) != NULL || strchr( name, '?' ) != NULL || strchr( name, '&' ) != NULL ) {
+ RemapWrapper* wrapper = new RemapWrapper( model, name );
+ wrapper->DecRef();
+ }
+ else
+ {
+ ModelWrapper* wrapper = new ModelWrapper( model, name );
+ wrapper->DecRef();
+ }
+}