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"
31 const char *vsIslandDebugView
=
32 "uniform mat4 worldMat;\n"
33 "varying vec4 color;\n"
35 " color = gl_Color;\n"
36 " gl_Position = gl_ModelViewProjectionMatrix * worldMat * gl_Vertex;\n"
39 const char *fsIslandDebugView
=
40 "varying vec4 color;\n"
42 " gl_FragColor = color;\n"
45 ShaderCombination
IslandNode::debugViewShader
;
47 IslandNode::~IslandNode()
51 SceneNodeTpl
*IslandNode::parsingFunc(std::map
< std::string
, std::string
> &attribs
)
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
)
77 IslandNode
*island
= (IslandNode
*)Modules::sceneMan().getRenderableQueue()[i
].node
;
81 if (!island
->materialRes
->isOfClass(theClass
)) continue;
82 if (!Modules::renderer().setMaterial(island
->materialRes
, shaderContext
)) continue;
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
;
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
)
140 int IslandNode::getParami(int param
)
144 case IslandNodeParams::MaterialRes
:
145 if( materialRes
!= 0x0 ) return materialRes
->getHandle();
147 case IslandNodeParams::SizeX
:
149 case IslandNodeParams::SizeZ
:
152 return SceneNode::getParami( param
);
155 bool IslandNode::setParami(int param
, int value
)
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
);
167 materialRes
= (MaterialResource
*)res
;
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
);
180 // TODO: Recreate terrain
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
);
193 // TODO: Recreate terrain
196 return SceneNode::setParami(param
, value
);
199 float IslandNode::getParamf(int param
)
203 case IslandNodeParams::MeshQuality
:
206 return SceneNode::getParamf(param
);
209 bool IslandNode::setParamf(int param
, float value
)
213 case IslandNodeParams::MeshQuality
:
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
)
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;
233 heightdata
= new float[(sizeX
+ 1) * (sizeZ
+ 1)];
234 for (int i
= 0; i
< (sizeX
+ 1) * (sizeZ
+ 1); i
++)
238 // Create index buffers
239 createIndexBuffers();
240 // Create terrain patches
241 createVertexBuffers();
242 // Create extension plane around the terrain
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
;
255 unsigned short *indices
= new unsigned short[size
* size
* 6];
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;
270 indexBuffer
[i
] = Modules::renderer().uploadIndices(indices
, size
* size
* 6 * sizeof(short));
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
;
294 vertex
[2] = z
* TILE_SIZE
+ z2
;
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
];
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
)
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;
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;
340 for (int ix = 0; ix < width; ix ++)
342 int tilex = (ix + x) / TILE_SIZE;
343 int offsetx = (ix + x) % 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))
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))
363 for (int ix = 0; ix < width; ix ++)
365 int tilex = (ix + x) / TILE_SIZE;
366 int offsetx = (ix + x) % 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))
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
)]);
392 for (int iz
= 0; iz
< height
; iz
++)
394 int tilez
= (iz
+ y
) / TILE_SIZE
;
395 int offsetz
= (iz
+ y
) % TILE_SIZE
;
401 for (int ix
= 0; ix
< width
; ix
++)
403 int tilex
= (ix
+ x
) / TILE_SIZE
;
404 int offsetx
= (ix
+ x
) % 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()
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;
451 // TODO: Optimize this
452 int tilez
= z
/ TILE_SIZE
;
453 int offsetz
= z
% TILE_SIZE
;
460 int tilex
= x
/ TILE_SIZE
;
461 int offsetx
= x
% TILE_SIZE
;
467 float *vertex
= &vertexdata
[tilex
+ tilez
* EDGE_TILES
][(offsetz
* (TILE_SIZE
+ 1) + offsetx
) * 3];
469 if ((offsetx
== 0) && (tilex
> 0))
473 float *vertex
= &vertexdata
[tilex
+ tilez
* EDGE_TILES
][(offsetz
* (TILE_SIZE
+ 1) + offsetx
) * 3];
477 if ((offsetz
== 0) && (tilez
> 0))
482 int tilex
= x
/ TILE_SIZE
;
483 int offsetx
= x
% TILE_SIZE
;
489 float *vertex
= &vertexdata
[tilex
+ tilez
* EDGE_TILES
][(offsetz
* (TILE_SIZE
+ 1) + offsetx
) * 3];
491 if ((offsetx
== 0) && (tilex
> 0))
495 float *vertex
= &vertexdata
[tilex
+ tilez
* EDGE_TILES
][(offsetz
* (TILE_SIZE
+ 1) + offsetx
) * 3];
501 void IslandNode::updateNormal(int x
, int z
)
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;
516 // TODO: Optimize this
517 int tilez
= z
/ TILE_SIZE
;
518 int offsetz
= z
% TILE_SIZE
;
525 int tilex
= x
/ TILE_SIZE
;
526 int offsetx
= x
% 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))
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))
551 int tilex
= x
/ TILE_SIZE
;
552 int offsetx
= x
% 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))
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
;