diff --git a/gizmos/preselection.py b/gizmos/preselection.py index dd2dc390..b3e65671 100644 --- a/gizmos/preselection.py +++ b/gizmos/preselection.py @@ -56,17 +56,45 @@ def test_select(self, context, location): offscreen = global_data.offscreen if not offscreen: return -1 - with offscreen.bind(): - fb = gpu.state.active_framebuffer_get() - buffer = fb.read_color(mouse_x, mouse_y, 1, 1, 4, 0, "FLOAT") - r, g, b, alpha = buffer[0][0] - - if alpha > 0: - index = rgb_to_index(r, g, b) - if index != global_data.hover: - global_data.hover = index - context.area.tag_redraw() - elif global_data.hover != -1: + # TODO: Read buffer only once + PICK_SIZE = 10 + for x, y in get_spiral_coords(mouse_x, mouse_y, context.area.width, context.area.height, PICK_SIZE): + with offscreen.bind(): + fb = gpu.state.active_framebuffer_get() + buffer = fb.read_color(x, y, 1, 1, 4, 0, "FLOAT") + r, g, b, alpha = buffer[0][0] + + if alpha > 0: + index = rgb_to_index(r, g, b) + if index != global_data.hover: + global_data.hover = index + context.area.tag_redraw() + return -1 + + if global_data.hover != -1: context.area.tag_redraw() global_data.hover = -1 return -1 + + +def _spiral(N, M): + x,y = 0,0 + dx, dy = 0, -1 + + for dumb in range(N*M): + if abs(x) == abs(y) and [dx,dy] != [1,0] or x>0 and y == 1-x: + dx, dy = -dy, dx # corner, change direction + + if abs(x)>N/2 or abs(y)>M/2: # non-square + dx, dy = -dy, dx # change direction + x, y = -y+dx, x+dy # jump + + yield x, y + x, y = x+dx, y+dy + +def get_spiral_coords(X: int, Y: int, width: int, height: int, radius: int = 0): + """Returns a list of coordinates to check starting from given position spiraling out""" + + for x, y in _spiral(radius+1,radius+1): + if 0 <= (X+x) <= width and 0 <= (Y+y) <= height: + yield (X+x, Y+y) \ No newline at end of file diff --git a/model/base_entity.py b/model/base_entity.py index 5e158b1e..a198f34b 100644 --- a/model/base_entity.py +++ b/model/base_entity.py @@ -90,7 +90,7 @@ def line_width(self): @property def line_width_select(self): - return 20 * preferences.get_scale() + return 4 * preferences.get_scale() def __str__(self): _, local_index = breakdown_index(self.slvs_index) @@ -230,11 +230,9 @@ def draw(self, context): if not self.is_point(): shader.uniform_bool("dashed", (self.is_dashed(),)) - - if not self.is_point(): - viewport = [context.area.width, context.area.height] - shader.uniform_float("Viewport", viewport) - shader.uniform_float("thickness", self.line_width) + shader.uniform_float("dash_width", 0.05) + shader.uniform_float("dash_factor", 0.3) + gpu.state.line_width_set(self.line_width) batch.draw(shader) gpu.shader.unbind() @@ -256,10 +254,10 @@ def draw_id(self, context): shader.uniform_float("color", (*index_to_rgb(self.slvs_index), 1.0)) if not self.is_point(): - viewport = [context.area.width, context.area.height] - shader.uniform_float("Viewport", viewport) - shader.uniform_float("thickness", self.line_width_select) + # viewport = [context.area.width, context.area.height] + # shader.uniform_float("Viewport", viewport) shader.uniform_bool("dashed", (False,)) + gpu.state.line_width_set(self.line_width_select) batch.draw(shader) gpu.shader.unbind() diff --git a/shaders.py b/shaders.py index f4d00054..22083226 100644 --- a/shaders.py +++ b/shaders.py @@ -1,5 +1,6 @@ import gpu -from gpu.types import GPUShader +from gpu.types import GPUShader, GPUShaderCreateInfo, GPUStageInterfaceInfo +from gpu.shader import create_from_info from bpy import app import sys @@ -16,28 +17,16 @@ class Shaders: base_vertex_shader_3d = """ - uniform mat4 ModelViewProjectionMatrix; - - in vec3 pos; - void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f); + + vec2 ssPos = vec2(gl_Position.xy / gl_Position.w); + stipple_start = stipple_pos = ssPos; } """ base_fragment_shader_3d = """ - uniform vec4 color; - uniform float dash_width = 10.0; - uniform float dash_factor = 0.40; - uniform vec2 Viewport; - uniform bool dashed = false; - - noperspective in vec2 stipple_pos; - flat in vec2 stipple_start; - - out vec4 fragColor; void main() { - float aspect = Viewport.x/Viewport.y; float distance_along_line = distance(stipple_pos, stipple_start); float normalized_distance = fract(distance_along_line / dash_width); @@ -56,6 +45,31 @@ class Shaders: } """ + @classmethod + def get_base_shader_3d_info(cls): + + vert_out = GPUStageInterfaceInfo("stipple_pos_interface") + vert_out.no_perspective("VEC2", "stipple_pos") + vert_out.flat("VEC2", "stipple_start") + + # NOTE: How to set default values? + + shader_info = GPUShaderCreateInfo() + shader_info.push_constant("MAT4", "ModelViewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.push_constant("FLOAT", "dash_width") + shader_info.push_constant("FLOAT", "dash_factor") + # shader_info.push_constant("VEC2", "Viewport") + shader_info.push_constant("BOOL", "dashed") + shader_info.vertex_in(0, "VEC3", "pos") + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, "VEC4", "fragColor") + + shader_info.vertex_source(cls.base_vertex_shader_3d) + shader_info.fragment_source(cls.base_fragment_shader_3d) + + return shader_info + @staticmethod @cache def uniform_color_3d(): @@ -66,13 +80,21 @@ def uniform_color_3d(): @classmethod @cache def uniform_color_image_2d(cls): - vertex_shader = """ - uniform mat4 ModelViewProjectionMatrix; - - in vec2 pos; - in vec2 texCoord; - out vec2 v_texCoord; - + vert_out = GPUStageInterfaceInfo("uniform_color_image_2d_interface") + vert_out.smooth("VEC2", "v_texCoord") + + shader_info = GPUShaderCreateInfo() + shader_info.define("blender_srgb_to_framebuffer_space(a)", "a") + shader_info.push_constant("MAT4", "ModelViewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.vertex_in(0, "VEC2", "pos") + shader_info.vertex_in(1, "VEC2", "texCoord") + shader_info.sampler(0, "FLOAT_2D", "image") + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, "VEC4", "fragColor") + + shader_info.vertex_source( + """ void main() { gl_Position = ( @@ -81,12 +103,9 @@ def uniform_color_image_2d(cls): v_texCoord = texCoord; } """ - fragment_shader = """ - uniform vec4 color; - uniform sampler2D image; - in vec2 v_texCoord; - out vec4 fragColor; - + ) + shader_info.fragment_source( + """ void main() { fragColor = blender_srgb_to_framebuffer_space( @@ -94,11 +113,13 @@ def uniform_color_image_2d(cls): ); } """ - return GPUShader( - vertex_shader, - fragment_shader, ) + shader = create_from_info(shader_info) + del vert_out + del shader_info + return shader + @classmethod @cache def id_line_3d(cls): @@ -108,113 +129,42 @@ def id_line_3d(cls): @classmethod @cache def uniform_color_line_3d(cls): - geometry_shader = """ - layout(lines) in; - layout(triangle_strip, max_vertices = 10) out; - uniform mat4 ModelViewProjectionMatrix; - uniform vec2 Viewport; - uniform float thickness = float(0.1); - - /* We leverage hardware interpolation to compute distance along the line. */ - noperspective out vec2 stipple_pos; /* In screen space */ - flat out vec2 stipple_start; /* In screen space */ - - out vec2 mTexCoord; - out float alpha; - float aspect = Viewport.x/Viewport.y; - vec2 pxVec = vec2(1.0/Viewport.x,1.0/Viewport.y); - float minLength = length(pxVec); - vec2 get_line_width(vec2 normal, float width){ - vec2 offsetvec = vec2(normal * width); - if (length(offsetvec) < minLength){ - offsetvec = normalize(offsetvec); - offsetvec *= minLength; - } - return(offsetvec); - } - float get_line_alpha(vec2 normal, float width){ - vec2 offsetvec = vec2(normal * width); - float alpha = 1.0; - if (length(offsetvec) < minLength){ - alpha *= (length(offsetvec)/minLength); - } - return alpha; - } - void main() { - //calculate line normal - vec4 p1 = gl_in[0].gl_Position; - vec4 p2 = gl_in[1].gl_Position; - vec2 ssp1 = vec2(p1.xy / p1.w); - vec2 ssp2 = vec2(p2.xy / p2.w); - float width = thickness; - vec2 dir = normalize((ssp2 - ssp1) * Viewport.xy); - vec2 normal = vec2(-dir[1], dir[0]); - normal = normalize(normal); - - // get offset factor from normal and user input thickness - vec2 offset = get_line_width(normal,width) / Viewport.xy; - float lineAlpha = get_line_alpha(normal,width); - vec4 coords[4]; - vec2 texCoords[4]; - coords[0] = vec4((ssp1 + offset)*p1.w,p1.z,p1.w); - texCoords[0] = vec2(0,1); - coords[1] = vec4((ssp1 - offset)*p1.w,p1.z,p1.w); - texCoords[1] = vec2(0,0); - coords[2] = vec4((ssp2 + offset)*p2.w,p2.z,p2.w); - texCoords[2] = vec2(0,1); - coords[3] = vec4((ssp2 - offset)*p2.w,p2.z,p2.w); - texCoords[3] = vec2(0,0); - - for (int i = 0; i < 4; ++i) { - mTexCoord = texCoords[i]; - gl_Position = coords[i]; - alpha = lineAlpha; - - vec4 stipple_base; - if (i < 2) { - stipple_base = vec4(ssp1*p1.w,p1.z,p1.w); - } - else { - stipple_base = vec4(ssp2*p2.w, p2.z, p2.w); - } - stipple_start = stipple_pos = Viewport * 0.5 * (stipple_base.xy / stipple_base.w); - - EmitVertex(); - } - EndPrimitive(); - } - """ - - return GPUShader( - cls.base_vertex_shader_3d, - cls.base_fragment_shader_3d, - geocode=geometry_shader, - ) + shader_info = cls.get_base_shader_3d_info() + shader = create_from_info(shader_info) + del shader_info + return shader @staticmethod @cache def id_shader_3d(): - vertex_shader = """ - uniform mat4 ModelViewProjectionMatrix; - in vec3 pos; + shader_info = GPUShaderCreateInfo() + shader_info.push_constant("MAT4", "ModelViewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.vertex_in(0, "VEC3", "pos") + shader_info.fragment_out(0, "VEC4", "fragColor") + shader_info.vertex_source( + """ void main() { gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); } """ + ) - fragment_shader = """ - uniform vec4 color; - out vec4 fragColor; - + shader_info.fragment_source( + """ void main() { fragColor = color; } """ - return GPUShader(vertex_shader, fragment_shader) + ) + + shader = create_from_info(shader_info) + del shader_info + return shader @staticmethod @cache