transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / plugins / model / cpicomodel.cpp
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #include "cpicomodel.h"\r
23 #include "cpicosurface.h"\r
24 \r
25 CPicoModel::CPicoModel(const PicoModelKey& key)\r
26 : m_refcount(1)\r
27 {\r
28   load(key.first.GetBuffer(), key.second);\r
29 }\r
30 \r
31 CPicoModel::CPicoModel(const Str& name)\r
32 : m_refcount(1)\r
33 {\r
34   load(name.GetBuffer(), 0);\r
35 }\r
36 \r
37 CPicoModel::CPicoModel(const Str& name, const int frame)\r
38 : m_refcount(1)\r
39 {\r
40   load(name.GetBuffer(), frame);\r
41 }\r
42 \r
43 CPicoModel::CPicoModel(const char *name, const int frame)\r
44 : m_refcount(1)\r
45 {\r
46   load(name, frame);\r
47 }\r
48 \r
49 void CPicoModel::load(const char *name, const int frame)\r
50 {\r
51   CPicoSurface *surf;\r
52   picoSurface_t *pSurface;\r
53   int i;\r
54 \r
55   m_name= new char[strlen(name)+1];\r
56   strcpy(m_name,name);\r
57 \r
58   m_frame = frame;\r
59 \r
60   if( !(m_pModel = PicoLoadModel(m_name, frame)) )\r
61   {\r
62     int len = strlen(m_name);\r
63 \r
64     // Try loading an mdc if md3 fails and vice-versa (fixme: only do this for games with mdc support)\r
65     if( !strcmp( m_name + len - 4, ".md3" ) )\r
66     {\r
67       m_name[len - 1] = 'c';\r
68       m_pModel = PicoLoadModel(m_name, frame);\r
69     } else if( !strcmp( m_name + len - 4, ".mdc" ) )\r
70     {\r
71       m_name[len - 1] = '3';\r
72       m_pModel = PicoLoadModel(m_name, frame);\r
73     }\r
74   }\r
75 \r
76   if( m_pModel )\r
77   {\r
78     m_children = g_ptr_array_new();\r
79           aabb_clear(&m_BBox);\r
80     for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ )\r
81           {\r
82       pSurface = PicoGetModelSurface(m_pModel,i);\r
83       surf = new CPicoSurface(pSurface);\r
84       g_ptr_array_add(m_children, surf);\r
85       aabb_extend_by_aabb(&m_BBox, surf->GetAABB());\r
86           }\r
87   }\r
88   else\r
89   {\r
90      m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0;\r
91      m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0;\r
92   }\r
93 \r
94   m_parents = g_ptr_array_new();\r
95 }\r
96 \r
97 CPicoModel::~CPicoModel()\r
98 {\r
99   if( m_pModel ) {\r
100     for(unsigned int i=0; i<m_children->len; i++)\r
101       ((CPicoSurface*)m_children->pdata[i])->DecRef();\r
102     g_ptr_array_free(m_children, FALSE);\r
103   }\r
104   g_ptr_array_free(m_parents, FALSE);\r
105   delete [] m_name;\r
106 }\r
107 \r
108 void CPicoModel::AddParent( CPicoParent *parent )\r
109 {\r
110   g_ptr_array_add(m_parents, parent);\r
111 }\r
112 \r
113 void CPicoModel::RemoveParent( CPicoParent *parent )\r
114 {\r
115   unsigned int i;\r
116   for(i=0; i<m_parents->len; i++) {\r
117     if( parent == (CPicoParent*)m_parents->pdata[i] )\r
118       g_ptr_array_remove_index_fast(m_parents, i);\r
119   }\r
120 }\r
121 \r
122 void CPicoModel::Reload( void )\r
123 {\r
124   CPicoSurface *surf;\r
125   picoSurface_t *pSurface;\r
126   int i;\r
127   unsigned int j;\r
128 \r
129   // Get rid of the old model\r
130   if( m_pModel ) {\r
131     for(j=0; j<m_children->len; j++) {\r
132       ((CPicoSurface*)m_children->pdata[j])->DecRef();\r
133       g_ptr_array_remove_index_fast(m_children, j);\r
134     }\r
135   }\r
136 \r
137   // And reload it\r
138   m_pModel = PicoLoadModel(m_name, m_frame);\r
139 \r
140   if( m_pModel )\r
141   {\r
142     m_children = g_ptr_array_new();\r
143           aabb_clear(&m_BBox);\r
144     for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ )\r
145           {\r
146       pSurface = PicoGetModelSurface(m_pModel,i);\r
147       surf = new CPicoSurface(pSurface);\r
148       g_ptr_array_add(m_children, surf);\r
149       aabb_extend_by_aabb(&m_BBox, surf->GetAABB());\r
150           }\r
151   }\r
152   else\r
153   {\r
154      m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0;\r
155      m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0;\r
156   }\r
157 \r
158   for(j=0; j<m_parents->len; j++) {\r
159     ((CPicoParent*)m_parents->pdata[j])->UpdateShaders();\r
160   }\r
161 }\r
162 \r
163 void CPicoModel::Draw(int state, vector<IShader*> shaders, int rflags) const\r
164 {\r
165   if( m_pModel ) {\r
166     for(unsigned int i=0; i<m_children->len; i++)\r
167       ((CPicoSurface*)m_children->pdata[i])->Draw(state, shaders[i], rflags);\r
168   }\r
169 }\r
170 \r
171 void CPicoModel::Draw(int state, int rflags) const\r
172 {\r
173   if( m_pModel ) {\r
174     for(unsigned int i=0; i<m_children->len; i++)\r
175       ((CPicoSurface*)m_children->pdata[i])->Draw(state, rflags);\r
176   }\r
177 }\r
178 \r
179 bool CPicoModel::TestRay(const ray_t *ray, vec_t *dist) const\r
180 {\r
181   vec_t dist_start = *dist;\r
182   vec_t dist_local = *dist;\r
183         ray_t ray_local = *ray;\r
184 \r
185   if( !m_pModel ) {\r
186     return false;\r
187   }\r
188 \r
189   if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local))\r
190     return false;\r
191   dist_local = dist_start;\r
192 \r
193   for(unsigned int i=0; i<m_children->len; i++)\r
194   {\r
195     if(((CPicoSurface*)m_children->pdata[i])->TestRay(&ray_local, &dist_local))\r
196     {\r
197       *dist = dist_local;\r
198     }\r
199   }\r
200 \r
201   return *dist < dist_start;\r
202 }\r
203 \r
204 int CPicoModel::GetNumSurfaces( void )\r
205 {\r
206   if( !m_pModel ) {\r
207     return 0;\r
208   }\r
209 \r
210   return m_children->len;\r
211 }\r
212 \r
213 char *CPicoModel::GetShaderNameForSurface( const unsigned int surf )\r
214 {\r
215   if( !m_pModel || surf < 0 || surf >= m_children->len ) {\r
216     return 0;\r
217   }\r
218 \r
219   return ((CPicoSurface*)m_children->pdata[surf])->GetShaderName();\r
220 }\r