Skip to content

Commit

Permalink
Draw ellipse with geo shader + tilt
Browse files Browse the repository at this point in the history
  • Loading branch information
einarf committed Apr 16, 2020
1 parent 1d6a4c6 commit b337afe
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 52 deletions.
86 changes: 43 additions & 43 deletions arcade/draw_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,33 +216,10 @@ def draw_circle_filled(center_x: float, center_y: float, radius: float,
The default value of -1 means arcade will try to calulate a reasonable
amount of segments based on the size of the circle.
"""
window = get_window()
if not window:
raise RuntimeError("No window found")

ctx = window.ctx
program = ctx.shape_ellipse_unbuffered_program
geometry = ctx.shape_ellipse_unbuffered_geometry
buffer = ctx.shape_ellipse_unbuffered_buffer
# We need to normalize the color because we are setting it as a float uniform
if len(color) == 3:
color_normalized = (color[0] / 255, color[1] / 255, color[2] / 255, 1.0)
elif len(color) == 4:
color_normalized = (color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255) # type: ignore
else:
raise ValueError("Invalid color format. Use a 3 or 4 component tuple")

program['Projection'] = get_projection().flatten()
program['color'] = color_normalized
program['size'] = radius, radius
program['segments'] = num_segments
buffer.write(data=array.array('f', (center_x, center_y)).tobytes())

geometry.render(program, mode=gl.GL_POINTS, vertices=1)

# width = radius * 2
# height = radius * 2
# draw_ellipse_filled(center_x, center_y, width, height, color, num_segments=num_segments)
draw_ellipse_filled(center_x, center_y, radius * 2, radius * 2, color, 0, num_segments)


def draw_circle_outline(center_x: float, center_y: float, radius: float,
Expand Down Expand Up @@ -287,29 +264,52 @@ def draw_ellipse_filled(center_x: float, center_y: float,
:param int num_segments: float of triangle segments that make up this
circle. Higher is better quality, but slower render time.
"""
window = get_window()
if not window:
raise RuntimeError("No window found")

unrotated_point_list = []

for segment in range(num_segments):
theta = 2.0 * 3.1415926 * segment / num_segments

x = (width / 2) * math.cos(theta)
y = (height / 2) * math.sin(theta)

unrotated_point_list.append([x, y])

if tilt_angle == 0:
uncentered_point_list = unrotated_point_list
ctx = window.ctx
program = ctx.shape_ellipse_unbuffered_program
geometry = ctx.shape_ellipse_unbuffered_geometry
buffer = ctx.shape_ellipse_unbuffered_buffer
# We need to normalize the color because we are setting it as a float uniform
if len(color) == 3:
color_normalized = (color[0] / 255, color[1] / 255, color[2] / 255, 1.0)
elif len(color) == 4:
color_normalized = (color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255) # type: ignore
else:
uncentered_point_list = []
for point in unrotated_point_list:
uncentered_point_list.append(rotate_point(point[0], point[1], 0, 0, tilt_angle))
raise ValueError("Invalid color format. Use a 3 or 4 component tuple")

point_list = []
for point in uncentered_point_list:
point_list.append((point[0] + center_x, point[1] + center_y))
program['Projection'] = get_projection().flatten()
program['color'] = color_normalized
program['shape'] = width / 2, height / 2, tilt_angle
program['segments'] = num_segments
buffer.write(data=array.array('f', (center_x, center_y)).tobytes())

_generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_FAN)
geometry.render(program, mode=gl.GL_POINTS, vertices=1)

# unrotated_point_list = []
#
# for segment in range(num_segments):
# theta = 2.0 * 3.1415926 * segment / num_segments
#
# x = (width / 2) * math.cos(theta)
# y = (height / 2) * math.sin(theta)
#
# unrotated_point_list.append([x, y])
#
# if tilt_angle == 0:
# uncentered_point_list = unrotated_point_list
# else:
# uncentered_point_list = []
# for point in unrotated_point_list:
# uncentered_point_list.append(rotate_point(point[0], point[1], 0, 0, tilt_angle))
#
# point_list = []
# for point in uncentered_point_list:
# point_list.append((point[0] + center_x, point[1] + center_y))
#
# _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_FAN)


