Implemented Horde3D terrain textures.
[openstranded.git] / src / eal / horde3d / extensions / island.cc
blob0a19483ebec6303e0e5b010a06ce8b857e6524b5
1 /*
2 * Island scene node for Horde3D
4 * Copyright (C) 2009 Mathias Gottschlag, Nicolas Schulz, Volker Wiendl
6 * This file is part of OpenStranded
8 * OpenStranded is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * OpenStranded is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with OpenStranded. If not, see <http://www.gnu.org/licenses/>.
22 #include "eal/horde3d/extensions/island.hh"
23 #include "egModules.h"
24 #include "egMaterial.h"
25 #include "utOpenGL.h"
27 namespace eal
29 namespace horde3d
31 const char *vsIslandDebugView =
32 "uniform mat4 worldMat;\n"
33 "varying vec4 color;\n"
34 "void main() {\n"
35 " color = gl_Color;\n"
36 " gl_Position = gl_ModelViewProjectionMatrix * worldMat * gl_Vertex;\n"
37 "}";
39 const char *fsIslandDebugView =
40 "varying vec4 color;\n"
41 "void main() {\n"
42 " gl_FragColor = color;\n"
43 "}\n";
45 ShaderCombination IslandNode::debugViewShader;
47 IslandNode::~IslandNode()
51 SceneNodeTpl *IslandNode::parsingFunc(std::map< std::string, std::string > &attribs)
53 // TODO
55 SceneNode *IslandNode::factoryFunc(const SceneNodeTpl &nodeTpl)
57 if( nodeTpl.type != SNT_IslandNode ) return 0x0;
59 return new IslandNode( *(IslandNodeTpl *)&nodeTpl );
61 void IslandNode::renderFunc(const std::string &shaderContext, const std::string &theClass, bool debugView,
62 const Frustum *frust1, const Frustum *frust2, RenderingOrder::List order, int occSet)
64 CameraNode *curCam = Modules::renderer().getCurCamera();
65 if( curCam == 0x0 ) return;
67 Modules::renderer().setMaterial( 0x0, "" );
69 // Loop through island queue
70 for( uint32 i = 0, s = (uint32)Modules::sceneMan().getRenderableQueue().size(); i < s; ++i )
72 if( Modules::sceneMan().getRenderableQueue()[i].type != SNT_IslandNode )
74 continue;
77 IslandNode *island = (IslandNode*)Modules::sceneMan().getRenderableQueue()[i].node;
79 if (!debugView)
81 if (!island->materialRes->isOfClass(theClass)) continue;
82 if (!Modules::renderer().setMaterial(island->materialRes, shaderContext)) continue;
84 else
86 Modules::renderer().setShader(&debugViewShader);
89 int terrainSize = glGetUniformLocation( Modules::renderer().getCurShader()->shaderObject, "terrainSize" );
91 Vec3f localCamPos( curCam->getAbsTrans().x[12], curCam->getAbsTrans().x[13], curCam->getAbsTrans().x[14] );
92 localCamPos = island->_absTrans.inverted() * localCamPos;
93 // Draw terrain
94 // TODO
95 for (int i = 0; i < TILE_COUNT; i++)
97 if (island->terrainpatches[i] != 0)
99 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, island->indexBuffer[0]);
100 glBindBuffer(GL_ARRAY_BUFFER, island->terrainpatches[i]);
101 glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, (char*)0);
102 glNormalPointer(GL_FLOAT, sizeof(float) * 3,
103 (char*)((TILE_SIZE + 1) * (TILE_SIZE + 1) * sizeof(float) * 3));
104 glEnableClientState(GL_VERTEX_ARRAY);
105 glEnableClientState(GL_NORMAL_ARRAY);
107 // World transformation
108 ShaderCombination *curShader = Modules::renderer().getCurShader();
109 if (curShader->uni_worldMat >= 0)
111 glUniformMatrix4fv(curShader->uni_worldMat, 1, false, &island->_absTrans.x[0]);
113 if (curShader->uni_worldNormalMat >= 0)
115 Matrix4f normalMat4 = island->_absTrans.inverted().transposed();
116 float normalMat[9] = { normalMat4.x[0], normalMat4.x[1], normalMat4.x[2],
117 normalMat4.x[4], normalMat4.x[5], normalMat4.x[6],
118 normalMat4.x[8], normalMat4.x[9], normalMat4.x[10] };
119 glUniformMatrix3fv(curShader->uni_worldNormalMat, 1, false, normalMat );
122 if( terrainSize >= 0 )
123 glUniform4f( terrainSize, island->sizeX, island->sizeZ, 0, 0 );
125 glDrawElements(GL_TRIANGLES, TILE_SIZE * TILE_SIZE * 6, GL_UNSIGNED_SHORT, (char *)0);
126 Modules::renderer().incStat(EngineStats::BatchCount, 1);
127 Modules::renderer().incStat(EngineStats::TriCount, TILE_SIZE * TILE_SIZE * 2);
129 glDisableClientState(GL_VERTEX_ARRAY);
130 glDisableClientState(GL_NORMAL_ARRAY);
136 bool IslandNode::canAttach(SceneNode &parent)
138 return true;
140 int IslandNode::getParami(int param)
142 switch( param )
144 case IslandNodeParams::MaterialRes:
145 if( materialRes != 0x0 ) return materialRes->getHandle();
146 else return 0;
147 case IslandNodeParams::SizeX:
148 return sizeX;
149 case IslandNodeParams::SizeZ:
150 return sizeZ;
151 default:
152 return SceneNode::getParami( param );
155 bool IslandNode::setParami(int param, int value)
157 Resource *res;
158 switch( param )
160 case IslandNodeParams::MaterialRes:
161 res = Modules::resMan().resolveResHandle( value );
162 if (res == 0x0 || res->getType() != ResourceTypes::Material)
164 Modules::log().writeDebugInfo( "Invalid Material resource for Island node %i", _handle );
165 return false;
167 materialRes = (MaterialResource*)res;
168 return true;
169 case IslandNodeParams::SizeX:
170 if ((value <= 0) || (value > 512))
172 Modules::log().writeDebugInfo( "Invalid size for Terrain node %i (must be 2^x + 1)", _handle );
173 return false;
176 if (sizeX == value)
177 return true;
179 sizeX = value;
180 // TODO: Recreate terrain
181 return true;
182 case IslandNodeParams::SizeZ:
183 if ((value <= 0) || (value > 512))
185 Modules::log().writeDebugInfo( "Invalid size for Terrain node %i (must be 2^x + 1)", _handle );
186 return false;
189 if (sizeZ == value)
190 return true;
192 sizeZ = value;
193 // TODO: Recreate terrain
194 return true;
195 default:
196 return SceneNode::setParami(param, value);
199 float IslandNode::getParamf(int param)
201 switch (param)
203 case IslandNodeParams::MeshQuality:
204 return meshQuality;
205 default:
206 return SceneNode::getParamf(param);
209 bool IslandNode::setParamf(int param, float value)
211 switch (param)
213 case IslandNodeParams::MeshQuality:
214 meshQuality = value;
215 return true;
216 default:
217 return SceneNode::setParamf(param, value);
221 IslandNode::IslandNode(const IslandNodeTpl &islandTpl) : SceneNode(islandTpl),
222 materialRes(islandTpl.matRes), sizeX(islandTpl.sizeX), sizeZ(islandTpl.sizeZ),
223 meshQuality(islandTpl.meshQuality), heightdata(islandTpl.heightdata)
225 _renderable = true;
226 localBBox.getMinCoords() = Vec3f(-1000, -1000, -1000);
227 localBBox.getMaxCoords() = Vec3f(1000, 1000, 1000);
228 for (int i = 0; i < TILE_COUNT; i++)
230 terrainpatches[i] = 0;
231 vertexdata[i] = 0;
233 heightdata = new float[(sizeX + 1) * (sizeZ + 1)];
234 for (int i = 0; i < (sizeX + 1) * (sizeZ + 1); i++)
236 heightdata[i] = 0.5;
238 // Create index buffers
239 createIndexBuffers();
240 // Create terrain patches
241 createVertexBuffers();
242 // Create extension plane around the terrain
243 createExtension();
244 // Set height data
245 updateVertices(0, 0, sizeX + 1, sizeZ + 1);
248 void IslandNode::createIndexBuffers()
250 int size = TILE_SIZE;
251 for (int i = 0; i < 5; i++)
253 int factor = TILE_SIZE / size;
254 // Create buffer
255 unsigned short *indices = new unsigned short[size * size * 6];
256 // Surface
257 for (int z = 0; z < size; z++)
259 for (int x = 0; x < size; x++)
261 indices[(z * size + x) * 6 + 0] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + 0;
262 indices[(z * size + x) * 6 + 2] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor;
263 indices[(z * size + x) * 6 + 1] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0;
264 indices[(z * size + x) * 6 + 3] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor;
265 indices[(z * size + x) * 6 + 5] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + factor;
266 indices[(z * size + x) * 6 + 4] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0;
269 // TODO: Skirts
270 indexBuffer[i] = Modules::renderer().uploadIndices(indices, size * size * 6 * sizeof(short));
271 delete[] indices;
275 void IslandNode::createVertexBuffers()
277 int alignedx = ((sizeX - 1) + TILE_SIZE) & ~(TILE_SIZE - 1);
278 int alignedz = ((sizeZ - 1) + TILE_SIZE) & ~(TILE_SIZE - 1);
279 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
280 // Create flat vertex buffers
281 for (int z = 0; z < alignedz / TILE_SIZE; z++)
283 for (int x = 0; x < alignedx / TILE_SIZE; x++)
285 // Create and fill vertex buffer
286 vertexdata[x + z * EDGE_TILES] = new float[size * 2];
287 for (int z2 = 0; z2 < TILE_SIZE + 1; z2++)
289 for (int x2 = 0; x2 < TILE_SIZE + 1; x2++)
291 float *vertex = &vertexdata[x + z * EDGE_TILES][(z2 * (TILE_SIZE + 1) + x2) * 3];
292 vertex[0] = x * TILE_SIZE + x2;
293 vertex[1] = 0;
294 vertex[2] = z * TILE_SIZE + z2;
297 // Normals
298 for (int z2 = 0; z2 < TILE_SIZE + 1; z2++)
300 for (int x2 = 0; x2 < TILE_SIZE + 1; x2++)
302 float *vertex = &vertexdata[x + z * EDGE_TILES][(z2 * (TILE_SIZE + 1) + x2) * 3 + size];
303 vertex[0] = 0;
304 vertex[1] = 1;
305 vertex[2] = 0;
308 // TODO: skirts
309 // Create mesh
310 terrainpatches[x + z * EDGE_TILES] = Modules::renderer().uploadVertices(vertexdata[x + z * EDGE_TILES],
311 size * sizeof(float) * 2);
315 float IslandNode::getHeight(int x, int z)
317 if (x < 0) x = 0;
318 if (z < 0) z = 0;
319 if (x > sizeX) x = sizeX;
320 if (z > sizeZ) z = sizeZ;
322 return heightdata[z * (sizeX + 1) + x];
324 void IslandNode::updateVertices(int x, int y, int width, int height)
326 int tilesx = sizeX / TILE_SIZE;
327 int tilesz = sizeZ / TILE_SIZE;
328 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
329 // Set vertex data
330 // TODO: Optimize this
331 /*for (int iz = 0; iz < height; iz++)
333 int tilez = (iz + y) / TILE_SIZE;
334 int offsetz = (iz + y) % TILE_SIZE;
335 if (tilez == tilesz)
337 tilez--;
338 offsetz = TILE_SIZE;
340 for (int ix = 0; ix < width; ix ++)
342 int tilex = (ix + x) / TILE_SIZE;
343 int offsetx = (ix + x) % TILE_SIZE;
344 if (tilex == tilesx)
346 tilex--;
347 offsetx = TILE_SIZE;
349 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
350 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
351 if ((offsetx == 0) && (tilex > 0))
353 tilex--;
354 offsetx = TILE_SIZE;
355 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
356 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
359 if ((offsetz == 0) && (tilez > 0))
361 tilez--;
362 offsetz = TILE_SIZE;
363 for (int ix = 0; ix < width; ix ++)
365 int tilex = (ix + x) / TILE_SIZE;
366 int offsetx = (ix + x) % TILE_SIZE;
367 if (tilex == tilesx)
369 tilex--;
370 offsetx = TILE_SIZE;
372 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
373 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
374 if ((offsetx == 0) && (tilex > 0))
376 tilex--;
377 offsetx = TILE_SIZE;
378 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
379 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
384 for (int iz = 0; iz < height; iz++)
386 for (int ix = 0; ix < width; ix ++)
388 setHeight(x + ix, y + iz, heightdata[(iz + y) * (sizeX + 1) + (ix + x)]);
391 // Compute normals
392 for (int iz = 0; iz < height; iz++)
394 int tilez = (iz + y) / TILE_SIZE;
395 int offsetz = (iz + y) % TILE_SIZE;
396 if (tilez == tilesz)
398 tilez--;
399 offsetz = TILE_SIZE;
401 for (int ix = 0; ix < width; ix ++)
403 int tilex = (ix + x) / TILE_SIZE;
404 int offsetx = (ix + x) % TILE_SIZE;
405 if (tilex == tilesx)
407 tilex--;
408 offsetx = TILE_SIZE;
410 float h1 = getHeight(x + ix - 1, y + iz);
411 float h2 = getHeight(x + ix + 1, y + iz);
412 float h3 = getHeight(x + ix, y + iz - 1);
413 float h4 = getHeight(x + ix, y + iz + 1);
414 Vec3f v1(2.0f, h2 - h1, 0.0f);
415 Vec3f v2(0.0f, h4 - h3, 2.0f);
416 Vec3f normal = v2.cross(v1).normalized();
417 /*float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3 + size];
418 vertex[0] = normal.x;
419 vertex[1] = normal.y;
420 vertex[2] = normal.z;*/
421 updateNormal(x + ix, y + iz);
424 // Refresh vertex buffers
425 for (int iz = y / TILE_SIZE; iz <= (y + height) / TILE_SIZE; iz++)
427 for (int ix = x / TILE_SIZE; ix <= (x + width) / TILE_SIZE; ix++)
429 Modules::renderer().updateVertices(vertexdata[ix + iz * EDGE_TILES],
430 0, size * sizeof(float) * 2, terrainpatches[ix + iz * EDGE_TILES]);
435 void IslandNode::createExtension()
440 float *IslandNode::getHeightData()
442 return heightdata;
445 void IslandNode::setHeight(int x, int z, float height)
447 int tilesx = sizeX / TILE_SIZE;
448 int tilesz = sizeZ / TILE_SIZE;
449 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
450 // Set vertex data
451 // TODO: Optimize this
452 int tilez = z / TILE_SIZE;
453 int offsetz = z % TILE_SIZE;
454 if (tilez == tilesz)
456 tilez--;
457 offsetz = TILE_SIZE;
460 int tilex = x / TILE_SIZE;
461 int offsetx = x % TILE_SIZE;
462 if (tilex == tilesx)
464 tilex--;
465 offsetx = TILE_SIZE;
467 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
468 vertex[1] = height;
469 if ((offsetx == 0) && (tilex > 0))
471 tilex--;
472 offsetx = TILE_SIZE;
473 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
474 vertex[1] = height;
477 if ((offsetz == 0) && (tilez > 0))
479 tilez--;
480 offsetz = TILE_SIZE;
482 int tilex = x / TILE_SIZE;
483 int offsetx = x % TILE_SIZE;
484 if (tilex == tilesx)
486 tilex--;
487 offsetx = TILE_SIZE;
489 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
490 vertex[1] = height;
491 if ((offsetx == 0) && (tilex > 0))
493 tilex--;
494 offsetx = TILE_SIZE;
495 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
496 vertex[1] = height;
501 void IslandNode::updateNormal(int x, int z)
503 // Compute normal
504 float h1 = getHeight(x - 1, z);
505 float h2 = getHeight(x + 1, z);
506 float h3 = getHeight(x, z - 1);
507 float h4 = getHeight(x, z + 1);
508 Vec3f v1(2.0f, h2 - h1, 0.0f);
509 Vec3f v2(0.0f, h4 - h3, 2.0f);
510 Vec3f normal = v2.cross(v1).normalized();
512 int tilesx = sizeX / TILE_SIZE;
513 int tilesz = sizeZ / TILE_SIZE;
514 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
515 // Set vertex data
516 // TODO: Optimize this
517 int tilez = z / TILE_SIZE;
518 int offsetz = z % TILE_SIZE;
519 if (tilez == tilesz)
521 tilez--;
522 offsetz = TILE_SIZE;
525 int tilex = x / TILE_SIZE;
526 int offsetx = x % TILE_SIZE;
527 if (tilex == tilesx)
529 tilex--;
530 offsetx = TILE_SIZE;
532 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3 + size];
533 vertex[0] = normal.x;
534 vertex[1] = normal.y;
535 vertex[2] = normal.z;
536 if ((offsetx == 0) && (tilex > 0))
538 tilex--;
539 offsetx = TILE_SIZE;
540 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3 + size];
541 vertex[0] = normal.x;
542 vertex[1] = normal.y;
543 vertex[2] = normal.z;
546 if ((offsetz == 0) && (tilez > 0))
548 tilez--;
549 offsetz = TILE_SIZE;
551 int tilex = x / TILE_SIZE;
552 int offsetx = x % TILE_SIZE;
553 if (tilex == tilesx)
555 tilex--;
556 offsetx = TILE_SIZE;
558 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3 + size];
559 vertex[0] = normal.x;
560 vertex[1] = normal.y;
561 vertex[2] = normal.z;
562 if ((offsetx == 0) && (tilex > 0))
564 tilex--;
565 offsetx = TILE_SIZE;
566 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3 + size];
567 vertex[0] = normal.x;
568 vertex[1] = normal.y;
569 vertex[2] = normal.z;