diff --git a/mk/linux/Jamfile b/mk/linux/Jamfile index f9cddf44..7e67c726 100644 --- a/mk/linux/Jamfile +++ b/mk/linux/Jamfile @@ -74,6 +74,7 @@ if $(WX_AVAILABLE) = "yes" { } ### Viewer ### +if $(WX_AVAILABLE) = "yes" { SubDir TOP g3d_viewer ; GLEST_VIEWER_DIRS = . ; @@ -85,6 +86,7 @@ if $(WX_AVAILABLE) = "yes" { LinkWith glest_g3dviewer : glestlib ; ExternalLibs glest_g3dviewer : SDL GL GLU WX ; IncludeDir glest_g3dviewer : ../shared_lib/include/$(LIB_INCLUDE_DIRS) $(GLEST_VIEWER_DIRS) ; +} ### Configurator ### SubDir TOP configurator ; diff --git a/source/g3d_viewer/main.cpp b/source/g3d_viewer/main.cpp index f44eb04a..0b0b9e77 100644 --- a/source/g3d_viewer/main.cpp +++ b/source/g3d_viewer/main.cpp @@ -2,7 +2,8 @@ #include -#include "graphics_factory_gl.h" +//#include "graphics_factory_gl.h" +#include "model_gl.h" #include "graphics_interface.h" #include "util.h" #include "conversion.h" diff --git a/source/g3d_viewer/main.h b/source/g3d_viewer/main.h index 1b64eb40..d48754ff 100644 --- a/source/g3d_viewer/main.h +++ b/source/g3d_viewer/main.h @@ -3,14 +3,11 @@ #include -#include -#include +#include +#include #include "renderer.h" -//#include "util.h" - -//using Shared::Platform::Window; -//using Shared::Platform::MouseState; +#include "util.h" using std::string; diff --git a/source/g3d_viewer/renderer.cpp b/source/g3d_viewer/renderer.cpp index bce37cc1..29dd79ea 100644 --- a/source/g3d_viewer/renderer.cpp +++ b/source/g3d_viewer/renderer.cpp @@ -1,12 +1,8 @@ #include "renderer.h" -#include "opengl.h" -//#include "texture_gl.h" #include "graphics_factory_gl.h" #include "graphics_interface.h" -//#include "factory_repository.h" - using namespace Shared::Graphics; using namespace Shared::Graphics::Gl; diff --git a/source/glest_game/menu/menu_state_custom_game.cpp b/source/glest_game/menu/menu_state_custom_game.cpp new file mode 100644 index 00000000..b0d1966a --- /dev/null +++ b/source/glest_game/menu/menu_state_custom_game.cpp @@ -0,0 +1,646 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2005 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 "menu_state_custom_game.h" + +#include "renderer.h" +#include "sound_renderer.h" +#include "core_data.h" +#include "config.h" +#include "menu_state_new_game.h" +#include "metrics.h" +#include "network_manager.h" +#include "network_message.h" +#include "client_interface.h" +#include "conversion.h" +#include "socket.h" +#include "game.h" + +#include "leak_dumper.h" +#include + +namespace Glest{ namespace Game{ + +using namespace Shared::Util; + +// ===================================================== +// class MenuStateCustomGame +// ===================================================== + +MenuStateCustomGame::MenuStateCustomGame(Program *program, MainMenu *mainMenu, bool openNetworkSlots): + MenuState(program, mainMenu, "new-game") +{ + Lang &lang= Lang::getInstance(); + NetworkManager &networkManager= NetworkManager::getInstance(); + + needToSetChangedGameSettings = false; + lastSetChangedGameSettings = time(NULL);; + + vector glestMaps, megaMaps, teamItems, controlItems; + + //create + buttonReturn.init(350, 140, 125); + buttonPlayNow.init(525, 140, 125); + + //map listBox + findAll("maps/*.gbm", glestMaps, true, true); + findAll("maps/*.mgm", megaMaps, true, false); + + mapFiles.resize(glestMaps.size() + megaMaps.size()); + if (!glestMaps.empty()) { + copy(glestMaps.begin(), glestMaps.end(), mapFiles.begin()); + } + if (!megaMaps.empty()) { + copy(megaMaps.begin(), megaMaps.end(), mapFiles.begin() + glestMaps.size()); + } + if(mapFiles.size()==0){ + throw runtime_error("There are no maps"); + } + vector results; + for(int i= 0; i < mapFiles.size(); ++i){ + results.push_back(formatString(mapFiles[i])); + } + listBoxMap.init(200, 260, 150); + listBoxMap.setItems(results); + labelMap.init(200, 290); + labelMapInfo.init(200, 230, 200, 40); + + //tileset listBox + findAll("tilesets/*.", results); + if(results.size()==0){ + throw runtime_error("There is no tile set"); + } + tilesetFiles= results; + for(int i= 0; isetState(new MenuStateNewGame(program, mainMenu)); + } + else if(buttonPlayNow.mouseClick(x,y) && buttonPlayNow.getEnabled()) { + + closeUnusedSlots(); + soundRenderer.playFx(coreData.getClickSoundC()); + + GameSettings gameSettings; + loadGameSettings(&gameSettings); + + // Send the game settings to each client if we have at least one networked client + if( hasNetworkGameSettings() == true && + needToSetChangedGameSettings == true) + { + serverInterface->setGameSettings(&gameSettings,true); + + needToSetChangedGameSettings = false; + lastSetChangedGameSettings = time(NULL); + } + + bool bOkToStart = serverInterface->launchGame(&gameSettings); + if(bOkToStart == true) + { + + program->setState(new Game(program, &gameSettings)); + } + } + else if(listBoxMap.mouseClick(x, y)){ + printf("%s\n", mapFiles[listBoxMap.getSelectedItemIndex()].c_str()); + + loadMapInfo(Map::getMapPath(mapFiles[listBoxMap.getSelectedItemIndex()]), &mapInfo); + labelMapInfo.setText(mapInfo.desc); + updateControlers(); + + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + else if(listBoxTileset.mouseClick(x, y)){ + + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + else if(listBoxTechTree.mouseClick(x, y)){ + reloadFactions(); + + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + else + { + for(int i=0; i(listBoxControls[j].getSelectedItemIndex()); + if(ct==ctHuman){ + if(humanIndex1==-1){ + humanIndex1= j; + } + else{ + humanIndex2= j; + } + } + } + + //no human + if(humanIndex1==-1 && humanIndex2==-1){ + listBoxControls[i].setSelectedItemIndex(ctHuman); + } + + //2 humans + if(humanIndex1!=-1 && humanIndex2!=-1){ + listBoxControls[humanIndex1==i? humanIndex2: humanIndex1].setSelectedItemIndex(ctClosed); + } + updateNetworkSlots(); + + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + else if(listBoxFactions[i].mouseClick(x, y)){ + + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + else if(listBoxTeams[i].mouseClick(x, y)) + { + if(hasNetworkGameSettings() == true) + { + needToSetChangedGameSettings = true; + lastSetChangedGameSettings = time(NULL);; + } + } + } + } +} + +void MenuStateCustomGame::mouseMove(int x, int y, const MouseState *ms){ + + buttonReturn.mouseMove(x, y); + buttonPlayNow.mouseMove(x, y); + + for(int i=0; igetSlot(i); + + assert(connectionSlot!=NULL); + + //if(Socket::enableDebugText) printf("In [%s::%s] A - ctNetwork\n",__FILE__,__FUNCTION__); + + if(connectionSlot->isConnected()) + { + haveAtLeastOneNetworkClientConnected = true; + //if(Socket::enableDebugText) printf("In [%s::%s] B - ctNetwork\n",__FILE__,__FUNCTION__); + + string label = connectionSlot->getName(); + if(connectionSlot->getAllowDownloadDataSynch() == true && + connectionSlot->getAllowGameDataSynchCheck() == true) + { + if(connectionSlot->getNetworkGameDataSynchCheckOk() == false) + { + label = connectionSlot->getName() + " - waiting to synch:"; + if(connectionSlot->getNetworkGameDataSynchCheckOkMap() == false) + { + label = label + " map"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkTile() == false) + { + label = label + " tile"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkTech() == false) + { + label = label + " techtree"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkFogOfWar() == false) + { + label = label + " FogOfWar == false"; + } + + } + else + { + label = connectionSlot->getName() + " - data synch is ok"; + } + } + else + { + label = connectionSlot->getName(); + + if(connectionSlot->getAllowGameDataSynchCheck() == true) + { + label += " - warning synch mismatch for:"; + if(connectionSlot->getNetworkGameDataSynchCheckOkMap() == false) + { + label = label + " map"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkTile() == false) + { + label = label + " tile"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkTech() == false) + { + label = label + " techtree"; + } + if(connectionSlot->getNetworkGameDataSynchCheckOkFogOfWar() == false) + { + label = label + " FogOfWar == false"; + } + } + } + + labelNetStatus[i].setText(label); + } + else + { + //if(Socket::enableDebugText) printf("In [%s::%s] C - ctNetwork\n",__FILE__,__FUNCTION__); + + labelNetStatus[i].setText(lang.get("NotConnected")); + } + + //if(Socket::enableDebugText) printf("In [%s::%s] END - ctNetwork\n",__FILE__,__FUNCTION__); + } + else{ + labelNetStatus[i].setText(""); + } + } + + // Send the game settings to each client if we have at least one networked client + if( serverInterface->getAllowDownloadDataSynch() == true && + haveAtLeastOneNetworkClientConnected == true && + needToSetChangedGameSettings == true && + difftime(time(NULL),lastSetChangedGameSettings) >= 2) + { + GameSettings gameSettings; + loadGameSettings(&gameSettings); + serverInterface->setGameSettings(&gameSettings); + + needToSetChangedGameSettings = false; + lastSetChangedGameSettings = time(NULL); + } + + //call the chat manager + chatManager.updateNetwork(); + + //console + console.update(); +} + +void MenuStateCustomGame::loadGameSettings(GameSettings *gameSettings) +{ + //if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__); + + int factionCount= 0; + + gameSettings->setDescription(formatString(mapFiles[listBoxMap.getSelectedItemIndex()])); + gameSettings->setMap(mapFiles[listBoxMap.getSelectedItemIndex()]); + gameSettings->setTileset(tilesetFiles[listBoxTileset.getSelectedItemIndex()]); + gameSettings->setTech(techTreeFiles[listBoxTechTree.getSelectedItemIndex()]); + gameSettings->setDefaultUnits(true); + gameSettings->setDefaultResources(true); + gameSettings->setDefaultVictoryConditions(true); + + for(int i=0; i(listBoxControls[i].getSelectedItemIndex()); + if(ct != ctClosed) + { + if(ct == ctHuman) + { + gameSettings->setThisFactionIndex(factionCount); + } + gameSettings->setFactionControl(factionCount, ct); + gameSettings->setTeam(factionCount, listBoxTeams[i].getSelectedItemIndex()); + gameSettings->setStartLocationIndex(factionCount, i); + gameSettings->setFactionTypeName(factionCount, factionFiles[listBoxFactions[i].getSelectedItemIndex()]); + factionCount++; + } + } + gameSettings->setFactionCount(factionCount); + + //if(Socket::enableDebugText) printf("In [%s::%s] gameSettings->getTileset() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getTileset().c_str()); + //if(Socket::enableDebugText) printf("In [%s::%s] gameSettings->getTech() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getTech().c_str()); + //if(Socket::enableDebugText) printf("In [%s::%s] gameSettings->getMap() = [%s]\n",__FILE__,__FUNCTION__,gameSettings->getMap().c_str()); + + //if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__); +} + +// ============ PRIVATE =========================== + +bool MenuStateCustomGame::hasNetworkGameSettings() +{ + bool hasNetworkSlot = false; + + for(int i=0; i(listBoxControls[i].getSelectedItemIndex()); + if(ct != ctClosed) + { + if(ct == ctNetwork) + { + hasNetworkSlot = true; + break; + } + } + } + + return hasNetworkSlot; +} + +void MenuStateCustomGame::loadMapInfo(string file, MapInfo *mapInfo){ + + struct MapFileHeader{ + int32 version; + int32 maxPlayers; + int32 width; + int32 height; + int32 altFactor; + int32 waterLevel; + int8 title[128]; + }; + + Lang &lang= Lang::getInstance(); + + try{ + FILE *f= fopen(file.c_str(), "rb"); + if(f==NULL) + throw runtime_error("Can't open file"); + + MapFileHeader header; + size_t readBytes = fread(&header, sizeof(MapFileHeader), 1, f); + + mapInfo->size.x= header.width; + mapInfo->size.y= header.height; + mapInfo->players= header.maxPlayers; + + mapInfo->desc= lang.get("MaxPlayers")+": "+intToStr(mapInfo->players)+"\n"; + mapInfo->desc+=lang.get("Size")+": "+intToStr(mapInfo->size.x) + " x " + intToStr(mapInfo->size.y); + + fclose(f); + } + catch(exception e){ + throw runtime_error("Error loading map file: "+file+'\n'+e.what()); + } + +} + +void MenuStateCustomGame::reloadFactions(){ + + vector results; + + findAll("techs/"+techTreeFiles[listBoxTechTree.getSelectedItemIndex()]+"/factions/*.", results); + if(results.size()==0){ + throw runtime_error("There is no factions for this tech tree"); + } + factionFiles= results; + for(int i= 0; igetSlot(i)->isConnected()){ + listBoxControls[i].setSelectedItemIndex(ctClosed); + } + } + } + updateNetworkSlots(); +} + +void MenuStateCustomGame::updateNetworkSlots() +{ + ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface(); + + for(int i= 0; igetSlot(i) == NULL && listBoxControls[i].getSelectedItemIndex() == ctNetwork) + { + serverInterface->addSlot(i); + } + if(serverInterface->getSlot(i) != NULL && listBoxControls[i].getSelectedItemIndex() != ctNetwork) + { + serverInterface->removeSlot(i); + } + } +} + +void MenuStateCustomGame::keyDown(char key) +{ + //send key to the chat manager + chatManager.keyDown(key); +} + +void MenuStateCustomGame::keyPress(char c) +{ + chatManager.keyPress(c); +} + + +}}//end namespace diff --git a/source/glest_game/world/map.cpp b/source/glest_game/world/map.cpp new file mode 100644 index 00000000..cdba6f9e --- /dev/null +++ b/source/glest_game/world/map.cpp @@ -0,0 +1,704 @@ +// ============================================================== +// 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.h" + +#include + +#include "tileset.h" +#include "unit.h" +#include "resource.h" +#include "logger.h" +#include "tech_tree.h" +#include "config.h" +#include "leak_dumper.h" +#include "util.h" + +using namespace Shared::Graphics; +using namespace Shared::Util; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class Cell +// ===================================================== + +Cell::Cell(){ + //game data + for(int i=0; iisPutrefacting(); +} + +// ===================================================== +// class SurfaceCell +// ===================================================== + +SurfaceCell::SurfaceCell(){ + object= NULL; + vertex= Vec3f(0.f); + normal= Vec3f(0.f, 1.f, 0.f); + surfaceType= -1; + surfaceTexture= NULL; +} + +SurfaceCell::~SurfaceCell(){ + delete object; +} + +bool SurfaceCell::isFree() const{ + return object==NULL || object->getWalkable(); +} + +void SurfaceCell::deleteResource(){ + delete object; + object= NULL; +} + +void SurfaceCell::setExplored(int teamIndex, bool explored){ + this->explored[teamIndex]= explored; +} + +void SurfaceCell::setVisible(int teamIndex, bool visible){ + this->visible[teamIndex]= visible; +} + +// ===================================================== +// class Map +// ===================================================== + +// ===================== PUBLIC ======================== + +const int Map::cellScale= 2; +const int Map::mapScale= 2; + +Map::Map(){ + cells= NULL; + surfaceCells= NULL; + startLocations= NULL; +} + +Map::~Map(){ + Logger::getInstance().add("Cells", true); + + delete [] cells; + delete [] surfaceCells; + delete [] startLocations; +} + +void Map::load(const string &path, TechTree *techTree, Tileset *tileset){ + + struct MapFileHeader{ + int32 version; + int32 maxPlayers; + int32 width; + int32 height; + int32 altFactor; + int32 waterLevel; + int8 title[128]; + int8 author[128]; + int8 description[256]; + }; + + try{ + FILE *f= fopen(path.c_str(), "rb"); + if(f!=NULL){ + + //read header + MapFileHeader header; + size_t readBytes = fread(&header, sizeof(MapFileHeader), 1, f); + + if(next2Power(header.width) != header.width){ + throw runtime_error("Map width is not a power of 2"); + } + + if(next2Power(header.height) != header.height){ + throw runtime_error("Map height is not a power of 2"); + } + + heightFactor= header.altFactor; + waterLevel= static_cast((header.waterLevel-0.01f)/heightFactor); + title= header.title; + maxPlayers= header.maxPlayers; + surfaceW= header.width; + surfaceH= header.height; + w= surfaceW*cellScale; + h= surfaceH*cellScale; + + + //start locations + startLocations= new Vec2i[maxPlayers]; + for(int i=0; isetVertex(Vec3f(i*mapScale, alt / heightFactor, j*mapScale)); + } + } + + //read surfaces + for(int j=0; jsetSurfaceType(surf-1); + } + } + + //read objects and resources + for(int j=0; jsetObject(NULL); + } + else if(objNumber <= Tileset::objCount){ + Object *o= new Object(tileset->getObjectType(objNumber-1), sc->getVertex()); + sc->setObject(o); + for(int k=0; kgetResourceTypeCount(); ++k){ + const ResourceType *rt= techTree->getResourceType(k); + if(rt->getClass()==rcTileset && rt->getTilesetObject()==objNumber){ + o->setResource(rt, Vec2i(i, j)); + } + } + } + else{ + const ResourceType *rt= techTree->getTechResourceType(objNumber - Tileset::objCount) ; + Object *o= new Object(NULL, sc->getVertex()); + o->setResource(rt, Vec2i(i, j)); + sc->setObject(o); + } + } + } + } + else{ + throw runtime_error("Can't open file"); + } + fclose(f); + } + catch(const exception &e){ + throw runtime_error("Error loading map: "+ path+ "\n"+ e.what()); + } +} + +void Map::init(){ + Logger::getInstance().add("Heightmap computations", true); + smoothSurface(); + computeNormals(); + computeInterpolatedHeights(); + computeNearSubmerged(); + computeCellColors(); +} + + +// ==================== is ==================== + +bool Map::isInside(int x, int y) const{ + return x>=0 && y>=0 && x=0 && sy>=0 && sxgetResource(); + if(r!=NULL){ + if(r->getType()==rt){ + resourcePos= pos + Vec2i(i,j); + return true; + } + } + } + } + } + return false; +} + + +// ==================== free cells ==================== + +bool Map::isFreeCell(const Vec2i &pos, Field field) const{ + return + isInside(pos) && + getCell(pos)->isFree(field) && + (field==fAir || getSurfaceCell(toSurfCoords(pos))->isFree()) && + (field!=fLand || !getDeepSubmerged(getCell(pos))); +} + +bool Map::isFreeCellOrHasUnit(const Vec2i &pos, Field field, const Unit *unit) const{ + if(isInside(pos)){ + Cell *c= getCell(pos); + if(c->getUnit(unit->getCurrField())==unit){ + return true; + } + else{ + return isFreeCell(pos, field); + } + } + return false; +} + +bool Map::isAproxFreeCell(const Vec2i &pos, Field field, int teamIndex) const{ + + if(isInside(pos)){ + const SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos)); + + if(sc->isVisible(teamIndex)){ + return isFreeCell(pos, field); + } + else if(sc->isExplored(teamIndex)){ + return field==fLand? sc->isFree() && !getDeepSubmerged(getCell(pos)): true; + } + else{ + return true; + } + } + return false; +} + +bool Map::isFreeCells(const Vec2i & pos, int size, Field field) const{ + for(int i=pos.x; igetType()->getSize(); + + for(int i=pos2.x; igetUnit(unit->getCurrField())!=unit){ + if(!isFreeCell(Vec2i(i, j), unit->getCurrField())){ + return false; + } + } + } + else{ + return false; + } + } + } + return true; +} + +//checks if a unit can move from between 2 cells using only visible cells (for pathfinding) +bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2) const{ + int size= unit->getType()->getSize(); + int teamIndex= unit->getTeam(); + Field field= unit->getCurrField(); + + //single cell units + if(size==1){ + if(!isAproxFreeCell(pos2, field, teamIndex)){ + return false; + } + if(pos1.x!=pos2.x && pos1.y!=pos2.y){ + if(!isAproxFreeCell(Vec2i(pos1.x, pos2.y), field, teamIndex)){ + return false; + } + if(!isAproxFreeCell(Vec2i(pos2.x, pos1.y), field, teamIndex)){ + return false; + } + } + return true; + } + + //multi cell units + else{ + for(int i=pos2.x; igetUnit(unit->getCurrField())!=unit){ + if(!isAproxFreeCell(Vec2i(i, j), field, teamIndex)){ + return false; + } + } + } + else{ + return false; + } + } + } + return true; + } +} + +//put a units into the cells +void Map::putUnitCells(Unit *unit, const Vec2i &pos){ + + assert(unit!=NULL); + const UnitType *ut= unit->getType(); + + for(int i=0; igetSize(); ++i){ + for(int j=0; jgetSize(); ++j){ + Vec2i currPos= pos + Vec2i(i, j); + assert(isInside(currPos)); + if(!ut->hasCellMap() || unit->getCellMapCell(i, j)){ + assert(getCell(currPos)->getUnit(unit->getCurrField())==NULL); + getCell(currPos)->setUnit(unit->getCurrField(), unit); + } + + } + } + unit->setPos(pos); +} + +//removes a unit from cells +void Map::clearUnitCells(Unit *unit, const Vec2i &pos){ + + assert(unit!=NULL); + const UnitType *ut= unit->getType(); + + for(int i=0; igetSize(); ++i){ + for(int j=0; jgetSize(); ++j){ + Vec2i currPos= pos + Vec2i(i, j); + assert(isInside(currPos)); + if(!ut->hasCellMap() || unit->getCellMapCell(i, j)){ + assert(getCell(currPos)->getUnit(unit->getCurrField())==unit); + getCell(currPos)->setUnit(unit->getCurrField(), NULL); + } + } + } +} + +// ==================== misc ==================== + +//returnis if unit is next to pos +bool Map::isNextTo(const Vec2i &pos, const Unit *unit) const{ + + for(int i=-1; i<=1; ++i){ + for(int j=-1; j<=1; ++j){ + if(isInside(pos.x+i, pos.y+j)) { + if(getCell(pos.x+i, pos.y+j)->getUnit(fLand)==unit){ + return true; + } + } + } + } + return false; +} + +void Map::clampPos(Vec2i &pos) const{ + if(pos.x<0){ + pos.x=0; + } + if(pos.y<0){ + pos.y=0; + } + if(pos.x>=w){ + pos.x=w-1; + } + if(pos.y>=h){ + pos.y=h-1; + } +} + +void Map::prepareTerrain(const Unit *unit){ + flatternTerrain(unit); + computeNormals(); + computeInterpolatedHeights(); +} + +// ==================== PRIVATE ==================== + +// ==================== compute ==================== + +void Map::flatternTerrain(const Unit *unit){ + float refHeight= getSurfaceCell(toSurfCoords(unit->getCenteredPos()))->getHeight(); + for(int i=-1; i<=unit->getType()->getSize(); ++i){ + for(int j=-1; j<=unit->getType()->getSize(); ++j){ + Vec2i pos= unit->getPos()+Vec2i(i, j); + Cell *c= getCell(pos); + SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos)); + //we change height if pos is inside world, if its free or ocupied by the currenty building + if(isInside(pos) && sc->getObject()==NULL && (c->getUnit(fLand)==NULL || c->getUnit(fLand)==unit)){ + sc->setHeight(refHeight); + } + } + } +} + +//compute normals +void Map::computeNormals(){ + //compute center normals + for(int i=1; isetNormal( + getSurfaceCell(i, j)->getVertex().normal(getSurfaceCell(i, j-1)->getVertex(), + getSurfaceCell(i+1, j)->getVertex(), + getSurfaceCell(i, j+1)->getVertex(), + getSurfaceCell(i-1, j)->getVertex())); + } + } +} + +void Map::computeInterpolatedHeights(){ + + for(int i=0; isetHeight(getSurfaceCell(toSurfCoords(Vec2i(i, j)))->getHeight()); + } + } + + for(int i=1; isetHeight(getSurfaceCell(i, j)->getHeight()); + } + else if(k!=0 && l==0){ + getCell(i*cellScale+k, j*cellScale)->setHeight(( + getSurfaceCell(i, j)->getHeight()+ + getSurfaceCell(i+1, j)->getHeight())/2.f); + } + else if(l!=0 && k==0){ + getCell(i*cellScale, j*cellScale+l)->setHeight(( + getSurfaceCell(i, j)->getHeight()+ + getSurfaceCell(i, j+1)->getHeight())/2.f); + } + else{ + getCell(i*cellScale+k, j*cellScale+l)->setHeight(( + getSurfaceCell(i, j)->getHeight()+ + getSurfaceCell(i, j+1)->getHeight()+ + getSurfaceCell(i+1, j)->getHeight()+ + getSurfaceCell(i+1, j+1)->getHeight())/4.f); + } + } + } + } + } +} + + +void Map::smoothSurface(){ + + float *oldHeights= new float[surfaceW*surfaceH]; + + for(int i=0; isetHeight(height); + Object *object= getSurfaceCell(i, j)->getObject(); + if(object!=NULL){ + object->setHeight(height); + } + } + } + + delete [] oldHeights; +} + +void Map::computeNearSubmerged(){ + + for(int i=0; isetNearSubmerged(anySubmerged); + } + } +} + +void Map::computeCellColors(){ + for(int i=0; igetHeight()*1.5f, 1.f, 1.5f); + sc->setColor(Vec3f(1.0f, 1.0f, 1.0f)/factor); + } + else{ + sc->setColor(Vec3f(1.0f, 1.0f, 1.0f)); + } + } + } +} + +// static +string Map::getMapPath(const string &mapName) { + string mega = "maps/" + mapName + ".mgm"; + string glest = "maps/" + mapName + ".gbm"; + if (fileExists(mega)) { + return mega; + } else if (fileExists(glest)) { + return glest; + } else { + throw runtime_error("Map " + mapName + " not found."); + } +} + +// ===================================================== +// class PosCircularIterator +// ===================================================== + +PosCircularIterator::PosCircularIterator(const Map *map, const Vec2i ¢er, int radius){ + this->map= map; + this->radius= radius; + this->center= center; + pos= center - Vec2i(radius, radius); + pos.x-= 1; +} + +bool PosCircularIterator::next(){ + + //iterate while dont find a cell that is inside the world + //and at less or equal distance that the radius + do{ + pos.x++; + if(pos.x > center.x+radius){ + pos.x= center.x-radius; + pos.y++; + } + if(pos.y>center.y+radius) + return false; + } + while(floor(pos.dist(center)) >= (radius+1) || !map->isInside(pos)); + //while(!(pos.dist(center) <= radius && map->isInside(pos))); + + return true; +} + +const Vec2i &PosCircularIterator::getPos(){ + return pos; +} + + +// ===================================================== +// class PosQuadIterator +// ===================================================== + +PosQuadIterator::PosQuadIterator(const Map *map, const Quad2i &quad, int step){ + this->map= map; + this->quad= quad; + this->boundingRect= quad.computeBoundingRect(); + this->step= step; + pos= boundingRect.p[0]; + --pos.x; + pos.x= (pos.x/step)*step; + pos.y= (pos.y/step)*step; +} + +bool PosQuadIterator::next(){ + + do{ + pos.x+= step; + if(pos.x > boundingRect.p[1].x){ + pos.x= (boundingRect.p[0].x/step)*step; + pos.y+= step; + } + if(pos.y>boundingRect.p[1].y) + return false; + } + while(!quad.isInside(pos)); + + return true; +} + +void PosQuadIterator::skipX(){ + pos.x+= step; +} + +const Vec2i &PosQuadIterator::getPos(){ + return pos; +} + +}}//end namespace diff --git a/source/glest_map_editor/main.cpp b/source/glest_map_editor/main.cpp index 7f85cb23..d572ab99 100755 --- a/source/glest_map_editor/main.cpp +++ b/source/glest_map_editor/main.cpp @@ -9,8 +9,6 @@ // License, or (at your option) any later version // ============================================================== - - #include "main.h" #include diff --git a/source/glest_map_editor/map.cpp b/source/glest_map_editor/map.cpp new file mode 100644 index 00000000..832338f7 --- /dev/null +++ b/source/glest_map_editor/map.cpp @@ -0,0 +1,756 @@ +// ============================================================== +// 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.h" + +#include +#include + +using namespace Shared::Util; +using namespace std; + +namespace MapEditor { + +// =============================================== +// class Map +// =============================================== + +// ================== PUBLIC ===================== + +Map::Map() { + altFactor = 3; + waterLevel = 4; + cells = NULL; + startLocations = NULL; + reset(64, 64, 10.f, 1); + resetFactions(8); + title = ""; + desc = ""; + author = ""; + refAlt = 10; +} + +Map::~Map() { + delete [] startLocations; + for (int i = 0; i < h; i++) { + delete cells[i]; + } + delete cells; +} + + +float Map::getHeight(int x, int y) const { + return cells[x][y].height; +} + +int Map::getSurface(int x, int y) const { + return cells[x][y].surface; +} + +int Map::getObject(int x, int y) const { + return cells[x][y].object; +} + +int Map::getResource(int x, int y) const { + return cells[x][y].resource; +} + +int Map::getStartLocationX(int index) const { + return startLocations[index].x; +} + +int Map::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 Map::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 Map::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 centre of the brush + int goalAlt; + int overBounds = refAlt + height; + if (overBounds > 20) { + goalAlt = 20; + } + else if (overBounds < 0) { + goalAlt = 0; + } else { + goalAlt = overBounds; + } + + // If the radius is 1 don't bother doing any calculations + if (radius == 1) { + 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 centre 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 Map::setHeight(int x, int y, float height) { + cells[x][y].height = height; +} + +void Map::setRefAlt(int x, int y) { + if (inside(x, y)) { + refAlt = static_cast(cells[x][y].height); + } +} + +void Map::flipX() { + Cell **oldCells = cells; + + cells = new Cell*[w]; + for (int i = 0; i < w; i++) { + cells[i] = new Cell[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 Map::flipY() { + Cell **oldCells = cells; + + cells = new Cell*[w]; + for (int i = 0; i < w; i++) { + cells[i] = new Cell[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 Map::changeSurface(int x, int y, int 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 Map::setSurface(int x, int y, int surface) { + cells[x][y].surface = surface; +} + +void Map::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 Map::setObject(int x, int y, int object) { + cells[x][y].object = object; + if (object != 0) cells[x][y].resource = 0; +} + +void Map::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 Map::setResource(int x, int y, int resource) { + cells[x][y].resource = resource; + if (resource != 0) cells[x][y].object = 0; +} + +void Map::changeStartLocation(int x, int y, int faction) { + if ((faction - 1) < maxFactions && inside(x, y)) { + startLocations[faction].x = x; + startLocations[faction].y = y; + } +} + +bool Map::inside(int x, int y) { + return (x >= 0 && x < w && y >= 0 && y < h); +} + +void Map::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; + } + + this->w = w; + this->h = h; + this->maxFactions = maxFactions; + + cells = new Cell*[w]; + for (int i = 0; i < w; i++) { + cells[i] = new Cell[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 Map::resize(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; + } + + int oldW = this->w; + int oldH = this->h; + this->w = w; + this->h = h; + this->maxFactions = maxFactions; + + //create new cells + Cell **oldCells = cells; + cells = new Cell*[w]; + for (int i = 0; i < w; i++) { + cells[i] = new Cell[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 Map::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; + + maxFactions = maxPlayers; + + startLocations = new StartLocation[maxFactions]; + for (int i = 0; i < maxFactions; i++) { + startLocations[i].x = 0; + startLocations[i].y = 0; + } +} + +void Map::setTitle(const string &title) { + this->title = title; +} + +void Map::setDesc(const string &desc) { + this->desc = desc; +} + +void Map::setAuthor(const string &author) { + this->author = author; +} + +void Map::setAdvanced(int altFactor, int waterLevel) { + this->altFactor = altFactor; + this->waterLevel = waterLevel; +} + +int Map::getHeightFactor() const { + return altFactor; +} + +int Map::getWaterLevel() const { + return waterLevel; +} + +void Map::randomizeHeights() { + resetHeights(random.randRange(8, 10)); + sinRandomize(0); + decalRandomize(4); + sinRandomize(1); +} + +void Map::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 Map::switchSurfaces(int surf1, int surf2) { + if (surf1 > 0 && surf1 <= 5 && surf2 > 0 && surf2 <= 5) { + 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 Map::loadFromFile(const string &path) { + + FILE *f1 = fopen(path.c_str(), "rb"); + if (f1 != NULL) { + + //read header + MapFileHeader header; + size_t readBytes = 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) { + readBytes = fread(&startLocations[i].x, sizeof(int32), 1, f1); + readBytes = 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) { + readBytes = 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) { + readBytes = 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; + readBytes = fread(&obj, sizeof(int8), 1, f1); + if (obj <= 10) { + cells[i][j].object = obj; + } else { + cells[i][j].resource = obj - 10; + } + } + } + + fclose(f1); + } else { + throw runtime_error("error opening map file: " + path); + } +} + + +void Map::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 Map::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 Map::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 Map::decalRandomize(int strenght) { + //first row + int lastHeight = 10; + 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 Map::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 diff --git a/source/shared_lib/include/platform/sdl/gl_wrap.h b/source/shared_lib/include/platform/sdl/gl_wrap.h new file mode 100644 index 00000000..d8f170bb --- /dev/null +++ b/source/shared_lib/include/platform/sdl/gl_wrap.h @@ -0,0 +1,57 @@ +// ============================================================== +// This file is part of Glest Shared Library (www.glest.org) +// +// Copyright (C) 2005 Matthias Braun +// +// 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 _SHARED_PLATFORM_GLWRAP_H_ +#define _SHARED_PLATFORM_GLWRAP_H_ + +#include +#define GL_GLEXT_PROTOTYPES +#include + +#include + +#include "font.h" +#include "types.h" + +using std::string; + +using Shared::Graphics::FontMetrics; + +namespace Shared{ namespace Platform{ + +// ===================================================== +// class PlatformContextGl +// ===================================================== + +class PlatformContextGl { +public: + virtual ~PlatformContextGl() {} + + virtual void init(int colorBits, int depthBits, int stencilBits); + virtual void end(); + + virtual void makeCurrent(); + virtual void swapBuffers(); + + DeviceContextHandle getHandle() const { return 0; } +}; + +// ===================================================== +// Global Fcs +// ===================================================== + +void createGlFontBitmaps(uint32 &base, const string &type, int size, int width, int charCount, FontMetrics &metrics); +void createGlFontOutlines(uint32 &base, const string &type, int width, float depth, int charCount, FontMetrics &metrics); +const char *getPlatformExtensions(const PlatformContextGl *pcgl); +void* getGlProcAddress(const char *procName); + +}}//end namespace + +#endif diff --git a/source/shared_lib/sources/graphics/model.cpp b/source/shared_lib/sources/graphics/model.cpp index 58e148a0..3a5b8ff9 100644 --- a/source/shared_lib/sources/graphics/model.cpp +++ b/source/shared_lib/sources/graphics/model.cpp @@ -94,7 +94,7 @@ void Mesh::updateInterpolationVertices(float t, bool cycle) const{ void Mesh::loadV2(const string &dir, FILE *f, TextureManager *textureManager){ //read header MeshHeaderV2 meshHeader; - fread(&meshHeader, sizeof(MeshHeaderV2), 1, f); + size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV2), 1, f); if(meshHeader.normalFrameCount!=meshHeader.vertexFrameCount){ @@ -129,21 +129,21 @@ void Mesh::loadV2(const string &dir, FILE *f, TextureManager *textureManager){ } //read data - fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); - fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(textures[mtDiffuse]!=NULL){ - fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); + readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); } - fread(&diffuseColor, sizeof(Vec3f), 1, f); - fread(&opacity, sizeof(float32), 1, f); + readBytes = fread(&diffuseColor, sizeof(Vec3f), 1, f); + readBytes = fread(&opacity, sizeof(float32), 1, f); fseek(f, sizeof(Vec4f)*(meshHeader.colorFrameCount-1), SEEK_CUR); - fread(indices, sizeof(uint32)*indexCount, 1, f); + readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f); } void Mesh::loadV3(const string &dir, FILE *f, TextureManager *textureManager){ //read header MeshHeaderV3 meshHeader; - fread(&meshHeader, sizeof(MeshHeaderV3), 1, f); + size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV3), 1, f); if(meshHeader.normalFrameCount!=meshHeader.vertexFrameCount){ @@ -174,23 +174,23 @@ void Mesh::loadV3(const string &dir, FILE *f, TextureManager *textureManager){ } //read data - fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); - fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(textures[mtDiffuse]!=NULL){ for(int i=0; i(cMapPath)); string mapFullPath= dir + "/" + mapPath; @@ -232,12 +232,12 @@ void Mesh::load(const string &dir, FILE *f, TextureManager *textureManager){ } //read data - fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); - fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f); + readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f); if(meshHeader.textures!=0){ - fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); + readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f); } - fread(indices, sizeof(uint32)*indexCount, 1, f); + readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f); //tangents if(textures[mtNormal]!=NULL){ @@ -440,7 +440,7 @@ void Model::loadG3d(const string &path){ //file header FileHeader fileHeader; - fread(&fileHeader, sizeof(FileHeader), 1, f); + size_t readBytes = fread(&fileHeader, sizeof(FileHeader), 1, f); if(strncmp(reinterpret_cast(fileHeader.id), "G3D", 3)!=0){ printf("In [%s::%s] file = [%s] fileheader.id = [%s][%c]\n",__FILE__,__FUNCTION__,path.c_str(),reinterpret_cast(fileHeader.id),fileHeader.id[0]); @@ -453,7 +453,7 @@ void Model::loadG3d(const string &path){ //model header ModelHeader modelHeader; - fread(&modelHeader, sizeof(ModelHeader), 1, f); + readBytes = fread(&modelHeader, sizeof(ModelHeader), 1, f); meshCount= modelHeader.meshCount; if(modelHeader.type!=mtMorphMesh){ throw runtime_error("Invalid model type"); @@ -469,7 +469,7 @@ void Model::loadG3d(const string &path){ //version 3 else if(fileHeader.version==3){ - fread(&meshCount, sizeof(meshCount), 1, f); + readBytes = fread(&meshCount, sizeof(meshCount), 1, f); meshes= new Mesh[meshCount]; for(uint32 i=0; i +#include +#include + +#include "util.h" +#include "math_util.h" +#include "random.h" +#include "leak_dumper.h" + +using namespace Shared::Util; +using namespace std; + +namespace Shared{ namespace Graphics{ + +using namespace Util; + +// ===================================================== +// file structs +// ===================================================== + +#pragma pack(push, 1) + +struct BitmapFileHeader{ + uint8 type1; + uint8 type2; + uint32 size; + uint16 reserved1; + uint16 reserved2; + uint32 offsetBits; +}; + +struct BitmapInfoHeader{ + uint32 size; + int32 width; + int32 height; + uint16 planes; + uint16 bitCount; + uint32 compression; + uint32 sizeImage; + int32 xPelsPerMeter; + int32 yPelsPerMeter; + uint32 clrUsed; + uint32 clrImportant; +}; + +struct TargaFileHeader{ + int8 idLength; + int8 colourMapType; + int8 dataTypeCode; + int16 colourMapOrigin; + int16 colourMapLength; + int8 colourMapDepth; + int16 xOrigin; + int16 yOrigin; + int16 width; + int16 height; + int8 bitsPerPixel; + int8 imageDescriptor; +}; + +#pragma pack(pop) + +const int tgaUncompressedRgb= 2; +const int tgaUncompressedBw= 3; + +// ===================================================== +// class PixmapIoTga +// ===================================================== + +PixmapIoTga::PixmapIoTga(){ + file= NULL; +} + +PixmapIoTga::~PixmapIoTga(){ + if(file!=NULL){ + fclose(file); + } +} + +void PixmapIoTga::openRead(const string &path){ + file= fopen(path.c_str(),"rb"); + if (file==NULL){ + throw runtime_error("Can't open TGA file: "+ path); + } + + //read header + TargaFileHeader fileHeader; + size_t readBytes = fread(&fileHeader, sizeof(TargaFileHeader), 1, file); + + //check that we can load this tga file + if(fileHeader.idLength!=0){ + throw runtime_error(path + ": id field is not 0"); + } + + if(fileHeader.dataTypeCode!=tgaUncompressedRgb && fileHeader.dataTypeCode!=tgaUncompressedBw){ + throw runtime_error(path + ": only uncompressed BW and RGB targa images are supported"); + } + + //check bits per pixel + if(fileHeader.bitsPerPixel!=8 && fileHeader.bitsPerPixel!=24 && fileHeader.bitsPerPixel!=32){ + throw runtime_error(path + ": only 8, 24 and 32 bit targa images are supported"); + } + + h= fileHeader.height; + w= fileHeader.width; + components= fileHeader.bitsPerPixel/8; +} + +void PixmapIoTga::read(uint8 *pixels){ + read(pixels, components); +} + +void PixmapIoTga::read(uint8 *pixels, int components){ + for(int i=0; icomponents==1){ + size_t readBytes = fread(&l, 1, 1, file); + r= l; + g= l; + b= l; + a= 255; + } + else{ + size_t readBytes = fread(&b, 1, 1, file); + readBytes = fread(&g, 1, 1, file); + readBytes = fread(&r, 1, 1, file); + if(this->components==4){ + readBytes = fread(&a, 1, 1, file); + } + else{ + a= 255; + } + l= (r+g+b)/3; + } + + switch(components){ + case 1: + pixels[i]= l; + break; + case 3: + pixels[i]= r; + pixels[i+1]= g; + pixels[i+2]= b; + break; + case 4: + pixels[i]= r; + pixels[i+1]= g; + pixels[i+2]= b; + pixels[i+3]= a; + break; + } + } +} + +void PixmapIoTga::openWrite(const string &path, int w, int h, int components){ + this->w= w; + this->h= h; + this->components= components; + + file= fopen(path.c_str(),"wb"); + if (file==NULL){ + throw runtime_error("Can't open TGA file: "+ path); + } + + TargaFileHeader fileHeader; + memset(&fileHeader, 0, sizeof(TargaFileHeader)); + fileHeader.dataTypeCode= components==1? tgaUncompressedBw: tgaUncompressedRgb; + fileHeader.bitsPerPixel= components*8; + fileHeader.width= w; + fileHeader.height= h; + fileHeader.imageDescriptor= components==4? 8: 0; + + fwrite(&fileHeader, sizeof(TargaFileHeader), 1, file); +} + +void PixmapIoTga::write(uint8 *pixels){ + if(components==1){ + fwrite(pixels, h*w, 1, file); + } + else{ + for(int i=0; iw= w; + this->h= h; + this->components= components; + + file= fopen(path.c_str(),"wb"); + if (file==NULL){ + throw runtime_error("Can't open BMP file for writting: "+ path); + } + + BitmapFileHeader fileHeader; + fileHeader.type1='B'; + fileHeader.type2='M'; + fileHeader.offsetBits=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader); + fileHeader.size=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader)+3*h*w; + + fwrite(&fileHeader, sizeof(BitmapFileHeader), 1, file); + + //info header + BitmapInfoHeader infoHeader; + infoHeader.bitCount=24; + infoHeader.clrImportant=0; + infoHeader.clrUsed=0; + infoHeader.compression=0; + infoHeader.height= h; + infoHeader.planes=1; + infoHeader.size=sizeof(BitmapInfoHeader); + infoHeader.sizeImage=0; + infoHeader.width= w; + infoHeader.xPelsPerMeter= 0; + infoHeader.yPelsPerMeter= 0; + + fwrite(&infoHeader, sizeof(BitmapInfoHeader), 1, file); +} + +void PixmapIoBmp::write(uint8 *pixels){ + for (int i=0; iw= -1; + this->components= components; + pixels= NULL; +} + +void Pixmap1D::init(int w, int components){ + this->w= w; + this->components= components; + pixels= new uint8[w*components]; +} + +Pixmap1D::~Pixmap1D(){ + delete [] pixels; +} + +void Pixmap1D::load(const string &path){ + string extension= path.substr(path.find_last_of('.')+1); + if(extension=="bmp"){ + loadBmp(path); + } + else if(extension=="tga"){ + loadTga(path); + } + else{ + throw runtime_error("Unknown pixmap extension: "+extension); + } +} + +void Pixmap1D::loadBmp(const string &path){ + + PixmapIoBmp plb; + plb.openRead(path); + + //init + if(plb.getH()==1){ + w= plb.getW(); + } + else if(plb.getW()==1){ + w= plb.getH(); + } + else{ + throw runtime_error("One of the texture dimensions must be 1"); + } + + if(components==-1){ + components= 3; + } + if(pixels==NULL){ + pixels= new uint8[w*components]; + } + + //data + plb.read(pixels, components); +} + +void Pixmap1D::loadTga(const string &path){ + + PixmapIoTga plt; + plt.openRead(path); + + //init + if(plt.getH()==1){ + w= plt.getW(); + } + else if(plt.getW()==1){ + w= plt.getH(); + } + else{ + throw runtime_error("One of the texture dimensions must be 1"); + } + + int fileComponents= plt.getComponents(); + + if(components==-1){ + components= fileComponents; + } + if(pixels==NULL){ + pixels= new uint8[w*components]; + } + + //read data + plt.read(pixels, components); +} + +// ===================================================== +// class Pixmap2D +// ===================================================== + +// ===================== PUBLIC ======================== + +Pixmap2D::Pixmap2D(){ + h= -1; + w= -1; + components= -1; + pixels= NULL; +} + +Pixmap2D::Pixmap2D(int components){ + init(components); +} + +Pixmap2D::Pixmap2D(int w, int h, int components){ + init(w, h, components); +} + +void Pixmap2D::init(int components){ + this->w= -1; + this->h= -1; + this->components= components; + pixels= NULL; +} + +void Pixmap2D::init(int w, int h, int components){ + this->w= w; + this->h= h; + this->components= components; + pixels= new uint8[h*w*components]; +} + +Pixmap2D::~Pixmap2D(){ + delete [] pixels; +} + +void Pixmap2D::load(const string &path){ + string extension= path.substr(path.find_last_of('.')+1); + if(extension=="bmp"){ + loadBmp(path); + } + else if(extension=="tga"){ + loadTga(path); + } + else{ + throw runtime_error("Unknown pixmap extension: "+extension); + } +} + +void Pixmap2D::loadBmp(const string &path){ + + PixmapIoBmp plb; + plb.openRead(path); + + //init + w= plb.getW(); + h= plb.getH(); + if(components==-1){ + components= 3; + } + if(pixels==NULL){ + pixels= new uint8[w*h*components]; + } + + //data + plb.read(pixels, components); +} + +void Pixmap2D::loadTga(const string &path){ + + PixmapIoTga plt; + plt.openRead(path); + w= plt.getW(); + h= plt.getH(); + + //header + int fileComponents= plt.getComponents(); + + //init + if(components==-1){ + components= fileComponents; + } + if(pixels==NULL){ + pixels= new uint8[w*h*components]; + } + + //read data + plt.read(pixels, components); +} + +void Pixmap2D::save(const string &path){ + string extension= path.substr(path.find_last_of('.')+1); + if(extension=="bmp"){ + saveBmp(path); + } + else if(extension=="tga"){ + saveTga(path); + } + else{ + throw runtime_error("Unknown pixmap extension: "+extension); + } +} + +void Pixmap2D::saveBmp(const string &path){ + PixmapIoBmp psb; + psb.openWrite(path, w, h, components); + psb.write(pixels); +} + +void Pixmap2D::saveTga(const string &path){ + PixmapIoTga pst; + pst.openWrite(path, w, h, components); + pst.write(pixels); +} + +void Pixmap2D::getPixel(int x, int y, uint8 *value) const{ + for(int i=0; i(value[i]*255.f); + } +} + +void Pixmap2D::setComponent(int x, int y, int component, uint8 value){ + pixels[(w*y+x)*components+component]= value; +} + +void Pixmap2D::setComponent(int x, int y, int component, float32 value){ + pixels[(w*y+x)*components+component]= static_cast(value*255.f); +} + +//vector set +void Pixmap2D::setPixel(int x, int y, const Vec3f &p){ + for(int i=0; i(p.ptr()[i]*255.f); + } +} + +void Pixmap2D::setPixel(int x, int y, const Vec4f &p){ + for(int i=0; i(p.ptr()[i]*255.f); + } +} + +void Pixmap2D::setPixel(int x, int y, float p){ + pixels[(w*y+x)*components]= static_cast(p*255.f); +} + +void Pixmap2D::setPixels(const uint8 *value){ + for(int i=0; iavg? 0: ((avg-distLu))*random.randRange(0.5f, 1.0f); + float ru= distRu>avg? 0: ((avg-distRu))*random.randRange(0.5f, 1.0f); + float ld= distLd>avg? 0: ((avg-distLd))*random.randRange(0.5f, 1.0f); + float rd= distRd>avg? 0: ((avg-distRd))*random.randRange(0.5f, 1.0f); + + float total= lu+ru+ld+rd; + + Vec4f pix= (leftUp->getPixel4f(i, j)*lu+ + rightUp->getPixel4f(i, j)*ru+ + leftDown->getPixel4f(i, j)*ld+ + rightDown->getPixel4f(i, j)*rd)*(1.0f/total); + + setPixel(i, j, pix); + } + } +} + +void Pixmap2D::lerp(float t, const Pixmap2D *pixmap1, const Pixmap2D *pixmap2){ + if( + !doDimensionsAgree(pixmap1) || + !doDimensionsAgree(pixmap2)) + { + throw runtime_error("Pixmap2D::lerp: pixmap dimensions don't agree"); + } + + for(int i=0; igetPixel4f(i, j).lerp(t, pixmap2->getPixel4f(i, j))); + } + } +} + +void Pixmap2D::copy(const Pixmap2D *sourcePixmap){ + + assert(components==sourcePixmap->getComponents()); + + if(w!=sourcePixmap->getW() || h!=sourcePixmap->getH()){ + throw runtime_error("Pixmap2D::copy() dimensions must agree"); + } + memcpy(pixels, sourcePixmap->getPixels(), w*h*sourcePixmap->getComponents()); +} + +void Pixmap2D::subCopy(int x, int y, const Pixmap2D *sourcePixmap){ + assert(components==sourcePixmap->getComponents()); + + if(wgetW() && hgetH()){ + throw runtime_error("Pixmap2D::subCopy(), bad dimensions"); + } + + uint8 *pixel= new uint8[components]; + + for(int i=0; igetW(); ++i){ + for(int j=0; jgetH(); ++j){ + sourcePixmap->getPixel(i, j, pixel); + setPixel(i+x, j+y, pixel); + } + } + + delete pixel; +} + +bool Pixmap2D::doDimensionsAgree(const Pixmap2D *pixmap){ + return pixmap->getW() == w && pixmap->getH() == h; +} + +// ===================================================== +// class Pixmap3D +// ===================================================== + +Pixmap3D::Pixmap3D(){ + w= -1; + h= -1; + d= -1; + components= -1; +} + +Pixmap3D::Pixmap3D(int w, int h, int d, int components){ + init(w, h, d, components); +} + +Pixmap3D::Pixmap3D(int d, int components){ + init(d, components); +} + +void Pixmap3D::init(int w, int h, int d, int components){ + this->w= w; + this->h= h; + this->d= d; + this->components= components; + pixels= new uint8[h*w*d*components];; +} + +void Pixmap3D::init(int d, int components){ + this->w= -1; + this->h= -1; + this->d= d; + this->components= components; + pixels= NULL; +} + +Pixmap3D::~Pixmap3D(){ + delete [] pixels; +} + +void Pixmap3D::loadSlice(const string &path, int slice){ + string extension= path.substr(path.find_last_of('.')+1); + if(extension=="bmp"){ + loadSliceBmp(path, slice); + } + else if(extension=="tga"){ + loadSliceTga(path, slice); + } + else{ + throw runtime_error("Unknown pixmap extension: "+extension); + } +} + +void Pixmap3D::loadSliceBmp(const string &path, int slice){ + + PixmapIoBmp plb; + plb.openRead(path); + + //init + w= plb.getW(); + h= plb.getH(); + if(components==-1){ + components= 3; + } + if(pixels==NULL){ + pixels= new uint8[w*h*d*components]; + } + + //data + plb.read(&pixels[slice*w*h*components], components); +} + +void Pixmap3D::loadSliceTga(const string &path, int slice){ + PixmapIoTga plt; + plt.openRead(path); + + //header + int fileComponents= plt.getComponents(); + + //init + w= plt.getW(); + h= plt.getH(); + if(components==-1){ + components= fileComponents; + } + if(pixels==NULL){ + pixels= new uint8[w*h*d*components]; + } + + //read data + plt.read(&pixels[slice*w*h*components], components); +} + +// ===================================================== +// class PixmapCube +// ===================================================== + +void PixmapCube::init(int w, int h, int components){ + for(int i=0; i<6; ++i){ + faces[i].init(w, h, components); + } +} + + //load & save +void PixmapCube::loadFace(const string &path, int face){ + faces[face].load(path); +} + +void PixmapCube::loadFaceBmp(const string &path, int face){ + faces[face].loadBmp(path); +} + +void PixmapCube::loadFaceTga(const string &path, int face){ + faces[face].loadTga(path); +} + +}}//end namespace diff --git a/source/shared_lib/sources/util/checksum.cpp b/source/shared_lib/sources/util/checksum.cpp new file mode 100644 index 00000000..7bed0a6a --- /dev/null +++ b/source/shared_lib/sources/util/checksum.cpp @@ -0,0 +1,70 @@ +// ============================================================== +// This file is part of Glest Shared Library (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 "checksum.h" + +#include +#include + +#include "util.h" +#include "leak_dumper.h" + +using namespace std; + +namespace Shared{ namespace Util{ + +// ===================================================== +// class Checksum +// ===================================================== + +Checksum::Checksum(){ + sum= 0; + r= 55665; + c1= 52845; + c2= 22719; +} + +void Checksum::addByte(int8 value){ + int32 cipher= (value ^ (r >> 8)); + + r= (cipher + r) * c1 + c2; + sum+= cipher; +} + +void Checksum::addString(const string &value){ + for(int i= 0; i