1 /***************************************************************************
2 graphobj.cpp - Graphics geometry object
3 -------------------
4 begin : Tue Apr 23 2002
5 copyright : (C) 2002 by CJP
6 email : cornware-cjp@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cmath>
20 #include "pi.h"
21
22 #include <GL/gl.h>
23
24 #include "glextensions.h"
25 #include "vector.h"
26 #include "usmacros.h"
27 #include "lconfig.h"
28 //#include "graphicworld.h"
29 #include "datafile.h"
30 #include "glbfile.h"
31 #include "lodtexture.h"
32
33 #include "graphobj.h"
34
CGraphObj(CDataManager * manager,eDataType type)35 CGraphObj::CGraphObj(CDataManager *manager, eDataType type) : CDataObject(manager, type)
36 {
37 m_CurrentTime = 0.0; //Initial value doesn't matter, as long as it isn't NaN, inf etc.
38 }
39
~CGraphObj()40 CGraphObj::~CGraphObj()
41 {
42 unload();
43 }
44
load(const CString & filename,const CParamList & list)45 bool CGraphObj::load(const CString &filename, const CParamList &list)
46 {
47 CGLBFile f;
48 if(!f.load(filename)) return false;
49
50 CDataObject::load(filename, list);
51
52 CString subset = m_ParamList.getValue("subset", "");
53 vector<CDataObject *> matarray;
54 if(m_DataManager != NULL)
55 matarray = m_DataManager->getSubset(CDataObject::eMaterial, subset);
56
57 unsigned int waterTesselation = theMainConfig->getValue("animation", "watertesselation").toInt();
58
59 //the primitives
60 for(unsigned int p=0; p < f.m_Primitives.size(); p++)
61 {
62 CGLBFile::SPrimitive &pr1 = f.m_Primitives[p];
63
64 m_Primitives.push_back(SPrimitive());
65 SPrimitive &pr2 = m_Primitives.back();
66
67 //Material
68 pr2.LODs = pr1.material.LODs;
69 pr2.opacity = pr1.material.Opacity;
70 pr2.reflectance = pr1.material.Reflectance;
71 pr2.emissivity = pr1.material.Emissivity;
72
73 //Color and texture:
74 //default:
75 pr2.texture[0] = pr2.texture[1] = pr2.texture[2] = pr2.texture[3] = 0;
76 pr2.color[0] = pr2.color[1] = pr2.color[2] = pr2.color[3] = pr1.material.ModulationColor;
77
78 //Process the user-defined color
79 if(pr1.material.Opacity < 0.01 && pr1.material.ModulationColor.z > 0.99)
80 {
81 printf("Changing to user-defined color\n");
82 pr2.opacity = 1.0;
83 pr2.color[0] = pr2.color[1] = pr2.color[2] = pr2.color[3] =
84 list.getValue("color", "1,1,1").toVector();
85 }
86
87 //add texture
88 if(pr1.material.Texture >= 0)
89 {
90 CLODTexture *tex = (CLODTexture *)matarray[pr1.material.Texture];
91
92 for(unsigned int lod=0; lod < 4; lod++)
93 {
94 if(tex->getSizeX(lod+1) <=4 || tex->getSizeY(lod+1) <= 4)
95 {
96 //TODO: blend modulation & replacement color
97 pr2.color[lod] = pr1.material.ReplacementColor;
98 }
99 else
100 {
101 pr2.texture[lod] = tex->getTextureID(lod+1);
102 }
103 }
104
105 }
106
107 //Animation
108 pr2.animation.rotationEnabled = (pr1.animation.AnimationFlags & 0x1) != 0;
109 pr2.animation.rotationOrigin = pr1.animation.rotationOrigin;
110 pr2.animation.rotationVelocity = pr1.animation.rotationVelocity;
111
112 //For water animation:
113 if(waterTesselation != 0 && (pr1.material.LODs & 16) != 0 && (pr1.material.LODs & 32) != 0)
114 {
115 m_WaterLevel = pr1.vertex[0].pos.y;
116 tesselateSquare(pr1, waterTesselation);
117 }
118
119 //add vertices
120 pr2.numVertices = pr1.vertex.size();
121 pr2.originalPos.resize(pr2.numVertices);
122 pr2.originalNor.resize(pr2.numVertices);
123 GLfloat *vertexptr = new GLfloat[8*pr1.vertex.size()];
124 for(unsigned int v=0; v < pr1.vertex.size(); v++)
125 {
126 CGLBFile::SVertex &vt = pr1.vertex[v];
127
128 pr2.originalPos[v] = vt.pos;
129 pr2.originalNor[v] = vt.nor;
130
131 GLfloat *offset = vertexptr + 8*v;
132
133 //GL_T2F_N3F_V3F array format:
134 *(offset ) = vt.tex.x;
135 *(offset+1) = vt.tex.y;
136
137 *(offset+2) = vt.nor.x;
138 *(offset+3) = vt.nor.y;
139 *(offset+4) = vt.nor.z;
140
141 *(offset+5) = vt.pos.x;
142 *(offset+6) = vt.pos.y;
143 *(offset+7) = vt.pos.z;
144 }
145 pr2.vertex = vertexptr;
146
147 //add indices
148 pr2.numIndices = pr1.index.size();
149 GLuint *indexptr = new GLuint[pr1.index.size()];
150 for(unsigned int i=0; i < pr1.index.size(); i++)
151 *(indexptr + i) = pr1.index[i];
152 pr2.index = indexptr;
153 }
154
155 return true;
156 }
157
unload()158 void CGraphObj::unload()
159 {
160 if(!isLoaded()) return;
161
162 CDataObject::unload();
163
164 //primitives:
165 for(unsigned int i=0; i < m_Primitives.size(); i++)
166 unloadPrimitive(m_Primitives[i]);
167 m_Primitives.clear();
168 }
169
unloadPrimitive(SPrimitive & pr)170 void CGraphObj::unloadPrimitive(SPrimitive &pr)
171 {
172 delete [] (GLfloat *)pr.vertex;
173 delete [] (GLuint *)pr.index;
174 }
175
176 //some flags for optimalisation:
177 bool tex_enabled;
178 bool use_blending;
179
draw(const SGraphicSettings * settings,CReflection * reflection,unsigned int lod,float t,bool useMaterials)180 void CGraphObj::draw(
181 const SGraphicSettings *settings, CReflection *reflection,
182 unsigned int lod, float t, bool useMaterials)
183 {
184 m_CurrentSettings = settings;
185 m_CurrentReflection = reflection;
186 m_CurrentLOD = lod;
187 m_UseMaterials = useMaterials;
188
189 if(settings->m_EnableAnimation && fabsf(t - m_CurrentTime) > 0.01)
190 {
191 m_CurrentTime = t;
192 animate(t);
193 }
194
195 //TODO: make this code very fast (it's the main drawing routine)
196
197 use_blending = (m_CurrentSettings->m_Transparency == SGraphicSettings::blend);
198 tex_enabled = true;
199
200 for(unsigned int p=0; p < m_Primitives.size(); p++)
201 {
202 const SPrimitive &pr = m_Primitives[p];
203
204 //LOD testing:
205 if(lod == 4 && (pr.LODs & 8) == 0) continue;
206 if(lod == 3 && (pr.LODs & 4) == 0) continue;
207 if(lod == 2 && (pr.LODs & 2) == 0) continue;
208 if(lod == 1 && (pr.LODs & 1) == 0) continue;
209
210 drawPrimitive(pr);
211 }
212
213 if(!tex_enabled)
214 glEnable(GL_TEXTURE_2D);
215
216 if(!use_blending && m_CurrentSettings->m_Transparency == SGraphicSettings::blend)
217 glEnable(GL_BLEND);
218 }
219
220
drawPrimitive(const SPrimitive & pr)221 void CGraphObj::drawPrimitive(const SPrimitive &pr)
222 {
223 CGLExtensions ext;
224
225 glInterleavedArrays(GL_T2F_N3F_V3F, 0, pr.vertex);
226
227 if(ext.hasCompiledVertexArray) //TODO: check if locking is a good idea
228 ext.glLockArrays(0, pr.numVertices);
229
230 //normal model
231 if(setMaterial(pr, false))
232 glDrawElements(GL_TRIANGLES, pr.numIndices, GL_UNSIGNED_INT, pr.index);
233
234 //reflection
235 if(m_CurrentReflection != NULL && setMaterial(pr, true))
236 {
237 m_CurrentReflection->enable(m_CurrentSettings);
238 glDrawElements(GL_TRIANGLES, pr.numIndices, GL_UNSIGNED_INT, pr.index);
239 m_CurrentReflection->disable();
240 tex_enabled = true;
241 }
242
243 if(ext.hasCompiledVertexArray) //TODO: check if locking is a good idea
244 ext.glUnlockArrays();
245 }
246
setMaterial(const SPrimitive & pr,bool forReflection)247 bool CGraphObj::setMaterial(const SPrimitive &pr, bool forReflection)
248 {
249 //color and alpha
250 float kleur[] = {1,1,1,0};
251
252 if(forReflection)
253 {
254 kleur[3] = pr.reflectance;
255 }
256 else
257 {
258 if(!m_UseMaterials) return true; //don't set the material
259
260 //Shininess:
261 float speccol[] = {pr.reflectance, pr.reflectance, pr.reflectance, 0.0};
262 //float speccol[] = {1,1,1, 0.0};
263 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, speccol);
264
265 //Color:
266 kleur[0] = pr.color[m_CurrentLOD-1].x;
267 kleur[1] = pr.color[m_CurrentLOD-1].y;
268 kleur[2] = pr.color[m_CurrentLOD-1].z;
269 kleur[3] = pr.opacity;
270
271 //texture
272 if(pr.texture[m_CurrentLOD-1] == 0)
273 {
274 if(tex_enabled)
275 {
276 glDisable(GL_TEXTURE_2D);
277 tex_enabled = false;
278 }
279 }
280 else
281 {
282 if(!tex_enabled)
283 {
284 glEnable(GL_TEXTURE_2D);
285 tex_enabled = true;
286 }
287 glBindTexture(GL_TEXTURE_2D, pr.texture[m_CurrentLOD-1]);
288 }
289 }
290
291 //blending:
292 if(kleur[3] < 0.1) return false; //don't draw this primitive
293 if(m_CurrentSettings->m_Transparency == SGraphicSettings::blend)
294 {
295 if(use_blending)
296 {
297 if(pr.reflectance > 0.9)
298 {
299 use_blending = false;
300 glDisable(GL_BLEND);
301 }
302 }
303 else
304 {
305 if(pr.reflectance <= 0.9)
306 {
307 use_blending = true;
308 glEnable(GL_BLEND);
309 }
310 }
311 }
312
313 //setting the material
314 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kleur);
315
316 return true;
317 }
318
animate(float t)319 void CGraphObj::animate(float t)
320 {
321 for(unsigned int p=0; p < m_Primitives.size(); p++)
322 {
323 SPrimitive &pr = m_Primitives[p];
324
325 if((pr.LODs & 16) != 0 && (pr.LODs & 32) != 0)
326 animateWater(pr, t);
327
328 if(pr.animation.rotationEnabled)
329 animateRotation(pr, t);
330 }
331 }
332
animateWater(SPrimitive & pr,float t)333 void CGraphObj::animateWater(SPrimitive &pr, float t)
334 {
335 for(unsigned int v=0; v < pr.numVertices; v++)
336 {
337 GLfloat *offset = (GLfloat *)pr.vertex + 8*v;
338
339 //GL_T2F_N3F_V3F array format:
340 /*
341 *(offset ) = vt.tex.x;
342 *(offset+1) = vt.tex.y;
343
344 *(offset+2) = vt.nor.x;
345 *(offset+3) = vt.nor.y;
346 *(offset+4) = vt.nor.z;
347
348 *(offset+5) = vt.pos.x;
349 *(offset+6) = vt.pos.y;
350 *(offset+7) = vt.pos.z;
351 */
352 float x = *(offset+5);
353 float z = *(offset+7);
354 float wave = 0.4 * (
355 sin(( x+z)*2*M_PI/TILESIZE + 2.0*t) +
356 sin(( x-z)*2*M_PI/TILESIZE + 2.0*t) +
357 sin((-x+z)*2*M_PI/TILESIZE + 2.0*t) +
358 sin((-x-z)*2*M_PI/TILESIZE + 2.0*t)
359 )
360 + 0.25 * (
361 sin(( 2*x+z)*2*M_PI/TILESIZE + 5.11*t) +
362 sin(( x-2*z)*2*M_PI/TILESIZE + 5.11*t) +
363 sin((-x+2*z)*2*M_PI/TILESIZE + 5.11*t) +
364 sin((-2*x-z)*2*M_PI/TILESIZE + 5.11*t)
365 );
366 *(offset+6) = m_WaterLevel + wave;
367 }
368
369 //printf("Animate water\n");
370 }
371
animateRotation(SPrimitive & pr,float t)372 void CGraphObj::animateRotation(SPrimitive &pr, float t)
373 {
374 CVector origin = pr.animation.rotationOrigin;
375 CVector velocity = pr.animation.rotationVelocity;
376
377 CMatrix rmat; rmat.setRotation(velocity * t);
378
379 CVector pos, nor;
380
381 for(unsigned int v=0; v < pr.numVertices; v++)
382 {
383 pos = pr.originalPos[v];
384 nor = pr.originalNor[v];
385
386 pos -= origin;
387
388 pos *= rmat;
389 nor *= rmat;
390
391 pos += origin;
392
393 GLfloat *offset = (GLfloat *)pr.vertex + 8*v;
394
395 //GL_T2F_N3F_V3F array format:
396 /*
397 *(offset ) = vt.tex.x;
398 *(offset+1) = vt.tex.y;
399
400 *(offset+2) = vt.nor.x;
401 *(offset+3) = vt.nor.y;
402 *(offset+4) = vt.nor.z;
403
404 *(offset+5) = vt.pos.x;
405 *(offset+6) = vt.pos.y;
406 *(offset+7) = vt.pos.z;
407 */
408
409 *(offset+2) = nor.x;
410 *(offset+3) = nor.y;
411 *(offset+4) = nor.z;
412
413 *(offset+5) = pos.x;
414 *(offset+6) = pos.y;
415 *(offset+7) = pos.z;
416 }
417 }
418
419