reduce lag by introducing BLPRenderer cache class for BLP thumbnail rendering
This commit is contained in:
@@ -3,15 +3,9 @@
|
|||||||
#include <math/vector_2d.hpp>
|
#include <math/vector_2d.hpp>
|
||||||
#include <noggit/TextureManager.h>
|
#include <noggit/TextureManager.h>
|
||||||
#include <noggit/Log.h> // LogDebug
|
#include <noggit/Log.h> // LogDebug
|
||||||
#include <opengl/context.hpp>
|
|
||||||
#include <opengl/scoped.hpp>
|
|
||||||
#include <opengl/shader.hpp>
|
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtGui/QOffscreenSurface>
|
|
||||||
#include <QtGui/QOpenGLFramebufferObjectFormat>
|
|
||||||
#include <QtGui/QPixmap>
|
#include <QtGui/QPixmap>
|
||||||
#include <QtOpenGL/QGLPixelBuffer>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -260,43 +254,126 @@ void blp_texture::finishLoading()
|
|||||||
|
|
||||||
namespace noggit
|
namespace noggit
|
||||||
{
|
{
|
||||||
QPixmap* render_blp_to_pixmap ( std::string const& blp_filename
|
|
||||||
, int width
|
|
||||||
, int height
|
|
||||||
)
|
|
||||||
{
|
|
||||||
static std::map<std::tuple<std::string, int, int>, QPixmap> cache{};
|
|
||||||
std::tuple<std::string, int, int> const curEntry{blp_filename, width, height};
|
|
||||||
auto it{cache.find(curEntry)};
|
|
||||||
|
|
||||||
if(it != cache.end())
|
BLPRenderer::BLPRenderer()
|
||||||
return &it->second;
|
{
|
||||||
|
_cache = {};
|
||||||
|
|
||||||
opengl::context::save_current_context const context_save (::gl);
|
opengl::context::save_current_context const context_save (::gl);
|
||||||
QOpenGLContext context;
|
_context.create();
|
||||||
context.create();
|
|
||||||
|
|
||||||
QOpenGLFramebufferObjectFormat fmt;
|
_fmt.setSamples(1);
|
||||||
fmt.setSamples(1);
|
_fmt.setInternalTextureFormat(GL_RGBA8);
|
||||||
fmt.setInternalTextureFormat(GL_RGBA8);
|
|
||||||
|
|
||||||
QOffscreenSurface surface;
|
_surface.create();
|
||||||
surface.create();
|
|
||||||
|
|
||||||
context.makeCurrent(&surface);
|
_context.makeCurrent(&_surface);
|
||||||
|
|
||||||
opengl::context::scoped_setter const context_set (::gl, &context);
|
opengl::context::scoped_setter const context_set (::gl, &_context);
|
||||||
|
|
||||||
opengl::scoped::bool_setter<GL_CULL_FACE, GL_FALSE> cull;
|
opengl::scoped::bool_setter<GL_CULL_FACE, GL_FALSE> cull;
|
||||||
opengl::scoped::bool_setter<GL_DEPTH_TEST, GL_FALSE> depth;
|
opengl::scoped::bool_setter<GL_DEPTH_TEST, GL_FALSE> depth;
|
||||||
|
|
||||||
opengl::scoped::deferred_upload_vertex_arrays<1> vao;
|
_vao.upload();
|
||||||
vao.upload();
|
_buffers.upload();
|
||||||
opengl::scoped::deferred_upload_buffers<3> buffers;
|
|
||||||
buffers.upload();
|
GLuint const& indices_vbo = _buffers[0];
|
||||||
GLuint const& indices_vbo = buffers[0];
|
GLuint const& vertices_vbo = _buffers[1];
|
||||||
GLuint const& vertices_vbo = buffers[1];
|
GLuint const& texcoords_vbo = _buffers[2];
|
||||||
GLuint const& texcoords_vbo = buffers[2];
|
|
||||||
|
std::vector<math::vector_2d> vertices =
|
||||||
|
{
|
||||||
|
{-1.0f, -1.0f}
|
||||||
|
,{-1.0f, 1.0f}
|
||||||
|
,{ 1.0f, 1.0f}
|
||||||
|
,{ 1.0f, -1.0f}
|
||||||
|
};
|
||||||
|
std::vector<math::vector_2d> texcoords =
|
||||||
|
{
|
||||||
|
{0.f, 0.f}
|
||||||
|
,{0.f, 1.0f}
|
||||||
|
,{1.0f, 1.0f}
|
||||||
|
,{1.0f, 0.f}
|
||||||
|
};
|
||||||
|
std::vector<std::uint16_t> indices = {0,1,2, 2,3,0};
|
||||||
|
|
||||||
|
gl.bufferData<GL_ARRAY_BUFFER, math::vector_2d>(vertices_vbo, vertices, GL_STATIC_DRAW);
|
||||||
|
gl.bufferData<GL_ARRAY_BUFFER, math::vector_2d>(texcoords_vbo, texcoords, GL_STATIC_DRAW);
|
||||||
|
gl.bufferData<GL_ELEMENT_ARRAY_BUFFER, std::uint16_t>(indices_vbo, indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
|
||||||
|
_program.reset(new opengl::program
|
||||||
|
(
|
||||||
|
{
|
||||||
|
{
|
||||||
|
GL_VERTEX_SHADER, R"code(
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec2 tex_coord;
|
||||||
|
out vec2 f_tex_coord;
|
||||||
|
|
||||||
|
uniform float width;
|
||||||
|
uniform float height;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
f_tex_coord = vec2(tex_coord.x * width, -tex_coord.y * height);
|
||||||
|
gl_Position = vec4(position.x * width / 2, position.y * height / 2, position.z, 1.0);
|
||||||
|
}
|
||||||
|
)code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GL_FRAGMENT_SHADER, R"code(
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
in vec2 f_tex_coord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
out_color = vec4(texture(tex, f_tex_coord/2.f + vec2(0.5)).rgb, 1.);
|
||||||
|
}
|
||||||
|
)code"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
opengl::scoped::use_program shader (*_program.get());
|
||||||
|
|
||||||
|
opengl::scoped::vao_binder const _ (_vao[0]);
|
||||||
|
|
||||||
|
{
|
||||||
|
opengl::scoped::buffer_binder<GL_ARRAY_BUFFER> vertices_binder (vertices_vbo);
|
||||||
|
shader.attrib("position", 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
opengl::scoped::buffer_binder<GL_ARRAY_BUFFER> texcoords_binder (texcoords_vbo);
|
||||||
|
shader.attrib("tex_coord", 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap* BLPRenderer::render_blp_to_pixmap ( std::string const& blp_filename
|
||||||
|
, int width
|
||||||
|
, int height
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::tuple<std::string, int, int> const curEntry{blp_filename, width, height};
|
||||||
|
auto it{_cache.find(curEntry)};
|
||||||
|
|
||||||
|
if(it != _cache.end())
|
||||||
|
return &it->second;
|
||||||
|
|
||||||
|
opengl::context::save_current_context const context_save (::gl);
|
||||||
|
|
||||||
|
_context.makeCurrent(&_surface);
|
||||||
|
|
||||||
|
opengl::context::scoped_setter const context_set (::gl, &_context);
|
||||||
|
|
||||||
opengl::texture::set_active_texture(0);
|
opengl::texture::set_active_texture(0);
|
||||||
blp_texture texture(blp_filename);
|
blp_texture texture(blp_filename);
|
||||||
@@ -307,90 +384,25 @@ namespace noggit
|
|||||||
|
|
||||||
float h = static_cast<float>(height);
|
float h = static_cast<float>(height);
|
||||||
float w = static_cast<float>(width);
|
float w = static_cast<float>(width);
|
||||||
float half_h = h * 0.5f;
|
|
||||||
float half_w = w * 0.5f;
|
|
||||||
|
|
||||||
std::vector<math::vector_2d> vertices =
|
QOpenGLFramebufferObject pixel_buffer(width, height, _fmt);
|
||||||
{
|
|
||||||
{-half_w, -half_h}
|
|
||||||
,{-half_w, half_h}
|
|
||||||
,{ half_w, half_h}
|
|
||||||
,{ half_w, -half_h}
|
|
||||||
};
|
|
||||||
std::vector<math::vector_2d> texcoords =
|
|
||||||
{
|
|
||||||
{0.f, 0.f}
|
|
||||||
,{0.f, h}
|
|
||||||
,{w, h}
|
|
||||||
,{w, 0.f}
|
|
||||||
};
|
|
||||||
std::vector<std::uint16_t> indices = {0,1,2, 2,3,0};
|
|
||||||
|
|
||||||
gl.bufferData<GL_ARRAY_BUFFER, math::vector_2d>(vertices_vbo, vertices, GL_STATIC_DRAW);
|
|
||||||
gl.bufferData<GL_ARRAY_BUFFER, math::vector_2d>(texcoords_vbo, texcoords, GL_STATIC_DRAW);
|
|
||||||
gl.bufferData<GL_ELEMENT_ARRAY_BUFFER, std::uint16_t>(indices_vbo, indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
QOpenGLFramebufferObject pixel_buffer(width, height, fmt);
|
|
||||||
pixel_buffer.bind();
|
pixel_buffer.bind();
|
||||||
|
|
||||||
gl.viewport(0, 0, w, h);
|
gl.viewport(0, 0, w, h);
|
||||||
gl.clearColor(.0f, .0f, .0f, 1.f);
|
gl.clearColor(.0f, .0f, .0f, 1.f);
|
||||||
gl.clear(GL_COLOR_BUFFER_BIT);
|
gl.clear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
opengl::program program
|
opengl::scoped::use_program shader (*_program.get());
|
||||||
(
|
|
||||||
{
|
|
||||||
{
|
|
||||||
GL_VERTEX_SHADER, R"code(
|
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
in vec4 position;
|
|
||||||
in vec2 tex_coord;
|
|
||||||
out vec2 f_tex_coord;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
f_tex_coord = vec2(tex_coord.x, -tex_coord.y);
|
|
||||||
gl_Position = position;
|
|
||||||
}
|
|
||||||
)code"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GL_FRAGMENT_SHADER,
|
|
||||||
R"code(
|
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
uniform sampler2D tex;
|
|
||||||
|
|
||||||
in vec2 f_tex_coord;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
out_color = vec4(texture(tex, f_tex_coord/2.f + vec2(0.5)).rgb, 1.);
|
|
||||||
}
|
|
||||||
)code"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
opengl::scoped::use_program shader (program);
|
|
||||||
|
|
||||||
shader.uniform("tex", 0);
|
shader.uniform("tex", 0);
|
||||||
|
shader.uniform("width", w);
|
||||||
|
shader.uniform("height", h);
|
||||||
|
|
||||||
texture.bind();
|
texture.bind();
|
||||||
|
|
||||||
opengl::scoped::vao_binder const _ (vao[0]);
|
opengl::scoped::vao_binder const _ (_vao[0]);
|
||||||
|
|
||||||
{
|
opengl::scoped::buffer_binder<GL_ELEMENT_ARRAY_BUFFER> indices_binder(_buffers[0]);
|
||||||
opengl::scoped::buffer_binder<GL_ARRAY_BUFFER> vertices_binder (vertices_vbo);
|
|
||||||
shader.attrib("position", 2, GL_FLOAT, GL_FALSE, 0, 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
opengl::scoped::buffer_binder<GL_ARRAY_BUFFER> texcoords_binder (texcoords_vbo);
|
|
||||||
shader.attrib("tex_coord", 2, GL_FLOAT, GL_FALSE, 0, 0);
|
|
||||||
}
|
|
||||||
opengl::scoped::buffer_binder<GL_ELEMENT_ARRAY_BUFFER> indices_binder(indices_vbo);
|
|
||||||
|
|
||||||
gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
|
gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
|
||||||
|
|
||||||
@@ -404,7 +416,7 @@ out_color = vec4(texture(tex, f_tex_coord/2.f + vec2(0.5)).rgb, 1.);
|
|||||||
("failed rendering " + blp_filename + " to pixmap");
|
("failed rendering " + blp_filename + " to pixmap");
|
||||||
}
|
}
|
||||||
|
|
||||||
return &(cache[curEntry] = std::move(result));
|
return &(_cache[curEntry] = std::move(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
#include <noggit/AsyncObject.h>
|
#include <noggit/AsyncObject.h>
|
||||||
#include <noggit/multimap_with_normalized_key.hpp>
|
#include <noggit/multimap_with_normalized_key.hpp>
|
||||||
#include <opengl/texture.hpp>
|
#include <opengl/texture.hpp>
|
||||||
|
#include <opengl/context.hpp>
|
||||||
|
#include <opengl/scoped.hpp>
|
||||||
|
#include <opengl/shader.hpp>
|
||||||
|
|
||||||
|
#include <QtGui/QOffscreenSurface>
|
||||||
|
#include <QtGui/QOpenGLFramebufferObjectFormat>
|
||||||
|
#include <QtOpenGL/QGLPixelBuffer>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
@@ -12,6 +19,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
struct BLPHeader;
|
struct BLPHeader;
|
||||||
|
|
||||||
struct blp_texture : public opengl::texture, AsyncObject
|
struct blp_texture : public opengl::texture, AsyncObject
|
||||||
@@ -81,8 +89,35 @@ private:
|
|||||||
|
|
||||||
namespace noggit
|
namespace noggit
|
||||||
{
|
{
|
||||||
QPixmap* render_blp_to_pixmap ( std::string const& blp_filename
|
|
||||||
, int width = -1
|
class BLPRenderer
|
||||||
, int height = -1
|
{
|
||||||
);
|
private:
|
||||||
|
BLPRenderer();
|
||||||
|
|
||||||
|
BLPRenderer( const BLPRenderer&);
|
||||||
|
BLPRenderer& operator=( BLPRenderer& );
|
||||||
|
|
||||||
|
std::map<std::tuple<std::string, int, int>, QPixmap> _cache;
|
||||||
|
|
||||||
|
QOpenGLContext _context;
|
||||||
|
QOpenGLFramebufferObjectFormat _fmt;
|
||||||
|
QOffscreenSurface _surface;
|
||||||
|
std::unique_ptr<opengl::program> _program;
|
||||||
|
|
||||||
|
opengl::scoped::deferred_upload_vertex_arrays<1> _vao;
|
||||||
|
opengl::scoped::deferred_upload_buffers<3> _buffers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static BLPRenderer& getInstance()
|
||||||
|
{
|
||||||
|
static BLPRenderer instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap* render_blp_to_pixmap ( std::string const& blp_filename, int width = -1, int height = -1);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace noggit
|
|||||||
new QVBoxLayout (this);
|
new QVBoxLayout (this);
|
||||||
|
|
||||||
auto icon (new QLabel (this));
|
auto icon (new QLabel (this));
|
||||||
icon->setPixmap (*render_blp_to_pixmap ("interface/icons/inv_potion_83.blp"));
|
icon->setPixmap (*BLPRenderer::getInstance().render_blp_to_pixmap ("interface/icons/inv_potion_83.blp"));
|
||||||
layout()->addWidget (icon);
|
layout()->addWidget (icon);
|
||||||
//! \todo was Skurri32
|
//! \todo was Skurri32
|
||||||
layout()->addWidget (new QLabel ("Noggit Studio", this));
|
layout()->addWidget (new QLabel ("Noggit Studio", this));
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace noggit
|
|||||||
_need_update = false;
|
_need_update = false;
|
||||||
|
|
||||||
show();
|
show();
|
||||||
setPixmap (*render_blp_to_pixmap (_filename, width(), height()));
|
setPixmap (*BLPRenderer::getInstance().render_blp_to_pixmap (_filename, width(), height()));
|
||||||
setToolTip(QString::fromStdString(_filename));
|
setToolTip(QString::fromStdString(_filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace noggit
|
|||||||
layout->addLayout (bottom_layout);
|
layout->addLayout (bottom_layout);
|
||||||
|
|
||||||
auto icon (new QLabel (this));
|
auto icon (new QLabel (this));
|
||||||
icon->setPixmap (*render_blp_to_pixmap ("interface/icons/inv_misc_enggizmos_swissarmy.blp"));
|
icon->setPixmap (*BLPRenderer::getInstance().render_blp_to_pixmap ("interface/icons/inv_misc_enggizmos_swissarmy.blp"));
|
||||||
top_layout->addWidget (icon);
|
top_layout->addWidget (icon);
|
||||||
top_layout->addWidget (new QLabel ("Select a model to add.\nYou should select a chunk first.", this));
|
top_layout->addWidget (new QLabel ("Select a model to add.\nYou should select a chunk first.", this));
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ namespace noggit
|
|||||||
new QHBoxLayout (warning);
|
new QHBoxLayout (warning);
|
||||||
auto icon (new QLabel (warning));
|
auto icon (new QLabel (warning));
|
||||||
icon->setPixmap
|
icon->setPixmap
|
||||||
(*render_blp_to_pixmap ("interface/gossipframe/availablequesticon.blp"));
|
(*BLPRenderer::getInstance().render_blp_to_pixmap ("interface/gossipframe/availablequesticon.blp"));
|
||||||
warning->layout()->addWidget (icon);
|
warning->layout()->addWidget (icon);
|
||||||
warning->layout()->addWidget
|
warning->layout()->addWidget
|
||||||
(new QLabel ("Changes may not take effect until next launch.", warning));
|
(new QLabel ("Changes may not take effect until next launch.", warning));
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace noggit
|
|||||||
//! \note The one time Qt is const correct and we don't want that.
|
//! \note The one time Qt is const correct and we don't want that.
|
||||||
auto that (const_cast<model_item*> (this));
|
auto that (const_cast<model_item*> (this));
|
||||||
that->_rendered = true;
|
that->_rendered = true;
|
||||||
that->_pixmap = *render_blp_to_pixmap (data (Qt::DisplayRole).toString().prepend ("tileset/").toStdString(), 256, 256);
|
that->_pixmap = *BLPRenderer::getInstance().render_blp_to_pixmap (data (Qt::DisplayRole).toString().prepend ("tileset/").toStdString(), 256, 256);
|
||||||
}
|
}
|
||||||
return QIcon(_pixmap);
|
return QIcon(_pixmap);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ namespace noggit
|
|||||||
_texture_paths.emplace(display_name.toStdString());
|
_texture_paths.emplace(display_name.toStdString());
|
||||||
|
|
||||||
QListWidgetItem* list_item = new QListWidgetItem(_texture_list);
|
QListWidgetItem* list_item = new QListWidgetItem(_texture_list);
|
||||||
list_item->setIcon(*render_blp_to_pixmap(filename, _texture_list->iconSize().width(), _texture_list->iconSize().height()));
|
list_item->setIcon(*BLPRenderer::getInstance().render_blp_to_pixmap(filename, _texture_list->iconSize().width(), _texture_list->iconSize().height()));
|
||||||
list_item->setToolTip(display_name);
|
list_item->setToolTip(display_name);
|
||||||
list_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
|
list_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace opengl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \todo cache lookups?
|
//! \todo _cache lookups?
|
||||||
GLuint program::uniform_location (std::string const& name) const
|
GLuint program::uniform_location (std::string const& name) const
|
||||||
{
|
{
|
||||||
return gl.getUniformLocation (*_handle, name.c_str());
|
return gl.getUniformLocation (*_handle, name.c_str());
|
||||||
|
|||||||
Reference in New Issue
Block a user