diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 8f992578bfe..23c98013575 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -294,6 +294,7 @@ set(SRC engines/overlay/overlay_next_grid.hh engines/overlay/overlay_next_instance.hh engines/overlay/overlay_next_lattice.hh + engines/overlay/overlay_next_light.hh engines/overlay/overlay_next_metaball.hh engines/overlay/overlay_next_prepass.hh engines/overlay/overlay_next_private.hh diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.cc b/source/blender/draw/engines/overlay/overlay_next_instance.cc index d3741887795..2302d829094 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_next_instance.cc @@ -80,6 +80,11 @@ void Instance::begin_sync() prepass.begin_sync(resources, state); empties.begin_sync(); lattices.begin_sync(resources, state); + + auto begin_sync_layer = [&](OverlayLayer &layer) { layer.lights.begin_sync(); }; + begin_sync_layer(regular); + begin_sync_layer(infront); + metaballs.begin_sync(); speakers.begin_sync(); grid.begin_sync(resources, state, view); @@ -90,6 +95,8 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) const bool in_edit_mode = object_is_edit_mode(ob_ref.object); const bool needs_prepass = true; /* TODO */ + OverlayLayer &layer = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) ? infront : regular; + if (needs_prepass) { switch (ob_ref.object->type) { case OB_MESH: @@ -137,6 +144,9 @@ void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) lattices.object_sync(manager, ob_ref, resources, state); } break; + case OB_LAMP: + layer.lights.object_sync(ob_ref, resources, state); + break; case OB_MBALL: if (!in_edit_mode) { metaballs.object_sync(ob_ref, resources, state); @@ -155,6 +165,12 @@ void Instance::end_sync() { resources.end_sync(); + auto end_sync_layer = [&](OverlayLayer &layer) { + layer.lights.end_sync(resources, shapes, state); + }; + end_sync_layer(regular); + end_sync_layer(infront); + metaballs.end_sync(resources, shapes, state); empties.end_sync(resources, shapes, state); speakers.end_sync(resources, shapes, state); @@ -222,6 +238,7 @@ void Instance::draw(Manager &manager) background.draw(resources, manager); + regular.lights.draw(resources.overlay_line_fb, manager, view); empties.draw(resources, manager, view); lattices.draw(resources, manager, view); metaballs.draw(resources, manager, view); @@ -230,7 +247,8 @@ void Instance::draw(Manager &manager) grid.draw(resources, manager, view); empties.draw_in_front(resources, manager, view); - lattices.draw_in_front(resources, manager, view); + /* TODO(: Breaks selection on M1 Max. */ + // lattices.draw_in_front(resources, manager, view); metaballs.draw_in_front(resources, manager, view); speakers.draw_in_front(resources, manager, view); diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.hh b/source/blender/draw/engines/overlay/overlay_next_instance.hh index 7e6dc4a45c9..cd67511e07b 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_next_instance.hh @@ -14,6 +14,7 @@ #include "overlay_next_empty.hh" #include "overlay_next_grid.hh" #include "overlay_next_lattice.hh" +#include "overlay_next_light.hh" #include "overlay_next_metaball.hh" #include "overlay_next_prepass.hh" #include "overlay_next_speaker.hh" @@ -41,6 +42,13 @@ class Instance { /** Overlay types. */ Background background; Prepass prepass; + + struct OverlayLayer { + const SelectionType selection_type_; + + Lights lights = {selection_type_}; + } regular{selection_type_}, infront{selection_type_}; + Metaballs metaballs = {selection_type_}; Empties empties = {selection_type_}; Lattices lattices; diff --git a/source/blender/draw/engines/overlay/overlay_next_light.hh b/source/blender/draw/engines/overlay/overlay_next_light.hh new file mode 100644 index 00000000000..df8e74abd3d --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_next_light.hh @@ -0,0 +1,197 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "overlay_next_private.hh" + +namespace blender::draw::overlay { + +class Lights { + using LightInstanceBuf = ShapeInstanceBuf; + using GroundLineInstanceBuf = ShapeInstanceBuf; + + private: + const SelectionType selection_type_; + + PassSimple ps_ = {"Lights"}; + + struct CallBuffers { + const SelectionType selection_type_; + GroundLineInstanceBuf ground_line_buf = {selection_type_, "ground_line_buf"}; + LightInstanceBuf icon_inner_buf = {selection_type_, "icon_inner_buf"}; + LightInstanceBuf icon_outer_buf = {selection_type_, "icon_outer_buf"}; + LightInstanceBuf icon_sun_rays_buf = {selection_type_, "icon_sun_rays_buf"}; + LightInstanceBuf point_buf = {selection_type_, "point_buf"}; + LightInstanceBuf sun_buf = {selection_type_, "sun_buf"}; + LightInstanceBuf spot_buf = {selection_type_, "spot_buf"}; + LightInstanceBuf spot_cone_back_buf = {selection_type_, "spot_cone_back_buf"}; + LightInstanceBuf spot_cone_front_buf = {selection_type_, "spot_cone_front_buf"}; + LightInstanceBuf area_disk_buf = {selection_type_, "area_disk_buf"}; + LightInstanceBuf area_square_buf = {selection_type_, "area_square_buf"}; + } call_buffers_{selection_type_}; + + public: + Lights(const SelectionType selection_type) : selection_type_(selection_type){}; + + void begin_sync() + { + call_buffers_.ground_line_buf.clear(); + call_buffers_.icon_inner_buf.clear(); + call_buffers_.icon_outer_buf.clear(); + call_buffers_.icon_sun_rays_buf.clear(); + call_buffers_.point_buf.clear(); + call_buffers_.sun_buf.clear(); + call_buffers_.spot_buf.clear(); + call_buffers_.spot_cone_back_buf.clear(); + call_buffers_.spot_cone_front_buf.clear(); + call_buffers_.area_disk_buf.clear(); + call_buffers_.area_square_buf.clear(); + } + + void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state) + { + ExtraInstanceData data(ob_ref.object->object_to_world(), + float4{res.object_wire_color(ob_ref, state).xyz(), 1.0f}, + 1.0f); + float4 &theme_color = data.color_; + + /* Pack render data into object matrix. */ + float4x4 &matrix = data.object_to_world_; + float &area_size_x = matrix[0].w; + float &area_size_y = matrix[1].w; + float &spot_cosine = matrix[0].w; + float &spot_blend = matrix[1].w; + float &clip_start = matrix[2].w; + float &clip_end = matrix[3].w; + + const Light &la = *static_cast(ob_ref.object->data); + const select::ID select_id = res.select_id(ob_ref); + + /* FIXME / TODO: clip_end has no meaning nowadays. + * In EEVEE, Only clip_start is used shadow-mapping. + * Clip end is computed automatically based on light power. + * For now, always use the custom distance as clip_end. */ + clip_end = la.att_dist; + clip_start = la.clipsta; + + call_buffers_.ground_line_buf.append(float4(matrix.location()), select_id); + + const float4 light_color = {la.r, la.g, la.b, 1.0f}; + const bool show_light_colors = state.overlay.flag & V3D_OVERLAY_SHOW_LIGHT_COLORS; + + /* Draw the outer ring of the light icon and the sun rays in `light_color`, if required. */ + call_buffers_.icon_outer_buf.append(data, select_id); + call_buffers_.icon_inner_buf.append(show_light_colors ? data.with_color(light_color) : data, + select_id); + + switch (la.type) { + case LA_LOCAL: + area_size_x = area_size_y = la.radius; + call_buffers_.point_buf.append(data, select_id); + break; + case LA_SUN: + call_buffers_.sun_buf.append(data, select_id); + call_buffers_.icon_sun_rays_buf.append( + show_light_colors ? data.with_color(light_color) : data, select_id); + break; + case LA_SPOT: { + /* Previous implementation was using the clip-end distance as cone size. + * We cannot do this anymore so we use a fixed size of 10. (see #72871) */ + rescale_m4(matrix.ptr(), float3{10.0f, 10.0f, 10.0f}); + /* For cycles and EEVEE the spot attenuation is: + * `y = (1/sqrt(1 + x^2) - a)/((1 - a) b)` + * x being the tangent of the angle between the light direction and the generatrix of the + * cone. We solve the case where spot attenuation y = 1 and y = 0 root for y = 1 is + * `sqrt(1/c^2 - 1)`. root for y = 0 is `sqrt(1/a^2 - 1)` and use that to position the + * blend circle. */ + const float a = cosf(la.spotsize * 0.5f); + const float b = la.spotblend; + const float c = a * b - a - b; + const float a2 = a * a; + const float c2 = c * c; + /* Optimized version or root1 / root0 */ + spot_blend = sqrtf((a2 - a2 * c2) / (c2 - a2 * c2)); + spot_cosine = a; + /* HACK: We pack the area size in alpha color. This is decoded by the shader. */ + theme_color[3] = -max_ff(la.radius, FLT_MIN); + call_buffers_.spot_buf.append(data, select_id); + if ((la.mode & LA_SHOW_CONE) && !DRW_state_is_select()) { + const float4 color_inside{0.0f, 0.0f, 0.0f, 0.5f}; + const float4 color_outside{1.0f, 1.0f, 1.0f, 0.3f}; + call_buffers_.spot_cone_front_buf.append(data.with_color(color_inside), select_id); + call_buffers_.spot_cone_back_buf.append(data.with_color(color_outside), select_id); + } + break; + } + case LA_AREA: + const bool uniform_scale = !ELEM(la.area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE); + LightInstanceBuf &area_buf = ELEM(la.area_shape, LA_AREA_SQUARE, LA_AREA_RECT) ? + call_buffers_.area_square_buf : + call_buffers_.area_disk_buf; + area_size_x = la.area_size; + area_size_y = uniform_scale ? la.area_size : la.area_sizey; + area_buf.append(data, select_id); + break; + } + } + + void end_sync(Resources &res, ShapeCache &shapes, const State &state) + { + const DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state; + ps_.init(); + res.select_bind(ps_); + + { + PassSimple::Sub &sub_pass = ps_.sub("spot_cone_front"); + sub_pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_FRONT | + state.clipping_state); + sub_pass.shader_set(res.shaders.extra_shape.get()); + sub_pass.bind_ubo("globalsBlock", &res.globals_buf); + call_buffers_.spot_cone_front_buf.end_sync(sub_pass, shapes.light_spot_volume.get()); + } + { + PassSimple::Sub &sub_pass = ps_.sub("spot_cone_back"); + sub_pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | + DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK | state.clipping_state); + sub_pass.shader_set(res.shaders.extra_shape.get()); + sub_pass.bind_ubo("globalsBlock", &res.globals_buf); + call_buffers_.spot_cone_back_buf.end_sync(sub_pass, shapes.light_spot_volume.get()); + } + { + PassSimple::Sub &sub_pass = ps_.sub("light_shapes"); + sub_pass.state_set(pass_state); + sub_pass.shader_set(res.shaders.extra_shape.get()); + sub_pass.bind_ubo("globalsBlock", &res.globals_buf); + call_buffers_.icon_inner_buf.end_sync(sub_pass, shapes.light_icon_outer_lines.get()); + call_buffers_.icon_outer_buf.end_sync(sub_pass, shapes.light_icon_inner_lines.get()); + call_buffers_.icon_sun_rays_buf.end_sync(sub_pass, shapes.light_icon_sun_rays.get()); + call_buffers_.point_buf.end_sync(sub_pass, shapes.light_point_lines.get()); + call_buffers_.sun_buf.end_sync(sub_pass, shapes.light_sun_lines.get()); + call_buffers_.spot_buf.end_sync(sub_pass, shapes.light_spot_lines.get()); + call_buffers_.area_disk_buf.end_sync(sub_pass, shapes.light_area_disk_lines.get()); + call_buffers_.area_square_buf.end_sync(sub_pass, shapes.light_area_square_lines.get()); + } + { + PassSimple::Sub &sub_pass = ps_.sub("ground_line"); + sub_pass.state_set(pass_state | DRW_STATE_BLEND_ALPHA); + sub_pass.shader_set(res.shaders.extra_ground_line.get()); + sub_pass.bind_ubo("globalsBlock", &res.globals_buf); + call_buffers_.ground_line_buf.end_sync(sub_pass, shapes.ground_line.get()); + } + } + + void draw(Framebuffer &framebuffer, Manager &manager, View &view) + { + GPU_framebuffer_bind(framebuffer); + manager.submit(ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_private.hh b/source/blender/draw/engines/overlay/overlay_next_private.hh index 499f8f57db8..d711e257b57 100644 --- a/source/blender/draw/engines/overlay/overlay_next_private.hh +++ b/source/blender/draw/engines/overlay/overlay_next_private.hh @@ -84,6 +84,18 @@ class ShapeCache { BatchPtr speaker; + BatchPtr ground_line; + + BatchPtr light_icon_outer_lines; + BatchPtr light_icon_inner_lines; + BatchPtr light_icon_sun_rays; + BatchPtr light_point_lines; + BatchPtr light_sun_lines; + BatchPtr light_spot_lines; + BatchPtr light_area_disk_lines; + BatchPtr light_area_square_lines; + BatchPtr light_spot_volume; + ShapeCache(); }; @@ -119,6 +131,7 @@ class ShaderModule { ShaderPtr depth_mesh; ShaderPtr extra_shape; ShaderPtr extra_wire_object; + ShaderPtr extra_ground_line; ShaderPtr lattice_points; ShaderPtr lattice_wire; @@ -262,7 +275,7 @@ template struct ShapeInstanceBuf : private select::Selec data_buf.append(data); } - void end_sync(PassSimple &pass, gpu::Batch *shape) + void end_sync(PassSimple::Sub &pass, gpu::Batch *shape) { if (data_buf.is_empty()) { return; diff --git a/source/blender/draw/engines/overlay/overlay_next_shader.cc b/source/blender/draw/engines/overlay/overlay_next_shader.cc index 09bace914a3..644deba2b9b 100644 --- a/source/blender/draw/engines/overlay/overlay_next_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_next_shader.cc @@ -89,18 +89,27 @@ ShaderModule::ShaderModule(const SelectionType selection_type, const bool clippi info.additional_info( "draw_view", "draw_modelmat_new", "draw_resource_handle_new", "draw_globals"); }); + lattice_points = selectable_shader( "overlay_edit_lattice_point", [](gpu::shader::ShaderCreateInfo &info) { info.additional_infos_.clear(); info.additional_info( "draw_view", "draw_modelmat_new", "draw_resource_handle_new", "draw_globals"); }); + lattice_wire = selectable_shader( "overlay_edit_lattice_wire", [](gpu::shader::ShaderCreateInfo &info) { info.additional_infos_.clear(); info.additional_info( "draw_view", "draw_modelmat_new", "draw_resource_handle_new", "draw_globals"); }); + + extra_ground_line = selectable_shader( + "overlay_extra_groundline", [](gpu::shader::ShaderCreateInfo &info) { + info.storage_buf(0, Qualifier::READ, "vec4", "data_buf[]"); + info.define("inst_pos", "data_buf[gl_InstanceID].xyz"); + info.vertex_inputs_.pop_last(); + }); } ShaderModule &ShaderModule::module_get(SelectionType selection_type, bool clipping_enabled) diff --git a/source/blender/draw/engines/overlay/overlay_next_shape.cc b/source/blender/draw/engines/overlay/overlay_next_shape.cc index cfc293488f5..7c2be3281e5 100644 --- a/source/blender/draw/engines/overlay/overlay_next_shape.cc +++ b/source/blender/draw/engines/overlay/overlay_next_shape.cc @@ -52,6 +52,11 @@ enum VertexClass { VCLASS_EMPTY_SIZE = 1 << 14, }; +static constexpr int diamond_nsegments = 4; +static constexpr int inner_nsegments = 8; +static constexpr int outer_nsegments = 10; +static constexpr int circle_nsegments = 32; + static constexpr float bone_box_verts[8][3] = { {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, @@ -67,12 +72,43 @@ static constexpr std::array bone_box_wire = { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, }; +static void append_line_loop( + Vector &dest, Span verts, float z, int flag, bool dashed = false) +{ + const int step = dashed ? 2 : 1; + for (int i : IndexRange(verts.size() / step)) { + for (int j : IndexRange(2)) { + float2 cv = verts[(i * step + j) % (verts.size())]; + dest.append({{cv[0], cv[1], z}, flag}); + } + } +} + +static float light_distance_z_get(char axis, const bool start) +{ + switch (axis) { + case 'x': /* - X */ + return start ? 0.4f : 0.3f; + case 'X': /* + X */ + return start ? 0.6f : 0.7f; + case 'y': /* - Y */ + return start ? 1.4f : 1.3f; + case 'Y': /* + Y */ + return start ? 1.6f : 1.7f; + case 'z': /* - Z */ + return start ? 2.4f : 2.3f; + case 'Z': /* + Z */ + return start ? 2.6f : 2.7f; + } + return 0.0; +} + /* A single ring of vertices. */ static Vector ring_vertices(const float radius, const int segments) { Vector verts; for (int i : IndexRange(segments)) { - float angle = (2 * M_PI * i) / segments; + float angle = (2 * math::numbers::pi * i) / segments; verts.append(radius * float2(math::cos(angle), math::sin(angle))); } return verts; @@ -105,6 +141,17 @@ static Vector sphere_axes_circles(const float radius, return verts; } +static void light_append_direction_line(Vector &verts) +{ + const Vector diamond = ring_vertices(1.2f, diamond_nsegments); + const float zsta = light_distance_z_get('z', true); + const float zend = light_distance_z_get('z', false); + verts.append({{0.0, 0.0, zsta}, VCLASS_LIGHT_DIST}); + verts.append({{0.0, 0.0, zend}, VCLASS_LIGHT_DIST}); + append_line_loop(verts, diamond, zsta, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE); + append_line_loop(verts, diamond, zend, VCLASS_LIGHT_DIST | VCLASS_SCREENSPACE); +} + ShapeCache::ShapeCache() { /* quad_wire */ @@ -318,7 +365,7 @@ ShapeCache::ShapeCache() }; /* speaker */ { - const int segments = 16; + constexpr int segments = 16; Vector verts; for (int j = 0; j < 3; j++) { @@ -328,8 +375,8 @@ ShapeCache::ShapeCache() verts.append({{r, 0.0f, z}}); for (int i = 1; i < segments; i++) { - float x = cosf(2.0f * float(M_PI) * i / segments) * r; - float y = sinf(2.0f * float(M_PI) * i / segments) * r; + float x = cosf(2.0f * math::numbers::pi * i / segments) * r; + float y = sinf(2.0f * math::numbers::pi * i / segments) * r; Vertex v{{x, y, z}}; verts.append(v); verts.append(v); @@ -358,6 +405,141 @@ ShapeCache::ShapeCache() speaker = BatchPtr( GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); } + /* ground line */ + { + const Vector ring = ring_vertices(1.35f, diamond_nsegments); + + Vector verts; + /* Ground Point */ + append_line_loop(verts, ring, 0.0f, 0); + /* Ground Line */ + verts.append({{0.0, 0.0, 1.0}, 0}); + verts.append({{0.0, 0.0, 0.0}, 0}); + + ground_line = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light spot volume */ + { + Vector verts; + + /* Cone apex */ + verts.append({{0.0f, 0.0f, 0.0f}, 0}); + /* Cone silhouette */ + for (const int angle_i : IndexRange(circle_nsegments + 1)) { + const float angle = (2.0f * math::numbers::pi * angle_i) / circle_nsegments; + const float s = sinf(-angle); + const float c = cosf(-angle); + verts.append({{s, c, -1.0f}, VCLASS_LIGHT_SPOT_SHAPE}); + } + light_spot_volume = BatchPtr(GPU_batch_create_ex( + GPU_PRIM_TRI_FAN, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light icon outer lines */ + { + constexpr float r = 9.0f; + const Vector ring = ring_vertices(r * 1.33f, outer_nsegments * 2); + + Vector verts; + append_line_loop(verts, ring, 0.0f, VCLASS_SCREENSPACE, true); + light_icon_outer_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light icon inner lines */ + { + constexpr float r = 9.0f; + const Vector diamond = ring_vertices(r * 0.3f, diamond_nsegments); + const Vector ring = ring_vertices(r, inner_nsegments * 2); + + Vector verts; + append_line_loop(verts, diamond, 0.0f, VCLASS_SCREENSPACE); + append_line_loop(verts, ring, 0.0f, VCLASS_SCREENSPACE, true); + + light_icon_inner_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light icon sun rays */ + { + constexpr int num_rays = 8; + constexpr float r = 9.0f; + const Vector ring = ring_vertices(r, num_rays); + const std::array scales{1.6f, 1.9f, 2.2f, 2.5f}; + + Vector verts; + for (const float2 &point : ring) { + for (float scale : scales) { + float2 scaled = point * scale; + verts.append({{scaled.x, scaled.y, 0.0f}, VCLASS_SCREENSPACE}); + } + } + light_icon_sun_rays = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light point lines */ + { + const Vector ring = ring_vertices(1.0f, circle_nsegments); + + Vector verts; + append_line_loop(verts, ring, 0.0f, VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE); + light_point_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light sun lines */ + { + Vector verts; + /* Direction Line */ + verts.append({{0.0, 0.0, 0.0}, 0}); + verts.append({{0.0, 0.0, -20.0}, 0}); /* Good default. */ + light_sun_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light spot lines */ + { + const Vector ring = ring_vertices(1.0f, circle_nsegments); + + Vector verts; + /* Light area */ + append_line_loop(verts, ring, 0.0f, VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE); + /* Cone cap */ + append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_SPOT_SHAPE); + append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_BLEND); + /* Cone silhouette */ + for (const float2 &point : ring) { + verts.append({{0.0f, 0.0f, 0.0f}, 0}); + verts.append({{point.x, point.y, -1.0f}, VCLASS_LIGHT_SPOT_SHAPE | VCLASS_LIGHT_SPOT_CONE}); + } + + light_append_direction_line(verts); + + light_spot_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light area disk lines */ + { + const Vector ring = ring_vertices(0.5f, circle_nsegments); + + Vector verts; + /* Light area */ + append_line_loop(verts, ring, 0.0f, VCLASS_LIGHT_AREA_SHAPE); + + light_append_direction_line(verts); + + light_area_disk_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } + /* light area square lines */ + { + const Array rect{{-0.5f, -0.5f}, {-0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, -0.5f}}; + + Vector verts; + /* Light area */ + append_line_loop(verts, rect, 0.0f, VCLASS_LIGHT_AREA_SHAPE); + + light_append_direction_line(verts); + + light_area_square_lines = BatchPtr( + GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO)); + } } } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index c160d125b06..47255fef999 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -213,12 +213,20 @@ struct ExtraInstanceData { float4x4 object_to_world_; #if !defined(GPU_SHADER) && defined(__cplusplus) - ExtraInstanceData(const float4x4 &object_to_world, float4 &color, float draw_size) + ExtraInstanceData(const float4x4 &object_to_world, const float4 &color, float draw_size) { this->color_ = color; this->object_to_world_ = object_to_world; this->object_to_world_[3][3] = draw_size; }; + + ExtraInstanceData with_color(const float4 &color) const + { + ExtraInstanceData copy = *this; + copy.color_ = color; + return copy; + } + #endif }; BLI_STATIC_ASSERT_ALIGN(ExtraInstanceData, 16) diff --git a/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl index 411f96f6057..b4af2199565 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl @@ -4,9 +4,11 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) void main() { + select_id_set(in_select_buf[gl_InstanceID]); finalColor = colorLight; /* Relative to DPI scaling. Have constant screen size. */ diff --git a/source/blender/draw/engines/select/select_instance.hh b/source/blender/draw/engines/select/select_instance.hh index 11121eb18fc..a5962e20f4d 100644 --- a/source/blender/draw/engines/select/select_instance.hh +++ b/source/blender/draw/engines/select/select_instance.hh @@ -70,7 +70,7 @@ struct SelectBuf { } } - void select_bind(PassSimple &pass) + void select_bind(PassSimple::Sub &pass) { if (selection_type != SelectionType::DISABLED) { select_buf.push_update();