2020-03-12 23:05:12 +10:30
tool
2021-01-29 19:26:44 +10:30
extends Control
var tween : = Tween . new ( )
var mesh : = Mesh . new ( )
2019-11-10 15:09:14 +10:30
2021-01-05 01:38:38 +10:30
export var ring_px : = 4 # Analogous to diameter
export var receptor_px : = 24 # Diameter
export var shadow_px : = 8 # Outer edge, analogous to radius
export var line_color : = Color . blue
export var dot_color : = Color . blue
2021-01-05 22:27:11 +10:30
export var shadow_color : = Color ( 0.0 , 0.0 , 0.0 , 0.57 )
2021-01-06 23:10:50 +10:30
var alpha : = 1.0
2019-11-18 13:11:02 +10:30
var center : = Vector2 ( 0.0 , 0.0 )
2019-11-10 15:09:14 +10:30
2020-03-12 23:05:12 +10:30
var ring_vertex_count : = 36
var ring_skew : = 0.0
2019-12-18 15:59:56 +10:30
func make_ring_mesh ( inner_vertices : int , thickness : float , radius : float , skew : = 0.5 , repeat_start : = true ) :
2019-12-17 15:05:27 +10:30
# This makes a trianglestrip around the ring, consisting of chords on the inside and tangents on the outside.
# The goal is to exchange some fragment and vertex processing load:
# - a full quad of the ring would be the maximum fragment load and minimum vertex load
# - a complex mesh closely following the outline of the ring would minimize discarded fragments at the cost of increased vertex processing
# - the ideal workload ratio is probably different for each GPU and also depends on other things our program is doing
assert ( inner_vertices > = 3 )
assert ( thickness > 0.0 )
assert ( radius > 0.0 )
# While values of 3 and 4 are mathematically possible, they result in half of the trianglestrip being degenerate for thin lines.
# Only values of 5 and above should be used practically.
var vertices = inner_vertices * 2
# For simplicity's sake, the width of the ring will be the full thickness at the receptor points.
# For high vertex counts a slightly more optimal mesh could be constructed based on the thickness at each arc of the ring and where it would be intersected by the outer tangent.
# Essentially, we will be making an inner polygon and an outer polygon.
var angle_increment = TAU / float ( inner_vertices )
var angle_outer_offset = skew * angle_increment
var r1 = radius - thickness * 0.5
# Outer polygon side-length = inner side-length / sin(inside angle/2)
# inside angle for a polygon is pi-tau/n. We already precalculated tau/n for other purposes.
var r2 = ( radius + thickness * 0.5 ) / sin ( ( PI - angle_increment ) / 2 )
2019-12-20 21:39:03 +10:30
var UV_r1 = r1 / radius
var UV_r2 = r2 / radius
2019-12-21 20:42:19 +10:30
2019-12-17 15:05:27 +10:30
var vertex_list = PoolVector2Array ( )
2019-12-20 21:39:03 +10:30
var UV_list = PoolVector2Array ( )
2019-12-18 15:59:56 +10:30
var inner_list = PoolVector2Array ( )
var outer_list = PoolVector2Array ( )
2019-12-17 15:05:27 +10:30
for i in inner_vertices :
var angle_i = i * angle_increment
var angle_o = angle_i + angle_outer_offset
vertex_list . push_back ( polar2cartesian ( r1 , angle_i ) )
vertex_list . push_back ( polar2cartesian ( r2 , angle_o ) )
2019-12-18 15:59:56 +10:30
inner_list . push_back ( vertex_list [ - 2 ] )
outer_list . push_back ( vertex_list [ - 1 ] )
2019-12-20 21:39:03 +10:30
UV_list . push_back ( polar2cartesian ( UV_r1 , angle_i ) )
UV_list . push_back ( polar2cartesian ( UV_r2 , angle_o ) )
2019-12-18 15:59:56 +10:30
if repeat_start :
vertex_list . push_back ( vertex_list [ 0 ] )
vertex_list . push_back ( vertex_list [ 1 ] )
inner_list . push_back ( vertex_list [ 0 ] )
outer_list . push_back ( vertex_list [ 1 ] )
2019-12-20 21:39:03 +10:30
UV_list . push_back ( UV_list [ 0 ] )
UV_list . push_back ( UV_list [ 1 ] )
return [ vertex_list , inner_list , outer_list , UV_list ]
2019-12-21 20:42:19 +10:30
2019-12-17 15:05:27 +10:30
func triangle_area ( a : Vector2 , b : Vector2 , c : Vector2 ) - > float :
return 0.5 * abs ( ( a . x - c . x ) * ( b . y - a . y ) - ( a . x - b . x ) * ( c . y - a . y ) )
2019-12-18 15:59:56 +10:30
func inscribe_polygon_area ( r : float , sides : int ) - > float :
return 0.5 * sides * r * r * sin ( TAU / sides )
func circumscribe_polygon_area ( r : float , sides : int ) - > float :
return sides * r * r * tan ( PI / sides )
2019-12-17 15:05:27 +10:30
func arc_point_list ( center : Vector2 , radius : float , angle_from : = 0.0 , angle_to : = 360.0 , points : = 90 ) - > PoolVector2Array :
var point_list = PoolVector2Array ( )
for i in range ( points ) :
var angle = deg2rad ( angle_from + i * ( angle_to - angle_from ) / ( points - 1 ) )
point_list . push_back ( center + polar2cartesian ( radius , angle ) )
return point_list
2019-11-14 22:27:30 +10:30
2019-12-18 15:59:56 +10:30
func draw_old ( circles : = true , shadows : = true ) : # Receptor ring
2019-11-19 00:17:48 +10:30
var receptor_circle : = arc_point_list ( center , GameTheme . receptor_ring_radius , 0.0 , 360.0 , 360 )
var receptor_centers : = arc_point_list ( center , GameTheme . receptor_ring_radius , Rules . FIRST_COLUMN_ANGLE_DEG , Rules . FIRST_COLUMN_ANGLE_DEG + 360.0 - Rules . COLS_ANGLE_DEG , Rules . COLS )
2019-11-10 15:09:14 +10:30
2019-12-18 15:59:56 +10:30
if shadows :
2019-12-20 21:39:03 +10:30
draw_polyline ( receptor_circle , shadow_color , ring_px + shadow_px / 2 , true )
2019-12-18 15:59:56 +10:30
if circles :
for i in range ( len ( receptor_centers ) ) :
2019-12-20 21:39:03 +10:30
draw_circle ( receptor_centers [ i ] , receptor_px / 2 + shadow_px , shadow_color )
2019-12-18 15:59:56 +10:30
draw_polyline ( receptor_circle , GameTheme . receptor_color , ring_px , true )
if circles :
for i in range ( len ( receptor_centers ) ) :
draw_circle ( receptor_centers [ i ] , receptor_px / 2 , GameTheme . receptor_color )
2019-12-20 21:39:03 +10:30
func draw_tris ( ) :
var dbg_color = Color ( 1.0 , 0.0 , 0.0 , 1.0 )
draw_polyline ( ring_vertices [ 0 ] , dbg_color )
draw_polyline ( ring_vertices [ 1 ] , dbg_color )
draw_polyline ( ring_vertices [ 2 ] , dbg_color )
var ring_vertices
func update_ring_mesh ( ) :
var ring_thickness = receptor_px + shadow_px * 2
2020-03-12 23:05:12 +10:30
ring_vertices = make_ring_mesh ( ring_vertex_count , ring_thickness , GameTheme . receptor_ring_radius , ring_skew )
2019-12-20 21:39:03 +10:30
var temp_mesh = ArrayMesh . new ( )
var mesh_arrays = [ ]
mesh_arrays . resize ( Mesh . ARRAY_MAX )
mesh_arrays [ Mesh . ARRAY_VERTEX ] = ring_vertices [ 0 ]
mesh_arrays [ Mesh . ARRAY_TEX_UV ] = ring_vertices [ 3 ]
# mesh_arrays[Mesh.ARRAY_COLOR] = colors
temp_mesh . add_surface_from_arrays ( Mesh . PRIMITIVE_TRIANGLE_STRIP , mesh_arrays )
mesh = temp_mesh
2019-12-21 20:42:19 +10:30
2019-12-18 15:59:56 +10:30
func _draw ( ) :
2019-12-20 21:39:03 +10:30
# draw_old(true, true)
2021-01-05 22:27:11 +10:30
# draw_tris()
2021-01-05 01:38:38 +10:30
# var mesh_v = ring_vertex_count
# var ring_thickness = receptor_px + shadow_px*2
# var estimated_area = circumscribe_polygon_area(GameTheme.receptor_ring_radius+ring_thickness*0.5, mesh_v) - inscribe_polygon_area(GameTheme.receptor_ring_radius-ring_thickness*0.5, mesh_v)
# var ideal_ring_area = PI * (pow(GameTheme.receptor_ring_radius+receptor_px/2+shadow_px, 2) - pow(GameTheme.receptor_ring_radius-receptor_px/2-shadow_px, 2))
2021-01-06 23:10:50 +10:30
# var quad_area = 4*pow(GameTheme.receptor_ring_radius+receptor_px/2+shadow_px, 2)
2019-12-21 20:42:19 +10:30
2019-12-20 21:39:03 +10:30
material . set_shader_param ( " dot_radius " , 0.5 * receptor_px / GameTheme . receptor_ring_radius )
material . set_shader_param ( " line_thickness " , 0.5 * ring_px / GameTheme . receptor_ring_radius )
material . set_shader_param ( " shadow_thickness " , shadow_px / GameTheme . receptor_ring_radius )
material . set_shader_param ( " px " , 0.5 / GameTheme . receptor_ring_radius )
2021-01-05 01:38:38 +10:30
material . set_shader_param ( " px2 " , 1.0 / GameTheme . receptor_ring_radius )
material . set_shader_param ( " line_color " , line_color )
material . set_shader_param ( " dot_color " , dot_color )
material . set_shader_param ( " shadow_color " , shadow_color )
2021-01-06 23:10:50 +10:30
material . set_shader_param ( " alpha " , alpha )
2019-12-20 21:39:03 +10:30
2021-01-29 19:26:44 +10:30
draw_mesh ( mesh , null , null , Transform2D ( 0.0 , rect_size * 0.5 ) )
2020-03-12 23:05:12 +10:30
func set_ring_vertex_count ( num : int ) :
assert ( num > 3 )
ring_vertex_count = num
update_ring_mesh ( )
func set_ring_skew ( skew : int ) :
ring_skew = skew
2019-12-20 21:39:03 +10:30
update_ring_mesh ( )
2019-11-14 22:27:30 +10:30
2020-04-26 13:49:44 +09:30
func set_receptor_positions ( skew : = 0.0 ) :
2019-12-20 21:39:03 +10:30
material . set_shader_param ( " num_receptors " , Rules . COLS )
2020-04-26 21:20:31 +09:30
material . set_shader_param ( " receptor_offset " , PI / Rules . COLS )
2019-12-21 20:42:19 +10:30
2020-04-26 13:49:44 +09:30
func _ready ( ) :
2021-01-29 19:26:44 +10:30
add_child ( tween )
2020-04-26 13:49:44 +09:30
set_receptor_positions ( )
2019-12-20 21:39:03 +10:30
update_ring_mesh ( )
2021-01-08 00:51:29 +10:30
set_alpha ( float ( Engine . editor_hint ) )
2019-12-17 15:05:27 +10:30
$ " /root " . connect ( " size_changed " , self , " update " )
2019-12-21 20:42:19 +10:30
2021-01-06 23:10:50 +10:30
func set_alpha ( a ) :
alpha = a
material . set_shader_param ( " alpha " , alpha )
2021-01-05 00:03:36 +10:30
func fade ( visible : bool ) :
2021-01-29 19:26:44 +10:30
tween . interpolate_method ( self , " set_alpha " , alpha , float ( visible ) , abs ( alpha - float ( visible ) ) * 2.0 )
tween . start ( )