mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-21 18:02:43 +01:00
Overahaul of rwviewer to simplify the code and improve usability
- Shared ViewerWidget has been removed. Now multiple instances exist
This commit is contained in:
parent
6780be6fff
commit
6f9c3db52e
@ -444,7 +444,7 @@ void GameData::loadModelFile(const std::string& name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameData::loadModel(ModelID model) {
|
bool GameData::loadModel(ModelID model) {
|
||||||
auto info = modelinfo[model].get();
|
auto info = modelinfo[model].get();
|
||||||
/// @todo replace openFile with API for loading from CDIMAGE archives
|
/// @todo replace openFile with API for loading from CDIMAGE archives
|
||||||
auto name = info->name;
|
auto name = info->name;
|
||||||
@ -482,13 +482,13 @@ void GameData::loadModel(ModelID model) {
|
|||||||
if (!file) {
|
if (!file) {
|
||||||
logger->error("Data", "Failed to load model for " +
|
logger->error("Data", "Failed to load model for " +
|
||||||
std::to_string(model) + " [" + name + "]");
|
std::to_string(model) + " [" + name + "]");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
auto m = dffLoader.loadFromMemory(file);
|
auto m = dffLoader.loadFromMemory(file);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
logger->error("Data",
|
logger->error("Data",
|
||||||
"Error loading model file for " + std::to_string(model));
|
"Error loading model file for " + std::to_string(model));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
/// @todo handle timeinfo models correctly.
|
/// @todo handle timeinfo models correctly.
|
||||||
auto isSimple = info->type() == ModelDataType::SimpleInfo;
|
auto isSimple = info->type() == ModelDataType::SimpleInfo;
|
||||||
@ -509,6 +509,8 @@ void GameData::loadModel(ModelID model) {
|
|||||||
clump->setModel(m);
|
clump->setModel(m);
|
||||||
/// @todo how is LOD handled for clump objects?
|
/// @todo how is LOD handled for clump objects?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameData::loadIFP(const std::string& name) {
|
void GameData::loadIFP(const std::string& name) {
|
||||||
|
@ -150,7 +150,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Loads and associates a model's data
|
* Loads and associates a model's data
|
||||||
*/
|
*/
|
||||||
void loadModel(ModelID model);
|
bool loadModel(ModelID model);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads an IFP file containing animations
|
* Loads an IFP file containing animations
|
||||||
|
@ -15,6 +15,7 @@ add_executable(rwviewer WIN32
|
|||||||
views/ObjectViewer.cpp
|
views/ObjectViewer.cpp
|
||||||
views/ModelViewer.cpp
|
views/ModelViewer.cpp
|
||||||
views/WorldViewer.cpp
|
views/WorldViewer.cpp
|
||||||
|
views/ViewerInterface.cpp
|
||||||
|
|
||||||
ViewerWidget.cpp
|
ViewerWidget.cpp
|
||||||
ItemListModel.cpp
|
ItemListModel.cpp
|
||||||
|
@ -1,35 +1,44 @@
|
|||||||
#include "ViewerWidget.hpp"
|
#include "ViewerWidget.hpp"
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <algorithm>
|
|
||||||
#include <data/Clump.hpp>
|
|
||||||
#include <engine/Animator.hpp>
|
#include <engine/Animator.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/GameObject.hpp>
|
|
||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
#include <render/GameRenderer.hpp>
|
#include <render/GameRenderer.hpp>
|
||||||
#include <render/ObjectRenderer.hpp>
|
#include <render/ObjectRenderer.hpp>
|
||||||
#include <render/OpenGLRenderer.hpp>
|
|
||||||
|
|
||||||
ViewerWidget::ViewerWidget(QGLFormat g, QWidget* parent,
|
constexpr float kViewFov = glm::radians(90.0f);
|
||||||
const QGLWidget* shareWidget, Qt::WindowFlags f)
|
|
||||||
: QGLWidget(g, parent, shareWidget, f)
|
namespace {
|
||||||
, renderer(nullptr)
|
ViewCamera OrbitCamera (const glm::vec2& viewPort, const glm::vec2& viewAngles,
|
||||||
, gworld(nullptr)
|
float viewDistance, glm::mat4& view, glm::mat4& proj)
|
||||||
, activeModel(nullptr)
|
{
|
||||||
|
ViewCamera vc;
|
||||||
|
glm::vec3 eye(sin(viewAngles.x) * cos(viewAngles.y),
|
||||||
|
cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y));
|
||||||
|
|
||||||
|
vc.position = eye * viewDistance;
|
||||||
|
vc.frustum.aspectRatio = viewPort.x / viewPort.y;
|
||||||
|
proj = vc.frustum.projection();
|
||||||
|
view = glm::lookAt(vc.position, {0.f, 0.f, 0.f}, {0.f, 0.f, 1.f});
|
||||||
|
vc.rotation = -glm::quat_cast(view);
|
||||||
|
vc.frustum.update(proj * view);
|
||||||
|
return vc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewerWidget::ViewerWidget(QOpenGLContext* context, QWindow* parent)
|
||||||
|
: QWindow(parent)
|
||||||
|
, context(context)
|
||||||
, selectedFrame(nullptr)
|
, selectedFrame(nullptr)
|
||||||
, dummyObject(nullptr)
|
|
||||||
, currentObjectID(0)
|
|
||||||
, _lastModel(nullptr)
|
|
||||||
, canimation(nullptr)
|
|
||||||
, viewDistance(1.f)
|
, viewDistance(1.f)
|
||||||
, dragging(false)
|
, dragging(false)
|
||||||
, moveFast(false)
|
, moveFast(false)
|
||||||
, _frameWidgetDraw(nullptr)
|
, _frameWidgetDraw(nullptr)
|
||||||
, _frameWidgetGeom(nullptr) {
|
, _frameWidgetGeom(nullptr) {
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setSurfaceType(OpenGLSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WidgetVertex {
|
struct WidgetVertex {
|
||||||
@ -43,12 +52,7 @@ std::vector<WidgetVertex> widgetVerts = {{-.5f, 0.f, 0.f}, {.5f, 0.f, 0.f},
|
|||||||
{0.f, -.5f, 0.f}, {0.f, .5f, 0.f},
|
{0.f, -.5f, 0.f}, {0.f, .5f, 0.f},
|
||||||
{0.f, 0.f, -.5f}, {0.f, 0.f, .5f}};
|
{0.f, 0.f, -.5f}, {0.f, 0.f, .5f}};
|
||||||
|
|
||||||
void ViewerWidget::initializeGL() {
|
void ViewerWidget::initGL() {
|
||||||
QGLWidget::initializeGL();
|
|
||||||
timer.setInterval(25);
|
|
||||||
connect(&timer, SIGNAL(timeout()), SLOT(updateGL()));
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
_frameWidgetDraw = new DrawBuffer;
|
_frameWidgetDraw = new DrawBuffer;
|
||||||
_frameWidgetDraw->setFaceType(GL_LINES);
|
_frameWidgetDraw->setFaceType(GL_LINES);
|
||||||
_frameWidgetGeom = new GeometryBuffer;
|
_frameWidgetGeom = new GeometryBuffer;
|
||||||
@ -64,88 +68,93 @@ void ViewerWidget::initializeGL() {
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::resizeGL(int w, int h) {
|
void ViewerWidget::drawModel(GameRenderer& r, ClumpPtr& model) {
|
||||||
QGLWidget::resizeGL(w, h);
|
glm::mat4 view, proj;
|
||||||
glViewport(0, 0, w, h);
|
const auto& vc = OrbitCamera({width(), height()},
|
||||||
}
|
viewAngles,
|
||||||
|
viewDistance,
|
||||||
void ViewerWidget::paintGL() {
|
view, proj);
|
||||||
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
glViewport(0, 0, width(), height());
|
|
||||||
|
|
||||||
if (world() == nullptr) return;
|
|
||||||
|
|
||||||
RW_CHECK(renderer != nullptr, "GameRenderer is null");
|
|
||||||
auto& r = *renderer;
|
|
||||||
|
|
||||||
r.setViewport(width(), height());
|
|
||||||
|
|
||||||
if (dummyObject && dummyObject->animator) {
|
|
||||||
dummyObject->animator->tick(1.f / 60.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
r.getRenderer()->invalidate();
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
|
|
||||||
glm::mat4 m(1.f);
|
|
||||||
|
|
||||||
r.getRenderer()->useProgram(r.worldProg.get());
|
r.getRenderer()->useProgram(r.worldProg.get());
|
||||||
|
r.getRenderer()->setSceneParameters(
|
||||||
|
{proj, view, glm::vec4(0.15f), glm::vec4(0.7f), glm::vec4(1.f),
|
||||||
|
glm::vec4(0.f), 90.f, vc.frustum.far});
|
||||||
|
model->getFrame()->updateHierarchyTransform();
|
||||||
|
|
||||||
ViewCamera vc;
|
ObjectRenderer _renderer(world(), vc, 1.f, 0);
|
||||||
|
RenderList renders;
|
||||||
|
_renderer.renderClump(model.get(), glm::mat4(), nullptr, renders);
|
||||||
|
r.getRenderer()->drawBatched(renders);
|
||||||
|
|
||||||
float viewFov = glm::radians(45.f);
|
drawFrameWidget(model->getFrame().get());
|
||||||
|
r.renderPostProcess();
|
||||||
|
}
|
||||||
|
|
||||||
vc.frustum.far = 500.f;
|
void ViewerWidget::drawObject(GameRenderer &r, GameObject *object) {
|
||||||
vc.frustum.near = 0.1f;
|
glm::mat4 view, proj;
|
||||||
vc.frustum.fov = viewFov;
|
const auto& vc = OrbitCamera({width(), height()},
|
||||||
vc.frustum.aspectRatio = width() / (height() * 1.f);
|
viewAngles,
|
||||||
|
viewDistance,
|
||||||
|
view, proj);
|
||||||
|
|
||||||
ClumpPtr model = activeModel;
|
r.getRenderer()->useProgram(r.worldProg.get());
|
||||||
if (model != _lastModel) {
|
r.getRenderer()->setSceneParameters(
|
||||||
_lastModel = model;
|
|
||||||
emit modelChanged(_lastModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 eye(sin(viewAngles.x) * cos(viewAngles.y),
|
|
||||||
cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y));
|
|
||||||
|
|
||||||
if (model) {
|
|
||||||
model->getFrame()->updateHierarchyTransform();
|
|
||||||
|
|
||||||
// Ensure camera is still accurate
|
|
||||||
vc.position = eye * viewDistance;
|
|
||||||
glm::mat4 proj = vc.frustum.projection();
|
|
||||||
glm::mat4 view = glm::lookAt(vc.position, glm::vec3(0.f, 0.f, 0.f),
|
|
||||||
glm::vec3(0.f, 0.f, 1.f));
|
|
||||||
vc.rotation = -glm::quat_cast(view);
|
|
||||||
vc.frustum.update(proj * view);
|
|
||||||
|
|
||||||
r.getRenderer()->setSceneParameters(
|
|
||||||
{proj, view, glm::vec4(0.15f), glm::vec4(0.7f), glm::vec4(1.f),
|
{proj, view, glm::vec4(0.15f), glm::vec4(0.7f), glm::vec4(1.f),
|
||||||
glm::vec4(0.f), 90.f, vc.frustum.far});
|
glm::vec4(0.f), 90.f, vc.frustum.far});
|
||||||
|
|
||||||
r.getRenderer()->invalidate();
|
ObjectRenderer objectRenderer(world(), vc, 1.f, 0);
|
||||||
|
RenderList renders;
|
||||||
|
objectRenderer.buildRenderList(object, renders);
|
||||||
|
std::sort(renders.begin(), renders.end(),
|
||||||
|
[](const Renderer::RenderInstruction& a,
|
||||||
|
const Renderer::RenderInstruction& b) {
|
||||||
|
return a.sortKey < b.sortKey;
|
||||||
|
});
|
||||||
|
r.getRenderer()->drawBatched(renders);
|
||||||
|
r.renderPostProcess();
|
||||||
|
}
|
||||||
|
|
||||||
r.setupRender();
|
void ViewerWidget::drawWorld(GameRenderer& r) {
|
||||||
|
ViewCamera vc;
|
||||||
|
vc.frustum.fov = kViewFov;
|
||||||
|
vc.frustum.far = 1000.f;
|
||||||
|
vc.frustum.near = 0.1f;
|
||||||
|
vc.position = viewPosition;
|
||||||
|
vc.rotation = glm::angleAxis(glm::half_pi<float>() + viewAngles.x,
|
||||||
|
glm::vec3(0.f, 0.f, 1.f)) *
|
||||||
|
glm::angleAxis(viewAngles.y, glm::vec3(0.f, 1.f, 0.f));
|
||||||
|
vc.frustum.aspectRatio = width() / (height() * 1.f);
|
||||||
|
r.renderWorld(world(), vc, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
ObjectRenderer renderer(world(), vc, 1.f, 0);
|
void ViewerWidget::paintGL() {
|
||||||
RenderList renders;
|
glViewport(0, 0, width(), height());
|
||||||
renderer.renderClump(model.get(), glm::mat4(), nullptr, renders);
|
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
|
||||||
r.getRenderer()->drawBatched(renders);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
drawFrameWidget(model->getFrame().get());
|
if (world() == nullptr) return;
|
||||||
r.renderPostProcess();
|
|
||||||
} else if (world()->allObjects.size() > 0) {
|
RW_CHECK(_renderer != nullptr, "GameRenderer is null");
|
||||||
vc.frustum.fov = glm::radians(90.f);
|
auto& r = *_renderer;
|
||||||
vc.frustum.far = 1000.f;
|
r.getRenderer()->invalidate();
|
||||||
vc.position = viewPosition;
|
r.setViewport(width(), height());
|
||||||
vc.rotation = glm::angleAxis(glm::half_pi<float>() + viewAngles.x,
|
|
||||||
glm::vec3(0.f, 0.f, 1.f)) *
|
glEnable(GL_DEPTH_TEST);
|
||||||
glm::angleAxis(viewAngles.y, glm::vec3(0.f, 1.f, 0.f));
|
|
||||||
r.renderWorld(world(), vc, 0.f);
|
|
||||||
|
r.getRenderer()->invalidate();
|
||||||
|
r.setupRender();
|
||||||
|
|
||||||
|
switch (_viewMode) {
|
||||||
|
case Mode::Model:
|
||||||
|
if (_model) drawModel(r, _model);
|
||||||
|
break;
|
||||||
|
case Mode::Object:
|
||||||
|
if (_object) drawObject(r, _object);
|
||||||
|
break;
|
||||||
|
case Mode::World:
|
||||||
|
drawWorld(r);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,9 +175,9 @@ void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m) {
|
|||||||
}
|
}
|
||||||
dp.textures = {whiteTex};
|
dp.textures = {whiteTex};
|
||||||
|
|
||||||
RW_CHECK(renderer != nullptr, "GameRenderer is null");
|
RW_CHECK(_renderer != nullptr, "GameRenderer is null");
|
||||||
if(renderer != nullptr) {
|
if(_renderer != nullptr) {
|
||||||
renderer->getRenderer()->drawArrays(thisM, _frameWidgetDraw, dp);
|
_renderer->getRenderer()->drawArrays(thisM, _frameWidgetDraw, dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto c : f->getChildren()) {
|
for (auto c : f->getChildren()) {
|
||||||
@ -177,40 +186,51 @@ void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameWorld* ViewerWidget::world() {
|
GameWorld* ViewerWidget::world() {
|
||||||
return gworld;
|
return _world;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::showObject(qint16 item) {
|
void ViewerWidget::showObject(quint16 item) {
|
||||||
currentObjectID = item;
|
RW_ASSERT(world());
|
||||||
|
_viewMode = Mode::Object;
|
||||||
|
_objectID = item;
|
||||||
|
|
||||||
if (dummyObject) gworld->destroyObject(dummyObject);
|
if (_object) _world->destroyObject(_object);
|
||||||
|
_object = nullptr;
|
||||||
|
|
||||||
auto def = world()->data->modelinfo[item].get();
|
auto def = world()->data->modelinfo[item].get();
|
||||||
|
if (!def) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (def) {
|
if (!world()->data->loadModel(item)) {
|
||||||
switch (def->type()) {
|
return;
|
||||||
default:
|
}
|
||||||
dummyObject = gworld->createInstance(item, {});
|
|
||||||
break;
|
|
||||||
case ModelDataType::PedInfo:
|
|
||||||
dummyObject = gworld->createPedestrian(item, {});
|
|
||||||
break;
|
|
||||||
case ModelDataType::VehicleInfo:
|
|
||||||
dummyObject = gworld->createVehicle(item, {});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
RW_CHECK(dummyObject != nullptr, "Dummy Object is null");
|
switch (def->type()) {
|
||||||
if (dummyObject != nullptr) {
|
default:
|
||||||
activeModel = dummyObject->getModel();
|
_object = _world->createInstance(item, {});
|
||||||
}
|
break;
|
||||||
|
case ModelDataType::PedInfo:
|
||||||
|
_object = _world->createPedestrian(item, {});
|
||||||
|
break;
|
||||||
|
case ModelDataType::VehicleInfo:
|
||||||
|
_object = _world->createVehicle(item, {});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RW_CHECK(_object != nullptr, "Dummy Object is null");
|
||||||
|
|
||||||
|
if (_object->getModel()) {
|
||||||
|
auto objectRadius = _object->getModel()->getBoundingRadius();
|
||||||
|
viewDistance = objectRadius * 2;
|
||||||
|
viewAngles.x = glm::radians(-45.f);
|
||||||
|
viewAngles.y = glm::radians(22.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::showModel(ClumpPtr model) {
|
void ViewerWidget::showModel(ClumpPtr model) {
|
||||||
if (dummyObject) gworld->destroyObject(dummyObject);
|
_viewMode = Mode::Model;
|
||||||
dummyObject = nullptr;
|
_model = model;
|
||||||
activeModel = model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::selectFrame(ModelFrame* frame) {
|
void ViewerWidget::selectFrame(ModelFrame* frame) {
|
||||||
@ -218,12 +238,12 @@ void ViewerWidget::selectFrame(ModelFrame* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::exportModel() {
|
void ViewerWidget::exportModel() {
|
||||||
|
#if 0
|
||||||
QString toSv = QFileDialog::getSaveFileName(
|
QString toSv = QFileDialog::getSaveFileName(
|
||||||
this, "Export Model", QDir::homePath(), "Model (*.DFF)");
|
this, "Export Model", QDir::homePath(), "Model (*.DFF)");
|
||||||
|
|
||||||
if (toSv.size() == 0) return;
|
if (toSv.size() == 0) return;
|
||||||
|
|
||||||
#if 0
|
|
||||||
auto it = world()->objectTypes.find(currentObjectID);
|
auto it = world()->objectTypes.find(currentObjectID);
|
||||||
if( it != world()->objectTypes.end() ) {
|
if( it != world()->objectTypes.end() ) {
|
||||||
for( auto& archive : world()->data.archives ) {
|
for( auto& archive : world()->data.archives ) {
|
||||||
@ -240,14 +260,6 @@ void ViewerWidget::exportModel() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::dataLoaded(GameWorld* world) {
|
|
||||||
gworld = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewerWidget::setRenderer(GameRenderer* render) {
|
|
||||||
renderer = render;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewerWidget::keyPressEvent(QKeyEvent* e) {
|
void ViewerWidget::keyPressEvent(QKeyEvent* e) {
|
||||||
if (e->key() == Qt::Key_Shift) moveFast = true;
|
if (e->key() == Qt::Key_Shift) moveFast = true;
|
||||||
|
|
||||||
@ -270,11 +282,11 @@ void ViewerWidget::keyReleaseEvent(QKeyEvent* e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClumpPtr ViewerWidget::currentModel() const {
|
ClumpPtr ViewerWidget::currentModel() const {
|
||||||
return activeModel;
|
return _model;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObject* ViewerWidget::currentObject() const {
|
GameObject* ViewerWidget::currentObject() const {
|
||||||
return dummyObject;
|
return _object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWidget::mousePressEvent(QMouseEvent* e) {
|
void ViewerWidget::mousePressEvent(QMouseEvent* e) {
|
||||||
@ -297,3 +309,42 @@ void ViewerWidget::mouseMoveEvent(QMouseEvent* e) {
|
|||||||
void ViewerWidget::wheelEvent(QWheelEvent* e) {
|
void ViewerWidget::wheelEvent(QWheelEvent* e) {
|
||||||
viewDistance = qMax(viewDistance - e->angleDelta().y() / 240.f, 0.5f);
|
viewDistance = qMax(viewDistance - e->angleDelta().y() / 240.f, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewerWidget::gameLoaded(GameWorld *world, GameRenderer *renderer) {
|
||||||
|
_world = world;
|
||||||
|
_renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWidget::renderNow() {
|
||||||
|
if (!isExposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->makeCurrent(this);
|
||||||
|
|
||||||
|
if (!initialised) {
|
||||||
|
initGL();
|
||||||
|
initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
paintGL();
|
||||||
|
context->swapBuffers(this);
|
||||||
|
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewerWidget::event(QEvent *e) {
|
||||||
|
switch(e->type()) {
|
||||||
|
case QEvent::UpdateRequest:
|
||||||
|
renderNow();
|
||||||
|
return true;
|
||||||
|
default: return QWindow::event(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWidget::exposeEvent(QExposeEvent *) {
|
||||||
|
if (isExposed()) {
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#ifndef _RWVIEWER_VIEWERWIDGET_HPP_
|
||||||
#ifndef _VIEWERWIDGET_HPP_
|
#define _RWVIEWER_VIEWERWIDGET_HPP_
|
||||||
#define _VIEWERWIDGET_HPP_
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <data/Clump.hpp>
|
#include <data/Clump.hpp>
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
@ -13,27 +12,77 @@
|
|||||||
// Prevent Qt from conflicting with glLoadGen
|
// Prevent Qt from conflicting with glLoadGen
|
||||||
#define GL_ARB_debug_output
|
#define GL_ARB_debug_output
|
||||||
#define GL_KHR_debug
|
#define GL_KHR_debug
|
||||||
#include <QGLWidget>
|
#include <QOpenGLWindow>
|
||||||
|
|
||||||
class GameRenderer;
|
class GameRenderer;
|
||||||
class Clump;
|
class Clump;
|
||||||
class ViewerWidget : public QGLWidget {
|
class ViewerWidget : public QWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum class Mode {
|
||||||
|
//! View an Object, \see showObject
|
||||||
|
Object,
|
||||||
|
//! View a DFF model, \see showModel
|
||||||
|
Model,
|
||||||
|
//! View loaded instances, \see showWorld();
|
||||||
|
World,
|
||||||
|
};
|
||||||
|
|
||||||
GameRenderer* renderer;
|
ViewerWidget(QOpenGLContext* context, QWindow* parent);
|
||||||
|
|
||||||
QString currentFile;
|
void initGL();
|
||||||
|
void paintGL();
|
||||||
|
|
||||||
QTimer timer;
|
void renderNow();
|
||||||
GameWorld* gworld;
|
bool event(QEvent*) override;
|
||||||
|
|
||||||
ClumpPtr activeModel;
|
void exposeEvent(QExposeEvent*) override;
|
||||||
ModelFrame* selectedFrame;
|
|
||||||
GameObject* dummyObject;
|
ClumpPtr currentModel() const;
|
||||||
quint16 currentObjectID;
|
GameObject* currentObject() const;
|
||||||
|
|
||||||
|
GameWorld* world();
|
||||||
|
|
||||||
|
void setMode(Mode m) {
|
||||||
|
_viewMode = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mode currentMode() const {
|
||||||
|
return _viewMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void showObject(quint16 item);
|
||||||
|
void showModel(ClumpPtr model);
|
||||||
|
void selectFrame(ModelFrame* frame);
|
||||||
|
void exportModel();
|
||||||
|
|
||||||
|
void gameLoaded(GameWorld* world, GameRenderer* renderer);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void fileOpened(const QString& file);
|
||||||
|
|
||||||
|
void modelChanged(ClumpPtr model);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent*) override;
|
||||||
|
void keyReleaseEvent(QKeyEvent*) override;
|
||||||
|
void mousePressEvent(QMouseEvent*) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent*) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent*) override;
|
||||||
|
void wheelEvent(QWheelEvent*) override;
|
||||||
|
|
||||||
|
Mode _viewMode = Mode::World;
|
||||||
|
|
||||||
|
QOpenGLContext* context;
|
||||||
|
GameWorld* _world = nullptr;
|
||||||
|
GameRenderer* _renderer = nullptr;
|
||||||
|
|
||||||
|
ClumpPtr _model;
|
||||||
|
ModelFrame* selectedFrame = nullptr;
|
||||||
|
GameObject* _object = nullptr;
|
||||||
|
quint16 _objectID = 0;
|
||||||
|
|
||||||
ClumpPtr _lastModel;
|
|
||||||
Animation* canimation;
|
|
||||||
|
|
||||||
float viewDistance;
|
float viewDistance;
|
||||||
glm::vec2 viewAngles;
|
glm::vec2 viewAngles;
|
||||||
@ -49,47 +98,12 @@ class ViewerWidget : public QGLWidget {
|
|||||||
GLuint whiteTex;
|
GLuint whiteTex;
|
||||||
|
|
||||||
void drawFrameWidget(ModelFrame* f, const glm::mat4& = glm::mat4(1.f));
|
void drawFrameWidget(ModelFrame* f, const glm::mat4& = glm::mat4(1.f));
|
||||||
|
bool initialised = false;
|
||||||
|
|
||||||
public:
|
void drawModel(GameRenderer& r, ClumpPtr& model);
|
||||||
ViewerWidget(QGLFormat g, QWidget* parent = 0,
|
void drawObject(GameRenderer& r, GameObject* object);
|
||||||
const QGLWidget* shareWidget = 0, Qt::WindowFlags f = 0);
|
void drawWorld(GameRenderer& r);
|
||||||
|
|
||||||
virtual void initializeGL();
|
|
||||||
|
|
||||||
virtual void resizeGL(int w, int h);
|
|
||||||
|
|
||||||
virtual void paintGL();
|
|
||||||
|
|
||||||
ClumpPtr currentModel() const;
|
|
||||||
GameObject* currentObject() const;
|
|
||||||
|
|
||||||
GameWorld* world();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
void showObject(qint16 item);
|
|
||||||
void showModel(ClumpPtr model);
|
|
||||||
void selectFrame(ModelFrame* frame);
|
|
||||||
|
|
||||||
void exportModel();
|
|
||||||
|
|
||||||
void dataLoaded(GameWorld* world);
|
|
||||||
|
|
||||||
void setRenderer(GameRenderer* renderer);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
void fileOpened(const QString& file);
|
|
||||||
|
|
||||||
void modelChanged(ClumpPtr model);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent*) override;
|
|
||||||
void keyReleaseEvent(QKeyEvent*) override;
|
|
||||||
void mousePressEvent(QMouseEvent*) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent*) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent*) override;
|
|
||||||
void wheelEvent(QWheelEvent*) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,14 +9,12 @@
|
|||||||
#include <render/GameRenderer.hpp>
|
#include <render/GameRenderer.hpp>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDebug>
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <QOffscreenSurface>
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSignalMapper>
|
#include <QWindow>
|
||||||
#include <fstream>
|
#include <QMessageBox>
|
||||||
|
|
||||||
static int MaxRecentGames = 5;
|
static int MaxRecentGames = 5;
|
||||||
|
|
||||||
@ -25,8 +23,16 @@ ViewerWindow::ViewerWindow(QWidget* parent, Qt::WindowFlags flags)
|
|||||||
, gameData(nullptr)
|
, gameData(nullptr)
|
||||||
, gameWorld(nullptr)
|
, gameWorld(nullptr)
|
||||||
, renderer(nullptr) {
|
, renderer(nullptr) {
|
||||||
|
show();
|
||||||
setMinimumSize(640, 480);
|
setMinimumSize(640, 480);
|
||||||
|
createMenus();
|
||||||
|
if (!setupEngine()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createDefaultViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWindow::createMenus() {
|
||||||
QMenuBar* mb = this->menuBar();
|
QMenuBar* mb = this->menuBar();
|
||||||
QMenu* file = mb->addMenu("&File");
|
QMenu* file = mb->addMenu("&File");
|
||||||
|
|
||||||
@ -45,84 +51,52 @@ ViewerWindow::ViewerWindow(QWidget* parent, Qt::WindowFlags flags)
|
|||||||
connect(ex, SIGNAL(triggered()), QApplication::instance(),
|
connect(ex, SIGNAL(triggered()), QApplication::instance(),
|
||||||
SLOT(closeAllWindows()));
|
SLOT(closeAllWindows()));
|
||||||
|
|
||||||
//----------------------- View Mode setup
|
|
||||||
|
|
||||||
QGLFormat glFormat;
|
|
||||||
glFormat.setVersion(3, 3);
|
|
||||||
glFormat.setProfile(QGLFormat::CoreProfile);
|
|
||||||
|
|
||||||
viewerWidget = new ViewerWidget(glFormat);
|
|
||||||
viewerWidget->context()->makeCurrent();
|
|
||||||
connect(this, SIGNAL(loadedData(GameWorld*)), viewerWidget,
|
|
||||||
SLOT(dataLoaded(GameWorld*)));
|
|
||||||
|
|
||||||
//------------- Object Viewer
|
|
||||||
m_views[ViewMode::Object] = new ObjectViewer(viewerWidget);
|
|
||||||
m_viewNames[ViewMode::Object] = "Objects";
|
|
||||||
|
|
||||||
//------------- Model Viewer
|
|
||||||
m_views[ViewMode::Model] = new ModelViewer(viewerWidget);
|
|
||||||
m_viewNames[ViewMode::Model] = "Model";
|
|
||||||
|
|
||||||
//------------- World Viewer
|
|
||||||
m_views[ViewMode::World] = new WorldViewer(viewerWidget);
|
|
||||||
m_viewNames[ViewMode::World] = "World";
|
|
||||||
|
|
||||||
//------------- display mode switching
|
|
||||||
viewSwitcher = new QStackedWidget;
|
|
||||||
auto signalMapper = new QSignalMapper(this);
|
|
||||||
auto switchPanel = new QVBoxLayout();
|
|
||||||
int i = 0;
|
|
||||||
for (auto viewer : m_views) {
|
|
||||||
viewSwitcher->addWidget(viewer);
|
|
||||||
connect(this, SIGNAL(loadedData(GameWorld*)), viewer,
|
|
||||||
SLOT(showData(GameWorld*)));
|
|
||||||
|
|
||||||
auto viewerButton = new QPushButton(m_viewNames[i].c_str());
|
|
||||||
signalMapper->setMapping(m_views[i], i);
|
|
||||||
signalMapper->setMapping(viewerButton, i);
|
|
||||||
connect(viewerButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
|
|
||||||
switchPanel->addWidget(viewerButton);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
// Map world viewer loading placements to switch to the world viewer
|
|
||||||
connect(m_views[ViewMode::World], SIGNAL(placementsLoaded(QString)),
|
|
||||||
signalMapper, SLOT(map()));
|
|
||||||
|
|
||||||
switchView(ViewMode::Object);
|
|
||||||
|
|
||||||
connect(m_views[ViewMode::Object], SIGNAL(showObjectModel(uint16_t)), this,
|
|
||||||
SLOT(showObjectModel(uint16_t)));
|
|
||||||
connect(m_views[ViewMode::Object], SIGNAL(showObjectModel(uint16_t)),
|
|
||||||
m_views[ViewMode::Model], SLOT(showObject(uint16_t)));
|
|
||||||
connect(this, SIGNAL(loadAnimations(QString)), m_views[ViewMode::Model],
|
|
||||||
SLOT(loadAnimations(QString)));
|
|
||||||
|
|
||||||
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(switchView(int)));
|
|
||||||
connect(signalMapper, SIGNAL(mapped(int)), viewSwitcher,
|
|
||||||
SLOT(setCurrentIndex(int)));
|
|
||||||
|
|
||||||
switchPanel->addStretch();
|
|
||||||
auto mainlayout = new QHBoxLayout();
|
|
||||||
mainlayout->addLayout(switchPanel);
|
|
||||||
mainlayout->addWidget(viewSwitcher);
|
|
||||||
auto mainwidget = new QWidget();
|
|
||||||
mainwidget->setLayout(mainlayout);
|
|
||||||
|
|
||||||
mb->addMenu("&Data");
|
mb->addMenu("&Data");
|
||||||
|
|
||||||
QMenu* anim = mb->addMenu("&Animation");
|
|
||||||
anim->addAction("Load &Animations", this, SLOT(openAnimations()));
|
|
||||||
|
|
||||||
QMenu* map = mb->addMenu("&Map");
|
|
||||||
map->addAction("Load IPL", m_views[ViewMode::World],
|
|
||||||
SLOT(loadPlacements()));
|
|
||||||
|
|
||||||
this->setCentralWidget(mainwidget);
|
|
||||||
|
|
||||||
updateRecentGames();
|
updateRecentGames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViewerWindow::setupEngine() {
|
||||||
|
QSurfaceFormat format = windowHandle()->format();
|
||||||
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
format.setVersion(3,3);
|
||||||
|
context_ = new QOpenGLContext(this);
|
||||||
|
context_->setShareContext(QOpenGLContext::globalShareContext());
|
||||||
|
context_->setFormat(format);
|
||||||
|
|
||||||
|
hiddenSurface = new QOffscreenSurface(windowHandle()->screen());
|
||||||
|
hiddenSurface->setFormat(format);
|
||||||
|
hiddenSurface->create();
|
||||||
|
|
||||||
|
if (!context_->create()) {
|
||||||
|
QMessageBox::critical(this, "OpenGL Failure",
|
||||||
|
"Failed to create OpenGL context");
|
||||||
|
QApplication::exit(1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerWindow::createDefaultViews() {
|
||||||
|
views = new QTabWidget(this);
|
||||||
|
|
||||||
|
auto objectView = new ObjectViewer(this);
|
||||||
|
views->addTab(objectView, "Objects");
|
||||||
|
connect(this, &ViewerWindow::gameLoaded, objectView, &ObjectViewer::showData);
|
||||||
|
|
||||||
|
auto modelView = new ModelViewer(this);
|
||||||
|
views->addTab(modelView, "Model");
|
||||||
|
connect(this, &ViewerWindow::gameLoaded, modelView, &ModelViewer::showData);
|
||||||
|
connect(objectView, &ObjectViewer::showObjectModel, modelView, &ModelViewer::showObject);
|
||||||
|
|
||||||
|
auto worldView = new WorldViewer(this);
|
||||||
|
views->addTab(worldView, "World");
|
||||||
|
connect(this, &ViewerWindow::gameLoaded, worldView, &WorldViewer::showData);
|
||||||
|
|
||||||
|
setCentralWidget(views);
|
||||||
|
}
|
||||||
|
|
||||||
void ViewerWindow::showEvent(QShowEvent*) {
|
void ViewerWindow::showEvent(QShowEvent*) {
|
||||||
static bool first = true;
|
static bool first = true;
|
||||||
if (first) {
|
if (first) {
|
||||||
@ -140,14 +114,6 @@ void ViewerWindow::closeEvent(QCloseEvent* event) {
|
|||||||
QMainWindow::closeEvent(event);
|
QMainWindow::closeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWindow::openAnimations() {
|
|
||||||
QFileDialog dialog(this, "Open Animations", QDir::homePath(),
|
|
||||||
"IFP Animations (*.ifp)");
|
|
||||||
if (dialog.exec()) {
|
|
||||||
loadAnimations(dialog.selectedFiles()[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewerWindow::loadGame() {
|
void ViewerWindow::loadGame() {
|
||||||
QString dir = QFileDialog::getExistingDirectory(
|
QString dir = QFileDialog::getExistingDirectory(
|
||||||
this, tr("Open Directory"), QDir::homePath(),
|
this, tr("Open Directory"), QDir::homePath(),
|
||||||
@ -158,19 +124,26 @@ void ViewerWindow::loadGame() {
|
|||||||
|
|
||||||
void ViewerWindow::loadGame(const QString& path) {
|
void ViewerWindow::loadGame(const QString& path) {
|
||||||
QDir gameDir(path);
|
QDir gameDir(path);
|
||||||
|
if (path.isEmpty()) {
|
||||||
if (gameDir.exists() && path.size() > 0) {
|
return;
|
||||||
gameData =
|
|
||||||
new GameData(&engineLog, gameDir.absolutePath().toStdString());
|
|
||||||
gameWorld = new GameWorld(&engineLog, gameData);
|
|
||||||
renderer = new GameRenderer(&engineLog, gameData);
|
|
||||||
gameWorld->state = new GameState;
|
|
||||||
viewerWidget->setRenderer(renderer);
|
|
||||||
|
|
||||||
gameWorld->data->load();
|
|
||||||
|
|
||||||
loadedData(gameWorld);
|
|
||||||
}
|
}
|
||||||
|
if (!gameDir.exists()) {
|
||||||
|
QMessageBox::critical(this, "Error", "The requested path doesn't exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!makeCurrent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gameData = std::make_unique<GameData>(&engineLog, gameDir.absolutePath().toStdString());
|
||||||
|
gameWorld = std::make_unique<GameWorld>(&engineLog, gameData.get());
|
||||||
|
renderer = std::make_unique<GameRenderer>(&engineLog, gameData.get());
|
||||||
|
gameWorld->state = new GameState;
|
||||||
|
|
||||||
|
gameWorld->data->load();
|
||||||
|
|
||||||
|
gameLoaded(gameWorld.get(), renderer.get());
|
||||||
|
|
||||||
QSettings settings("OpenRW", "rwviewer");
|
QSettings settings("OpenRW", "rwviewer");
|
||||||
QStringList recent = settings.value("recentGames").toStringList();
|
QStringList recent = settings.value("recentGames").toStringList();
|
||||||
@ -189,19 +162,8 @@ void ViewerWindow::openRecent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWindow::switchView(int mode) {
|
|
||||||
if (mode < int(m_views.size())) {
|
|
||||||
m_views[mode]->setViewerWidget(viewerWidget);
|
|
||||||
} else {
|
|
||||||
RW_ERROR("Unhandled view mode" << mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewerWindow::showObjectModel(uint16_t) {
|
void ViewerWindow::showObjectModel(uint16_t) {
|
||||||
// Switch to the model viewer
|
#warning implement me
|
||||||
switchView(ViewMode::Model);
|
|
||||||
viewSwitcher->setCurrentIndex(
|
|
||||||
viewSwitcher->indexOf(m_views[ViewMode::Model]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewerWindow::updateRecentGames() {
|
void ViewerWindow::updateRecentGames() {
|
||||||
@ -221,3 +183,22 @@ void ViewerWindow::updateRecentGames() {
|
|||||||
|
|
||||||
recentSep->setVisible(recent.size() > 0);
|
recentSep->setVisible(recent.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewerWindow::~ViewerWindow() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewerWindow::makeCurrent() {
|
||||||
|
if (!context_->makeCurrent(hiddenSurface)) {
|
||||||
|
QMessageBox::critical(this, "OpenGL", "makeCurrent failed");
|
||||||
|
QApplication::exit(1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewerWidget *ViewerWindow::createViewer() {
|
||||||
|
auto view = new ViewerWidget(context_, windowHandle());
|
||||||
|
connect(this, &ViewerWindow::gameLoaded, view, &ViewerWidget::gameLoaded);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _VIEWERWINDOW_HPP_
|
#ifndef _VIEWERWINDOW_HPP_
|
||||||
#define _VIEWERWINDOW_HPP_
|
#define _VIEWERWINDOW_HPP_
|
||||||
#include <core/Logger.hpp>
|
#include <core/Logger.hpp>
|
||||||
@ -6,76 +5,60 @@
|
|||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QStackedWidget>
|
#include <QTabWidget>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include <QOffscreenSurface>
|
||||||
|
|
||||||
#include <array>
|
#include <memory>
|
||||||
|
|
||||||
class ViewerWidget;
|
class ViewerWidget;
|
||||||
class ViewerInterface;
|
class ViewerInterface;
|
||||||
class GameRenderer;
|
class GameRenderer;
|
||||||
class QGLContext;
|
|
||||||
|
|
||||||
class ViewerWindow : public QMainWindow {
|
class ViewerWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
QOpenGLContext* context_;
|
||||||
enum ViewMode { Object = 0, Model = 1, World = 2, _Count };
|
QOffscreenSurface* hiddenSurface;
|
||||||
|
QTabWidget* views;
|
||||||
|
|
||||||
Logger engineLog;
|
Logger engineLog;
|
||||||
|
|
||||||
GameData* gameData;
|
std::unique_ptr<GameData> gameData;
|
||||||
GameWorld* gameWorld;
|
std::unique_ptr<GameWorld> gameWorld;
|
||||||
GameRenderer* renderer;
|
std::unique_ptr<GameRenderer> renderer;
|
||||||
GameState* state;
|
|
||||||
|
|
||||||
/** Contains the OGL context */
|
|
||||||
ViewerWidget* viewerWidget;
|
|
||||||
|
|
||||||
std::array<ViewerInterface*, ViewMode::_Count> m_views;
|
|
||||||
std::array<std::string, ViewMode::_Count> m_viewNames;
|
|
||||||
|
|
||||||
QStackedWidget* viewSwitcher;
|
|
||||||
|
|
||||||
QGLContext* context;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ViewerWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
ViewerWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
||||||
|
~ViewerWindow();
|
||||||
/**
|
|
||||||
* @brief openGame Loads a game's dat file.
|
|
||||||
* @param datFile
|
|
||||||
*/
|
|
||||||
void openGame(const QString& datFile);
|
|
||||||
|
|
||||||
virtual void showEvent(QShowEvent*);
|
virtual void showEvent(QShowEvent*);
|
||||||
|
|
||||||
virtual void closeEvent(QCloseEvent*);
|
virtual void closeEvent(QCloseEvent*);
|
||||||
|
|
||||||
|
ViewerWidget* createViewer();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void openAnimations();
|
|
||||||
|
|
||||||
void loadGame();
|
void loadGame();
|
||||||
|
|
||||||
void loadGame(const QString& path);
|
void loadGame(const QString& path);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void gameLoaded(GameWorld*, GameRenderer*);
|
||||||
void loadedData(GameWorld* world);
|
|
||||||
void loadAnimations(const QString& file);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void openRecent();
|
void openRecent();
|
||||||
|
|
||||||
void switchView(int mode);
|
|
||||||
|
|
||||||
void showObjectModel(uint16_t object);
|
void showObjectModel(uint16_t object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QAction*> recentGames;
|
QList<QAction*> recentGames;
|
||||||
QAction* recentSep;
|
QAction* recentSep;
|
||||||
void updateRecentGames();
|
void updateRecentGames();
|
||||||
|
|
||||||
|
void createMenus();
|
||||||
|
bool setupEngine();
|
||||||
|
void createDefaultViews();
|
||||||
|
|
||||||
|
bool makeCurrent();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QStyleFactory>
|
|
||||||
#include "ViewerWindow.hpp"
|
#include "ViewerWindow.hpp"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
ViewerWindow viewer;
|
ViewerWindow viewer;
|
||||||
viewer.show();
|
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
@ -6,37 +6,22 @@
|
|||||||
#include <widgets/ModelFramesWidget.hpp>
|
#include <widgets/ModelFramesWidget.hpp>
|
||||||
#include "ViewerWidget.hpp"
|
#include "ViewerWidget.hpp"
|
||||||
|
|
||||||
ModelViewer::ModelViewer(ViewerWidget* viewer, QWidget* parent,
|
ModelViewer::ModelViewer(QWidget* parent, Qt::WindowFlags f)
|
||||||
Qt::WindowFlags f)
|
|
||||||
: ViewerInterface(parent, f), viewing(nullptr) {
|
: ViewerInterface(parent, f), viewing(nullptr) {
|
||||||
mainSplit = new QSplitter;
|
mainSplit = new QSplitter;
|
||||||
mainLayout = new QVBoxLayout;
|
mainLayout = new QVBoxLayout;
|
||||||
|
|
||||||
viewerWidget = viewer;
|
|
||||||
viewerWidget->setMinimumSize(250, 250);
|
|
||||||
|
|
||||||
animationWidget = new AnimationListWidget;
|
|
||||||
connect(animationWidget, SIGNAL(selectedAnimationChanged(Animation*)),
|
|
||||||
SLOT(playAnimation(Animation*)));
|
|
||||||
|
|
||||||
frames = new ModelFramesWidget;
|
frames = new ModelFramesWidget;
|
||||||
frames->setMaximumWidth(300);
|
frames->setMaximumWidth(300);
|
||||||
|
|
||||||
|
viewerWidget = createViewer();
|
||||||
|
viewerWidget->setMode(ViewerWidget::Mode::Model);
|
||||||
|
|
||||||
mainSplit->addWidget(frames);
|
mainSplit->addWidget(frames);
|
||||||
mainSplit->addWidget(animationWidget);
|
mainSplit->addWidget(QWidget::createWindowContainer(viewerWidget));
|
||||||
mainLayout->addWidget(mainSplit);
|
mainLayout->addWidget(mainSplit);
|
||||||
|
|
||||||
this->setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
connect(frames, SIGNAL(selectedFrameChanged(ModelFrame*)), viewerWidget,
|
|
||||||
SLOT(selectFrame(ModelFrame*)));
|
|
||||||
setViewerWidget(viewerWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelViewer::setViewerWidget(ViewerWidget* widget) {
|
|
||||||
viewerWidget = widget;
|
|
||||||
mainSplit->addWidget(viewerWidget);
|
|
||||||
showModel(viewing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelViewer::showModel(ClumpPtr model) {
|
void ModelViewer::showModel(ClumpPtr model) {
|
||||||
@ -46,35 +31,27 @@ void ModelViewer::showModel(ClumpPtr model) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModelViewer::showObject(uint16_t object) {
|
void ModelViewer::showObject(uint16_t object) {
|
||||||
viewerWidget->showObject(object);
|
auto def = world()->data->modelinfo[object].get();
|
||||||
viewing = viewerWidget->currentModel();
|
if (!def) {
|
||||||
frames->setModel(viewing);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
void ModelViewer::loadAnimations(const QString& file) {
|
|
||||||
std::ifstream dfile(file.toStdString().c_str(), std::ios_base::binary);
|
|
||||||
AnimationList anims;
|
|
||||||
|
|
||||||
if (dfile.is_open()) {
|
|
||||||
dfile.seekg(0, std::ios_base::end);
|
|
||||||
size_t length = dfile.tellg();
|
|
||||||
dfile.seekg(0);
|
|
||||||
char* file = new char[length];
|
|
||||||
dfile.read(file, length);
|
|
||||||
|
|
||||||
LoaderIFP loader;
|
|
||||||
if (loader.loadFromMemory(file)) {
|
|
||||||
for (auto& f : loader.animations) {
|
|
||||||
anims.push_back(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
animationWidget->setAnimations(anims);
|
auto modelName = def->name + ".dff";
|
||||||
|
auto textureName = def->name + ".txd";
|
||||||
|
auto textures = world()->data->loadTextureArchive(textureName);
|
||||||
|
|
||||||
|
LoaderDFF dffLoader;
|
||||||
|
dffLoader.setTextureLookupCallback(
|
||||||
|
[&](const std::string& texture, const std::string&) {
|
||||||
|
return textures.at(texture);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto file = world()->data->index.openFile(modelName);
|
||||||
|
if (!file) {
|
||||||
|
RW_ERROR("Couldn't load " << modelName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showModel(dffLoader.loadFromMemory(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelViewer::playAnimation(AnimationPtr anim) {
|
|
||||||
viewerWidget->currentObject()->animator->playAnimation(0, anim, 1.f, true);
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#define _MODELVIEWER_HPP_
|
#define _MODELVIEWER_HPP_
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include "AnimationListWidget.hpp"
|
|
||||||
|
|
||||||
#include "ViewerInterface.hpp"
|
#include "ViewerInterface.hpp"
|
||||||
|
|
||||||
@ -16,7 +15,6 @@
|
|||||||
class ViewerWidget;
|
class ViewerWidget;
|
||||||
class Clump;
|
class Clump;
|
||||||
class ModelFramesWidget;
|
class ModelFramesWidget;
|
||||||
class Animation;
|
|
||||||
|
|
||||||
class ModelViewer : public ViewerInterface {
|
class ModelViewer : public ViewerInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -29,14 +27,8 @@ class ModelViewer : public ViewerInterface {
|
|||||||
|
|
||||||
ModelFramesWidget* frames;
|
ModelFramesWidget* frames;
|
||||||
|
|
||||||
AnimationList loadedAnimations;
|
|
||||||
AnimationListWidget* animationWidget;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModelViewer(ViewerWidget* viewer = 0, QWidget* parent = 0,
|
ModelViewer(QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
Qt::WindowFlags f = 0);
|
|
||||||
|
|
||||||
void setViewerWidget(ViewerWidget* widget) override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
@ -49,9 +41,6 @@ public slots:
|
|||||||
* Display a game object's model
|
* Display a game object's model
|
||||||
*/
|
*/
|
||||||
void showObject(uint16_t object);
|
void showObject(uint16_t object);
|
||||||
|
|
||||||
void loadAnimations(const QString& file);
|
|
||||||
void playAnimation(AnimationPtr anim);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,16 +1,112 @@
|
|||||||
#include "ObjectViewer.hpp"
|
#include "ObjectViewer.hpp"
|
||||||
#include <QDebug>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <models/ObjectListModel.hpp>
|
#include <models/ObjectListModel.hpp>
|
||||||
#include "ViewerWidget.hpp"
|
#include <ViewerWindow.hpp>
|
||||||
|
|
||||||
ObjectViewer::ObjectViewer(ViewerWidget* viewer, QWidget* parent,
|
#include <QCheckBox>
|
||||||
Qt::WindowFlags f)
|
#include <QLineEdit>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectSearchModel : public QSortFilterProxyModel {
|
||||||
|
public:
|
||||||
|
ObjectSearchModel(QObject* parent)
|
||||||
|
: QSortFilterProxyModel(parent) { }
|
||||||
|
|
||||||
|
void showCARS(bool cars) {
|
||||||
|
_showCars = cars;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showOBJS(bool objs) {
|
||||||
|
_showMisc = objs;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showPEDS(bool peds) {
|
||||||
|
_showPeds = peds;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterName(const QString& name) {
|
||||||
|
_name = name.toStdString();
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filterAcceptsRow(int sourceRow,
|
||||||
|
const QModelIndex &sourceParent) const override
|
||||||
|
{
|
||||||
|
auto index0 = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||||
|
const auto& model = _data->modelinfo.at(index0.internalId());
|
||||||
|
|
||||||
|
switch (model->type()) {
|
||||||
|
case ModelDataType::VehicleInfo:
|
||||||
|
if (!_showCars)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case ModelDataType::PedInfo:
|
||||||
|
if (!_showPeds)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!_showMisc)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(!_name.empty() && model->name.find(_name) == std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setModel(ObjectListModel* model) {
|
||||||
|
_data = model->gameData();
|
||||||
|
QSortFilterProxyModel::setSourceModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameData* _data = nullptr;
|
||||||
|
private:
|
||||||
|
bool _showPeds = true;
|
||||||
|
bool _showMisc = true;
|
||||||
|
bool _showCars = true;
|
||||||
|
|
||||||
|
std::string _name;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
QLayout* searchControls(ObjectSearchModel* search) {
|
||||||
|
auto bar = new QHBoxLayout;
|
||||||
|
|
||||||
|
auto searchBox = new QLineEdit;
|
||||||
|
searchBox->setPlaceholderText("Search");
|
||||||
|
QObject::connect(searchBox, &QLineEdit::textChanged, search, &ObjectSearchModel::filterName);
|
||||||
|
|
||||||
|
auto cars = new QCheckBox;
|
||||||
|
cars->setText("CARS");
|
||||||
|
cars->setChecked(true);
|
||||||
|
QObject::connect(cars, &QCheckBox::clicked, search, &ObjectSearchModel::showCARS );
|
||||||
|
auto peds = new QCheckBox;
|
||||||
|
peds->setText("PEDS");
|
||||||
|
peds->setChecked(true);
|
||||||
|
QObject::connect(peds, &QCheckBox::clicked, search, &ObjectSearchModel::showPEDS );
|
||||||
|
auto misc = new QCheckBox;
|
||||||
|
misc->setText("Misc");
|
||||||
|
misc->setChecked(true);
|
||||||
|
QObject::connect(misc, &QCheckBox::clicked, search, &ObjectSearchModel::showOBJS );
|
||||||
|
|
||||||
|
bar->addWidget(searchBox, 1);
|
||||||
|
bar->addWidget(cars);
|
||||||
|
bar->addWidget(peds);
|
||||||
|
bar->addWidget(misc);
|
||||||
|
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectViewer::ObjectViewer(QWidget* parent, Qt::WindowFlags f)
|
||||||
: ViewerInterface(parent, f) {
|
: ViewerInterface(parent, f) {
|
||||||
mainLayout = new QHBoxLayout;
|
mainLayout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
auto leftLayout = new QVBoxLayout;
|
||||||
|
|
||||||
objectList = new QTableView;
|
objectList = new QTableView;
|
||||||
|
|
||||||
objectMenu = new QMenu(objectList);
|
objectMenu = new QMenu(objectList);
|
||||||
objectList->setContextMenuPolicy(Qt::CustomContextMenu);
|
objectList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
auto viewModelAction = new QAction("View Model", objectMenu);
|
auto viewModelAction = new QAction("View Model", objectMenu);
|
||||||
@ -18,11 +114,22 @@ ObjectViewer::ObjectViewer(ViewerWidget* viewer, QWidget* parent,
|
|||||||
connect(viewModelAction, SIGNAL(triggered()), this, SLOT(menuViewModel()));
|
connect(viewModelAction, SIGNAL(triggered()), this, SLOT(menuViewModel()));
|
||||||
connect(objectList, SIGNAL(customContextMenuRequested(QPoint)), this,
|
connect(objectList, SIGNAL(customContextMenuRequested(QPoint)), this,
|
||||||
SLOT(onCustomContextMenu(QPoint)));
|
SLOT(onCustomContextMenu(QPoint)));
|
||||||
|
filterModel = new ObjectSearchModel(this);
|
||||||
|
objectList->setModel(filterModel);
|
||||||
|
objectList->setColumnWidth(0, 50);
|
||||||
|
objectList->setColumnWidth(1, 150);
|
||||||
|
objectList->setColumnWidth(2, 200);
|
||||||
|
objectList->setSortingEnabled(true);
|
||||||
|
connect(objectList->selectionModel(),
|
||||||
|
SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
|
||||||
|
SLOT(showItem(QModelIndex)));
|
||||||
|
|
||||||
mainLayout->addWidget(objectList);
|
leftLayout->addLayout(searchControls(filterModel));
|
||||||
|
leftLayout->addWidget(objectList);
|
||||||
|
mainLayout->addLayout(leftLayout, 6);
|
||||||
|
|
||||||
previewWidget = viewer;
|
previewWidget = createViewer();
|
||||||
previewWidget->setMinimumSize(250, 250);
|
previewWidget->setMode(ViewerWidget::Mode::Object);
|
||||||
|
|
||||||
infoLayout = new QGridLayout;
|
infoLayout = new QGridLayout;
|
||||||
|
|
||||||
@ -35,29 +142,23 @@ ObjectViewer::ObjectViewer(ViewerWidget* viewer, QWidget* parent,
|
|||||||
infoLayout->addWidget(previewClass, 2, 1);
|
infoLayout->addWidget(previewClass, 2, 1);
|
||||||
infoLayout->addWidget(new QLabel("Model"), 3, 0);
|
infoLayout->addWidget(new QLabel("Model"), 3, 0);
|
||||||
infoLayout->addWidget(previewModel, 3, 1);
|
infoLayout->addWidget(previewModel, 3, 1);
|
||||||
|
infoLayout->addWidget(QWidget::createWindowContainer(previewWidget), 0, 0, 1, 2);
|
||||||
|
infoLayout->setRowStretch(0, 1);
|
||||||
|
|
||||||
mainLayout->addLayout(infoLayout);
|
mainLayout->addLayout(infoLayout, 4);
|
||||||
|
setLayout(mainLayout);
|
||||||
this->setLayout(mainLayout);
|
|
||||||
|
|
||||||
setViewerWidget(previewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectViewer::setViewerWidget(ViewerWidget* widget) {
|
|
||||||
// widgetLayout->removeWidget(previewWidget);
|
|
||||||
previewWidget = widget;
|
|
||||||
infoLayout->addWidget(previewWidget, 0, 0, 1, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectViewer::worldChanged() {
|
void ObjectViewer::worldChanged() {
|
||||||
if (objectList->model()) {
|
if (filterModel->sourceModel()) {
|
||||||
delete objectList->model();
|
delete filterModel->sourceModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
objectList->setModel(new ObjectListModel(world()->data, objectList));
|
auto newModel = new ObjectListModel(world()->data, this);
|
||||||
connect(objectList->selectionModel(),
|
filterModel->setModel(newModel);
|
||||||
SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
|
objectList->sortByColumn(0, Qt::AscendingOrder);
|
||||||
SLOT(showItem(QModelIndex)));
|
|
||||||
|
objectList->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectViewer::showItem(qint16 item) {
|
void ObjectViewer::showItem(qint16 item) {
|
||||||
@ -73,7 +174,8 @@ void ObjectViewer::showItem(qint16 item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ObjectViewer::showItem(QModelIndex model) {
|
void ObjectViewer::showItem(QModelIndex model) {
|
||||||
showItem(model.internalId());
|
auto source = filterModel->mapToSource(model);
|
||||||
|
showItem(source.internalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectViewer::onCustomContextMenu(const QPoint& p) {
|
void ObjectViewer::onCustomContextMenu(const QPoint& p) {
|
||||||
@ -85,7 +187,7 @@ void ObjectViewer::onCustomContextMenu(const QPoint& p) {
|
|||||||
|
|
||||||
void ObjectViewer::menuViewModel() {
|
void ObjectViewer::menuViewModel() {
|
||||||
if (contextMenuIndex.isValid()) {
|
if (contextMenuIndex.isValid()) {
|
||||||
auto id = contextMenuIndex.internalId();
|
auto source = filterModel->mapToSource(contextMenuIndex);
|
||||||
showObjectModel(id);
|
showObjectModel(source.internalId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _OBJECTVIEWER_HPP_
|
#ifndef _OBJECTVIEWER_HPP_
|
||||||
#define _OBJECTVIEWER_HPP_
|
#define _OBJECTVIEWER_HPP_
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
@ -10,10 +9,13 @@
|
|||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
class ViewerWidget;
|
class ViewerWidget;
|
||||||
class Clump;
|
class Clump;
|
||||||
|
|
||||||
|
class ObjectSearchModel;
|
||||||
|
|
||||||
class ObjectViewer : public ViewerInterface {
|
class ObjectViewer : public ViewerInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -29,23 +31,18 @@ class ObjectViewer : public ViewerInterface {
|
|||||||
QMenu* objectMenu;
|
QMenu* objectMenu;
|
||||||
QModelIndex contextMenuIndex;
|
QModelIndex contextMenuIndex;
|
||||||
|
|
||||||
public:
|
ObjectSearchModel* filterModel;
|
||||||
ObjectViewer(ViewerWidget* viewer = 0, QWidget* parent = 0,
|
|
||||||
Qt::WindowFlags f = 0);
|
|
||||||
|
|
||||||
void setViewerWidget(ViewerWidget* widget);
|
public:
|
||||||
|
ObjectViewer(QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void worldChanged() override;
|
void worldChanged() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void modelChanged(Clump* model);
|
|
||||||
|
|
||||||
void showObjectModel(uint16_t object);
|
void showObjectModel(uint16_t object);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void showItem(qint16 item);
|
void showItem(qint16 item);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
7
rwviewer/views/ViewerInterface.cpp
Normal file
7
rwviewer/views/ViewerInterface.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "ViewerInterface.hpp"
|
||||||
|
|
||||||
|
#include "ViewerWindow.hpp"
|
||||||
|
|
||||||
|
ViewerWidget* ViewerInterface::createViewer() {
|
||||||
|
return static_cast<ViewerWindow*>(window())->createViewer();
|
||||||
|
}
|
@ -13,19 +13,22 @@ public:
|
|||||||
: QWidget(parent, f), m_world(nullptr) {
|
: QWidget(parent, f), m_world(nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setViewerWidget(ViewerWidget* widget) = 0;
|
|
||||||
|
|
||||||
GameWorld* world() {
|
GameWorld* world() {
|
||||||
return m_world;
|
return m_world;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void worldChanged() {
|
virtual void worldChanged() {}
|
||||||
}
|
|
||||||
|
ViewerWidget* createViewer();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void gameLoaded(GameWorld*, GameRenderer*);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void showData(GameWorld* world) {
|
void showData(GameWorld* world, GameRenderer* renderer) {
|
||||||
m_world = world;
|
m_world = world;
|
||||||
|
gameLoaded(world, renderer);
|
||||||
worldChanged();
|
worldChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,22 +3,13 @@
|
|||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
WorldViewer::WorldViewer(ViewerWidget* viewer, QWidget* parent,
|
WorldViewer::WorldViewer(QWidget* parent, Qt::WindowFlags f)
|
||||||
Qt::WindowFlags f)
|
|
||||||
: ViewerInterface(parent, f) {
|
: ViewerInterface(parent, f) {
|
||||||
mainLayout = new QVBoxLayout;
|
mainLayout = new QVBoxLayout;
|
||||||
|
|
||||||
viewerWidget = viewer;
|
mainLayout->addWidget(QWidget::createWindowContainer(createViewer()));
|
||||||
viewerWidget->setMinimumSize(250, 250);
|
|
||||||
|
|
||||||
this->setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
}
|
|
||||||
|
|
||||||
void WorldViewer::setViewerWidget(ViewerWidget* widget) {
|
|
||||||
viewerWidget = widget;
|
|
||||||
// Clear the active model
|
|
||||||
widget->showModel(nullptr);
|
|
||||||
mainLayout->addWidget(viewerWidget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldViewer::loadPlacements(const QString& file) {
|
void WorldViewer::loadPlacements(const QString& file) {
|
||||||
|
@ -18,10 +18,7 @@ class WorldViewer : public ViewerInterface {
|
|||||||
ViewerWidget* viewerWidget;
|
ViewerWidget* viewerWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WorldViewer(ViewerWidget* viewer = 0, QWidget* parent = 0,
|
WorldViewer(QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
Qt::WindowFlags f = 0);
|
|
||||||
|
|
||||||
void setViewerWidget(ViewerWidget* widget) override;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void placementsLoaded(const QString& file);
|
void placementsLoaded(const QString& file);
|
||||||
|
Loading…
Reference in New Issue
Block a user