1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2004
4 // This file is part of Scorched3D.
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <land/LandVisibilityPatch.h>
22 #include <land/VisibilityPatchGrid.h>
23 #include <landscapemap/LandscapeMaps.h>
24 #include <landscapemap/GraphicalHeightMap.h>
25 #include <landscape/GraphicalLandscapeMap.h>
26 #include <graph/OptionsDisplay.h>
27 #include <graph/MainCamera.h>
28 #include <client/ScorchedClient.h>
29 #include <common/Logger.h>
30 #include <GLEXT/GLStateExtension.h>
31 #include <GLEXT/GLInfo.h>
32 #include <GLW/GLWFont.h>
34 LandVisibilityPatch::LandVisibilityPatch() :
35 visible_(false), recalculateErrors_(false),
36 leftPatch_(0), rightPatch_(0),
37 topPatch_(0), bottomPatch_(0),
43 LandVisibilityPatch::~LandVisibilityPatch()
47 static float getHeight(int x
, int y
)
49 int mapWidth
= ScorchedClient::instance()->getLandscapeMaps().
50 getGroundMaps().getLandscapeWidth();
52 GraphicalLandscapeMap
*landscapeMap
= (GraphicalLandscapeMap
*)
53 ScorchedClient::instance()->getLandscapeMaps().
54 getGroundMaps().getHeightMap().getGraphicalMap();
55 return landscapeMap
->getHeightData()[x
+ (y
* (mapWidth
+ 1))].floatPosition
[2];
58 static float calculateError(int x1
, int x2
, int y1
, int y2
,
59 float x1y1
, float x2y2
, float x1y2
, float x2y1
)
61 if (x2
- x1
<= 1) return 0.0f
;
63 int midx
= (x1
+ x2
) / 2;
64 int midy
= (y1
+ y2
) / 2;
65 float actualheight
= getHeight(midx
, midy
);
67 float approxheight1
= (x1y1
+ x2y2
) / 2.0f
;
68 float approxheight2
= (x1y2
+ x2y1
) / 2.0f
;
69 float approxheight3
= (x1y1
+ x1y2
) / 2.0f
;
70 float approxheight4
= (x1y1
+ x2y1
) / 2.0f
;
71 float approxheight5
= (x1y2
+ x2y2
) / 2.0f
;
72 float approxheight6
= (x2y1
+ x2y2
) / 2.0f
;
74 float heightdiff1
= fabs(approxheight1
- actualheight
);
75 float heightdiff2
= fabs(approxheight2
- actualheight
);
77 float errorChild1
= calculateError(x1
, midx
, y1
, midy
,
78 x1y1
, approxheight1
, approxheight3
, approxheight4
);
79 float errorChild2
= calculateError(midx
, x2
, y1
, midy
,
80 approxheight4
, approxheight6
, approxheight1
, x2y1
);
81 float errorChild3
= calculateError(x1
, midx
, midy
, y2
,
82 approxheight3
, approxheight5
, x1y2
, approxheight2
);
83 float errorChild4
= calculateError(midx
, x2
, midy
, y2
,
84 approxheight2
, x2y2
, approxheight5
, approxheight6
);
86 float errorChildren
= MAX(errorChild1
, MAX(errorChild2
, MAX(errorChild3
, errorChild4
)));
87 float totalError
= MAX(errorChildren
, MAX(heightdiff1
, heightdiff2
));
91 void LandVisibilityPatch::setLocation(int x
, int y
,
92 LandVisibilityPatch
*leftPatch
,
93 LandVisibilityPatch
*rightPatch
,
94 LandVisibilityPatch
*topPatch
,
95 LandVisibilityPatch
*bottomPatch
)
97 int mapWidth
= ScorchedClient::instance()->getLandscapeMaps().
98 getGroundMaps().getLandscapeWidth();
99 int mapHeight
= ScorchedClient::instance()->getLandscapeMaps().
100 getGroundMaps().getLandscapeHeight();
102 DIALOG_ASSERT(x
>= 0 && y
>= 0 &&
103 x
< mapWidth
&& y
< mapHeight
);
105 // Set location and neighbors
107 leftPatch_
= leftPatch
;
108 rightPatch_
= rightPatch
;
109 topPatch_
= topPatch
;
110 bottomPatch_
= bottomPatch
;
112 // Set pointers to heightmap
113 dataSize_
= (mapWidth
+ 1) * (mapHeight
+ 1);
115 GraphicalLandscapeMap
*landscapeMap
= (GraphicalLandscapeMap
*)
116 ScorchedClient::instance()->getLandscapeMaps().
117 getGroundMaps().getHeightMap().getGraphicalMap();
118 dataOffSet_
= (x
+ (y
* (mapWidth
+ 1))) *
119 sizeof(GraphicalLandscapeMap::HeightData
) / sizeof(float);
124 void LandVisibilityPatch::calculateErrors()
127 minHeight_
= 100000.0f
;
128 for (int i
=0; i
<=5; i
++)
134 for (int y1
=y_
; y1
<y_
+32; y1
+=skip
)
136 for (int x1
=x_
; x1
<x_
+32; x1
+=skip
)
141 float x1y1
= getHeight(x1
, y1
);
142 float x2y2
= getHeight(x2
, y2
);
143 float x1y2
= getHeight(x1
, y2
);
144 float x2y1
= getHeight(x2
, y1
);
146 float thisError
= calculateError(x1
, x2
, y1
, y2
,
147 x1y1
, x2y2
, x1y2
, x2y1
);
148 error
= MAX(error
, thisError
);
150 if (x1y1
> maxHeight_
) maxHeight_
= x1y1
;
151 if (x1y1
< minHeight_
) minHeight_
= x1y1
;
156 indexErrors_
[i
] = error
;
159 float heightRange
= maxHeight_
- minHeight_
;
160 boundingSize_
= MAX(32.0f
, heightRange
) * 1.25f
;
161 position_
= Vector(float(x_
+ 16), float(y_
+ 16),
162 heightRange
/ 2.0f
+ minHeight_
);
165 bool LandVisibilityPatch::setVisible(float distance
)
169 if (recalculateErrors_
)
172 recalculateErrors_
= false;
175 float maxError
= 5.0f
;
176 if (distance
< 32.0f
) maxError
= 1.0f
;
177 else if (distance
< 64.0f
) maxError
= 1.5f
;
178 else if (distance
< 256.0f
) maxError
= 3.0f
;
180 visibilityIndex_
= 0;
181 if (!OptionsDisplay::instance()->getNoLandLOD())
183 for (int i
=0; i
<=5; i
++)
185 if (indexErrors_
[i
] > maxError
) break;
186 visibilityIndex_
= i
;
193 void LandVisibilityPatch::setNotVisible()
198 void LandVisibilityPatch::draw(MipMapPatchIndex
&index
, bool simple
)
200 GraphicalLandscapeMap
*landscapeMap
= (GraphicalLandscapeMap
*)
201 ScorchedClient::instance()->getLandscapeMaps().
202 getGroundMaps().getHeightMap().getGraphicalMap();
203 float *heightMapData
= &landscapeMap
->getHeightData()->floatPosition
[0];
206 GLInfo::addNoTriangles(index
.getSize() - 2);
208 if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
209 GLStateExtension::hasDrawRangeElements())
213 if (landscapeMap
->getBufferObject())
215 data
= (float*) NULL
+ dataOffSet_
;
219 data
= &heightMapData
[dataOffSet_
];
223 glVertexPointer(3, GL_FLOAT
, sizeof(GraphicalLandscapeMap::HeightData
), data
);
228 glNormalPointer(GL_FLOAT
, sizeof(GraphicalLandscapeMap::HeightData
), data
+ 3);
231 if (GLStateExtension::hasMultiTex())
233 glClientActiveTextureARB(GL_TEXTURE1_ARB
);
234 glTexCoordPointer(2, GL_FLOAT
, sizeof(GraphicalLandscapeMap::HeightData
), data
+ 6);
235 if (GLStateExtension::getTextureUnits() > 2)
237 glClientActiveTextureARB(GL_TEXTURE2_ARB
);
238 glTexCoordPointer(2, GL_FLOAT
, sizeof(GraphicalLandscapeMap::HeightData
), data
+ 8);
241 glClientActiveTextureARB(GL_TEXTURE0_ARB
);
242 glTexCoordPointer(2, GL_FLOAT
, sizeof(GraphicalLandscapeMap::HeightData
), data
+ 6);
245 // Map indices to draw
246 unsigned short *indices
= 0;
247 if (index
.getBufferOffSet() != -1)
249 indices
= (unsigned short *) NULL
+ (index
.getBufferOffSet() / sizeof(unsigned short));
253 indices
= index
.getIndices();
257 glDrawRangeElements(GL_TRIANGLE_STRIP
,
263 DIALOG_ASSERT((index
.getMaxIndex()-index
.getMinIndex()+1) <
264 GLStateExtension::getMaxElementVertices());
265 DIALOG_ASSERT(index
.getSize() <
266 GLStateExtension::getMaxElementIndices());
270 glBegin(GL_TRIANGLE_STRIP
);
271 for (int i
=0; i
<index
.getSize(); i
++)
273 float *data
= &heightMapData
[dataOffSet_
] +
274 (sizeof(GraphicalLandscapeMap::HeightData
) / 4 * index
.getIndices()[i
]);
277 glNormal3fv(data
+ 3);
278 glTexCoord2fv(data
+ 6);
279 if (GLStateExtension::hasMultiTex())
281 glMultiTexCoord2fvARB(GL_TEXTURE1_ARB
, data
+ 6);
282 if (GLStateExtension::getTextureUnits() > 2)
284 glMultiTexCoord2fvARB(GL_TEXTURE2_ARB
, data
+ 8);
295 void LandVisibilityPatch::drawLODLevel(MipMapPatchIndex
&index
)
297 if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT
, GL_FILL
);
299 GraphicalLandscapeMap
*landscapeMap
= (GraphicalLandscapeMap
*)
300 ScorchedClient::instance()->getLandscapeMaps().
301 getGroundMaps().getHeightMap().getGraphicalMap();
302 float *heightMapData
= &landscapeMap
->getHeightData()->floatPosition
[0];
304 Vector
red(1.0f
, 0.0f
, 0.0f
);
305 Vector
yellow(1.0f
, 1.0f
, 0.0f
);
306 GLWFont::instance()->getGameFont()->drawBilboard(red
, 1.0f
, 3.0f
,
307 position_
[0], position_
[1], position_
[2],
308 S3D::formatStringBuffer("%i", visibilityIndex_
));
310 if ((MainCamera::instance()->getCamera().getLookAt() - position_
).Magnitude() < 20.0f
)
312 for (int i
=0; i
<index
.getSize(); i
++)
314 float *data
= &heightMapData
[dataOffSet_
] +
315 (sizeof(GraphicalLandscapeMap::HeightData
) / 4 * index
.getIndices()[i
]);
317 GLWFont::instance()->getGameFont()->drawBilboard(yellow
, 1.0f
, 1.0f
,
318 data
[0], data
[1], data
[2] + i
* 1.5f
,
319 S3D::formatStringBuffer("%i", i
));
323 if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT
, GL_LINE
);