From 28fa127ead2de98ee0e63c94bfc08f09729d9f46 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Fri, 29 Oct 2021 09:13:58 +0200 Subject: [PATCH] gfx/debug: Helper class to handle common debug rendering --- CMakeLists.txt | 2 + data/effects/shared.effect | 9 ++ data/effects/standard.effect | 65 ++++++++- source/gfx/gfx-debug.cpp | 266 +++++++++++++++++++++++++++++++++++ source/gfx/gfx-debug.hpp | 50 +++++++ 5 files changed, 386 insertions(+), 6 deletions(-) create mode 100644 source/gfx/gfx-debug.cpp create mode 100644 source/gfx/gfx-debug.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f64f73..0538b14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1156,6 +1156,8 @@ list(APPEND PROJECT_PRIVATE_SOURCE "source/util/util-platform.cpp" "source/util/util-threadpool.cpp" "source/util/util-threadpool.hpp" + "source/gfx/gfx-debug.hpp" + "source/gfx/gfx-debug.cpp" "source/gfx/gfx-source-texture.hpp" "source/gfx/gfx-source-texture.cpp" "source/obs/gs/gs-helper.hpp" diff --git a/data/effects/shared.effect b/data/effects/shared.effect index e47a331..afc8d6a 100644 --- a/data/effects/shared.effect +++ b/data/effects/shared.effect @@ -50,6 +50,11 @@ struct VertexData { float4 pos : POSITION; float2 uv : TEXCOORD0; }; +struct VertexColorData { + float4 pos : POSITION; + float4 clr : COLOR; + float2 uv : TEXCOORD0; +}; //------------------------------------------------------------------------------ // Vertex Shaders @@ -58,6 +63,10 @@ VertexData DefaultVertexShader(VertexData vtx) { vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); return vtx; }; +VertexColorData ColorVertexShader(VertexColorData vtx) { + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; +}; //------------------------------------------------------------------------------ // Color Conversion diff --git a/data/effects/standard.effect b/data/effects/standard.effect index 873bb6e..d56a698 100644 --- a/data/effects/standard.effect +++ b/data/effects/standard.effect @@ -8,12 +8,12 @@ uniform texture2D InputB< >; //------------------------------------------------------------------------------ -// Technique: Draw +// Technique: Texture //------------------------------------------------------------------------------ // Parameters: // - InputA: RGBA Texture -float4 PSDraw(VertexData vtx) : TARGET { +float4 PSTexture(VertexData vtx) : TARGET { return InputA.Sample(BlankSampler, vtx.uv); }; @@ -22,17 +22,44 @@ technique Draw pass { vertex_shader = DefaultVertexShader(vtx); - pixel_shader = PSDraw(vtx); + pixel_shader = PSTexture(vtx); + }; +}; +technique Texture +{ + pass + { + vertex_shader = DefaultVertexShader(vtx); + pixel_shader = PSTexture(vtx); }; }; //------------------------------------------------------------------------------ -// Technique: Draw +// Technique: TextureColor //------------------------------------------------------------------------------ // Parameters: // - InputA: RGBA Texture -float4 PSDrawPremultiplied(VertexData vtx) : TARGET { +float4 PSTextureColor(VertexColorData vtx) : TARGET { + return InputA.Sample(BlankSampler, vtx.uv) * vtx.clr; +}; + +technique TextureColor +{ + pass + { + vertex_shader = ColorVertexShader(vtx); + pixel_shader = PSTextureColor(vtx); + }; +}; + +//------------------------------------------------------------------------------ +// Technique: Texture Premultiplied +//------------------------------------------------------------------------------ +// Parameters: +// - InputA: RGBA Texture + +float4 PSTexturePremultiplied(VertexData vtx) : TARGET { float4 rgba = InputA.Sample(BlankSampler, vtx.uv); rgba.rgb /= rgba.a > (1. / 1024.) ? rgba.a : 1.0; return rgba; @@ -43,7 +70,15 @@ technique DrawPremultiplied pass { vertex_shader = DefaultVertexShader(vtx); - pixel_shader = PSDrawPremultiplied(vtx); + pixel_shader = PSTexturePremultiplied(vtx); + }; +}; +technique TexturePremultiplied +{ + pass + { + vertex_shader = DefaultVertexShader(vtx); + pixel_shader = PSTexturePremultiplied(vtx); }; }; @@ -69,3 +104,21 @@ technique RestoreAlpha pixel_shader = PSRestoreAlpha(vtx); }; }; + +//------------------------------------------------------------------------------ +// Technique: Color +//------------------------------------------------------------------------------ +// Parameters: + +float4 PSColor(VertexColorData vtx) : TARGET { + return vtx.clr; +}; + +technique Color +{ + pass + { + vertex_shader = ColorVertexShader(vtx); + pixel_shader = PSColor(vtx); + }; +}; diff --git a/source/gfx/gfx-debug.cpp b/source/gfx/gfx-debug.cpp new file mode 100644 index 0000000..ca23a54 --- /dev/null +++ b/source/gfx/gfx-debug.cpp @@ -0,0 +1,266 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "gfx-debug.hpp" +#include +#include "graphics/matrix4.h" +#include "obs/gs/gs-helper.hpp" +#include "plugin.hpp" +#include "util/util-logging.hpp" + +#ifdef _DEBUG +#define ST_PREFIX "<%s> " +#define D_LOG_ERROR(x, ...) P_LOG_ERROR(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) +#define D_LOG_WARNING(x, ...) P_LOG_WARN(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) +#define D_LOG_INFO(x, ...) P_LOG_INFO(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) +#define D_LOG_DEBUG(x, ...) P_LOG_DEBUG(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__) +#else +#define ST_PREFIX " " +#define D_LOG_ERROR(...) P_LOG_ERROR(ST_PREFIX __VA_ARGS__) +#define D_LOG_WARNING(...) P_LOG_WARN(ST_PREFIX __VA_ARGS__) +#define D_LOG_INFO(...) P_LOG_INFO(ST_PREFIX __VA_ARGS__) +#define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__) +#endif + +std::shared_ptr streamfx::gfx::debug::get() +{ + static std::weak_ptr instance; + static std::mutex lock; + + std::unique_lock ul(lock); + if (instance.expired()) { + auto hard_instance = std::shared_ptr(new streamfx::gfx::debug()); + instance = hard_instance; + return hard_instance; + } + return instance.lock(); +} + +streamfx::gfx::debug::debug() +{ + { + std::filesystem::path file = ::streamfx::data_file_path("effects/standard.effect"); + try { + _effect = std::make_shared<::streamfx::obs::gs::effect>(file); + } catch (...) { + D_LOG_ERROR("Failed to load '%s'.", file.generic_u8string().c_str()); + } + } +} + +streamfx::gfx::debug::~debug() +{ + obs::gs::context gctx{}; + + _point_vb.reset(); + _line_vb.reset(); + _arrow_vb.reset(); + _quad_vb.reset(); +} + +void streamfx::gfx::debug::draw_point(float x, float y, uint32_t color) +{ + obs::gs::context gctx{}; + + if (!_point_vb) { + _point_vb = std::make_shared(1u, 1u); + } + + { + auto vtx = _point_vb->at(0); + vec3_set(vtx.position, x, y, 0.); + *vtx.color = color; + } + + gs_load_indexbuffer(nullptr); + gs_load_vertexbuffer(_point_vb->update(true)); + while (gs_effect_loop(_effect->get_object(), "Color")) { + gs_draw(GS_POINTS, 0, 1); + } + gs_load_vertexbuffer(nullptr); +} + +void streamfx::gfx::debug::draw_line(float x, float y, float x2, float y2, uint32_t color /*= 0xFFFFFFFF*/) +{ + obs::gs::context gctx{}; + + if (!_line_vb) { + _line_vb = std::make_shared(2u, 1u); + } + + { + auto vtx = _line_vb->at(0); + vec3_set(vtx.position, x, y, 0.); + *vtx.color = color; + } + { + auto vtx = _line_vb->at(1); + vec3_set(vtx.position, x2, y2, 0.); + *vtx.color = color; + } + + gs_load_indexbuffer(nullptr); + gs_load_vertexbuffer(_line_vb->update(true)); + while (gs_effect_loop(_effect->get_object(), "Color")) { + gs_draw(GS_LINES, 0, 2); + } + gs_load_vertexbuffer(nullptr); +} + +void streamfx::gfx::debug::draw_arrow(float x, float y, float x2, float y2, float w /*= 0.*/, + uint32_t color /*= 0xFFFFFFFF*/) +{ + obs::gs::context gctx{}; + + if (!_arrow_vb) { + _arrow_vb = std::make_shared(5u, 1u); + } + + float dx = x2 - x; + float dy = y2 - y; + float ang = atan2(-dx, dy); + float len = sqrt(dx * dx + dy * dy); + + if (abs(w) <= 1) { + w = len / 3.; + } + + matrix4 rotator; + matrix4_identity(&rotator); + matrix4_rotate_aa4f(&rotator, &rotator, 0, 0, 1, ang); + vec3 offset; + vec3_set(&offset, x, y, 0.); + + { + auto vtx = _arrow_vb->at(0); + vec3_set(vtx.position, 0, 0, 0.); + vec3_transform(vtx.position, vtx.position, &rotator); + vec3_add(vtx.position, vtx.position, &offset); + *vtx.color = color; + } + { + auto vtx = _arrow_vb->at(1); + vec3_set(vtx.position, 0, len, 0.); + vec3_transform(vtx.position, vtx.position, &rotator); + vec3_add(vtx.position, vtx.position, &offset); + *vtx.color = color; + } + { + auto vtx = _arrow_vb->at(2); + vec3_set(vtx.position, -w, len - w, 0.); + vec3_transform(vtx.position, vtx.position, &rotator); + vec3_add(vtx.position, vtx.position, &offset); + *vtx.color = color; + } + { + auto vtx = _arrow_vb->at(3); + vec3_set(vtx.position, w, len - w, 0.); + vec3_transform(vtx.position, vtx.position, &rotator); + vec3_add(vtx.position, vtx.position, &offset); + *vtx.color = color; + } + { + auto vtx = _arrow_vb->at(4); + vec3_set(vtx.position, 0, len, 0.); + vec3_transform(vtx.position, vtx.position, &rotator); + vec3_add(vtx.position, vtx.position, &offset); + *vtx.color = color; + } + + gs_load_indexbuffer(nullptr); + gs_load_vertexbuffer(_arrow_vb->update(true)); + while (gs_effect_loop(_effect->get_object(), "Color")) { + gs_draw(GS_LINESTRIP, 0, 5); + } + gs_load_vertexbuffer(nullptr); +} + +void streamfx::gfx::debug::draw_rectangle(float x, float y, float w, float h, bool frame, + uint32_t color /*= 0xFFFFFFFF*/) +{ + obs::gs::context gctx{}; + + if (!_quad_vb) { + _quad_vb = std::make_shared(5u, 1u); + } + + if (frame) { + { + auto vtx = _quad_vb->at(0); + vec3_set(vtx.position, x, y, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(1); + vec3_set(vtx.position, x + w, y, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(2); + vec3_set(vtx.position, x + w, y + h, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(3); + vec3_set(vtx.position, x, y + h, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(4); + vec3_set(vtx.position, x, y, 0.); + *vtx.color = color; + } + + gs_load_indexbuffer(nullptr); + gs_load_vertexbuffer(_quad_vb->update(true)); + while (gs_effect_loop(_effect->get_object(), "Color")) { + gs_draw(GS_LINESTRIP, 0, 5); + } + gs_load_vertexbuffer(nullptr); + } else { + { + auto vtx = _quad_vb->at(0); + vec3_set(vtx.position, x, y, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(1); + vec3_set(vtx.position, x + w, y, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(2); + vec3_set(vtx.position, x, y + h, 0.); + *vtx.color = color; + } + { + auto vtx = _quad_vb->at(3); + vec3_set(vtx.position, x + w, y + h, 0.); + *vtx.color = color; + } + + gs_load_indexbuffer(nullptr); + gs_load_vertexbuffer(_quad_vb->update(true)); + while (gs_effect_loop(_effect->get_object(), "Color")) { + gs_draw(GS_TRISTRIP, 0, 4); + } + gs_load_vertexbuffer(nullptr); + } +} diff --git a/source/gfx/gfx-debug.hpp b/source/gfx/gfx-debug.hpp new file mode 100644 index 0000000..d904cb6 --- /dev/null +++ b/source/gfx/gfx-debug.hpp @@ -0,0 +1,50 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include "obs/gs/gs-effect.hpp" +#include "obs/gs/gs-vertexbuffer.hpp" + +namespace streamfx::gfx { + class debug { + std::shared_ptr<::streamfx::obs::gs::effect> _effect; + std::shared_ptr<::streamfx::obs::gs::vertex_buffer> _point_vb; + std::shared_ptr<::streamfx::obs::gs::vertex_buffer> _line_vb; + std::shared_ptr<::streamfx::obs::gs::vertex_buffer> _arrow_vb; + std::shared_ptr<::streamfx::obs::gs::vertex_buffer> _quad_vb; + + public /* Singleton */: + static std::shared_ptr get(); + + private: + debug(); + + public: + ~debug(); + + void draw_point(float x, float y, uint32_t color = 0xFFFFFFFF); + + void draw_line(float x, float y, float x2, float y2, uint32_t color = 0xFFFFFFFF); + + void draw_arrow(float x, float y, float x2, float y2, float w = 0., uint32_t color = 0xFFFFFFFF); + + void draw_rectangle(float x, float y, float w, float h, bool frame, uint32_t color = 0xFFFFFFFF); + }; +} // namespace streamfx::gfx