WIP gizmo for parametreic extrusion, see #1324

This commit is contained in:
QwiglyDee
2021-03-01 18:42:28 +07:00
parent b9f81b8014
commit 63384a730b
3 changed files with 674 additions and 1 deletions
@@ -6,7 +6,7 @@ bpy = sys.modules.get("bpy")
if bpy is not None:
import bpy
import importlib
from . import handler, ui, prop, operator
from . import handler, ui, prop, operator, gizmos
modules = {
"project": None,
@@ -145,6 +145,11 @@ if bpy is not None:
ui.BIM_UL_drawinglist,
ui.BIM_UL_topics,
ui.BIM_ADDON_preferences,
gizmos.UglyDotGizmo,
gizmos.DotGizmo,
gizmos.DimensionLabelGizmo,
gizmos.ExtrusionGuidesGizmo,
gizmos.ExtrusionWidget
]
for module in modules.values():
@@ -0,0 +1,400 @@
import bpy
import blf
from bpy import types
import math
from mathutils import Vector, Matrix
from mathutils import geometry
import gpu, bgl
from bpy_extras import view3d_utils
from .shaders import DotsGizmoShader, ExtrusionGuidesShader, BaseLinesShader
"""Gizmos under the hood
## Transforms:
source/blender/windowmanager/gizmo/WM_gizmo_types.h
matrix_basis -- "Transformation of this gizmo." = placement in scene
matrix_offset -- "Custom offset from origin." = local transforms according to state/value
matrix_space -- "The space this gizmo is being modified in." used by some gizmos for undefined purposes
matrix_world -- final matrix, scaled according to viewport zoom and custom scale_basis
source/blender/windowmanager/gizmo/intern/wm_gizmo.c:WM_gizmo_calc_matrix_final_params
final = space @ (autoscale * (basis @ offset))
final = space @ (basis @ offset) -- if gizmo.use_draw_scale == False
final = space @ ((autoscale * basis) @ offset) -- if gizmo.use_draw_offset_scale
source/blender/windowmanager/gizmo/intern/wm_gizmo.c:wm_gizmo_calculate_scale
autoscale = gizmo.scale_basis * magic(preferences, matrix_space, matrix_basis, context.region_data)
magic -- making 1.0 to match preferences.view.gizmo_size pixels (75 by default)
## Selection
select_id -- apparently, id of a selectable part
test_select -- expected to return id of selection, doesn't seem to work
draw_select -- fake-draw of selection geometry for gpu-side cursor tracking
"""
# some geometries for Gizmo.custom_shape shaders
CUBE = (
(+1, +1, +1), (-1, +1, +1), (+1, -1, +1), # top
(+1, -1, +1), (-1, +1, +1), (-1, -1, +1),
(+1, +1, +1), (+1, -1, +1), (+1, +1, -1), # right
(+1, +1, -1), (+1, -1, +1), (+1, -1, -1),
(+1, +1, +1), (+1, +1, -1), (-1, +1, +1), # back
(-1, +1, +1), (+1, +1, -1), (-1, +1, -1),
(-1, -1, -1), (-1, +1, -1), (+1, -1, -1), # bot
(+1, -1, -1), (-1, +1, -1), (+1, +1, -1),
(-1, -1, -1), (-1, -1, +1), (-1, +1, -1), # left
(-1, +1, -1), (-1, -1, +1), (-1, +1, +1),
(-1, -1, -1), (+1, -1, -1), (-1, -1, +1), # front
(-1, -1, +1), (+1, -1, -1), (+1, -1, +1)
)
DISC = (
(0.0, 0.0, 0.0), (1.0, 0.0, 0), (0.8660254037844387, 0.49999999999999994, 0),
(0.0, 0.0, 0.0), (0.8660254037844387, 0.49999999999999994, 0), (0.5000000000000001, 0.8660254037844386, 0),
(0.0, 0.0, 0.0), (0.5000000000000001, 0.8660254037844386, 0), (6.123233995736766e-17, 1.0, 0),
(0.0, 0.0, 0.0), (6.123233995736766e-17, 1.0, 0), (-0.4999999999999998, 0.8660254037844387, 0),
(0.0, 0.0, 0.0), (-0.4999999999999998, 0.8660254037844387, 0), (-0.8660254037844385, 0.5000000000000003, 0),
(0.0, 0.0, 0.0), (-0.8660254037844385, 0.5000000000000003, 0), (-1.0, 1.2246467991473532e-16, 0),
(0.0, 0.0, 0.0), (-1.0, 1.2246467991473532e-16, 0), (-0.8660254037844388, -0.4999999999999997, 0),
(0.0, 0.0, 0.0), (-0.8660254037844388, -0.4999999999999997, 0), (-0.5000000000000004, -0.8660254037844384, 0),
(0.0, 0.0, 0.0), (-0.5000000000000004, -0.8660254037844384, 0), (-1.8369701987210297e-16, -1.0, 0),
(0.0, 0.0, 0.0), (-1.8369701987210297e-16, -1.0, 0), (0.49999999999999933, -0.866025403784439, 0),
(0.0, 0.0, 0.0), (0.49999999999999933, -0.866025403784439, 0), (0.8660254037844384, -0.5000000000000004, 0),
(0.0, 0.0, 0.0), (0.8660254037844384, -0.5000000000000004, 0), (1.0, 0.0, 0),
)
X3DISC = (
(0.0, 0.0, 0.0), (1.0, 0.0, 0), (0.8660254037844387, 0.49999999999999994, 0),
(0.0, 0.0, 0.0), (0.8660254037844387, 0.49999999999999994, 0), (0.5000000000000001, 0.8660254037844386, 0),
(0.0, 0.0, 0.0), (0.5000000000000001, 0.8660254037844386, 0), (6.123233995736766e-17, 1.0, 0),
(0.0, 0.0, 0.0), (6.123233995736766e-17, 1.0, 0), (-0.4999999999999998, 0.8660254037844387, 0),
(0.0, 0.0, 0.0), (-0.4999999999999998, 0.8660254037844387, 0), (-0.8660254037844385, 0.5000000000000003, 0),
(0.0, 0.0, 0.0), (-0.8660254037844385, 0.5000000000000003, 0), (-1.0, 1.2246467991473532e-16, 0),
(0.0, 0.0, 0.0), (-1.0, 1.2246467991473532e-16, 0), (-0.8660254037844388, -0.4999999999999997, 0),
(0.0, 0.0, 0.0), (-0.8660254037844388, -0.4999999999999997, 0), (-0.5000000000000004, -0.8660254037844384, 0),
(0.0, 0.0, 0.0), (-0.5000000000000004, -0.8660254037844384, 0), (-1.8369701987210297e-16, -1.0, 0),
(0.0, 0.0, 0.0), (-1.8369701987210297e-16, -1.0, 0), (0.49999999999999933, -0.866025403784439, 0),
(0.0, 0.0, 0.0), (0.49999999999999933, -0.866025403784439, 0), (0.8660254037844384, -0.5000000000000004, 0),
(0.0, 0.0, 0.0), (0.8660254037844384, -0.5000000000000004, 0), (1.0, 0.0, 0),
(0.0, 0.0, 0.0), (0, 1.0, 0.0), (0, 0.8660254037844387, 0.49999999999999994),
(0.0, 0.0, 0.0), (0, 0.8660254037844387, 0.49999999999999994), (0, 0.5000000000000001, 0.8660254037844386),
(0.0, 0.0, 0.0), (0, 0.5000000000000001, 0.8660254037844386), (0, 6.123233995736766e-17, 1.0),
(0.0, 0.0, 0.0), (0, 6.123233995736766e-17, 1.0), (0, -0.4999999999999998, 0.8660254037844387),
(0.0, 0.0, 0.0), (0, -0.4999999999999998, 0.8660254037844387), (0, -0.8660254037844385, 0.5000000000000003),
(0.0, 0.0, 0.0), (0, -0.8660254037844385, 0.5000000000000003), (0, -1.0, 1.2246467991473532e-16),
(0.0, 0.0, 0.0), (0, -1.0, 1.2246467991473532e-16), (0, -0.8660254037844388, -0.4999999999999997),
(0.0, 0.0, 0.0), (0, -0.8660254037844388, -0.4999999999999997), (0, -0.5000000000000004, -0.8660254037844384),
(0.0, 0.0, 0.0), (0, -0.5000000000000004, -0.8660254037844384), (0, -1.8369701987210297e-16, -1.0),
(0.0, 0.0, 0.0), (0, -1.8369701987210297e-16, -1.0), (0, 0.49999999999999933, -0.866025403784439),
(0.0, 0.0, 0.0), (0, 0.49999999999999933, -0.866025403784439), (0, 0.8660254037844384, -0.5000000000000004),
(0.0, 0.0, 0.0), (0, 0.8660254037844384, -0.5000000000000004), (0, 1.0, 0.0),
(0.0, 0.0, 0.0), (0.0, 0, 1.0), (0.49999999999999994, 0, 0.8660254037844387),
(0.0, 0.0, 0.0), (0.49999999999999994, 0, 0.8660254037844387), (0.8660254037844386, 0, 0.5000000000000001),
(0.0, 0.0, 0.0), (0.8660254037844386, 0, 0.5000000000000001), (1.0, 0, 6.123233995736766e-17),
(0.0, 0.0, 0.0), (1.0, 0, 6.123233995736766e-17), (0.8660254037844387, 0, -0.4999999999999998),
(0.0, 0.0, 0.0), (0.8660254037844387, 0, -0.4999999999999998), (0.5000000000000003, 0, -0.8660254037844385),
(0.0, 0.0, 0.0), (0.5000000000000003, 0, -0.8660254037844385), (1.2246467991473532e-16, 0, -1.0),
(0.0, 0.0, 0.0), (1.2246467991473532e-16, 0, -1.0), (-0.4999999999999997, 0, -0.8660254037844388),
(0.0, 0.0, 0.0), (-0.4999999999999997, 0, -0.8660254037844388), (-0.8660254037844384, 0, -0.5000000000000004),
(0.0, 0.0, 0.0), (-0.8660254037844384, 0, -0.5000000000000004), (-1.0, 0, -1.8369701987210297e-16),
(0.0, 0.0, 0.0), (-1.0, 0, -1.8369701987210297e-16), (-0.866025403784439, 0, 0.49999999999999933),
(0.0, 0.0, 0.0), (-0.866025403784439, 0, 0.49999999999999933), (-0.5000000000000004, 0, 0.8660254037844384),
(0.0, 0.0, 0.0), (-0.5000000000000004, 0, 0.8660254037844384), (0.0, 0, 1.0),
)
class CustomGizmo():
# FIXME: highliting/selection doesnt work
def draw_very_custom_shape(self, ctx, custom_shape, select_id=None):
# similar to draw_custom_shape
shape, batch, shader = custom_shape
shader.bind()
if select_id is not None:
gpu.select.load_id(select_id)
else:
if self.is_highlight:
color = (*self.color_highlight, self.alpha_highlight)
else:
color = (*self.color, self.alpha)
shader.uniform_float('color', color)
shape.glenable()
shape.uniform_region(ctx)
# shader.uniform_float('modelMatrix', self.matrix_world)
with gpu.matrix.push_pop():
gpu.matrix.multiply_matrix(self.matrix_world)
batch.draw()
bgl.glDisable(bgl.GL_BLEND)
class OffsetHandle():
"""Handling mouse to offset gizmo from base along Z axis"""
# FIXME: works a bit weird for rotated objects
def invoke(self, ctx, event):
self.init_value = self.target_get_value('offset') / self.scale_value
coordz = self.project_mouse(ctx, event)
if coordz is None:
return {'CANCELLED'}
self.init_coordz = coordz
return {'RUNNING_MODAL'}
def modal(self, ctx, event, tweak):
coordz = self.project_mouse(ctx, event)
if coordz is None:
return {'CANCELLED'}
delta = coordz - self.init_coordz
if 'PRECISE' in tweak:
delta /= 10.0
value = max(0, self.init_value + delta)
value *= self.scale_value
# ctx.area.header_text_set(f"coords: {self.init_coordz} - {coordz}, delta: {delta}, value: {value}")
ctx.area.header_text_set(f"Depth: {value}")
self.target_set_value('offset', value)
return {'RUNNING_MODAL'}
def project_mouse(self, ctx, event):
"""Projecting mouse coords to local axis Z"""
# logic from source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c:gizmo_arrow_modal
mouse = Vector((event.mouse_region_x, event.mouse_region_y))
region = ctx.region
region3d = ctx.region_data
ray_orig = view3d_utils.region_2d_to_origin_3d(region, region3d, mouse)
ray_norm = view3d_utils.region_2d_to_vector_3d(region, region3d, mouse)
# 'arrow' origin and direction
base = Vector((0, 0, 0))
axis = Vector((0, 0, 1))
# projecttion of the arrow to a plane, perpendicular to view ray
axis_proj = axis - ray_norm * axis.dot(ray_norm)
# intersection of the axis with the plane through view origin perpendicular to the arrow projection
coords = geometry.intersect_line_plane(base, axis, ray_orig, axis_proj)
return coords.z
def exit(self, ctx, cancel):
if cancel:
self.target_set_value('offset', self.init_value)
else:
self.group.update(ctx)
class UglyDotGizmo(OffsetHandle, types.Gizmo):
"""three orthogonal circles"""
bl_idname = "BIM_GT_uglydot_3d"
bl_target_properties = (
{'id': 'offset', 'type': 'FLOAT', 'array_length': 1},
)
__slots__ = (
'scale_value',
'custom_shape',
'init_value',
'init_coordz',
)
def setup(self):
self.custom_shape = self.new_custom_shape(type='TRIS', verts=X3DISC)
def refresh(self):
offset = self.target_get_value('offset') / self.scale_value
self.matrix_offset.col[3][2] = offset # z-shift
def draw(self, ctx):
self.refresh()
self.draw_custom_shape(self.custom_shape)
def draw_select(self, ctx, select_id):
self.refresh()
self.draw_custom_shape(self.custom_shape, select_id=select_id)
class DotGizmo(CustomGizmo, OffsetHandle, types.Gizmo):
"""Single dot viewport-aligned"""
# FIXME: make it selectable
bl_idname = "BIM_GT_dot_2d"
bl_target_properties = (
{'id': 'offset', 'type': 'FLOAT', 'array_length': 1},
)
__slots__ = (
'scale_value',
'custom_shape',
)
def setup(self):
shader = DotsGizmoShader()
self.custom_shape = shader, shader.batch(pos=((0, 0, 0),)), shader.prog
self.use_draw_scale = False
def refresh(self):
offset = self.target_get_value('offset') / self.scale_value
self.matrix_offset.col[3][2] = offset # z-shifted
def draw(self, ctx):
self.refresh()
self.draw_very_custom_shape(ctx, self.custom_shape)
def draw_select(self, ctx, select_id):
self.refresh()
self.draw_very_custom_shape(ctx, self.custom_shape, select_id=select_id)
# doesn't get called
# def test_select(self, ctx, location):
# pass
class ExtrusionGuidesGizmo(CustomGizmo, types.Gizmo):
"""Extrusion guides
Noninteractive gizmo to indicate extrusion depth and planes.
Draws main segment and orthogonal cross at endpoints.
"""
bl_idname = "BIM_GT_extrusion_guides"
bl_target_properties = (
{'id': 'depth', 'type': 'FLOAT', 'array_length': 1},
)
__slots__ = (
'scale_value',
'custom_shape'
)
def setup(self):
shader = ExtrusionGuidesShader()
self.custom_shape = shader, shader.batch(pos=((0, 0, 0), (0, 0, 1))), shader.prog
self.use_draw_scale = False
def refresh(self):
depth = self.target_get_value('depth') / self.scale_value
self.matrix_offset.col[2][2] = depth # z-scaled
def draw(self, ctx):
self.refresh()
self.draw_very_custom_shape(ctx, self.custom_shape)
class DimensionLabelGizmo(types.Gizmo):
"""Text label for a dimension"""
# does not work properly, fonts are totally screwed up
bl_idname = "BIM_GT_dimension_label"
bl_target_properties = (
{'id': 'value', 'type': 'FLOAT', 'array_length': 1},
)
__slots__ = (
'text_label'
)
def setup(self):
pass
def refresh(self, ctx):
value = self.target_get_value('value')
self.matrix_offset.col[3][2] = value * .5
unit_system = ctx.scene.unit_settings.system
self.text_label = bpy.utils.units.to_string(unit_system, 'LENGTH', value, 3, split_unit=False)
def draw(self, ctx):
self.refresh(ctx)
self.draw_text(ctx)
def draw_text(self, ctx):
font_id = 0
font_size = 16
dpi = ctx.preferences.system.dpi
# pos = self.matrix_world @ Vector((0, 0, 0, 1))
# pos = Vector((0, 0, 0.5))
# region = ctx.region
# region3d = ctx.region_data
# pos = view3d_utils.location_3d_to_region_2d(region, region3d, pos)
# text = self.text_label
blf.size(font_id, font_size, dpi)
blf.position(font_id, 0, 0, 0)
blf.color(font_id, *self.color, self.alpha)
blf.draw(font_id, "ABC")
class ExtrusionWidget(types.GizmoGroup):
bl_idname = "bim.extrusion_widget"
bl_label = "Extrusion Gizmos"
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_options = {'3D', 'PERSISTENT'}
# FIXME: use proper scale from ifc value to blender units
@classmethod
def poll(cls, ctx):
obj = ctx.object
return (obj and obj.type == 'MESH'
and obj.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth') is not None)
def setup(self, ctx):
target = ctx.object
prop = target.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth')
basis = target.matrix_world.normalized()
theme = ctx.preferences.themes[0].user_interface
gz = self.handle = self.gizmos.new('BIM_GT_uglydot_3d')
gz.matrix_basis = basis
gz.scale_basis = 0.1
gz.color = gz.color_highlight = tuple(theme.gizmo_primary)
gz.alpha = 0.5
gz.alpha_highlight = 1.0
gz.use_draw_modal = True
gz.target_set_prop('offset', prop, 'value')
gz.scale_value = 1000
gz = self.guides = self.gizmos.new('BIM_GT_extrusion_guides')
gz.matrix_basis = basis
gz.color = gz.color_highlight = tuple(theme.gizmo_secondary)
gz.alpha = gz.alpha_highlight = 0.5
gz.use_draw_modal = True
gz.target_set_prop('depth', prop, 'value')
gz.scale_value = 1000
# gz = self.label = self.gizmos.new('GIZMO_GT_dimension_label')
# gz.matrix_basis = basis
# gz.color = tuple(theme.gizmo_secondary)
# gz.alpha = 0.5
# gz.use_draw_modal = True
# gz.target_set_prop('value', target.demo, 'depth')
def refresh(self, ctx):
"""updating gizmos"""
target = ctx.object
basis = target.matrix_world.normalized()
self.handle.matrix_basis = basis
self.guides.matrix_basis = basis
def update(self, ctx):
"""updating object"""
bpy.ops.bim.update_parametric_representation()
# parameters disappear after update
# need to retrieve and rebind them again
bpy.ops.bim.get_representation_ifc_parameters()
target = ctx.object
prop = target.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth')
self.handle.target_set_prop('offset', prop, 'value')
self.guides.target_set_prop('depth', prop, 'value')
@@ -0,0 +1,268 @@
from mathutils import Matrix
import bgl
from gpu.types import GPUShader
from gpu_extras.batch import batch_for_shader
class BaseShader():
"""Wrapepr for GPUShader
To use for viewport decorations with geometry generated on GPU side.
The Geometry shader works in clipping coords (aftre projecting before division and window scaling).
To make window-scale geometry, vectors should be calculated in window space and than back-projected to clipping spae.
Provide `winSize` uniform vector with halfsize of window, and use W2C and C2W macros.
Replace glsl code in derived classes.
Beware of unused attributes and uniforms: glsl compiler will optimize them out and blender fail with an exception.
Vertex topology attribute to use with line segments:
- 0 = inner
- 1 = starting
- 2 = ending
- 3 = isolated
"""
TYPE = None # should be LINES|POINTS|etc
DEF_GLSL = """
#define PI 3.141592653589793
"""
VERT_GLSL = """
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec3 pos;
in uint topology;
out vec4 gl_Position;
out uint topo;
void main() {
gl_Position = viewMatrix * modelMatrix * vec4(pos, 1.0);
topo = topology;
}
"""
# prepended to geom_glsl
LIB_GLSL = """
uniform vec2 winSize;
// convert camera to window
#define C2W(v) vec4(v.x * winSize.x / v.w, v.y * winSize.y / v.w, v.z / v.w, 1)
// convert window to camera
#define W2C(v) vec4(v.x * v.w / winSize.x, v.y * v.w / winSize.y, v.z * v.w, 1)
void emitSegment(vec4 p0, vec4 p1) {
gl_Position = p0;
EmitVertex();
gl_Position = p1;
EmitVertex();
EndPrimitive();
}
void emitTriangle(vec4 p1, vec4 p2, vec4 p3) {
gl_Position = p1;
EmitVertex();
gl_Position = p2;
EmitVertex();
gl_Position = p3;
EmitVertex();
EndPrimitive();
}
"""
GEOM_GLSL = """
"""
FRAG_GLSL = """
uniform vec4 color;
out vec4 fragColor;
void main() {
fragColor = color;
}
"""
def __init__(self):
# NB: libcode arg doesn't work
self.prog = GPUShader(vertexcode=self.VERT_GLSL,
fragcode=self.FRAG_GLSL,
geocode=self.LIB_GLSL + self.GEOM_GLSL,
defines=self.DEF_GLSL)
def batch(self, indices=None, **data):
"""Returns automatic GPUBatch filled with provided parameters
"""
batch = batch_for_shader(self.prog, self.TYPE, data, indices=indices)
batch.program_set(self.prog)
return batch
def bind(self):
self.prog.bind()
def glenable(self):
bgl.glEnable(bgl.GL_BLEND)
bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
bgl.glBlendEquation(bgl.GL_FUNC_ADD)
# bgl.glEnable(bgl.GL_DEPTH_TEST)
# bgl.glDepthFunc(bgl.GL_LEQUAL)
# bgl.glDepthMask(True)
def uniform_region(self, ctx):
region = ctx.region
region3d = ctx.region_data
try:
self.prog.uniform_float('viewMatrix', region3d.perspective_matrix)
except ValueError: # unused uniform
pass
try:
self.prog.uniform_float('winSize', (region.width / 2, region.height / 2))
except ValueError: # unused uniform
pass
class BaseLinesShader(BaseShader):
"""Draws line segments with gaps around vertices at endpoints
"""
TYPE = 'LINES'
DEF_GLSL = BaseShader.DEF_GLSL + """
#define GAP_SIZE {gap_size}
"""
GEOM_GLSL = """
layout(lines) in;
in uint topo[];
layout(line_strip, max_vertices=2) out;
void main() {
vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position;
uint t0 = topo[0], t1 = topo[1];
vec4 p0w = C2W(p0), p1w = C2W(p1);
vec4 edge = p1w - p0w, dir = normalize(edge);
vec4 gap = dir * GAP_SIZE;
vec4 p0_ = p0w, p1_ = p1w;
if (t0 == 1u) {
p0_ += gap;
}
if (t1 == 2u) {
p1_ -= gap;
}
emitSegment(W2C(p0_), W2C(p1_));
}
"""
def __init__(self, gap_size=16):
super().__init__(gap_size=gap_size)
def glenable(self):
super().glenable()
bgl.glEnable(bgl.GL_LINE_SMOOTH)
class GizmoShader(BaseShader):
"""Gizmo 2D shader
Scaling to match viewport is partially controlled by user preferences and gizmo code.
"""
# TODO: add some magic to respect gizmo settings/params
VERT_GLSL = """
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
void main() {
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
}
"""
class DotsGizmoShader(GizmoShader):
"""Draws circles of radius 1 around points"""
TYPE = 'POINTS'
DEF_GLSL = BaseShader.DEF_GLSL + """
#define CIRCLE_SEGMENTS 12
#define CIRCLE_RADIUS 8
"""
GEOM_GLSL = """
layout(points) in;
layout(triangle_strip, max_vertices=36) out;
// apparently can be precalculated
void makeCircle(out vec4 circle[CIRCLE_SEGMENTS+1]) {
float angle_d = PI * 2 / CIRCLE_SEGMENTS;
for(int i = 0; i<=CIRCLE_SEGMENTS; i++) {
float angle = angle_d * i;
circle[i] = vec4(cos(angle), sin(angle), 0, 0) * CIRCLE_RADIUS;
}
}
void main() {
vec4 p0 = gl_in[0].gl_Position;
vec4 p0w = C2W(p0);
vec4 circle[CIRCLE_SEGMENTS+1];
makeCircle(circle);
vec4 p1w, p2w;
for(int i = 0; i<=CIRCLE_SEGMENTS; i++) {
p1w = p0w + circle[i];
p2w = p0w + circle[i+1];
emitTriangle(p0, W2C(p1w), W2C(p2w));
}
/*
for(int i = 0; i<=CIRCLE_SEGMENTS; i++) {
p1w = p0 + circle[i];
p2w = p0 + circle[i+1];
emitTriangle(p0, p1w, p2w);
}
*/
}
"""
class ExtrusionGuidesShader(GizmoShader):
"""Draws lines and add cross in XY plane at endpoints"""
TYPE = 'LINES'
DEF_GLSL = BaseShader.DEF_GLSL + """
#define CROSS_SIZE .5
"""
GEOM_GLSL = """
uniform mat4 ModelViewProjectionMatrix;
layout(lines) in;
layout(line_strip, max_vertices=10) out;
void main() {
vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position;
vec4 p0w = C2W(p0), p1w = C2W(p1);
emitSegment(p0, p1);
vec4 bx = ModelViewProjectionMatrix[0] * CROSS_SIZE;
vec4 by = ModelViewProjectionMatrix[1] * CROSS_SIZE;
emitSegment(p0 - bx, p0 + bx);
emitSegment(p0 - by, p0 + by);
emitSegment(p1 - bx, p1 + bx);
emitSegment(p1 - by, p1 + by);
}
"""
def glenable(self):
super().glenable()
bgl.glEnable(bgl.GL_LINE_SMOOTH)