Trails/modifiers/trail/trail.wren
Ronja 3c95c9e5f3 Initial Commit
first implementation of distance based trail
2022-01-23 11:01:09 +01:00

324 lines
9.4 KiB
Text

import "luxe: io" for IO
import "luxe: world" for World, Entity, Modifiers, ModifierSystem, Transform
import "luxe: draw" for Draw, PathStyle, LineCap
import "luxe: color" for Color
import "luxe: render" for Geometry, Primitive, IndexType, Render
import "luxe: assets" for Assets, Strings
import "luxe: bytes" for Uint16, Floats
import "queue" for Queue
import "modifiers/trail/trail.modifier" for ModifierData
import "luxe: math" for Math
//User facing API
//This is what the user of your modifier will interact with
class Trail {
static create(entity) { Modifiers.create(This, entity) }
static destroy(entity) { Modifiers.destroy(This, entity) }
static has(entity) { Modifiers.has(This, entity) }
static reset(entity){
Modifiers.get_system(This, entity).reset(entity )
}
} //Trail
#hidden
class Point {
construct new(pos: Vec, up: Vec){
_pos = pos
_up = up
}
pos{_pos}
up{_up}
}
#hidden
class TrailData {
construct new(geometry, indices, positions, colors, uvs){
_geometry = geometry
_index_buf = indices
_pos_buf = positions
_col_buf = colors
_uv_buf = uvs
_progress = 0
_progress_since_last_point = 0
_points = Queue.new()
}
geometry{_geometry}
index_buffer{_index_buf}
position_buffer{_pos_buf}
color_buffer{_col_buf}
uv_buffer{_uv_buf}
points: Queue {_points}
progress: Num {_progress}
progress=(v){_progress=v}
progress_since_last_point: Num {_progress_since_last_point}
progress_since_last_point=(v){_progress_since_last_point = v}
previous_pos: Vec {_previous_pos}
previous_pos=(v){_previous_pos=v}
previous_up: Vec {_previous_up}
previous_up=(v){_previous_up}
}
//Your modifier system implementation.
//This speaks to the engine and your user facing API
//to do the actual work. You'll get notified when things change
//in the world and respond to them here.
class TrailSystem is ModifierSystem {
construct new() {
//called when your system is first created.
_instance_data = {}
}
init(world) {
_world = world
_draw = Draw.create(World.render_set(world))
var edge_debug = PathStyle.new()
edge_debug.color = [1,1,1,1]
edge_debug.thickness = 2
edge_debug.cap = LineCap.round
_debug_edge_style = edge_debug
var path_debug = PathStyle.new()
path_debug.color = [1, 0, 0, 1]
path_debug.thickness = 1
_debug_path_style = path_debug
}
reset(entity: Entity){
_instance_data[entity].points.clear()
}
destroy() {
Draw.destroy(_draw)
}
attach(entity, data: ModifierData) {
var material_id = Strings.get(data.material)
var material = Assets.material(material_id)
var index_buffer = create_index_buffer(data.subdivisions)
var geo = Geometry.create(Primitive.triangle, material, (data.subdivisions - 1) * 6, IndexType.u16, index_buffer)
var pos_buffer = create_position_buffer(data.edge_length, data.length, data.subdivisions)
Geometry.set_vertex_buffer(geo, 0, pos_buffer)
var color_buffer = create_color_buffer(data.edge_length, data.length, data.subdivisions)
Geometry.set_vertex_buffer(geo, 1, color_buffer)
var uv_buffer = create_uv_buffer(data.edge_length, data.length, data.subdivisions)
Geometry.set_vertex_buffer(geo, 2, uv_buffer)
var identity = Floats.new(16)
identity.transform(0, 0, 0, 0, 0, 0, 1, 1, 1)
Geometry.set_world_matrix(geo, identity)
World.render_set_add(_world, geo, entity)
_instance_data[entity] = TrailData.new(geo, index_buffer, pos_buffer, color_buffer, uv_buffer)
}
create_position_buffer(height: Num, length: Num, subdivs: Num): VertexBuffer{
var raw = Floats.new(4 * 2 * subdivs)
for(i in 0...subdivs){
var x = length * i / (subdivs - 1)
raw[i*2*4+0] = x
raw[i*2*4+1] = 0
raw[i*2*4+2] = 0
raw[i*2*4+3] = 1
raw[i*2*4+4] = x
raw[i*2*4+5] = height
raw[i*2*4+6] = 0
raw[i*2*4+7] = 1
}
//var arr = (0...(raw.size/4)).map{|i|"[%(raw[i*4]), %(raw[i*4+1]), %(raw[i*4+2])]"}.join("\n")
//System.print(arr)
return Render.create_vertex_buffer(raw, raw.length)
}
create_color_buffer(height: Num, length: Num, subdivs: Num): VertexBuffer{
var raw = Floats.new(4 * 2 * subdivs)
for(i in 0...subdivs){
var x = length * i / (subdivs - 1)
raw[i*2*4+0] = 1
raw[i*2*4+1] = 1
raw[i*2*4+2] = 1
raw[i*2*4+3] = 1
raw[i*2*4+4] = 1
raw[i*2*4+5] = 1
raw[i*2*4+6] = 1
raw[i*2*4+7] = 1
}
//var arr = (0...(raw.size/4)).map{|i|"[%(raw[i*4]), %(raw[i*4+1]), %(raw[i*4+2])]"}.join("\n")
//System.print(arr)
return Render.create_vertex_buffer(raw, raw.length)
}
create_uv_buffer(height: Num, length: Num, subdivs: Num): VertexBuffer{
var raw = Floats.new(2 * 2 * subdivs)
for(i in 0...subdivs){
var x = i / (subdivs - 1)
raw[i*2*2+0] = x
raw[i*2*2+1] = 1
raw[i*2*2+2] = x
raw[i*2*2+3] = 0
}
//var arr = (0...(raw.size/2)).map{|i|"[%(raw[i*2]), %(raw[i*2+1])]"}.join("\n")
//System.print(arr)
return Render.create_vertex_buffer(raw, raw.length)
}
create_index_buffer(subdivs: Num): IndexBuffer{
var index_count = (subdivs - 1) * 6
var raw = Uint16.new(index_count)
for(i in 0...(subdivs-1)){
//first triangle
raw[i*6+0] = i * 2 + 0
raw[i*6+1] = i * 2 + 2
raw[i*6+2] = i * 2 + 1
//second triangle
raw[i*6+3] = i * 2 + 1
raw[i*6+4] = i * 2 + 2
raw[i*6+5] = i * 2 + 3
}
//var arr = (0...(raw.length/(3*4))).map{|i|"[%(raw[i*3]), %(raw[i*3+1]), %(raw[i*3+2])]"}.join("\n")
//System.print(arr)
return Render.create_index_buffer(raw, raw.length)
}
detach(entity, data: ModifierData) {
//called when detached from an entity, like on destroy
}
tick(delta) {
//System.print("positions")
record_positions()
//System.print("buffers")
update_buffers()
//System.print("debug")
debug_draw()
//System.print("end")
} //tick
record_positions(){
each{|entity, data: ModifierData|
if(!Transform.has(entity)) return
var instance_data: TrailData = _instance_data[entity]
var pos = Transform.get_pos_world(entity)
var up = Transform.local_dir_to_world(entity, 0, data.edge_length * 0.5, 0)
var prev_pos = instance_data.previous_pos || pos
var prev_up = instance_data.previous_up || up
var dist = instance_data.progress_since_last_point
var diff = Math.dist(pos, prev_pos)
if(diff > data.length){
var dir = [prev_pos.x - pos.x, prev_pos.y - pos.y, prev_pos.z - pos.z]
Math.normalize(dir)
dir.x = dir.x * data.length
dir.y = dir.y * data.length
dir.z = dir.z * data.length
prev_pos.x = pos.x + dir.x
prev_pos.y = pos.y + dir.y
prev_pos.z = pos.z + dir.z
diff = data.length
}
dist = dist + diff
var step = data.length / data.subdivisions
while(dist > step){
dist = dist - step
var t = 1 - dist / diff
var point = Point.new([
Math.lerp(prev_pos.x, pos.x, t),
Math.lerp(prev_pos.y, pos.y, t),
Math.lerp(prev_pos.z, pos.z, t)
], [
Math.lerp(prev_up.x, up.x, t),
Math.lerp(prev_up.y, up.y, t),
Math.lerp(prev_up.z, up.z, t)
])
Math.normalize(point.up)
if(instance_data.points.count >= data.subdivisions - 1) instance_data.points.dequeue()
instance_data.points.enqueue(point)
}
instance_data.progress_since_last_point = dist
instance_data.previous_pos = pos
instance_data.previous_up = up
}
}
update_buffers(){
each{|entity, data: ModifierData|
var instance_data: TrailData = _instance_data[entity]
var positions = Floats.new(Render.vertex_buffer_get_size(instance_data.position_buffer) / 4)
Render.vertex_buffer_get_data(instance_data.position_buffer, positions, positions.size * 4, 0)
//System.print("positions(%(Render.vertex_buffer_get_size(instance_data.position_buffer))):")
//System.print((0...(positions.size/4)).map{|i|"[%(positions[i*4]), %(positions[i*4+1]), %(positions[i*4+2])]"}.join("\n"))
var i = -1
for(p in instance_data.points){
i = i + 1
positions[i * 8 + 0] = p.pos.x - p.up.x * data.edge_length * 0.5
positions[i * 8 + 1] = p.pos.y - p.up.y * data.edge_length * 0.5
positions[i * 8 + 2] = p.pos.z - p.up.z * data.edge_length * 0.5
positions[i * 8 + 4] = p.pos.x + p.up.x * data.edge_length * 0.5
positions[i * 8 + 5] = p.pos.y + p.up.y * data.edge_length * 0.5
positions[i * 8 + 6] = p.pos.z + p.up.z * data.edge_length * 0.5
}
if(Transform.has(entity)){
i = i + 1
var start = Transform.local_point_to_world(entity, 0, data.edge_length * -0.5, 0)
var end = Transform.local_point_to_world(entity, 0, data.edge_length * 0.5, 0)
positions[i * 8 + 0] = start.x
positions[i * 8 + 1] = start.y
positions[i * 8 + 2] = start.z
positions[i * 8 + 4] = end.x
positions[i * 8 + 5] = end.y
positions[i * 8 + 6] = end.z
}
Render.vertex_buffer_replace(instance_data.position_buffer, positions, positions.length)
Geometry.set_vert_count(instance_data.geometry, i.max(0) * 6)
}
}
debug_draw(){
each {|entity, data: ModifierData|
var start = [0, 0]
var end = [0, data.edge_length]
var depth = 0
if(Transform.has(entity)){
start = Transform.local_point_to_world(entity, 0, data.edge_length * -0.5, 0)
end = Transform.local_point_to_world(entity, 0, data.edge_length * 0.5, 0)
depth = Transform.get_depth2D_world(entity)
}
Draw.line(_draw, start.x, start.y, end.x, end.y, depth, _debug_edge_style)
var instance_data: TrailData = _instance_data[entity]
if(instance_data.points.count > 1){
Draw.path3D(_draw, instance_data.points.map{|p:Point|p.pos}.toList, _debug_path_style, false)
}
}
Draw.commit(_draw)
}
} //TrailSystem
var Modifier = TrailSystem //required