00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "SDL_image.h"
00012 #include <iostream>
00013 #include <list>
00014 #include <string>
00015 #include "ccmath.h"
00016 #include "Log.h"
00017 #include "Config.h"
00018 #include "Texture.h"
00019 #include "normals.h"
00020 #include "collisions.h"
00021 #include "QuadNode.h"
00022 #include "BoundBox.h"
00023 #include "Point.h"
00024 #include "Frustum.h"
00025 #include "Ocean.h"
00026 #include "Terrain.h"
00027
00028 using namespace std;
00029
00030
00031
00032
00033
00034
00035
00036 #define TNORMALS_INDEX(X, Z, T) ((((Z)*m_w + (X)) * 3) + (T))
00037
00038 #define TERRAIN_ARRAY(X, Z, T) m_terrainArray[((((Z) * m_w) + (X)) * (3+3+2+2)) + (T)]
00039
00040 #define TERRAIN_ARRAY_INDEX(X, Z) (((Z) * m_w) + (X))
00041
00042 #define VERTEX(X, Z) m_vertexData[((((Z) * m_w) + (X)) * m_vertexStride) + m_vertexOffset]
00043
00044 #define ARRAY_STRIDE ((3+3+2+2) * sizeof(GLfloat))
00045
00046 #define ARRAY_VERTEX 0
00047 #define ARRAY_NORMAL 3
00048 #define ARRAY_TEX0 6
00049 #define ARRAY_TEX1 8
00050
00051 Terrain::Terrain(string file, GLfloat vScaleIn, int quadSizeIn) {
00052 SDL_Surface *Image;
00053 BoundBox *box;
00054 Uint8 *p;
00055
00056
00057 int xDiff;
00058 int zDiff;
00059
00060 QuadNode::s_quadSize = quadSizeIn;
00061
00062
00063 Image = IMG_Load(file.c_str());
00064 if (!Image) {
00065 throw string("Error: Could not load file " + file);
00066 }
00067
00068 m_w = Image->w;
00069 m_h = Image->h;
00070
00071 xDiff = (int) m_w / 2;
00072 zDiff = (int) m_h / 2;
00073
00074
00075 m_ocean = new Ocean(m_w, m_h);
00076 if (m_ocean == NULL) {
00077 Log::s_log->Message("Warning: Could not create ocean object");
00078 } else {
00079 Log::s_log->Message("Ocean created");
00080 }
00081
00082
00083
00084 m_terrainArray = new GLfloat[m_w*m_h*(3+3+2+2)];
00085
00086 if (Config::s_config->CheckVBO()) {
00087
00088
00089 m_vertexData = new GLfloat[m_w*m_h];
00090
00091
00092 m_vertexStride = 1;
00093
00094
00095 m_vertexOffset = 0;
00096 } else {
00097
00098 m_vertexData = m_terrainArray;
00099
00100
00101 m_vertexStride = (3+3+2+2);
00102
00103
00104 m_vertexOffset = 1;
00105 }
00106
00107 p = (Uint8 *) Image->pixels;
00108
00109 for (int z = 0; z < m_h; z++){
00110 for (int x = 0; x < m_w; x++){
00111 TERRAIN_ARRAY(x, z, ARRAY_VERTEX+0) = (GLfloat) x - xDiff;
00112 TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1) = (p[z*Image->pitch + x*Image->format->BytesPerPixel] - 128) * vScaleIn;
00113 TERRAIN_ARRAY(x, z, ARRAY_VERTEX+2) = (GLfloat) z - zDiff;
00114
00115
00116
00117 if (Config::s_config->CheckVBO()) {
00118 VERTEX(x, z) = TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1);
00119 }
00120
00121
00122 TERRAIN_ARRAY(x, z, ARRAY_TEX0+0) = ((float) x) / ((float) m_w);
00123 TERRAIN_ARRAY(x, z, ARRAY_TEX0+1) = ((float) z) / ((float) m_h);
00124
00125
00126 TERRAIN_ARRAY(x, z, ARRAY_TEX1+0) = x*DETAIL_SCALE;
00127 TERRAIN_ARRAY(x, z, ARRAY_TEX1+1) = z*DETAIL_SCALE;
00128
00129
00130 }
00131 }
00132
00133 SDL_FreeSurface(Image);
00134
00135 Log::s_log->Message("Heightmap generated");
00136
00137 CalcNormals();
00138
00139
00140 Log::s_log->Message("Normals generated");
00141
00142
00143
00144 m_texture = new Texture("land.png");
00145 m_detailTex = new Texture("detail.png");
00146
00147
00148 SetGlArrayPointers();
00149
00150
00151 glActiveTexture(GL_TEXTURE0);
00152 glEnable(GL_TEXTURE_2D);
00153 m_texture->BindTexture();
00154 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00155
00156
00157 glActiveTexture(GL_TEXTURE1);
00158 glEnable(GL_TEXTURE_2D);
00159 m_detailTex->BindTexture();
00160 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
00161 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 2);
00162
00163
00164 m_material[0] = 1.0;
00165 m_material[1] = 1.0;
00166 m_material[2] = 1.0;
00167 m_material[3] = 1.0;
00168
00169
00170 box = new BoundBox();
00171
00172 box->m_b1 = new Point(0.0 - (int) m_w/2, 0.0, 0.0 - (int) m_h/2);
00173 box->m_b2 = new Point((int) m_w/2, 0.0, 0.0 - (int) m_h/2);
00174 box->m_b3 = new Point(0.0 - (int) m_w/2, 0.0, (int) m_h/2 - 1);
00175 box->m_b4 = new Point((int) m_w/2 - 1, 0.0, (int) m_h/2 - 1);
00176
00177
00178 m_frustum = new Frustum();
00179
00180
00181 m_root = new QuadNode(this, box);
00182
00183 Log::s_log->Message("Quadtree generated");
00184
00185
00186
00187 if (Config::s_config->CheckVBO()) {
00188
00189 delete []m_terrainArray;
00190 m_terrainArray = NULL;
00191 }
00192
00193
00194
00195 glDisable(GL_TEXTURE_2D);
00196 glActiveTexture(GL_TEXTURE0);
00197 }
00198
00199 Terrain::~Terrain() {
00200
00201 delete m_ocean;
00202
00203
00204 delete m_root;
00205
00206
00207 delete m_frustum;
00208
00209 if (Config::s_config->CheckVBO()) {
00210
00211 glDeleteBuffers(1, &m_buffer);
00212
00213
00214 delete []m_vertexData;
00215 } else {
00216
00217 delete []m_terrainArray;
00218 m_terrainArray = NULL;
00219
00220
00221 m_vertexData = NULL;
00222 }
00223
00224
00225 delete m_texture;
00226 delete m_detailTex;
00227
00228
00229
00230
00231 Log::s_log->Message("Terrain deleted");
00232 }
00233
00234 void Terrain::Update(unsigned int ticks) {
00235 m_ocean->Update(ticks);
00236 }
00237
00238 void Terrain::Draw() {
00239
00240 glMaterialfv(GL_FRONT, GL_AMBIENT, m_material);
00241 glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material);
00242
00243
00244 glActiveTexture(GL_TEXTURE0);
00245
00246 m_texture->BindTexture();
00247
00248
00249 glActiveTexture(GL_TEXTURE1);
00250 glEnable(GL_TEXTURE_2D);
00251 m_detailTex->BindTexture();
00252
00253 m_frustum->GetFrustum();
00254
00255 m_root->Draw(m_frustum);
00256
00257
00258
00259 glDisable(GL_TEXTURE_2D);
00260 glActiveTexture(GL_TEXTURE0);
00261
00262 glEnable(GL_BLEND);
00263 m_ocean->Draw();
00264 glDisable(GL_BLEND);
00265 }
00266
00267 bool Terrain::CheckLineCollision(GLfloat xIn, GLfloat zIn, int size,
00268 double v[3], float mag) {
00269 int xMin, xMax;
00270 int zMin, zMax;
00271
00272 xIn = (m_w/2) + xIn;
00273 zIn = (m_h/2) + zIn;
00274
00275 xMin = (int) xIn - (size/2);
00276 xMax = (int) xIn + (size/2);
00277 if (xMin < 0) xMin = 0;
00278 if (xMax > (m_w-2)) xMax = (m_w-2);
00279
00280 zMin = (int) zIn - (size/2);
00281 zMax = (int) zIn + (size/2);
00282 if (zMin < 0) zMin = 0;
00283 if (zMax > (m_h-2)) zMax = (m_h-2);
00284
00285
00286 v[2] = v[2] * -1;
00287
00288 for (int z = zMin; z < zMax; z++){
00289 for(int x = xMin; x < xMax; x++) {
00290 if (NeedCollision(x, z)) {
00291 double orig[3];
00292 double vert0[3];
00293 double vert1[3];
00294 double vert2[3];
00295 double vert3[3];
00296 double r1, r2, r3;
00297
00298 orig[0] = xIn;
00299 orig[1] = 0;
00300 orig[2] = zIn;
00301
00302 vert0[0] = x;
00303 vert0[1] = VERTEX(x, z);
00304 vert0[2] = z;
00305
00306 vert1[0] = x+1;
00307 vert1[1] = VERTEX(x+1, z);
00308 vert1[2] = z;
00309
00310 vert2[0] = x;
00311 vert2[1] = VERTEX(x, z+1);
00312 vert2[2] = z+1;
00313
00314 vert3[0] = x+1;
00315 vert3[1] = VERTEX(x+1, z+1);
00316 vert3[2] = z+1;
00317
00318 if (intersect_triangle(orig, v, vert0, vert2, vert1, &r1, &r2, &r3)) {
00319 if ((r1 >= 0) && (r1 < mag)) {
00320
00321 return true;
00322 }
00323 }
00324 if (intersect_triangle(orig, v, vert2, vert3, vert1, &r1, &r2, &r3)) {
00325 if ((r1 >= 0) && (r1 < mag)) {
00326
00327 return true;
00328 }
00329 }
00330 }
00331 }
00332 }
00333
00334 return false;
00335 }
00336
00337 bool Terrain::NeedCollision(int x, int z) {
00338 GLfloat v1, v2, v3, v4;
00339
00340 v1 = VERTEX(x, z);
00341 v2 = VERTEX(x, z+1);
00342 v3 = VERTEX(x+1, z);
00343 v4 = VERTEX(x+1, z+1);
00344
00345 if (((v1 <= 0) || (v2 <= 0) || (v3 <= 0) || (v4 <= 0)) &&
00346 ((v1 >= 0) || (v2 >= 0) || (v3 >= 0) || (v4 >= 0))) {
00347 return true;
00348 } else return false;
00349 }
00350
00351
00352 void Terrain::CalcNormals() {
00353 GLfloat point1[3], point2[3], point3[3];
00354 GLfloat *tnormals1;
00355 GLfloat *tnormals2;
00356
00357 short int z, x;
00358
00359 if (m_terrainArray == NULL) return;
00360
00361 tnormals1 = new GLfloat[m_w*m_h*3];
00362 tnormals2 = new GLfloat[m_w*m_h*3];
00363
00364 for (z = 0; z < m_h-1; z++) {
00365 for (x = 0; x < m_w-1; x++) {
00366 point1[0] = x;
00367 point1[1] = TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1);
00368 point1[2] = z;
00369
00370 point2[0] = x;
00371 point2[1] = TERRAIN_ARRAY(x, z+1, ARRAY_VERTEX+1);
00372 point2[2] = z+1;
00373
00374 point3[0] = x+1;
00375 point3[1] = TERRAIN_ARRAY(x+1, z, ARRAY_VERTEX+1);
00376 point3[2] = z;
00377
00378 crossProduct(point1, point2, point3, &tnormals1[TNORMALS_INDEX(x, z, 0)]);
00379
00380 point1[0] = x;
00381 point1[1] = TERRAIN_ARRAY(x, z+1, ARRAY_VERTEX+1);
00382 point1[2] = z+1;
00383
00384 point2[0] = x+1;
00385 point2[1] = TERRAIN_ARRAY(x+1, z+1, ARRAY_VERTEX+1);
00386 point2[2] = z+1;
00387
00388 point3[0] = x+1;
00389 point3[1] = TERRAIN_ARRAY(x+1, z, ARRAY_VERTEX+1);
00390 point3[2] = z;
00391
00392 crossProduct(point1, point2, point3, &tnormals2[TNORMALS_INDEX(x, z, 0)]);
00393 }
00394 }
00395
00396 for (z = 1; z < m_h-1; z++) {
00397 for (x = 1; x < m_w-1; x++) {
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 TERRAIN_ARRAY(x, z, ARRAY_NORMAL+0) = (tnormals2[TNORMALS_INDEX(x-1, z-1, 0)] + tnormals1[TNORMALS_INDEX(x-1, z, 0)] +
00411 tnormals2[TNORMALS_INDEX(x-1, z, 0)] + tnormals1[TNORMALS_INDEX(x, z-1, 0)] +
00412 tnormals2[TNORMALS_INDEX(x, z-1, 0)] + tnormals1[TNORMALS_INDEX(x, z, 0)]);
00413 TERRAIN_ARRAY(x, z, ARRAY_NORMAL+1) = (tnormals2[TNORMALS_INDEX(x-1, z-1, 1)] + tnormals1[TNORMALS_INDEX(x-1, z, 1)] +
00414 tnormals2[TNORMALS_INDEX(x-1, z, 1)] + tnormals1[TNORMALS_INDEX(x, z-1, 1)] +
00415 tnormals2[TNORMALS_INDEX(x, z-1, 1)] + tnormals1[TNORMALS_INDEX(x, z, 1)]);
00416 TERRAIN_ARRAY(x, z, ARRAY_NORMAL+2) = (tnormals2[TNORMALS_INDEX(x-1, z-1, 2)] + tnormals1[TNORMALS_INDEX(x-1, z, 2)] +
00417 tnormals2[TNORMALS_INDEX(x-1, z, 2)] + tnormals1[TNORMALS_INDEX(x, z-1, 2)] +
00418 tnormals2[TNORMALS_INDEX(x, z-1, 2)] + tnormals1[TNORMALS_INDEX(x, z, 2)]);
00419
00420
00421
00422 normalize(&TERRAIN_ARRAY(x, z, ARRAY_NORMAL));
00423 }
00424 }
00425
00426
00427 delete []tnormals1;
00428 delete []tnormals2;
00429 }
00430
00431 GLfloat Terrain::GetHeight(int x, int y) {
00432 if ((x < m_w) && (y < m_h)) {
00433 return VERTEX(x, y);
00434 } else return 0;
00435 }
00436
00437
00438 unsigned int *Terrain::GenIndexArray(BoundBox *box, int *vertexCount, GLfloat *minHeight, GLfloat *maxHeight, unsigned int *minRange, unsigned int *maxRange) {
00439
00440 GLfloat tMaxHeight = -256;
00441 GLfloat tMinHeight = 256;
00442
00443 unsigned int tMinRange = m_w*m_h+1;
00444 unsigned int tMaxRange = 0;
00445
00446
00447 int xDiff = (int) m_w / 2;
00448 int zDiff = (int) m_h / 2;
00449
00450
00451 int xMin = ((int) box->m_b1->m_x) + xDiff;
00452 int xMax = ((int) box->m_b2->m_x) + xDiff;
00453
00454
00455 int zMin = ((int) box->m_b1->m_z) + zDiff;
00456 int zMax = ((int) box->m_b3->m_z) + zDiff;
00457
00458
00459 int step = -1;
00460 int xEnd;
00461 int x;
00462
00463 int count = 0;
00464
00465
00466
00467 int xCount;
00468 int zCount;
00469
00470
00471 xCount = (int) box->m_b2->m_x - (int) box->m_b1->m_x + 1;
00472 if (zMax >= m_h) {
00473
00474 zCount = (int) box->m_b3->m_z - (int) box->m_b1->m_z - 1;
00475 } else {
00476
00477 zCount = (int) box->m_b3->m_z - (int) box->m_b1->m_z;
00478 }
00479
00480
00481 *vertexCount = (xCount * 2 + 1) * zCount;
00482
00483 unsigned int *indexArray = new unsigned int[*vertexCount];
00484
00485
00486
00487
00488 for (int z = zMin; z < zMax; z++) {
00489
00490 step = -1 * step;
00491 if (step > 0) {
00492 x = xMin;
00493 xEnd = xMax+1;
00494 } else {
00495 x = xMax;
00496 xEnd = xMin-1;
00497 }
00498
00499
00500 if (z+1 < m_h) {
00501
00502 while (x != xEnd) {
00503
00504 if (GetHeight(x, z) > tMaxHeight) tMaxHeight = GetHeight(x, z);
00505 if (GetHeight(x, z) < tMinHeight) tMinHeight = GetHeight(x, z);
00506
00507 if (GetHeight(x, z+1) > tMaxHeight) tMaxHeight = GetHeight(x, z+1);
00508 if (GetHeight(x, z+1) < tMinHeight) tMinHeight = GetHeight(x, z+1);
00509
00510
00511 indexArray[count++] = TERRAIN_ARRAY_INDEX(x, z);
00512 indexArray[count++] = TERRAIN_ARRAY_INDEX(x, z+1);
00513
00514 if ((unsigned int) TERRAIN_ARRAY_INDEX(x, z) > tMaxRange) tMaxRange = TERRAIN_ARRAY_INDEX(x, z);
00515 if ((unsigned int) TERRAIN_ARRAY_INDEX(x, z+1) > tMaxRange) tMaxRange = TERRAIN_ARRAY_INDEX(x, z+1);
00516
00517 if ((unsigned int) TERRAIN_ARRAY_INDEX(x, z) < tMinRange) tMinRange = TERRAIN_ARRAY_INDEX(x, z);
00518 if ((unsigned int) TERRAIN_ARRAY_INDEX(x, z+1) < tMinRange) tMinRange = TERRAIN_ARRAY_INDEX(x, z+1);
00519
00520
00521 x += step;
00522 }
00523
00524
00525 indexArray[count++] = TERRAIN_ARRAY_INDEX(x-step, z+1);
00526 }
00527 }
00528
00529
00530 *maxHeight = tMaxHeight;
00531 *minHeight = tMinHeight;
00532
00533
00534 *minRange = tMinRange;
00535 *maxRange = tMaxRange;
00536
00537 return indexArray;
00538 }
00539
00540 void Terrain::SetGlArrayPointers() {
00541 if (Config::s_config->CheckVBO()) {
00542
00543
00544
00545 glGenBuffers(1, &m_buffer);
00546
00547
00548 glEnableClientState(GL_VERTEX_ARRAY);
00549 glEnableClientState(GL_NORMAL_ARRAY);
00550 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00551 glClientActiveTexture(GL_TEXTURE1);
00552 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00553
00554
00555 glBindBuffer(GL_ARRAY_BUFFER_ARB, m_buffer);
00556 glBufferData(GL_ARRAY_BUFFER_ARB, m_w*m_h*(3+3+2+2)*sizeof(GL_FLOAT), m_terrainArray, GL_STATIC_DRAW_ARB);
00557
00558
00559 char *t = NULL;
00560
00561
00562 glVertexPointer(3, GL_FLOAT, ARRAY_STRIDE, &t[ARRAY_VERTEX*sizeof(GL_FLOAT)]);
00563
00564
00565 glNormalPointer(GL_FLOAT, ARRAY_STRIDE, &t[ARRAY_NORMAL*sizeof(GL_FLOAT)]);
00566
00567
00568 glClientActiveTexture(GL_TEXTURE0);
00569 glTexCoordPointer(2, GL_FLOAT, ARRAY_STRIDE, &t[ARRAY_TEX0*sizeof(GL_FLOAT)]);
00570
00571
00572 glClientActiveTexture(GL_TEXTURE1);
00573 glTexCoordPointer(2, GL_FLOAT, ARRAY_STRIDE, &t[ARRAY_TEX1*sizeof(GL_FLOAT)]);
00574 } else {
00575
00576
00577
00578 glEnableClientState(GL_VERTEX_ARRAY);
00579 glVertexPointer(3, GL_FLOAT, ARRAY_STRIDE, &TERRAIN_ARRAY(0, 0, ARRAY_VERTEX));
00580
00581 glEnableClientState(GL_NORMAL_ARRAY);
00582 glNormalPointer(GL_FLOAT, ARRAY_STRIDE, &TERRAIN_ARRAY(0, 0, ARRAY_NORMAL));
00583
00584 glClientActiveTexture(GL_TEXTURE0);
00585 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00586 glTexCoordPointer(2, GL_FLOAT, ARRAY_STRIDE, &TERRAIN_ARRAY(0, 0, ARRAY_TEX0));
00587
00588 glClientActiveTexture(GL_TEXTURE1);
00589 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00590 glTexCoordPointer(2, GL_FLOAT, ARRAY_STRIDE, &TERRAIN_ARRAY(0, 0, ARRAY_TEX1));
00591 }
00592 }
00593
00594 void Terrain::GetMinMax(BoundBox *box, GLfloat *minHeight, GLfloat *maxHeight) {
00595
00596 GLfloat tHigh = 0;
00597 GLfloat tLow = 0;
00598
00599
00600 int xDiff = (int) m_w / 2;
00601 int zDiff = (int) m_h / 2;
00602
00603
00604 int startX = ((int) box->m_b1->m_x) + xDiff;
00605 int endX = ((int) box->m_b2->m_x) + xDiff;
00606 int startZ = ((int) box->m_b1->m_z) + zDiff;
00607 int endZ = ((int) box->m_b3->m_z) + zDiff;
00608
00609
00610 for (int z = startZ; z < endZ; z++) {
00611 for (int x = startX; x < endX; x++) {
00612
00613
00614 if (VERTEX(x, z) > tHigh) tHigh = VERTEX(x, z);
00615 if (VERTEX(x, z) < tLow) tLow = VERTEX(x, z);
00616 }
00617 }
00618
00619
00620 *maxHeight = tHigh;
00621 *minHeight = tLow;
00622 }
00623
00624 GLfloat Terrain::CalcHeight(GLfloat x, GLfloat z) {
00625
00626
00627 int tempXCoord, tempZCoord;
00628
00629 int xCoord = (int) x;
00630 int zCoord = (int) z;
00631
00632 if ((x >= m_w) || (z >= m_h)) {
00633
00634 Log::s_log->Message("Warning: x (%d) or z (%d) too large in calcHeight", x, z);
00635 return 0;
00636 }
00637 if ((x < 0) || (z < 0)) {
00638
00639 Log::s_log->Message("Warning: x (%d) or z (%d) less than zero in calcHeight", x, z);
00640 return 0;
00641 }
00642
00643 if (xCoord + 1 < m_w) {
00644 tempXCoord = xCoord + 1;
00645 } else {
00646 tempXCoord = xCoord;
00647 }
00648
00649 if (zCoord + 1 < m_h) {
00650 tempZCoord = zCoord + 1;
00651 } else {
00652 tempZCoord = zCoord;
00653 }
00654
00655 double orig[3] = {x, 128, z};
00656 double ray[3] = {0, -1, 0};
00657 double vert0[3] = {xCoord, VERTEX(xCoord, zCoord), zCoord};
00658 double vert1[3] = {xCoord+1, VERTEX(tempXCoord, zCoord), zCoord};
00659 double vert2[3] = {xCoord, VERTEX(xCoord, tempZCoord), zCoord+1};
00660 double vert3[3] = {xCoord+1, VERTEX(tempXCoord, tempZCoord), zCoord+1};
00661 double r1, r2, r3;
00662
00663 if (intersect_triangle(orig, ray, vert0, vert2, vert1, &r1, &r2, &r3)) {
00664 return 128 - r1;
00665 }
00666 if (intersect_triangle(orig, ray, vert2, vert3, vert1, &r1, &r2, &r3)) {
00667 return 128 - r1;
00668 }
00669
00670
00671
00672 cout << "Problem!" << endl;
00673 return 0;
00674 }
00675
00676 int Terrain::GetWidth() {
00677 return m_w;
00678 }
00679
00680 int Terrain::GetHeight() {
00681 return m_h;
00682 }
00683
00684 void Terrain::CalcNormals2(std::string file) {
00685 SDL_Surface *Image;
00686 Uint8 *p;
00687
00688
00689 Image = IMG_Load(file.c_str());
00690 if (!Image) {
00691 throw string("Could not load normals from " + file);
00692 }
00693
00694
00695 if ((Image->w != m_w) || (Image->h != m_h)) {
00696 throw string("Normal map and heightmap not the same size");
00697 }
00698
00699
00700 if (m_terrainArray == NULL) return;
00701
00702 p = (Uint8 *) Image->pixels;
00703
00704 for (int y = 0; y < Image->h; y++){
00705 for (int x = 0; x < Image->w; x++){
00706
00707
00708
00709
00710 TERRAIN_ARRAY(x, y, ARRAY_NORMAL+0) = ((double) p[(y*Image->w + x)*Image->format->BytesPerPixel + 2*y] / 255) * 2 - 1;
00711 TERRAIN_ARRAY(x, y, ARRAY_NORMAL+1) = ((double) p[(y*Image->w + x)*Image->format->BytesPerPixel + 2*y + 1] / 255) * 2 - 1;
00712 TERRAIN_ARRAY(x, y, ARRAY_NORMAL+2) = ((double) p[(y*Image->w + x)*Image->format->BytesPerPixel + 2*y + 2] / 255) * 2 - 1;
00713
00714
00715
00716
00717 normalize(&TERRAIN_ARRAY(x, y, ARRAY_NORMAL));
00718 }
00719 }
00720
00721
00722 SDL_FreeSurface(Image);
00723 }
00724
00725
00726
00727
00728
00729 void Terrain::LocateShoreLine(BoundBox *box, list< Point* > *pointList) {
00730 bool insert;
00731
00732
00733 int xDiff = (int) m_w / 2;
00734 int zDiff = (int) m_h / 2;
00735
00736
00737 int startX = ((int) box->m_b1->m_x) + xDiff;
00738 int endX = ((int) box->m_b2->m_x) + xDiff;
00739 int startZ = ((int) box->m_b1->m_z) + zDiff;
00740 int endZ = ((int) box->m_b3->m_z) + zDiff;
00741
00742 if (startX < 1) startX = 1;
00743 if (endX > m_w-2) endX = m_w-2;
00744 if (startZ < 1) startZ = 1;
00745 if (endZ > m_h-2) endZ = m_h-2;
00746
00747
00748 for (int z = startZ; z < endZ; z++) {
00749 for (int x = startX; x < endX; x++) {
00750
00751
00752 insert = false;
00753
00754
00755 if (TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1) > 0) continue;
00756
00757 if (TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1) == 0) insert = true;
00758
00759 if (TERRAIN_ARRAY(x+1, z, ARRAY_VERTEX+1) > 0) insert = true;
00760 else if (TERRAIN_ARRAY(x-1, z, ARRAY_VERTEX+1) > 0) insert = true;
00761 else if (TERRAIN_ARRAY(x, z+1, ARRAY_VERTEX+1) > 0) insert = true;
00762 else if (TERRAIN_ARRAY(x, z-1, ARRAY_VERTEX+1) > 0) insert = true;
00763
00764
00765
00766 if (insert) {
00767 pointList->push_back(new Point(x-xDiff, 0, z-zDiff));
00768 }
00769 }
00770 }
00771 }
00772
00773 bool Terrain::FindNearestShoreAngle(Point *p, float *angle) {
00774 int dX = m_w/2;
00775 int dZ = m_h/2;
00776
00777 int pX = (int)p->m_x+dX;
00778 int pZ = (int)p->m_z+dZ;
00779
00780 double orig[3] = {pX, 0, pZ};
00781 double ray[3];
00782 double vert0[3];
00783 double vert1[3];
00784 double vert2[3];
00785 double vert3[3];
00786 double r1, r2, r3;
00787
00788 int minAngle = 0;
00789 double minDX;
00790 double minDZ;
00791 double minDist = 100.0;
00792
00793 double tempAngleRadians;
00794
00795 float height = CalcHeight(pX, pZ);
00796 if (height > -.0001) return false;
00797
00798
00799 for (int tempAngle = 0; tempAngle < 360; tempAngle++) {
00800 tempAngleRadians = degreesToRadians(tempAngle);
00801 ray[0] = sin(tempAngleRadians);
00802 ray[1] = 0;
00803 ray[2] = cos(tempAngleRadians);
00804
00805
00806 for (int z = pZ-1; z < pZ+1; z++) {
00807 for (int x = pX-1; x < pX+1; x++) {
00808 vert0[0] = x;
00809 vert0[1] = TERRAIN_ARRAY(x, z, ARRAY_VERTEX+1);
00810 vert0[2] = z;
00811
00812 vert1[0] = x+1;
00813 vert1[1] = TERRAIN_ARRAY(x+1, z, ARRAY_VERTEX+1);
00814 vert1[2] = z;
00815
00816 vert2[0] = x;
00817 vert2[1] = TERRAIN_ARRAY(x, z+1, ARRAY_VERTEX+1);
00818 vert2[2] = z+1;
00819
00820 vert3[0] = x+1;
00821 vert3[1] = TERRAIN_ARRAY(x+1, z+1, ARRAY_VERTEX+1);
00822 vert3[2] = z+1;
00823
00824 if (intersect_triangle(orig, ray, vert0, vert2, vert1, &r1, &r2, &r3)) {
00825 if ((r1 < minDist) && (r1 > 0)) {
00826 minDist = r1;
00827 minAngle = tempAngle;
00828 }
00829 }
00830 if (intersect_triangle(orig, ray, vert2, vert3, vert1, &r1, &r2, &r3)) {
00831 if ((r1 < minDist) && (r1 > 0)) {
00832 minDist = r1;
00833 minAngle = tempAngle;
00834 }
00835 }
00836 }
00837 }
00838 }
00839
00840 if (minDist == 100) return false;
00841
00842
00843 tempAngleRadians = degreesToRadians((double) minAngle);
00844 minDX = sin(tempAngleRadians) * minDist;
00845 minDZ = cos(tempAngleRadians) * minDist;
00846
00847
00848 p->m_x += minDX;
00849 p->m_y = 0;
00850 p->m_z += minDZ;
00851
00852 *angle = minAngle;
00853
00854 return true;
00855 }
00856