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 Vec3f
localCamPos( curCam
->getAbsTrans().x
[12], curCam
->getAbsTrans().x
[13], curCam
->getAbsTrans().x
[14] );
90 localCamPos
= island
->_absTrans
.inverted() * localCamPos
;
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
)
135 int IslandNode::getParami(int param
)
139 case IslandNodeParams::MaterialRes
:
140 if( materialRes
!= 0x0 ) return materialRes
->getHandle();
142 case IslandNodeParams::SizeX
:
144 case IslandNodeParams::SizeZ
:
147 return SceneNode::getParami( param
);
150 bool IslandNode::setParami(int param
, int value
)
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
);
162 materialRes
= (MaterialResource
*)res
;
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
);
175 // TODO: Recreate terrain
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
);
188 // TODO: Recreate terrain
191 return SceneNode::setParami(param
, value
);
194 float IslandNode::getParamf(int param
)
198 case IslandNodeParams::MeshQuality
:
201 return SceneNode::getParamf(param
);
204 bool IslandNode::setParamf(int param
, float value
)
208 case IslandNodeParams::MeshQuality
:
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
)
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;
228 heightdata
= new float[(sizeX
+ 1) * (sizeZ
+ 1)];
229 for (int i
= 0; i
< (sizeX
+ 1) * (sizeZ
+ 1); i
++)
233 // Create index buffers
234 createIndexBuffers();
235 // Create terrain patches
236 createVertexBuffers();
237 // Create extension plane around the terrain
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
;
250 unsigned short *indices
= new unsigned short[size
* size
* 6];
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;
265 indexBuffer
[i
] = Modules::renderer().uploadIndices(indices
, size
* size
* 6 * sizeof(short));
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
;
289 vertex
[2] = z
* TILE_SIZE
+ z2
;
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
];
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
)
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
;
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
;
334 for (int ix
= 0; ix
< width
; ix
++)
336 int tilex
= (ix
+ x
) / TILE_SIZE
;
337 int offsetx
= (ix
+ x
) % 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))
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))
357 for (int ix
= 0; ix
< width
; ix
++)
359 int tilex
= (ix
+ x
) / TILE_SIZE
;
360 int offsetx
= (ix
+ x
) % 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))
372 float *vertex
= &vertexdata
[tilex
+ tilez
* EDGE_TILES
][(offsetz
* (TILE_SIZE
+ 1) + offsetx
) * 3];
373 vertex
[1] = heightdata
[(iz
+ y
) * (sizeX
+ 1) + (ix
+ x
)];
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()