implement multi context rendering

This commit is contained in:
Skarn
2020-11-14 03:19:01 +03:00
parent b7026b3481
commit d9b5ba58f0
23 changed files with 957 additions and 77 deletions

View File

@@ -0,0 +1,13 @@
#ifndef NOGGIT_CONTEXTOBJECT_HPP
#define NOGGIT_CONTEXTOBJECT_HPP
namespace noggit
{
enum NoggitRenderContext
{
MAP_VIEW,
ASSET_BROWSER
};
}
#endif //NOGGIT_CONTEXTOBJECT_HPP

View File

@@ -16,9 +16,10 @@
#include <sstream>
#include <string>
Model::Model(const std::string& filename)
Model::Model(const std::string& filename, noggit::NoggitRenderContext context)
: AsyncObject(filename)
, _finished_upload(false)
, _context(context)
{
memset(&header, 0, sizeof(ModelHeader));
}
@@ -1610,7 +1611,7 @@ void Model::lightsOff(opengl::light lbase)
void Model::upload()
{
for (std::string texture : _textureFilenames)
_textures.emplace_back(texture);
_textures.emplace_back(texture, _context);
_buffers.upload();
_vertex_arrays.upload();

View File

@@ -14,6 +14,7 @@
#include <noggit/Particle.h>
#include <noggit/TextureManager.h>
#include <noggit/tool_enums.hpp>
#include <noggit/ContextObject.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.fwd.hpp>
@@ -211,7 +212,7 @@ public:
return std::vector<T>(start, start + count);
}
Model(const std::string& name);
Model(const std::string& name, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
void draw( math::matrix_4x4 const& model_view
, ModelInstance& instance
@@ -297,6 +298,8 @@ private:
int _anim_time;
int _global_animtime;
noggit::NoggitRenderContext _context;
void initCommon(const MPQFile& f);
bool isAnimated(const MPQFile& f);
void initAnimated(const MPQFile& f);

View File

@@ -7,17 +7,20 @@
#include <noggit/Model.h> // Model, etc.
#include <noggit/ModelInstance.h>
#include <noggit/WMOInstance.h>
#include <noggit/ContextObject.hpp>
#include <opengl/primitives.hpp>
#include <opengl/scoped.hpp>
#include <opengl/shader.hpp>
ModelInstance::ModelInstance(std::string const& filename)
: model (filename)
ModelInstance::ModelInstance(std::string const& filename, noggit::NoggitRenderContext context)
: model (filename, context)
, _context(context)
{
}
ModelInstance::ModelInstance(std::string const& filename, ENTRY_MDDF const*d)
: model (filename)
ModelInstance::ModelInstance(std::string const& filename, ENTRY_MDDF const*d, noggit::NoggitRenderContext context)
: model (filename, context)
, _context(context)
{
uid = d->uniqueID;
pos = math::vector_3d(d->pos[0], d->pos[1], d->pos[2]);
@@ -239,8 +242,9 @@ std::vector<math::vector_3d> const& ModelInstance::extents()
}
wmo_doodad_instance::wmo_doodad_instance(std::string const& filename, MPQFile* f)
: ModelInstance (filename)
wmo_doodad_instance::wmo_doodad_instance(std::string const& filename, MPQFile* f, noggit::NoggitRenderContext context)
: ModelInstance(filename, context)
, _context(context)
{
float ff[4];

View File

@@ -8,6 +8,7 @@
#include <noggit/MapHeaders.h> // ENTRY_MDDF
#include <noggit/ModelManager.h>
#include <noggit/Selection.h>
#include <noggit/ContextObject.hpp>
#include <noggit/tile_index.hpp>
#include <noggit/tool_enums.hpp>
#include <opengl/shader.fwd.hpp>
@@ -38,8 +39,12 @@ public:
// longest side of an AABB transformed model's bounding box from the M2 header
float size_cat;
explicit ModelInstance(std::string const& filename);
explicit ModelInstance(std::string const& filename, ENTRY_MDDF const*d);
explicit ModelInstance(std::string const& filename,
noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
explicit ModelInstance(std::string const& filename,
ENTRY_MDDF const*d,
noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
ModelInstance(ModelInstance const& other) = default;
ModelInstance& operator= (ModelInstance const& other) = default;
@@ -56,8 +61,10 @@ public:
, _extents(other._extents)
, _transform_mat_transposed(other._transform_mat_transposed)
, _transform_mat_inverted(other._transform_mat_inverted)
, _context(other._context)
{
}
ModelInstance& operator= (ModelInstance&& other)
{
std::swap (model, other.model);
@@ -71,6 +78,7 @@ public:
std::swap (_extents, other._extents);
std::swap(_transform_mat_transposed, other._transform_mat_transposed);
std::swap(_transform_mat_inverted, other._transform_mat_inverted);
std::swap(_context, other._context);
return *this;
}
@@ -102,6 +110,8 @@ public:
protected:
bool _need_recalc_extents = true;
noggit::NoggitRenderContext _context;
std::vector<math::vector_3d> _extents = std::vector<math::vector_3d>(2);
virtual void update_transform_matrix();
@@ -116,16 +126,19 @@ public:
math::quaternion doodad_orientation;
math::vector_3d world_pos;
explicit wmo_doodad_instance(std::string const& filename, MPQFile* f);
explicit wmo_doodad_instance(std::string const& filename
, MPQFile* f
, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
wmo_doodad_instance(wmo_doodad_instance const& other) = default;
wmo_doodad_instance& operator= (wmo_doodad_instance const& other) = default;
wmo_doodad_instance (wmo_doodad_instance&& other)
: ModelInstance (other)
, doodad_orientation (other.doodad_orientation)
, world_pos (other.world_pos)
wmo_doodad_instance(wmo_doodad_instance&& other)
: ModelInstance(other)
, doodad_orientation(other.doodad_orientation)
, world_pos(other.world_pos)
, _need_matrix_update(other._need_matrix_update)
, _context(other._context)
{
}
@@ -135,6 +148,7 @@ public:
std::swap (doodad_orientation, other.doodad_orientation);
std::swap (world_pos, other.world_pos);
std::swap (_need_matrix_update, other._need_matrix_update);
std::swap (_context, other._context);
return *this;
}
@@ -149,4 +163,5 @@ protected:
private:
bool _need_matrix_update = true;
noggit::NoggitRenderContext _context;
};

View File

@@ -4,6 +4,7 @@
#include <noggit/Model.h>
#include <noggit/multimap_with_normalized_key.hpp>
#include <noggit/ContextObject.hpp>
#include <map>
#include <string>
@@ -27,37 +28,46 @@ private:
struct scoped_model_reference
{
scoped_model_reference (std::string const& filename)
: _valid (true)
, _filename (filename)
, _model (ModelManager::_.emplace (_filename))
scoped_model_reference (
std::string const& filename
, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW)
: _valid(true)
, _filename(filename)
, _model(ModelManager::_.emplace (_filename, context))
, _context(context)
{}
scoped_model_reference (scoped_model_reference const& other)
: _valid (other._valid)
, _filename (other._filename)
, _model (ModelManager::_.emplace (_filename))
, _model (ModelManager::_.emplace(_filename, other._context))
, _context(other._context)
{}
scoped_model_reference& operator= (scoped_model_reference const& other)
{
_valid = other._valid;
_filename = other._filename;
_model = ModelManager::_.emplace (_filename);
_model = ModelManager::_.emplace (_filename, other._context);
_context = other._context;
return *this;
}
scoped_model_reference (scoped_model_reference&& other)
: _valid (other._valid)
, _filename (other._filename)
, _model (other._model)
: _valid(other._valid)
, _filename(other._filename)
, _model(other._model)
, _context(other._context)
{
other._valid = false;
}
scoped_model_reference& operator= (scoped_model_reference&& other)
{
std::swap (_valid, other._valid);
std::swap (_filename, other._filename);
std::swap (_model, other._model);
std::swap(_valid, other._valid);
std::swap(_filename, other._filename);
std::swap(_model, other._model);
std::swap(_context, other._context);
other._valid = false;
return *this;
}
@@ -66,7 +76,7 @@ struct scoped_model_reference
{
if (_valid)
{
ModelManager::_.erase (_filename);
ModelManager::_.erase(_filename, _context);
}
}
@@ -83,4 +93,5 @@ private:
bool _valid;
std::string _filename;
Model* _model;
noggit::NoggitRenderContext _context;
};

View File

@@ -0,0 +1,487 @@
#include "ModelView.hpp"
#include <opengl/scoped.hpp>
#include <math/projection.hpp>
#include <noggit/Selection.h>
#include <noggit/tool_enums.hpp>
#include <noggit/ContextObject.hpp>
#include <vector>
#include <cmath>
#include <stdexcept>
using namespace noggit::Red::AssetBrowser;
static const float XSENS = 15.0f;
static const float YSENS = 15.0f;
ModelViewer::ModelViewer(QWidget *parent)
: QOpenGLWidget(parent)
, _camera (math::vector_3d(0.0f, 0.0f, 0.0f), math::degrees(0.0f), math::degrees(0.0f))
, _settings (new QSettings (this))
{
setFocusPolicy(Qt::StrongFocus);
setMouseTracking (true);
_startup_time.start();
look = false;
moving = strafing = updown = lookat = turn = 0.0f;
mousedir = -1.0f;
_update_every_event_loop.start (0);
connect (&_update_every_event_loop, &QTimer::timeout, [this] { update(); });
}
void ModelViewer::setModel(std::string const &filename)
{
opengl::context::scoped_setter const _ (::gl, context());
makeCurrent();
// remove old instance
if (_model_instance.which() == eEntry_WMO)
{
delete boost::get<selected_wmo_type>(_model_instance);
}
else
{
delete boost::get<selected_model_type>(_model_instance);
}
// add new model instance
QString q_filename = QString(filename.c_str());
if (q_filename.endsWith(".wmo"))
{
auto instance = new WMOInstance(filename, noggit::NoggitRenderContext::ASSET_BROWSER);
_model_instance = instance;
instance->wmo->wait_until_loaded();
instance->recalcExtents();
}
else if (q_filename.endsWith(".m2"))
{
auto instance = new ModelInstance(filename, noggit::NoggitRenderContext::ASSET_BROWSER);
_model_instance = instance;
instance->model->wait_until_loaded();
instance->recalcExtents();
}
else
{
throw std::logic_error("Asset browser only supports viewing M2 and WMO for now.");
}
resetCamera();
}
void ModelViewer::resetCamera()
{
float radius = 0.f;
if (_model_instance.which() == eEntry_WMO)
{
WMOInstance* wmo = boost::get<selected_wmo_type>(_model_instance);
auto bb_center = (wmo->extents[0] + wmo->extents[1]) / 2;
radius = (bb_center - wmo->extents[0]).length();
}
else
{
ModelInstance* model = boost::get<selected_model_type>(_model_instance);
auto extents = model->extents();
auto bb_center = (extents[0] + extents[1]) / 2;
radius = (bb_center - extents[0]).length();
}
float distance_factor = abs( aspect_ratio() * radius / sin(_camera.fov()) / 2);
_camera.position = {0.f, 0.f, 0.f};
_camera.move_forward_factor(-1.f, distance_factor);
}
void ModelViewer::initializeGL()
{
opengl::context::scoped_setter const _ (::gl, context());
gl.viewport(0.0f, 0.0f, width(), height());
gl.clearColor (0.7f, 0.5f, 0.5f, 1.0f);
}
void ModelViewer::paintGL()
{
const qreal now(_startup_time.elapsed() / 1000.0);
opengl::context::scoped_setter const _ (::gl, context());
makeCurrent();
gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
tick(now - _last_update);
_last_update = now;
draw();
}
void ModelViewer::resizeGL(int w, int h)
{
opengl::context::scoped_setter const _ (::gl, context());
gl.viewport(0.0f, 0.0f, w, h);
}
void ModelViewer::tick(float dt)
{
if (turn)
{
_camera.add_to_yaw(math::degrees(turn));
}
if (lookat)
{
_camera.add_to_pitch(math::degrees(lookat));
}
if (moving)
{
_camera.move_forward(moving, dt);
}
if (strafing)
{
_camera.move_horizontal(strafing, dt);
}
if (updown)
{
_camera.move_vertical(updown, dt);
}
}
void ModelViewer::draw()
{
opengl::context::scoped_setter const _ (::gl, context());
makeCurrent();
float culldistance = 10000000;
bool draw_doodads_wmo = true;
math::matrix_4x4 const mvp(model_view().transposed() * projection().transposed());
math::frustum const frustum (mvp);
if (!_m2_program)
{
setModel("world/wmo/azeroth/buildings/human_farm/farm.wmo");
_m2_program.reset
( new opengl::program
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("m2_vs") }
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("m2_fs") }
}
);
}
if (!_m2_instanced_program)
{
_m2_instanced_program.reset
( new opengl::program
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("m2_vs", {"instanced"}) }
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("m2_fs") }
}
);
}
if (!_m2_ribbons_program)
{
_m2_ribbons_program.reset
( new opengl::program
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("ribbon_vs") }
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("ribbon_fs") }
}
);
}
if (!_m2_particles_program)
{
_m2_particles_program.reset
( new opengl::program
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("particle_vs") }
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("particle_fs") }
}
);
}
if (!_wmo_program)
{
_wmo_program.reset
( new opengl::program
{ { GL_VERTEX_SHADER, opengl::shader::src_from_qrc("wmo_vs") }
, { GL_FRAGMENT_SHADER, opengl::shader::src_from_qrc("wmo_fs") }
}
);
}
if (!_liquid_render)
{
_liquid_render.emplace();
}
gl.enable(GL_DEPTH_TEST);
gl.depthFunc(GL_LEQUAL);
gl.enable(GL_BLEND);
gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// draw WMOs
std::unordered_map<std::string, std::vector<ModelInstance*>> _wmo_doodads;
if (_model_instance.which() == eEntry_WMO)
{
// set anim time only once per frame
{
opengl::scoped::use_program water_shader {_liquid_render->shader_program()};
water_shader.uniform("animtime", 0 / 2880.f);
water_shader.uniform("model_view", model_view().transposed());
water_shader.uniform("projection", projection().transposed());
math::vector_4d ocean_color_light(math::vector_3d(1.0f, 1.0f, 1.0f), 1.f);
math::vector_4d ocean_color_dark(math::vector_3d(1.0f, 1.0f, 1.0f), 1.f);
math::vector_4d river_color_light(math::vector_3d(1.0f, 1.0f, 1.0f), 1.f);
math::vector_4d river_color_dark(math::vector_3d(1.0f, 1.0f, 1.0f), 1.f);
water_shader.uniform("ocean_color_light", ocean_color_light);
water_shader.uniform("ocean_color_dark", ocean_color_dark);
water_shader.uniform("river_color_light", river_color_light);
water_shader.uniform("river_color_dark", river_color_dark);
water_shader.uniform("use_transform", 1);
}
{
opengl::scoped::use_program wmo_program{*_wmo_program.get()};
wmo_program.uniform("model_view", model_view().transposed());
wmo_program.uniform("projection", projection().transposed());
wmo_program.uniform("tex1", 0);
wmo_program.uniform("tex2", 1);
wmo_program.uniform("draw_fog", 0);
wmo_program.uniform("exterior_light_dir", math::vector_3d(0.0f, 1.0f, 0.0f));
wmo_program.uniform("exterior_diffuse_color", math::vector_3d(1.0f, 1.0f, 1.0f));
wmo_program.uniform("exterior_ambient_color", math::vector_3d(1.0f, 1.0f, 1.0f));
auto wmo_instance = boost::get<selected_wmo_type>(_model_instance);
wmo_instance->draw(
wmo_program, model_view().transposed(), projection().transposed(), frustum, culldistance,
math::vector_3d(0.0f, 0.0f, 0.0f), false, false // doodads
, false, _liquid_render.get(), std::vector<selection_type>(), 0, false, display_mode::in_3D
);
gl.enable(GL_BLEND);
gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl.enable(GL_CULL_FACE);
if (draw_doodads_wmo)
{
for (auto &doodad : wmo_instance->get_visible_doodads(frustum, culldistance, _camera.position, false,
display_mode::in_3D))
{
_wmo_doodads[doodad->model->filename].push_back(doodad);
}
}
}
}
// draw M2
std::unordered_map<Model*, std::size_t> model_with_particles;
std::unordered_map<Model*, std::size_t> model_boxes_to_draw;
{
opengl::scoped::use_program m2_shader {*_m2_instanced_program.get()};
m2_shader.uniform("model_view", model_view().transposed());
m2_shader.uniform("projection", projection().transposed());
m2_shader.uniform("tex1", 0);
m2_shader.uniform("tex2", 1);
m2_shader.uniform("draw_fog", 0);
m2_shader.uniform("light_dir", math::vector_3d(0.0f, 1.0f, 0.0f));
m2_shader.uniform("diffuse_color", math::vector_3d(1.0f, 1.0f, 1.0f));
m2_shader.uniform("ambient_color", math::vector_3d(1.0f, 1.0f, 1.0f));
if (_model_instance.which() == eEntry_Model)
{
auto model_instance = boost::get<selected_model_type>(_model_instance);
model_instance->model->draw(
model_view().transposed()
, std::vector<ModelInstance*>{model_instance}
, m2_shader
, frustum
, culldistance
, _camera.position
, false
, 0
, false
, false
, model_with_particles
, model_boxes_to_draw
, display_mode::in_3D
);
}
if (draw_doodads_wmo)
{
for (auto& it : _wmo_doodads)
{
it.second[0]->model->draw(
model_view().transposed()
, it.second
, m2_shader
, frustum
, culldistance
, _camera.position
, false
, 0
, false
, false
, model_with_particles
, model_boxes_to_draw
, display_mode::in_3D
);
}
}
}
gl.bindVertexArray(0);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
math::matrix_4x4 ModelViewer::model_view() const
{
return _camera.look_at_matrix();
}
math::matrix_4x4 ModelViewer::projection() const
{
float far_z = _settings->value("farZ", 2048).toFloat();
return math::perspective(_camera.fov(), aspect_ratio(), 1.f, far_z);
}
float ModelViewer::aspect_ratio() const
{
return float (width()) / float (height());
}
void ModelViewer::mouseMoveEvent(QMouseEvent* event)
{
QLineF const relative_movement (_last_mouse_pos, event->pos());
if (look)
{
_camera.add_to_yaw(math::degrees(relative_movement.dx() / XSENS));
_camera.add_to_pitch(math::degrees(mousedir * relative_movement.dy() / YSENS));
}
_last_mouse_pos = event->pos();
}
void ModelViewer::mousePressEvent(QMouseEvent* event)
{
look = true;
}
void ModelViewer::mouseReleaseEvent(QMouseEvent* event)
{
look = false;
}
void ModelViewer::wheelEvent(QWheelEvent* event)
{
}
void ModelViewer::keyReleaseEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_W || event->key() == Qt::Key_S)
{
moving = 0.0f;
}
if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)
{
lookat = 0.0f;
}
if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Left)
{
turn = 0.0f;
}
if (event->key() == Qt::Key_D || event->key() == Qt::Key_A)
{
strafing = 0.0f;
}
if (event->key() == Qt::Key_Q || event->key() == Qt::Key_E)
{
updown = 0.0f;
}
}
void ModelViewer::focusOutEvent(QFocusEvent* event)
{
//moving = 0.0f;
//lookat = 0.0f;
// turn = 0.0f;
//strafing = 0.0f;
// updown = 0.0f;
}
void ModelViewer::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_W)
{
moving = 1.0f;
}
if (event->key() == Qt::Key_S)
{
moving = -1.0f;
}
if (event->key() == Qt::Key_Up)
{
lookat = 0.75f;
}
if (event->key() == Qt::Key_Down)
{
lookat = -0.75f;
}
if (event->key() == Qt::Key_Right)
{
turn = 0.75f;
}
if (event->key() == Qt::Key_Left)
{
turn = -0.75f;
}
if (event->key() == Qt::Key_D)
{
strafing = 1.0f;
}
if (event->key() == Qt::Key_A)
{
strafing = -1.0f;
}
if (event->key() == Qt::Key_Q)
{
updown = 1.0f;
}
if (event->key() == Qt::Key_E)
{
updown = -1.0f;
}
}

