HeightMap.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <common/Triangle.h>
00022 #include <landscapemap/HeightMap.h>
00023 #include <landscapemap/GraphicalHeightMap.h>
00024 #include <common/Defines.h>
00025 
00026 static const int minMapShift = 3;
00027 static FixedVector nvec(fixed(0), fixed(0), fixed(1));
00028 
00029 HeightMap::HeightMap() : 
00030         heightData_(0), graphicalMap_(0)
00031 {
00032 }
00033 
00034 HeightMap::~HeightMap()
00035 {
00036         delete [] heightData_;
00037 }
00038 
00039 void HeightMap::create(const int width, const int height)
00040 {
00041         width_ = width; 
00042         height_ = height;
00043 
00044         delete [] heightData_;
00045         heightData_ = new HeightData[(width_ + 1) * (height_ + 1)];
00046 
00047         reset();
00048 
00049         if (graphicalMap_) graphicalMap_->create(width, height);
00050 }
00051 
00052 void HeightMap::reset()
00053 {
00054         HeightData *current = heightData_;
00055         for (int y=0; y<=height_; y++)
00056         {
00057                 for (int x=0; x<=width_; x++)
00058                 {
00059                         current->position[0] = fixed(x);
00060                         current->position[1] = fixed(y);
00061                         current->position[2] = fixed(0);
00062 
00063                         current->normal[0] = fixed(0);
00064                         current->normal[1] = fixed(0);
00065                         current->normal[2] = fixed(1);
00066 
00067                         current++;
00068                 }
00069         }
00070 }
00071 
00072 bool HeightMap::getVector(FixedVector &vec, int x, int y)
00073 {
00074         if (x < 0 || y < 0 || x>width_ || y>height_) return false;
00075 
00076         vec = heightData_[(width_+1) * y + x].position;
00077         return true;
00078 }
00079 
00080 void HeightMap::getVectorPos(int pos, int &x, int &y, int dist)
00081 {
00082         switch (pos)
00083         {
00084         case 0:
00085                 x=-dist; y=0;
00086                 break;
00087         case 1:
00088                 x=0; y=dist;
00089                 break;
00090         case 2:
00091                 x=dist; y=0;
00092                 break;
00093         default:
00094                 x=0; y=-dist;
00095         }
00096 }
00097 
00098 bool HeightMap::getIntersect(Line &line, Vector &intersect)
00099 {
00100         Vector direction = -((Vector &)line.getDirection()).Normalize();
00101         Vector start = line.getEnd();
00102 
00103         for (int i=0; i<1000; i++)
00104         {
00105                 fixed height = getHeight((int) start[0], (int) start[1]);
00106                 if (height > fixed(int(start[2])))
00107                 {
00108                         if (start[0] < 0 || start[0] > getMapWidth() ||
00109                                 start[1] < 0 || start[1] > getMapHeight())
00110                         {
00111                                 return false;
00112                         }
00113 
00114                         intersect = start;
00115                         return true;
00116                 }
00117 
00118                 start += direction;
00119         }
00120         return false;
00121 }
00122 
00123 fixed HeightMap::getInterpHeight(fixed w, fixed h)
00124 {
00125         fixed ihx = w.floor(); 
00126         fixed ihy = h.floor();
00127         fixed ihx2 = ihx+1;
00128         fixed ihy2 = ihy+1; 
00129 
00130         fixed fhx = w - ihx;
00131         fixed fhy = h - ihy;
00132         
00133         fixed heightA = getHeight(ihx.asInt(), ihy.asInt());
00134         fixed heightB = getHeight(ihx.asInt(), ihy2.asInt());
00135         fixed heightC = getHeight(ihx2.asInt(), ihy.asInt());
00136         fixed heightD = getHeight(ihx2.asInt(), ihy2.asInt());
00137 
00138         fixed heightDiffAB = heightB-heightA;
00139         fixed heightDiffCD = heightD-heightC;
00140         fixed heightE = heightA + (heightDiffAB * fhy);
00141         fixed heightF = heightC + (heightDiffCD * fhy);
00142 
00143         fixed heightDiffEF = heightF - heightE;
00144         fixed height = heightE + (heightDiffEF * fhx);  
00145 
00146         return height;
00147 }
00148 
00149 FixedVector &HeightMap::getNormal(int w, int h)
00150 {
00151         if (w >= 0 && h >= 0 && w<=width_ && h<=height_) 
00152         {
00153                 int pos = (width_+1) * h + w;
00154 
00155                 HeightMap::HeightData *heightData = &heightData_[pos];
00156 
00157                 FixedVector &normal = heightData->normal;
00158                 if (normal[0] == fixed(0) && 
00159                         normal[1] == fixed(0) && 
00160                         normal[2] == fixed(0))
00161                 {
00162                         int x = w;
00163                         int y = h;
00164 
00165                         static FixedVector C;
00166                         C = heightData->position;
00167 
00168                         static FixedVector total;
00169                         total.zero();
00170 
00171                         int times = 0;
00172                         for (int dist=1; dist<=3; dist+=2)
00173                         {
00174                                 for (int a=0, b=1; a<4; a+=2, b+=2)
00175                                 {
00176                                         if (b>3) b=0;
00177 
00178                                         static FixedVector A;
00179                                         int aPosX, aPosY;
00180                                         getVectorPos(a, aPosX, aPosY, dist);
00181                                         if (!getVector(A, aPosX + x, aPosY + y)) continue;
00182 
00183                                         static FixedVector B;
00184                                         int bPosX, bPosY;                               
00185                                         getVectorPos(b, bPosX, bPosY, dist);
00186                                         if (!getVector(B, bPosX + x, bPosY + y)) continue;
00187 
00188                                         A-=C;
00189                                         B.StoreInvert();
00190                                         B+=C;
00191                                         A *= B;
00192                                         A.StoreNormalize();
00193                                         total += A;
00194                                         times += 1;
00195                                 }
00196 
00197                                 if (times > 4) break;
00198                         }
00199 
00200                         normal = total.Normalize();
00201                         if (graphicalMap_) graphicalMap_->setNormal(w, h, normal.asVector());                   
00202                 }
00203 
00204                 return normal; 
00205         }
00206         nvec = FixedVector(fixed(0), fixed(0), fixed(1));
00207         return nvec; 
00208 }
00209 
00210 void HeightMap::getInterpNormal(fixed w, fixed h, FixedVector &normal)
00211 {
00212         fixed ihx = w.floor();
00213         fixed ihy = h.floor();
00214         fixed ihx2 = ihx+1;
00215         fixed ihy2 = ihy+1;
00216 
00217         fixed fhx = w - ihx;
00218         fixed fhy = h - ihy;
00219 
00220         FixedVector &normalA = getNormal(ihx.asInt(), ihy.asInt());
00221         FixedVector &normalB = getNormal(ihx.asInt(), ihy2.asInt());
00222         FixedVector &normalC = getNormal(ihx2.asInt(), ihy.asInt());
00223         FixedVector &normalD = getNormal(ihx2.asInt(), ihy2.asInt());
00224 
00225         static FixedVector normalDiffAB;
00226         normalDiffAB = normalB;
00227         normalDiffAB -= normalA;
00228         normalDiffAB *= fhy;
00229         static FixedVector normalDiffCD;
00230         normalDiffCD = normalD;
00231         normalDiffCD -= normalC;
00232         normalDiffCD *= fhy;
00233 
00234         static FixedVector normalE;
00235         normalE = normalA;
00236         normalE += normalDiffAB;
00237         static FixedVector normalF;
00238         normalF = normalC;
00239         normalF += normalDiffCD;
00240 
00241         static FixedVector normalDiffEF;
00242         normalDiffEF = normalF;
00243         normalDiffEF -= normalE;
00244         normalDiffEF *= fhx;
00245 
00246         normal = normalE;
00247         normal += normalDiffEF;
00248 }
00249 
00250 void HeightMap::setHeight(int w, int h, fixed height)
00251 {
00252         DIALOG_ASSERT(w >= 0 && h >= 0 && w<=width_ && h<=height_);
00253 
00254         HeightData &data = heightData_[(width_+1) * h + w];
00255         data.position[2] = height;
00256         if (graphicalMap_) graphicalMap_->setHeight(w, h, height.asFloat());
00257 
00258         // Reset all of the normals around this position
00259         for (int dist=1; dist<=3; dist++)
00260         {
00261                 for (int a=0; a<4; a++)
00262                 {
00263                         int aPosX, aPosY;
00264                         getVectorPos(a, aPosX, aPosY, dist);
00265 
00266                         int x = w + aPosX;
00267                         int y = h + aPosY;
00268                         if (x>=0 && y>=0 && x<=width_ && y<=height_)
00269                         {
00270                                 heightData_[(width_+1) * y + x].normal.zero();
00271                         }
00272                 }
00273         }
00274         heightData_[(width_+1) * h + w].normal.zero();
00275 }

Generated on Mon Feb 16 15:14:50 2009 for Scorched3D by  doxygen 1.5.3