Graphic debugging proof of concept

So, i am doing like @Xikon and sharing here a piece of code I use a lot right now.

Currently drawing in the viewport is easier than never!, I really like the new draw api!
But as everyone know, we, python programmers are lazy, so having a package that does stuff for us is fantastic.

Following that principle, I made a package for myself, and found it so handy that I had to share.

class DrawCallbackPx:
	def __init__(self):
		self.vertices = []
		self.colors = []
		self.text = []
		self.thickness = 2
		self.font_shadow = (0, 0, 0, 0.5)
		self.shader = gpu.shader.from_builtin("2D_SMOOTH_COLOR")
		self.batch_redraw = False
		self.batch = None
		self.handler = None

	def __call__(self):
		self.draw()

	def add_text(self, text, location, size, color=(0, 0, 0, 1), dpi=72):
		self.text.append((text, location, size, color, dpi))

	def add_circle(self, center, radius, resolution, color=(1, 0, 0, 1)):
		self.batch_redraw = True
		for i in range(resolution):
			line_point_a = (sin(i / resolution * 2 * pi) * radius + center[0],
							cos(i / resolution * 2 * pi) * radius + center[1])
			line_point_b = (sin((i + 1) / resolution * 2 * pi) * radius + center[0],
							cos((i + 1) / resolution * 2 * pi) * radius + center[1])
			self.add_line(line_point_a, line_point_b, color)

	def add_line(self, point_a, point_b, color_a=(1, 0, 0, 1), color_b=None):
		self.batch_redraw = True
		self.vertices.append(point_a)
		self.vertices.append(point_b)
		self.colors.append(color_a)
		self.colors.append(color_b if color_b else color_a)

	def remove_last_line(self):
		self.vertices.pop(-1)
		self.vertices.pop(-1)

	def remove_last_text(self):
		self.text.pop(-1)

	def clear(self):
		self.vertices.clear()
		self.colors.clear()
		self.text.clear()

	def update_batch(self):
		self.batch_redraw = False
		self.batch = gpu_extras.batch.batch_for_shader(self.shader, "LINES",
													   {"pos": self.vertices, "color": self.colors})

	def setup_handler(self):
		self.handler = bpy.types.SpaceView3D.draw_handler_add(self, (), "WINDOW", "POST_PIXEL")

	def remove_handler(self):
		bpy.types.SpaceView3D.draw_handler_remove(self.handler, "WINDOW")

	def draw(self):
		bgl.glEnable(bgl.GL_BLEND)
		if self.batch_redraw or not self.batch:
			self.update_batch()
		bgl.glLineWidth(self.thickness)
		self.shader.bind()
		self.batch.draw(self.shader)
		bgl.glLineWidth(1)

		for text, location, size, color, dpi in self.text:
			blf.position(0, location[0], location[1], 0)
			blf.size(0, size, dpi)
			blf.color(0, *color)
			blf.shadow(0, 3, *self.font_shadow)
			blf.draw(0, text)

		bgl.glDisable(bgl.GL_BLEND)

For drawing in blender, the main pattern is to make a function and add it as a handler, it somehow has some funky namespace problems so, we have to pass all the data for drawing through a tuple argument.
I really don’t like this pattern, so here is what I did.

Its a class that contains a __call__ method which makes it behave like a function, BUT it can store data in its own namespace and anyone who get a reference to its instance can change that data remotely, different from a method, it can be accessed from multiple operators and still be a single instance.

Personally, I like it because it abstracts all the drawing funkyness into add_line() methods which are really easy to use, I guess it could be extended with add_triangle() and add_primitive() methods also.

ezgif-2-6b36647985a1

8 Likes

Saving each sub operation (child operation) under a master operation (parent operation) as a temporary save state before applying the operation could provide greater flexibility for the user. (Allowing the user to edit the sub operations before applying.) Think modifiers.

Examples:

  1. The user draws a series of connected lines. The user selects an intersecting point and moves the point, then applies the operation.

  2. The user draws a series of connected lines. The user selects an intersecting point and snaps the point to a location (vertex), then applies the operation.

  3. The user draws a series of connected lines. The user selects an intersecting point and converts the point to a nurb curve, adjusts the curve, then applies the operation.

  4. The user draws a series of connected lines. The user rotates around an object and continues to draw a series of connected lines. The user selects an intersecting point and converts the point to a nurb curve, adjusts the curve, then applies the operation.

This method could be used for most if not all operations in Blender.