terom@185: #ifndef TERRAIN_HH terom@185: #define TERRAIN_HH terom@185: terom@185: #include "Vector.hh" terom@296: #include "Types.hh" terom@185: #include "Config.hh" terom@417: #include "Configuration.hh" terom@185: terom@417: #include terom@417: terom@424: #if GRAPHICS_ENABLED terom@424: #include "Graphics/Drawable.hh" terom@424: terom@424: #endif terom@424: terom@406: /** terom@406: * Different types of terrain available terom@406: */ terom@255: enum TerrainType { terom@406: /** Empty space, air */ terom@406: TERRAIN_EMPTY = 0x00, terom@406: terom@406: /** Dirt, which can be destroyed/dug through */ terom@406: TERRAIN_DIRT = 0x01, terom@406: terom@406: /** Indestructible rock */ terom@406: TERRAIN_ROCK = 0x02 terom@255: }; terom@185: terom@185: /** terom@185: * Terrain class. Represents game terrain and contains member terom@185: * functions to manipulate terrain and get info about it. terom@185: * terom@185: * Terrain resolution is a constant that is defined in terom@185: * configuration. Terrain has a scale (i.e. the width and height in terom@185: * "real" units. Scaling is needed because physics simulation uses terom@185: * "real" units. The idea is that this class is used with "real" units terom@185: * and it uses pixelcoordinates internally. terom@185: */ terom@185: class Terrain { terom@406: protected: terom@408: /** The terrain data is stored as a linear array in row-major order, with width * height elements */ terom@406: TerrainPixel *terrain_buf; terom@406: terom@406: /** Terrain dimensions */ terom@406: PixelDimension width, height; terom@417: terom@417: #if GRAPHICS_ENABLED terom@406: /** We pre-render the textured terrain data for display */ terom@203: CL_PixelBuffer pixbuf; terom@424: terom@424: /** Generated texture pattern */ terom@424: std::vector > texture; terom@417: #endif terom@417: terom@408: public: terom@255: /** terom@409: * Construct a new terrain based on the given configuration terom@409: * terom@409: * @param config a TerrainConfig describing how to build the terrain terom@255: */ terom@409: explicit Terrain (const TerrainConfig &config); terom@255: terom@255: /** terom@408: * Construct the terrain using the provided terrain data. The given \a terrain_buf must be a linear array in the terom@408: * same format as Terrain::terrain_buf, meaning a row-major order array with width * height elements. The buffer terom@408: * must be allocated on the heap using 'new []', and ownership will be transferred (i.e. the buffer is not copied, terom@408: * and will eventually be delete []'d). terom@408: * terom@408: * @param width terrain width terom@408: * @param height terrain height terom@408: * @param terrain_buf dynamically allocated width * height array of terrain data terom@408: */ terom@408: Terrain (PixelDimension width, PixelDimension height, TerrainPixel *terrain_buf); terom@408: terom@408: /** terom@408: * Destructor, frees our terrain buffer terom@255: */ terom@406: ~Terrain (void); terom@406: terom@406: private: terom@406: /* No copying */ terom@406: Terrain (const Terrain ©); terom@406: Terrain &operator= (const Terrain ©); terom@255: terom@255: protected: terom@406: /** terom@406: * Set induvidual pixel value, updates both terrain_buf and pixbuf terom@406: */ terom@406: inline void setType (PixelDimension x, PixelDimension y, TerrainType t) { terom@406: terrain_buf[y * width + x] = (TerrainPixel) t; terom@255: terom@417: #if GRAPHICS_ENABLED terom@406: // XXX: locking? terom@406: pixbuf.draw_pixel(x, y, getTexturePixel(x, y)); terom@417: #endif terom@406: } terom@406: terom@406: /** terom@406: * Generate random terrain using given seed terom@406: * terom@406: * @param seed seed for the random number generator terom@406: */ terom@406: void generateTerrain (int seed); terom@406: terom@406: /** terom@406: * Regenerates our pixbuf from the current terrain. This is a slow process, but using the pixbuffer directly terom@406: * greatly speeds up drawing. terom@406: */ terom@406: void generatePixelBuffer (void); terom@406: terom@424: #if GRAPHICS_ENABLED terom@406: /** terom@406: * Generates an area of random texture using a fractal-based algorithm, this can then be applied to the terrain terom@406: * pixels using noisifyPixel terom@406: */ terom@406: void generateTexture(); terom@406: terom@406: /** terom@406: * Applies noise generated using generateTexture to generate a slightly varying color for the terrain pixel terom@406: * at \a pc. terom@406: */ terom@423: Color getTexturePixel (PixelDimension x, PixelDimension y); terom@424: #endif terom@185: terom@185: /** terom@185: * Scale parameter to "pixels" terom@185: * terom@185: * @param x Scaled value terom@185: * @return Corresponding value in pixels terom@185: */ terom@406: inline PixelDimension scale (float x) const { terom@406: return (int) x; terom@406: } nireco@243: terom@185: public: terom@255: /** terom@255: * Get pixel location of a point that is in "real" units. terom@255: * terom@255: * @param point Point in "real" units terom@255: * @return Int vector terom@255: */ terom@406: inline PixelCoordinate getPixelCoordinate (Vector point) const { terom@406: return PixelCoordinate(scale(point.x), scale(point.y)); terom@406: } terom@185: terom@255: /** terom@255: * Return the terrain dimensions à la a PixelCoordinate terom@255: */ terom@408: PixelCoordinate getDimensions (void) const { terom@406: return PixelCoordinate(width, height); terom@406: } terom@255: terom@185: /** terom@408: * Return dimensions in component form terom@408: */ terom@408: PixelDimension getWidth (void) const { terom@408: return width; terom@408: } terom@408: terom@408: PixelDimension getHeight (void) const { terom@408: return height; terom@408: } terom@408: terom@408: /** terom@406: * Return the type of terrain at given position. Returns TERRAIN_ROCK if given point is not inside terrain area. terom@185: * terom@406: * @param x terrain x coordinate terom@406: * @param y terrain x coordinate terom@406: * @return terrain pixel type terom@185: */ terom@406: TerrainType getType (PixelDimension x, PixelDimension y) const { terom@406: // XXX: optimize access by removing error checking? terom@406: if (x < 0 || y < 0 || x >= width || y >= height) terom@406: return TERRAIN_ROCK; terom@406: terom@406: return (TerrainType) terrain_buf[y * width + x]; terom@406: } terom@406: terom@406: inline TerrainType getType (PixelCoordinate pc) const { terom@406: return getType(pc.x, pc.y); terom@406: } terom@406: terom@406: terom@406: inline TerrainType getType (Vector point) const { terom@406: return getType(getPixelCoordinate(point)); terom@406: } terom@185: terom@185: /** terom@406: * Get raw read-only terrain data buffer terom@185: * terom@406: * @see terrain_buf terom@406: */ terom@406: const TerrainPixel* getTerrainBuffer (void) const; terom@406: terom@406: /** terom@406: * Load new terrain data from given buffer. Must be the right size terom@406: * terom@406: * @see terrain_buf terom@406: */ terom@406: void loadFromBuffer (const TerrainPixel *buf); terom@406: terom@406: /** terom@406: * Check if the given point is terrain terom@185: */ terom@255: bool collides (const Vector &point) const; terom@406: terom@185: /** terom@406: * Check if the given line collides with terrain terom@185: * terom@406: * @param begin line starting point terom@406: * @param end line ending point terom@185: */ terom@255: bool collides (const Vector &begin, const Vector &end) const; terom@185: terom@185: /** terom@406: * Remove a circular area of terrain terom@185: * terom@406: * @param pos circle center terom@406: * @param r circle radius terom@185: */ terom@255: void removeGround (const Vector &pos, float r); terom@185: terom@185: /** terom@406: * Returns direction normal vector for the given \a point. terom@185: * terom@406: * \a point should be ground, and \a prevPoint air. terom@406: * terom@406: * @param point the ground that we collided into terom@406: * @param prevPoint position in air where we were before the collision terom@406: * @return direction ormal vector, or (0,0) if there's no terrain terom@185: */ terom@255: Vector getNormal (Vector point, Vector prevPoint) const; terom@185: terom@417: #if GRAPHICS_ENABLED terom@185: /** terom@406: * Draw the terrain onto the given graphics context terom@185: * terom@406: * @param gc Graphics to draw on terom@406: * @param camera view position terom@185: */ terom@412: virtual void draw (graphics::Display &display, PixelCoordinate camera = PixelCoordinate(0, 0)); terom@417: #endif terom@185: }; terom@185: terom@185: #endif