cnq3/code/renderer/crp_sun_editor.cpp
myT 30150e889e added sunlight and volumetric lighting
fixed depth linearization
2024-03-29 04:19:38 +01:00

210 lines
5 KiB
C++

/*
===========================================================================
Copyright (C) 2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3).
Challenge Quake 3 is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Challenge Quake 3 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
===========================================================================
*/
// Cinematic Rendering Pipeline - sunlight editor
#include "crp_local.h"
#include "../client/cl_imgui.h"
#include "compshaders/crp/fullscreen.h"
#include "compshaders/crp/sun_overlay.h"
#pragma pack(push, 4)
struct SunOverlayRC
{
vec3_t direction;
float angle;
vec3_t color;
float padding;
float textureWidth;
float textureHeight;
};
#pragma pack(pop)
static bool LoadSunFile(const char* filePath)
{
bool success = false;
void* data = NULL;
if(ri.FS_ReadFile(filePath, &data) == sizeof(crp.sunlightData) &&
data != NULL)
{
memcpy(&crp.sunlightData, data, sizeof(crp.sunlightData));
success = true;
}
if(data != NULL)
{
ri.FS_FreeFile(data);
}
return success;
}
static void SaveSunFile(const char* filePath)
{
FS_EnableCNQ3FolderWrites(qtrue);
ri.FS_WriteFile(filePath, &crp.sunlightData, sizeof(crp.sunlightData));
FS_EnableCNQ3FolderWrites(qfalse);
}
static void LoadSunFromShader(const shader_t* skyShader)
{
vec2_t angles;
angles[0] = DEG2RAD(skyShader->sunAzimuth);
angles[1] = DEG2RAD(skyShader->sunInclination);
VectorCopy(skyShader->sunColor, crp.sunlightData.color);
crp.sunlightData.intensity = 1.0f;
AzimuthInclinationToDirection(crp.sunlightData.direction, angles);
}
void DirectionToAzimuthInclination(float* sc, const float* dir)
{
// 0=azimuth/phi, 1=inclination/theta
sc[0] = atan2f(dir[1], dir[0]);
sc[1] = atan2f(sqrtf(dir[0] * dir[0] + dir[1] * dir[1]), dir[2]);
}
void AzimuthInclinationToDirection(float* dir, const float* sc)
{
// 0=azimuth/phi, 1=inclination/theta
dir[0] = sinf(sc[1]) * cosf(sc[0]);
dir[1] = sinf(sc[1]) * sinf(sc[0]);
dir[2] = cosf(sc[1]);
}
void SunlightEditor::Init()
{
{
GraphicsPipelineDesc desc("G-Buffer Depth");
MakeFullScreenPipeline(desc, ShaderByteCode(g_sun_overlay_ps));
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
pipeline = CreateGraphicsPipeline(desc);
}
}
void SunlightEditor::ProcessWorld(world_t& world)
{
skyShader = NULL;
for(int i = 0; i < tr.numShaders; i++)
{
if(tr.shaders[i]->isSunDataValid)
{
skyShader = tr.shaders[i];
break;
}
}
if(!LoadSunFile(va("sun/%s.sun", world.baseName)) &&
skyShader != NULL)
{
LoadSunFromShader(skyShader);
}
}
void SunlightEditor::DrawOverlay()
{
if(!drawOverlay || !IsViewportFullscreen(backEnd.viewParms))
{
return;
}
srp.renderMode = RenderMode::None;
SCOPED_RENDER_PASS("Sun Overlay", 1.0f, 1.0f, 1.0f);
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
CmdBeginBarrier();
CmdTextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit);
CmdEndBarrier();
SunOverlayRC rc = {};
rc.angle = 0.0f;
VectorCopy(crp.sunlightData.color, rc.color);
VectorCopy(crp.sunlightData.direction, rc.direction);
rc.textureWidth = glConfig.vidWidth;
rc.textureHeight = glConfig.vidHeight;
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
CmdBindPipeline(pipeline);
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
CmdDraw(3, 0);
}
void SunlightEditor::DrawGUI()
{
if(tr.world == NULL)
{
return;
}
GUI_AddMainMenuItem(GUI_MainMenu::Tools, "Edit Sunlight", "", &windowActive);
if(!windowActive)
{
return;
}
if(ImGui::Begin("Sunlight", &windowActive, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Checkbox("Draw Sun", &drawOverlay);
float angles[2];
DirectionToAzimuthInclination(angles, crp.sunlightData.direction);
ImGui::NewLine();
ImGui::SliderAngle("Azimuth", &angles[0], 0.0f, 360.0f);
ImGui::SliderAngle("Inclination", &angles[1], 0.0f, 180.0f);
AzimuthInclinationToDirection(crp.sunlightData.direction, angles);
ImGui::ColorEdit3("Color", crp.sunlightData.color);
ImGui::SliderFloat("Light intensity", &crp.sunlightData.intensity, 0.0f, 10.0f);
ImGui::NewLine();
if(ImGui::Button("Save Config..."))
{
OpenSaveFileDialog("sun", ".sun");
}
ImGui::SameLine();
if(ImGui::Button("Open Config..."))
{
OpenOpenFileDialog("sun", ".sun");
}
if(skyShader != NULL)
{
ImGui::SameLine();
if(ImGui::Button("Import from Sky Shader"))
{
LoadSunFromShader(skyShader);
}
}
if(SaveFileDialog())
{
SaveSunFile(GetSaveFileDialogPath());
}
if(OpenFileDialog())
{
LoadSunFile(GetOpenFileDialogPath());
}
}
ImGui::End();
}