From 18a5b37d4f4374a2e039362c788ab5ade412b58c Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 24 May 2023 21:48:39 -0400 Subject: [PATCH] lightstyle stuff --- lightpreview/glview.cpp | 97 +++++++++++++++++++++++++++++++------ lightpreview/glview.h | 9 +++- lightpreview/mainwindow.cpp | 79 +++++++++++++++++++++++++++++- lightpreview/mainwindow.h | 2 + 4 files changed, 169 insertions(+), 18 deletions(-) diff --git a/lightpreview/glview.cpp b/lightpreview/glview.cpp index e7b5ad56..3636faeb 100644 --- a/lightpreview/glview.cpp +++ b/lightpreview/glview.cpp @@ -30,6 +30,7 @@ See file, 'COPYING', for details. #include #include #include +#include #include #include @@ -100,17 +101,18 @@ in vec2 uv; in vec2 lightmap_uv; in vec3 normal; flat in vec3 flat_color; +flat in uint styles; out vec4 color; uniform sampler2D texture_sampler; -uniform sampler2D lightmap_sampler; +uniform sampler2DArray lightmap_sampler; uniform float opacity; uniform bool lightmap_only; uniform bool fullbright; uniform bool drawnormals; -uniform bool showtris; uniform bool drawflat; +uniform float style_scalars[256]; void main() { if (drawnormals) { @@ -120,7 +122,20 @@ void main() { color = vec4(flat_color, opacity); } else { vec3 texcolor = lightmap_only ? vec3(0.5) : texture(texture_sampler, uv).rgb; - vec3 lmcolor = fullbright ? vec3(0.5) : texture(lightmap_sampler, lightmap_uv).rgb; + vec3 lmcolor = fullbright ? vec3(0.5) : vec3(0); + + if (!fullbright) + { + for (uint i = 0u; i < 32u; i += 8u) + { + uint style = (styles >> i) & 0xFFu; + + if (style == 0xFFu) + break; + + lmcolor += texture(lightmap_sampler, vec3(lightmap_uv, (float) style)).rgb * style_scalars[style]; + } + } // 2.0 for overbright color = vec4(texcolor * lmcolor * 2.0, opacity); @@ -136,11 +151,13 @@ layout (location = 1) in vec2 vertex_uv; layout (location = 2) in vec2 vertex_lightmap_uv; layout (location = 3) in vec3 vertex_normal; layout (location = 4) in vec3 vertex_flat_color; +layout (location = 5) in uint vertex_styles; out vec2 uv; out vec2 lightmap_uv; out vec3 normal; flat out vec3 flat_color; +flat out uint styles; uniform mat4 MVP; @@ -151,13 +168,27 @@ void main() { lightmap_uv = vertex_lightmap_uv; normal = vertex_normal; flat_color = vertex_flat_color; + styles = vertex_styles; } )"; +void GLView::handleLoggedMessage(const QOpenGLDebugMessage &debugMessage) +{ + qDebug() << debugMessage.message(); +} + void GLView::initializeGL() { initializeOpenGLFunctions(); + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + + logger->initialize(); // initializes in the current context, i.e. ctx + + connect(logger, &QOpenGLDebugLogger::messageLogged, this, &GLView::handleLoggedMessage); + logger->startLogging(); + // set up shader m_program = new QOpenGLShaderProgram(); @@ -178,8 +209,8 @@ void GLView::initializeGL() m_program_lightmap_only_location = m_program->uniformLocation("lightmap_only"); m_program_fullbright_location = m_program->uniformLocation("fullbright"); m_program_drawnormals_location = m_program->uniformLocation("drawnormals"); - m_program_showtris_location = m_program->uniformLocation("showtris"); m_program_drawflat_location = m_program->uniformLocation("drawflat"); + m_program_style_scalars_location = m_program->uniformLocation("style_scalars"); m_program->release(); m_program_wireframe->bind(); @@ -232,9 +263,12 @@ void GLView::paintGL() m_program->setUniformValue(m_program_lightmap_only_location, m_lighmapOnly); m_program->setUniformValue(m_program_fullbright_location, m_fullbright); m_program->setUniformValue(m_program_drawnormals_location, m_drawNormals); - m_program->setUniformValue(m_program_showtris_location, m_showTris); m_program->setUniformValue(m_program_drawflat_location, m_drawFlat); + for (int i = 0; i < 256; i++) { + m_program->setUniformValue(m_program_style_scalars_location + i, 1.f); + } + // opaque draws for (auto &draw : m_drawcalls) { if (draw.opacity != 1.0f) @@ -316,6 +350,17 @@ void GLView::setKeepOrigin(bool keeporigin) m_keepOrigin = keeporigin; } +void GLView::setLightStyleIntensity(int style_id, int intensity) +{ + makeCurrent(); + m_program->bind(); + m_program->setUniformValue(m_program_style_scalars_location + style_id, intensity / 200.f); + m_program->release(); + doneCurrent(); + + update(); +} + void GLView::takeScreenshot(QString destPath, int w, int h) { // update aspect ratio @@ -347,12 +392,10 @@ void GLView::takeScreenshot(QString destPath, int w, int h) } void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries_t &bspx, - const std::vector &entities, const settings::common_settings &settings) + const std::vector &entities, const full_atlas_t &lightmap, const settings::common_settings &settings) { img::load_textures(&bsp, settings); - // build lightmap atlas - auto atlas = build_lightmap_atlas(bsp, bspx, false, true); auto facenormals = BSPX_FaceNormals(bsp, bspx); // NOTE: according to https://doc.qt.io/qt-6/qopenglwidget.html#resource-initialization-and-cleanup @@ -365,17 +408,32 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries m_vbo.allocate(0); m_indexBuffer.allocate(0); - // upload lightmap atlas + int32_t highest_depth = 0; + + for (auto &style : lightmap.style_to_lightmap_atlas) { + highest_depth = max(highest_depth, style.first); + } + + // upload lightmap atlases { - const auto &lm_tex = atlas.style_to_lightmap_atlas.at(0); + const auto &lm_tex = lightmap.style_to_lightmap_atlas.begin()->second; lightmap_texture = - std::make_unique(QImage(reinterpret_cast(lm_tex.pixels.data()), - lm_tex.width, lm_tex.height, QImage::Format_RGBA8888)); + std::make_unique(QOpenGLTexture::Target2DArray); + lightmap_texture->setSize(lm_tex.width, lm_tex.height); + lightmap_texture->setLayers(highest_depth + 1); lightmap_texture->setAutoMipMapGenerationEnabled(false); lightmap_texture->setMagnificationFilter(QOpenGLTexture::Linear); lightmap_texture->setMinificationFilter(QOpenGLTexture::Linear); + + lightmap_texture->setFormat(QOpenGLTexture::TextureFormat::RGBAFormat); + + lightmap_texture->allocateStorage(); + + for (auto &style : lightmap.style_to_lightmap_atlas) { + lightmap_texture->setData(0, style.first, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, reinterpret_cast(style.second.pixels.data())); + } } // this determines what can be batched together in a draw call @@ -463,6 +521,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries qvec2f lightmap_uv; qvec3f normal; qvec3f flat_color; + uint32_t styles; }; std::vector verts; std::vector indexBuffer; @@ -493,7 +552,7 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries const size_t first_vertex_of_face = verts.size(); - const auto lm_uvs = atlas.facenum_to_lightmap_uvs.at(fnum); + const auto lm_uvs = lightmap.facenum_to_lightmap_uvs.at(fnum); // output a vertex for each vertex of the face for (int j = 0; j < f->numedges; ++j) { @@ -513,11 +572,14 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries vertex_normal = plane_normal; } - verts.push_back({.pos = pos + model_offset, + verts.push_back({ + .pos = pos + model_offset, .uv = uv, .lightmap_uv = lightmap_uv, .normal = vertex_normal, - .flat_color = flat_color}); + .flat_color = flat_color, + .styles = (uint32_t) (f->styles[0]) | (uint32_t) (f->styles[1] << 8) | (uint32_t) (f->styles[2] << 16) | (uint32_t) (f->styles[3] << 24) + }); } // output the vertex indices for this face @@ -571,6 +633,11 @@ void GLView::renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries glVertexAttribPointer( 4 /* attrib */, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void *)offsetof(vertex_t, flat_color)); + // styles + glEnableVertexAttribArray(5 /* attrib */); + glVertexAttribIPointer( + 5 /* attrib */, 1, GL_UNSIGNED_INT, sizeof(vertex_t), (void *)offsetof(vertex_t, styles)); + doneCurrent(); // schedule repaint diff --git a/lightpreview/glview.h b/lightpreview/glview.h index 68e68fee..1a39e2a1 100644 --- a/lightpreview/glview.h +++ b/lightpreview/glview.h @@ -25,6 +25,7 @@ See file, 'COPYING', for details. #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ See file, 'COPYING', for details. #include #include #include +#include enum class keys_t : uint32_t { @@ -105,8 +107,8 @@ private: int m_program_lightmap_only_location = 0; int m_program_fullbright_location = 0; int m_program_drawnormals_location = 0; - int m_program_showtris_location = 0; int m_program_drawflat_location = 0; + int m_program_style_scalars_location = 0; // uniform locations (wireframe program) int m_program_wireframe_mvp_location = 0; @@ -116,7 +118,7 @@ public: ~GLView(); void renderBSP(const QString &file, const mbsp_t &bsp, const bspxentries_t &bspx, - const std::vector &entities, const settings::common_settings &settings); + const std::vector &entities, const full_atlas_t &lightmap, const settings::common_settings &settings); void setCamera(const qvec3d &origin, const qvec3d &fwd); void setLighmapOnly(bool lighmapOnly); void setFullbright(bool fullbright); @@ -124,6 +126,8 @@ public: void setShowTris(bool showtris); void setDrawFlat(bool drawflat); void setKeepOrigin(bool keeporigin); + // intensity = 0 to 200 + void setLightStyleIntensity(int style_id, int intensity); const bool &getKeepOrigin() const { return m_keepOrigin; } void takeScreenshot(QString destPath, int w, int h); @@ -136,6 +140,7 @@ protected: private: void startMovementTimer(); void stopMovementTimer(); + void handleLoggedMessage(const QOpenGLDebugMessage &debugMessage); protected: void mousePressEvent(QMouseEvent *event) override; diff --git a/lightpreview/mainwindow.cpp b/lightpreview/mainwindow.cpp index c1095be0..281ffc1d 100644 --- a/lightpreview/mainwindow.cpp +++ b/lightpreview/mainwindow.cpp @@ -37,11 +37,16 @@ See file, 'COPYING', for details. #include #include #include +#include +#include +#include +#include #include #include #include #include +#include #include "glview.h" @@ -92,6 +97,20 @@ MainWindow::MainWindow(QWidget *parent) formLayout->addRow(showtris); formLayout->addRow(keepposition); + lightstyles = new QVBoxLayout(); + + auto *lightstyles_group = new QGroupBox(tr("Lightstyles")); + lightstyles_group->setLayout(lightstyles); + + auto *scrollArea = new QScrollArea(); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(lightstyles_group); + scrollArea->setBackgroundRole(QPalette::Window); + scrollArea->setFrameShadow(QFrame::Plain); + scrollArea->setFrameShape(QFrame::NoFrame); + + formLayout->addRow(scrollArea); + auto *form = new QWidget(); form->setLayout(formLayout); @@ -310,6 +329,48 @@ void MainWindow::reload() loadFileInternal(m_mapFile, true); } +class QLightStyleSlider : public QFrame +{ +public: + int32_t style_id; + + QLightStyleSlider(int32_t style_id, GLView *glView) : + QFrame(), + style_id(style_id), + glView(glView) + { + auto *style_layout = new QHBoxLayout(); + + auto *style = new QSlider(Qt::Horizontal); + style->setRange(0, 200); + style->setValue(100); + style->setSingleStep(1); + style->setTickPosition(QSlider::TicksBothSides); + style->setTickInterval(50); + + connect(style, &QSlider::valueChanged, + this, &QLightStyleSlider::setValue); + + auto *style_label = new QLabel(); + style_label->setText(QString::asprintf("%i", style_id)); + + style_layout->addWidget(style_label); + style_layout->addWidget(style); + + setLayout(style_layout); + setFrameShadow(QFrame::Plain); + setFrameShape(QFrame::NoFrame); + } + +private: + void setValue(int value) + { + glView->setLightStyleIntensity(style_id, value); + } + + GLView *glView; +}; + void MainWindow::loadFileInternal(const QString &file, bool is_reload) { qDebug() << "loadFileInternal " << file; @@ -370,7 +431,10 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload) auto ents = EntData_Parse(bsp); - glView->renderBSP(file, bsp, d.bspx.entries, ents, render_settings); + // build lightmap atlas + auto atlas = build_lightmap_atlas(bsp, d.bspx.entries, false, true); + + glView->renderBSP(file, bsp, d.bspx.entries, ents, atlas, render_settings); if (!is_reload && !glView->getKeepOrigin()) { for (auto &ent : ents) { @@ -393,4 +457,17 @@ void MainWindow::loadFileInternal(const QString &file, bool is_reload) } } } + + // set lightstyle data + if (!is_reload) { + while ( QWidget* w = lightstyles->parentWidget()->findChild(QString(), Qt::FindDirectChildrenOnly) ) { + delete w; + } + + for (auto &style_entry : atlas.style_to_lightmap_atlas) { + + auto *style = new QLightStyleSlider(style_entry.first, glView); + lightstyles->addWidget(style); + } + } } \ No newline at end of file diff --git a/lightpreview/mainwindow.h b/lightpreview/mainwindow.h index f262493b..f0336ae4 100644 --- a/lightpreview/mainwindow.h +++ b/lightpreview/mainwindow.h @@ -20,6 +20,7 @@ See file, 'COPYING', for details. #pragma once #include +#include class GLView; class QFileSystemWatcher; @@ -61,4 +62,5 @@ private: QLineEdit *qbsp_options; QLineEdit *vis_options; QLineEdit *light_options; + QVBoxLayout *lightstyles; };