/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2022 Blender Foundation. */ /** \file * \ingroup draw * * \brief Simple API to draw debug shapes and log in the viewport. * * Both CPU and GPU implementation are supported and symmetrical (meaning GPU shader can use it * too, see common_debug_print/draw_lib.glsl). * * NOTE: CPU logging will overlap GPU logging on screen as it is drawn after. */ #pragma once #include "BLI_math_vec_types.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" #include "DNA_object_types.h" #include "DRW_gpu_wrapper.hh" namespace blender::draw { /* Shortcuts to avoid boilerplate code and match shader API. */ #define drw_debug_line(...) DRW_debug_get()->draw_line(__VA_ARGS__) #define drw_debug_polygon(...) DRW_debug_get()->draw_polygon(__VA_ARGS__) #define drw_debug_bbox(...) DRW_debug_get()->draw_bbox(__VA_ARGS__) #define drw_debug_sphere(...) DRW_debug_get()->draw_sphere(__VA_ARGS__) #define drw_debug_point(...) DRW_debug_get()->draw_point(__VA_ARGS__) #define drw_debug_matrix(...) DRW_debug_get()->draw_matrix(__VA_ARGS__) #define drw_debug_matrix_as_bbox(...) DRW_debug_get()->draw_matrix_as_bbox(__VA_ARGS__) #define drw_print(...) DRW_debug_get()->print(__VA_ARGS__) #define drw_print_hex(...) DRW_debug_get()->print_hex(__VA_ARGS__) #define drw_print_binary(...) DRW_debug_get()->print_binary(__VA_ARGS__) #define drw_print_no_endl(...) DRW_debug_get()->print_no_endl(__VA_ARGS__) /* Will log variable along with its name, like the shader version of print(). */ #define drw_print_id(v_) DRW_debug_get()->print(#v_, "= ", v_) #define drw_print_id_no_endl(v_) DRW_debug_get()->print_no_endl(#v_, "= ", v_) class DebugDraw { private: using DebugDrawBuf = StorageBuffer; using DebugPrintBuf = StorageBuffer; /** Data buffers containing all verts or chars to draw. */ DebugDrawBuf cpu_draw_buf_ = {"DebugDrawBuf-CPU"}; DebugDrawBuf gpu_draw_buf_ = {"DebugDrawBuf-GPU"}; DebugPrintBuf cpu_print_buf_ = {"DebugPrintBuf-CPU"}; DebugPrintBuf gpu_print_buf_ = {"DebugPrintBuf-GPU"}; /** True if the gpu buffer have been requested and may contain data to draw. */ bool gpu_print_buf_used = false; bool gpu_draw_buf_used = false; /** Matrix applied to all points before drawing. Could be a stack if needed. */ float4x4 model_mat_; /** Precomputed shapes verts. */ Vector sphere_verts_; Vector point_verts_; /** Cursor position for print functionality. */ uint print_col_ = 0; uint print_row_ = 0; public: DebugDraw(); ~DebugDraw(){}; /** * Resets all buffers and reset model matrix state. * Not to be called by user. */ void init(); /** * Resets model matrix state to identity. */ void modelmat_reset(); /** * Sets model matrix transform to apply to any vertex passed to drawing functions. */ void modelmat_set(const float modelmat[4][4]); /** * Drawing functions that will draw wire-frames with the given color. */ void draw_line(float3 v1, float3 v2, float4 color = {1, 0, 0, 1}); void draw_polygon(Span poly_verts, float4 color = {1, 0, 0, 1}); void draw_bbox(const BoundBox &bbox, const float4 color = {1, 0, 0, 1}); void draw_sphere(const float3 center, float radius, const float4 color = {1, 0, 0, 1}); void draw_point(const float3 center, float radius = 0.01f, const float4 color = {1, 0, 0, 1}); /** * Draw a matrix transformation as 3 colored axes. */ void draw_matrix(const float4x4 m4); /** * Draw a matrix as a 2 units length bounding box, centered on origin. */ void draw_matrix_as_bbox(float4x4 mat, const float4 color = {1, 0, 0, 1}); /** * Will draw all debug shapes and text cached up until now to the current view / frame-buffer. * Draw buffers will be emptied and ready for new debug data. */ void display_to_view(); /** * Log variable or strings inside the viewport. * Using a unique non string argument will print the variable name with it. * Concatenate by using multiple arguments. i.e: `print("Looped ", n, "times.")`. */ template void print(StringRefNull str, Ts... args) { print_no_endl(str, args...); print_newline(); } template void print(const T &value) { print_value(value); print_newline(); } template void print_hex(const T &value) { print_value_hex(value); print_newline(); } template void print_binary(const T &value) { print_value_binary(value); print_newline(); } /** * Same as `print()` but does not finish the line. */ void print_no_endl(std::string arg) { print_string(arg); } void print_no_endl(StringRef arg) { print_string(arg); } void print_no_endl(StringRefNull arg) { print_string(arg); } void print_no_endl(char const *arg) { print_string(StringRefNull(arg)); } template void print_no_endl(T arg) { print_value(arg); } template void print_no_endl(T arg, Ts... args) { print_no_endl(arg); print_no_endl(args...); } /** * Not to be called by user. Should become private. */ GPUStorageBuf *gpu_draw_buf_get(); GPUStorageBuf *gpu_print_buf_get(); private: uint color_pack(float4 color); DRWDebugVert vert_pack(float3 pos, uint color); void draw_line(float3 v1, float3 v2, uint color); void print_newline(); void print_string_start(uint len); void print_string(std::string str); void print_char4(uint data); void print_append_char(uint char1, uint &char4); void print_append_digit(uint digit, uint &char4); void print_append_space(uint &char4); void print_value_binary(uint value); void print_value_uint(uint value, const bool hex, bool is_negative, const bool is_unsigned); template void print_value(const T &value); template void print_value_hex(const T &value); template void print_value_binary(const T &value); void display_lines(); void display_prints(); }; } // namespace blender::draw /** * Ease of use function to get the debug module. * TODO(fclem): Should be removed once DRWManager is no longer global. * IMPORTANT: Can return nullptr if storage buffer is not supported. */ blender::draw::DebugDraw *DRW_debug_get();