refactor: Refactor map
- Extract map logic into a separate class - Load map properties as part of the area
This commit is contained in:
parent
74fe30beaa
commit
5677bf29cb
9 changed files with 258 additions and 108 deletions
|
@ -399,6 +399,7 @@ set(GAME_HEADERS
|
|||
src/game/gui/partyselect.h
|
||||
src/game/gui/saveload.h
|
||||
src/game/gui/selectoverlay.h
|
||||
src/game/map.h
|
||||
src/game/object/area.h
|
||||
src/game/object/camera.h
|
||||
src/game/object/creature.h
|
||||
|
@ -486,6 +487,7 @@ set(GAME_SOURCES
|
|||
src/game/gui/partyselect.cpp
|
||||
src/game/gui/saveload.cpp
|
||||
src/game/gui/selectoverlay.cpp
|
||||
src/game/map.cpp
|
||||
src/game/object/area.cpp
|
||||
src/game/object/camera.cpp
|
||||
src/game/object/creature.cpp
|
||||
|
|
|
@ -17,18 +17,16 @@
|
|||
|
||||
#include "map.h"
|
||||
|
||||
#include "../../../common/log.h"
|
||||
#include "../../../render/mesh/quad.h"
|
||||
#include "../../../render/textures.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../../game.h"
|
||||
#include "../../map.h"
|
||||
|
||||
#include "../colors.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::gui;
|
||||
using namespace reone::render;
|
||||
using namespace reone::resource;
|
||||
|
||||
namespace reone {
|
||||
|
@ -56,98 +54,22 @@ void MapMenu::load() {
|
|||
|
||||
disableControl("BTN_PRTYSLCT");
|
||||
disableControl("BTN_RETURN");
|
||||
|
||||
string arrowTex("mm_barrow");
|
||||
if (_version == GameVersion::TheSithLords) {
|
||||
arrowTex += "_p";
|
||||
}
|
||||
_arrow = Textures::instance().get(arrowTex, TextureType::GUI);
|
||||
}
|
||||
|
||||
void MapMenu::update(float dt) {
|
||||
const ModuleInfo &info = _game->module()->info();
|
||||
string mapResRef("lbl_map" + info.entryArea);
|
||||
_map = Textures::instance().get(mapResRef, TextureType::GUI);
|
||||
}
|
||||
|
||||
void MapMenu::render() const {
|
||||
GUI::render();
|
||||
|
||||
if (!_map) return;
|
||||
|
||||
drawMap();
|
||||
drawPartyLeader();
|
||||
}
|
||||
|
||||
void MapMenu::drawMap() const {
|
||||
Control &label = getControl("LBL_Map");
|
||||
const Control::Extent &extent = label.extent();
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::translate(transform, glm::vec3(_controlOffset.x + extent.left, _controlOffset.y + extent.top, 0.0f));
|
||||
transform = glm::scale(transform, glm::vec3(extent.width, extent.height, 1.0f));
|
||||
glm::vec4 bounds(
|
||||
_controlOffset.x + extent.left,
|
||||
_controlOffset.y + extent.top,
|
||||
extent.width,
|
||||
extent.height);
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.general.model = transform;
|
||||
|
||||
Shaders::instance().activate(ShaderProgram::GUIGUI, locals);
|
||||
|
||||
_map->bind(0);
|
||||
|
||||
Quad::getDefault().renderTriangles();
|
||||
}
|
||||
|
||||
void MapMenu::drawPartyLeader() const {
|
||||
shared_ptr<Creature> partyLeader(_game->party().leader());
|
||||
if (!partyLeader) return;
|
||||
|
||||
const ModuleInfo &info = _game->module()->info();
|
||||
glm::vec3 leaderPos(partyLeader->position());
|
||||
float scaleX, scaleY, relX, relY;
|
||||
|
||||
switch (info.northAxis) {
|
||||
case 0:
|
||||
case 1:
|
||||
scaleX = (info.mapPoint1.x - info.mapPoint2.x) / (info.worldPoint1.x - info.worldPoint2.x);
|
||||
scaleY = (info.mapPoint1.y - info.mapPoint2.y) / (info.worldPoint1.y - info.worldPoint2.y);
|
||||
relX = (leaderPos.x - info.worldPoint1.x) * scaleX + info.mapPoint1.x;
|
||||
relY = (leaderPos.y - info.worldPoint1.y) * scaleY + info.mapPoint1.y;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
scaleX = (info.mapPoint1.y - info.mapPoint2.y) / (info.worldPoint1.x - info.worldPoint2.x);
|
||||
scaleY = (info.mapPoint1.x - info.mapPoint2.x) / (info.worldPoint1.y - info.worldPoint2.y);
|
||||
relX = (leaderPos.y - info.worldPoint1.y) * scaleY + info.mapPoint1.x;
|
||||
relY = (leaderPos.x - info.worldPoint1.x) * scaleX + info.mapPoint1.y;
|
||||
break;
|
||||
default:
|
||||
warn("Map: invalid north axis: " + to_string(info.northAxis));
|
||||
return;
|
||||
}
|
||||
|
||||
Control &label = getControl("LBL_Map");
|
||||
const Control::Extent &extent = label.extent();
|
||||
|
||||
relX *= extent.width / static_cast<float>(_map->width());
|
||||
relY *= extent.height / static_cast<float>(_map->height());
|
||||
|
||||
glm::vec3 arrowPos(
|
||||
_controlOffset.x + extent.left + relX * extent.width - 0.5f * _arrow->width(),
|
||||
_controlOffset.y + extent.top + relY * extent.height - 0.5f * _arrow->height(),
|
||||
0.0f);
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::translate(transform, arrowPos);
|
||||
transform = glm::scale(transform, glm::vec3(_arrow->width(), _arrow->height(), 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.general.model = transform;
|
||||
|
||||
Shaders::instance().activate(ShaderProgram::GUIGUI, locals);
|
||||
|
||||
_arrow->bind(0);
|
||||
|
||||
Quad::getDefault().renderTriangles();
|
||||
shared_ptr<Area> area(_game->module()->area());
|
||||
area->map().render(Map::Mode::Default, bounds);
|
||||
}
|
||||
|
||||
void MapMenu::onClick(const string &control) {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../../../gui/gui.h"
|
||||
|
||||
namespace reone {
|
||||
|
@ -24,24 +26,19 @@ namespace reone {
|
|||
namespace game {
|
||||
|
||||
class Game;
|
||||
class Map;
|
||||
|
||||
class MapMenu : public gui::GUI {
|
||||
public:
|
||||
MapMenu(Game *game);
|
||||
|
||||
void load() override;
|
||||
void update(float dt) override;
|
||||
void render() const override;
|
||||
|
||||
private:
|
||||
Game *_game { nullptr };
|
||||
std::shared_ptr<render::Texture> _map;
|
||||
std::shared_ptr<render::Texture> _arrow;
|
||||
|
||||
void onClick(const std::string &control) override;
|
||||
|
||||
void drawMap() const;
|
||||
void drawPartyLeader() const;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
|
|
156
src/game/map.cpp
Normal file
156
src/game/map.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The reone project contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "map.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "glm/mat4x4.hpp"
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "../render/mesh/quad.h"
|
||||
#include "../render/textures.h"
|
||||
#include "../resource/types.h"
|
||||
|
||||
#include "game.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
using namespace reone::render;
|
||||
using namespace reone::resource;
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace game {
|
||||
|
||||
Map::Map(Game *game) : _game(game) {
|
||||
if (!game) {
|
||||
throw invalid_argument("game must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
void Map::load(const string &area, const GffStruct &gffs) {
|
||||
loadProperties(gffs);
|
||||
loadTexture(area);
|
||||
|
||||
if (!_arrow) {
|
||||
loadArrow();
|
||||
}
|
||||
}
|
||||
|
||||
void Map::loadProperties(const GffStruct &gffs) {
|
||||
_northAxis = gffs.getInt("NorthAxis");
|
||||
_worldPoint1 = glm::vec2(gffs.getFloat("WorldPt1X"), gffs.getFloat("WorldPt1Y"));
|
||||
_worldPoint2 = glm::vec2(gffs.getFloat("WorldPt2X"), gffs.getFloat("WorldPt2Y"));
|
||||
_mapPoint1 = glm::vec2(gffs.getFloat("MapPt1X"), gffs.getFloat("MapPt1Y"));
|
||||
_mapPoint2 = glm::vec2(gffs.getFloat("MapPt2X"), gffs.getFloat("MapPt2Y"));
|
||||
}
|
||||
|
||||
void Map::loadTexture(const string &area) {
|
||||
string resRef("lbl_map" + area);
|
||||
_texture = Textures::instance().get(resRef, TextureType::GUI);
|
||||
}
|
||||
|
||||
void Map::loadArrow() {
|
||||
string resRef("mm_barrow");
|
||||
if (_game->version() == GameVersion::TheSithLords) {
|
||||
resRef += "_p";
|
||||
}
|
||||
_arrow = Textures::instance().get(resRef, TextureType::GUI);
|
||||
}
|
||||
|
||||
void Map::render(Mode mode, const glm::vec4 &bounds) const {
|
||||
if (!_texture) return;
|
||||
|
||||
drawArea(mode, bounds);
|
||||
drawPartyLeader(mode, bounds);
|
||||
}
|
||||
|
||||
void Map::drawArea(Mode mode, const glm::vec4 &bounds) const {
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::translate(transform, glm::vec3(bounds[0], bounds[1], 0.0f));
|
||||
transform = glm::scale(transform, glm::vec3(bounds[2], bounds[3], 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.general.model = transform;
|
||||
|
||||
Shaders::instance().activate(ShaderProgram::GUIGUI, locals);
|
||||
|
||||
_texture->bind(0);
|
||||
|
||||
Quad::getDefault().renderTriangles();
|
||||
}
|
||||
|
||||
void Map::drawPartyLeader(Mode mode, const glm::vec4 &bounds) const {
|
||||
shared_ptr<Creature> partyLeader(_game->party().leader());
|
||||
if (!partyLeader) return;
|
||||
|
||||
glm::vec3 worldPos(partyLeader->position());
|
||||
|
||||
glm::vec2 mapPos(getMapPosition(worldPos));
|
||||
mapPos.x *= bounds[2] / static_cast<float>(_texture->width());
|
||||
mapPos.y *= bounds[3] / static_cast<float>(_texture->height());
|
||||
|
||||
glm::vec3 arrowPos(
|
||||
bounds[0] + mapPos.x * bounds[2] - 0.5f * _arrow->width(),
|
||||
bounds[1] + mapPos.y * bounds[3] - 0.5f * _arrow->height(),
|
||||
0.0f);
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::translate(transform, arrowPos);
|
||||
transform = glm::scale(transform, glm::vec3(_arrow->width(), _arrow->height(), 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.general.model = transform;
|
||||
|
||||
Shaders::instance().activate(ShaderProgram::GUIGUI, locals);
|
||||
|
||||
_arrow->bind(0);
|
||||
|
||||
Quad::getDefault().renderTriangles();
|
||||
}
|
||||
|
||||
glm::vec2 Map::getMapPosition(const glm::vec2 &world) const {
|
||||
float scaleX, scaleY;
|
||||
glm::vec2 result(0.0f);
|
||||
|
||||
switch (_northAxis) {
|
||||
case 0:
|
||||
case 1:
|
||||
scaleX = (_mapPoint1.x - _mapPoint2.x) / (_worldPoint1.x - _worldPoint2.x);
|
||||
scaleY = (_mapPoint1.y - _mapPoint2.y) / (_worldPoint1.y - _worldPoint2.y);
|
||||
result.x = (world.x - _worldPoint1.x) * scaleX + _mapPoint1.x;
|
||||
result.y = (world.y - _worldPoint1.y) * scaleY + _mapPoint1.y;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
scaleX = (_mapPoint1.y - _mapPoint2.y) / (_worldPoint1.x - _worldPoint2.x);
|
||||
scaleY = (_mapPoint1.x - _mapPoint2.x) / (_worldPoint1.y - _worldPoint2.y);
|
||||
result.x = (world.y - _worldPoint1.y) * scaleY + _mapPoint1.x;
|
||||
result.y = (world.x - _worldPoint1.x) * scaleX + _mapPoint1.y;
|
||||
break;
|
||||
default:
|
||||
warn("Map: invalid north axis: " + to_string(_northAxis));
|
||||
break;
|
||||
}
|
||||
|
||||
return move(result);
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
} // namespace reone
|
70
src/game/map.h
Normal file
70
src/game/map.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The reone project contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "glm/vec2.hpp"
|
||||
#include "glm/vec4.hpp"
|
||||
|
||||
#include "../render/texture.h"
|
||||
#include "../resource/gfffile.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace game {
|
||||
|
||||
class Game;
|
||||
|
||||
class Map {
|
||||
public:
|
||||
enum class Mode {
|
||||
Default,
|
||||
Minimap
|
||||
};
|
||||
|
||||
Map(Game *game);
|
||||
|
||||
void load(const std::string &area, const resource::GffStruct &gffs);
|
||||
void render(Mode mode, const glm::vec4 &bounds) const;
|
||||
|
||||
private:
|
||||
int _northAxis { 0 };
|
||||
glm::vec2 _worldPoint1 { 0.0f };
|
||||
glm::vec2 _worldPoint2 { 0.0f };
|
||||
glm::vec2 _mapPoint1 { 0.0f };
|
||||
glm::vec2 _mapPoint2 { 0.0f };
|
||||
|
||||
Game *_game { nullptr };
|
||||
std::shared_ptr<render::Texture> _texture;
|
||||
std::shared_ptr<render::Texture> _arrow;
|
||||
|
||||
void loadProperties(const resource::GffStruct &gffs);
|
||||
void loadTexture(const std::string &area);
|
||||
void loadArrow();
|
||||
|
||||
void drawArea(Mode mode, const glm::vec4 &bounds) const;
|
||||
void drawPartyLeader(Mode mode, const glm::vec4 &bounds) const;
|
||||
|
||||
glm::vec2 getMapPosition(const glm::vec2 &world) const;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
|
||||
} // namespace reone
|
|
@ -68,7 +68,8 @@ Area::Area(uint32_t id, Game *game) :
|
|||
_collisionDetector(this),
|
||||
_objectSelector(this, &game->party()),
|
||||
_actionExecutor(game),
|
||||
_combat(game) {
|
||||
_combat(game),
|
||||
_map(game) {
|
||||
|
||||
const GraphicsOptions &opts = _game->options().graphics;
|
||||
_cameraAspect = opts.width / static_cast<float>(opts.height);
|
||||
|
@ -140,6 +141,7 @@ void Area::loadARE(const GffStruct &are) {
|
|||
loadCameraStyle(are);
|
||||
loadAmbientColor(are);
|
||||
loadScripts(are);
|
||||
loadMap(are);
|
||||
}
|
||||
|
||||
void Area::loadCameraStyle(const GffStruct &are) {
|
||||
|
@ -171,6 +173,10 @@ void Area::loadScripts(const GffStruct &are) {
|
|||
_onUserDefined = are.getString("OnUserDefined");
|
||||
}
|
||||
|
||||
void Area::loadMap(const GffStruct &are) {
|
||||
_map.load(_name, are.getStruct("Map"));
|
||||
}
|
||||
|
||||
void Area::loadGIT(const GffStruct &git) {
|
||||
loadProperties(git);
|
||||
loadCreatures(git);
|
||||
|
@ -816,6 +822,10 @@ Combat &Area::combat() {
|
|||
return _combat;
|
||||
}
|
||||
|
||||
Map &Area::map() {
|
||||
return _map;
|
||||
}
|
||||
|
||||
const ObjectList &Area::objects() const {
|
||||
return _objects;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "../camera/thirdperson.h"
|
||||
#include "../camera/types.h"
|
||||
#include "../collisiondetect.h"
|
||||
#include "../map.h"
|
||||
#include "../objectselect.h"
|
||||
#include "../pathfinder.h"
|
||||
|
||||
|
@ -90,6 +91,7 @@ public:
|
|||
const Pathfinder &pathfinder() const;
|
||||
const RoomMap &rooms() const;
|
||||
Combat &combat();
|
||||
Map &map();
|
||||
|
||||
// Objects
|
||||
|
||||
|
@ -128,6 +130,7 @@ private:
|
|||
CameraStyle _cameraStyle;
|
||||
std::string _music;
|
||||
float _heartbeatTimeout { kHeartbeatInterval };
|
||||
Map _map;
|
||||
|
||||
// Scripts
|
||||
|
||||
|
@ -180,10 +183,13 @@ private:
|
|||
void loadVIS();
|
||||
void loadPTH();
|
||||
void loadARE(const resource::GffStruct &are);
|
||||
void loadGIT(const resource::GffStruct &gffs);
|
||||
|
||||
void loadCameraStyle(const resource::GffStruct &are);
|
||||
void loadAmbientColor(const resource::GffStruct &are);
|
||||
void loadScripts(const resource::GffStruct &are);
|
||||
void loadGIT(const resource::GffStruct &gffs);
|
||||
void loadMap(const resource::GffStruct &are);
|
||||
|
||||
void loadProperties(const resource::GffStruct &git);
|
||||
void loadCreatures(const resource::GffStruct &git);
|
||||
void loadDoors(const resource::GffStruct &git);
|
||||
|
|
|
@ -76,14 +76,6 @@ void Module::loadArea(const GffStruct &ifo) {
|
|||
shared_ptr<Area> area(_game->objectFactory().newArea());
|
||||
area->load(_info.entryArea, *are, *git);
|
||||
_area = move(area);
|
||||
|
||||
// TODO: move map properties to Area
|
||||
auto &map = are->getStruct("Map");
|
||||
_info.northAxis = map.getInt("NorthAxis");
|
||||
_info.worldPoint1 = glm::vec2(map.getFloat("WorldPt1X"), map.getFloat("WorldPt1Y"));
|
||||
_info.worldPoint2 = glm::vec2(map.getFloat("WorldPt2X"), map.getFloat("WorldPt2Y"));
|
||||
_info.mapPoint1 = glm::vec2(map.getFloat("MapPt1X"), map.getFloat("MapPt1Y"));
|
||||
_info.mapPoint2 = glm::vec2(map.getFloat("MapPt2X"), map.getFloat("MapPt2Y"));
|
||||
}
|
||||
|
||||
void Module::loadPlayer() {
|
||||
|
|
|
@ -46,11 +46,6 @@ struct ModuleInfo {
|
|||
std::string entryArea;
|
||||
glm::vec3 entryPosition { 0.0f };
|
||||
float entryHeading { 0.0f };
|
||||
int northAxis { 0 };
|
||||
glm::vec2 worldPoint1 { 0.0f };
|
||||
glm::vec2 worldPoint2 { 0.0f };
|
||||
glm::vec2 mapPoint1 { 0.0f };
|
||||
glm::vec2 mapPoint2 { 0.0f };
|
||||
};
|
||||
|
||||
class Door;
|
||||
|
|
Loading…
Reference in a new issue