View File

@@ -0,0 +1,89 @@
#ifndef NOGGIT_ModelView_HPP
#define NOGGIT_ModelView_HPP
#include <QWidget>
#include <QOpenGLWidget>
#include <QSettings>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QKeyEvent>
#include <QFocusEvent>
#include <QPointF>
#include <QElapsedTimer>
#include <QTimer>
#include <math/matrix_4x4.hpp>
#include <math/vector_3d.hpp>
#include <noggit/camera.hpp>
#include <noggit/WMOInstance.h>
#include <noggit/Selection.h>
#include <noggit/WMO.h>
#include <noggit/Model.h>
namespace noggit
{
namespace Red::AssetBrowser
{
class ModelViewer : public QOpenGLWidget
{
Q_OBJECT
public:
explicit ModelViewer(QWidget* parent = nullptr);
void resetCamera();
void setModel(std::string const& filename);
private:
QTimer _update_every_event_loop;
QPointF _last_mouse_pos;
float moving, strafing, updown, mousedir, turn, lookat;
bool look;
QElapsedTimer _startup_time;
qreal _last_update = 0.f;
noggit::camera _camera;
QSettings* _settings;
std::unique_ptr<opengl::program> _m2_program;
std::unique_ptr<opengl::program> _m2_instanced_program;
std::unique_ptr<opengl::program> _m2_particles_program;
std::unique_ptr<opengl::program> _m2_ribbons_program;
std::unique_ptr<opengl::program> _m2_box_program;
std::unique_ptr<opengl::program> _wmo_program;
boost::optional<liquid_render> _liquid_render = boost::none;
selection_type _model_instance;
void tick(float dt);
void draw();
math::matrix_4x4 model_view() const;
math::matrix_4x4 projection() const;
float aspect_ratio() const;
void initializeGL() override;
void paintGL() override;
void resizeGL (int w, int h) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
};
}
}
#endif //NOGGIT_ModelView_HPP

