1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 02:12:45 +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:
Daniel Evans 2018-01-16 01:05:23 +00:00
parent 6780be6fff
commit 6f9c3db52e
16 changed files with 549 additions and 455 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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,89 +68,94 @@ 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());
ViewCamera vc;
float viewFov = glm::radians(45.f);
vc.frustum.far = 500.f;
vc.frustum.near = 0.1f;
vc.frustum.fov = viewFov;
vc.frustum.aspectRatio = width() / (height() * 1.f);
ClumpPtr model = activeModel;
if (model != _lastModel) {
_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( 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});
model->getFrame()->updateHierarchyTransform();
r.getRenderer()->invalidate(); ObjectRenderer _renderer(world(), vc, 1.f, 0);
r.setupRender();
ObjectRenderer renderer(world(), vc, 1.f, 0);
RenderList renders; RenderList renders;
renderer.renderClump(model.get(), glm::mat4(), nullptr, renders); _renderer.renderClump(model.get(), glm::mat4(), nullptr, renders);
r.getRenderer()->drawBatched(renders); r.getRenderer()->drawBatched(renders);
drawFrameWidget(model->getFrame().get()); drawFrameWidget(model->getFrame().get());
r.renderPostProcess(); r.renderPostProcess();
} else if (world()->allObjects.size() > 0) { }
vc.frustum.fov = glm::radians(90.f);
void ViewerWidget::drawObject(GameRenderer &r, GameObject *object) {
glm::mat4 view, proj;
const auto& vc = OrbitCamera({width(), height()},
viewAngles,
viewDistance,
view, proj);
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});
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();
}
void ViewerWidget::drawWorld(GameRenderer& r) {
ViewCamera vc;
vc.frustum.fov = kViewFov;
vc.frustum.far = 1000.f; vc.frustum.far = 1000.f;
vc.frustum.near = 0.1f;
vc.position = viewPosition; vc.position = viewPosition;
vc.rotation = glm::angleAxis(glm::half_pi<float>() + viewAngles.x, vc.rotation = glm::angleAxis(glm::half_pi<float>() + viewAngles.x,
glm::vec3(0.f, 0.f, 1.f)) * glm::vec3(0.f, 0.f, 1.f)) *
glm::angleAxis(viewAngles.y, glm::vec3(0.f, 1.f, 0.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); r.renderWorld(world(), vc, 0.f);
} }
void ViewerWidget::paintGL() {
glViewport(0, 0, width(), height());
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (world() == nullptr) return;
RW_CHECK(_renderer != nullptr, "GameRenderer is null");
auto& r = *_renderer;
r.getRenderer()->invalidate();
r.setViewport(width(), height());
glEnable(GL_DEPTH_TEST);
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;
}
} }
void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m) { void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m) {
@ -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 (!world()->data->loadModel(item)) {
return;
}
if (def) {
switch (def->type()) { switch (def->type()) {
default: default:
dummyObject = gworld->createInstance(item, {}); _object = _world->createInstance(item, {});
break; break;
case ModelDataType::PedInfo: case ModelDataType::PedInfo:
dummyObject = gworld->createPedestrian(item, {}); _object = _world->createPedestrian(item, {});
break; break;
case ModelDataType::VehicleInfo: case ModelDataType::VehicleInfo:
dummyObject = gworld->createVehicle(item, {}); _object = _world->createVehicle(item, {});
break; break;
} }
RW_CHECK(dummyObject != nullptr, "Dummy Object is null"); RW_CHECK(_object != nullptr, "Dummy Object is null");
if (dummyObject != nullptr) {
activeModel = dummyObject->getModel(); 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();
}
}

View File

@ -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

View File

@ -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()) {
return;
}
if (!gameDir.exists()) {
QMessageBox::critical(this, "Error", "The requested path doesn't exist");
return;
}
if (gameDir.exists() && path.size() > 0) { if (!makeCurrent()) {
gameData = return;
new GameData(&engineLog, gameDir.absolutePath().toStdString()); }
gameWorld = new GameWorld(&engineLog, gameData);
renderer = new GameRenderer(&engineLog, gameData); 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->state = new GameState;
viewerWidget->setRenderer(renderer);
gameWorld->data->load(); gameWorld->data->load();
loadedData(gameWorld); 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;
}

View File

@ -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

View File

@ -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();
} }

View File

@ -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) { auto modelName = def->name + ".dff";
std::ifstream dfile(file.toStdString().c_str(), std::ios_base::binary); auto textureName = def->name + ".txd";
AnimationList anims; auto textures = world()->data->loadTextureArchive(textureName);
if (dfile.is_open()) { LoaderDFF dffLoader;
dfile.seekg(0, std::ios_base::end); dffLoader.setTextureLookupCallback(
size_t length = dfile.tellg(); [&](const std::string& texture, const std::string&) {
dfile.seekg(0); return textures.at(texture);
char* file = new char[length]; });
dfile.read(file, length);
LoaderIFP loader; auto file = world()->data->index.openFile(modelName);
if (loader.loadFromMemory(file)) { if (!file) {
for (auto& f : loader.animations) { RW_ERROR("Couldn't load " << modelName);
anims.push_back(f); return;
} }
showModel(dffLoader.loadFromMemory(file));
} }
delete[] file;
}
animationWidget->setAnimations(anims);
}
void ModelViewer::playAnimation(AnimationPtr anim) {
viewerWidget->currentObject()->animator->playAnimation(0, anim, 1.f, true);
}

View File

@ -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

View File

@ -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());
} }
} }

View File

@ -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:

View File

@ -0,0 +1,7 @@
#include "ViewerInterface.hpp"
#include "ViewerWindow.hpp"
ViewerWidget* ViewerInterface::createViewer() {
return static_cast<ViewerWindow*>(window())->createViewer();
}

View File

@ -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();
} }

View File

@ -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) {

View 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);