Files

866 lines
27 KiB
C++
Executable File

#include <root.h>
#include <quad.h>
#include <model.h>
#include <light.h>
#include <material.h>
#include <imageAsset.h>
#include <assetManager.h>
#include <button.h>
#include <solUtil.h>
#include <stateManager.h>
#include "map.h"
#include "util.h"
#include "vehicle.h"
#include "game.h"
#include "player.h"
#include "gameObject.h"
#include "pathfinder.h"
#include "gameManager.h"
#include "defConfigs.h"
#include "resourceDeposit.h"
#include "activeGameState.h"
#include "concreteGuiManager.h"
#include "gameObjectFactory.h"
namespace battleship{
using namespace std;
using namespace vb01;
using namespace vb01Gui;
using namespace gameBase;
using namespace configData;
static Map *map = nullptr;
static Map::Minimap *minimap = nullptr;
Map::Minimap* Map::Minimap::getSingleton(){
if(!minimap) minimap = new Map::Minimap();
return minimap;
}
Map::Minimap::Minimap(){
Vector3 mapSize = Map::getSingleton()->getMapSize();
float ratio = mapSize.x / mapSize.z;
sol::state_view SOL_LUA_VIEW = generateView();
SOL_LUA_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Gui/activeGameState.lua");
sol::table sizeTbl = SOL_LUA_VIEW["minimapSize"];
float initSizeX = sizeTbl["x"], initSizeY = sizeTbl["y"];
if(ratio < 1){
float x = initSizeX * ratio;
SOL_LUA_VIEW["_minimapPos"]["x"] = .5 * (initSizeX - x) ;
SOL_LUA_VIEW["_minimapSize"]["x"] = x;
SOL_LUA_VIEW["_minimapSize"]["y"] = initSizeY;
}
else{
float y = initSizeY / ratio;
SOL_LUA_VIEW["_minimapPos"]["y"] = .5 * (initSizeY - y);
SOL_LUA_VIEW["_minimapSize"]["x"] = initSizeX;
SOL_LUA_VIEW["_minimapSize"]["y"] = y;
}
string refIconFile = SOL_LUA_VIEW["refIcon"];
string basePath = GameManager::getSingleton()->getPath() + "Textures/Icons/Minimap/";
for(ResourceDeposit *rd : Game::getSingleton()->getCivilianPlayer()->getResourceDeposits())
depositIcons.push_back(initIcon(rd->getPos(), basePath + refIconFile));
string camIconFile = SOL_LUA_VIEW["eyeIcon"];
camIcon = initIcon(Root::getSingleton()->getCamera()->getPosition(), basePath + camIconFile);
}
Map::Minimap::~Minimap(){
Node *guiNode = Root::getSingleton()->getGuiNode();
for(Node *node : depositIcons){
guiNode->dettachChild(node);
delete node;
}
depositIcons.clear();
guiNode->dettachChild(camIcon);
delete camIcon;
}
Node* Map::Minimap::initIcon(Vector3 posOnMap, string iconPath){
string p[]{iconPath};
ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(iconPath);
Vector3 iconSize = Vector3(asset->width, asset->height, 0);
Texture *tex = new Texture(p, 1, false);
Root *root = Root::getSingleton();
Material *mat = new Material(root->getLibPath() + "gui");
mat->addBoolUniform("texturingEnabled", true);
mat->addTexUniform("diffuseMap", tex, false);
sol::state_view SOL_LUA_VIEW = generateView();
sol::table posTbl = SOL_LUA_VIEW["minimapPos"],
_posTbl = SOL_LUA_VIEW["_minimapPos"],
sizeTbl = SOL_LUA_VIEW["minimapSize"],
_sizeTbl = SOL_LUA_VIEW["_minimapSize"];
Vector2 minimapSize = Vector2((float)_sizeTbl["x"], (float)_sizeTbl["y"]);
Vector3 minimapPos = Vector3((float)_posTbl["x"], (float)posTbl["y"] + (float)_posTbl["y"], (float)posTbl["z"]);
Vector3 mapSize = Map::getSingleton()->getMapSize();
Vector2 iconPos = Vector2(
minimapSize.x * (posOnMap.x + .5 * mapSize.x) / mapSize.x,
minimapSize.y * (posOnMap.z + .5 * mapSize.z) / mapSize.z
);
Quad *quad = new Quad(iconSize, false);
quad->setMaterial(mat);
Node *node = new Node(minimapPos + Vector3(iconPos.x, iconPos.y, .05) - .5 * iconSize);
node->attachMesh(quad);
root->getGuiNode()->attachChild(node);
return node;
}
//TODO add a flag to Player::getUnits* whether to include garrisoned units
void Map::Minimap::updateImage(){
GameManager *gm = GameManager::getSingleton();
Map *map = Map::getSingleton();
string imagePath = gm->getPath() + "Models/Maps/" + map->getMapName() + "/minimap.jpg";
ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(imagePath);
int width = asset->width, height = asset->height;
Vector3 mapSize = map->getMapSize();
vector<pair<Unit*, Vector2>> unitMinimapPos;
ActiveGameState *activeState = (ActiveGameState*)gm->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
for(Player *pl : Game::getSingleton()->getPlayers(true))
if(pl->getTeam() == activeState->getPlayer()->getTeam()){
vector<Unit*> units = pl->getUnits();
for(Unit *u : units){
if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue;
Vector2 coords = Vector2(
int(u->getPos().x / mapSize.x * width),
int(-u->getPos().z / mapSize.z * height)
);
unitMinimapPos.push_back(make_pair(u, coords));
}
}
int pxId = 0, numChannels = asset->numChannels, size = width * height * numChannels;
float losFactor = .6;
for(u8 *p = asset->image; p != asset->image + size; p += numChannels, pxId += numChannels){
*(p + 0) = losFactor * oldImageData[pxId + 0];
*(p + 1) = losFactor * oldImageData[pxId + 1];
*(p + 2) = losFactor * oldImageData[pxId + 2];
}
int unitPxRadius = 1;
for(pair<Unit*, Vector2> unitPair : unitMinimapPos){
Unit *losUnit = unitPair.first;
Vector2 losUnitCoords = unitPair.second;
float minimapLos = losUnit->getLineOfSight() / mapSize.x * width;
for(int x = max(-.5f * width, losUnitCoords.x - minimapLos); x < min(.5f * width, losUnitCoords.x + minimapLos); x++){
for(int y = max(-.5f * height, losUnitCoords.y - minimapLos); y < min(.5f * height, losUnitCoords.y + minimapLos); y++){
int pxId = width * (y + .5 * height) + (x + .5 * width);
Vector2 coords = Vector2(x, y);
if(coords.getDistanceFrom(losUnitCoords) < minimapLos){
asset->image[numChannels * pxId + 0] = oldImageData[numChannels * pxId + 0];
asset->image[numChannels * pxId + 1] = oldImageData[numChannels * pxId + 1];
asset->image[numChannels * pxId + 2] = oldImageData[numChannels * pxId + 2];
for(pair<Unit*, Vector2> addUnitPair : unitMinimapPos)
if(fabs(addUnitPair.second.x - coords.x) < unitPxRadius && fabs(addUnitPair.second.y - coords.y) < unitPxRadius){
Vector3 unitCol = addUnitPair.first->getPlayer()->getColor();
asset->image[numChannels * pxId + 0] = unitCol.x * 255;
asset->image[numChannels * pxId + 1] = unitCol.y * 255;
asset->image[numChannels * pxId + 2] = unitCol.z * 255;
break;
}
}
}
}
}
Node *rectNode = ConcreteGuiManager::getSingleton()->getButton("minimap")->getRectNode();
Material *mat = rectNode->getMesh(0)->getMaterial();
Texture *tex = ((Material::TextureUniform*)mat->getUniform("diffuseMap"))->value;
tex->loadImageData(asset, false);
}
void Map::Minimap::updateCamFrame(Button *minimapButton){
Vector3 camPos = Root::getSingleton()->getCamera()->getPosition();
Vector3 mapSize = Map::getSingleton()->getMapSize();
Vector2 minimapSize = minimapButton->getSize();
Vector2 iconPos = Vector2(
minimapSize.x * (camPos.x + .5 * mapSize.x) / mapSize.x,
minimapSize.y * (camPos.z + .5 * mapSize.z) / mapSize.z
);
camIcon->setPosition(minimapButton->getPos() + Vector3(iconPos.x, iconPos.y, .06));
}
void Map::Minimap::update(){
Button *mb = ConcreteGuiManager::getSingleton()->getButton("minimap");
if(!(GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE) && mb)) return;
updateCamFrame(mb);
}
void Map::Minimap::load(){
for(Node *node : depositIcons)
node->setVisible(true);
AssetManager *am = AssetManager::getSingleton();
string minimapPath = GameManager::getSingleton()->getPath() + "Models/Maps/" + Map::getSingleton()->getMapName() + "/minimap.jpg";
am->load(minimapPath);
ImageAsset *asset = (ImageAsset*)am->getAsset(minimapPath);
int imgSize = asset->width * asset->height * asset->numChannels;
oldImageData = new u8[imgSize];
for(int i = 0; i < imgSize; i++)
oldImageData[i] = asset->image[i];
}
void Map::Minimap::unload(){
for(Node *node : depositIcons)
node->setVisible(false);
delete[] oldImageData;
}
Map* Map::getSingleton(){
if(!map) map = new Map;
return map;
}
vector<Map::Edge> Map::generateAdjacentNodeEdges(int numVertCells, int i, int numHorCells, int j, int weight){
vector<Map::Edge> edges;
bool checkUp = (i > 0), checkRight = (j < numHorCells - 1), checkDown = (i < numVertCells - 1), checkLeft = (j > 0);
if(checkLeft)
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * i + j - 1));
if(checkRight)
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * i + j + 1));
if(checkUp)
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * (i - 1) + j));
if(checkDown)
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * (i + 1) + j));
if(checkUp && checkLeft)
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i - 1) + j - 1));
if(checkUp && checkRight)
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i - 1) + j + 1));
if(checkDown && checkLeft)
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i + 1) + j - 1));
if(checkDown && checkRight)
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i + 1) + j + 1));
return edges;
}
void Map::update(){
Minimap::getSingleton()->update();
}
void Map::loadSkybox(){
sol::state_view SOL_LUA_STATE = generateView();
string skyboxName = SOL_LUA_STATE[mapTable]["skybox"];
string basePath = GameManager::getSingleton()->getPath() + "Textures/Skyboxes/" + skyboxName;
const int numPaths = 6;
string path[numPaths] = {
basePath + "/left.jpg",
basePath + "/right.jpg",
basePath + "/up.jpg",
basePath + "/down.jpg",
basePath + "/front.jpg",
basePath + "/back.jpg"
};
for(int i = 0; i < numPaths; i++)
AssetManager::getSingleton()->load(path[i]);
Root::getSingleton()->createSkybox(path);
}
void Map::loadLights(){
sol::state_view SOL_LUA_VIEW = generateView();
sol::table lightsTbl = SOL_LUA_VIEW[mapTable]["lights"];
int numLights = lightsTbl.size();
for(int i = 0; i < numLights; i++){
int id = i + 1;
Light::Type type = (Light::Type)lightsTbl[id]["type"];
sol::table colTbl = lightsTbl[id]["color"];
Light *light = new Light(type);
light->setColor(Vector3(colTbl["x"], colTbl["y"], colTbl["z"]));
Node *lightNode = new Node();
lights.push_back(lightNode);
lightNode->addLight(light);
if(type == Light::Type::DIRECTIONAL){
sol::table dirTbl = lightsTbl[id]["dir"];
Vector3 dir = Vector3(dirTbl["x"], dirTbl["y"], dirTbl["z"]).norm();
lightNode->lookAt(dir);
}
Root::getSingleton()->getRootNode()->attachChild(lightNode);
}
}
void Map::loadTerrainObject(int id){
string texPath = "", albedoPath = "";
Quad *quad = nullptr;
Node *node = nullptr;
sol::state_view SOL_LUA_STATE = generateView();
if(id == -1){
string basePath = GameManager::getSingleton()->getPath() + "Models/Maps/" + mapName + "/";
albedoPath = SOL_LUA_STATE[mapTable]["terrain"]["albedo"];
texPath = basePath + albedoPath;
string modelPath = SOL_LUA_STATE[mapTable]["terrain"]["model"];
string terrainFile = basePath + modelPath;
AssetManager::getSingleton()->load(terrainFile);
node = (Model*)((new Model(terrainFile))->getChild(0));
Node *par = node->getParent();
par->dettachChild(node);
delete par;
}
else{
sol::table waterBodyTable = SOL_LUA_STATE[mapTable]["waterbodies"][id + 1], posTable = waterBodyTable["pos"];
albedoPath = waterBodyTable["albedo"];
texPath = GameManager::getSingleton()->getPath() + "Textures/Water/" + albedoPath;
quad = new Quad(Vector3(waterBodyTable["size"]["x"], waterBodyTable["size"]["y"], 1), true);
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
node = new Node(pos);
node->attachMesh(quad);
}
terrainNode->attachChild(node);
Material *mat = new Material(Root::getSingleton()->getLibPath() + "texture");
mat->addBoolUniform("texturingEnabled", true);
mat->addBoolUniform("lightingEnabled", true);
mat->addBoolUniform("constLightingEnabled", true);
mat->addBoolUniform("normalMapEnabled", false);
mat->addBoolUniform("specularMapEnabled", false);
mat->addBoolUniform("castShadow", false);
string fr[]{texPath};
AssetManager::getSingleton()->load(fr[0]);
Texture *t = new Texture(fr, 1, false);
mat->addTexUniform("textures[0]", t, true);
if(id == -1)
((Model*)node)->setMaterial(mat);
else{
mat->setTransparent(true);
quad->setMaterial(mat);
}
}
int Map::getNumMapSpawnPoints(string name){
if(name != "")
generateView().script_file(GameManager::getSingleton()->getPath() + "Models/Maps/" + name + "/" + name + ".lua");
sol::table spawnPointsTbl = generateView()["metadata"]["spawnPoints"];
return spawnPointsTbl.size();
}
//TODO improve for underwater cells
vector<int> Map::getSurroundingCells(Vector3 p, int numRings){
int numHorCells = int(mapSize.x / CELL_SIZE.x);
int numVertCells = int(mapSize.z / CELL_SIZE.z);
int horId = int((.5 * mapSize.x + p.x) / CELL_SIZE.x);
int vertId = int((.5 * mapSize.z + p.z) / CELL_SIZE.z);
vector<int> cellIds;
for(int i = max(vertId - numRings, 0); i <= min(vertId + numRings, numVertCells - 1); i++)
for(int j = max(horId - numRings, 0); j <= min(horId + numRings, numHorCells - 1); j++)
cellIds.push_back(numHorCells * i + j);
return cellIds;
}
void Map::blockCells(Unit *unit){
vector<int> surroundingCellIds = getSurroundingCells(unit->getPos(), 0);
for(int scid : surroundingCellIds){
if(cells[scid].blockedBy && cells[scid].blockedBy != unit) continue;
bool within = unit->pointWithinObj(cells[scid].pos);
cells[scid].blockedBy = (within ? unit : nullptr);
}
}
void Map::unblockCells(Unit *unit){
vector<int> surroundingCellIds = getSurroundingCells(unit->getPos(), 0);
for(int scid : surroundingCellIds)
if(cells[scid].blockedBy == unit)
cells[scid].blockedBy = nullptr;
}
void Map::loadSpawnPoints(){
sol::state_view SOL_LUA_VIEW = generateView();
int numSpawnPoints = getNumMapSpawnPoints();
for(int i = 0; i < numSpawnPoints; i++){
sol::table posTable = SOL_LUA_VIEW[mapTable]["spawnPoints"][i + 1];
spawnPoints.push_back(Vector3(posTable["x"], posTable["y"], posTable["z"]));
}
}
void Map::loadPlayerGameObjects(Player *player, sol::table playerTbl){
sol::state_view SOL_LUA_VIEW = generateView();
string resDepInd = "resourceDeposits";
sol::optional<sol::table> resDepTblOpt = playerTbl[resDepInd];
if(resDepTblOpt != sol::nullopt){
sol::table resDepTbl = playerTbl[resDepInd];
int numNpcObjs = resDepTbl.size();
for(int j = 0; j < numNpcObjs; j++){
sol::table npcObjTable = resDepTbl[j + 1];
int id = npcObjTable["id"];
sol::table posTable = npcObjTable["pos"];
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
sol::table rotTable = npcObjTable["rot"];
Quaternion rot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
int initAmmount = resDepTbl[j + 1]["initAmmount"];
player->addResourceDeposit(GameObjectFactory::createResourceDeposit(player, id, pos, rot, initAmmount));
}
}
string unitInd = "units";
sol::optional<sol::table> unitsTblOpt = playerTbl[unitInd];
if(unitsTblOpt != sol::nullopt){
sol::table unitsTbl = playerTbl[unitInd];
int numUnits = unitsTbl.size();
for(int j = 0; j < numUnits; j++){
sol::table unitTable = unitsTbl[j + 1];
string posInd = "pos";
Vector3 pos = Vector3(unitTable[posInd]["x"], unitTable[posInd]["y"], unitTable[posInd]["z"]);
string rotInd = "rot";
Quaternion rot = Quaternion(unitTable[rotInd]["w"], unitTable[rotInd]["x"], unitTable[rotInd]["y"], unitTable[rotInd]["z"]);
int id = unitTable["id"];
int buildStatus = unitTable["buildStatus"].get_or(0);
player->addUnit(GameObjectFactory::createUnit(player, id, pos, rot, buildStatus));
}
}
}
//TODO move minimap loading elsewhere
void Map::loadPlayersGameObjects(){
Game *game = Game::getSingleton();
vector<Player*> choosablePlayers = game->getPlayers(false);
sol::state_view SOL_LUA_VIEW = generateView();
for(int i = 0; i < choosablePlayers.size(); i++){
sol::table playerTbl = SOL_LUA_VIEW[mapTable]["choosablePlayers"][i + 1];
loadPlayerGameObjects(choosablePlayers[i], playerTbl);
sol::table unitsTbl = playerTbl["units"];
int numUnits = unitsTbl.size();
if(numUnits == 0){
int engiId;
switch(choosablePlayers[i]->getFaction()){
case 0:
engiId = 9;
break;
case 1:
engiId = 11;
break;
case 2:
engiId = 13;
break;
}
Vector3 sp = getSpawnPoint(choosablePlayers[i]->getSpawnPointId());
choosablePlayers[i]->addUnit(GameObjectFactory::createUnit(choosablePlayers[i], engiId, sp, Quaternion::QUAT_W));
}
}
sol::table civPlayerTbl = SOL_LUA_VIEW[mapTable]["civilianPlayer"];
loadPlayerGameObjects(game->getCivilianPlayer(), civPlayerTbl);
}
void Map::preprareScene(bool empty){
Game::getSingleton()->setCivilianPlayer(new Player(0, 0, 0, .5 * Vector3::VEC_IJK));
Root *root = Root::getSingleton();
Node *rootNode = root->getRootNode();
string libPath = root->getLibPath();
terrainNode = new Node();
rootNode->attachChild(terrainNode);
cellNode = new Node();
cellNode->setVisible(false);
rootNode->attachChild(cellNode);
landCellMat = new Material(libPath + "texture");
landCellMat->addBoolUniform("lightingEnabled", false);
landCellMat->addBoolUniform("texturingEnabled", false);
landCellMat->addVec4Uniform("diffuseColor", Vector4(0, 1, 0, 1));
waterCellMat = new Material(libPath + "texture");
waterCellMat->addBoolUniform("lightingEnabled", false);
waterCellMat->addBoolUniform("texturingEnabled", false);
waterCellMat->addVec4Uniform("diffuseColor", Vector4(0, 0, 1, 1));
Camera *cam = root->getCamera();
cam->setFarPlane(600);
cam->setPosition(Vector3(1, 1, 1) * configData::CAMERA_DISTANCE);
cam->lookAt(Vector3(-1, -1, -1).norm(), Vector3(-1, 1, -1).norm());
if(empty){
Light *light = new Light(Light::Type::AMBIENT);
light->setColor(Vector3::VEC_IJK * .9);
Node *node = new Node();
node->addLight(light);
Root::getSingleton()->getRootNode()->attachChild(node);
lights.push_back(node);
}
}
//TODO implement toggleable cell rendering
//TODO remove srcCellId from the Edge struct
void Map::loadCells(){
sol::state_view SOL_LUA_VIEW = generateView();
sol::table cellsTable = SOL_LUA_VIEW["cells"];
int numCells = cellsTable.size();
for(int i = 0; i < numCells; i++){
sol::table cellTable = cellsTable[i + 1], posTable = cellTable["pos"];
int numEdges = cellTable["numEdges"];
vector<Edge> edges;
for(int j = 0; j < numEdges; j++){
sol::table edgeTable = cellTable["edges"][j + 1];
edges.push_back(Edge(edgeTable["weight"], edgeTable["srcCellId"], edgeTable["destCellId"]));
}
int numUnderWaterCells = cellTable["numUnderWaterCells"];
vector<int> underWaterCellIds;
for(int j = 0; j < numUnderWaterCells; j++)
underWaterCellIds.push_back((int)cellTable["underWaterCellId"][j + 1]);
Vector3 cellPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
Cell::Type cellType = (Cell::Type)cellTable["type"];
/*
Quad *quad = new Quad(Vector3(CELL_SIZE.x, CELL_SIZE.z, 0));
quad->setWireframe(true);
quad->setMaterial(cellType == Cell::Type::LAND ? landCellMat : waterCellMat);
Node *node = new Node(cellPos + Vector3::VEC_J * .1);
node->attachMesh(quad);
*/
cells.push_back(Cell(cellPos, cellType, edges, underWaterCellIds));
}
}
void Map::fillRegion(vector<Map::Cell*>& regionCells, int cellId){
Map::Cell::Type type = cells[cellId].type;
if(find(regionCells.begin(), regionCells.end(), &cells[cellId]) == regionCells.end())
regionCells.push_back(&cells[cellId]);
for(int i = 0; i < cells[cellId].edges.size(); i++){
int adjCellId = cells[cellId].edges[i].destCellId;
bool underwaterWaterCell = (
find(cells[cellId].underWaterCellIds.begin(), cells[cellId].underWaterCellIds.end(), adjCellId)
!=
cells[cellId].underWaterCellIds.end()
);
if(underwaterWaterCell || cells[adjCellId].type != type) continue;
bool adjCellInRegion = (find(regionCells.begin(), regionCells.end(), &cells[adjCellId]) == regionCells.end());
if(adjCellInRegion) fillRegion(regionCells, adjCellId);
}
}
void Map::calculateRegions(){
bool allCellsInRegions = false;
int nextCellId = 0, numSurfaceCells = (int(mapSize.x / CELL_SIZE.x)) * (int(mapSize.z / CELL_SIZE.z));
while(!allCellsInRegions){
vector<Map::Cell*> regionCells;
fillRegion(regionCells, nextCellId);
regions.push_back(make_pair(cells[nextCellId].type, regionCells));
int sumCellsInRegions = 0;
for(int i = 0; i < regions.size(); i++)
sumCellsInRegions += regions[i].second.size();
allCellsInRegions = (sumCellsInRegions == numSurfaceCells);
if(!allCellsInRegions)
for(int i = 0; i < cells.size(); i++){
bool inRegion = false;
for(int j = 0; j < regions.size(); j++)
if(find(regions[j].second.begin(), regions[j].second.end(), &cells[i]) != regions[j].second.end()){
inRegion = true;
break;
}
if(!inRegion){
nextCellId = i;
break;
}
}
}
for(pair<Map::Cell::Type, vector<Cell*>>& reg : regions){
if(reg.first != Cell::Type::WATER) continue;
int oldNumCells = reg.second.size();
for(int i = 0; i < oldNumCells; i++)
for(int ucId : reg.second[i]->underWaterCellIds)
reg.second.push_back(&cells[ucId]);
}
}
void Map::load(string mapName){
this->mapName = mapName;
Pathfinder::getSingleton()->setImpassibleNodeVal(u32(0 - 1));
string path = GameManager::getSingleton()->getPath();
AssetManager::getSingleton()->load(path + "Textures/", true);
sol::state_view SOL_LUA_STATE = generateView();
SOL_LUA_STATE.script_file(path + "Models/Maps/" + mapName + "/" + mapName + ".lua");
SOL_LUA_STATE.script_file(path + "Models/Maps/" + mapName + "/cells.lua");
sol::table sizeTable = SOL_LUA_STATE[mapTable]["size"];
mapSize = Vector3(sizeTable["x"], sizeTable["y"], sizeTable["z"]);
preprareScene(false);
loadSpawnPoints();
loadSkybox();
loadCells();
calculateRegions();
loadTerrainObject(-1);
sol::optional<sol::table> lightsOpt = SOL_LUA_STATE[mapTable]["lights"];
if(lightsOpt != sol::nullopt)
loadLights();
sol::table wbTbl = SOL_LUA_STATE[mapTable]["waterbodies"];
int numWaterbodies = wbTbl.size();
for(int i = 0; i < numWaterbodies; i++)
loadTerrainObject(i);
loadPlayersGameObjects();
}
void Map::create(string mapName, Vector3 mapSize){
this->mapName = mapName;
this->mapSize = mapSize;
//addSpawnPoint(Vector3::VEC_ZERO);
preprareScene(true);
}
//TODO unload skybox assets
void Map::unloadSkybox(){
Root::getSingleton()->removeSkybox();
}
void Map::unloadLights(){
while(!lights.empty()){
Root::getSingleton()->getRootNode()->dettachChild(lights[0]);
delete lights[0];
lights.erase(lights.begin());
}
}
void Map::unloadCells(){
while(cellNode->getNumChildren() > 0){
Node *node = cellNode->getChild(0);
node->getMesh(0)->setMaterial(nullptr);
cellNode->dettachChild(node);
delete node;
}
delete landCellMat;
delete waterCellMat;
cells.clear();
}
//TODO unload terrain assets
void Map::unloadTerrainObjects(){
while(terrainNode->getNumChildren() > 0){
Node *node = terrainNode->getChild(0);
terrainNode->dettachChild(node);
delete node;
}
}
void Map::unloadPlayerObjects(){
for(Player *pl : Game::getSingleton()->getPlayers(true)){
while(pl->getNumUnits() > 0){
pl->removeUnit(0);
}
while(pl->getNumResourceDeposits() > 0){
pl->removeResourceDeposit(0);
}
}
}
void Map::destroyScene(){
Node *rootNode = Root::getSingleton()->getRootNode();
rootNode->dettachChild(terrainNode);
rootNode->dettachChild(cellNode);
delete terrainNode;
delete cellNode;
}
void Map::unload(){
Minimap::getSingleton()->unload();
unloadPlayerObjects();
unloadCells();
unloadTerrainObjects();
destroyScene();
unloadLights();
unloadSkybox();
spawnPoints.clear();
}
vector<RayCaster::CollisionResult> Map::raycastTerrain(Vector3 rayPos, Vector3 rayDir, bool bothTerrTypes){
vector<RayCaster::CollisionResult> allResults = RayCaster::cast(rayPos, rayDir, terrainNode->getChild(0), 0, configData::DIST_FROM_RAY);
if(bothTerrTypes){
vector<Node*> waterNodes = terrainNode->getChildren();
waterNodes.erase(waterNodes.begin());
vector<RayCaster::CollisionResult> waterResults = RayCaster::cast(rayPos, rayDir, waterNodes);
allResults.insert(allResults.end(), waterResults.begin(), waterResults.end());
RayCaster::sortResults(allResults);
}
return allResults;
}
template<typename T> int Map::bsearch(vector<T> haystack, T needle, float eps){
T haystackMidVal;
bool sizeHaystackEven = (haystack.size() % 2 == 0);
int midValId = haystack.size() / 2;
if(sizeHaystackEven)
haystackMidVal = (haystack[midValId - 1] + haystack[midValId]) / 2;
else
haystackMidVal = haystack[midValId];
int beginId, endId;
if(fabs(haystackMidVal - needle) > eps){
if(fabs(haystackMidVal - needle) < eps){
beginId = 0;
endId = (midValId - 1);
}
else{
endId = haystack.size() - 1;
endId = (midValId + 1);
}
return bsearch(vector<T>(haystack.begin() + beginId, haystack.begin() + endId), needle);
}
else{
if(sizeHaystackEven)
return midValId - (needle > haystackMidVal ? 0 : 1);
else
return midValId;
}
}
//TODO replace search with binary search
//TODO optimize horizontal and vertical id calculcation
int Map::getCellId(Vector3 pos, bool checkUnderwaterCells){
int numHorCells = int(mapSize.x / CELL_SIZE.x), horId = -1;
for(int i = 0; i < numHorCells; i++)
if(fabs(cells[i].pos.x - pos.x) <= .5 * CELL_SIZE.x){
horId = i;
break;
}
int numVertCells = int(mapSize.z / CELL_SIZE.z), vertId = -1;
for(int i = 0; i < numVertCells; i++)
if(fabs(cells[i * numHorCells].pos.z - pos.z) <= .5 * CELL_SIZE.z){
vertId = i;
break;
}
int surfaceCellId = vertId * numHorCells + horId;
if(checkUnderwaterCells && cells[surfaceCellId].type == Cell::Type::WATER && !cells[surfaceCellId].underWaterCellIds.empty()){
int cellId = surfaceCellId;
for(int i = 0; i <= cells[surfaceCellId].underWaterCellIds.size(); i++){
cellId = (i == 0 ? surfaceCellId : cells[surfaceCellId].underWaterCellIds[i - 1]);
if(fabs(cells[cellId].pos.y - pos.y) < .5 * CELL_SIZE.y)
return cellId;
}
return surfaceCellId;
}
else return surfaceCellId;
}
}