Code archives/3D Graphics - Mesh/Vent_lib. A B3D-like vector GFX system

This code has been declared by its author to be Public Domain code.

Download source code

Vent_lib. A B3D-like vector GFX system by big10p2013
This lib duplicates the B3D commandset for vector GFX entities. I wrote this years ago, so can't remember if I completed it, or not. However, most of the functionality is there, at least.

This lib is a bit of a monster, so has had to be split into 2 parts. Part 1 is below, followed by part 2 in the following post. Copy/paste part 1 into the IDE, then copy/paste part 2, directly after it. Now, save the file as 'vent_lib.bb'.
;
; (vent_lib.bb)
;
; VentLib - 2D Vector Entity System Library.
;
;
;


	;
	; Constants.
	;

	Const VL_VERT_BUFF_SIZE% = 100
	Const VL_LINE_BUFF_SIZE% = 100
	
	Const VL_PICK_MODE_NONE%		= 0
	Const VL_PICK_MODE_CIRCLE%	= 1
	Const VL_PICK_MODE_POLY%		= 2
	Const VL_PICK_MODE_BOX%			= 3

	Const VL_CLASS_PIVOT%	= 0
	Const VL_CLASS_MESH%	= 1	

	;
	; Globals.
	;
	
	; Linked list of all pickable entities.
	Global vl_first_pickable.vl_elinkT = Null
	
	; Tform command results.
	Global vl_tformed_x#
	Global vl_tformed_y#

	; Screen scale metrics.
	Global vl_screen_units_x#		= 10.0
	Global vl_screen_units_y#
	Global vl_unit_size_pixels#
	
	; Default vertex render size.
	Global vl_vertex_size% = 0
	
	; Default vector line flicker intensity.
	Global vl_vector_flicker# = 0;.25
	
	; vl__lines_intersect_xy(), vl__line_intersects_circle() results.
	Global vl_intersect_x#
	Global vl_intersect_y#	
	
	; Latest pick status variables.
	Global vl_picked_entity.vl_entityT	= Null
	Global vl_picked_line%							= -1
	Global vl_picked_x#									= 0.0
	Global vl_picked_y#									= 0.0
	Global vl_picked_nx#								= 0.0
	Global vl_picked_ny#								= 0.0
	
	; Latest picked point and pick line deltas from pick origin - needed for vl_picked_time().
	Global vl_picked_dx#								= 0.0
	Global vl_picked_dy#								= 0.0
	Global vl_pick_line_dx#							= 0.0
	Global vl_pick_line_dy#							= 0.0

	
	;
	; Types.
	;
	
	; Main entity type.
		
	Type vl_entityT
		Field visuals.vl_visualsT					; Visual data required by mesh class entities.

		Field x#													; Local X coord of entity origin.
		Field y#													; Local Y coord of entity origin.
		Field scale_x#										; Local X scale of entity.
		Field scale_y#										; Local Y scale of entity.
		Field rot#												; Local rotation angle of entity.

		Field parent.vl_entityT						; Entity's parent entity.
		Field first_child.vl_elinkT				; Linked list of child entities.

		Field class%											; Entity class type.
		Field hidden%											; Visibility status (can be overidden if parent is hidden).
		Field name$												; Entity name.
		Field pick_mode%									; Entity pick mode.
		Field obscurer%										; Entity obscurer status used by vl_entity_visible().
		Field radius#											; Entity pick radius.
		Field box_x#											; Entity pick box X position.
		Field box_y#											; Entity pick box Y position.
		Field box_width#									; Entity pick box width.
		Field box_height#									; Entity pick box height.
	End Type

	; Mesh entity visual data type.
	
	Type vl_visualsT
		Field mesh.vl_meshT								; Entity mesh data.

		Field order%											; Draw order.
		Field r%, g%, b%									; Entity color.
		Field brightness#									; Entity brightness.
		
		Field draw_me%										; Flags to renderer whether entity is to be drawn, or not.
		Field vert_x#[VL_VERT_BUFF_SIZE]	; Transformed vertices buffer - X coords.
		Field vert_y#[VL_VERT_BUFF_SIZE]	; Transformed vertices buffer - Y coords
	End Type

	; Mesh type.
		
	Type vl_meshT
		Field first_user.vl_elinkT					; Linked list of entities using this mesh.
		
		Field last_vert_i%									; Index of last defined vertex.
		Field vert_x#[VL_VERT_BUFF_SIZE]		; Mesh vertices buffer - X coords.
		Field vert_y#[VL_VERT_BUFF_SIZE]		; Mesh vertices buffer - Y coords.
		
		Field last_line_i%									; Index of last defined line.
		Field line_v0_i%[VL_LINE_BUFF_SIZE]	; Mesh vector line buffer - start coords.
		Field line_v1_i%[VL_LINE_BUFF_SIZE]	; Mesh vector line buffer - end coords.
		Field line_hard%[VL_LINE_BUFF_SIZE] ; Flags indicating if line is hard(1) or soft(0).
	End Type


	; Entity linked list type.
	
	Type vl_elinkT
		Field entity.vl_entityT			; Entity being referenced.
		Field next_elink.vl_elinkT	; Next entity link in list.
	End Type








;
;
;
Function vl_graphics(width%, height%, depth% = 0, mode% = 0)

	Graphics width, height, depth, mode

	vl_scale_graphics(vl_screen_units_x)
	
End Function


