初步完成page的按需加载卸载

dev-VirtualTexture
wuyize 2023-02-23 22:18:52 +08:00
parent 063be364c2
commit b23d55e876
16 changed files with 256 additions and 137 deletions

View File

@ -70,6 +70,7 @@
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)ArchitectureColoredPainting\src\Editor\RightBar;$(SolutionDir)ArchitectureColoredPainting\src\Editor\;$(SolutionDir)FramelessHelper\include;$(SolutionDir)FramelessHelper\qmake\inc\core;$(SolutionDir)FramelessHelper\include\FramelessHelper\Core;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)include;$(SolutionDir)ArchitectureColoredPainting\src\Editor\RightBar;$(SolutionDir)ArchitectureColoredPainting\src\Editor\;$(SolutionDir)FramelessHelper\include;$(SolutionDir)FramelessHelper\qmake\inc\core;$(SolutionDir)FramelessHelper\include\FramelessHelper\Core;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>FRAMELESSHELPER_WIDGETS_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>FRAMELESSHELPER_WIDGETS_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level1</WarningLevel>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@ -171,6 +172,7 @@
<None Include="res\Shaders\model_shadow.frag" /> <None Include="res\Shaders\model_shadow.frag" />
<None Include="res\Shaders\model_shadow.geom" /> <None Include="res\Shaders\model_shadow.geom" />
<None Include="res\Shaders\model_shadow.vert" /> <None Include="res\Shaders\model_shadow.vert" />
<None Include="res\Shaders\pageId_downsample.comp" />
<None Include="res\Shaders\painting.comp" /> <None Include="res\Shaders\painting.comp" />
<None Include="res\Shaders\painting.frag" /> <None Include="res\Shaders\painting.frag" />
<None Include="res\Shaders\painting.vert" /> <None Include="res\Shaders\painting.vert" />

View File

@ -326,6 +326,9 @@
<None Include="res\Shaders\brdf_lut.comp"> <None Include="res\Shaders\brdf_lut.comp">
<Filter>Resource Files\Shaders</Filter> <Filter>Resource Files\Shaders</Filter>
</None> </None>
<None Include="res\Shaders\pageId_downsample.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtUic Include="EditorWidget.ui"> <QtUic Include="EditorWidget.ui">

View File

@ -31,6 +31,7 @@
<file>Shaders/irradiance_convolution.frag</file> <file>Shaders/irradiance_convolution.frag</file>
<file>Shaders/cubemap_prefilter.frag</file> <file>Shaders/cubemap_prefilter.frag</file>
<file>Shaders/brdf_lut.comp</file> <file>Shaders/brdf_lut.comp</file>
<file>Shaders/pageId_downsample.comp</file>
</qresource> </qresource>
<qresource prefix="/qt/etc"> <qresource prefix="/qt/etc">
<file>qt.conf</file> <file>qt.conf</file>

View File

@ -9,7 +9,7 @@ layout (location = 0) out vec4 gBaseColor;
layout (location = 1) out vec3 gNormal; layout (location = 1) out vec3 gNormal;
layout (location = 2) out vec3 gPosition; layout (location = 2) out vec3 gPosition;
layout (location = 3) out vec2 gMetallicRoughness; layout (location = 3) out vec2 gMetallicRoughness;
layout (location = 4) out uint gPaintingIndex; layout (location = 4) out uvec2 gPaintingIndex;
in vec2 TexCoords; in vec2 TexCoords;
in vec3 WorldPos; in vec3 WorldPos;
@ -52,6 +52,6 @@ void main()
else else
gMetallicRoughness = vec2(0,1); gMetallicRoughness = vec2(0,1);
gPaintingIndex = 0; gPaintingIndex = uvec2(0);
} }

View File

@ -1,4 +1,5 @@
#version 450 core #version 450 core
#extension GL_ARB_sparse_texture2 : enable
uniform sampler2D texture_basecolor; uniform sampler2D texture_basecolor;
@ -6,8 +7,11 @@ in vec2 TexCoords;
void main() void main()
{ {
//gBaseColor = vec4(1,0,0,1); vec4 baseColor;// = texture(texture_basecolor, TexCoords);
vec4 baseColor = texture(texture_basecolor, TexCoords); float lod = textureQueryLod(texture_basecolor, TexCoords).x;
while(!sparseTexelsResidentARB(sparseTextureLodARB(texture_basecolor, TexCoords, lod, baseColor))&&lod<textureQueryLevels(texture_basecolor))
lod++;
if(baseColor.a<0.4) if(baseColor.a<0.4)
discard; discard;
} }

View File

