MegaGlest/source/glest_map_editor/program.cpp

684 lines
19 KiB
C++

// ==============================================================
// 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 "program.h"
#include "util.h"
#include <iostream>
#include "platform_util.h"
using namespace Shared::Util;
namespace MapEditor {
////////////////////////////
// class UndoPoint
////////////////////////////
int UndoPoint::w = 0;
int UndoPoint::h = 0;
UndoPoint::UndoPoint()
: change(ctNone)
, surface(0)
, object(0)
, resource(0)
, height(0) {
w = Program::map->getW();
h = Program::map->getH();
}
/*
UndoPoint::UndoPoint(ChangeType change) {
w = Program::map->getW();
h = Program::map->getH();
init(change);
}*/
void UndoPoint::init(ChangeType change) {
this->change = change;
switch (change) {
// Back up everything
case ctAll:
// Back up heights
case ctHeight:
case ctGradient:
// Build an array of heights from the map
//std::cout << "Building an array of heights to use for our UndoPoint" << std::endl;
height = new float[w * h];
for (int i = 0; i < w; ++i) {
for (int j = 0; j < h; ++j) {
height[j * w + i] = Program::map->getHeight(i, j);
}
}
//std::cout << "Built the array" << std::endl;
if (change != ctAll) break;
// Back up surfaces
case ctSurface:
surface = new int[w * h];
for (int i = 0; i < w; ++i) {
for (int j = 0; j < h; ++j) {
surface[j * w + i] = Program::map->getSurface(i, j);
}
}
if (change != ctAll) break;
// Back up both objects and resources if either changes
case ctObject:
case ctResource:
object = new int[w * h];
for (int i = 0; i < w; ++i) {
for (int j = 0; j < h; ++j) {
object[j * w + i] = Program::map->getObject(i, j);
}
}
resource = new int[w * h];
for (int i = 0; i < w; ++i) {
for (int j = 0; j < h; ++j) {
resource[j * w + i] = Program::map->getResource(i, j);
}
}
break;
}
}
UndoPoint::~UndoPoint() {
delete [] height;
delete [] resource;
delete [] object;
delete [] surface;
}
void UndoPoint::revert() {
//std::cout << "attempting to revert last changes to " << undoID << std::endl;
switch (change) {
// Revert Everything
case ctAll:
// Revert Heights
case ctHeight:
case ctGradient:
// Restore the array of heights to the map
//std::cout << "attempting to restore the height array" << std::endl;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
Program::map->setHeight(i, j, height[j * w + i]);
}
}
if (change != ctAll) break;
// Revert surfaces
case ctSurface:
//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, static_cast<MapSurfaceType>(surface[j * w + i]));
}
}
if (change != ctAll) break;
// Revert objects and resources
case ctObject:
case ctResource:
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
Program::map->setObject(i, j, object[j * w + i]);
}
}
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
Program::map->setResource(i, j, resource[j * w + i]);
}
}
break;
}
//std::cout << "reverted changes (we hope)" << std::endl;
}
// ===============================================
// class Program
// ===============================================
MapPreview *Program::map = NULL;
Program::Program(int w, int h, string playerName) {
cellSize = 5;
grid=false;
heightmap=false;
hideWater=false;
ofsetX = 0;
ofsetY = 0;
map = new MapPreview();
resetFactions(8);
renderer.initMapSurface(w, h);
map->setAuthor(playerName);
}
void Program::init() {
undoStack = ChangeStack();
redoStack = ChangeStack();
cellSize = 5;
grid=false;
heightmap=false;
hideWater=false;
ofsetX = 0;
ofsetY = 0;
map = NULL;
}
Program::~Program() {
delete map;
map = NULL;
}
int Program::getObject(int x, int y) {
int i=(x - ofsetX) / cellSize;
int j= (y + ofsetY) / cellSize;
if (map && map->inside(i, j)) {
return map->getObject(i,j);
}
else {
return 0;
}
}
int Program::getCellX(int x) {
return (x - ofsetX) / cellSize;
}
int Program::getCellY(int y) {
return (y + ofsetY) / cellSize;
}
int Program::getResource(int x, int y) {
int i=(x - ofsetX) / cellSize;
int j= (y + ofsetY) / cellSize;
if (map && map->inside(i, j)) {
return map->getResource(i,j);
}
else {
return 0;
}
}
void Program::glestChangeMapHeight(int x, int y, int Height, int radius) {
if(map) map->glestChangeHeight((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, Height, radius);
}
void Program::pirateChangeMapHeight(int x, int y, int Height, int radius) {
if(map) map->pirateChangeHeight((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, Height, radius);
}
void Program::changeMapSurface(int x, int y, int surface, int radius) {
if(map) map->changeSurface((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, static_cast<MapSurfaceType>(surface), radius);
}
void Program::changeMapObject(int x, int y, int object, int radius, bool overwrite) {
if(map) map->changeObject((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, object, radius, overwrite);
}
void Program::changeMapResource(int x, int y, int resource, int radius, bool overwrite) {
if(map) map->changeResource((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, resource, radius, overwrite);
}
void Program::changeStartLocation(int x, int y, int player) {
if(map) map->changeStartLocation((x - ofsetX) / cellSize, (y + ofsetY) / cellSize, player);
}
void Program::setUndoPoint(ChangeType change) {
if (change == ctLocation) return;
undoStack.push(UndoPoint());
undoStack.top().init(change);
redoStack.clear();
}
bool Program::undo() {
if (undoStack.empty()) {
return false;
}
// push current state onto redo stack
redoStack.push(UndoPoint());
redoStack.top().init(undoStack.top().getChange());
undoStack.top().revert();
undoStack.pop();
return true;
}
bool Program::redo() {
if (redoStack.empty()) {
return false;
}
// push current state onto undo stack
undoStack.push(UndoPoint());
undoStack.top().init(redoStack.top().getChange());
redoStack.top().revert();
redoStack.pop();
return true;
}
void Program::renderMap(int w, int h, pair<int,int>* mouse_pos, int* radius) {
//printf("Rendering map\n");
if(map) renderer.renderMap(map, ofsetX, ofsetY, w, h, cellSize, grid,heightmap,hideWater,mouse_pos,radius);
}
void Program::setRefAlt(int x, int y) {
if(map) map->setRefAlt((x - ofsetX) / cellSize, (y + ofsetY) / cellSize);
}
void Program::flipX() {
if(map) map->flipX();
}
void Program::flipY() {
if(map) map->flipY();
}
void Program::mirrorX() { // copy left to right
if(map) {
int w=map->getW();
int h=map->getH();
for (int i = 0; i < w/2; i++) {
for (int j = 0; j < h; j++) {
map->copyXY(w-i-1,j , i,j);
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationX(i) >= w/2) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if((map->getStartLocationX(i) < w/2) && (map->getStartLocationX(i)!=0 || map->getStartLocationY(i)!=0)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii)==0) { // first free one
map->changeStartLocation(w-map->getStartLocationX(i)-1, map->getStartLocationY(i), ii);
break;
}
}
}
}
void Program::mirrorY() { // copy top to bottom
if(map) {
int w=map->getW();
int h=map->getH();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h/2; j++) {
map->copyXY(i,h-j-1 , i,j);
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationY(i) >= h/2) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if((map->getStartLocationY(i) < h/2) && (map->getStartLocationX(i)!=0 || map->getStartLocationY(i)!=0)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii)==0) { // first free one
map->changeStartLocation(map->getStartLocationX(i), h-map->getStartLocationY(i)-1, ii);
break;
}
}
}
}
void Program::mirrorXY() { // copy leftbottom to topright, can handle non-sqaure maps
if(map) {
int w=map->getW();
int h=map->getH();
if (h==w) {
for (int i = 0; i < w-1; i++) {
for (int j = i+1; j < h; j++) {
map->copyXY(j,i , i,j);
}
}
}
// Non-sqaure maps:
else if (h < w) { // copy horizontal strips
int s=w/h; // 2 if twice as wide as heigh
for (int i = 0; i < w/s-1; i++) {
for (int j = i+1; j < h; j++) {
for (int p = 0; p < s; p++) map->copyXY(j*s+p,i , i*s+p,j);
}
}
}
else { // copy vertical strips
int s=h/w; // 2 if twice as heigh as wide
for (int i = 0; i < w-1; i++) {
for (int j = i+1; j < h/s; j++) {
for (int p = 0; p < s; p++) map->copyXY(j,i*s+p , i,j*s+p);
}
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationX(i) > map->getStartLocationY(i)) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if(map->getStartLocationX(i) < map->getStartLocationY(i)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii) == 0) { // first free one
map->changeStartLocation(map->getStartLocationY(i)*w/h, map->getStartLocationX(i)*h/w, ii);
break;
}
}
}
}
void Program::rotatecopyX() {
if(map) {
int w=map->getW();
int h=map->getH();
for (int i = 0; i < w/2; i++) {
for (int j = 0; j < h; j++) {
map->copyXY(w-i-1,h-j-1 , i,j);
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationX(i) >= w/2) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if((map->getStartLocationX(i) < w/2) && (map->getStartLocationX(i)!=0 || map->getStartLocationY(i)!=0)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii)==0) { // first free one
map->changeStartLocation(w-map->getStartLocationX(i)-1, h-map->getStartLocationY(i)-1, ii);
break;
}
}
}
}
void Program::rotatecopyY() {
if(map) {
int w=map->getW();
int h=map->getH();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h/2; j++) {
map->copyXY(w-i-1,h-j-1 , i,j);
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationY(i) >= h/2) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if((map->getStartLocationY(i) < h/2) && (map->getStartLocationX(i)!=0 || map->getStartLocationY(i)!=0)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii)==0) { // first free one
map->changeStartLocation(w-map->getStartLocationX(i)-1, h-map->getStartLocationY(i)-1, ii);
break;
}
}
}
}
void Program::rotatecopyXY() {
if(map) {
int w=map->getW();
int h=map->getH();
int sw=w/h; if(sw<1) sw=1; // x-squares per y
int sh=h/w; if(sh<1) sh=1; // y-squares per x
if (sh==1)
for (int j = 0; j < h-1; j++) { // row by row!
for (int i = j*sw; i < w; i++) {
map->copyXY(i,j , w-i-1,h-j-1);
}
}
else
for (int i = 0; i <w; i++) { // column for colum!
for (int j = h-1-i*sh; j >= 0; j--) {
map->copyXY(w-i-1,j , i,h-j-1);
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationX(i) > map->getStartLocationY(i)) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if(map->getStartLocationX(i) < map->getStartLocationY(i)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii) == 0) { // first free one
map->changeStartLocation(w-map->getStartLocationX(i)-1, h-map->getStartLocationY(i)-1, ii);
break;
}
}
}
}
void Program::rotatecopyCorner() { // rotate top left 1/4 to top right 1/4
if(map) {
int w=map->getW();
int h=map->getH();
if (h==w) {
for (int i = 0; i < w/2; i++) {
for (int j = 0; j < h/2; j++) {
map->copyXY(w-j-1,i , i,j);
}
}
}
// Non-sqaure maps:
else if (h < w) { // copy horizontal strips
int s=w/h; // 2 if twice as wide as heigh
for (int i = 0; i < w/s/2; i++) {
for (int j = 0; j < h/2; j++) {
for (int p = 0; p < s; p++) map->copyXY(w-j*s-1-p,i , i*s+p,j);
}
}
}
else { // copy vertical strips
int s=h/w; // 2 if twice as heigh as wide
for (int i = 0; i < w/2; i++) {
for (int j = 0; j < h/s/2; j++) {
for (int p = 0; p < s; p++) map->copyXY(w-j-1,i*s+p , i,j*s+p);
}
}
}
// move players
for (int i = 0; i < map->getMaxFactions(); ++i) // first remove players from target corner
if (map->getStartLocationX(i) >= w/2 && map->getStartLocationY(i) < h/2) map->changeStartLocation(0,0,i);
for (int i = 0; i < map->getMaxFactions(); ++i) {
if((map->getStartLocationX(i) < w/2 && map->getStartLocationY(i) < h/2) && (map->getStartLocationX(i)!=0 || map->getStartLocationY(i)!=0)) // any startpositions to copy?
for (int ii = 0; ii < map->getMaxFactions(); ++ii)
if(map->getStartLocationX(ii)==0 && map->getStartLocationY(ii)==0) { // first free one
map->changeStartLocation(w-map->getStartLocationY(i)*w/h-1, map->getStartLocationX(i)*h/w, ii);
break;
}
}
}
}
void Program::shiftLeft() {
if(map) {
int w=map->getW()-1;
int h=map->getH();
for (int i=0; i<w; i++)
for (int j=0; j<h; j++)
map->copyXY(i,j , i+1,j);
for (int i = 0; i < map->getMaxFactions(); ++i) // move players
map->changeStartLocation(map->getStartLocationX(i)-1, map->getStartLocationY(i), i); // it allready check limits
}
}
void Program::flipDiagonal() {
if(map) {
int w=map->getW();
int h=map->getH();
for (int i=0; i<w; i++)
for (int j=i; j<h; j++){
map->swapXY(i,j , j,i);
}
for (int i = 0; i < map->getMaxFactions(); ++i) // move players
if (map->getStartLocationX(i) != 0 || map->getStartLocationY(i) != 0) // don't move the unset ones
map->changeStartLocation(map->getStartLocationY(i), map->getStartLocationX(i), i); // it allready check limits
}
}
void Program::shiftRight() {
if(map) {
int w=map->getW()-1;
int h=map->getH();
for (int i=w; i>0; i--)
for (int j=0; j<h; j++)
map->copyXY(i,j , i-1,j);
for (int i = 0; i < map->getMaxFactions(); ++i) // move players
if (map->getStartLocationX(i) != 0 || map->getStartLocationY(i) != 0) // don't move the unset ones
map->changeStartLocation(map->getStartLocationX(i)+1, map->getStartLocationY(i), i); // it allready check limits
}
}
void Program::shiftUp() {
if(map) {
int w=map->getW();
int h=map->getH()-1;
for (int i=0; i<w; i++)
for (int j=0; j<h; j++)
map->copyXY(i,j , i,j+1);
for (int i = 0; i < map->getMaxFactions(); ++i) // move players
map->changeStartLocation(map->getStartLocationX(i), map->getStartLocationY(i)-1, i); // it allready check limits
}
}
void Program::shiftDown() {
if(map) {
int w=map->getW();
int h=map->getH()-1;
for (int i=0; i<w; i++)
for (int j=h; j>0; j--)
map->copyXY(i,j , i,j-1);
for (int i = 0; i < map->getMaxFactions(); ++i) // move players
if (map->getStartLocationX(i) != 0 || map->getStartLocationY(i) != 0) // don't move the unset ones
map->changeStartLocation(map->getStartLocationX(i), map->getStartLocationY(i)+1, i); // it allready check limits
}
}
void Program::randomizeMapHeights(bool withReset,int minimumHeight, int maximumHeight, int chanceDivider, int smoothRecursions) {
if(map) map->randomizeHeights(withReset, minimumHeight, maximumHeight, chanceDivider, smoothRecursions);
}
void Program::importMapHeights(unsigned char* data) {
if(map) map->importMapHeights(data);
}
void Program::randomizeFactions() {
if(map) map->randomizeFactions();
}
void Program::switchMapSurfaces(int surf1, int surf2) {
if(map) map->switchSurfaces(static_cast<MapSurfaceType>(surf1), static_cast<MapSurfaceType>(surf2));
}
void Program::reset(int w, int h, int alt, int surf) {
undoStack.clear();
redoStack.clear();
if(map) map->reset(w, h, (float) alt, static_cast<MapSurfaceType>(surf));
}
void Program::resize(int w, int h) {
if(map) map->resize(w, h);
}
void Program::resetFactions(int maxFactions) {
if(map) map->resetFactions(maxFactions);
randomizeFactions();
}
bool Program::setMapTitle(const string &title) {
if(map) {
if (map->getTitle() != title) {
map->setTitle(title);
return true;
}
}
return false;
}
bool Program::setMapDesc(const string &desc) {
if(map) {
if (map->getDesc() != desc) {
map->setDesc(desc);
return true;
}
}
return false;
}
bool Program::setMapAuthor(const string &author) {
if(map) {
if (map->getAuthor() != author) {
map->setAuthor(author);
return true;
}
}
return false;
}
void Program::setOfset(int x, int y) {
ofsetX += x;
ofsetY -= y;
}
void Program::incCellSize(int i) {
if(map) {
int minInc = 2 - cellSize;
if (i < minInc) {
i = minInc;
}
cellSize += i;
ofsetX -= (map->getW() * i) / 2;
ofsetY += (map->getH() * i) / 2;
}
}
void Program::resetOfset() {
ofsetX = 0;
ofsetY = 0;
cellSize = 5;
}
bool Program::setGridOnOff() {
grid=!grid;
return grid;
}
bool Program::setHeightMapOnOff() {
heightmap=!heightmap;
return heightmap;
}
bool Program::setHideWaterOnOff() {
hideWater=!hideWater;
return hideWater;
}
void Program::setMapAdvanced(int altFactor, int waterLevel, int cliffLevel , int cameraHeight) {
if(map) map->setAdvanced(altFactor, waterLevel, cliffLevel, cameraHeight);
}
void Program::loadMap(const string &path) {
undoStack.clear();
redoStack.clear();
std::string encodedPath = path;
map->loadFromFile(encodedPath);
}
void Program::saveMap(const string &path) {
if(map) {
std::string encodedPath = path;
map->saveToFile(encodedPath);
}
}
}// end namespace