diff --git a/mk/linux/Jamfile b/mk/linux/Jamfile index 4be95eead..089c47ab3 100644 --- a/mk/linux/Jamfile +++ b/mk/linux/Jamfile @@ -4,6 +4,26 @@ UseAutoconf ; Package license.txt readme.txt ; +#ALWAYS getSVNVersion : @getSVNVersion_action ; + +rule getSVNVersion { + echo 'hi' ; +} + +actions getSVNVersion_action +{ +# echo '"'`svnversion`'"' >sources/glest_game/facilities/svn_version_tmp.h + echo '"'`svnversion`'"' ; + echo 'hi' ; +# if diff -N svn_version_tmp.hpp src/svn_version.hpp >/dev/null; then +# rm svn_version_tmp.hpp +# else +# mv svn_version_tmp.hpp src/svn_version.hpp +# fi +} + +ALWAYS getSVNVersion ; + #### Library #### SubDir TOP shared_lib sources ; @@ -37,6 +57,7 @@ LIB_DIRS = sound sound/openal xml + map glew lua streflop diff --git a/source/glest_game/menu/menu_state_custom_game.cpp b/source/glest_game/menu/menu_state_custom_game.cpp index 85cb1ca80..cdb63393a 100644 --- a/source/glest_game/menu/menu_state_custom_game.cpp +++ b/source/glest_game/menu/menu_state_custom_game.cpp @@ -2629,214 +2629,4 @@ void MenuStateCustomGame::cleanupFactionTexture() { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } - -// ======================================= - -MapPreview::MapPreview() { - altFactor = 3; - waterLevel = 4; - //cells = NULL; - cells.clear(); - startLocations = NULL; - reset(128, 128, 10.f, 1); - resetFactions(8); - title = ""; - desc = ""; - author = ""; - refAlt = 10; -} - -MapPreview::~MapPreview() { - delete [] startLocations; - startLocations = NULL; - - if(hasFileLoaded() == true) { - //for (int i = 0; i < h; i++) { - // delete [] cells[i]; - //} - //delete [] cells; - - fileLoaded = false; - } - //cells = NULL; - cells.clear(); -} - - -float MapPreview::getHeight(int x, int y) const { - return cells[x][y].height; -} - -int MapPreview::getSurface(int x, int y) const { - return cells[x][y].surface; -} - -int MapPreview::getObject(int x, int y) const { - return cells[x][y].object; -} - -int MapPreview::getResource(int x, int y) const { - return cells[x][y].resource; -} - -int MapPreview::getStartLocationX(int index) const { - return startLocations[index].x; -} - -int MapPreview::getStartLocationY(int index) const { - return startLocations[index].y; -} - -bool MapPreview::inside(int x, int y) { - return (x >= 0 && x < w && y >= 0 && y < h); -} - -void MapPreview::reset(int w, int h, float alt, int surf) { - if (w < 16 || h < 16) { - throw runtime_error("Size of map must be at least 16x16"); - return; - } - - if (w > 1024 || h > 1024) { - throw runtime_error("Size of map can be at most 1024x1024"); - return; - } - - if (alt < 0 || alt > 20) { - throw runtime_error("Height must be in the range 0-20"); - return; - } - - if (surf < 1 || surf > 5) { - throw runtime_error("Surface must be in the range 1-5"); - return; - } - - /* - if (cells != NULL) { - for (int i = 0; i < this->w; i++) { - delete [] cells[i]; - } - delete [] cells; - } - */ - cells.clear(); - - this->w = w; - this->h = h; - this->maxFactions = maxFactions; - - cells.resize(w); - - //cells = new Cell*[w]; - for (int i = 0; i < w; i++) { - //cells[i] = new Cell[h]; - cells[i].resize(h); - for (int j = 0; j < h; j++) { - cells[i][j].height = alt; - cells[i][j].object = 0; - cells[i][j].resource = 0; - cells[i][j].surface = surf; - } - } -} - -void MapPreview::resetFactions(int maxPlayers) { - if (maxPlayers<1 || maxPlayers>8){ - throw runtime_error("Max Players must be in the range 1-8"); - } - - if (startLocations != NULL) { - delete [] startLocations; - startLocations = NULL; - } - - maxFactions = maxPlayers; - - startLocations = new StartLocation[maxFactions]; - for (int i = 0; i < maxFactions; i++) { - startLocations[i].x = 0; - startLocations[i].y = 0; - } -} - -int MapPreview::getHeightFactor() const { - return altFactor; -} - -int MapPreview::getWaterLevel() const { - return waterLevel; -} - -void MapPreview::loadFromFile(const string &path) { - altFactor = 3; - waterLevel = 4; - //cells = NULL; - cells.clear(); - startLocations = NULL; - reset(128, 128, 10.f, 1); - resetFactions(8); - title = ""; - desc = ""; - author = ""; - refAlt = 10; - - FILE *f1 = fopen(path.c_str(), "rb"); - if (f1 != NULL) { - - //read header - MapFileHeaderPreview header; - size_t bytes = fread(&header, sizeof(MapFileHeaderPreview), 1, f1); - - altFactor = header.altFactor; - waterLevel = header.waterLevel; - title = header.title; - author = header.author; - desc = header.description; - - //read start locations - resetFactions(header.maxFactions); - for (int i = 0; i < maxFactions; ++i) { - bytes = fread(&startLocations[i].x, sizeof(int32), 1, f1); - bytes = fread(&startLocations[i].y, sizeof(int32), 1, f1); - } - - //read Heights - reset(header.width, header.height, 10, 1); - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - bytes = fread(&cells[i][j].height, sizeof(float), 1, f1); - } - } - - //read surfaces - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - bytes = fread(&cells[i][j].surface, sizeof(int8), 1, f1); - } - } - - //read objects - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - int8 obj; - bytes = fread(&obj, sizeof(int8), 1, f1); - if (obj <= 10) { - cells[i][j].object = obj; - } else { - cells[i][j].resource = obj - 10; - } - } - } - - fclose(f1); - - fileLoaded = true; - } else { - throw runtime_error("error opening map file: " + path); - } -} - -// ==================== PRIVATE ==================== - }}//end namespace diff --git a/source/glest_game/menu/menu_state_custom_game.h b/source/glest_game/menu/menu_state_custom_game.h index 8cf5b1958..293fef5b6 100644 --- a/source/glest_game/menu/menu_state_custom_game.h +++ b/source/glest_game/menu/menu_state_custom_game.h @@ -15,90 +15,12 @@ #include "main_menu.h" #include "chat_manager.h" #include "simple_threads.h" -#include "game.h" +#include "map_preview.h" #include "leak_dumper.h" -namespace Glest{ namespace Game{ - -struct MapFileHeaderPreview { - int32 version; - int32 maxFactions; - int32 width; - int32 height; - int32 altFactor; - int32 waterLevel; - int8 title[128]; - int8 author[128]; - int8 description[256]; -}; - -// =============================================== -// class Map -// =============================================== - -class MapPreview { -public: - static const int maxHeight = 20; - static const int minHeight = 0; - -private: - struct Cell { - int surface; - int object; - int resource; - float height; - }; - - struct StartLocation { - int x; - int y; - }; - - RandomGen random; - string title; - string author; - string desc; - string recScn; - int type; - int h; - int w; - int altFactor; - int waterLevel; - //Cell **cells; - std::vector > cells; - int maxFactions; - StartLocation *startLocations; - int refAlt; - bool fileLoaded; - -public: - MapPreview(); - ~MapPreview(); - float getHeight(int x, int y) const; - int getSurface(int x, int y) const; - int getObject(int x, int y) const; - int getResource(int x, int y) const; - int getStartLocationX(int index) const; - int getStartLocationY(int index) const; - int getHeightFactor() const; - int getWaterLevel() const; - bool inside(int x, int y); - - int getH() const {return h;} - int getW() const {return w;} - int getMaxFactions() const {return maxFactions;} - string getTitle() const {return title;} - string getDesc() const {return desc;} - string getAuthor() const {return author;} - - void reset(int w, int h, float alt, int surf); - void resetFactions(int maxFactions); - - void loadFromFile(const string &path); - bool hasFileLoaded() const { return fileLoaded; } -}; - +using namespace Shared::Map; +namespace Glest { namespace Game { // =============================== // class MenuStateCustomGame diff --git a/source/glest_map_editor/program.cpp b/source/glest_map_editor/program.cpp index ec2f35be0..639aa720d 100644 --- a/source/glest_map_editor/program.cpp +++ b/source/glest_map_editor/program.cpp @@ -115,7 +115,7 @@ void UndoPoint::revert() { //std::cout << "attempting to restore the surface array" << std::endl; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { - Program::map->setSurface(i, j, surface[j * w + i]); + Program::map->setSurface(i, j, static_cast(surface[j * w + i])); } } if (change != ctAll) break; @@ -141,13 +141,13 @@ void UndoPoint::revert() { // class Program // =============================================== -Map *Program::map = NULL; +MapPreview *Program::map = NULL; Program::Program(int w, int h) { cellSize = 6; ofsetX = 0; ofsetY = 0; - map = new Map(); + map = new MapPreview(); renderer.init(w, h); } @@ -186,7 +186,7 @@ void Program::pirateChangeMapHeight(int x, int y, int Height, int radius) { } void Program::changeMapSurface(int x, int y, int surface, int radius) { - map->changeSurface((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, surface, radius); + map->changeSurface((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, static_cast(surface), radius); } void Program::changeMapObject(int x, int y, int object, int radius) { @@ -261,17 +261,17 @@ void Program::randomizeMap() { } void Program::switchMapSurfaces(int surf1, int surf2) { - map->switchSurfaces(surf1, surf2); + map->switchSurfaces(static_cast(surf1), static_cast(surf2)); } void Program::reset(int w, int h, int alt, int surf) { undoStack.clear(); redoStack.clear(); - map->reset(w, h, (float) alt, surf); + map->reset(w, h, (float) alt, static_cast(surf)); } void Program::resize(int w, int h, int alt, int surf) { - map->resize(w, h, (float) alt, surf); + map->resize(w, h, (float) alt, static_cast(surf)); } void Program::resetFactions(int maxFactions) { diff --git a/source/glest_map_editor/program.h b/source/glest_map_editor/program.h new file mode 100644 index 000000000..801163d07 --- /dev/null +++ b/source/glest_map_editor/program.h @@ -0,0 +1,150 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef _MAPEDITOR_PROGRAM_H_ +#define _MAPEDITOR_PROGRAM_H_ + +//#include "map.h" +#include "map_preview.h" +#include "renderer.h" + +#include + +using std::stack; +using namespace Shared::Map; + +namespace MapEditor { + +class MainWindow; + +enum ChangeType { + ctNone = -1, + ctHeight, + ctSurface, + ctObject, + ctResource, + ctLocation, + ctGradient, + ctAll +}; + +// ============================================= +// class Undo Point +// A linked list class that is more of an extension / modification on +// the already existing Cell struct in map.h +// Provides the ability to only specify a certain property of the map to change +// ============================================= +class UndoPoint { + private: + // Only keep a certain number of undo points in memory otherwise + // Big projects could hog a lot of memory + const static int MAX_UNDO_LIST_SIZE = 100; // TODO get feedback on this value + static int undoCount; + + ChangeType change; + + // Pointers to arrays of each property + int *surface; + int *object; + int *resource; + float *height; + + // Map width and height + static int w; + static int h; + + public: + UndoPoint(); + ~UndoPoint(); + void init(ChangeType change); + void revert(); + + inline ChangeType getChange() const { return change; } +}; + +class ChangeStack : public std::stack { +public: + static const int maxSize = 100; + + void clear() { c.clear(); } + + void push(UndoPoint p) { + if (c.size() >= maxSize) { + c.pop_front(); + } + stack::push(p); + } +}; + +// =============================================== +// class Program +// =============================================== + +class Program { +private: + Renderer renderer; + int ofsetX, ofsetY; + int cellSize; + //static Map *map; + static MapPreview *map; + friend class UndoPoint; + + ChangeStack undoStack, redoStack; + +public: + Program(int w, int h); + ~Program(); + + //map cell change + void glestChangeMapHeight(int x, int y, int Height, int radius); + void pirateChangeMapHeight(int x, int y, int Height, int radius); + void changeMapSurface(int x, int y, int surface, int radius); + void changeMapObject(int x, int y, int object, int radius); + void changeMapResource(int x, int y, int resource, int radius); + void changeStartLocation(int x, int y, int player); + + void setUndoPoint(ChangeType change); + bool undo(); + bool redo(); + + //map ops + void reset(int w, int h, int alt, int surf); + void resize(int w, int h, int alt, int surf); + void resetFactions(int maxFactions); + void setRefAlt(int x, int y); + void flipX(); + void flipY(); + void randomizeMapHeights(); + void randomizeMap(); + void switchMapSurfaces(int surf1, int surf2); + void loadMap(const string &path); + void saveMap(const string &path); + + //map misc + bool setMapTitle(const string &title); + bool setMapDesc(const string &desc); + bool setMapAuthor(const string &author); + void setMapAdvanced(int altFactor, int waterLevel); + + //misc + void renderMap(int w, int h); + void setOfset(int x, int y); + void incCellSize(int i); + void resetOfset(); + + int getObject(int x, int y); + int getResource(int x, int y); + static const MapPreview *getMap() {return map;} +}; + +}// end namespace + +#endif diff --git a/source/glest_map_editor/renderer.cpp b/source/glest_map_editor/renderer.cpp index d5136bc8b..24c394064 100644 --- a/source/glest_map_editor/renderer.cpp +++ b/source/glest_map_editor/renderer.cpp @@ -37,7 +37,7 @@ void Renderer::init(int clientW, int clientH) { assertGl(); } -void Renderer::renderMap(Map *map, int x, int y, int clientW, int clientH, int cellSize) { +void Renderer::renderMap(MapPreview *map, int x, int y, int clientW, int clientH, int cellSize) { float alt; float showWater; diff --git a/source/glest_map_editor/renderer.h b/source/glest_map_editor/renderer.h new file mode 100644 index 000000000..3a242d4d8 --- /dev/null +++ b/source/glest_map_editor/renderer.h @@ -0,0 +1,33 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martio Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef _MAPEDITOR_RENDERER_H_ +#define _MAPEDITOR_RENDERER_H_ + +#include "map_preview.h" + +using namespace Shared::Map; + +namespace MapEditor { + +// =============================================== +// class Renderer +// =============================================== + +class Renderer { +public: + void init(int clientW, int clientH); + void renderMap(MapPreview *map, int x, int y, int clientW, int clientH, int cellSize); +}; + +}// end namespace + +#endif diff --git a/source/shared_lib/include/map/map_preview.h b/source/shared_lib/include/map/map_preview.h new file mode 100644 index 000000000..adf20a6d5 --- /dev/null +++ b/source/shared_lib/include/map/map_preview.h @@ -0,0 +1,173 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martio Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef _MAPPREVIEW_MAP_H_ +#define _MAPPREVIEW_MAP_H_ + +#include "util.h" +#include "types.h" +#include "randomgen.h" +#include + +using Shared::Platform::int8; +using Shared::Platform::int32; +using Shared::Platform::float32; +using Shared::Util::RandomGen; + +namespace Shared { namespace Map { + +enum MapSurfaceType { + st_Grass = 1, + st_Secondary_Grass, + st_Road, + st_Stone, + st_Ground + +}; + +static const int MAX_TITLE_LENGTH = 128; +static const int MAX_AUTHOR_LENGTH = 128; +static const int MAX_DESCRIPTION_LENGTH = 256; + +static const int MIN_MAP_CELL_DIMENSION = 16; +static const int MAX_MAP_CELL_DIMENSION = 1024; + +static const int MIN_MAP_CELL_HEIGHT = 0; +static const int MAX_MAP_CELL_HEIGHT = 20; +static const int DEFAULT_MAP_CELL_HEIGHT = 10; + +static const int MIN_MAP_FACTIONCOUNT = 1; +static const int MAX_MAP_FACTIONCOUNT = 8; +static const int DEFAULT_MAP_FACTIONCOUNT = 8; + +static const int DEFAULT_MAP_CELL_WIDTH = 128; +static const int DEFAULT_MAP_CELL_LENGTH = 128; + +static const MapSurfaceType DEFAULT_MAP_CELL_SURFACE_TYPE = st_Grass; + +static const int DEFAULT_MAP_CELL_HEIGHT_FACTOR = 3; +static const int DEFAULT_MAP_WATER_DEPTH = 4; + +struct MapFileHeader { + int32 version; + int32 maxFactions; + int32 width; + int32 height; + int32 altFactor; + int32 waterLevel; + int8 title[MAX_TITLE_LENGTH]; + int8 author[MAX_AUTHOR_LENGTH]; + int8 description[MAX_DESCRIPTION_LENGTH]; +}; + +// =============================================== +// class Map +// =============================================== + +class MapPreview { +public: + static const int maxHeight = 20; + static const int minHeight = 0; + +private: + struct Cell { + int surface; + int object; + int resource; + float height; + }; + + struct StartLocation { + int x; + int y; + }; + + RandomGen random; + string title; + string author; + string desc; + string recScn; + int type; + int h; + int w; + int altFactor; + int waterLevel; + //Cell **cells; + std::vector > cells; + + int maxFactions; + //StartLocation *startLocations; + std::vector startLocations; + int refAlt; + + bool fileLoaded; + +public: + MapPreview(); + ~MapPreview(); + float getHeight(int x, int y) const; + MapSurfaceType getSurface(int x, int y) const; + int getObject(int x, int y) const; + int getResource(int x, int y) const; + int getStartLocationX(int index) const; + int getStartLocationY(int index) const; + int getHeightFactor() const; + int getWaterLevel() const; + bool inside(int x, int y); + + void setRefAlt(int x, int y); + void setAdvanced(int altFactor, int waterLevel); + void setTitle(const string &title); + void setDesc(const string &desc); + void setAuthor(const string &author); + + int getH() const {return h;} + int getW() const {return w;} + int getMaxFactions() const {return maxFactions;} + string getTitle() const {return title;} + string getDesc() const {return desc;} + string getAuthor() const {return author;} + + void glestChangeHeight(int x, int y, int height, int radius); + void pirateChangeHeight(int x, int y, int height, int radius); + void changeSurface(int x, int y, MapSurfaceType surface, int radius); + void changeObject(int x, int y, int object, int radius); + void changeResource(int x, int y, int resource, int radius); + void changeStartLocation(int x, int y, int player); + + void setHeight(int x, int y, float height); + void setSurface(int x, int y, MapSurfaceType surface); + void setObject(int x, int y, int object); + void setResource(int x, int y, int resource); + + void flipX(); + void flipY(); + void reset(int w, int h, float alt, MapSurfaceType surf); + void resize(int w, int h, float alt, MapSurfaceType surf); + void resetFactions(int maxFactions); + void randomizeHeights(); + void randomize(); + void switchSurfaces(MapSurfaceType surf1, MapSurfaceType surf2); + + void loadFromFile(const string &path); + void saveToFile(const string &path); + + void resetHeights(int height); + void sinRandomize(int strenght); + void decalRandomize(int strenght); + void applyNewHeight(float newHeight, int x, int y, int strenght); + + bool hasFileLoaded() const {return fileLoaded;} +}; + +}}// end namespace + +#endif diff --git a/source/shared_lib/sources/map/map_preview.cpp b/source/shared_lib/sources/map/map_preview.cpp new file mode 100644 index 000000000..ebb630322 --- /dev/null +++ b/source/shared_lib/sources/map/map_preview.cpp @@ -0,0 +1,820 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + + +#include "map_preview.h" + +//#include +#include "math_wrapper.h" +#include + +using namespace Shared::Util; +using namespace std; + +namespace Shared { namespace Map { + +// =============================================== +// class MapPreview +// =============================================== + +// ================== PUBLIC ===================== + +MapPreview::MapPreview() { + fileLoaded = false; + altFactor = DEFAULT_MAP_CELL_HEIGHT_FACTOR; + waterLevel = DEFAULT_MAP_WATER_DEPTH; + //cells = NULL; + cells.clear(); + //startLocations = NULL; + startLocations.clear(); + reset(DEFAULT_MAP_CELL_WIDTH, DEFAULT_MAP_CELL_LENGTH, DEFAULT_MAP_CELL_HEIGHT, DEFAULT_MAP_CELL_SURFACE_TYPE); + resetFactions(DEFAULT_MAP_FACTIONCOUNT); + title = ""; + desc = ""; + author = ""; + refAlt = DEFAULT_MAP_CELL_HEIGHT; +} + +MapPreview::~MapPreview() { + //delete [] startLocations; + //startLocations = NULL; + startLocations.clear(); + + //for (int i = 0; i < h; i++) { + // delete [] cells[i]; + //} + //delete [] cells; + //cells = NULL; + cells.clear(); +} + +float MapPreview::getHeight(int x, int y) const { + return cells[x][y].height; +} + +MapSurfaceType MapPreview::getSurface(int x, int y) const { + return static_cast(cells[x][y].surface); +} + +int MapPreview::getObject(int x, int y) const { + return cells[x][y].object; +} + +int MapPreview::getResource(int x, int y) const { + return cells[x][y].resource; +} + +int MapPreview::getStartLocationX(int index) const { + return startLocations[index].x; +} + +int MapPreview::getStartLocationY(int index) const { + return startLocations[index].y; +} + +static int get_dist(int delta_x, int delta_y) { + float dx = delta_x; + float dy = delta_y; + + return static_cast(sqrtf(dx * dx + dy * dy)); +} + +void MapPreview::glestChangeHeight(int x, int y, int height, int radius) { + + for (int i = x - radius + 1; i < x + radius; i++) { + for (int j = y - radius + 1; j < y + radius; j++) { + if (inside(i, j)) { + int dist = get_dist(i - x, j - y); + if (radius > dist) { + int oldAlt = static_cast(cells[i][j].height); + int altInc = height * (radius - dist - 1) / radius; + if (height > 0) { + altInc++; + } + if (height < 0) { + altInc--; + } + int newAlt = refAlt + altInc; + if ((height > 0 && newAlt > oldAlt) || (height < 0 && newAlt < oldAlt) || height == 0) { + if (newAlt >= 0 && newAlt <= 20) { + cells[i][j].height = static_cast(newAlt); + } + } + } + } + } + } +} + + +void MapPreview::pirateChangeHeight(int x, int y, int height, int radius) { + // Make sure not to try and blanket change the height over the bounds + // Find our goal height for the center of the brush + + int overBounds = refAlt + height; + int goalAlt = overBounds; + if (overBounds > 20) { + goalAlt = 20; + } + else if (overBounds < 0) { + goalAlt = 0; + } + + // If the radius is 1 don't bother doing any calculations + if (radius == 1) { + if(inside(x, y)){ + cells[x][y].height = goalAlt; + } + return; + } + + // Get Old height reference points and compute gradients + // from the heights of the sides and corners of the brush to the center goal height + float gradient[3][3]; // [i][j] + int indexI = 0; + for (int i = x - radius; i <= x + radius; i += radius) { + int indexJ = 0; + for (int j = y - radius; j <= y + radius; j += radius) { + // round off the corners + int ti, tj; + if (abs(i - x) == abs(j - y)) { + ti = (i - x) * 0.707 + x + 0.5; + tj = (j - y) * 0.707 + y + 0.5; + } else { + ti = i; + tj = j; + } + if (inside(ti, tj)) { + gradient[indexI][indexJ] = (cells[ti][tj].height - goalAlt) / radius; + //} else if (dist == 0) { + //gradient[indexI][indexJ] = 0; + } + else { + // assume outside the map bounds is height 10 + gradient[indexI][indexJ] = (10.0 - goalAlt) / radius; + } + //std::cout << "gradient[" << indexI << "][" << indexJ << "] = " << gradient[indexI][indexJ] << std::endl; + //std::cout << "derived from height " << cells[ti][tj].height << " at " << ti << " " << tj << std::endl; + indexJ++; + } + indexI++; + } + //std::cout << endl; + + // A brush with radius n cells should have a true radius of n-1 distance + radius -= 1; + for (int i = x - radius; i <= x + radius; i++) { + for (int j = y - radius; j <= y + radius; j++) { + int dist = get_dist(i - x, j - y); + if (inside(i, j) && dist < radius) { + // Normalize di and dj and round them to an int so they can be used as indicies + float normIf = (float(i - x)/ radius); + float normJf = (float(j - y)/ radius); + int normI[2]; + int normJ[2]; + float usedGrad; + + // Build a search box to find the gradients we are concerned about + // Find the nearest i indices + if (normIf < -0.33) { + normI[0] = 0; + if (normIf == 0) { + normI[1] = 0; + } + else { + normI[1] = 1; + } + } + else if (normIf < 0.33) { + normI[0] = 1; + if (normIf > 0) { + normI[1] = 2; + } + else if (normIf < 0) { + normI[1] = 0; + } + else /*(normIf == 0)*/ { + normI[1] = 1; + } + } + else { + normI[0] = 2; + if (normIf == 1) { + normI[1] = 2; + } + else { + normI[1] = 1; + } + } + // find nearest j indices + if (normJf < -0.33) { + normJ[0] = 0; + if (normJf == 0) { + normJ[1] = 0; + } + else { + normJ[1] = 1; + } + } + else if (normJf < 0.33) { + normJ[0] = 1; + if (normJf > 0) { + normJ[1] = 2; + } + else if (normJf < 0) { + normJ[1] = 0; + } + else /*(normJf == 0)*/ { + normJ[1] = 1; + } + } + else { + normJ[0] = 2; + if (normJf == 1) { + normJ[1] = 2; + } + else { + normJ[1] = 1; + } + } + + // Determine which gradients to use and take a weighted average + if (abs(normIf) > abs(normJf)) { + usedGrad = + gradient[normI[0]] [normJ[0]] * abs(normJf) + + gradient[normI[0]] [normJ[1]] * (1 - abs(normJf)); + } + else if (abs(normIf) < abs(normJf)) { + usedGrad = + gradient[normI[0]] [normJ[0]] * abs(normIf) + + gradient[normI[1]] [normJ[0]] * (1 - abs(normIf)); + } + else { + usedGrad = + gradient[normI[0]] [normJ[0]]; + } + + + float newAlt = usedGrad * dist + goalAlt; + + // if the change in height and what is supposed to be the change in height + // are the same sign then we can change the height + if ( ((newAlt - cells[i][j].height) > 0 && height > 0) || + ((newAlt - cells[i][j].height) < 0 && height < 0) || + height == 0) { + cells[i][j].height = newAlt; + } + } + } + } +} + +void MapPreview::setHeight(int x, int y, float height) { + cells[x][y].height = height; +} + +void MapPreview::setRefAlt(int x, int y) { + if (inside(x, y)) { + refAlt = static_cast(cells[x][y].height); + } +} + +void MapPreview::flipX() { + //Cell **oldCells = cells; + std::vector > oldCells = cells; + + //cells = new Cell*[w]; + cells.clear(); + cells.resize(w); + for (int i = 0; i < w; i++) { + //cells[i] = new Cell[h]; + cells[i].resize(h); + for (int j = 0; j < h; j++) { + cells[i][j].height = oldCells[w-i-1][j].height; + cells[i][j].object = oldCells[w-i-1][j].object; + cells[i][j].resource = oldCells[w-i-1][j].resource; + cells[i][j].surface = oldCells[w-i-1][j].surface; + } + } + + for (int i = 0; i < maxFactions; ++i) { + startLocations[i].x = w - startLocations[i].x - 1; + } + + //for (int i = 0; i < w; i++) { + // delete [] oldCells[i]; + //} + //delete [] oldCells; +} + +void MapPreview::flipY() { + //Cell **oldCells = cells; + std::vector > oldCells = cells; + + //cells = new Cell*[w]; + cells.clear(); + cells.resize(w); + + for (int i = 0; i < w; i++) { + //cells[i] = new Cell[h]; + cells[i].resize(h); + for (int j = 0; j < h; j++) { + cells[i][j].height = oldCells[i][h-j-1].height; + cells[i][j].object = oldCells[i][h-j-1].object; + cells[i][j].resource = oldCells[i][h-j-1].resource; + cells[i][j].surface = oldCells[i][h-j-1].surface; + } + } + + for (int i = 0; i < maxFactions; ++i) { + startLocations[i].y = h - startLocations[i].y - 1; + } + + //for (int i = 0; i < w; i++) { + // delete [] oldCells[i]; + //} + //delete [] oldCells; +} + +void MapPreview::changeSurface(int x, int y, MapSurfaceType surface, int radius) { + int i, j; + int dist; + + for (i = x - radius + 1; i < x + radius; i++) { + for (j = y - radius + 1; j < y + radius; j++) { + if (inside(i, j)) { + dist = get_dist(i - x, j - y); + if (radius >= dist) { + cells[i][j].surface = surface; + } + } + } + } +} + +void MapPreview::setSurface(int x, int y, MapSurfaceType surface) { + cells[x][y].surface = surface; +} + +void MapPreview::changeObject(int x, int y, int object, int radius) { + int i, j; + int dist; + + for (i = x - radius + 1; i < x + radius; i++) { + for (j = y - radius + 1; j < y + radius; j++) { + if (inside(i, j)) { + dist = get_dist(i - x, j - y); + if (radius >= dist) { + cells[i][j].object = object; + cells[i][j].resource = 0; + } + } + } + } +} + +void MapPreview::setObject(int x, int y, int object) { + cells[x][y].object = object; + if (object != 0) cells[x][y].resource = 0; +} + +void MapPreview::changeResource(int x, int y, int resource, int radius) { + int i, j; + int dist; + + for (i = x - radius + 1; i < x + radius; i++) { + for (j = y - radius + 1; j < y + radius; j++) { + if (inside(i, j)) { + dist = get_dist(i - x, j - y); + if (radius >= dist) { + cells[i][j].resource = resource; + cells[i][j].object = 0; + } + } + } + } +} + +void MapPreview::setResource(int x, int y, int resource) { + cells[x][y].resource = resource; + if (resource != 0) cells[x][y].object = 0; +} + +void MapPreview::changeStartLocation(int x, int y, int faction) { + if ((faction - 1) < maxFactions && inside(x, y)) { + startLocations[faction].x = x; + startLocations[faction].y = y; + } +} + +bool MapPreview::inside(int x, int y) { + return (x >= 0 && x < w && y >= 0 && y < h); +} + +void MapPreview::reset(int w, int h, float alt, MapSurfaceType surf) { + if (w < MIN_MAP_CELL_DIMENSION || h < MIN_MAP_CELL_DIMENSION) { + char szBuf[1024]=""; + sprintf(szBuf,"Size of map must be at least %dx%d",MIN_MAP_CELL_DIMENSION,MIN_MAP_CELL_DIMENSION); + throw runtime_error(szBuf); + return; + } + + if (w > MAX_MAP_CELL_DIMENSION || h > MAX_MAP_CELL_DIMENSION) { + char szBuf[1024]=""; + sprintf(szBuf,"Size of map can be at most %dx%d",MAX_MAP_CELL_DIMENSION,MAX_MAP_CELL_DIMENSION); + throw runtime_error(szBuf); + } + + if (alt < MIN_MAP_CELL_HEIGHT || alt > MAX_MAP_CELL_HEIGHT) { + char szBuf[1024]=""; + sprintf(szBuf,"Height must be in the range %d-%d",MIN_MAP_CELL_HEIGHT,MAX_MAP_CELL_HEIGHT); + throw runtime_error(szBuf); + } + + if (surf < st_Grass || surf > st_Ground) { + char szBuf[1024]=""; + sprintf(szBuf,"Surface must be in the range %d-%d",st_Grass,st_Ground); + throw runtime_error(szBuf); + } + + //if (cells != NULL) { + // for (int i = 0; i < this->w; i++) { + // delete [] cells[i]; + // } + // delete [] cells; + //} + cells.clear(); + + this->w = w; + this->h = h; + this->maxFactions = maxFactions; + + //cells = new Cell*[w]; + cells.resize(w); + for (int i = 0; i < w; i++) { + //cells[i] = new Cell[h]; + cells[i].resize(h); + for (int j = 0; j < h; j++) { + cells[i][j].height = alt; + cells[i][j].object = 0; + cells[i][j].resource = 0; + cells[i][j].surface = surf; + } + } +} + +void MapPreview::resize(int w, int h, float alt, MapSurfaceType surf) { + if (w < MIN_MAP_CELL_DIMENSION || h < MIN_MAP_CELL_DIMENSION) { + char szBuf[1024]=""; + sprintf(szBuf,"Size of map must be at least %dx%d",MIN_MAP_CELL_DIMENSION,MIN_MAP_CELL_DIMENSION); + throw runtime_error(szBuf); + return; + } + + if (w > MAX_MAP_CELL_DIMENSION || h > MAX_MAP_CELL_DIMENSION) { + char szBuf[1024]=""; + sprintf(szBuf,"Size of map can be at most %dx%d",MAX_MAP_CELL_DIMENSION,MAX_MAP_CELL_DIMENSION); + throw runtime_error(szBuf); + } + + if (alt < MIN_MAP_CELL_HEIGHT || alt > MAX_MAP_CELL_HEIGHT) { + char szBuf[1024]=""; + sprintf(szBuf,"Height must be in the range %d-%d",MIN_MAP_CELL_HEIGHT,MAX_MAP_CELL_HEIGHT); + throw runtime_error(szBuf); + } + + if (surf < st_Grass || surf > st_Ground) { + char szBuf[1024]=""; + sprintf(szBuf,"Surface must be in the range %d-%d",st_Grass,st_Ground); + throw runtime_error(szBuf); + } + + int oldW = this->w; + int oldH = this->h; + this->w = w; + this->h = h; + this->maxFactions = maxFactions; + + //create new cells + //Cell **oldCells = cells; + std::vector > oldCells = cells; + + //cells = new Cell*[w]; + cells.resize(w); + for (int i = 0; i < w; i++) { + //cells[i] = new Cell[h]; + cells[i].resize(h); + for (int j = 0; j < h; j++) { + cells[i][j].height = alt; + cells[i][j].object = 0; + cells[i][j].resource = 0; + cells[i][j].surface = surf; + } + } + + int wOffset = w < oldW ? 0 : (w - oldW) / 2; + int hOffset = h < oldH ? 0 : (h - oldH) / 2; + //assign old values to cells + for (int i = 0; i < oldW; i++) { + for (int j = 0; j < oldH; j++) { + if (i + wOffset < w && j + hOffset < h) { + cells[i+wOffset][j+hOffset].height = oldCells[i][j].height; + cells[i+wOffset][j+hOffset].object = oldCells[i][j].object; + cells[i+wOffset][j+hOffset].resource = oldCells[i][j].resource; + cells[i+wOffset][j+hOffset].surface = oldCells[i][j].surface; + } + } + } + for (int i = 0; i < maxFactions; ++i) { + startLocations[i].x += wOffset; + startLocations[i].y += hOffset; + } + + //delete old cells + //if (oldCells != NULL) { + // for (int i = 0; i < oldW; i++) + // delete [] oldCells[i]; + // delete [] oldCells; + //} +} + +void MapPreview::resetFactions(int maxPlayers) { + if (maxPlayers < MIN_MAP_FACTIONCOUNT || maxPlayers > MAX_MAP_FACTIONCOUNT) { + char szBuf[1024]=""; + sprintf(szBuf,"Max Players must be in the range %d-%d",MIN_MAP_FACTIONCOUNT,MAX_MAP_FACTIONCOUNT); + throw runtime_error(szBuf); + } + + //if (startLocations != NULL) { + // delete [] startLocations; + // startLocations = NULL; + //} + startLocations.clear(); + + maxFactions = maxPlayers; + + //startLocations = new StartLocation[maxFactions]; + startLocations.resize(maxFactions); + for (int i = 0; i < maxFactions; i++) { + startLocations[i].x = 0; + startLocations[i].y = 0; + } +} + +void MapPreview::setTitle(const string &title) { + this->title = title; +} + +void MapPreview::setDesc(const string &desc) { + this->desc = desc; +} + +void MapPreview::setAuthor(const string &author) { + this->author = author; +} + +void MapPreview::setAdvanced(int altFactor, int waterLevel) { + this->altFactor = altFactor; + this->waterLevel = waterLevel; +} + +int MapPreview::getHeightFactor() const { + return altFactor; +} + +int MapPreview::getWaterLevel() const { + return waterLevel; +} + +void MapPreview::randomizeHeights() { + resetHeights(random.randRange(8, 10)); + sinRandomize(0); + decalRandomize(4); + sinRandomize(1); +} + +void MapPreview::randomize() { + randomizeHeights(); + + int slPlaceFactorX = random.randRange(0, 1); + int slPlaceFactorY = random.randRange(0, 1) * 2; + + for (int i = 0; i < maxFactions; ++i) { + StartLocation sl; + float slNoiseFactor = random.randRange(0.5f, 0.8f); + + sl.x = static_cast(w * slNoiseFactor * ((i + slPlaceFactorX) % 2) + w * (1.f - slNoiseFactor) / 2.f); + sl.y = static_cast(h * slNoiseFactor * (((i + slPlaceFactorY) / 2) % 2) + h * (1.f - slNoiseFactor) / 2.f); + startLocations[i] = sl; + } +} + +void MapPreview::switchSurfaces(MapSurfaceType surf1, MapSurfaceType surf2) { + if (surf1 >= st_Grass && surf1 <= st_Ground && surf2 >= st_Grass && surf2 <= st_Ground) { + for (int i = 0; i < w; ++i) { + for (int j = 0; j < h; ++j) { + if (cells[i][j].surface == surf1) { + cells[i][j].surface = surf2; + } + else if (cells[i][j].surface == surf2) { + cells[i][j].surface = surf1; + } + } + } + } + else { + throw runtime_error("Incorrect surfaces"); + } +} + +void MapPreview::loadFromFile(const string &path) { + + FILE *f1 = fopen(path.c_str(), "rb"); + if (f1 != NULL) { + + //read header + MapFileHeader header; + size_t bytes = fread(&header, sizeof(MapFileHeader), 1, f1); + + altFactor = header.altFactor; + waterLevel = header.waterLevel; + title = header.title; + author = header.author; + desc = header.description; + + //read start locations + resetFactions(header.maxFactions); + for (int i = 0; i < maxFactions; ++i) { + bytes = fread(&startLocations[i].x, sizeof(int32), 1, f1); + bytes = fread(&startLocations[i].y, sizeof(int32), 1, f1); + } + + //read Heights + reset(header.width, header.height, DEFAULT_MAP_CELL_HEIGHT, DEFAULT_MAP_CELL_SURFACE_TYPE); + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + bytes = fread(&cells[i][j].height, sizeof(float), 1, f1); + } + } + + //read surfaces + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + bytes = fread(&cells[i][j].surface, sizeof(int8), 1, f1); + } + } + + //read objects + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + int8 obj; + bytes = fread(&obj, sizeof(int8), 1, f1); + if (obj <= 10) { + cells[i][j].object = obj; + } + else { + cells[i][j].resource = obj - 10; + } + } + } + + fclose(f1); + + fileLoaded = true; + } + else { + throw runtime_error("error opening map file: " + path); + } +} + + +void MapPreview::saveToFile(const string &path) { + + FILE *f1 = fopen(path.c_str(), "wb"); + if (f1 != NULL) { + + //write header + MapFileHeader header; + + header.version = 1; + header.maxFactions = maxFactions; + header.width = w; + header.height = h; + header.altFactor = altFactor; + header.waterLevel = waterLevel; + strncpy(header.title, title.c_str(), 128); + strncpy(header.author, author.c_str(), 128); + strncpy(header.description, desc.c_str(), 256); + + fwrite(&header, sizeof(MapFileHeader), 1, f1); + + //write start locations + for (int i = 0; i < maxFactions; ++i) { + fwrite(&startLocations[i].x, sizeof(int32), 1, f1); + fwrite(&startLocations[i].y, sizeof(int32), 1, f1); + } + + //write Heights + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + fwrite(&cells[i][j].height, sizeof(float32), 1, f1); + } + } + + //write surfaces + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + fwrite(&cells[i][j].surface, sizeof(int8), 1, f1); + } + } + + //write objects + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + if (cells[i][j].resource == 0) + fwrite(&cells[i][j].object, sizeof(int8), 1, f1); + else { + int8 res = cells[i][j].resource + 10; + fwrite(&res, sizeof(int8), 1, f1); + } + } + } + + fclose(f1); + + } + else { + throw runtime_error("Error opening map file: " + path); + } + + void randomHeight(int x, int y, int height); +} + +// ==================== PRIVATE ==================== + +void MapPreview::resetHeights(int height) { + for (int i = 0; i < w; ++i) { + for (int j = 0; j < h; ++j) { + cells[i][j].height = static_cast(height); + } + } +} + +void MapPreview::sinRandomize(int strenght) { + float sinH1 = random.randRange(5.f, 40.f); + float sinH2 = random.randRange(5.f, 40.f); + float sinV1 = random.randRange(5.f, 40.f); + float sinV2 = random.randRange(5.f, 40.f); + float ah = static_cast(10 + random.randRange(-2, 2)); + float bh = static_cast((maxHeight - minHeight) / random.randRange(2, 3)); + float av = static_cast(10 + random.randRange(-2, 2)); + float bv = static_cast((maxHeight - minHeight) / random.randRange(2, 3)); + + for (int i = 0; i < w; ++i) { + for (int j = 0; j < h; ++j) { + float normH = static_cast(i) / w; + float normV = static_cast(j) / h; + + float sh = (sinf(normH * sinH1) + sin(normH * sinH2)) / 2.f; + float sv = (sinf(normV * sinV1) + sin(normV * sinV2)) / 2.f; + + float newHeight = (ah + bh * sh + av + bv * sv) / 2.f; + applyNewHeight(newHeight, i, j, strenght); + } + } +} + +void MapPreview::decalRandomize(int strenght) { + //first row + int lastHeight = DEFAULT_MAP_CELL_HEIGHT; + for (int i = 0; i < w; ++i) { + lastHeight += random.randRange(-1, 1); + lastHeight = clamp(lastHeight, minHeight, maxHeight); + applyNewHeight(static_cast(lastHeight), i, 0, strenght); + } + + //other rows + for (int j = 1; j < h; ++j) { + int height = static_cast(cells[0][j-1].height + random.randRange(-1, 1)); + applyNewHeight(static_cast(clamp(height, minHeight, maxHeight)), 0, j, strenght); + for (int i = 1; i < w; ++i) { + height = static_cast((cells[i][j-1].height + cells[i-1][j].height) / 2.f + random.randRange(-1, 1)); + float newHeight = static_cast(clamp(height, minHeight, maxHeight)); + applyNewHeight(newHeight, i, j, strenght); + } + } +} + +void MapPreview::applyNewHeight(float newHeight, int x, int y, int strenght) { + cells[x][y].height = static_cast(((cells[x][y].height * strenght) + newHeight) / (strenght + 1)); +} + +}}// end namespace