transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / plugins / entity / miscmodel.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 <stdlib.h>\r
23 \r
24 #include "entity_entitymodel.h"\r
25 #include "entity.h"\r
26 \r
27 //\r
28 // CEntityMiscModel implementation\r
29 //\r
30 \r
31 CEntityMiscModel::CEntityMiscModel (entity_t *e)\r
32 {\r
33   refCount = 1;\r
34   m_entity = e;\r
35   m_model = NULL;\r
36   VectorSet(m_translate, 0,0,0);\r
37   VectorSet(m_euler, 0,0,0);\r
38   VectorSet(m_scale, 1,1,1);\r
39   VectorSet(m_pivot, 0,0,0);\r
40   m4x4_identity(m_transform);\r
41   m4x4_identity(m_inverse_transform);\r
42 }\r
43 \r
44 CEntityMiscModel::~CEntityMiscModel ()\r
45 {\r
46   if(m_cachereq.GetBuffer()[0] != ':'\r
47     && m_version.c_str()[0] != '\0')\r
48     GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str());\r
49 }\r
50 \r
51 \r
52 // IRender\r
53 \r
54 void CEntityMiscModel::Draw(int state, int rflags) const\r
55 {\r
56   // push the current modelview matrix\r
57   // FIXME: put in a check for stack recursion depth..\r
58   // or avoid recursion of opengl matrix stack\r
59   g_QglTable.m_pfn_qglPushMatrix();\r
60   // apply the parent-to-local transform\r
61         g_QglTable.m_pfn_qglMultMatrixf(m_transform);\r
62 \r
63   pivot_draw(m_pivot);\r
64 \r
65   // draw children\r
66   if(m_model && m_model->pRender)  \r
67   {\r
68     m_model->pRender->Draw(state, rflags);\r
69   }\r
70  \r
71   g_QglTable.m_pfn_qglPopMatrix();\r
72 }\r
73 \r
74 // ISelect\r
75 \r
76 bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const\r
77 {\r
78   vec_t dist_start = *dist;\r
79   vec_t dist_local = *dist;\r
80         ray_t ray_local = *ray;\r
81 \r
82   if (aabb_test_ray(&m_BBox, ray) == 0)\r
83     return false;\r
84 \r
85   ray_transform(&ray_local, m_inverse_transform);\r
86 \r
87   if(m_model && m_model->pSelect)\r
88   {\r
89     if(m_model->pSelect->TestRay(&ray_local, &dist_local))\r
90         *dist = dist_local;\r
91   }\r
92   else *dist = dist_local;\r
93 \r
94   return *dist < dist_start;\r
95 }\r
96 \r
97 \r
98 //IEdit\r
99 \r
100 void CEntityMiscModel::Translate(const vec3_t translation)\r
101 {\r
102   VectorIncrement(translation, m_translate);\r
103   UpdateCachedData();\r
104 }\r
105 \r
106 void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation)\r
107 {\r
108   m4x4_t rotation_matrix;\r
109 \r
110   m4x4_identity(rotation_matrix);\r
111   m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, eXYZ, pivot);\r
112   m4x4_transform_point(rotation_matrix, m_translate);\r
113 \r
114   VectorIncrement(rotation, m_euler);\r
115 \r
116   UpdateCachedData();\r
117 }\r
118 \r
119 void CEntityMiscModel::OnKeyValueChanged(entity_t *e, const char *key, const char* value)\r
120 {\r
121   if(strcmp(key, "model") == 0)\r
122     SetName(value);\r
123   else if(strcmp(key, "_frame") == 0)\r
124   {\r
125     SetName(ValueForKey(e, "model"));\r
126   }\r
127   else if(strcmp(key, "angle") == 0)\r
128   {\r
129     VectorSet(m_euler, 0.f, 0.f, 0.f);\r
130     m_euler[2] = atof(value);\r
131     UpdateCachedData();\r
132   }\r
133   else if(strcmp(key, "angles") == 0)\r
134   {\r
135     VectorSet(m_euler, 0.f, 0.f, 0.f);\r
136     if (value[0] != '\0')\r
137       sscanf (value, "%f %f %f", &m_euler[1], &m_euler[2], &m_euler[0]);\r
138     UpdateCachedData();\r
139   }\r
140   else if(strcmp(key, "modelscale") == 0 || strcmp(key,"modelscale_vec") == 0)\r
141   {\r
142     const char *s;\r
143     VectorSet(m_scale, 1.f, 1.f, 1.f);\r
144     s = ValueForKey(e,"modelscale");\r
145     if (s[0] != '\0')\r
146     {\r
147       float f = atof(s);\r
148       if( f != 0 )\r
149         VectorSet(m_scale, f, f, f);\r
150       else\r
151         Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n");\r
152     }\r
153     s = ValueForKey(e,"modelscale_vec");\r
154     if (s[0] != '\0')\r
155     {\r
156       sscanf (s, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]);\r
157       if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0)\r
158       {\r
159         VectorSet(m_scale, 1,1,1);\r
160         Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n");\r
161       }\r
162     }\r
163     UpdateCachedData();\r
164   }\r
165   else if(strcmp(key, "origin") == 0)\r
166   {\r
167     sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); \r
168     UpdateCachedData();\r
169   }\r
170   else if(strncmp(key,"_remap",6) == 0)\r
171   {\r
172     SetName(ValueForKey(e, "model"));\r
173   }\r
174 }\r
175 \r
176 //\r
177 // CEntityMiscModel\r
178 //\r
179 \r
180 // private:\r
181 \r
182 void CEntityMiscModel::BuildCacheRequestString(const char *name)\r
183 {\r
184   bool hasRemaps = false;\r
185 \r
186   m_cachereq.Format( "%s:%i", name, IntForKey(m_entity,"_frame") );\r
187 \r
188   for (epair_t* ep = m_entity->epairs ; ep ; ep=ep->next)\r
189   {\r
190     if( strncmp(ep->key,"_remap",6) == 0 )\r
191     {\r
192       if( !hasRemaps )\r
193       {\r
194         hasRemaps = true;\r
195         m_cachereq += "?";\r
196       } else {\r
197         m_cachereq += "&";\r
198       }\r
199       m_cachereq += ep->value;\r
200     }\r
201   }\r
202 }\r
203 \r
204 void CEntityMiscModel::SetName(const char *name)\r
205 {\r
206   Str m_oldcachereq = m_cachereq;\r
207 \r
208   if( name[0] == '\0' ) {\r
209     return;\r
210   }\r
211 \r
212   BuildCacheRequestString(name);\r
213 \r
214   if(strcmp(m_oldcachereq, m_cachereq) == 0)\r
215     return;\r
216 \r
217   if(m_cachereq.GetBuffer()[0] != ':'\r
218     && m_version.c_str()[0] != '\0')\r
219     GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str());\r
220 \r
221   m_model = NULL;\r
222 \r
223   if(name[0] != '\0')\r
224   {\r
225     const char* dot = strrchr(name, '.');\r
226     if(dot != NULL)\r
227     {\r
228       m_version = ++dot;\r
229       m_model = GetModelCache()->GetByID(m_cachereq.GetBuffer(), m_version.c_str());\r
230     }\r
231   }\r
232 \r
233   UpdateCachedData();\r
234 }\r
235 \r
236 \r
237 void CEntityMiscModel::UpdateCachedData()\r
238 {\r
239   aabb_t aabb_temp;\r
240 \r
241   m4x4_identity(m_transform);\r
242   m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, eXYZ, m_scale, m_pivot);\r
243   memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t));\r
244   m4x4_invert(m_inverse_transform);\r
245 \r
246   aabb_clear(&aabb_temp);\r
247 \r
248   if(m_model && m_model->pRender)\r
249     aabb_extend_by_aabb(&aabb_temp, m_model->pRender->GetAABB());\r
250   else\r
251     VectorSet(aabb_temp.extents, 8, 8, 8);\r
252 \r
253   aabb_for_transformed_aabb(&m_BBox, &aabb_temp, m_transform);\r
254 }\r