def draw_ellipse_outline(center_x: float, center_y: float, width: float,
Expand Down
11 changes: 8 additions & 3 deletions arcade/experimental/examples/shapes_perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ def do_draw_lines(self):
arcade.draw_lines(self.line_list, (255, 0, 0, 10))

def do_draw_circle_filled(self):
for c in self.single_circle_calls:
arcade.draw_circle_filled(c[0], c[1], c[2], c[3])
# for c in self.single_circle_calls:
# arcade.draw_circle_filled(c[0], c[1], c[2], c[3])
arcade.draw_circle_filled(400, 300, 300, arcade.color.AZURE)

def do_draw_ellipse_filled(self):
arcade.draw_ellipse_filled(400, 300, 100, 200, arcade.color.AZURE, self.elapsed * 10)

def do_draw_circle_outline(self):
pass
Expand All @@ -67,6 +71,7 @@ def on_draw(self):
# self.do_draw_line()
# self.do_draw_lines()
self.do_draw_circle_filled()
# self.do_draw_ellipse_filled()

self.execution_time += time.time() - start
self.frames += 1
Expand All @@ -79,7 +84,7 @@ def on_draw(self):
))
self.execution_time = 0
self.frames = 0
except:
except Exception:
import traceback
traceback.print_exc()
exit(0)
Expand Down
24 changes: 18 additions & 6 deletions arcade/resources/shaders/shapes/ellipse/filled_unbuffered_geo.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,27 @@ layout (triangle_strip, max_vertices = 256) out;

uniform mat4 Projection;
uniform int segments;
// xy size of the ellipse
uniform vec2 size;

// [x, y, tilt]
uniform vec3 shape;

void main() {
// Get center of the circle
vec2 center = gl_in[0].gl_Position.xy;
int segments_selected = 0;

// Calculate rotation/tilt
float angle = radians(shape.z);
mat2 rot = mat2(
cos(angle), -sin(angle),
sin(angle), cos(angle)
);

if (segments > 0) {
// The user defined number of segments. Clamp it.
segments_selected = segments;
} else {
// Estimate the number of segments needed based on size
segments_selected = int(2.0 * PI * max(size.x, size.y) / 10.0);
segments_selected = int(2.0 * PI * max(shape.x, shape.y) / 10.0);
}
// Clamp number of segments
segments_selected = clamp(segments_selected, MIN_SEGMENTS, MAX_SEGMENTS);
Expand All @@ -37,10 +43,16 @@ void main() {
gl_Position = Projection * vec4(center, 0.0, 1.0);
EmitVertex();

gl_Position = Projection * vec4(center + vec2(sin((i + 1) * step), cos((i + 1) * step)) * size, 0.0, 1.0);
// Calculate the ellipse/circle using 0, 0 as origin
vec2 p1 = vec2(sin((i + 1) * step), cos((i + 1) * step)) * shape.xy;
// Rotate the circle and then add translation to get the right origin
gl_Position = Projection * vec4((rot * p1) + center, 0.0, 1.0);
EmitVertex();

gl_Position = Projection * vec4(center + vec2(sin(i * step), cos(i * step)) * size, 0.0, 1.0);
// Calculate the ellipse/circle using 0, 0 as origin
vec2 p2 = vec2(sin(i * step), cos(i * step)) * shape.xy;
// Rotate the circle and then add translation to get the right origin
gl_Position = Projection * vec4((rot * p2) + center, 0.0, 1.0);
EmitVertex();

EndPrimitive();
Expand Down

0 comments on commit b337afe

Please sign in to comment.