View File

@@ -0,0 +1,64 @@
#include "AssetBrowser.hpp"
#include <ui_AssetBrowser.h>
#include <noggit/MPQ.h>
#include <noggit/Log.h>
#include <noggit/Red/AssetBrowser/Ui/Model/TreeManager.hpp>
#include <QStandardItemModel>
#include <QItemSelectionModel>
using namespace noggit::Red::AssetBrowser::Ui;
AssetBrowserWidget::AssetBrowserWidget(QWidget *parent)
{
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
ui = new ::Ui::AssetBrowser;
ui->setupUi(this);
_model = new QStandardItemModel(this);
ui->listfileTree->setModel(_model);
connect(ui->listfileTree->selectionModel(), &QItemSelectionModel::selectionChanged
,[=] (const QItemSelection& selected, const QItemSelection& deselected)
{
for (auto index : selected.indexes())
{
auto path = index.data(Qt::UserRole).toString();
if (path.endsWith(".wmo") || path.endsWith(".m2"))
{
ui->openGLWidget->setModel(path.toStdString());
}
}
}
);
auto start = std::chrono::high_resolution_clock::now();
updateModelData();
auto stop = std::chrono::high_resolution_clock::now();
auto duration = duration_cast<std::chrono::seconds>(stop - start);
LogDebug << duration.count() << std::endl;
}
void AssetBrowserWidget::updateModelData()
{
Model::TreeManager tree_mgr = Model::TreeManager(_model);
for (auto path : gListfile)
{
QString q_path = QString(path.c_str());
if (!(q_path.endsWith(".wmo") || q_path.endsWith(".m2")))
continue;
tree_mgr.addItem(path.c_str());
}
}
AssetBrowserWidget::~AssetBrowserWidget()
{
delete ui;
}

