# HG changeset patch # User Tero Marttila # Date 1232481624 -7200 # Node ID a2e35ca66c741cee3d77b41a9df92919bd408da8 # Parent 7a8c7a0a12617083cab18a690da0cfb5acd3380a cleanup Terrain, use a single linear array instead of nested vectors diff -r 7a8c7a0a1261 -r a2e35ca66c74 src/Network/Client.cc --- a/src/Network/Client.cc Sat Jan 17 02:58:36 2009 +0200 +++ b/src/Network/Client.cc Tue Jan 20 22:00:24 2009 +0200 @@ -34,7 +34,7 @@ // the terrain byte array size_t terrain_size = map_w * map_h; - uint8_t terrain_buf[map_w][map_h]; + uint8_t terrain_buf[map_w * map_h]; // read uncompressed terrain data size_t inflate_size = pkt.read_uncompressed(terrain_buf, terrain_size); @@ -43,15 +43,12 @@ if (inflate_size != terrain_size) throw Error("Corrupt terrain data"); - // translate map data to terrain vector - for (PixelDimension x = 0; x < map_w; x++) { - for (PixelDimension y = 0; y < map_h; y++) { - terrain.terrain[x][y] = (TerrainType) terrain_buf[x][y]; - } - } + // XXX: rework access + if (terrain.getDimensions() != PixelCoordinate(map_w, map_h)) + throw Error("terrain is of the wrong size"); - // update the pixbuf - terrain.generatePixelBuffer(); + // load into terrain + terrain.loadFromBuffer(terrain_buf); } void NetworkClient::player_quit (NetworkClientRemotePlayer *player) { diff -r 7a8c7a0a1261 -r a2e35ca66c74 src/Network/Server.cc --- a/src/Network/Server.cc Sat Jan 17 02:58:36 2009 +0200 +++ b/src/Network/Server.cc Tue Jan 20 22:00:24 2009 +0200 @@ -240,14 +240,9 @@ // translate to a byte array size_t terrain_size = map.x * map.y; - uint8_t terrain_buf[map.x][map.y]; - // copy over from terrain vector - for (PixelDimension x = 0; x < map.x; x++) { - for (PixelDimension y = 0; y < map.y; y++) { - terrain_buf[x][y] = (uint8_t) terrain.terrain[x][y]; - } - } + // get terrain buffer + const uint8_t *terrain_buf = terrain.getTerrainBuffer(); // allocate our packet... BigNetworkPacket pkt ( diff -r 7a8c7a0a1261 -r a2e35ca66c74 src/Terrain.cc --- a/src/Terrain.cc Sat Jan 17 02:58:36 2009 +0200 +++ b/src/Terrain.cc Tue Jan 20 22:00:24 2009 +0200 @@ -19,205 +19,251 @@ }; Terrain::Terrain (void) : - map_width(0), map_height(0) + terrain_buf(NULL), width(0), height(0) { } -Terrain::Terrain (PixelDimension map_width, PixelDimension map_height, int seed) : - terrain(map_width, std::vector(map_height, TERRAIN_DIRT)), - map_width(map_width), - map_height(map_height) +Terrain::Terrain (PixelDimension width, PixelDimension height, int seed) : + terrain_buf(NULL), + width(width), + height(height) { + // allocate+generate random terrain generateTerrain(seed); } -Terrain::Terrain (const Terrain &t) -{ - map_width = t.map_width; - map_height = t.map_height; - terrain = t.terrain; +Terrain::~Terrain (void) { + // free terrain data + delete[] terrain_buf; +} +void Terrain::generateTerrain (int seed) { + // shouldn't be generated yet + assert(!terrain_buf); + + // set random number generator seed. + srand(seed); + + // allocate terrain buffer + terrain_buf = new TerrainPixel[width * height]; + + // fill with dirt + memset(terrain_buf, TERRAIN_DIRT, width * height); + + // some constants to control random generation + const int min_range = 25; + const int max_range = 80; + const int num = 50; + const int rock_rarity = 4; + + // generate \a num random circles + for (int i = 0; i < num; i++) { + // circle origin + PixelCoordinate mid (rand() % width, rand() % height); + + // radius + int range = rand() % (max_range - min_range) + min_range; + + // circle type + TerrainType type = TERRAIN_EMPTY; + + // tweak to make sure that there's a circle in the midle of the cave + if (i == 0) { + mid.x = width / 2; + mid.y = height / 2; + range = 150; + + } else if (rand() % rock_rarity == 0) { + // some rock + type = TERRAIN_ROCK; + } + + // iterate over the area of the circle + for ( + PixelDimension y = std::max((PixelDimension) 0, mid.y - range); + y < std::min(height, mid.y + range); + y++ + ) { + for ( + PixelDimension x = std::max((PixelDimension) 0, mid.x - range); + x < std::min(width, mid.x + range); + x++ + ) { + // inside radius? + if ((x - mid.x) * (x - mid.x) + (y - mid.y) * (y - mid.y) < range * range) + terrain_buf[y * width + x] = (TerrainPixel) type; + } + } + } + + // update pixel buffer generatePixelBuffer(); } -/* - * Texture generation util functions - */ -static void fractal_step(std::vector& 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; - sum += land[((i+size-dist)%size)+(j*size)]; - sum += land[i+((j+size-dist)%size)*size]; - sum += land[((i+dist)%size)+j*size]; - sum += land[i+((j+dist)%size)*size]; - land[i+j*size] = sum/4 + (rand()%10000-5000)*str; - } - } - for(int i = dist; i < size; i += dist*2) { - for(int j = 0; j < size; j += dist*2) { - double sum = 0; - sum += land[((i+size-dist)%size)+(j*size)]; - sum += land[i+((j+size-dist)%size)*size]; - sum += land[((i+dist)%size)+j*size]; - sum += land[i+((j+dist)%size)*size]; - land[i+j*size] = sum/4 + (rand()%10000-5000)*str; +void Terrain::generatePixelBuffer (void) { + // initialize textures + generateTexture(); + + // create the pixel buffer of the correct size + pixbuf = CL_PixelBuffer(width, height, 4 * width, CL_PixelFormat::rgba8888); + + // iterate over each pixel + for (PixelDimension x = 0; x < width; x++) { + for (PixelDimension y = 0; y < height; y++) { + // draw textureized pixel color + pixbuf.draw_pixel(x, y, getTexturePixel(x, y)); } } } -static void fractal_diamond(std::vector& 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) { +/* + * Texture generation utility functions + */ +static void fractal_step (std::vector& 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; - sum += land[((i+size-dist)%size)+(((j+size-dist)%size)*size)]; - sum += land[((i+dist)%size)+((j+size-dist)%size)*size]; - sum += land[(i+size-dist)%size+((j+dist)%size)*size]; - sum += land[(i+dist)%size+((j+dist)%size)*size]; - land[i+j*size] = sum/4 + (rand()%10000-5000)*str; + sum += land[(i + size - dist) % size + j * size]; + sum += land[i + ((j + size - dist) % size) * size]; + sum += land[(i + dist) % size + j * size]; + sum += land[i + ((j + dist) % size) * size]; + land[i + j * size] = sum / 4 + (rand() % 10000 - 5000) * str; + } + } + for (int i = dist; i < size; i += dist * 2) { + for (int j = 0; j < size; j += dist * 2) { + double sum = 0; + sum += land[(i + size - dist) % size + j * size]; + sum += land[i + ((j + size - dist) % size) * size]; + sum += land[(i + dist) % size + j * size]; + sum += land[i + ((j + dist) % size) * size]; + land[i + j * size] = sum / 4 + (rand() % 10000 - 5000) * str; } } } -void Terrain::generate_texture (void) { +static void fractal_diamond (std::vector& 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; + sum += land[(i + size - dist) % size + ((j + size - dist) % size) * size]; + sum += land[(i + dist) % size + ((j + size - dist) % size) * size]; + sum += land[(i + size - dist) % size + ((j + dist) % size) * size]; + sum += land[(i + dist) % size + ((j + dist) % size) * size]; + land[i + j * size] = sum / 4 + (rand() % 10000 - 5000) * str; + } + } +} + +void Terrain::generateTexture (void) { + // texture is a 128x128 px pattern int texturesize = 128; + + // store the generated texture texture = std::vector >(texturesize, std::vector(texturesize)); - std::vector land(texture.size()*texture.size()); + + // generate texture into this + std::vector land(texture.size() * texture.size()); + + // XXX: magic constants with unintelligble names double str = 0.8; double H = 0.8; - for(int i = 512; i >= 1; i /= 2) { + + // do some magic + for (int i = 512; i >= 1; i /= 2) { fractal_diamond(land, texturesize, str, i); fractal_step(land, texturesize, str, i); str *= H; } + double min = 100000; double max = -100000; - for(int i = 0; i < texturesize*texturesize; i++) { - if(land[i] < min) min = land[i]; - if(land[i] > max) max = land[i]; + + // find the range of minimum and maximum values + for (int i = 0; i < texturesize * texturesize; i++) { + if (land[i] < min) min = land[i]; + if (land[i] > max) max = land[i]; } + + // normalize min down to zero max -= min; - for(int i = 0; i < texturesize*texturesize; i++) { + + // normalize values to [0, max] + for (int i = 0; i < texturesize * texturesize; i++) { land[i] -= min; } - for(int i = 0; i < texturesize*texturesize; i++) { - land[i] = land[i]*255/max; - texture[i%texturesize][i/texturesize] = (int)(land[i]); + + // copy+mangle land to texture as integers + for (int i = 0; i < texturesize * texturesize; i++) { + land[i] = land[i] * 255 / max; + texture[i % texturesize][i / texturesize] = (int) land[i]; } } -/** - * Changes color depending on x and y values - * x and y should be valid coordinates (not outside) - */ -void Terrain::noisifyPixel(CL_Color& color, PixelCoordinate pc) { +static int normalizeRange (int min, int val, int max) { + if (val < min) + return min; + + else if (val > max) + return max; + + else + return val; +} + +CL_Color Terrain::getTexturePixel (PixelDimension x, PixelDimension y) { + CL_Color color; int texture_fade = 8; - switch (terrain[pc.x][pc.y]) { - case TERRAIN_EMPTY: - break; - case TERRAIN_DIRT: - texture_fade = 4; - break; - case TERRAIN_ROCK: - texture_fade = 2; - break; + + // determine fade constant + switch (getType(x, y)) { + case TERRAIN_EMPTY: + color = COLOR_EMPTY; + break; + + case TERRAIN_DIRT: + color = COLOR_DIRT; + texture_fade = 4; + break; + + case TERRAIN_ROCK: + color = COLOR_ROCK; + texture_fade = 2; + break; } - int tx = (pc.x + texture_fade * 37) % texture.size(); - int ty = (pc.y + texture_fade * 37) % texture[0].size(); + + // calculate texture coordinate + int tx = (x + texture_fade * 37) % texture.size(); + int ty = (y + texture_fade * 37) % texture[0].size(); + + // get color components int red = color.get_red(); int green = color.get_green(); int blue = color.get_blue(); - + + // apply noise from texture red += (texture[tx][ty] - 128) / texture_fade; green += (texture[tx][ty] - 128) / texture_fade; blue += (texture[tx][ty] - 128) / texture_fade; - - if (red < 0) - red = 0; - else if (red >= 256) - red = 255; - - if (green < 0) - green = 0; - else if (green >= 256) - green = 255; - - if (blue < 0) - blue = 0; - else if (blue >= 256) - blue = 255; - - color = CL_Color(red, green, blue); + + // normalize colors to within range and return new color + return CL_Color( + normalizeRange(0, red, 255), + normalizeRange(0, green, 255), + normalizeRange(0, blue, 255) + ); } -/** - * Sets to color the correct color of pixel in (x,y) - */ -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[pc.x][pc.y]) { - case TERRAIN_EMPTY: - color = COLOR_EMPTY; - break; - - case TERRAIN_DIRT: - color = COLOR_DIRT; - break; - - case TERRAIN_ROCK: - color = COLOR_ROCK; - break; - } - - noisifyPixel(color, pc); +const TerrainPixel* Terrain::getTerrainBuffer (void) const { + return terrain_buf; } - -void Terrain::generatePixelBuffer (void) { - // initialze texture - generate_texture(); - - // create pixel buffer - pixbuf = CL_PixelBuffer(map_width, map_height, 4 * map_width, CL_PixelFormat::rgba8888); + +void Terrain::loadFromBuffer (const TerrainPixel *buf) { + // copy bytes + memcpy(terrain_buf, buf, width * height); - CL_Color 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); - } - } -} - -PixelCoordinate Terrain::getPixelCoordinate (Vector point) const { - // XXX: assume 1:1 - return PixelCoordinate((int) point.x, (int) point.y); -} - -PixelCoordinate Terrain::getDimensions (void) const { - return PixelCoordinate(map_width, map_height); -} - -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]; -} - -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); + // regenerate pixbuf + generatePixelBuffer(); } bool Terrain::collides (const Vector &point) const { @@ -225,85 +271,74 @@ } 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. + // TODO: Maybe there should be another function that also returns the point where we collided. - // We'll use Bresenhams line algorithm to go trough all the - // "pixels" of the line. + // use Bresenhams line algorithm to go trough all the "pixels" of the line. PixelCoordinate b = getPixelCoordinate(begin); PixelCoordinate e = getPixelCoordinate(end); + // steepness of line (large angle against horizontal) bool steep = (abs(e.y - b.y) > abs(e.x - b.x)); // k > 1 - + + // if the line is steep, swap the 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 + + // normalize so that the line goes upwards + if (b.x > e.x) std::swap(b, e); - } - + + // line length 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; + PixelDimension y = b.y; + + // ascending or descending line? + PixelDimension ystep = b.y < e.y ? 1 : -1; - // Go trough the line - for (PixelDimension x = b.x; x <= e.x; x++) { + // iterate through the pixels on the line + 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! + // x and y coordinates must be switched if steep + if (getType(y, x) != TERRAIN_EMPTY) return true; - } + } else { - if (getType(x, y) != TERRAIN_EMPTY) { - // Collision! + if (getType(x, y) != TERRAIN_EMPTY) return true; - } + } err = err - dy; if (err < 0) { - // Check if we want to make an ystep + // check if we want to make an ystep y = y + ystep; err = err + dx; } } - return false; // No Collision + // no collision + return false; } 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. - + // scale arguments to pixel units PixelCoordinate mid = getPixelCoordinate(pos); - PixelDimension r = (unsigned int) radius; // XXX: scale + PixelDimension r = scale(radius); + + // iterate through the circle's pixels + for (PixelDimension j = mid.y - r; j < mid.y + r; j++) { + for (PixelDimension i = mid.x - r; i < mid.x + r; i++) { + // getType also returns TERRAIN_ROCK if out-of-bounds + if (getType(i, j) != TERRAIN_ROCK) { - 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 - + // within radius? 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); + // update terrain buf + setType(i, j, TERRAIN_EMPTY); } } } @@ -339,12 +374,8 @@ return 0; } -/** - * point should be ground and prevPoint air, but it's easy to assure that - * @param point - pixel on ground to which was collided - * @param prevPoint - pixel where we are when we collide - */ Vector Terrain::getNormal(Vector point, Vector prevPoint) const { + // XXX: cleanup PixelCoordinate p = getPixelCoordinate(point); assert(point != prevPoint); @@ -375,66 +406,13 @@ return normal; } -// TODO: This could better :) -// TODO: And this need some cleaning :) -void Terrain::generateTerrain (int seed) { - srand(seed); // Set random number generator seed. - - // Some constants to control random generation - const int min_range = 25; - const int max_range = 80; - const int num = 50; - const int rock_rarity = 4; - - // Generate circles (or whatever) - for (int i = 0; i < num; i++) { - // Random generate circle attributes - 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) { - mid.x = map_width / 2; - mid.y = map_height / 2; - range = 150; - } - - 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 ( - 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; - } - } - } - } +void Terrain::draw (Graphics *g, PixelCoordinate camera) { + // XXX: can we optimize this somehow? - // regenerate pixel buffer - this->generatePixelBuffer(); -} - -void Terrain::draw (Graphics *g, PixelCoordinate camera) { + // load the terrain pixbuf as a surface CL_Surface surf (pixbuf); + + // draw it onto the graphics, offset by camera position surf.draw(-camera.x, -camera.y, g->get_gc()); } -std::vector > Terrain::getTerrain() const { - return terrain; -} - diff -r 7a8c7a0a1261 -r a2e35ca66c74 src/Terrain.hh --- a/src/Terrain.hh Sat Jan 17 02:58:36 2009 +0200 +++ b/src/Terrain.hh Tue Jan 20 22:00:24 2009 +0200 @@ -8,13 +8,26 @@ #include "Types.hh" #include "Config.hh" +/** + * Different types of terrain available + */ enum TerrainType { - TERRAIN_EMPTY, - TERRAIN_DIRT, - TERRAIN_ROCK + /** Empty space, air */ + TERRAIN_EMPTY = 0x00, + + /** Dirt, which can be destroyed/dug through */ + TERRAIN_DIRT = 0x01, + + /** Indestructible rock */ + TERRAIN_ROCK = 0x02 }; /** + * Terrain "pixel" type + */ +typedef uint8_t TerrainPixel; + +/** * Terrain class. Represents game terrain and contains member * functions to manipulate terrain and get info about it. * @@ -25,57 +38,78 @@ * and it uses pixelcoordinates internally. */ class Terrain { -public: // XXX: until we fix Network's access to this - std::vector > terrain; +protected: + /** The terrain data is stored as a linear array in row-major order, with width*height elements */ + TerrainPixel *terrain_buf; + + /** Terrain dimensions */ + PixelDimension width, height; - /** - * Generates pixelbuffer from terrain. Should be used only on - * constructors because this is expected to be slow. - */ - void generatePixelBuffer(); - -protected: - // terrain dimensions - PixelDimension map_width, map_height; - - // We can pre-render the terrain as a pixel buffer and then just modify this + /** We pre-render the textured terrain data for display */ CL_PixelBuffer pixbuf; - // terrain texture + // XXX: terrain texture std::vector > texture; /** * Default constructor. The width/height are set to zero and the terrain is invalid until it gets updated - * - * @param scale The "real" width and height of the terrain. */ Terrain (void); /** * Constructor. * - * @param scale The "real" width and height of the terrain. - * @param seed Random number generator seed used to create the - * terrain. + * @param width terrain width + * @param height terrain height + * @param seed andom number generator seed used to generate the random terrain. */ - Terrain (PixelDimension map_width, PixelDimension map_height, int seed); - - /** - * Copy constructor. - * - * @param t Terrain to be copied. - */ - Terrain (const Terrain &t); + Terrain (PixelDimension width, PixelDimension height, int seed); /** * Destructor */ - ~Terrain (void) {} + ~Terrain (void); + +private: + /* No copying */ + Terrain (const Terrain ©); + Terrain &operator= (const Terrain ©); protected: - void generate_texture(); - void noisifyPixel(CL_Color& col, PixelCoordinate pc); + /** + * Set induvidual pixel value, updates both terrain_buf and pixbuf + */ + inline void setType (PixelDimension x, PixelDimension y, TerrainType t) { + terrain_buf[y * width + x] = (TerrainPixel) t; + // XXX: locking? + pixbuf.draw_pixel(x, y, getTexturePixel(x, y)); + } + + /** + * Generate random terrain using given seed + * + * @param seed seed for the random number generator + */ + void generateTerrain (int seed); + + /** + * Regenerates our pixbuf from the current terrain. This is a slow process, but using the pixbuffer directly + * greatly speeds up drawing. + */ + void generatePixelBuffer (void); + + /** + * Generates an area of random texture using a fractal-based algorithm, this can then be applied to the terrain + * pixels using noisifyPixel + */ + void generateTexture(); + + /** + * Applies noise generated using generateTexture to generate a slightly varying color for the terrain pixel + * at \a pc. + */ + CL_Color getTexturePixel (PixelDimension x, PixelDimension y); /** * Scale parameter to "pixels" @@ -83,12 +117,9 @@ * @param x Scaled value * @return Corresponding value in pixels */ - PixelDimension scale (float x) const; - - /** - * Sets to color the correct color of pixel in (x,y) - */ - void loadPixelColor (CL_Color& color, PixelCoordinate pc); + inline PixelDimension scale (float x) const { + return (int) x; + } public: /** @@ -97,92 +128,94 @@ * @param point Point in "real" units * @return Int vector */ - PixelCoordinate getPixelCoordinate (Vector point) const; + inline PixelCoordinate getPixelCoordinate (Vector point) const { + return PixelCoordinate(scale(point.x), scale(point.y)); + } /** * Return the terrain dimensions à la a PixelCoordinate */ - PixelCoordinate getDimensions (void) const; + inline PixelCoordinate getDimensions (void) const { + return PixelCoordinate(width, height); + } /** - * Return the type of terrain at given position. Returns ROCK if - * given point is not inside terrain area. + * Return the type of terrain at given position. Returns TERRAIN_ROCK if given point is not inside terrain area. * - * @param x X coordinate - * @param y Y coordinate - * @return Terrain type + * @param x terrain x coordinate + * @param y terrain x coordinate + * @return terrain pixel type */ - TerrainType getType (PixelDimension px, PixelDimension py) const; - TerrainType getType (PixelCoordinate pc) const; - TerrainType getType (Vector point) const; + TerrainType getType (PixelDimension x, PixelDimension y) const { + // XXX: optimize access by removing error checking? + if (x < 0 || y < 0 || x >= width || y >= height) + return TERRAIN_ROCK; + + return (TerrainType) terrain_buf[y * width + x]; + } + + inline TerrainType getType (PixelCoordinate pc) const { + return getType(pc.x, pc.y); + } + + + inline TerrainType getType (Vector point) const { + return getType(getPixelCoordinate(point)); + } /** - * Check if given point has some terrain. + * Get raw read-only terrain data buffer * - * @param point Point that is in scaled units. + * @see terrain_buf + */ + const TerrainPixel* getTerrainBuffer (void) const; + + /** + * Load new terrain data from given buffer. Must be the right size + * + * @see terrain_buf + */ + void loadFromBuffer (const TerrainPixel *buf); + + /** + * Check if the given point is terrain */ bool collides (const Vector &point) const; + /** - * Check if given line collides with terrain. + * Check if the given line collides with terrain * - * @param begin Line begin point in scaled units. - * @param end Line end point in scaled units. + * @param begin line starting point + * @param end line ending point */ bool collides (const Vector &begin, const Vector &end) const; /** - * Remove a circular area from terrain. + * Remove a circular area of terrain * - * @param pos Circle center - * @param r Circle radius + * @param pos circle center + * @param r circle radius */ void removeGround (const Vector &pos, float r); /** - * Return normal for the given point. + * Returns direction normal vector for the given \a point. * - * @param point Point for which the normal is calculated. - * @return Normal vector ((0,0) if there's no terrain) + * \a point should be ground, and \a prevPoint air. + * + * @param point the ground that we collided into + * @param prevPoint position in air where we were before the collision + * @return direction ormal vector, or (0,0) if there's no terrain */ Vector getNormal (Vector point, Vector prevPoint) const; /** - * Generate random terrain. + * Draw the terrain onto the given graphics context * - * @param seed Seed for the randomnumber generator. - */ - void generateTerrain (int seed); - - /** - * Draw the terrain for given graphicscontext. - * - * @param gc CL_GraphicContext - * @param camera - upper left corner of screen + * @param gc Graphics to draw on + * @param camera view position */ virtual void draw (Graphics *g, PixelCoordinate camera = PixelCoordinate(0, 0)); - - /** - * Draw part of the terrain for given graphiscontext. - * - * @param gc CL_GraphicContext - * @param center Center of the rectangle drawn. - * @param dimension Dimensions of the rectangle. - */ - //void draw(CL_GraphicContext &gc, Vector center, Vector dimensions); - - /** - * Set terrain. - * - * @param terrain Terrain. - */ - void setTerrain (const std::vector > &terrain); - - /** - * Get terrain. - * - * @return Terrain. - */ - std::vector > getTerrain() const; }; #endif