src/Terrain.cc
changeset 255 99431fdb0dc8
parent 248 e40ef56dc62c
child 282 e0e4dfc3e528
--- a/src/Terrain.cc	Sun Dec 07 19:59:25 2008 +0000
+++ b/src/Terrain.cc	Sun Dec 07 20:07:28 2008 +0000
@@ -1,4 +1,5 @@
 #include "Terrain.hh"
+#include "Graphics.hh"
 #include "Engine.hh"
 
 #include <cmath>
@@ -6,17 +7,30 @@
 #include <algorithm>
 #include <ClanLib/display.h>
 
-Terrain::Terrain() {}
-Terrain::Terrain(const int &seed) 
-    : terrain(MAP_WIDTH, std::vector<TerrainType>(MAP_HEIGHT, DIRT)){
-    this->generateTerrain(seed);
-}
-Terrain::Terrain(const Terrain &t) {
-    this->terrain = t.getTerrain();
-    this->generatePixelBuffer();
+Terrain::Terrain (void) :
+    map_width(0), map_height(0)
+{
 }
 
-void fractal_step(std::vector<double>& land, int size, double str, int dist) {
+Terrain::Terrain (PixelDimension map_width, PixelDimension map_height, int seed) :
+    map_width(map_width), map_height(map_height), terrain(map_width, std::vector<TerrainType>(map_height, TERRAIN_DIRT))
+{
+    generateTerrain(seed);
+}
+
+Terrain::Terrain (const Terrain &t) 
+{
+    map_width = t.map_width;
+    map_height = t.map_height;
+    terrain = t.terrain;
+
+    generatePixelBuffer();
+}
+
+/*
+ * Texture generation util functions
+ */
+static void fractal_step(std::vector<double>& land, int size, double str, int dist) {
     for(int i = 0; i < size; i += dist*2) {
         for(int j = dist; j < size; j += dist*2) {
             double sum = 0;
@@ -38,7 +52,8 @@
         }
     }
 }
-void fractal_diamond(std::vector<double>& land, int size, double str, int dist) {
+
+static void fractal_diamond(std::vector<double>& land, int size, double str, int dist) {
     for(int i = dist; i < size; i += dist*2) {
         for(int j = dist; j < size; j += dist*2) {
             double sum = 0;
@@ -54,7 +69,7 @@
 /**
  * Algorithm read from http://www.gameprogrammer.com/fractal.html
  */
-void Terrain::generate_texture() {
+void Terrain::generate_texture (void) {
     int texturesize = 128;
     texture = std::vector<std::vector<int> >(texturesize, std::vector<int>(texturesize));
     std::vector<double> land(texture.size()*texture.size());
@@ -85,27 +100,31 @@
  * Changes color depending on x and y values
  * x and y should be valid coordinates (not outside)
  */
-void Terrain::noisifyPixel(CL_Color& color, int x, int y) {
-    int tx = x%texture.size();
-    int ty = y%texture[0].size();
+void Terrain::noisifyPixel(CL_Color& color, PixelCoordinate pc) {
+    int tx = pc.x % texture.size();
+    int ty = pc.y % texture[0].size();
     int red = color.get_red();
     int green = color.get_green();
     int blue = color.get_blue();
-    red += texture[tx][ty]/8-16;
-    green += texture[tx][ty]/8-16;
-    blue += texture[tx][ty]/8-16;
-    if(red < 0)
+
+    red += texture[tx][ty] / 8 - 16;
+    green += texture[tx][ty] / 8 - 16;
+    blue += texture[tx][ty] / 8 - 16;
+
+    if (red < 0)
         red = 0;
-    if(red >= 256)
+    else if (red >= 256)
         red = 255;
-    if(green < 0)
+
+    if (green < 0)
         green = 0;
-    if(blue >= 256)
+    else if (green >= 256)
+        green = 255;
+
+    if (blue < 0)
+        blue = 0;
+    else if (blue >= 256)
         blue = 255;
-    if(blue < 0)
-        blue = 0;
-    if(green >= 256)
-        green = 255;
 
     color = CL_Color(red, green, blue);
 }
@@ -113,137 +132,156 @@
 /**
  * Sets to color the correct color of pixel in (x,y)
  */
-void Terrain::loadPixelColor(CL_Color& color, int x, int y) {
-    if ((x < 0) || (y < 0) ||(x >= MAP_WIDTH) || (y >= MAP_HEIGHT)) {
+void Terrain::loadPixelColor(CL_Color& color, PixelCoordinate pc) {
+    if ((pc.x < 0) || (pc.y < 0) || (pc.x >= map_width) || (pc.y >= map_height)) {
         color = CL_Color(0, 0, 0);
         return;
     }
-    switch(terrain[x][y]) {
-    case EMPTY:
+
+    switch (terrain[pc.x][pc.y]) {
+    case TERRAIN_EMPTY:
         color = COLOR_EMPTY;
-        noisifyPixel(color, x, y);
         break;
-    case DIRT:
+
+    case TERRAIN_DIRT:
         color = COLOR_DIRT;
-        noisifyPixel(color, x, y);
         break;
-    case ROCK:
+
+    case TERRAIN_ROCK:
         color = COLOR_ROCK;
-        noisifyPixel(color, x, y);
         break;
     }
+        
+    noisifyPixel(color, pc);
 }
 
-void Terrain::generatePixelBuffer() {
+void Terrain::generatePixelBuffer (void) {
+    // initialze texture
     generate_texture();
-    this->pixbuf = CL_PixelBuffer(MAP_WIDTH, MAP_HEIGHT, 4*MAP_WIDTH, 
-                                  CL_PixelFormat::rgba8888);
+
+    // create pixel buffer
+    pixbuf = CL_PixelBuffer(map_width, map_height, 4 * map_width, CL_PixelFormat::rgba8888);
 
     CL_Color color;
-    for (uint16_t i = 0; i < MAP_WIDTH; i++) {
-        for (uint16_t j = 0; j < MAP_HEIGHT; j++) {
-            switch(terrain[i][j]) {
-            case EMPTY:
-                color = COLOR_EMPTY;
-                break;
-            case DIRT:
-                color = COLOR_DIRT;
-                break;
-            case ROCK:
-                color = COLOR_ROCK;
-                break;
-            default: // TODO: Shouldn't be here.
-                break; 
-            }
-            loadPixelColor(color, i, j);
-            this->pixbuf.draw_pixel(i, j, color);
+
+    for (PixelDimension x = 0; x < map_width; x++) {
+        for (PixelDimension y = 0; y < map_height; y++) {
+            PixelCoordinate pc(x, y);
+
+            loadPixelColor(color, pc);
+
+            pixbuf.draw_pixel(pc.x, pc.y, color);
         }
     }
 }
 
-Vector Terrain::getPixelLocation(Vector point) const{
-    return Vector(scale(point.x), 
-                  scale(point.y));
-}
-
-uint16_t Terrain::scale(float x) const {
-    return (uint16_t)(x/MAP_SCALE);
+PixelCoordinate Terrain::getPixelCoordinate (Vector point) const {
+    return PixelCoordinate(point.x, point.y);
 }
 
-TerrainType Terrain::getType(int32_t x, int32_t y) const {
-    if ((x < 0) || (y < 0) ||(x >= MAP_WIDTH) || (y >= MAP_HEIGHT)) {
-        return ROCK;
-    }
-    return terrain[x][y];
-}
-TerrainType Terrain::getType(Vector point) const {
-    return getType((int32_t)point.x, (int32_t)point.y);
+PixelCoordinate Terrain::getDimensions (void) const {
+    return PixelCoordinate(map_width, map_height);
 }
 
-bool Terrain::collides(const Vector &point) const {
-    return (getType(point) != EMPTY);
+TerrainType Terrain::getType (PixelDimension px, PixelDimension py) const {
+    if ((px < 0) || (py < 0) ||(px >= map_width) || (py >= map_height))
+        return TERRAIN_ROCK;
+
+    return terrain[px][py];
 }
 
-bool Terrain::collides(const Vector &begin, const Vector &end) const {
+TerrainType Terrain::getType (PixelCoordinate pc) const {
+    return getType(pc.x, pc.y);
+}
+
+TerrainType Terrain::getType (Vector point) const {
+    return getType((PixelDimension) point.x, (PixelDimension) point.y);
+}
+
+bool Terrain::collides (const Vector &point) const {
+    return (getType(point) != TERRAIN_EMPTY);
+}
+
+bool Terrain::collides (const Vector &begin, const Vector &end) const {
     // TODO: Maybe we should have another function prototype that also
     // returns the point where we collided.
 
     // We'll use Bresenhams line algorithm to go trough all the
     // "pixels" of the line.
-    Vector b = getPixelLocation(begin);
-    Vector e = getPixelLocation(end);
+    PixelCoordinate b = getPixelCoordinate(begin);
+    PixelCoordinate e = getPixelCoordinate(end);
 
     bool steep = (abs(e.y - b.y) > abs(e.x - b.x)); // k > 1
-    if (steep) { // Line is steep -> swap x and y coordinates
+
+    if (steep) { 
+        // Line is steep -> swap x and y coordinates
         std::swap(b.x, b.y);
         std::swap(e.x, e.y);
     }
-    if (b.x > e.x) { // Line goes down -> make it go up
+
+    if (b.x > e.x) { 
+        // Line goes down -> make it go up
         std::swap(b, e);
     }
-    uint16_t dx = e.x - b.x;
-    uint16_t dy = abs(e.y - b.y);
-    int32_t err = dx/2;
-    uint16_t ystep;
-    uint16_t y = b.y;
+
+    PixelDimension dx = e.x - b.x, dy = abs(e.y - b.y);
+    PixelDimension err = dx / 2;
+    PixelDimension ystep, y = b.y;
+
     // Is the line ascending or descending
-    if (b.y < e.y) ystep = 1;
-    else ystep = -1;
+    if (b.y < e.y) 
+        ystep = 1;
+
+    else 
+        ystep = -1;
+
     // Go trough the line
-    for (uint16_t x =  b.x; x <= e.x; x++) {
-        if (steep) { // X and Y coordinates must be switched if steep
-            if (getType(y,x) != EMPTY) { // Collision!
+    for (PixelDimension x =  b.x; x <= e.x; x++) {
+        if (steep) { 
+            // X and Y coordinates must be switched if steep
+            if (getType(y, x) != TERRAIN_EMPTY) { 
+                // Collision!
                 return true;
             }
         } else {
-            if (getType(x,y) != EMPTY) { // Collision!
+            if (getType(x, y) != TERRAIN_EMPTY) { 
+                // Collision!
                 return true;
             }
         }
+
         err = err - dy;
-        if (err < 0) { // Check if we want to make an ystep
+
+        if (err < 0) { 
+            // Check if we want to make an ystep
             y = y + ystep;
             err = err + dx;
         }
     }
+
     return false; // No Collision
 }
 
-void Terrain::removeGround(const Vector &pos, const float &radius) {
+void Terrain::removeGround (const Vector &pos, float radius) {
     // TODO: Implement. Some circle algoritmh should be usefull here,
     // though the current impelementation doesn't seem too bad either.
 
-    Vector mid = getPixelLocation(pos);
-    uint16_t r = scale(radius);
-    for (uint16_t i = mid.x-r; i < mid.x+r; i++) {
-        for (uint16_t j = mid.y-r; j < mid.y+r; j++) {
-            if (getType(i, j) != ROCK) { // getType returns ROCK if
-                                         // out of bounds
-                if ((i-mid.x)*(i-mid.x)+(j-mid.y)*(j-mid.y) < r*r) {
-                    terrain[i][j] = EMPTY;
-                    CL_Color color(0, 0, 0);
-                    loadPixelColor(color, i, j);
-                    pixbuf.draw_pixel(i, j, color);
+    PixelCoordinate mid = getPixelCoordinate(pos);
+    PixelDimension r = radius;
+
+    for (PixelDimension i = mid.x - r; i < mid.x + r; i++) {
+        for (PixelDimension j = mid.y-r; j < mid.y+r; j++) {
+            PixelCoordinate pc(i, j);
+
+            if (getType(pc) != TERRAIN_ROCK) { 
+                // getType returns ROCK if out of bounds
+
+                if ((i - mid.x) * (i - mid.x) + (j - mid.y) * (j - mid.y) < r * r) {
+                    terrain[i][j] = TERRAIN_EMPTY;
+
+                    CL_Color color;
+                    loadPixelColor(color, pc);
+                    pixbuf.draw_pixel(pc.x, pc.y, color);
                 }
             }
         }
@@ -254,25 +292,26 @@
  * Gets the index of the given coordinate direction
  * referring to the DIRECTIONS table in Physics.hh
  */
-int getDirectionIndex (Vector direction) {
+static int getDirectionIndex (Vector direction) {
     Vector dir = direction.roundToInt();
     if(dir.x == 0 && dir.y == -1) {
         return 0;
-    } else if(dir.x == 1 && dir.y == -1) {
+    } else if (dir.x == 1 && dir.y == -1) {
         return 1;
-    } else if(dir.x == 1 && dir.y == 0) {
+    } else if (dir.x == 1 && dir.y == 0) {
         return 2;
-    } else if(dir.x == 1 && dir.y == 1) {
+    } else if (dir.x == 1 && dir.y == 1) {
         return 3;
-    } else if(dir.x == 0 && dir.y == 1) {
+    } else if (dir.x == 0 && dir.y == 1) {
         return 4;
-    } else if(dir.x == -1 && dir.y == 1) {
+    } else if (dir.x == -1 && dir.y == 1) {
         return 5;
-    } else if(dir.x == -1 && dir.y == 0) {
+    } else if (dir.x == -1 && dir.y == 0) {
         return 6;
-    } else if(dir.x == -1 && dir.y == -1) {
+    } else if (dir.x == -1 && dir.y == -1) {
         return 7;
     }
+
     Engine::log(DEBUG, "Terrain.getDirectionIndex ") << "invalid direction: " << direction;
     return 0;
 }
@@ -283,7 +322,7 @@
  * @param prevPoint - pixel where we are when we collide
  */
 Vector Terrain::getNormal(Vector point, Vector prevPoint) const {
-    Vector p = getPixelLocation(point);
+    PixelCoordinate p = getPixelCoordinate(point);
 
     assert(point != prevPoint);
 
@@ -291,54 +330,44 @@
 
     // These two must be rounded separately
     int dirIdx = getDirectionIndex(prevPoint.roundToInt() - point.roundToInt());
-//    dirIdx = (dirIdx+4)%8;
 
     normal += DIRECTIONS[dirIdx];
+
     for (int i = 1; i <= 2; i++) {
-        if(getType(point + DIRECTIONS[(dirIdx+i+8)%8]) == EMPTY) {
+        if (getType(point + DIRECTIONS[(dirIdx+i+8)%8]) == TERRAIN_EMPTY) {
             normal += DIRECTIONS[(dirIdx+i+8)%8];
         }
     }
+
     for (int i = 1; i <= 2; i++) {
-        if(getType(point + DIRECTIONS[(dirIdx-i+8)%8]) == EMPTY) {
+        if (getType(point + DIRECTIONS[(dirIdx-i+8)%8]) == TERRAIN_EMPTY) {
             normal += DIRECTIONS[(dirIdx-i+8)%8];
         }
     }
 
-    if (getType(point) == EMPTY || getType(prevPoint) != EMPTY) {
+    if (getType(point) == TERRAIN_EMPTY || getType(prevPoint) != TERRAIN_EMPTY) {
         Engine::log(DEBUG, "Physics.getNormal ") << "logic ground error";
     }
     
-
-//    for (int i = 0; i < 8; i++) {
-//        if (getType(p.x+DIRECTIONS[i].x, p.y+DIRECTIONS[i].y) == EMPTY) {
-//            normal += DIRECTIONS[i];
-//        }
-//    }
-
-   
-    // Special cases
-    /*    Vector tmp = direction(direction(prevPoint-point) + direction(normal));
-    Engine::log(DEBUG, "Terrain.getNormal") << "tmp: " << tmp;
-    if (normal.length() == 0 || (tmp.x != 0 && tmp.y != 0 && getType(tmp.x, tmp.y) != EMPTY)) 
-        normal = prevPoint - point; // Direct hit
-    */
-//    Engine::log(DEBUG, "Terrain.getNormal") << "Normal: " << normal;
     return normal;
-    return Vector(0,-1);
 }
 
-Vector direction(const Vector &v) {
+// XXX: weird vectors
+Vector direction (const Vector &v) {
     Vector tmp(v);
-    if (tmp.length() > 0) tmp /= tmp.length();
+
+    if (tmp.length() > 0) 
+        tmp /= tmp.length();
+
     tmp.x = (uint16_t)(tmp.x);
     tmp.y = (uint16_t)(tmp.y);
+
     return tmp;
 }
 
 // TODO: This could better :)
 // TODO: And this need some cleaning :)
-void Terrain::generateTerrain(int seed) {
+void Terrain::generateTerrain (int seed) {
     srand(seed); // Set random number generator seed.
 
     // Some constants to control random generation
@@ -350,48 +379,49 @@
     // Generate circles (or whatever)
     for (int i = 0; i < num; i++) {
         // Random generate circle attributes
-        int midx = rand()%MAP_WIDTH;
-        int midy = rand()%MAP_HEIGHT;
+        PixelCoordinate mid(rand() % map_width, rand() % map_width);
+
         int range = rand()%(max_range-min_range)+min_range;
 
         // Make sure that there's a circle in the midle of the cave
         if (i == 0) {
-            midx = MAP_WIDTH/2;
-            midy = MAP_WIDTH/2;
+            mid.x = map_width / 2;
+            mid.y = map_height / 2;
             range = 150;
         }
 
-        TerrainType type = EMPTY;
-        if (rand()%rock_rarity == 0) {
-            type = ROCK;
+        TerrainType type = TERRAIN_EMPTY;
+
+        if (rand() % rock_rarity == 0) {
+            type = TERRAIN_ROCK;
         }
 
         // Loops for every pixel of the cirlcle (or square as it seems
         // now)
-        for (int x = std::max(0, midx-range); 
-             x < std::min((int32_t)MAP_WIDTH, midx+range); 
-             x++) {
-            for (int y = std::max(0, midy-range);
-                    y < std::min((int32_t)MAP_HEIGHT, midy+range);
-                    y++) {
-                
-                //terrain[x][y] = type;
-
-                if ((x-midx)*(x-midx)+(y-midy)*(y-midy) < range*range) {
+        for (
+            PixelDimension x = std::max((PixelDimension) 0, mid.x - range); 
+            x < std::min(map_width, mid.x + range); 
+            x++
+        ) {
+            for (
+                PixelDimension y = std::max((PixelDimension) 0, mid.y - range);
+                y < std::min(map_height, mid.y + range);
+                y++
+            ) {
+                if ((x - mid.x) * (x - mid.x) + (y - mid.y) * (y - mid.y) < range * range) {
                     terrain[x][y] = type;
                 }
             }
-            
         } 
-        
     }
     
+    // regenerate pixel buffer
     this->generatePixelBuffer();
 }
 
-void Terrain::draw(CL_GraphicContext *gc, Vector camera) {
-    CL_Surface surf(this->pixbuf);
-    surf.draw((int)-camera.x, (int)-camera.y ,gc);
+void Terrain::draw (Graphics *g, PixelCoordinate camera) {
+    CL_Surface surf (pixbuf);
+    surf.draw(-camera.x, -camera.y, g->get_gc());
 }
 
 std::vector<std::vector<TerrainType> > Terrain::getTerrain() const {