View File

@@ -0,0 +1,31 @@
#ifndef NOGGIT_ASSETBROWSER_HPP
#define NOGGIT_ASSETBROWSER_HPP
#include <QWidget>
#include <ui_AssetBrowser.h>
#include <QStandardItemModel>
namespace noggit
{
namespace Red::AssetBrowser::Ui
{
class AssetBrowserWidget : public QWidget
{
public:
AssetBrowserWidget(QWidget* parent = nullptr);
~AssetBrowserWidget();
private:
::Ui::AssetBrowser* ui;
QStandardItemModel* _model;
void updateModelData();
};
}
}
#endif //NOGGIT_ASSETBROWSER_HPP

View File

@@ -0,0 +1,50 @@
#include "TreeManager.hpp"
using namespace noggit::Red::AssetBrowser::Ui::Model;
QStandardItem* TreeManager::addItem(QString path)
{
QStandardItem * item = root;
QStringList p(path.split(sep, Qt::SkipEmptyParts));
if (items.contains(path))
return items[path];
QString path_remainder = QString("");
while (!p.isEmpty())
{
QString elt = p.takeFirst();
path_remainder = path_remainder + elt;
QStandardItem* child = find(path_remainder);
if (!child)
{
item->appendRow((child = new QStandardItem(elt)));
child->setData(QVariant(path_remainder), Qt::UserRole);
layered_items[path_remainder] = child;
}
item = child;
path_remainder = path_remainder + "/";
}
items.insert(path, item);
return item;
}
QStandardItem* TreeManager::find(QString path)
{
auto search = layered_items.find(path);
if (search != layered_items.end())
{
return search->second;
}
return nullptr;
}

