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