Added Horde3D terrain (still untextured).
[openstranded.git] / src / eal / horde3d / extensions / island.cc
blob5c8c287f0749cf5c36be822738e39ff951813e17
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 Vec3f localCamPos( curCam->getAbsTrans().x[12], curCam->getAbsTrans().x[13], curCam->getAbsTrans().x[14] );
90 localCamPos = island->_absTrans.inverted() * localCamPos;
91 // Draw terrain
92 // TODO
93 for (int i = 0; i < TILE_COUNT; i++)
95 if (island->terrainpatches[i] != 0)
97 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, island->indexBuffer[0]);
98 glBindBuffer(GL_ARRAY_BUFFER, island->terrainpatches[i]);
99 glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, (char*)0);
100 glNormalPointer(GL_FLOAT, sizeof(float) * 3,
101 (char*)((TILE_SIZE + 1) * (TILE_SIZE + 1) * sizeof(float) * 3));
102 glEnableClientState(GL_VERTEX_ARRAY);
103 glEnableClientState(GL_NORMAL_ARRAY);
105 // World transformation
106 ShaderCombination *curShader = Modules::renderer().getCurShader();
107 if (curShader->uni_worldMat >= 0)
109 glUniformMatrix4fv(curShader->uni_worldMat, 1, false, &island->_absTrans.x[0]);
111 if (curShader->uni_worldNormalMat >= 0)
113 Matrix4f normalMat4 = island->_absTrans.inverted().transposed();
114 float normalMat[9] = { normalMat4.x[0], normalMat4.x[1], normalMat4.x[2],
115 normalMat4.x[4], normalMat4.x[5], normalMat4.x[6],
116 normalMat4.x[8], normalMat4.x[9], normalMat4.x[10] };
117 glUniformMatrix3fv(curShader->uni_worldNormalMat, 1, false, normalMat );
120 glDrawElements(GL_TRIANGLES, TILE_SIZE * TILE_SIZE * 6, GL_UNSIGNED_SHORT, (char *)0);
121 Modules::renderer().incStat(EngineStats::BatchCount, 1);
122 Modules::renderer().incStat(EngineStats::TriCount, TILE_SIZE * TILE_SIZE * 2);
124 glDisableClientState(GL_VERTEX_ARRAY);
125 glDisableClientState(GL_NORMAL_ARRAY);
131 bool IslandNode::canAttach(SceneNode &parent)
133 return true;
135 int IslandNode::getParami(int param)
137 switch( param )
139 case IslandNodeParams::MaterialRes:
140 if( materialRes != 0x0 ) return materialRes->getHandle();
141 else return 0;
142 case IslandNodeParams::SizeX:
143 return sizeX;
144 case IslandNodeParams::SizeZ:
145 return sizeZ;
146 default:
147 return SceneNode::getParami( param );
150 bool IslandNode::setParami(int param, int value)
152 Resource *res;
153 switch( param )
155 case IslandNodeParams::MaterialRes:
156 res = Modules::resMan().resolveResHandle( value );
157 if (res == 0x0 || res->getType() != ResourceTypes::Material)
159 Modules::log().writeDebugInfo( "Invalid Material resource for Island node %i", _handle );
160 return false;
162 materialRes = (MaterialResource*)res;
163 return true;
164 case IslandNodeParams::SizeX:
165 if ((value <= 0) || (value > 512))
167 Modules::log().writeDebugInfo( "Invalid size for Terrain node %i (must be 2^x + 1)", _handle );
168 return false;
171 if (sizeX == value)
172 return true;
174 sizeX = value;
175 // TODO: Recreate terrain
176 return true;
177 case IslandNodeParams::SizeZ:
178 if ((value <= 0) || (value > 512))
180 Modules::log().writeDebugInfo( "Invalid size for Terrain node %i (must be 2^x + 1)", _handle );
181 return false;
184 if (sizeZ == value)
185 return true;
187 sizeZ = value;
188 // TODO: Recreate terrain
189 return true;
190 default:
191 return SceneNode::setParami(param, value);
194 float IslandNode::getParamf(int param)
196 switch (param)
198 case IslandNodeParams::MeshQuality:
199 return meshQuality;
200 default:
201 return SceneNode::getParamf(param);
204 bool IslandNode::setParamf(int param, float value)
206 switch (param)
208 case IslandNodeParams::MeshQuality:
209 meshQuality = value;
210 return true;
211 default:
212 return SceneNode::setParamf(param, value);
216 IslandNode::IslandNode(const IslandNodeTpl &islandTpl) : SceneNode(islandTpl),
217 materialRes(islandTpl.matRes), sizeX(islandTpl.sizeX), sizeZ(islandTpl.sizeZ),
218 meshQuality(islandTpl.meshQuality), heightdata(islandTpl.heightdata)
220 _renderable = true;
221 localBBox.getMinCoords() = Vec3f(-1000, 0, -1000);
222 localBBox.getMaxCoords() = Vec3f(1000, 1, 1000);
223 for (int i = 0; i < TILE_COUNT; i++)
225 terrainpatches[i] = 0;
226 vertexdata[i] = 0;
228 heightdata = new float[(sizeX + 1) * (sizeZ + 1)];
229 for (int i = 0; i < (sizeX + 1) * (sizeZ + 1); i++)
231 heightdata[i] = 0.5;
233 // Create index buffers
234 createIndexBuffers();
235 // Create terrain patches
236 createVertexBuffers();
237 // Create extension plane around the terrain
238 createExtension();
239 // Set height data
240 updateVertices(0, 0, sizeX + 1, sizeZ + 1);
243 void IslandNode::createIndexBuffers()
245 int size = TILE_SIZE;
246 for (int i = 0; i < 5; i++)
248 int factor = TILE_SIZE / size;
249 // Create buffer
250 unsigned short *indices = new unsigned short[size * size * 6];
251 // Surface
252 for (int z = 0; z < size; z++)
254 for (int x = 0; x < size; x++)
256 indices[(z * size + x) * 6 + 0] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + 0;
257 indices[(z * size + x) * 6 + 2] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor;
258 indices[(z * size + x) * 6 + 1] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0;
259 indices[(z * size + x) * 6 + 3] = (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor;
260 indices[(z * size + x) * 6 + 5] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + factor;
261 indices[(z * size + x) * 6 + 4] = (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0;
264 // TODO: Skirts
265 indexBuffer[i] = Modules::renderer().uploadIndices(indices, size * size * 6 * sizeof(short));
266 delete[] indices;
270 void IslandNode::createVertexBuffers()
272 int alignedx = ((sizeX - 1) + TILE_SIZE) & ~(TILE_SIZE - 1);
273 int alignedz = ((sizeZ - 1) + TILE_SIZE) & ~(TILE_SIZE - 1);
274 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
275 // Create flat vertex buffers
276 for (int z = 0; z < alignedz / TILE_SIZE; z++)
278 for (int x = 0; x < alignedx / TILE_SIZE; x++)
280 // Create and fill vertex buffer
281 vertexdata[x + z * EDGE_TILES] = new float[size * 2];
282 for (int z2 = 0; z2 < TILE_SIZE + 1; z2++)
284 for (int x2 = 0; x2 < TILE_SIZE + 1; x2++)
286 float *vertex = &vertexdata[x + z * EDGE_TILES][(z2 * (TILE_SIZE + 1) + x2) * 3];
287 vertex[0] = x * TILE_SIZE + x2;
288 vertex[1] = 0;
289 vertex[2] = z * TILE_SIZE + z2;
292 // Normals
293 for (int z2 = 0; z2 < TILE_SIZE + 1; z2++)
295 for (int x2 = 0; x2 < TILE_SIZE + 1; x2++)
297 float *vertex = &vertexdata[x + z * EDGE_TILES][(z2 * (TILE_SIZE + 1) + x2) * 3 + size];
298 vertex[0] = 0;
299 vertex[1] = 1;
300 vertex[2] = 0;
303 // TODO: skirts
304 // Create mesh
305 terrainpatches[x + z * EDGE_TILES] = Modules::renderer().uploadVertices(vertexdata[x + z * EDGE_TILES],
306 size * sizeof(float) * 2);
310 float IslandNode::getHeight(int x, int z)
312 if (x < 0) x = 0;
313 if (z < 0) z = 0;
314 if (x > sizeX) x = sizeX;
315 if (z > sizeZ) z = sizeZ;
317 return heightdata[z * (sizeX + 1) + x];
319 void IslandNode::updateVertices(int x, int y, int width, int height)
321 int tilesx = sizeX / TILE_SIZE;
322 int tilesz = sizeZ / TILE_SIZE;
323 // Set vertex data
324 // TODO: Optimize this
325 for (int iz = 0; iz < height; iz++)
327 int tilez = (iz + y) / TILE_SIZE;
328 int offsetz = (iz + y) % TILE_SIZE;
329 if (tilez == tilesz)
331 tilez--;
332 offsetz = TILE_SIZE;
334 for (int ix = 0; ix < width; ix ++)
336 int tilex = (ix + x) / TILE_SIZE;
337 int offsetx = (ix + x) % TILE_SIZE;
338 if (tilex == tilesx)
340 tilex--;
341 offsetx = TILE_SIZE;
343 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
344 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
345 if ((offsetx == 0) && (tilex > 0))
347 tilex--;
348 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)];
353 if ((offsetz == 0) && (tilez > 0))
355 tilez--;
356 offsetz = TILE_SIZE;
357 for (int ix = 0; ix < width; ix ++)
359 int tilex = (ix + x) / TILE_SIZE;
360 int offsetx = (ix + x) % TILE_SIZE;
361 if (tilex == tilesx)
363 tilex--;
364 offsetx = TILE_SIZE;
366 float *vertex = &vertexdata[tilex + tilez * EDGE_TILES][(offsetz * (TILE_SIZE + 1) + offsetx) * 3];
367 vertex[1] = heightdata[(iz + y) * (sizeX + 1) + (ix + x)];
368 if ((offsetx == 0) && (tilex > 0))
370 tilex--;
371 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)];
378 // Compute normals
379 for (int iz = 0; iz < height; iz++)
381 for (int ix = 0; ix < width; ix ++)
383 float h1 = getHeight(x + ix - 1, y + iz);
384 float h2 = getHeight(x + ix + 1, y + iz);
385 float h3 = getHeight(x + ix, y + iz - 1);
386 float h4 = getHeight(x + ix, y + iz + 1);
387 Vec3f v1(2.0f, h2 - h1, 0.0f);
388 Vec3f v2(0.0f, h4 - h3, 2.0f);
389 Vec3f normal = v1.cross(v2);
392 // Refresh vertex buffers
393 int size = (TILE_SIZE + 1) * (TILE_SIZE + 1) * 3;
394 for (int iz = y / TILE_SIZE; iz <= (y + height) / TILE_SIZE; iz++)
396 for (int ix = x / TILE_SIZE; ix <= (x + width) / TILE_SIZE; ix++)
398 printf("Updating.\n");
399 Modules::renderer().updateVertices(vertexdata[ix + iz * EDGE_TILES],
400 0, size * sizeof(float), terrainpatches[ix + iz * EDGE_TILES]);
405 void IslandNode::createExtension()
410 float *IslandNode::getHeightData()
412 return heightdata;