View File

@@ -0,0 +1,40 @@
#ifndef NOGGIT_TREEMANAGER_HPP
#define NOGGIT_TREEMANAGER_HPP
#include <external/tsl/robin_map.h>
#include <chrono>
#include <QWidget>
#include <QStandardItemModel>
namespace noggit
{
namespace Red::AssetBrowser::Ui::Model
{
class TreeManager
{
Q_DISABLE_COPY(TreeManager)
public:
explicit TreeManager(QStandardItem* root) : root(root), sep(QLatin1Char('/')) {}
explicit TreeManager(QStandardItemModel* model) : root(model->invisibleRootItem()), sep(QLatin1Char('/')) {}
QStandardItem* addItem(QString path);
private:
QChar const sep;
QMap<QString, QStandardItem*> items;
tsl::robin_map<QString, QStandardItem*> layered_items;
QStandardItem* root;
QStandardItem* find(QString path);
};
}
}
#endif //NOGGIT_TREEMANAGER_HPP

View File

@@ -207,8 +207,9 @@ void blp_texture::loadFromCompressedData(BLPHeader const* lHeader, char const* l
}
}
blp_texture::blp_texture(const std::string& filenameArg)
blp_texture::blp_texture(const std::string& filenameArg, noggit::NoggitRenderContext context)
: AsyncObject(filenameArg)
, _context(context)
{
}
@@ -425,17 +426,19 @@ namespace noggit
}
}
scoped_blp_texture_reference::scoped_blp_texture_reference (std::string const& filename)
: _blp_texture (TextureManager::_.emplace (filename))
scoped_blp_texture_reference::scoped_blp_texture_reference (std::string const& filename, noggit::NoggitRenderContext context)
: _blp_texture(TextureManager::_.emplace(filename, context))
, _context(context)
{}
scoped_blp_texture_reference::scoped_blp_texture_reference (scoped_blp_texture_reference const& other)
: _blp_texture (other._blp_texture ? TextureManager::_.emplace (other._blp_texture->filename) : nullptr)
: _blp_texture(other._blp_texture ? TextureManager::_.emplace(other._blp_texture->filename, other._context) : nullptr)
, _context(other._context)
{}
void scoped_blp_texture_reference::Deleter::operator() (blp_texture* texture) const
{
TextureManager::_.erase (texture->filename);
TextureManager::_.erase(texture->filename, texture->getContext());
}
blp_texture* scoped_blp_texture_reference::operator->() const
@@ -449,5 +452,5 @@ blp_texture* scoped_blp_texture_reference::get() const
bool scoped_blp_texture_reference::operator== (scoped_blp_texture_reference const& other) const
{
return std::tie (_blp_texture) == std::tie (other._blp_texture);
return std::tie(_blp_texture) == std::tie(other._blp_texture);
}

