1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
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.
10 //
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.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <common/Triangle.h>
22 #include <landscapemap/HeightMap.h>
23 #include <landscapemap/GraphicalHeightMap.h>
24 #include <common/Defines.h>
25
26 static const int minMapShift = 3;
27 static FixedVector nvec(fixed(0), fixed(0), fixed(1));
28
HeightMap()29 HeightMap::HeightMap() :
30 width_(0), height_(0),
31 heightData_(0), graphicalMap_(0),
32 invertedNormals_(false)
33 {
34 }
35
~HeightMap()36 HeightMap::~HeightMap()
37 {
38 delete [] heightData_;
39 heightData_ = 0;
40 if (graphicalMap_) delete graphicalMap_;
41 graphicalMap_ = 0;
42 }
43
create(const int width,const int height,bool invertedNormals)44 void HeightMap::create(const int width, const int height, bool invertedNormals)
45 {
46 invertedNormals_ = invertedNormals;
47 width_ = width;
48 height_ = height;
49
50 delete [] heightData_;
51 heightData_ = new HeightData[(width_ + 1) * (height_ + 1)];
52
53 reset();
54
55 if (graphicalMap_) graphicalMap_->create(width, height);
56 }
57
reset()58 void HeightMap::reset()
59 {
60 HeightData *current = heightData_;
61 for (int y=0; y<=height_; y++)
62 {
63 for (int x=0; x<=width_; x++)
64 {
65 current->position[0] = fixed(x);
66 current->position[1] = fixed(y);
67 current->position[2] = fixed(0);
68
69 current->normal[0] = fixed(0);
70 current->normal[1] = fixed(0);
71 current->normal[2] = invertedNormals_?fixed(-1):fixed(1);
72
73 current++;
74 }
75 }
76 }
77
getVector(FixedVector & vec,int x,int y)78 bool HeightMap::getVector(FixedVector &vec, int x, int y)
79 {
80 if (x < 0 || y < 0 || x>width_ || y>height_) return false;
81
82 vec = heightData_[(width_+1) * y + x].position;
83 return true;
84 }
85
getVectorPos(int pos,int & x,int & y,int dist)86 void HeightMap::getVectorPos(int pos, int &x, int &y, int dist)
87 {
88 switch (pos)
89 {
90 case 0:
91 x=-dist; y=0;
92 break;
93 case 1:
94 x=0; y=dist;
95 break;
96 case 2:
97 x=dist; y=0;
98 break;
99 default:
100 x=0; y=-dist;
101 }
102 }
103
getIntersect(Line & line,Vector & intersect)104 bool HeightMap::getIntersect(Line &line, Vector &intersect)
105 {
106 Vector direction = -((Vector &)line.getDirection()).Normalize();
107 Vector start = line.getEnd();
108
109 for (int i=0; i<1000; i++)
110 {
111 fixed height = getHeight((int) start[0], (int) start[1]);
112 if (height > fixed(int(start[2])))
113 {
114 if (start[0] < 0 || start[0] > getMapWidth() ||
115 start[1] < 0 || start[1] > getMapHeight())
116 {
117 return false;
118 }
119
120 intersect = start;
121 return true;
122 }
123
124 start += direction;
125 }
126 return false;
127 }
128
getInterpHeight(fixed w,fixed h)129 fixed HeightMap::getInterpHeight(fixed w, fixed h)
130 {
131 fixed ihx = w.floor();
132 fixed ihy = h.floor();
133 fixed ihx2 = ihx+1;
134 fixed ihy2 = ihy+1;
135
136 fixed fhx = w - ihx;
137 fixed fhy = h - ihy;
138
139 fixed heightA = getHeight(ihx.asInt(), ihy.asInt());
140 fixed heightB = getHeight(ihx.asInt(), ihy2.asInt());
141 fixed heightC = getHeight(ihx2.asInt(), ihy.asInt());
142 fixed heightD = getHeight(ihx2.asInt(), ihy2.asInt());
143
144 fixed heightDiffAB = heightB-heightA;
145 fixed heightDiffCD = heightD-heightC;
146 fixed heightE = heightA + (heightDiffAB * fhy);
147 fixed heightF = heightC + (heightDiffCD * fhy);
148
149 fixed heightDiffEF = heightF - heightE;
150 fixed height = heightE + (heightDiffEF * fhx);
151
152 return height;
153 }
154
getNormal(int w,int h)155 FixedVector &HeightMap::getNormal(int w, int h)
156 {
157 if (w >= 0 && h >= 0 && w<=width_ && h<=height_)
158 {
159 int pos = (width_+1) * h + w;
160
161 HeightMap::HeightData *heightData = &heightData_[pos];
162
163 FixedVector &normal = heightData->normal;
164 if (normal[0] == fixed(0) &&
165 normal[1] == fixed(0) &&
166 normal[2] == fixed(0))
167 {
168 int x = w;
169 int y = h;
170
171 static FixedVector C;
172 C = heightData->position;
173
174 static FixedVector total;
175 total.zero();
176
177 int times = 0;
178 for (int dist=1; dist<=3; dist+=2)
179 {
180 for (int a=0, b=1; a<4; a+=2, b+=2)
181 {
182 if (b>3) b=0;
183
184 static FixedVector A;
185 int aPosX, aPosY;
186 getVectorPos(a, aPosX, aPosY, dist);
187 if (!getVector(A, aPosX + x, aPosY + y)) continue;
188
189 static FixedVector B;
190 int bPosX, bPosY;
191 getVectorPos(b, bPosX, bPosY, dist);
192 if (!getVector(B, bPosX + x, bPosY + y)) continue;
193
194 A-=C;
195 B.StoreInvert();
196 B+=C;
197 A *= B;
198 A.StoreNormalize();
199 total += A;
200 times += 1;
201 }
202
203 if (times > 4) break;
204 }
205
206 normal = total.Normalize();
207 if (invertedNormals_) normal.StoreInvert();
208 if (graphicalMap_) graphicalMap_->setNormal(w, h, normal.asVector());
209 }
210
211 return normal;
212 }
213 nvec = FixedVector(fixed(0), fixed(0), invertedNormals_?fixed(-1):fixed(1));
214 return nvec;
215 }
216
getInterpNormal(fixed w,fixed h,FixedVector & normal)217 void HeightMap::getInterpNormal(fixed w, fixed h, FixedVector &normal)
218 {
219 fixed ihx = w.floor();
220 fixed ihy = h.floor();
221 fixed ihx2 = ihx+1;
222 fixed ihy2 = ihy+1;
223
224 fixed fhx = w - ihx;
225 fixed fhy = h - ihy;
226
227 FixedVector &normalA = getNormal(ihx.asInt(), ihy.asInt());
228 FixedVector &normalB = getNormal(ihx.asInt(), ihy2.asInt());
229 FixedVector &normalC = getNormal(ihx2.asInt(), ihy.asInt());
230 FixedVector &normalD = getNormal(ihx2.asInt(), ihy2.asInt());
231
232 static FixedVector normalDiffAB;
233 normalDiffAB = normalB;
234 normalDiffAB -= normalA;
235 normalDiffAB *= fhy;
236 static FixedVector normalDiffCD;
237 normalDiffCD = normalD;
238 normalDiffCD -= normalC;
239 normalDiffCD *= fhy;
240
241 static FixedVector normalE;
242 normalE = normalA;
243 normalE += normalDiffAB;
244 static FixedVector normalF;
245 normalF = normalC;
246 normalF += normalDiffCD;
247
248 static FixedVector normalDiffEF;
249 normalDiffEF = normalF;
250 normalDiffEF -= normalE;
251 normalDiffEF *= fhx;
252
253 normal = normalE;
254 normal += normalDiffEF;
255 }
256
setHeight(int w,int h,fixed height)257 void HeightMap::setHeight(int w, int h, fixed height)
258 {
259 DIALOG_ASSERT(w >= 0 && h >= 0 && w<=width_ && h<=height_);
260
261 HeightData &data = heightData_[(width_+1) * h + w];
262 data.position[2] = height;
263 if (graphicalMap_) graphicalMap_->setHeight(w, h, height.asFloat());
264
265 // Reset all of the normals around this position
266 for (int dist=1; dist<=3; dist++)
267 {
268 for (int a=0; a<4; a++)
269 {
270 int aPosX, aPosY;
271 getVectorPos(a, aPosX, aPosY, dist);
272
273 int x = w + aPosX;
274 int y = h + aPosY;
275 if (x>=0 && y>=0 && x<=width_ && y<=height_)
276 {
277 heightData_[(width_+1) * y + x].normal.zero();
278 }
279 }
280 }
281 heightData_[(width_+1) * h + w].normal.zero();
282 }
283