740 lines
21 KiB
C++
Executable File
740 lines
21 KiB
C++
Executable File
#include "PreviewRenderer.hpp"
|
|
|
|
#include <opengl/scoped.hpp>
|
|
#include <noggit/rendering/Primitives.hpp>
|
|
#include <noggit/Selection.h>
|
|
#include <noggit/tool_enums.hpp>
|
|
#include <noggit/AsyncLoader.h>
|
|
|
|
#include <vector>
|
|
#include <cmath>
|
|
#include <stdexcept>
|
|
#include <limits>
|
|
#include <thread>
|
|
#include <chrono>
|
|
|
|
#include <QSettings>
|
|
#include <QColor>
|
|
#include <QMatrix4x4>
|
|
#include <QVector3D>
|
|
|
|
|
|
using namespace Noggit::Ui::Tools;
|
|
|
|
|
|
PreviewRenderer::PreviewRenderer(int width, int height, Noggit::NoggitRenderContext context, QWidget* parent)
|
|
: Noggit::Ui::Tools::ViewportManager::Viewport(parent)
|
|
, _camera (glm::vec3(0.0f, 0.0f, 0.0f), math::degrees(0.0f), math::degrees(0.0f))
|
|
, _settings (new QSettings())
|
|
, _width(width)
|
|
, _height(height)
|
|
, _liquid_texture_manager(context)
|
|
{
|
|
_context = context;
|
|
_cache = {};
|
|
|
|
OpenGL::context::save_current_context const context_save (::gl);
|
|
_offscreen_context.create();
|
|
|
|
_fmt.setSamples(1);
|
|
_fmt.setInternalTextureFormat(GL_RGBA8);
|
|
_fmt.setAttachment(QOpenGLFramebufferObject::Depth);
|
|
|
|
_offscreen_surface.create();
|
|
_offscreen_context.makeCurrent(&_offscreen_surface);
|
|
|
|
OpenGL::context::scoped_setter const context_set (::gl, &_offscreen_context);
|
|
|
|
_light_dir = glm::vec3(0.0f, 1.0f, 0.0f);
|
|
}
|
|
|
|
void PreviewRenderer::setModel(std::string const &filename)
|
|
{
|
|
_filename = filename;
|
|
_model_instances.clear();
|
|
_wmo_instances.clear();
|
|
|
|
// add new model instance
|
|
QString q_filename = QString(filename.c_str());
|
|
|
|
if (q_filename.endsWith(".wmo"))
|
|
{
|
|
auto& instance = _wmo_instances.emplace_back(filename, _context);
|
|
instance.wmo->wait_until_loaded();
|
|
instance.recalcExtents();
|
|
|
|
}
|
|
else if (q_filename.endsWith(".m2"))
|
|
{
|
|
auto& instance = _model_instances.emplace_back(filename, _context);
|
|
instance.model->wait_until_loaded();
|
|
instance.recalcExtents();
|
|
}
|
|
else
|
|
{
|
|
throw std::logic_error("Preview renderer only supports viewing M2 and WMO for now.");
|
|
}
|
|
|
|
_lighting_needs_update = true;
|
|
|
|
auto diffuse_color = _settings->value("assetBrowser/diffuse_light",
|
|
QVariant::fromValue(QColor::fromRgbF(1.0f, 0.532352924f, 0.0f))).value<QColor>();
|
|
_diffuse_light = {static_cast<float>(diffuse_color.redF()),
|
|
static_cast<float>(diffuse_color.greenF()),
|
|
static_cast<float>(diffuse_color.blueF())};
|
|
|
|
auto ambient_color = _settings->value("assetBrowser/ambient_light",
|
|
QVariant::fromValue(QColor::fromRgbF(0.407770514f, 0.508424163f, 0.602650642f))).value<QColor>();
|
|
|
|
_ambient_light = {static_cast<float>(ambient_color.redF()),
|
|
static_cast<float>(ambient_color.greenF()),
|
|
static_cast<float>(ambient_color.blueF())};
|
|
|
|
auto background_color = _settings->value("assetBrowser/background_color",
|
|
QVariant::fromValue(QColor(127, 127, 127))).value<QColor>();
|
|
|
|
_background_color = {static_cast<float>(background_color.redF()),
|
|
static_cast<float>(background_color.greenF()),
|
|
static_cast<float>(background_color.blueF())};
|
|
|
|
resetCamera();
|
|
}
|
|
|
|
void PreviewRenderer::setModelOffscreen(std::string const& filename)
|
|
{
|
|
OpenGL::context::save_current_context const context_save (::gl);
|
|
_offscreen_context.makeCurrent(&_offscreen_surface);
|
|
OpenGL::context::scoped_setter const context_set (::gl, &_offscreen_context);
|
|
|
|
setModel(filename);
|
|
}
|
|
|
|
|
|
void PreviewRenderer::resetCamera(float x, float y, float z, float roll, float yaw, float pitch)
|
|
{
|
|
_camera.reset(x, y, z, roll, yaw, pitch);
|
|
float radius = 0.f;
|
|
|
|
std::vector<glm::vec3> extents = calcSceneExtents();
|
|
_camera.position = (extents[0] + extents[1]) / 2.0f;
|
|
radius = std::max(glm::distance(_camera.position, extents[0]), glm::distance(_camera.position, extents[1]));
|
|
|
|
float distance_factor = abs( radius / sin(_camera.fov()._ / 2.f));
|
|
_camera.move_forward_factor(-1.f, distance_factor);
|
|
|
|
}
|
|
|
|
|
|
void PreviewRenderer::draw()
|
|
{
|
|
if (!_uploaded)
|
|
[[unlikely]]
|
|
{
|
|
upload();
|
|
}
|
|
|
|
gl.clearColor(_background_color.r, _background_color.g, _background_color.b, 1.0f);
|
|
gl.depthMask(GL_TRUE);
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
float culldistance = 10000000;
|
|
|
|
auto mv = model_view();
|
|
auto proj = projection();
|
|
|
|
glm::mat4x4 const mvp(proj * mv);
|
|
math::frustum const frustum (glm::transpose(mvp));
|
|
|
|
updateMVPUniformBlock(mv, proj);
|
|
|
|
if (_lighting_needs_update)
|
|
updateLightingUniformBlock();
|
|
|
|
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 (_draw_wmo.get() && !_wmo_instances.empty())
|
|
{
|
|
/* set anim time only once per frame
|
|
{
|
|
OpenGL::Scoped::use_program water_shader {_liquid_render->shader_program()};
|
|
water_shader.uniform("animtime", _animtime / 2880.f);
|
|
|
|
//water_shader.uniform("model_view", model_view().transposed());
|
|
//water_shader.uniform("projection", projection().transposed());
|
|
|
|
//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("camera", glm::vec3(_camera.position.x, _camera.position.y, _camera.position.z));
|
|
|
|
|
|
for (auto& wmo_instance : _wmo_instances)
|
|
{
|
|
wmo_instance.wmo->wait_until_loaded();
|
|
wmo_instance.wmo->waitForChildrenLoaded();
|
|
wmo_instance.ensureExtents();
|
|
wmo_instance.draw(
|
|
wmo_program, model_view(), projection(), frustum, culldistance,
|
|
_camera.position, _draw_boxes.get(), _draw_models.get()
|
|
, false, false, 0, false, display_mode::in_3D
|
|
, true, true, false, false, false
|
|
);
|
|
|
|
auto doodads = wmo_instance.get_doodads(true);
|
|
|
|
if (doodads)
|
|
{
|
|
for (auto& pair : *doodads)
|
|
{
|
|
for (auto& doodad : pair.second)
|
|
_wmo_doodads[doodad.model->file_key().filepath()].push_back(&doodad);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// draw M2
|
|
std::unordered_map<Model*, std::size_t> model_boxes_to_draw;
|
|
|
|
if (_draw_models.get() && !(_model_instances.empty() && _wmo_doodads.empty()))
|
|
{
|
|
if (_draw_animated.get())
|
|
ModelManager::resetAnim();
|
|
|
|
OpenGL::Scoped::use_program m2_shader {*_m2_instanced_program.get()};
|
|
|
|
OpenGL::M2RenderState model_render_state;
|
|
model_render_state.tex_arrays = { 0, 0 };
|
|
model_render_state.tex_indices = { 0, 0 };
|
|
model_render_state.tex_unit_lookups = { 0, 0 };
|
|
gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
gl.disable(GL_BLEND);
|
|
gl.depthMask(GL_TRUE);
|
|
m2_shader.uniform("blend_mode", 0);
|
|
m2_shader.uniform("unfogged", static_cast<int>(model_render_state.unfogged));
|
|
m2_shader.uniform("unlit", static_cast<int>(model_render_state.unlit));
|
|
m2_shader.uniform("tex_unit_lookup_1", 0);
|
|
m2_shader.uniform("tex_unit_lookup_2", 0);
|
|
m2_shader.uniform("pixel_shader", 0);
|
|
|
|
std::vector<ModelInstance*> instance{ nullptr };
|
|
std::vector<glm::mat4x4> instance_mtx{ glm::mat4x4(1)};
|
|
|
|
for (auto& model_instance : _model_instances)
|
|
{
|
|
model_instance.model->wait_until_loaded();
|
|
model_instance.model->waitForChildrenLoaded();
|
|
instance[0] = &model_instance;
|
|
instance_mtx[0] = model_instance.transformMatrix();
|
|
|
|
model_instance.model->renderer()->draw(
|
|
mv
|
|
, instance_mtx
|
|
, m2_shader
|
|
, model_render_state
|
|
, frustum
|
|
, culldistance
|
|
, _camera.position
|
|
, _animtime
|
|
, _draw_boxes.get()
|
|
, model_boxes_to_draw
|
|
, display_mode::in_3D
|
|
, false
|
|
, _draw_animated.get()
|
|
, true
|
|
, false
|
|
);
|
|
}
|
|
|
|
for (auto& it : _wmo_doodads)
|
|
{
|
|
instance_mtx.clear();
|
|
|
|
for (auto& instance : it.second)
|
|
{
|
|
instance_mtx.push_back(instance->transformMatrix());
|
|
}
|
|
|
|
it.second[0]->model->renderer()->draw(
|
|
mv
|
|
, instance_mtx
|
|
, m2_shader
|
|
, model_render_state
|
|
, frustum
|
|
, culldistance
|
|
, _camera.position
|
|
, _animtime
|
|
, _draw_boxes.get()
|
|
, model_boxes_to_draw
|
|
, display_mode::in_3D
|
|
, false
|
|
, _draw_animated.get()
|
|
, false
|
|
, false
|
|
);
|
|
}
|
|
|
|
|
|
if(_draw_boxes.get() && !model_boxes_to_draw.empty())
|
|
{
|
|
OpenGL::Scoped::use_program m2_box_shader{ *_m2_box_program.get() };
|
|
|
|
OpenGL::Scoped::bool_setter<GL_LINE_SMOOTH, GL_TRUE> const line_smooth;
|
|
gl.hint (GL_LINE_SMOOTH_HINT, GL_NICEST);
|
|
|
|
for (auto& it : model_boxes_to_draw)
|
|
{
|
|
glm::vec4 color = it.first->is_hidden()
|
|
? glm::vec4(0.f, 0.f, 1.f, 1.f)
|
|
: ( it.first->use_fake_geometry()
|
|
? glm::vec4(1.f, 0.f, 0.f, 1.f)
|
|
: glm::vec4(0.75f, 0.75f, 0.75f, 1.f)
|
|
)
|
|
;
|
|
|
|
m2_box_shader.uniform("color", color);
|
|
it.first->renderer()->drawBox(m2_box_shader, it.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
gl.bindVertexArray(0);
|
|
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
// model particles
|
|
|
|
/*
|
|
if (_draw_animated.get() && !model_with_particles.empty())
|
|
{
|
|
OpenGL::Scoped::bool_setter<GL_CULL_FACE, GL_FALSE> const cull;
|
|
OpenGL::Scoped::depth_mask_setter<GL_FALSE> const depth_mask;
|
|
|
|
OpenGL::Scoped::use_program particles_shader {*_m2_particles_program.get()};
|
|
|
|
particles_shader.uniform("model_view_projection", mvp);
|
|
particles_shader.uniform("tex", 0);
|
|
OpenGL::texture::set_active_texture(0);
|
|
|
|
for (auto& it : model_with_particles)
|
|
{
|
|
it.first->draw_particles(model_view().transposed(), particles_shader, it.second);
|
|
}
|
|
}
|
|
|
|
if (_draw_animated.get() && !model_with_particles.empty())
|
|
{
|
|
OpenGL::Scoped::bool_setter<GL_CULL_FACE, GL_FALSE> const cull;
|
|
OpenGL::Scoped::depth_mask_setter<GL_FALSE> const depth_mask;
|
|
|
|
OpenGL::Scoped::use_program ribbon_shader {*_m2_ribbons_program.get()};
|
|
|
|
ribbon_shader.uniform("model_view_projection", mvp);
|
|
ribbon_shader.uniform("tex", 0);
|
|
|
|
gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
|
|
for (auto& it : model_with_particles)
|
|
{
|
|
it.first->draw_ribbons(ribbon_shader, it.second);
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
gl.enable(GL_BLEND);
|
|
gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if (_draw_grid.get())
|
|
{
|
|
_grid.draw(mvp, glm::vec3(0.f, 0.f, 0.f),
|
|
glm::vec4(0.7f, 0.7f, 0.7f, 1.0f), 30.f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glm::mat4x4 PreviewRenderer::model_view() const
|
|
{
|
|
return _camera.look_at_matrix();
|
|
}
|
|
|
|
glm::mat4x4 PreviewRenderer::projection() const
|
|
{
|
|
float far_z = _settings->value("view_distance", 2000.f).toFloat();
|
|
return glm::perspective(_camera.fov()._, aspect_ratio(), 1.f, far_z);
|
|
}
|
|
|
|
float PreviewRenderer::aspect_ratio() const
|
|
{
|
|
return static_cast<float>(_width) / static_cast<float>(_height);
|
|
}
|
|
|
|
std::vector<glm::vec3> PreviewRenderer::calcSceneExtents()
|
|
{
|
|
glm::vec3 min = {std::numeric_limits<float>::max(),
|
|
std::numeric_limits<float>::max(),
|
|
std::numeric_limits<float>::max()};
|
|
|
|
glm::vec3 max = {std::numeric_limits<float>::min(),
|
|
std::numeric_limits<float>::min(),
|
|
std::numeric_limits<float>::min()};
|
|
|
|
for (auto& instance : _model_instances)
|
|
{
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
min[i] = std::min(instance.getExtents()[0][i], min[i]);
|
|
max[i] = std::max(instance.getExtents()[1][i], max[i]);
|
|
}
|
|
}
|
|
|
|
for (auto& instance : _wmo_instances)
|
|
{
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
min[i] = std::min(instance.getExtents()[0][i], min[i]);
|
|
max[i] = std::max(instance.getExtents()[1][i], max[i]);
|
|
}
|
|
}
|
|
|
|
return std::move(std::vector<glm::vec3>{min, max});
|
|
}
|
|
|
|
QPixmap* PreviewRenderer::renderToPixmap()
|
|
{
|
|
std::tuple<std::string, int, int> const curEntry{_filename, _width, _height};
|
|
auto it{_cache.find(curEntry)};
|
|
|
|
if(it != _cache.end())
|
|
return &it->second;
|
|
|
|
OpenGL::context::save_current_context const context_save (::gl);
|
|
|
|
_offscreen_context.makeCurrent(&_offscreen_surface);
|
|
|
|
OpenGL::context::scoped_setter const context_set (::gl, &_offscreen_context);
|
|
|
|
QOpenGLFramebufferObject pixel_buffer(_width, _height, _fmt);
|
|
pixel_buffer.bind();
|
|
|
|
gl.viewport(0, 0, _width, _height);
|
|
gl.clearColor(_background_color.r, _background_color.g, _background_color.b, 1.f);
|
|
gl.depthMask(GL_TRUE);
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
tick(1.0f);
|
|
draw();
|
|
|
|
auto async_loader = AsyncLoader::instance;
|
|
|
|
if (async_loader->is_loading())
|
|
{
|
|
// wait for the loader to finish
|
|
do
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
} while (async_loader->is_loading());
|
|
|
|
// redraw
|
|
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
draw();
|
|
}
|
|
|
|
// Clearing alpha from image
|
|
gl.colorMask(false, false, false, true);
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
gl.colorMask(true, true, true, true);
|
|
|
|
QPixmap result{};
|
|
result = std::move(QPixmap::fromImage(pixel_buffer.toImage()));
|
|
pixel_buffer.release();
|
|
|
|
if (result.isNull())
|
|
{
|
|
throw std::runtime_error("failed rendering " + _filename + " to pixmap");
|
|
}
|
|
|
|
return &(_cache[curEntry] = std::move(result));
|
|
}
|
|
|
|
void PreviewRenderer::setLightDirection(float y, float z)
|
|
{
|
|
_light_dir = {1.f, 0.5f, 0.f};
|
|
QMatrix4x4 matrix = QMatrix4x4();
|
|
matrix.rotate(z, 0.f, 1.f, 0.f);
|
|
matrix.rotate(y, 1.f, 0.f, 0.f);
|
|
|
|
QVector3D light_dir = {_light_dir.x, _light_dir.y, _light_dir.z};
|
|
light_dir = matrix * light_dir;
|
|
|
|
_light_dir.x = light_dir.x();
|
|
_light_dir.y = light_dir.y();
|
|
_light_dir.z = light_dir.z();
|
|
|
|
_lighting_needs_update = true;
|
|
}
|
|
|
|
|
|
void PreviewRenderer::update_emitters(float dt)
|
|
{
|
|
while (dt > 0.1f)
|
|
{
|
|
ModelManager::updateEmitters(0.1f);
|
|
dt -= 0.1f;
|
|
}
|
|
ModelManager::updateEmitters(dt);
|
|
}
|
|
|
|
void PreviewRenderer::tick(float dt)
|
|
{
|
|
dt = std::min(dt, 1.0f);
|
|
|
|
_animtime += dt * 1000.0f;
|
|
|
|
if (_draw_animated.get())
|
|
{
|
|
update_emitters(dt);
|
|
}
|
|
}
|
|
|
|
|
|
void PreviewRenderer::upload()
|
|
{
|
|
_buffers.upload();
|
|
|
|
// m2
|
|
|
|
_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") }
|
|
}
|
|
);
|
|
|
|
{
|
|
OpenGL::Scoped::use_program m2_shader{ *_m2_program.get() };
|
|
m2_shader.uniform("bone_matrices", 0);
|
|
m2_shader.uniform("tex1", 1);
|
|
m2_shader.uniform("tex2", 2);
|
|
|
|
m2_shader.bind_uniform_block("matrices", 0);
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, _mvp_ubo);
|
|
gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::MVPUniformBlock), NULL, GL_DYNAMIC_DRAW);
|
|
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::MVP, _mvp_ubo, 0, sizeof(OpenGL::MVPUniformBlock));
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
|
|
m2_shader.bind_uniform_block("lighting", 1);
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, _lighting_ubo);
|
|
gl.bufferData(GL_UNIFORM_BUFFER, sizeof(OpenGL::LightingUniformBlock), NULL, GL_DYNAMIC_DRAW);
|
|
gl.bindBufferRange(GL_UNIFORM_BUFFER, OpenGL::ubo_targets::LIGHTING, _lighting_ubo, 0, sizeof(OpenGL::LightingUniformBlock));
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
|
|
}
|
|
|
|
// m2 instaced
|
|
|
|
_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") }
|
|
}
|
|
);
|
|
|
|
{
|
|
OpenGL::Scoped::use_program m2_shader_instanced{ *_m2_instanced_program.get() };
|
|
m2_shader_instanced.bind_uniform_block("matrices", 0);
|
|
m2_shader_instanced.bind_uniform_block("lighting", 1);
|
|
m2_shader_instanced.uniform("bone_matrices", 0);
|
|
m2_shader_instanced.uniform("tex1", 1);
|
|
m2_shader_instanced.uniform("tex2", 2);
|
|
}
|
|
|
|
// m2 box
|
|
|
|
_m2_box_program.reset
|
|
(new OpenGL::program
|
|
{ { GL_VERTEX_SHADER, OpenGL::shader::src_from_qrc("m2_box_vs") }
|
|
, { GL_FRAGMENT_SHADER, OpenGL::shader::src_from_qrc("m2_box_fs") }
|
|
}
|
|
);
|
|
|
|
{
|
|
OpenGL::Scoped::use_program m2_box_shader{ *_m2_box_program.get() };
|
|
m2_box_shader.bind_uniform_block("matrices", 0);
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
|
|
_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") }
|
|
}
|
|
);
|
|
|
|
|
|
_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") }
|
|
}
|
|
);
|
|
|
|
*/
|
|
|
|
// wmo
|
|
|
|
_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") }
|
|
}
|
|
);
|
|
|
|
{
|
|
std::vector<int> samplers{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
|
|
|
OpenGL::Scoped::use_program wmo_program{ *_wmo_program.get() };
|
|
wmo_program.uniform("render_batches_tex", 0);
|
|
wmo_program.uniform("texture_samplers", samplers);
|
|
wmo_program.bind_uniform_block("matrices", 0);
|
|
wmo_program.bind_uniform_block("lighting", 1);
|
|
}
|
|
|
|
// liquid
|
|
_liquid_texture_manager.upload();
|
|
_liquid_program.reset
|
|
(new OpenGL::program
|
|
{ { GL_VERTEX_SHADER, OpenGL::shader::src_from_qrc("liquid_vs") }
|
|
, { GL_FRAGMENT_SHADER, OpenGL::shader::src_from_qrc("liquid_fs") }
|
|
}
|
|
);
|
|
|
|
{
|
|
OpenGL::Scoped::use_program liquid_render{ *_liquid_program.get() };
|
|
|
|
//setupLiquidChunkBuffers();
|
|
//setupLiquidChunkVAO(liquid_render);
|
|
|
|
static std::vector<int> samplers{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
|
|
|
liquid_render.bind_uniform_block("matrices", 0);
|
|
liquid_render.bind_uniform_block("lighting", 1);
|
|
liquid_render.bind_uniform_block("liquid_layers_params", 4);
|
|
liquid_render.uniform("vertex_data", 0);
|
|
liquid_render.uniform("texture_samplers", samplers);
|
|
|
|
}
|
|
|
|
setModel("world/wmo/azeroth/buildings/human_farm/farm.wmo");
|
|
|
|
auto background_color = _settings->value("assetBrowser/background_color",
|
|
QVariant::fromValue(QColor(127, 127, 127))).value<QColor>();
|
|
|
|
_background_color = { static_cast<float>(background_color.redF()),
|
|
static_cast<float>(background_color.greenF()),
|
|
static_cast<float>(background_color.blueF()) };
|
|
|
|
_uploaded = true;
|
|
|
|
}
|
|
|
|
|
|
void PreviewRenderer::unload()
|
|
{
|
|
_buffers.unload();
|
|
|
|
_m2_program.reset();
|
|
_m2_instanced_program.reset();
|
|
_m2_particles_program.reset();
|
|
_m2_ribbons_program.reset();
|
|
_m2_box_program.reset();
|
|
_wmo_program.reset();
|
|
_liquid_program.reset();
|
|
_liquid_texture_manager.unload();
|
|
|
|
_model_instances.clear();
|
|
_wmo_instances.clear();
|
|
|
|
_uploaded = false;
|
|
|
|
}
|
|
|
|
void PreviewRenderer::unloadOpenglData()
|
|
{
|
|
if (_offscreen_mode)
|
|
{
|
|
OpenGL::context::save_current_context const context_save (::gl);
|
|
_offscreen_context.makeCurrent(&_offscreen_surface);
|
|
OpenGL::context::scoped_setter const context_set (::gl, &_offscreen_context);
|
|
|
|
unload();
|
|
return;
|
|
}
|
|
|
|
assert(context() != nullptr);
|
|
makeCurrent();
|
|
OpenGL::context::scoped_setter const _ (::gl, context());
|
|
|
|
ModelManager::unload_all(_context);
|
|
WMOManager::unload_all(_context);
|
|
TextureManager::unload_all(_context);
|
|
|
|
unload();
|
|
}
|
|
|
|
void Noggit::Ui::Tools::PreviewRenderer::updateLightingUniformBlock()
|
|
{
|
|
|
|
glm::vec4 ocean_color_light(glm::vec3(1.0f, 1.0f, 1.0f), 1.f);
|
|
glm::vec4 ocean_color_dark(glm::vec3(1.0f, 1.0f, 1.0f), 1.f);
|
|
glm::vec4 river_color_light(glm::vec3(1.0f, 1.0f, 1.0f), 1.f);
|
|
glm::vec4 river_color_dark(glm::vec3(1.0f, 1.0f, 1.0f), 1.f);
|
|
|
|
_lighting_ubo_data.DiffuseColor_FogStart = { _diffuse_light.x,_diffuse_light.y,_diffuse_light.z, 0};
|
|
_lighting_ubo_data.AmbientColor_FogEnd = { _ambient_light.x, _ambient_light.y, _ambient_light.z, 0};
|
|
_lighting_ubo_data.FogColor_FogOn = { 0, 0, 0, 0};
|
|
_lighting_ubo_data.LightDir_FogRate = { _light_dir.x, _light_dir.y, _light_dir.z, 1.0f};
|
|
_lighting_ubo_data.OceanColorLight = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
_lighting_ubo_data.OceanColorDark = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
_lighting_ubo_data.RiverColorLight = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
_lighting_ubo_data.RiverColorDark = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, _lighting_ubo);
|
|
gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::LightingUniformBlock), &_lighting_ubo_data);
|
|
|
|
_lighting_needs_update = false;
|
|
}
|
|
|
|
void Noggit::Ui::Tools::PreviewRenderer::updateMVPUniformBlock(const glm::mat4x4& model_view, const glm::mat4x4& projection)
|
|
{
|
|
_mvp_ubo_data.model_view = model_view;
|
|
_mvp_ubo_data.projection = projection;
|
|
|
|
gl.bindBuffer(GL_UNIFORM_BUFFER, _mvp_ubo);
|
|
gl.bufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(OpenGL::MVPUniformBlock), &_mvp_ubo_data);
|
|
|
|
}
|