Merge from development branch heightmap to main.
[scorched3d.git] / src / client / land / LandVisibilityPatch.cpp
blob2078d822bba99c4ba120a87a539abf188a01c60b
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2004
3 //
4 // This file is part of Scorched3D.
5 //
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),
38 visibilityIndex_(-1),
39 dataSize_(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));
88 return totalError;
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
106 x_ = x; y_ = y;
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);
121 calculateErrors();
124 void LandVisibilityPatch::calculateErrors()
126 maxHeight_ = 0.0f;
127 minHeight_ = 100000.0f;
128 for (int i=0; i<=5; i++)
130 float error = 0.0f;
131 if (i>0)
133 int skip = 1 << i;
134 for (int y1=y_; y1<y_+32; y1+=skip)
136 for (int x1=x_; x1<x_+32; x1+=skip)
138 int x2 = x1 + skip;
139 int y2 = y1 + 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)
167 visible_ = true;
169 if (recalculateErrors_)
171 calculateErrors();
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;
190 return true;
193 void LandVisibilityPatch::setNotVisible()
195 visible_ = false;
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];
205 // Number triangles
206 GLInfo::addNoTriangles(index.getSize() - 2);
208 if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
209 GLStateExtension::hasDrawRangeElements())
211 // Map data to draw
212 float *data = 0;
213 if (landscapeMap->getBufferObject())
215 data = (float*) NULL + dataOffSet_;
217 else
219 data = &heightMapData[dataOffSet_];
222 // Vertices On
223 glVertexPointer(3, GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data);
225 if (!simple)
227 // Normals On
228 glNormalPointer(GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data + 3);
230 // Tex Coords
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));
251 else
253 indices = index.getIndices();
256 // Draw elements
257 glDrawRangeElements(GL_TRIANGLE_STRIP,
258 index.getMinIndex(),
259 index.getMaxIndex(),
260 index.getSize(),
261 GL_UNSIGNED_SHORT,
262 indices);
263 DIALOG_ASSERT((index.getMaxIndex()-index.getMinIndex()+1) <
264 GLStateExtension::getMaxElementVertices());
265 DIALOG_ASSERT(index.getSize() <
266 GLStateExtension::getMaxElementIndices());
268 else
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]);
275 if (!simple)
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);
289 glVertex3fv(data);
291 glEnd();
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);