View File

@@ -3,6 +3,7 @@
#pragma once
#include <noggit/AsyncObject.h>
#include <noggit/ContextObject.hpp>
#include <noggit/multimap_with_normalized_key.hpp>
#include <opengl/texture.hpp>
#include <opengl/context.hpp>
@@ -22,9 +23,10 @@
struct BLPHeader;
struct scoped_blp_texture_reference;
struct blp_texture : public opengl::texture, AsyncObject
{
blp_texture (std::string const& filename);
blp_texture (std::string const& filename, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
void finishLoading();
void loadFromUncompressedData(BLPHeader const* lHeader, char const* lData);
@@ -36,6 +38,8 @@ struct blp_texture : public opengl::texture, AsyncObject
void bind();
void upload();
noggit::NoggitRenderContext getContext() { return _context; };
virtual async_priority loading_priority() const
{
return async_priority::high;
@@ -47,13 +51,14 @@ private:
int _width;
int _height;
noggit::NoggitRenderContext _context;
private:
std::map<int, std::vector<uint32_t>> _data;
std::map<int, std::vector<uint8_t>> _compressed_data;
boost::optional<GLint> _compression_format;
};
struct scoped_blp_texture_reference;
class TextureManager
{
public:
@@ -67,7 +72,8 @@ private:
struct scoped_blp_texture_reference
{
scoped_blp_texture_reference() = delete;
scoped_blp_texture_reference (std::string const& filename);
scoped_blp_texture_reference (std::string const& filename,
noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
scoped_blp_texture_reference (scoped_blp_texture_reference const& other);
scoped_blp_texture_reference (scoped_blp_texture_reference&&) = default;
scoped_blp_texture_reference& operator= (scoped_blp_texture_reference const&) = delete;
@@ -85,6 +91,7 @@ private:
void operator() (blp_texture*) const;
};
std::unique_ptr<blp_texture, Deleter> _blp_texture;
noggit::NoggitRenderContext _context;
};
namespace noggit

View File

@@ -21,9 +21,10 @@
#include <vector>
WMO::WMO(const std::string& filenameArg)
WMO::WMO(const std::string& filenameArg, noggit::NoggitRenderContext context)
: AsyncObject(filenameArg)
, _finished_upload(false)
, _context(context)
{
}
@@ -118,7 +119,7 @@ void WMO::finishLoading ()
if (mapping.second)
{
textures.emplace_back(texture);
textures.emplace_back(texture, _context);
}
return mapping.first->second;
}
@@ -176,7 +177,7 @@ void WMO::finishLoading ()
{
if (MPQFile::exists(path))
{
skybox = scoped_model_reference(path);
skybox = scoped_model_reference(path, _context);
}
}
}
@@ -293,7 +294,7 @@ void WMO::finishLoading ()
size_t after_entry (f.getPos() + 0x28);
f.read (&x, sizeof (x));
modelis.emplace_back(ddnames + x.name_offset, &f);
modelis.emplace_back(ddnames + x.name_offset, &f, _context);
model_nearest_light_vector.emplace_back();
f.seek (after_entry);

View File

@@ -12,6 +12,7 @@
#include <noggit/TextureManager.h>
#include <noggit/tool_enums.hpp>
#include <noggit/wmo_liquid.hpp>
#include <noggit/ContextObject.hpp>
#include <opengl/primitives.hpp>
#include <boost/optional.hpp>
@@ -249,7 +250,7 @@ static_assert ( sizeof (mohd_flags) == sizeof (std::uint16_t)
class WMO : public AsyncObject
{
public:
explicit WMO(const std::string& name);
explicit WMO(const std::string& name, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
void draw ( opengl::scoped::use_program& wmo_shader
, math::matrix_4x4 const& model_view
@@ -267,6 +268,7 @@ public:
, bool world_has_skies
, display_mode display
);
bool draw_skybox( math::matrix_4x4 const& model_view
, math::vector_3d const& camera_pos
, opengl::scoped::use_program& m2_shader
@@ -308,6 +310,8 @@ public:
boost::optional<scoped_model_reference> skybox;
noggit::NoggitRenderContext _context;
bool is_hidden() const { return _hidden; }
void toggle_visibility() { _hidden = !_hidden; }
void show() { _hidden = false ; }
@@ -333,22 +337,26 @@ private:
struct scoped_wmo_reference
{
scoped_wmo_reference (std::string const& filename)
: _valid (true)
, _filename (filename)
, _wmo (WMOManager::_.emplace (_filename))
scoped_wmo_reference (std::string const& filename
, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW)
: _valid(true)
, _filename(filename)
, _context(context)
, _wmo (WMOManager::_.emplace(_filename, context))
{}
scoped_wmo_reference (scoped_wmo_reference const& other)
: _valid (other._valid)
, _filename (other._filename)
, _wmo (WMOManager::_.emplace (_filename))
: _valid(other._valid)
, _filename(other._filename)
, _wmo(WMOManager::_.emplace(_filename, other._context))
, _context(other._context)
{}
scoped_wmo_reference& operator= (scoped_wmo_reference const& other)
{
_valid = other._valid;
_filename = other._filename;
_wmo = WMOManager::_.emplace (_filename);
_wmo = WMOManager::_.emplace(_filename, other._context);
_context = other._context;
return *this;
}
@@ -356,6 +364,7 @@ struct scoped_wmo_reference
: _valid (other._valid)
, _filename (other._filename)
, _wmo (other._wmo)
, _context (other._context)
{
other._valid = false;
}
@@ -364,6 +373,7 @@ struct scoped_wmo_reference
std::swap(_valid, other._valid);
std::swap(_filename, other._filename);
std::swap(_wmo, other._wmo);
std::swap(_context, other._context);
other._valid = false;
return *this;
}
@@ -372,7 +382,7 @@ struct scoped_wmo_reference
{
if (_valid)
{
WMOManager::_.erase (_filename);
WMOManager::_.erase(_filename, _context);
}
}
@@ -390,4 +400,5 @@ private:
std::string _filename;
WMO* _wmo;
noggit::NoggitRenderContext _context;
};

View File

@@ -10,13 +10,14 @@
#include <opengl/primitives.hpp>
#include <opengl/scoped.hpp>
WMOInstance::WMOInstance(std::string const& filename, ENTRY_MODF const* d)
: wmo(filename)
WMOInstance::WMOInstance(std::string const& filename, ENTRY_MODF const* d, noggit::NoggitRenderContext context)
: wmo(filename, context)
, pos(math::vector_3d(d->pos[0], d->pos[1], d->pos[2]))
, dir(math::vector_3d(d->rot[0], d->rot[1], d->rot[2]))
, mUniqueID(d->uniqueID), mFlags(d->flags)
, mUnknown(d->unknown), mNameset(d->nameSet)
, _doodadset(d->doodadSet)
, _context(context)
{
extents[0] = math::vector_3d(d->extents[0][0], d->extents[0][1], d->extents[0][2]);
extents[1] = math::vector_3d(d->extents[1][0], d->extents[1][1], d->extents[1][2]);
@@ -25,8 +26,8 @@ WMOInstance::WMOInstance(std::string const& filename, ENTRY_MODF const* d)
change_doodadset(_doodadset);
}
WMOInstance::WMOInstance(std::string const& filename)
: wmo(filename)
WMOInstance::WMOInstance(std::string const& filename, noggit::NoggitRenderContext context)
: wmo(filename, context)
, pos(math::vector_3d(0.0f, 0.0f, 0.0f))
, dir(math::vector_3d(0.0f, 0.0f, 0.0f))
, mUniqueID(0)
@@ -34,6 +35,7 @@ WMOInstance::WMOInstance(std::string const& filename)
, mUnknown(0)
, mNameset(0)
, _doodadset(0)
, _context(context)
{
change_doodadset(_doodadset);
}

View File

@@ -5,6 +5,7 @@
#include <math/ray.hpp>
#include <math/vector_3d.hpp> // math::vector_3d
#include <noggit/WMO.h>
#include <noggit/ContextObject.hpp>
#include <cstdint>
#include <set>
@@ -30,7 +31,8 @@ public:
private:
void update_doodads();
noggit::NoggitRenderContext _context;
uint16_t _doodadset;
std::map<uint32_t, std::vector<wmo_doodad_instance>> _doodads_per_group;
@@ -41,8 +43,11 @@ private:
math::matrix_4x4 _transform_mat_transposed = math::matrix_4x4::uninitialized;
public:
WMOInstance(std::string const& filename, ENTRY_MODF const* d);
explicit WMOInstance(std::string const& filename);
WMOInstance(std::string const& filename, ENTRY_MODF const* d
, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
explicit WMOInstance(std::string const& filename
, noggit::NoggitRenderContext context = noggit::NoggitRenderContext::MAP_VIEW);
WMOInstance(WMOInstance const& other) = default;
WMOInstance& operator=(WMOInstance const& other) = default;
@@ -62,6 +67,7 @@ public:
, _transform_mat(other._transform_mat)
, _transform_mat_inverted(other._transform_mat_inverted)
, _transform_mat_transposed(other._transform_mat_transposed)
, _context(other._context)
{
std::swap (extents, other.extents);
}
@@ -83,6 +89,7 @@ public:
std::swap(_transform_mat, other._transform_mat);
std::swap(_transform_mat_inverted, other._transform_mat_inverted);
std::swap(_transform_mat_transposed, other._transform_mat_transposed);
std::swap(_context, other._context);
return *this;
}
/*

View File

@@ -91,6 +91,11 @@ namespace noggit
position += direction() * sign * move_speed * dt;
}
void camera::move_forward_factor (float sign, float factor)
{
position += direction() * sign * factor;
}
void camera::move_horizontal (float sign, float dt)
{
math::vector_3d const up (0.0f, 1.0f, 0.0f);

View File

@@ -34,6 +34,8 @@ namespace noggit
void move_horizontal (float sign, float dt);
void move_vertical (float sign, float dt);
void move_forward_factor (float sign, float factor);
math::vector_3d position;
float move_speed;

View File

@@ -4,6 +4,7 @@
#include <noggit/AsyncLoader.h>
#include <noggit/AsyncObject.h>
#include <noggit/ContextObject.hpp>
#include <noggit/Log.h>
#include <noggit/MPQ.h>
@@ -13,11 +14,26 @@
#include <map>
#include <string>
#include <unordered_map>
#include <QOpenGLContext>
struct pair_hash
{
template <class T1, class T2>
std::size_t operator() (const std::pair<T1,T2> &p) const
{
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
return h1 ^ h2; // use hash combine here
}
};
namespace noggit
{
template<typename T>
struct async_object_multimap_with_normalized_key
struct async_object_multimap_with_normalized_key
{
async_object_multimap_with_normalized_key (std::function<std::string (std::string)> normalize = &mpq::normalized_filename)
: _normalize (std::move (normalize))
@@ -25,24 +41,29 @@ namespace noggit
~async_object_multimap_with_normalized_key()
{
/*
apply ( [&] (std::string const& key, T const&)
{
LogDebug << key << ": " << _counts.at (key) << std::endl;
auto pair = std::make_pair(context, key);
LogDebug << key << ": " << _counts.at(pair) << std::endl;
}
);
*/
}
template<typename... Args>
T* emplace (std::string const& filename, Args&&... args)
T* emplace (std::string const& filename, noggit::NoggitRenderContext context, Args&&... args)
{
std::string const normalized (_normalize (filename));
auto pair = std::make_pair(context, normalized);
//LogDebug << "Emplacing " << normalized << " into context" << context << std::endl;
{
boost::mutex::scoped_lock const lock(_mutex);
if ([&] { return _counts[normalized]++; }())
if ([&] { return _counts[pair]++; }())
{
return &_elements.at (normalized);
return &_elements.at (pair);
}
}
@@ -51,8 +72,8 @@ namespace noggit
{
boost::mutex::scoped_lock const lock(_mutex);
return &_elements.emplace ( std::piecewise_construct
, std::forward_as_tuple (normalized)
, std::forward_as_tuple (normalized, args...)
, std::forward_as_tuple (pair)
, std::forward_as_tuple (normalized, context, args...)
).first->second;
}()
);
@@ -61,17 +82,20 @@ namespace noggit
return obj;
}
void erase (std::string const& filename)
{
void erase (std::string const& filename, noggit::NoggitRenderContext context)
{
std::string const normalized (_normalize (filename));
auto pair = std::make_pair(context, normalized);
//LogDebug << "Erasing " << normalized << " from context" << context << std::endl;
AsyncObject* obj = nullptr;
{
boost::mutex::scoped_lock lock(_mutex);
if (--_counts.at (normalized) == 0)
if (--_counts.at(pair) == 0)
{
obj = static_cast<AsyncObject*>(&_elements.at(normalized));
obj = static_cast<AsyncObject*>(&_elements.at(pair));
}
}
@@ -85,17 +109,18 @@ namespace noggit
{
boost::mutex::scoped_lock lock(_mutex);
_elements.erase (normalized);
_counts.erase (normalized);
_elements.erase(pair);
_counts.erase(pair);
}
}
}
void apply (std::function<void (std::string const&, T&)> fun)
{
boost::mutex::scoped_lock lock(_mutex);
for (auto& element : _elements)
{
fun (element.first, element.second);
fun (element.first.second, element.second);
}
}
void apply (std::function<void (std::string const&, T const&)> fun) const
@@ -103,14 +128,16 @@ namespace noggit
boost::mutex::scoped_lock lock(_mutex);
for (auto const& element : _elements)
{
fun (element.first, element.second);
fun (element.first.second, element.second);
}
}
private:
std::map<std::string, T> _elements;
std::unordered_map<std::string, std::size_t> _counts;
std::map<std::pair<int, std::string>, T> _elements;
std::unordered_map<std::pair<int, std::string>, std::size_t, pair_hash> _counts;
std::function<std::string (std::string)> _normalize;
boost::mutex _mutex;
};
}

View File

@@ -124,7 +124,7 @@ namespace opengl
{
errors += _extra_info();
#ifndef NOGGIT_DO_NOT_THROW_ON_OPENGL_ERRORS
LogError << _function << ":" + errors << std::endl;
LogError << _function << ":" + errors << std::endl;
#else
throw std::runtime_error (_function + ":" + errors);
#endif
@@ -751,4 +751,9 @@ namespace opengl
scoped::buffer_binder<GL_ELEMENT_ARRAY_BUFFER> const _ (index_buffer);
return drawElements (mode, count, type, indices);
}
QOpenGLContext* context::getCurrentContext()
{
return _current_context;
}
}

View File

@@ -166,6 +166,8 @@ namespace opengl
void bufferData(GLuint buffer, std::vector<T> const& data, GLenum usage);
void drawElements (GLenum mode, GLuint index_buffer, GLsizei count, GLenum type, GLvoid const* indices);
QOpenGLContext* getCurrentContext();
};
}