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