@ -0,0 +1,14 @@
#version 450 core
layout (local_size_x = 8, local_size_y = 8) in;
layout(rg16ui, binding = 3) uniform uimage2D gPageId;
uniform uvec2 dither = uvec2(0);
void main()
{
uvec2 targetLocation = gl_GlobalInvocationID.xy;
uvec2 sourceLocation = targetLocation * 8 + dither;
imageStore(gPageId, ivec2(targetLocation), uvec4(imageLoad(gPageId, ivec2(sourceLocation))));
}

View File

@ -4,11 +4,13 @@
uniform sampler2D texture_basecolor; uniform sampler2D texture_basecolor;
uniform sampler2D texture_metallic_roughness; uniform sampler2D texture_metallic_roughness;
uniform uint paintingId;
layout(location = 0) out vec4 gBaseColor; layout(location = 0) out vec4 gBaseColor;
layout(location = 1) out vec3 gNormal; layout(location = 1) out vec3 gNormal;
layout(location = 2) out vec3 gPosition; layout(location = 2) out vec3 gPosition;
layout(location = 3) out vec2 gMetallicRoughness; layout(location = 3) out vec2 gMetallicRoughness;
layout(location = 4) out uint gPaintingIndex; layout(location = 4) out uvec2 gPaintingIndex;
layout(location = 5) out vec2 gPaintingTexCoord; layout(location = 5) out vec2 gPaintingTexCoord;
in vec2 TexCoords; in vec2 TexCoords;
@ -17,24 +19,36 @@ in vec3 Normal;
void main() void main()
{ {
float lod = textureQueryLod(texture_basecolor, TexCoords).x; int lodExpect = int(textureQueryLod(texture_basecolor, TexCoords).x);
while(!sparseTexelsResidentARB(sparseTextureLodARB(texture_basecolor, TexCoords, lod, gBaseColor))&&lod<textureQueryLevels(texture_basecolor)) int levels = textureQueryLevels(texture_basecolor);
float lod = lodExpect;
while(!sparseTexelsResidentARB(sparseTextureLodARB(texture_basecolor, TexCoords, lod, gBaseColor))&&lod<levels)
lod++; lod++;
if(gBaseColor.a<0.4) if(gBaseColor.a<0.4)
discard; discard;
//gBaseColor = vec4( vec3(1),1 ); //gBaseColor = vec4( vec3(1),1 );
// mainImage(gBaseColor, vec2(1.,1.)-TexCoords);
gPosition = WorldPos; gPosition = WorldPos;
gNormal = normalize(Normal); gNormal = normalize(Normal);
//gMetallicRoughness = vec2(0,1); //gMetallicRoughness = vec2(0,1);
lod = textureQueryLod(texture_metallic_roughness, TexCoords).x; lod = lodExpect;
vec4 mt; vec4 mt;
while(!sparseTexelsResidentARB(sparseTextureLodARB(texture_metallic_roughness, TexCoords, lod, mt))&&lod<textureQueryLevels(texture_metallic_roughness)) while(!sparseTexelsResidentARB(sparseTextureLodARB(texture_metallic_roughness, TexCoords, lod, mt))&&lod<levels)
lod++; lod++;
gMetallicRoughness = mt.rg; gMetallicRoughness = mt.rg;
//gPaintingIndex = 1;
gPaintingIndex = 0; // int pageSize = textureSize(texture_basecolor, levels-1).x;
// uint pageId = 0;
// for(uint i = 0; i < lodExpect; i++)
// pageId += 1<<(2*(levels-1-i));
uint w = 1<<(levels-1-lodExpect);
ivec2 page = ivec2(TexCoords * vec2(w));
page = clamp(page, ivec2(0), ivec2(w-1));
// pageId += page.y*w+page.x;
if(lodExpect==levels-1)
gPaintingIndex = uvec2(0);
else
gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x);
gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2; gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2;
return; return;

View File

@ -22,12 +22,9 @@ void Mesh::draw()
{ {
if (shaderProgram->bind()) if (shaderProgram->bind())
{ {
glFunc->glActiveTexture(GL_TEXTURE0); glFunc->glBindTextureUnit(0, textureBasecolor);
glFunc->glBindTexture(GL_TEXTURE_2D, textureBasecolor); glFunc->glBindTextureUnit(1, textureMetallicRoughness);
glFunc->glActiveTexture(GL_TEXTURE1); glFunc->glBindTextureUnit(2, textureNormal);
glFunc->glBindTexture(GL_TEXTURE_2D, textureMetallicRoughness);
glFunc->glActiveTexture(GL_TEXTURE2);
glFunc->glBindTexture(GL_TEXTURE_2D, textureNormal);
shaderProgram->setUniformValue("texture_basecolor", 0); shaderProgram->setUniformValue("texture_basecolor", 0);
shaderProgram->setUniformValue("texture_metallic_roughness", 1); shaderProgram->setUniformValue("texture_metallic_roughness", 1);
shaderProgram->setUniformValue("texture_normal", 2); shaderProgram->setUniformValue("texture_normal", 2);
@ -44,8 +41,7 @@ void Mesh::drawShadow()
{ {
if (shadowProgram->bind()) if (shadowProgram->bind())
{ {
glFunc->glActiveTexture(GL_TEXTURE0); glFunc->glBindTextureUnit(0, textureBasecolor);
glFunc->glBindTexture(GL_TEXTURE_2D, textureBasecolor);
shadowProgram->setUniformValue("texture_basecolor", 0); shadowProgram->setUniformValue("texture_basecolor", 0);
QOpenGLVertexArrayObject::Binder bind(&VAO); QOpenGLVertexArrayObject::Binder bind(&VAO);

View File

@ -148,8 +148,8 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
} }
} }
m_mesh->paintingIndex = loadPainting(std::string(str.C_Str())); m_mesh->paintingId = loadPainting(std::string(str.C_Str()));
auto& handle = vtManager->paintings[m_mesh->paintingIndex]; auto& handle = vtManager->getPaintingHandle(m_mesh->paintingId);
m_mesh->textureBasecolor = handle.baseColor; m_mesh->textureBasecolor = handle.baseColor;
m_mesh->textureMetallicRoughness = handle.metallicRoughness; m_mesh->textureMetallicRoughness = handle.metallicRoughness;
m_mesh->setupMesh(); m_mesh->setupMesh();

View File

@ -13,15 +13,14 @@ void PaintingMesh::draw()
{ {
if (shaderProgram->bind()) if (shaderProgram->bind())
{ {
glFunc->glActiveTexture(GL_TEXTURE0); glFunc->glBindTextureUnit(0, textureBasecolor);
glFunc->glBindTexture(GL_TEXTURE_2D, textureBasecolor); glFunc->glBindTextureUnit(1, textureMetallicRoughness);
glFunc->glActiveTexture(GL_TEXTURE1);
glFunc->glBindTexture(GL_TEXTURE_2D, textureMetallicRoughness);
shaderProgram->setUniformValue("texture_basecolor", 0); shaderProgram->setUniformValue("texture_basecolor", 0);
shaderProgram->setUniformValue("texture_metallic_roughness", 1); shaderProgram->setUniformValue("texture_metallic_roughness", 1);
QOpenGLVertexArrayObject::Binder bind(&VAO); QOpenGLVertexArrayObject::Binder bind(&VAO);
shaderProgram->setUniformValue("model", model); shaderProgram->setUniformValue("model", model);
glFunc->glUniform1ui(glFunc->glGetUniformLocation(shaderProgram->programId(), "paintingId"), paintingId);
EBO.bind(); EBO.bind();
glFunc->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); glFunc->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
shaderProgram->release(); shaderProgram->release();
@ -31,6 +30,8 @@ void PaintingMesh::drawShadow()
{ {
if (shadowProgram->bind()) if (shadowProgram->bind())
{ {
glFunc->glBindTextureUnit(0, textureBasecolor);
shadowProgram->setUniformValue("texture_basecolor", 0);
QOpenGLVertexArrayObject::Binder bind(&VAO); QOpenGLVertexArrayObject::Binder bind(&VAO);
shadowProgram->setUniformValue("model", model); shadowProgram->setUniformValue("model", model);
EBO.bind(); EBO.bind();

View File

@ -25,7 +25,7 @@ namespace Renderer
QMatrix4x4 model; QMatrix4x4 model;
QOpenGLFunctions_4_5_Compatibility* glFunc; QOpenGLFunctions_4_5_Compatibility* glFunc;
QOpenGLShaderProgram* shaderProgram, * shadowProgram; QOpenGLShaderProgram* shaderProgram, * shadowProgram;
GLuint paintingIndex; GLuint paintingId;
PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model); PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model);
void draw() override; void draw() override;

View File

@ -10,6 +10,7 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "IblUtils.h" #include "IblUtils.h"
#include "VirtualTextureManager.h" #include "VirtualTextureManager.h"
#include <QDebug>
using namespace Renderer; using namespace Renderer;
@ -101,16 +102,34 @@ void Renderer::RendererGLWidget::setExposure(float exposure)
QOpenGLTexture randomMap(QOpenGLTexture::Target2D); QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
void GLAPIENTRY MessageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam)
{
//fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
// (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
// type, severity, message);
if (type == GL_DEBUG_TYPE_ERROR)
qCritical() << QString::fromStdString(std::format("GL_ERROR: type = {:#x}, severity = {:#x}, message = {}",
type, severity, message));
}
void RendererGLWidget::initializeGL() void RendererGLWidget::initializeGL()
{ {
gl = std::make_unique<GladGLContext>(); gl = std::make_unique<GladGLContext>();
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)QOpenGLContext::currentContext()->getProcAddress(name); })) if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)QOpenGLContext::currentContext()->getProcAddress(name); }))
qDebug() << "Failed to initialize GLAD"; qCritical() << "Failed to initialize GLAD";
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>(); QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
qDebug() << "GL_VERSION" << (char*)gl->GetString(GL_VERSION); qDebug() << "GL_VERSION" << (char*)gl->GetString(GL_VERSION);
gl->Enable(GL_DEBUG_OUTPUT);
gl->DebugMessageCallback(MessageCallback, 0);
gl->Enable(GL_DEPTH_TEST); gl->Enable(GL_DEPTH_TEST);
gl->DepthFunc(GL_LEQUAL); gl->DepthFunc(GL_LEQUAL);
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
@ -118,83 +137,83 @@ void RendererGLWidget::initializeGL()
shadowProgramPtr = new QOpenGLShaderProgram; shadowProgramPtr = new QOpenGLShaderProgram;
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert")) if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert"))
qDebug() << "ERROR:" << shadowProgramPtr->log(); qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Geometry, ":/Shaders/model_shadow.geom")) if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Geometry, ":/Shaders/model_shadow.geom"))
qDebug() << "ERROR:" << shadowProgramPtr->log(); qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag")) if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag"))
qDebug() << "ERROR:" << shadowProgramPtr->log(); qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->link()) if (!shadowProgramPtr->link())
qDebug() << "ERROR:" << shadowProgramPtr->log(); qCritical() << "ERROR:" << shadowProgramPtr->log();
plainProgramPtr = new QOpenGLShaderProgram; plainProgramPtr = new QOpenGLShaderProgram;
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/shader.vert")) if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/shader.vert"))
qDebug() << "ERROR:" << plainProgramPtr->log(); qCritical() << "ERROR:" << plainProgramPtr->log();
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/shader.frag")) if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/shader.frag"))
qDebug() << "ERROR:" << plainProgramPtr->log(); qCritical() << "ERROR:" << plainProgramPtr->log();
if (!plainProgramPtr->link()) if (!plainProgramPtr->link())
qDebug() << "ERROR:" << plainProgramPtr->log(); qCritical() << "ERROR:" << plainProgramPtr->log();
modelProgramPtr = new QOpenGLShaderProgram; modelProgramPtr = new QOpenGLShaderProgram;
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert")) if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert"))
qDebug() << "ERROR:" << modelProgramPtr->log(); qCritical() << "ERROR:" << modelProgramPtr->log();
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model.frag")) if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model.frag"))
qDebug() << "ERROR:" << modelProgramPtr->log(); qCritical() << "ERROR:" << modelProgramPtr->log();
if (!modelProgramPtr->link()) if (!modelProgramPtr->link())
qDebug() << "ERROR:" << modelProgramPtr->log(); qCritical() << "ERROR:" << modelProgramPtr->log();
paintingProgramPtr = new QOpenGLShaderProgram; paintingProgramPtr = new QOpenGLShaderProgram;
if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/painting.vert")) if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/painting.vert"))
qDebug() << "ERROR:" << paintingProgramPtr->log(); qCritical() << "ERROR:" << paintingProgramPtr->log();
if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/painting.frag")) if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/painting.frag"))
qDebug() << "ERROR:" << paintingProgramPtr->log(); qCritical() << "ERROR:" << paintingProgramPtr->log();
if (!paintingProgramPtr->link()) if (!paintingProgramPtr->link())
qDebug() << "ERROR:" << paintingProgramPtr->log(); qCritical() << "ERROR:" << paintingProgramPtr->log();
paintingCompProgramPtr = new QOpenGLShaderProgram; pageIdDownsampleProgramPtr = new QOpenGLShaderProgram;
if (!paintingCompProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/painting.comp")) if (!pageIdDownsampleProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/pageId_downsample.comp"))
qDebug() << "ERROR:" << paintingCompProgramPtr->log(); qCritical() << "ERROR:" << pageIdDownsampleProgramPtr->log();
if (!paintingCompProgramPtr->link()) if (!pageIdDownsampleProgramPtr->link())
qDebug() << "ERROR:" << paintingCompProgramPtr->log(); qCritical() << "ERROR:" << pageIdDownsampleProgramPtr->log();
depthInitProgramPtr = new QOpenGLShaderProgram; depthInitProgramPtr = new QOpenGLShaderProgram;
if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp")) if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp"))
qDebug() << "ERROR:" << depthInitProgramPtr->log(); qCritical() << "ERROR:" << depthInitProgramPtr->log();
if (!depthInitProgramPtr->link()) if (!depthInitProgramPtr->link())
qDebug() << "ERROR:" << depthInitProgramPtr->log(); qCritical() << "ERROR:" << depthInitProgramPtr->log();
depthMipmapProgramPtr = new QOpenGLShaderProgram; depthMipmapProgramPtr = new QOpenGLShaderProgram;
if (!depthMipmapProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_mipmap.comp")) if (!depthMipmapProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_mipmap.comp"))
qDebug() << "ERROR:" << depthMipmapProgramPtr->log(); qCritical() << "ERROR:" << depthMipmapProgramPtr->log();
if (!depthMipmapProgramPtr->link()) if (!depthMipmapProgramPtr->link())
qDebug() << "ERROR:" << depthMipmapProgramPtr->log(); qCritical() << "ERROR:" << depthMipmapProgramPtr->log();
shadowMappingProgramPtr = new QOpenGLShaderProgram; shadowMappingProgramPtr = new QOpenGLShaderProgram;
if (!shadowMappingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/shadow_mapping.comp")) if (!shadowMappingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/shadow_mapping.comp"))
qDebug() << "ERROR:" << shadowMappingProgramPtr->log(); qCritical() << "ERROR:" << shadowMappingProgramPtr->log();
if (!shadowMappingProgramPtr->link()) if (!shadowMappingProgramPtr->link())
qDebug() << "ERROR:" << shadowMappingProgramPtr->log(); qCritical() << "ERROR:" << shadowMappingProgramPtr->log();
ssgiProgramPtr = new QOpenGLShaderProgram; ssgiProgramPtr = new QOpenGLShaderProgram;
if (!ssgiProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/ssgi.comp")) if (!ssgiProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/ssgi.comp"))
qDebug() << "ERROR:" << ssgiProgramPtr->log(); qCritical() << "ERROR:" << ssgiProgramPtr->log();
if (!ssgiProgramPtr->link()) if (!ssgiProgramPtr->link())
qDebug() << "ERROR:" << ssgiProgramPtr->log(); qCritical() << "ERROR:" << ssgiProgramPtr->log();
finalProgramPtr = new QOpenGLShaderProgram; finalProgramPtr = new QOpenGLShaderProgram;
if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/final.vert")) if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/final.vert"))
qDebug() << "ERROR:" << finalProgramPtr->log(); qCritical() << "ERROR:" << finalProgramPtr->log();
if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/final.frag")) if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/final.frag"))
qDebug() << "ERROR:" << finalProgramPtr->log(); qCritical() << "ERROR:" << finalProgramPtr->log();
if (!finalProgramPtr->link()) if (!finalProgramPtr->link())
qDebug() << "ERROR:" << finalProgramPtr->log(); qCritical() << "ERROR:" << finalProgramPtr->log();
skyBoxProgramPtr = new QOpenGLShaderProgram; skyBoxProgramPtr = new QOpenGLShaderProgram;
if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/skybox.vert")) if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/skybox.vert"))
qDebug() << "ERROR:" << skyBoxProgramPtr->log(); qCritical() << "ERROR:" << skyBoxProgramPtr->log();
if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/skybox.frag")) if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/skybox.frag"))
qDebug() << "ERROR:" << skyBoxProgramPtr->log(); qCritical() << "ERROR:" << skyBoxProgramPtr->log();
if (!skyBoxProgramPtr->link()) if (!skyBoxProgramPtr->link())
qDebug() << "ERROR:" << skyBoxProgramPtr->log(); qCritical() << "ERROR:" << skyBoxProgramPtr->log();
shadowProgramPtr->bind(); shadowProgramPtr->bind();
gl->GenBuffers(1, &lightSpaceMatricesUBO); gl->GenBuffers(1, &lightSpaceMatricesUBO);
@ -271,6 +290,11 @@ void RendererGLWidget::initializeGL()
void RendererGLWidget::paintGL() void RendererGLWidget::paintGL()
{ {
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>(); QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
GLuint timeQuery;
gl->GenQueries(1, &timeQuery);
gl->BeginQuery(GL_TIME_ELAPSED, timeQuery);
gl->Enable(GL_CULL_FACE); gl->Enable(GL_CULL_FACE);
@ -342,40 +366,35 @@ void RendererGLWidget::paintGL()
} }
plainProgramPtr->release(); plainProgramPtr->release();
pageIdDownsampleProgramPtr->bind();
gl->BindImageTexture(3, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16UI);
gl->DispatchCompute(ceil(frameWidth / 8. / 8.), ceil(frameWidth / 8. / 8.), 1);
pageIdDownsampleProgramPtr->release();
std::vector<glm::u16vec2> pixels;
pixels.resize(ceil(frameWidth / 8.) * ceil(frameHeight / 8.));
gl->ReadBuffer(GL_COLOR_ATTACHMENT4);
gl->ReadnPixels(0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
vtManager->updatePages(pixels);
fboPtr->release(); fboPtr->release();
} }
GLuint paintingCompQuery; //depthInitProgramPtr->bind();
gl->GenQueries(1, &paintingCompQuery); //gl->ActiveTexture(GL_TEXTURE0);
gl->BeginQuery(GL_TIME_ELAPSED, paintingCompQuery); //gl->BindTexture(GL_TEXTURE_2D, gbuffers[6]);
//gl->BindImageTexture(0, gbuffers[7], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
//gl->DispatchCompute(ceil(depthWidth / 8.), ceil(depthHeight / 8.), 1);
//depthInitProgramPtr->release();
paintingCompProgramPtr->bind(); //depthMipmapProgramPtr->bind();
gl->BindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); //for (int i = 0; i <= 3; i++)
gl->BindImageTexture(1, gbuffers[3], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG8); // gl->BindImageTexture(i, gbuffers[7], i, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
gl->BindImageTexture(2, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16UI); //gl->DispatchCompute(ceil(depthWidth / 2. / 8.), ceil(depthHeight / 2. / 8.), 1);
gl->BindImageTexture(3, gbuffers[5], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG32F); //for (int i = 0; i <= 3; i++)
// gl->BindImageTexture(i, gbuffers[7], i + 3, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
//gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1); //gl->DispatchCompute(ceil(depthWidth / 2. / 8. / 8.), ceil(depthHeight / 2. / 8. / 8.), 1);
paintingCompProgramPtr->release(); //depthMipmapProgramPtr->release();
gl->EndQuery(GL_TIME_ELAPSED);
depthInitProgramPtr->bind();
gl->ActiveTexture(GL_TEXTURE0);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[6]);
gl->BindImageTexture(0, gbuffers[7], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
gl->DispatchCompute(ceil(depthWidth / 8.), ceil(depthHeight / 8.), 1);
depthInitProgramPtr->release();
depthMipmapProgramPtr->bind();
for (int i = 0; i <= 3; i++)
gl->BindImageTexture(i, gbuffers[7], i, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
gl->DispatchCompute(ceil(depthWidth / 2. / 8.), ceil(depthHeight / 2. / 8.), 1);
for (int i = 0; i <= 3; i++)
gl->BindImageTexture(i, gbuffers[7], i + 3, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
gl->DispatchCompute(ceil(depthWidth / 2. / 8. / 8.), ceil(depthHeight / 2. / 8. / 8.), 1);
depthMipmapProgramPtr->release();
shadowMappingProgramPtr->bind(); shadowMappingProgramPtr->bind();
shadowMappingProgramPtr->setUniformValue("view", view); shadowMappingProgramPtr->setUniformValue("view", view);
@ -388,22 +407,15 @@ void RendererGLWidget::paintGL()
shadowMappingProgramPtr->setUniformValue("camPos", camera.Position); shadowMappingProgramPtr->setUniformValue("camPos", camera.Position);
shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection); shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
shadowMappingProgramPtr->setUniformValue("mainLightRadiance", mainLightRadiance); shadowMappingProgramPtr->setUniformValue("mainLightRadiance", mainLightRadiance);
/*gl->ActiveTexture(GL_TEXTURE0);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);*/ gl->BindTextureUnit(1, gbuffers[1]);
gl->ActiveTexture(GL_TEXTURE1); gl->BindTextureUnit(2, gbuffers[2]);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[1]); gl->BindTextureUnit(3, gbuffers[3]);
gl->ActiveTexture(GL_TEXTURE2); gl->BindTextureUnit(4, shadowGbuffer);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[2]); gl->BindTextureUnit(5, irradianceMap);
gl->ActiveTexture(GL_TEXTURE3); gl->BindTextureUnit(6, prefilterMap);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[3]); gl->BindTextureUnit(7, brdfLUTTexture);
gl->ActiveTexture(GL_TEXTURE4);
gl->BindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
gl->ActiveTexture(GL_TEXTURE5);
gl->BindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap);
gl->ActiveTexture(GL_TEXTURE6);
gl->BindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap);
gl->ActiveTexture(GL_TEXTURE7);
gl->BindTexture(GL_TEXTURE_2D, brdfLUTTexture);
gl->BindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); gl->BindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->BindImageTexture(1, gbuffers[8], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F); gl->BindImageTexture(1, gbuffers[8], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F);
gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1); gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
@ -435,11 +447,9 @@ void RendererGLWidget::paintGL()
gl->Viewport(0, 0, frameWidth, frameHeight); gl->Viewport(0, 0, frameWidth, frameHeight);
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
finalProgramPtr->bind(); finalProgramPtr->bind();
finalProgramPtr->setUniformValue("exposure", exposure); finalProgramPtr->setUniformValue("exposure", exposure);
gl->ActiveTexture(GL_TEXTURE0); gl->BindTextureUnit(0, gbuffers[0]);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);
quadVAO.bind(); quadVAO.bind();
gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
quadVAO.release(); quadVAO.release();
@ -450,28 +460,29 @@ void RendererGLWidget::paintGL()
skyBoxProgramPtr->setUniformValue("view", view); skyBoxProgramPtr->setUniformValue("view", view);
skyBoxProgramPtr->setUniformValue("projection", projection); skyBoxProgramPtr->setUniformValue("projection", projection);
skyBoxProgramPtr->setUniformValue("exposure", exposure); skyBoxProgramPtr->setUniformValue("exposure", exposure);
gl->ActiveTexture(GL_TEXTURE0); gl->BindTextureUnit(0, skyCubemap);
gl->BindTexture(GL_TEXTURE_CUBE_MAP, skyCubemap);
IblUtils::renderCube(glFunc); IblUtils::renderCube(glFunc);
skyBoxProgramPtr->release(); skyBoxProgramPtr->release();
GLuint paintingCompDuration; gl->EndQuery(GL_TIME_ELAPSED);
gl->GetQueryObjectuiv(paintingCompQuery, GL_QUERY_RESULT, &paintingCompDuration); GLuint frameDuration;
gl->GetQueryObjectuiv(timeQuery, GL_QUERY_RESULT, &frameDuration);
clock_t currentFrame = std::clock(); clock_t currentFrame = std::clock();
deltaTime = (float)(currentFrame - lastFrame) / CLOCKS_PER_SEC; deltaTime = (float)(currentFrame - lastFrame) / CLOCKS_PER_SEC;
lastFrame = currentFrame; lastFrame = currentFrame;
static float accTime = 0, frameCnt = 0; static float accTime = 0, frameCnt = 0, averageDuration = 0;
accTime += deltaTime; accTime += deltaTime;
frameCnt++; frameCnt++;
averageDuration += frameDuration;
if (accTime > 1.) if (accTime > 1.)
{ {
std::cout << std::format("{:20}\r", ""); std::cout << std::format("{:20}\r", "");
std::cout << std::format("FPS: {:.2f} Painting: {}ms Pos: {},{},{}\r", frameCnt / accTime, paintingCompDuration / 1e6, camera.Position.x(), camera.Position.y(), camera.Position.z()); std::cout << std::format("FPS: {:.2f}({:.2f}ms) Pos: {:.2f},{:.2f},{:.2f}\r", frameCnt / accTime, averageDuration / 1e6 / frameCnt, camera.Position.x(), camera.Position.y(), camera.Position.z());
//std::cout << "FPS: " << frameCnt / accTime << " " << camera.Position.x() << " " << camera.Position.y() << " " << camera.Position.z() << "\r";
accTime = 0; accTime = 0;
frameCnt = 0; frameCnt = 0;
averageDuration = 0;
} }
if (pressedKeys.contains(Qt::Key_W)) { if (pressedKeys.contains(Qt::Key_W)) {
@ -536,7 +547,7 @@ void RendererGLWidget::resizeGL(int width, int height)
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffers[3], 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffers[3], 0);
//gPaintingIndex //gPaintingIndex
gl->BindTexture(GL_TEXTURE_2D, gbuffers[4]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[4]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, frameWidth, frameHeight, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG16UI, frameWidth, frameHeight, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, gbuffers[4], 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, gbuffers[4], 0);

View File

@ -59,7 +59,7 @@ namespace Renderer
QOpenGLShaderProgram* plainProgramPtr = nullptr; QOpenGLShaderProgram* plainProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr; QOpenGLShaderProgram* modelProgramPtr = nullptr;
QOpenGLShaderProgram* paintingProgramPtr = nullptr; QOpenGLShaderProgram* paintingProgramPtr = nullptr;
QOpenGLShaderProgram* paintingCompProgramPtr = nullptr; QOpenGLShaderProgram* pageIdDownsampleProgramPtr = nullptr;
QOpenGLShaderProgram* depthInitProgramPtr = nullptr; QOpenGLShaderProgram* depthInitProgramPtr = nullptr;
QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr; QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr;
QOpenGLShaderProgram* shadowMappingProgramPtr = nullptr; QOpenGLShaderProgram* shadowMappingProgramPtr = nullptr;

View File

@ -47,7 +47,7 @@ Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* gl)
} }
GLuint Renderer::VirtualTextureManager::createVirtualTexture(Painting painting) std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting painting)
{ {
const GLsizei levels = glm::log2(textureSize / pageSize) + 1; const GLsizei levels = glm::log2(textureSize / pageSize) + 1;
qDebug() << "levels:" << levels; qDebug() << "levels:" << levels;
@ -103,6 +103,66 @@ GLuint Renderer::VirtualTextureManager::createVirtualTexture(Painting painting)
} }
} }
paintings.emplace_back(baseColor, metallicRoughness, painting.buffers); paintings.emplace_back(baseColor, metallicRoughness, painting.buffers);
return paintings.size();
return paintings.size() - 1; }
Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std::uint16_t id)
{
return paintings[id - 1];
}
void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pageId, GLboolean commit)
{
auto& painting = getPaintingHandle(pageId.x >> 4);
GLint level = pageId.x & 0b1111;
glm::ivec2 page(pageId.y & 0b11111111, pageId.y >> 8);
qDebug() << commit << level << page.x << page.y;
gl->TexturePageCommitmentEXT(painting.baseColor, level,
static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y, 0,
static_cast<GLsizei>(pageSize), static_cast<GLsizei>(pageSize), 1,
commit);
gl->TexturePageCommitmentEXT(painting.metallicRoughness, level,
static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y, 0,
static_cast<GLsizei>(pageSize), static_cast<GLsizei>(pageSize), 1,
commit);
if (commit)
{
program.bind();
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
gl->DispatchCompute(pageSize / 8, pageSize / 8, 1);
program.release();
}
}
void Renderer::VirtualTextureManager::updatePages(const std::vector<glm::u16vec2>& pageIds)
{
for (auto iter = loadedPages.begin(); iter != loadedPages.end();)
{
iter->second--;
if (iter->second == 0)
{
pageCommitmentById(iter->first, GL_FALSE);
iter = loadedPages.erase(iter);
}
else
iter++;
}
for (auto& pageId : pageIds)
{
if (pageId.x)
{
auto [iter, success] = loadedPages.emplace(pageId, lifeTime);
if (success)
{
pageCommitmentById(pageId, GL_TRUE);
}
else
iter->second = lifeTime;
}
}
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Painting/Painting.h" #include "Painting/Painting.h"
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <unordered_map>
struct GladGLContext; struct GladGLContext;
@ -16,22 +17,35 @@ namespace Renderer
class VirtualTextureManager class VirtualTextureManager
{ {
public: public:
static constexpr GLsizei textureSize = 16384;
std::vector<PaintingHandle> paintings;
VirtualTextureManager(GladGLContext* gl); VirtualTextureManager(GladGLContext* gl);
/** /**
* @brief * @brief
* @param painting * @param painting
* @return paintings * @return ÐéÄâÎÆÀíid
*/ */
GLuint createVirtualTexture(Painting painting); std::uint16_t createVirtualTexture(Painting painting);
PaintingHandle& getPaintingHandle(std::uint16_t id);
void updatePages(const std::vector<glm::u16vec2>& pageIds);
private: private:
GladGLContext* gl; GladGLContext* gl;
static constexpr GLsizei textureSize = 16384;
static constexpr int lifeTime = 64;
GLint pageSize; GLint pageSize;
QOpenGLShaderProgram program; QOpenGLShaderProgram program;
std::vector<PaintingHandle> paintings;
struct u16vec2Hash
{
std::size_t operator()(glm::u16vec2 const& v) const
{
return ((std::size_t)v.y << 16) + v.x;
}
};
std::unordered_map<glm::u16vec2, int, u16vec2Hash> loadedPages;
void pageCommitmentById(const glm::u16vec2& pageId, GLboolean commit);
}; };
} }

View File

@ -27,12 +27,11 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
break; break;
case QtCriticalMsg: case QtCriticalMsg:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
break;
case QtFatalMsg:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);
break; break;
case QtFatalMsg:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_RED);
break;
} }
std::cout << std::format("{}({},{}) {}\n", std::cout << std::format("{}({},{}) {}\n",
QString(context.file).splitRef("\\").back().toLocal8Bit().data(), QString(context.file).splitRef("\\").back().toLocal8Bit().data(),