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