;
;
;
Function vl_scale_graphics(scale#)

	vl_screen_units_x		= scale
	vl_screen_units_y		= vl_screen_units_x * (Float(GraphicsHeight()) / GraphicsWidth())
	vl_unit_size_pixels	= (GraphicsWidth() - 1.0) / vl_screen_units_x

End Function


;
;
;
Function vl_graphics_width#()

	Return vl_screen_units_x

End Function


;
;
;
Function vl_graphics_height#()

	Return vl_screen_units_y

End Function


;
; Renders all visible entities to the currently set drawing buffer.
;
Function vl_render_world(clear% = True)

	;
	; Reset all entity render flags.
	;
	
	For visuals.vl_visualsT = Each vl_visualsT

		visuals\draw_me = False

	Next
	

	;
	; Transform all visible entities into actual screen coords.
	;
	
	For this.vl_entityT = Each vl_entityT

		If (this\parent = Null) And (Not this\hidden)

			If this\class = VL_CLASS_MESH
				; This entity has no parent so it's local coord system IS the global coord system.
				vl__tform_entity(this, this\x, this\y, this\rot, this\scale_x, this\scale_y)
			EndIf
						
			; Recursively tranform all this entity's children.
			If this\first_child <> Null
				vl__tform_children(this, this\x, this\y, this\rot, this\scale_x, this\scale_y)
			EndIf

		EndIf

	Next

	
	;
	; Draw all visible entities.
	;
	
	red		= ColorRed() 
	green	= ColorGreen()
	blue	= ColorBlue()

	If clear Then Cls
	
	LockBuffer GraphicsBuffer()

	If vl_vertex_size ; Draw vector lines AND verts...

		For visuals.vl_visualsT = Each vl_visualsT
	
			If visuals\draw_me
		
				mesh.vl_meshT = visuals\mesh
				
				brightness# = visuals\brightness
				flicker# = 1.0 - Rnd(0.0, vl_vector_flicker)
				r = (visuals\r * brightness) * flicker
				g = (visuals\g * brightness) * flicker
				b = (visuals\b * brightness) * flicker
		
				Color r, g, b
				
				;
				; Draw all lines defined in this mesh.
				;
				
				For i = 0 To mesh\last_line_i
		
					; Get line start and end vertex indices.
					v0_i = mesh\line_v0_i[i]
					v1_i = mesh\line_v1_i[i]
					
					; Draw vector line.
					Line visuals\vert_x[v0_i], visuals\vert_y[v0_i], visuals\vert_x[v1_i], visuals\vert_y[v1_i]
		
				Next
		
				;				
				; Draw verts at double brightness.
				;
				
				If r >= 128 Then r = 255 Else r = (r Shl 1)
				If g >= 128 Then g = 255 Else g = (g Shl 1)
				If b >= 128 Then b = 255 Else b = (b Shl 1)

				Color r, g, b
	
				If vl_vertex_size = 1 ; Draw simple 1x1 verts...
				
					For i = 0 To mesh\last_vert_i
			
						vx# = visuals\vert_x[i]
						vy# = visuals\vert_y[i]
						
						Line vx, vy, vx, vy
			
					Next

				Else ; Draw 3x3 verts...

					For i = 0 To mesh\last_vert_i
			
						vx# = visuals\vert_x[i]
						vy# = visuals\vert_y[i]
						
						Line vx-1, vy, vx+1, vy
						Line vx, vy-1, vx, vy+1
			
					Next

				EndIf
										
			EndIf

		Next

	Else ; Draw vector lines only...
	
		For visuals.vl_visualsT = Each vl_visualsT
	
			If visuals\draw_me
			
				mesh.vl_meshT = visuals\mesh
				
				brightness# = visuals\brightness
				flicker# = 1.0 - Rnd(0.0, vl_vector_flicker)
				r = (visuals\r * brightness) * flicker
				g = (visuals\g * brightness) * flicker
				b = (visuals\b * brightness) * flicker

				Color r, g, b
		
				;
				; Draw all lines defined in this mesh.
				;
				
				For i = 0 To mesh\last_line_i
		
					; Get line start and end vertex indices.
					v0_i = mesh\line_v0_i[i]
					v1_i = mesh\line_v1_i[i]
					
					; Draw vector line.
					Line visuals\vert_x[v0_i], visuals\vert_y[v0_i], visuals\vert_x[v1_i], visuals\vert_y[v1_i]
		
				Next
		
				;x# = vl_screen(vl__entity_x(this, True))
				;y# = vl_screen(vl__entity_y(this, True))
				;Line x, y, x, y

			EndIf

		Next

	EndIf
	
	UnlockBuffer GraphicsBuffer()
	
	; Reinstate original color.
	Color red, green, blue
	 
End Function


;
; Sets the flicker intensity to use when drawing vector lines.
;
; Params:
; value - Level of flicker to use. 0 = extreme flicker, 1 = no flicker.
;
Function vl_vector_flicker(value#)

	If value < 0.0

		value = 0.0

	ElseIf value > 1.0

		value = 1.0

	EndIf
	
	vl_vector_flicker = value

End Function


;
; Sets the size vertices should be drawn at.
;
; params:
; size - Size level all vertices are to be drawn at.
;        0 = Vertices are not drawn.
;        1 = Vertices are drawn using a single pixel.
;        2 = Vertices are drawn using a 3x3 pixel cross.
;
Function vl_vertex_size(size%)

	If size =< 0

		vl_vertex_size = 0

	ElseIf size >= 2

		vl_vertex_size = 2

	Else

		vl_vertex_size = 1

	EndIf

End Function


;
; Creates a blank mesh entity. Geometry can then be added to this mesh
; by using the vl_add_vertex and vl_add_line commands.
;
; Params:
; parent_ID - Handle of entity to be made the new mesh entity's parent.
;             The new mesh entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created mesh entity.
;
Function vl_create_mesh(parent_ID% = 0)

	entity.vl_entityT		= New vl_entityT
	visuals.vl_visualsT	= New vl_visualsT
	mesh.vl_meshT				= New vl_meshT

	entity_ID = Handle(entity)

	; Initialize new entity.
	
	entity\visuals			= visuals

	If parent_ID Then vl__add_child(Object.vl_entityT(parent_ID), entity)

	entity\first_child	= Null

	entity\x						= 0.0
	entity\y						= 0.0
	entity\scale_x			= 1.0
	entity\scale_y			= 1.0
	entity\rot					= 0.0

	entity\class 				= VL_CLASS_MESH
	entity\hidden				= False
	entity\name					= ""
	entity\pick_mode		= VL_PICK_MODE_NONE
	entity\obscurer			= False
	entity\radius				= 1.0
	entity\box_x				= -1.0
	entity\box_y				= -1.0
	entity\box_width		= 2.0
	entity\box_height		= 2.0

	; Initialize new entity visual data.	

	visuals\mesh				= mesh
	
	vl__entity_order(entity, 0)

	visuals\r						= 255
	visuals\g						= 255
	visuals\b						= 255
	visuals\brightness	= 0.5
	
	; Initialize new mesh.
		
	vl__add_user(mesh, entity)
	
	mesh\last_vert_i	= -1
	mesh\last_line_i	= -1

	Return entity_ID

End Function


;
; Creates a polygon mesh entity.
;
; Params:
; sides     - Number of sides the polygon should have.
; parent_ID - Handle of entity to be made the new mesh entity's parent.
;             The new mesh entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created polygon mesh entity.
;
Function vl_create_polygon(sides% = 3, parent_ID% = 0)

	mesh = vl_create_mesh(Parent_ID)
	
	total_verts	= sides
	vert_ang#		= 0.0
	delta_ang#	= 360.0 / sides

	; Add verts for all corners of polygon.
	For n = 0 To total_verts - 1

		vl_add_vertex(mesh, Cos(vert_ang), Sin(vert_ang))

		vert_ang = vert_ang + delta_ang
	Next	

	; Add vector lines.
	For n = 0 To total_verts - 2

		vl_add_line(mesh, n, n + 1)

	Next

	vl_add_line(mesh, total_verts - 1, 0)
	
	Return mesh
	
End Function


;
; Creates a box/square mesh entity.
;
; Params:
; parent_ID - Handle of entity to be made the new mesh entity's parent.
;             The new mesh entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created box mesh entity.
;
Function vl_create_box(parent_ID% = 0)

	mesh = vl_create_mesh(Parent_ID)
	
	vl_add_vertex(mesh,  1, -1)
	vl_add_vertex(mesh,  1,  1)
	vl_add_vertex(mesh, -1,  1)
	vl_add_vertex(mesh, -1, -1)

	vl_add_line(mesh, 0, 1)
	vl_add_line(mesh, 1, 2)
	vl_add_line(mesh, 2, 3)
	vl_add_line(mesh, 3, 0)
	
	Return mesh
	
End Function


;
; Creates a star-shaped mesh entity.
;
; Params:
; points    - Number of points the star should have.
; indent    - Sets the 'depth' of the indent between the points of the star.
; parent_ID - Handle of entity to be made the new mesh entity's parent.
;             The new mesh entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created star mesh entity.
;
Function vl_create_star(points% = 5, indent# = 0.5, parent_ID% = 0)

	mesh = vl_create_mesh(Parent_ID)
	
	total_verts	= points * 2
	vert_ang#		= 0.0
	delta_ang#	= 360.0 / total_verts

	; Add verts for all star points & indents.
	For n = 0 To total_verts - 1

		If (n And 1) Then size# = indent Else size# = 1.0

		vl_add_vertex(mesh, Cos(vert_ang) * size, Sin(vert_ang) * size)

		vert_ang = vert_ang + delta_ang

	Next

	; Add vector lines.
	For n = 0 To total_verts - 2

		vl_add_line(mesh, n, n + 1)

	Next

	vl_add_line(mesh, total_verts - 1, 0)

	Return mesh
	
End Function


;
; Creates a pivot entity.
;
; Params:
; parent_ID - Handle of entity to be made the new pivot entity's parent.
;             The new pivot will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created pivot entity.
;
Function vl_create_pivot(parent_ID% = 0)

	entity.vl_entityT		= New vl_entityT

	entity_ID = Handle(entity)

	; Initialize new entity.
	
	entity\visuals			= Null 

	If parent_ID Then vl__add_child(Object.vl_entityT(parent_ID), entity)

	entity\first_child	= Null

	entity\x						= 0.0
	entity\y						= 0.0
	entity\scale_x			= 1.0
	entity\scale_y			= 1.0
	entity\rot					= 0.0

	entity\class 				= VL_CLASS_PIVOT
	entity\hidden				= False
	entity\name					= ""
	entity\pick_mode		= VL_PICK_MODE_NONE
	entity\obscurer			= False
	entity\radius				= 1.0
	entity\box_x				= -1.0
	entity\box_y				= -1.0
	entity\box_width		= 2.0
	entity\box_height		= 2.0

	Return entity_ID

End Function


;
; Creates a point entity. Point entities disply as a single pixel when rendered.
;
; Params:
; parent_ID - Handle of entity to be made the new point entity's parent.
;             The new point entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created point entity.
;
Function vl_create_point(parent_ID% = 0)

	mesh = vl_create_mesh(Parent_ID)
	
	vl_add_vertex(mesh, 0, 0)

	vl_add_line(mesh, 0, 0)
	
	Return mesh

End Function


;
; Deletes an entity and frees all it's resources. All the entity's children are also freed.
;
; Params:
; entity_ID  - Handle of entity to be freed.
;
Function vl_free_entity(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	; Recursively free any child entities.
	If entity\first_child <> Null Then vl__free_children(entity)

	If entity\class = VL_CLASS_MESH	

		mesh.vl_meshT = entity\visuals\mesh
		vl__delete_user(mesh, entity)
		
		; Delete this mesh if no other entities are using it.
		If mesh\first_user = Null Then Delete mesh
	
		Delete entity\visuals

	EndIf

	If entity\pick_mode Then vl__delete_pickable(entity)

	If entity\parent <> Null Then vl__delete_child(entity)
	
	Delete entity
			
End Function


;
; Rotates all the vertices of a mesh by the specified rotation angle.
;
; Params:
; entity_ID  - Handle of entity referencing the mesh to be rotated.
; rot        - Angle to rotate the mesh by.
;
Function vl_rotate_mesh(entity_ID%, rot#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	mesh.vl_meshT = entity\visuals\mesh

	cos_rot# = Cos(rot)
	sin_rot# = Sin(rot)

	For i = 0 To mesh\last_vert_i

		vert_x# = mesh\vert_x[i]
		vert_y# = mesh\vert_y[i]

		mesh\vert_x[i] = (vert_x * cos_rot) - (vert_y * sin_rot)
		mesh\vert_y[i] = (vert_y * cos_rot) + (vert_x * sin_rot)
		
	Next

End Function


;
; Moves/Offsets all vertices of a mesh by the specified x,y amounts.
;
; Params:
; entity_ID  - Handle of entity referencing the mesh to be positioned.
; x          - X amount to move all vertices by.
; y          - Y amount to move all vertices by.
;
Function vl_position_mesh(entity_ID%, x#, y#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	For i = 0 To mesh\last_vert_i

		mesh\vert_x[i] = mesh\vert_x[i] + x
		mesh\vert_y[i] = mesh\vert_y[i] + y
		
	Next

End Function


;
; Adds a copy of one mesh to another mesh.
;
; Params:
; source_entity_ID - Handle of entity referencing the mesh to be copied.
; dest_entity_ID   - Handle of entity referencing the mesh to be added to.
; hardness         - Indicates what hardness the copied mesh lines should be given
;                    when added to the destination mesh:
;                    0 = Set all lines to be soft (unpickable).
;                    1 = Set all lines to be hard (pickable).
;                    2 = (default) Keep lines same as defined in source mesh.
;
Function vl_add_mesh(source_entity_ID%, dest_entity_ID%, hardness% = 2)

	If hardness < 0 Then hardness = 0
	
	source_entity.vl_entityT = Object.vl_entityT(source_entity_ID)
	source_mesh.vl_meshT = source_entity\visuals\mesh

	dest_entity.vl_entityT = Object.vl_entityT(dest_entity_ID)
	dest_mesh.vl_meshT = dest_entity\visuals\mesh

	; Copy all vertices from source mesh to destination mesh.
	
	vert_i_offset = dest_mesh\last_vert_i + 1
	dest_mesh\last_vert_i = dest_mesh\last_vert_i + source_mesh\last_vert_i + 1
	
	For i = 0 To source_mesh\last_vert_i

		dest_mesh\vert_x[vert_i_offset + i] = source_mesh\vert_x[i]
		dest_mesh\vert_y[vert_i_offset + i] = source_mesh\vert_y[i]
		
	Next

	; Copy all vector lines from source mesh to destination mesh.
	
	line_i_offset = dest_mesh\last_line_i + 1
	dest_mesh\last_line_i = dest_mesh\last_line_i + source_mesh\last_line_i + 1
	
	If hardness < 2 ; Set lines to specified hardness...

		For i = 0 To source_mesh\last_line_i
	
			dest_mesh\line_v0_i[line_i_offset + i] = source_mesh\line_v0_i[i] + vert_i_offset
			dest_mesh\line_v1_i[line_i_offset + i] = source_mesh\line_v1_i[i] + vert_i_offset
			dest_mesh\line_hard[line_i_offset + i] = hardness
	
		Next

	Else ; Keep source mesh's line hardness...
	
		For i = 0 To source_mesh\last_line_i
	
			dest_mesh\line_v0_i[line_i_offset + i] = source_mesh\line_v0_i[i] + vert_i_offset
			dest_mesh\line_v1_i[line_i_offset + i] = source_mesh\line_v1_i[i] + vert_i_offset
			dest_mesh\line_hard[line_i_offset + i] = source_mesh\line_hard[i]
	
		Next

	EndIf
			
End Function


;
; Creates a copy of an existing mesh.
;
; Params:
; entity_ID - Handle of entity whose mesh is to be copied.
; parent_ID - Handle of entity to be made the new mesh entity's parent.
;             The new mesh entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created mesh entity.
;
Function vl_copy_mesh(entity_ID%, parent_ID% = 0)

	new_mesh_ID = vl_create_mesh(parent_ID)
	
	vl_add_mesh(entity_ID, new_mesh_ID)
	
	Return new_mesh_ID
	
End Function


;
; Scales all vertices of a mesh by the specified x,y factors.
;
; Params:
; entity_ID  - Handle of entity referencing the mesh to be scaled.
; x          - X factor to scale all vertices by.
; y          - Y factor to scale all vertices by.
;
Function vl_scale_mesh(entity_ID%, scale_x#, scale_y#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	For i = 0 To mesh\last_vert_i

		mesh\vert_x[i] = mesh\vert_x[i] * scale_x
		mesh\vert_y[i] = mesh\vert_y[i] * scale_y
		
	Next

End Function


;
; Flips all vector lines of a mesh so they face the opposite way.
;
; Params:
; entity_ID  - Handle of entity referencing the mesh to be flipped.
;
Function vl_flip_mesh(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	For i = 0 To mesh\last_line_i

		temp_v0_i = mesh\line_v0_i[i]
		
		mesh\line_v0_i[i] = mesh\line_v1_i[i]
		mesh\line_v1_i[i] = temp_v0_i
		
	Next

End Function


;
; Scales and translates all vertices of a mesh so that the mesh occupies the specified box.
;
; Params:
; entity_ID  - Handle of entity referencing the mesh to be made to fit the box.
; x          - X coord of the corner of the fit box.
; y          - Y coord of the corner of the fit box.
; width      - Width of the fit box.
; height     - Height of the fit box.
; uniform    - False (default) to fit the mesh exactly inside the fit box.
;              True to scale verts uniformly so as to retain the mesh's aspect ratio.
;
Function vl_fit_mesh(entity_ID%, x#, y#, width#, height#, uniform% = False)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	If mesh\last_vert_i = -1 Then Return


	;
	; Find mesh width/height and x,y offset needed to centre the mesh inside the defined box (this is
	; required for meshes whose origin isn't at the dead-centre of the bounding box of it's verts).
	;
		
	biggest_x#	= mesh\vert_x[0]
	smallest_x#	= biggest_x
	biggest_y#	= mesh\vert_y[0]
	smallest_y#	= biggest_y

	For i = 1 To mesh\last_vert_i

		vert_x# = mesh\vert_x[i]

		If vert_x > biggest_x
			biggest_x = vert_x
		ElseIf vert_x < smallest_x
			smallest_x = vert_x
		EndIf

		vert_y# = mesh\vert_y[i]

		If vert_y > biggest_y
			biggest_y = vert_y
		ElseIf vert_y < smallest_y
			smallest_y = vert_y
		EndIf
		
	Next

	mesh_width# = biggest_x - smallest_x
	offset_x# = (biggest_x - mesh_width) + (mesh_width / 2.0)

	mesh_height# = biggest_y - smallest_y
	offset_y# = (biggest_y - mesh_height) + (mesh_height / 2.0)


	;
	; Change all mesh verts to fit inside the defined box.
	;

	; Find centre of defined box.
	origin_x# = x + (width / 2.0)
	origin_y# = y + (height / 2.0)

	If uniform ; Keep mesh aspect ratio...

		If mesh_width > mesh_height
			height = (width * (mesh_height / mesh_width)) * Sgn(height)
		Else
			width = (height * (mesh_width / mesh_height)) * Sgn(width)
		EndIf

	EndIf

	scale_x# = width / mesh_width
	scale_y# = height / mesh_height
		
	For i = 0 To mesh\last_vert_i

		mesh\vert_x[i] = origin_x + ((mesh\vert_x[i] - offset_x) * scale_x)
		mesh\vert_y[i] = origin_y + ((mesh\vert_y[i] - offset_y) * scale_y)
		
	Next

End Function


;
; Removes all vertices and/or vector lines from a mesh.
;
; Params:
; entity_ID   - Handle of entity referencing the mesh to be cleared.
; clear_verts - True (default) to remove al vertices. False not to.
; clear_lines - True (default) to remove al vector lines. False not to.
;
Function vl_clear_mesh(entity_ID%, clear_verts% = True, clear_lines% = True)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	If clear_verts Then mesh\last_vert_i = -1

	If clear_lines Then mesh\last_line_i = -1

End Function


;
; Determines whether the specified meshes are intersecting.
;
; Params:
; entity_a_ID - Handle of first mesh to test for intersection.
; entity_b_ID - Handle of second mesh to test for intersection.
;
; Returns:
; True if the two meshes are currently intersecting, False otherwise.
;
Function vl_meshes_intersect(entity_a_ID%, entity_b_ID%)

	; Transform mesh A to world space.
	entity_a.vl_entityT = Object.vl_entityT(entity_a_ID)
	visuals_a.vl_visualsT = entity_a\visuals
	mesh_a.vl_meshT = visuals_a\mesh
	vl__tform_entity_world(entity_a, vl__entity_x(entity_a, True), vl__entity_y(entity_a, True), vl__entity_rotation(entity_a, True), vl__entity_scale_x(entity_a, True), vl__entity_scale_y(entity_a, True))

	; Transform mesh B to world space.
	entity_b.vl_entityT = Object.vl_entityT(entity_b_ID)
	visuals_b.vl_visualsT = entity_b\visuals
	mesh_b.vl_meshT = visuals_b\mesh
	vl__tform_entity_world(entity_b, vl__entity_x(entity_b, True), vl__entity_y(entity_b, True), vl__entity_rotation(entity_b, True), vl__entity_scale_x(entity_b, True), vl__entity_scale_y(entity_b, True))

	If (mesh_a\last_line_i + mesh_b\last_line_i) > 10
		check_meshes = vl__vert_boxes_intersect(entity_a, entity_b)
	Else
		check_meshes = True
	EndIf
	
	If check_meshes ; See if any lines in mesh A intersect with any lines in mesh B...
	
		For a_i = 0 To mesh_a\last_line_i
	
			; Get this mesh A line start and delta.
			v0_i = mesh_a\line_v0_i[a_i]
			v1_i = mesh_a\line_v1_i[a_i]
	
			x1# = visuals_a\vert_x[v0_i]
			y1# = visuals_a\vert_y[v0_i]
	
			dx1# = visuals_a\vert_x[v1_i] - x1
			dy1# = visuals_a\vert_y[v1_i] - y1
	
			For b_i = 0 To mesh_b\last_line_i
	
				; Get this mesh B line start and delta.
				v0_i = mesh_b\line_v0_i[b_i]
				v1_i = mesh_b\line_v1_i[b_i]
		
				x2# = visuals_b\vert_x[v0_i]
				y2# = visuals_b\vert_y[v0_i]
		
				dx2# = visuals_b\vert_x[v1_i] - x2
				dy2# = visuals_b\vert_y[v1_i] - y2
	
				If vl__lines_intersect(x1, y1, dx1, dy1,  x2, y2, dx2, dy2) Then Return True
	
			Next
			
		Next
	
	EndIf
		
	Return False
	
End Function


;
; Returns the width of a mesh.
;
; Params:
; entity_ID - Handle of entity whose width is to be returned.
;
; Returns:
; The given entity's mesh width.
;
Function vl_mesh_width#(entity_ID%)

	Return vl__mesh_width(Object.vl_entityT(entity_ID))

End Function


;
; Returns the height of a mesh.
;
; Params:
; entity_ID - Handle of entity whose height is to be returned.
;
; Returns:
; The given entity's mesh height.
;
Function vl_mesh_height#(entity_ID%)

	Return vl__mesh_height(Object.vl_entityT(entity_ID))

End Function


;
; Returns the parent of an entity.
;
; Params:
; entity_ID - Handle of entity whose parent is to be returned.
;
; Returns:
; The handle of the given entity's parent.
;
Function vl_get_parent(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	Return Handle(entity\parent)

End Function


;
; Returns the child of an entity.
;
; Params:
; entity_ID - Handle of entity whose child is to be returned.
; child_num - Number of child to get. Range is 1 to vl_count_children().
;
; Returns:
; The handle of the given entity's child.
;
Function vl_get_child(entity_ID%, child_num)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	child_link.vl_elinkT = entity\first_child
	child.vl_entityT = Null
	count = 1
	
	While child_link <> Null
	
		If count = child_num Then Return Handle(child_link\entity)
		
		count = count + 1
		child_link = child_link\next_elink

	Wend

End Function


;
; Returns the first child of an entity with the given name. All the entity's 
; children and sub-children are searched, via recursion.
;
; Params:
; entity_ID - Handle of entity whose named child is to be returned.
; name      - The name of the child to find (case sensitive).
;
; Returns:
; The handle of the given entity's first child with the specified name.
;
Function vl_find_child(entity_ID%, name$)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	If entity\first_child <> Null Then Return Handle(vl__find_child(entity, name$))

End Function


;
; Returns the number of children an entity has.
;
; Params:
; entity_ID - Handle of entity whose children are to be counted.
;
; Returns:
; The total number of immediate children an entity has.
;
Function vl_count_children(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	child_link.vl_elinkT = entity\first_child

	total = 0
	
	While child_link <> Null

		total = total + 1			
		child_link = child_link\next_elink

	Wend

	Return total

End Function


;
; Sets the color of an entity.
;
; Params:
; entity_ID - Handle of entity whose color is to be set.
; r         - Red component of color.
; g         - Green component of color.
; b         - Blue component of color.
;
Function vl_entity_color(entity_ID%, r%, g%, b%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\visuals\r = r
	entity\visuals\g = g
	entity\visuals\b = b

End Function


;
; Sets an entity's brightness.
;
; Params:
; entity_ID - Handle of entity whose brightness is to be set.
; value     - Level of brightness to give the entity. 0 = invisible, 1 = fullbright.
;
Function vl_entity_brightness(entity_ID%, value#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	If value < 0.0

		value = 0.0

	ElseIf value > 1.0

		value = 1.0

	EndIf
	
	entity\visuals\brightness = value

End Function


;
; Returns the name of an entity.
;
; Params:
; entity_ID - Handle of entity whose name is to be returned.
;
; Returns:
; The given entity's name.
;
Function vl_entity_name$(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	Return entity\name$

End Function


;
; Returns the class of an entity.
;
; Params:
; entity_ID - Handle of entity whose class is to be returned.
;
; Returns:
; A string describing the class of the given entity.
;
Function vl_entity_class$(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	If entity\class
	
		Return "Mesh"
		
	Else
	
		Return "Pivot"
		
	EndIf

End Function


;
; Sets the name of an entity.
;
; Params:
; entity_ID - Handle of entity whose name is to be set.
; name      - Name to give the entity.
;
Function vl_name_entity(entity_ID%, name$)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\name$ = name$

End Function


;
; Sets the drawing order of an entity.
;
; Params:
; entity_ID - Handle of entity whose draw order is to be set.
; order     - Order the entity will be drawn in.
;
Function vl_entity_order(entity_ID%, order%)

	vl__entity_order(Object.vl_entityT(entity_ID), order)
	
End Function


;
; Sets an entity's pick mode.
;
; Params:
; entity_ID - Handle of entity whose pick mode is to be set.
; mode      - Mode of geometry to be used when picking the entity:
;             0 = None (unpickable)
;             1 = Circle (vl_entity_radius is used)
;             2 = Polygon (uses the polygon defined by the mesh's vector lines)
;             3 = Box (vl_entity_box is used)
; obscurer  - True (default) to determine the entity 'obscures' other entities
;             during a vl_entity_visible() call. 
;
Function vl_entity_pick_mode(entity_ID%, mode%, obscurer% = True)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	If mode < 0
	
		mode = 0
		
	ElseIf mode > 3
	
		mode = 3
		
	EndIf
	
	vl__entity_pick_mode(entity, mode, obscurer)
	
End Function


;
; Returns the nearest pickable entity ahead of the specified entity.
;
; Params:
; entity_ID - Handle of entity to pick ahead of.
; range#    - Distance to pick ahead of entity by.
;
Function vl_entity_pick(entity_ID%, range#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	; Temporarily assert entity is hidden to ensure it isn't included in the pick.
	hidden = entity\hidden
	entity\hidden = True
	
	rot# = vl__entity_rotation(entity, True)
	vl_line_pick(vl__entity_x(entity, True), vl__entity_y(entity, True), (Cos(rot) * range), (Sin(rot) * range))

	entity\hidden = hidden

	Return Handle(vl_picked_entity)

End Function


;
; Sets the dimensions on an entity's pick box.
;
; Params:
; entity_ID - Handle of entity whose pick box is to be set.
; x         - X position of entity's pick box.
; y         - Y position of entity's pick box.
; width     - Width of entity's pick box.
; height    - Height of entity's pick box.
;
Function vl_entity_box(entity_ID%, x#, y#, width#, height#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	;
	; Ensure box 'winds' clockwise from top-left corner to ensure the normal of a picked
	; box edge can be calculated correctly (i.e. normals need to point outward).
	;
	
	If width < 0.0

		x = x + width
		width = -width

	EndIf

	If height < 0.0

		y = y + height
		height = -height

	EndIf
	
	entity\box_x			= x
	entity\box_y			= y
	entity\box_width	= width
	entity\box_height	= height

End Function


;
; Sets the radius on an entity's pick circle.
;
; Params:
; entity_ID - Handle of entity whose pick circle is to be set.
; radius    - Radius of entity's pick circle.
;
Function vl_entity_radius(entity_ID%, radius#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\radius = radius

End Function


;
; Parents (attaches) one entity to another.
;
; Params:
; entity_ID - Handle of entity to be made a child of parent.
; parent_ID - Handle of entity to be made the parent of entity. 0 sets the entity to have no parent.
; glob      - True (default) for the entity to retain it's global position/rotation/scale.
;             False for the entity to retain it's local position/rotation/scale.
;
Function vl_entity_parent(entity_ID%, parent_ID%, glob% = True)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	If parent_ID ; Parent entity...

		parent.vl_entityT = Object.vl_entityT(parent_ID)

		If (entity = parent) Or (entity\parent = parent) Then Return

		If glob ; Retain entity's global position/rotation/scale...

			pg_scale_x# = vl__entity_scale_x(parent, True)
			pg_scale_y# = vl__entity_scale_y(parent, True)

			; Find global coords of entity, relative to parent.
			dx# = vl__entity_x(entity, True) - vl__entity_x(parent, True)
			dy# = vl__entity_y(entity, True) - vl__entity_y(parent, True)
			
			; Rotate coords into parent's coord system.
			inv_pg_rot# = -vl__entity_rotation(parent, True)

			cos_rot# = Cos(inv_pg_rot)
			sin_rot# = Sin(inv_pg_rot)
			
			x# = (dx * cos_rot) - (dy * sin_rot)
			y# = (dy * cos_rot) + (dx * sin_rot)

			; Scale global coords into parent's global scale.
			entity\x = x / pg_scale_x
			entity\y = y / pg_scale_y

			; Convert global entity rotation to equivalent in parent's coord system.
			entity\rot = vl__clamp_rot(vl__entity_rotation(entity, True) + inv_pg_rot)
			
			; Convert global entity scale to equivalent in parent's scale.
			entity\scale_x = vl__entity_scale_x(entity, True) / pg_scale_x
			entity\scale_y = vl__entity_scale_y(entity, True) / pg_scale_y

		EndIf

		If entity\parent <> Null Then vl__delete_child(entity)

		vl__add_child(parent, entity)
			
	Else ; Un-parent entity...

		If entity\parent <> Null ; Entity does have a parent...
		
			If glob ; Retain entity's global position/rotation/scale...
	
				global_x#				= vl__entity_x(entity, True)
				global_y#				= vl__entity_y(entity, True)
				global_rot#			= vl__entity_rotation(entity, True)
				global_scale_x#	= vl__entity_scale_x(entity, True)
				global_scale_y#	= vl__entity_scale_y(entity, True)
				
				entity\x				= global_x
				entity\y				= global_y
				entity\rot			= global_rot
				entity\scale_x	= global_scale_x
				entity\scale_y	= global_scale_y
			
			EndIf
	
			vl__delete_child(entity)
		
		EndIf
		
	EndIf
		
End Function


;
; Returns an entity's X position coordinate.
;
; Params:
; entity_ID - Handle of entity whose X coord is to be returned.
; glob      - True returns the entity's global X coord.
;             False (default) returns the entity's local X coord.
;
; Returns:
; The given entity's current X coord. 
;
Function vl_entity_x#(entity_ID%, glob% = False)

	Return vl__entity_x(Object.vl_entityT(entity_ID), glob)

End Function


;
; Returns an entity's Y position coordinate.
;
; Params:
; entity_ID - Handle of entity whose Y coord is to be returned.
; glob      - True returns the entity's global Y coord.
;             False (default) returns the entity's local Y coord.
;
; Returns:
; The given entity's current Y coord. 
;
Function vl_entity_y#(entity_ID%, glob% = False)

	Return vl__entity_y(Object.vl_entityT(entity_ID), glob)

End Function


;
; Returns an entity's width.
;
; Params:
; entity_ID - Handle of entity whose width is to be returned.
; glob      - True returns the entity's global width.
;             False (default) returns the entity's local width.
;
; Returns:
; The given entity's current width. 
;
Function vl_entity_width#(entity_ID%, glob% = False)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	If glob
	
		vl__tform_entity_world(entity, vl__entity_x(entity, True), vl__entity_y(entity, True), vl__entity_rotation(entity, True), vl__entity_scale_x(entity, True), vl__entity_scale_y(entity, True))
	
		visuals.vl_visualsT = entity\visuals
		mesh.vl_meshT = visuals\mesh
	
		If mesh\last_vert_i = -1 Then Return 0.0
		
		biggest#	= visuals\vert_x[0]
		smallest#	= biggest
	
		For i = 1 To mesh\last_vert_i
	
			vert_x# = visuals\vert_x[i]
	
			If vert_x > biggest
			
				biggest = vert_x
			
			ElseIf vert_x < smallest
			
				smallest = vert_x
				
			EndIf
			
		Next
	
		Return (biggest - smallest)

	Else
	
		Return Abs(vl__mesh_width(entity) * vl__entity_scale_x(entity, True))
	
	EndIf
	
End Function


;
; Returns an entity's height.
;
; Params:
; entity_ID - Handle of entity whose height is to be returned.
; glob      - True returns the entity's global height.
;             False (default) returns the entity's local height.
;
; Returns:
; The given entity's current height. 
;
Function vl_entity_height#(entity_ID%, glob% = False)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	If glob
	
		vl__tform_entity_world(entity, vl__entity_x(entity, True), vl__entity_y(entity, True), vl__entity_rotation(entity, True), vl__entity_scale_x(entity, True), vl__entity_scale_y(entity, True))
	
		visuals.vl_visualsT = entity\visuals
		mesh.vl_meshT = visuals\mesh
	
		If mesh\last_vert_i = -1 Then Return 0.0
		
		biggest#	= visuals\vert_y[0]
		smallest#	= biggest
	
		For i = 1 To mesh\last_vert_i
	
			vert_y# = visuals\vert_y[i]
	
			If vert_y > biggest
			
				biggest = vert_y
			
			ElseIf vert_y < smallest
			
				smallest = vert_y
				
			EndIf
			
		Next
	
		Return (biggest - smallest)

	Else
	
		Return Abs(vl__mesh_height(entity) * vl__entity_scale_y(entity, True))
	
	EndIf
	
End Function


;
; Returns an entity's angle of rotation.
;
; Params:
; entity_ID - Handle of entity whose rotation is to be returned.
; glob      - True returns the entity's global rotation.
;             False (default) returns the entity's local rotation.
;
; Returns:
; The given entity's current angle of rotation. 
;
Function vl_entity_rotation#(entity_ID%, glob% = False)

	Return vl__entity_rotation(Object.vl_entityT(entity_ID), glob)

End Function


;
; Returns an entity's X axis scale.
;
; Params:
; entity - Entity whose X scale is to be returned.
; glob   - True returns the entity's global X scale.
;          False (default) returns the entity's local X scale.
;
; Returns:
; The given entity's current X axis scale. 
;
Function vl_entity_scale_x#(entity_ID%, glob% = False)

	Return vl__entity_scale_x(Object.vl_entityT(entity_ID), glob)

End Function


;
; Returns an entity's Y axis scale.
;
; Params:
; entity - Entity whose Y scale is to be returned.
; glob   - True returns the entity's global Y scale.
;          False (default) returns the entity's local Y scale.
;
; Returns:
; The given entity's current Y axis scale. 
;
Function vl_entity_scale_y#(entity_ID%, glob% = False)

	Return vl__entity_scale_y(Object.vl_entityT(entity_ID), glob)

End Function


;
; Returns the distance between two entities.
;
; Params:
; entity_a_ID - Handle of first entity.
; entity_b_ID - Handle of second entity.
;
; Returns:
; The absolute distance between the two given entities.
;
Function vl_entity_distance#(entity_a_ID%, entity_b_ID%)

	entity_a.vl_entityT = Object.vl_entityT(entity_a_ID)
	entity_b.vl_entityT = Object.vl_entityT(entity_b_ID)

	dx# = vl__entity_x(entity_a, True) - vl__entity_x(entity_b, True)
	dy# = vl__entity_y(entity_a, True) - vl__entity_y(entity_b, True)

	Return Sqr(dx * dx + dy * dy)

End Function


;
; Determines whether two entities can 'see' each other i.e. there are no pickable, obscurer
; entities between the line-of-sight of the two entities.
;
; Params:
; entity_a_ID - Handle of first entity.
; entity_b_ID - Handle of second entity.
;
; Returns:
; True if both entities can see each other, false otherwise.
;
Function vl_entity_visible(entity_a_ID%, entity_b_ID%)

	entity_a.vl_entityT = Object.vl_entityT(entity_a_ID)
	entity_b.vl_entityT = Object.vl_entityT(entity_b_ID)

	sx# = vl__entity_x(entity_a, True)
	sy# = vl__entity_y(entity_a, True)
	dx# = vl__entity_x(entity_b, True) - sx
	dy# = vl__entity_y(entity_b, True) - sy

	;
	; See if there's any pickable, visible, obscurer entities between the two entities.
	;
	
	pickable.vl_elinkT = vl_first_pickable
	
	While pickable <> Null
	
		this.vl_entityT = pickable\entity
		
		If (this <> entity_a) And (this <> entity_b) And vl__entity_visible(this) And this\obscurer

			;
			; See if this entity is picked, using it's defined pick method.
			;
			
			Select this\pick_mode
			
			Case VL_PICK_MODE_CIRCLE
			
				cx# = vl__entity_x(this, True)
				cy# = vl__entity_y(this, True)
				
				If vl__line_intersects_circle(sx, sy, dx, dy,  cx, cy, this\radius) Then Return False

			Case VL_PICK_MODE_BOX

				rot# = vl__entity_rotation(this, True)
				cos_rot# = Cos(rot)
				sin_rot# = Sin(rot)
		
				trans_x# = (this\box_x * cos_rot) - (this\box_y * sin_rot)
				trans_y# = (this\box_y * cos_rot) + (this\box_x * sin_rot)

				edge_x# = vl__entity_x(this, True) + trans_x
				edge_y# = vl__entity_y(this, True) + trans_y
		
				width_dx#		= cos_rot * this\box_width
				width_dy#		= sin_rot * this\box_height
				height_dx#	= Cos(rot + 90) * this\box_width
				height_dy#	= Sin(rot + 90) * this\box_height
		
				For n = 1 To 4
				
					; Set correct delta for current edge being tested.
					Select n
					Case 1 ; Top.
						edge_dx# = width_dx
						edge_dy# = width_dy
					Case 2 ; Right.
						edge_dx# = height_dx
						edge_dy# = height_dy
					Case 3 ; Bottom.
						edge_dx# = -width_dx
						edge_dy# = -width_dy
					Case 4 ; Left.
						edge_dx# = -height_dx
						edge_dy# = -height_dy
					End Select
		
					If vl__lines_intersect(sx, sy, dx, dy,  edge_x, edge_y, edge_dx, edge_dy)
		
						Return False
								
					EndIf
					
					edge_x = edge_x + edge_dx
					edge_y = edge_y + edge_dy
				
				Next

			Case VL_PICK_MODE_POLY
			
				; Transform this entity's verts to world coords so we can check if it's vector
				; lines intersect with the pick line.
				vl__tform_entity_world(this, vl__entity_x(this, True), vl__entity_y(this, True), vl__entity_rotation(this, True), vl__entity_scale_x(this, True), vl__entity_scale_y(this, True))

				visuals.vl_visualsT = this\visuals
				mesh.vl_meshT = visuals\mesh
				
				If mesh\last_line_i > 6
					check_for_pick = vl__line_intersects_vert_box(this, sx, sy, dx, dy)
				Else
					check_for_pick = True
				EndIf
				
				If check_for_pick
				
					For i = 0 To mesh\last_line_i
			
						; Get this mesh line start and delta.
						v0_i = mesh\line_v0_i[i]
						v1_i = mesh\line_v1_i[i]
				
						mx# = visuals\vert_x[v0_i]
						my# = visuals\vert_y[v0_i]
				
						mdx# = visuals\vert_x[v1_i] - mx
						mdy# = visuals\vert_y[v1_i] - my
		
						If vl__lines_intersect(sx, sy, dx, dy,  mx, my, mdx, mdy)
					
							Return False
															
						EndIf
		
					Next
			
				EndIf
			
			End Select
			
		EndIf
	
		pickable = pickable\next_elink
		
	Wend

	Return True
	
End Function


;
; Determines whether an entity is within the bounds of the screen.
;
; Params:
; entityID - Handle of entity to check.
;
; Returns:
; True if the given entity is visible, false otherwise.
;
Function vl_entity_in_view(entityID%)

	entity.vl_entityT = Object.vl_entityT(entityID)

	If entity\class = VL_CLASS_MESH
	
	Else
	
		x# = vl__entity_x(entity, True)
		y# = vl__entity_y(entity, True)

		If (x < 0) Or (x > vl_screen_units_x) Then Return False
		If (y < 0) Or (y > vl_screen_units_y) Then Return False
	
		Return True

	EndIf
	
End Function


;
; Converts a world coordinate to the corresponding screen coordinate.
;
; Params:
; world - The world coord to be converted to screen coord.
;
; Returns:
; The screen coordinate that corresponds to the given world coordinate.
;
Function vl_screen#(world#)

	Return (world * vl_unit_size_pixels)

End Function


;
; Converts a screen coordinate to the corresponding world coordinate.
;
; Params:
; screen - The screen coord to be converted to world coord.
;
; Returns:
; The world coordinate that corresponds to the given screen coordinate.
;
Function vl_world#(screen#)

	Return (screen / vl_unit_size_pixels)

End Function


;
; Adds a new vertex to the mesh used by the given entity.
;
; Params:
; entity_ID - Handle of entity whose mesh is to receive the new vertex.
; x         - X coord of new vertex.
; y         - Y coord of new vertex.
;
; Returns:
; The index number of the newly created vertex.
;
Function vl_add_vertex(entity_ID%, x#, y#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh
	
	i = mesh\last_vert_i + 1
	mesh\last_vert_i = i
	
	mesh\vert_x[i] = x
	mesh\vert_y[i] = y

	Return i

End Function


;
; Adds a new vector line to the mesh used by the given entity.
;
; Params:
; entity_ID - Handle of entity whose mesh is to receive the new vector line.
; v0        - Index of vertex representing the start point of the vector line.
; v1        - Index of vertex representing the end point of the vector line.
; hard      - Flag indicating if line is hard or not.
;             False = Soft line (not pickable).
;             True (default) = Hard line (pickable).
;
; Returns:
; The index number of the newly created vector line.
;
Function vl_add_line(entity_ID%, v0%, v1%, hard% = True)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh

	i = mesh\last_line_i + 1
	mesh\last_line_i = i
	
	mesh\line_v0_i[i] = v0
	mesh\line_v1_i[i] = v1
	mesh\line_hard[i] = (hard <> 0)
		
	Return i

End Function


;
; Sets the hard state of an existing mesh vector line.
;
; Params:
; entity_ID - Handle of entity whose mesh holds the affected line.
; line_i    - Index of vector line to set the hard state of.
; hard      - Hard state to set the line to:
;             0 - Line is soft (unpickable).
;             1 - Line is hard (pickable).
;
Function vl_line_hard(entity_ID%, line_i%, hard%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\visuals\mesh\line_hard[line_i] = (hard <> 0)
		
End Function


;
; Returns the requested vertex index of the specified mesh vector line.
;
; Params:
; entity_ID - Handle of entity whose mesh holds the vector line vertex requested.
; line_i    - Index of vector line to get the vertex index of.
; vert_i    - Index of line vertex to be returned.
;             0 = Vector line's start vertex.
;             1 = Vector line's end vertex.
;
; Returns:
; The requested vertex index of the specified mesh vector line.
;
Function vl_line_vertex(entity_ID%, line_i%, vert_i%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	If vert_i

		Return entity\visuals\mesh\line_v1_i[line_i]

	Else

		Return entity\visuals\mesh\line_v0_i[line_i]

	EndIf
	
End Function


;
; Sets the coordinates of an existing mesh vertex.
;
; Params:
; entity_ID - Handle of entity whose mesh holds the affected vertex.
; vert_i    - Index of vertex to be set.
; x         - X coord to set vertex to.
; y         - Y coord to set vertex to.
;
Function vl_vertex_coords(entity_ID%, vert_i%, x#, y#)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	mesh.vl_meshT = entity\visuals\mesh
	
	mesh\vert_x[vert_i] = x
	mesh\vert_y[vert_i] = y

End Function


;
; Returns the X coordinate of a vertex.
;
; Params:
; entity_ID - Handle of entity whose mesh holds the specified vertex.
; vert_i    - Index of vertex to return the X coord of.
;
; Returns:
; The X coordinate of the specified vertex.
;
Function vl_vertex_x#(entity_ID%, vert_i%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	Return entity\visuals\mesh\vert_x[vert_i]

End Function


;
; Returns the Y coordinate of a vertex.
;
; Params:
; entity_ID - Handle of entity whose mesh holds the specified vertex.
; vert_i    - Index of vertex to return the Y coord of.
;
; Returns:
; The Y coordinate of the specified vertex.
;
Function vl_vertex_y#(entity_ID%, vert_i%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	
	Return entity\visuals\mesh\vert_y[vert_i]

End Function


;
; Returns the number of vertices in a mesh.
;
; Params:
; entity_ID - Handle of entity whose mesh vertices are to be counted.
;
; Returns:
; The total number of vertices defined in the specified entity's mesh.
;
Function vl_count_vertices(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	Return (entity\visuals\mesh\last_vert_i + 1)
	
End Function


;
; Returns the number of vector lines in a mesh.
;
; Params:
; entity_ID - Handle of entity whose mesh lines are to be counted.
;
; Returns:
; The total number of vector lines defined in the specified entity's mesh.
;
Function vl_count_lines(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	Return (entity\visuals\mesh\last_line_i + 1)
	
End Function


;
; Creates a copy of an existing entity. All children are also copied.
;
; Params:
; entity_ID - Handle of entity to be copied.
; parent_ID - Handle of entity to be made the new entity's parent.
;             The new entity will then adopt the parent's position/rotation/scale.
;
; Returns:
; The handle of the newly created entity copy.
;
Function vl_copy_entity(entity_ID%, parent_ID% = 0)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	;
	; Create and initialize new entity copy.
	;

	new_entity.vl_entityT = New vl_entityT
	new_entity_ID = Handle(new_entity)
	
	new_entity\visuals			= Null
	new_entity\scale_x			= 1.0
	new_entity\scale_y			= 1.0
	new_entity\rot					= 0.0
	new_entity\x						= 0.0
	new_entity\y						= 0.0
	new_entity\parent				= Null
	new_entity\first_child	= Null

	new_entity\class				= entity\class
	new_entity\hidden				= False
	new_entity\name					= entity\name
	new_entity\radius				= entity\radius
	new_entity\box_x				= entity\box_x
	new_entity\box_y				= entity\box_y
	new_entity\box_width		= entity\box_width
	new_entity\box_height		= entity\box_height

	vl__entity_pick_mode(new_entity, entity\pick_mode, entity\obscurer)

	If entity\class = VL_CLASS_MESH

		visuals.vl_visualsT			= entity\visuals
		new_visuals.vl_visualsT	= New vl_visualsT
		new_entity\visuals			= new_visuals

		vl__add_user(visuals\mesh, new_entity)
		vl__entity_order(new_entity, visuals\order)

		new_visuals\mesh				= visuals\mesh
		new_visuals\r						= visuals\r
		new_visuals\g						= visuals\g
		new_visuals\b						= visuals\b
		new_visuals\brightness	= visuals\brightness

	EndIf
	
	; Recursively copy any child entities.
	If entity\first_child <> Null Then vl__copy_children(entity, new_entity)

	; Keep this AFTER the recursion call, else an infinite loop will be entered
	; if the entity to be parented to is also the entity being copied!
	If parent_ID Then vl_entity_parent(new_entity_ID, parent_ID, False)

	Return new_entity_ID

End Function


;
; Hides an entity so that it's no longer drawn. All children are also hidden.
;
; Params:
; entity_ID - Handle of entity to be hidden.
;
Function vl_hide_entity(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\hidden = True

End Function


;
; Shows an entity.
;
; Params:
; entity_ID - Handle of entity to be shown.
;
Function vl_show_entity(entity_ID%)

	entity.vl_entityT = Object.vl_entityT(entity_ID)

	entity\hidden = False

End Function


;
; Positions an entity at an absolute position.
;
; Params:
; entity_ID - Handle of entity to be positioned.
; x         - X coord entity will be positioned at.
; y         - Y coord entity will be positioned at.
; glob      - True if the position is global.
;             False (default) if the position is local.
;
Function vl_position_entity(entity_ID%, x#, y#, glob% = False)

	entity.vl_entityT = Object.vl_entityT(entity_ID)
	parent.vl_entityT = entity\parent
	
	If glob And (parent <> Null)

		; Find global coords of x,y point, relative to parent.
		dx# = x - vl__entity_x(parent, True)
		dy# = y - vl__entity_y(parent, True)

		; Rotate coords into parent's coord system.
		inv_pg_rot# = -vl__entity_rotation(parent, True)

		cos_rot# = Cos(inv_pg_rot)
		sin_rot# = Sin(inv_pg_rot)
		
		x = (dx * cos_rot) - (dy * sin_rot)
		y = (dy * cos_rot) + (dx * sin_rot)

		; Scale coords to parent's global scale.
		entity\x = x / vl__entity_scale_x(parent, True)
		entity\y = y / vl__entity_scale_y(parent, True)

	Else
	
		entity\x = x
		entity\y = y
	
	EndIf

End Function

Comments

big10p2013
Part 2:


And here's a bare-bones Asteroid thingy, to demonstrate. Controls: Cursor keys and SPACE to fire.




BlitzSupport2013
Just went to try this, but it's unfortunately cut off at the end of the include -- might have to split it up a bit, not sure if there's a limit but it is nearly 64k in size so sounds likely.


big10p2013
Ah, yes. It seems to have been cut off. :( I'll see what I can do...


Code Archives Forum