695 lines
21 KiB
Text
695 lines
21 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, Material
|
|
import "luxe: assets" for Assets, Strings
|
|
import "luxe: bytes" for Uint16, Floats
|
|
import "luxe: math" for Math
|
|
|
|
import "trail: _queue" for Queue
|
|
|
|
import "trail: modifier/trail.modifier" for ModifierData
|
|
|
|
#doc="""
|
|
Modifier to add simple trails to entities.
|
|
Needs a Transform on the same entity to work.
|
|
|
|
```js
|
|
var entity = Entity.create(world)
|
|
Transform.create(entity)
|
|
Trail.create(entity)
|
|
|
|
//now just move and rotate the entity around
|
|
```
|
|
"""
|
|
class Trail {
|
|
static time_based{true}
|
|
static distance_based{false}
|
|
|
|
#doc="Add a trail modifier to an entity. Entity should also have a Transform."
|
|
#args(
|
|
entity = "The entity to add the trail modifier to."
|
|
)
|
|
static create(entity: Entity): None {
|
|
Modifiers.create(This, entity)
|
|
}
|
|
|
|
#doc="Remove the trail modifier from an entity."
|
|
#args(
|
|
entity = "The entity to remove the trail modifier from."
|
|
)
|
|
static destroy(entity: Entity): None {
|
|
Modifiers.destroy(This, entity)
|
|
}
|
|
|
|
#doc="Check whether an entity has a trail modifier or not."
|
|
#args(
|
|
entity = "The entity to check whether it has a trail modifier."
|
|
)
|
|
static has(entity: Entity): Bool {
|
|
return Modifiers.has(This, entity)
|
|
}
|
|
|
|
#doc="Reset trail to no length."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static reset(entity: Entity): None {
|
|
Modifiers.get_system(This, entity).reset(entity )
|
|
}
|
|
|
|
#doc="Set the width of a trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
width = "The new width of the trail."
|
|
)
|
|
static set_width(entity: Entity, width: Num): None {
|
|
Modifiers.get(This, entity).edge_length = width
|
|
}
|
|
|
|
#doc="Get the width of a trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_width(entity: Entity): Num {
|
|
return Modifiers.get(This, entity).edge_length
|
|
}
|
|
|
|
#doc="Set the length of a trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
length = "The new length of the trail."
|
|
)
|
|
static set_length(entity: Entity, length: Num): None {
|
|
Modifiers.get(This, entity).length = length
|
|
//todo: recalculate transient data?
|
|
}
|
|
|
|
#doc="Get the length of a trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_length(entity: Entity): Num {
|
|
return Modifiers.get(This, entity).length
|
|
}
|
|
|
|
#doc="""
|
|
Set whether the trail is time based or distance based.
|
|
|
|
```js
|
|
Trail.set_time_based(entity, Trail.distance_based)
|
|
```
|
|
"""
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
time_based = "`true` if its time based, `false` if its distance based."
|
|
)
|
|
static set_time_based(entity: Entity, time_based: Bool): None {
|
|
Modifiers.get(This, entity).time_based = time_based
|
|
}
|
|
|
|
#doc="""
|
|
Get whether the trail is time based or distance based. (true if time based, false if distance based)
|
|
"""
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_time_based(entity: Entity): Bool {
|
|
return Modifiers.get(This, entity).time_based
|
|
}
|
|
|
|
#doc="""
|
|
Set whether the trail should have normalized UVs of a trail.
|
|
If the UVs are normalized, they should be linear over distance,
|
|
especially with time based trails you otherwise can get very wobbly behaviour as speed changes.
|
|
"""
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
length = "Whether the trail should have normalized uvs."
|
|
)
|
|
static set_normalize_uvs(entity: Entity, normalize_uvs: Bool): None {
|
|
Modifiers.get(This, entity).normalize_uvs = normalize_uvs
|
|
}
|
|
|
|
#doc="Get whether a trail has normalized uvs."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_normalize_uvs(entity: Entity): Bool {
|
|
return Modifiers.get(This, entity).normalize_uvs
|
|
}
|
|
|
|
#doc="Set the material the trail is rendered with via its id."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static set_material_id(entity: Entity, material_id: String): None {
|
|
Strings.add(material_id)
|
|
Modifiers.get(This, entity).material = material_id
|
|
Modifiers.get_system(This, entity).set_material_id(entity, material_id)
|
|
}
|
|
|
|
#doc="Set the material the trail is rendered with."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static set_material(entity: Entity, material: Material): None {
|
|
var material_id = Material.get_source_id(material)
|
|
Strings.add(material_id)
|
|
Modifiers.get(This, entity).material = material_id
|
|
Modifiers.get_system(This, entity).set_material(entity, material)
|
|
}
|
|
|
|
#doc="Get the id of the currently used material."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_material_id(entity: Entity): String {
|
|
return Strings.get(Modifiers.get(This, entity).material)
|
|
}
|
|
|
|
#doc="""
|
|
Set mesh subdivisions around length of the trail.
|
|
This will rebuild the mesh entirely and potentially throw away custom materials you set via `set_material`.
|
|
"""
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
subdivisions = "Subdivisions along length."
|
|
)
|
|
static set_subdivisions_length(entity: Entity, subdivisions: Num){
|
|
Modifiers.get(This, entity).subdivisions_length = subdivisions
|
|
Modifiers.get_system(This, entity).recreate_buffers(entity)
|
|
}
|
|
|
|
#doc="Get subdivisions in length of trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_subdivisions_length(entity: Entity): Num{
|
|
return Modifiers.get(This, entity).subdivisions_length
|
|
}
|
|
|
|
#doc="""
|
|
Set mesh subdivisions around length of the trail.
|
|
This will rebuild the mesh entirely and potentially throw away custom materials you set via `set_material`.
|
|
"""
|
|
#args(
|
|
entity = "The entity with the trail modifier.",
|
|
subdivisions = "Subdivisions along width."
|
|
)
|
|
static set_subdivisions_width(entity: Entity, subdivisions: Num){
|
|
Modifiers.get(This, entity).subdivisions_width = subdivisions
|
|
Modifiers.get_system(This, entity).recreate_buffers(entity)
|
|
}
|
|
|
|
#doc="Get subdivisions in width of trail."
|
|
#args(
|
|
entity = "The entity with the trail modifier."
|
|
)
|
|
static get_subdivisions_width(entity: Entity): Num{
|
|
return Modifiers.get(This, entity).subdivisions_width
|
|
}
|
|
} //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.
|
|
#hidden
|
|
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
|
|
|
|
var mesh_debug = PathStyle.new()
|
|
mesh_debug.color = [0, 0, 1, 1]
|
|
mesh_debug.thickness = 0.5
|
|
_debug_mesh_style = mesh_debug
|
|
}
|
|
|
|
reset(entity: Entity){
|
|
_instance_data[entity].points.clear()
|
|
}
|
|
|
|
set_material_id(entity: Entity, material_id: String){
|
|
var material = Assets.material(material_id)
|
|
set_material(entity, material)
|
|
}
|
|
|
|
set_material(entity: Entity, material: Material){
|
|
var data = _instance_data[entity]
|
|
if(!data || !material) return
|
|
Geometry.set_material(entity, material)
|
|
}
|
|
|
|
recreate_buffers(entity: Entity){
|
|
//better solution for after fixes
|
|
/*var data = get(entity)
|
|
var inst_data: TrailData = _instance_data[entity]
|
|
|
|
if(!data || !inst_data) return
|
|
|
|
inst_data.points.clear()
|
|
|
|
var index_data = create_index_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
Render.index_buffer_replace(inst_data.index_buffer, index_data, index_data.length)
|
|
|
|
var pos_data = create_position_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
Render.vertex_buffer_replace(inst_data.position_buffer, pos_data, pos_data.length)
|
|
|
|
var uv_data = create_uv_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
Render.vertex_buffer_replace(inst_data.uv_buffer, uv_data, uv_data.length)
|
|
|
|
var color_data = create_color_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
Render.vertex_buffer_replace(inst_data.color_buffer, color_data, color_data.length)*/
|
|
|
|
//...but for now...
|
|
var data = get(entity)
|
|
detach(entity, data)
|
|
attach(entity, data)
|
|
}
|
|
|
|
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_length, data.subdivisions_width)
|
|
index_buffer = Render.create_index_buffer(index_buffer, index_buffer.length)
|
|
var geo = Geometry.create(Primitive.triangle, material, (data.subdivisions_length - 1) * 6, IndexType.u16, index_buffer)
|
|
|
|
var pos_buffer = create_position_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
pos_buffer = Render.create_vertex_buffer(pos_buffer, pos_buffer.length)
|
|
Geometry.set_vertex_buffer(geo, 0, pos_buffer)
|
|
|
|
var color_buffer = create_color_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
color_buffer = Render.create_vertex_buffer(color_buffer, color_buffer.length)
|
|
Geometry.set_vertex_buffer(geo, 1, color_buffer)
|
|
|
|
var uv_buffer = create_uv_buffer(data.subdivisions_length, data.subdivisions_width)
|
|
uv_buffer = Render.create_vertex_buffer(uv_buffer, uv_buffer.length)
|
|
Geometry.set_vertex_buffer(geo, 2, uv_buffer)
|
|
|
|
World.render_set_add(_world, geo, entity)
|
|
|
|
_instance_data[entity] = TrailData.new(geo, index_buffer, pos_buffer, color_buffer, uv_buffer)
|
|
}
|
|
|
|
create_position_buffer(subdivs_len: Num, subdivs_width: Num): Floats{
|
|
var raw = Floats.new(4 * subdivs_width * subdivs_len)
|
|
return raw
|
|
}
|
|
|
|
create_color_buffer(subdivs_len: Num, subdivs_width: Num): Floats{
|
|
var raw = Floats.new(4 * subdivs_width * subdivs_len)
|
|
for(i in 0...subdivs_len){
|
|
for(ii in 0...subdivs_width){
|
|
raw[i*subdivs_width*4 + ii*4 + 0] = 1
|
|
raw[i*subdivs_width*4 + ii*4 + 1] = 1
|
|
raw[i*subdivs_width*4 + ii*4 + 2] = 1
|
|
raw[i*subdivs_width*4 + ii*4 + 3] = 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 raw
|
|
}
|
|
|
|
create_uv_buffer(subdivs_len: Num, subdivs_width: Num): Floats{
|
|
var raw = Floats.new(2 * subdivs_width * subdivs_len)
|
|
for(i in 0...subdivs_len){
|
|
var x = i / (subdivs_len - 1)
|
|
for(ii in 0...subdivs_width){
|
|
var y = ii / (subdivs_width - 1)
|
|
raw[i*2*subdivs_width + ii*2 + 0] = x
|
|
raw[i*2*subdivs_width + ii*2 + 1] = y
|
|
}
|
|
}
|
|
//var arr = (0...(raw.size/2)).map{|i|"[%(raw[i*2]), %(raw[i*2+1])]"}.join("\n")
|
|
//System.print(arr)
|
|
return raw
|
|
}
|
|
|
|
create_index_buffer(subdivs_len: Num, subdivs_width: Num): Uint16{
|
|
var rows = subdivs_len - 1
|
|
var cols = subdivs_width-1
|
|
var index_count = rows * cols * 6
|
|
var raw = Uint16.new(index_count)
|
|
for(i in 0...rows){
|
|
for(ii in 0...cols){
|
|
//System.print("x: %(i) | y:%(ii)")
|
|
//first triangle
|
|
raw[i*6*cols + ii*6 + 0] = i * (cols+1) + ii + 0
|
|
raw[i*6*cols + ii*6 + 1] = i * (cols+1) + ii + cols+1
|
|
raw[i*6*cols + ii*6 + 2] = i * (cols+1) + ii + 1
|
|
//System.print("(%(i*6*cols + ii*6 + 0), %(i*6*cols + ii*6 + 1), %(i*6*cols + ii*6 + 2))")
|
|
//System.print("[%(i * (cols+1) + ii + 0), %(i * (cols+1) + ii + cols+1), %(i * (cols+1) + ii + 1)]")
|
|
|
|
//second triangle
|
|
raw[i*6*cols + ii*6 + 3] = i * (cols+1) + ii + 1
|
|
raw[i*6*cols + ii*6 + 4] = i * (cols+1) + ii + cols+1
|
|
raw[i*6*cols + ii*6 + 5] = i * (cols+1) + ii + cols+2
|
|
//System.print("(%(i*6*cols + ii*6 + 3), %(i*6*cols + ii*6 + 4), %(i*6*cols + ii*6 + 5))")
|
|
//System.print("[%(i * (cols+1) + ii + 1), %(i * (cols+1) + ii + cols+1), %(i * (cols+1) + ii + cols+2)]")
|
|
}
|
|
}
|
|
//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 raw
|
|
}
|
|
|
|
detach(entity, data: ModifierData) {
|
|
var inst_data: TrailData = _instance_data[entity]
|
|
World.render_set_remove(_world, inst_data.geometry, entity)
|
|
Geometry.destroy(inst_data.geometry)
|
|
Render.destroy_index_buffer(inst_data.index_buffer)
|
|
Render.destroy_vertex_buffer(inst_data.position_buffer)
|
|
Render.destroy_vertex_buffer(inst_data.color_buffer)
|
|
Render.destroy_vertex_buffer(inst_data.uv_buffer)
|
|
_instance_data.remove(entity)
|
|
}
|
|
|
|
tick(delta) {
|
|
if(World.tag_has(_world, "edit")){
|
|
each{|entity, data: ModifierData|
|
|
if(!Transform.has(entity)) return
|
|
|
|
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)
|
|
Draw.path3D(_draw, [start, end], _debug_edge_style, false)
|
|
}
|
|
Draw.commit(_draw)
|
|
return
|
|
}
|
|
|
|
//System.print("positions")
|
|
record_positions(delta)
|
|
//System.print("buffers")
|
|
update_buffers()
|
|
//System.print("debug")
|
|
//debug_draw()
|
|
//System.print("end")
|
|
} //tick
|
|
|
|
record_positions(delta: Num){
|
|
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:Num
|
|
if(data.time_based){
|
|
diff = delta
|
|
} else {
|
|
diff = Math.dist(pos, prev_pos)
|
|
}
|
|
if(diff > data.length){
|
|
if(data.time_based){
|
|
var t = data.length / diff
|
|
prev_pos.x = Math.lerp(pos.x, prev_pos.x, t)
|
|
prev_pos.y = Math.lerp(pos.y, prev_pos.y, t)
|
|
prev_pos.z = Math.lerp(pos.z, prev_pos.z, t)
|
|
} else {
|
|
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_length
|
|
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_length) 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|
|
|
if(!Transform.has(entity)) return
|
|
|
|
var instance_data: TrailData = _instance_data[entity]
|
|
var points = instance_data.points
|
|
|
|
var pos = Transform.get_pos_world(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)
|
|
|
|
var uvs: Floats
|
|
if(data.normalize_uvs){
|
|
uvs = Floats.new(Render.vertex_buffer_get_size(instance_data.uv_buffer) / 4)
|
|
Render.vertex_buffer_get_data(instance_data.uv_buffer, uvs, uvs.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
|
|
{
|
|
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)
|
|
|
|
for(ii in 0...data.subdivisions_width){
|
|
var t = ii / (data.subdivisions_width-1)
|
|
var pos_x = Math.lerp(start.x, end.x, t)
|
|
var pos_y = Math.lerp(start.y, end.y, t)
|
|
var pos_z = Math.lerp(start.z, end.z, t)
|
|
positions[i*4*data.subdivisions_width + ii*4 + 0] = pos_x
|
|
positions[i*4*data.subdivisions_width + ii*4 + 1] = pos_y
|
|
positions[i*4*data.subdivisions_width + ii*4 + 2] = pos_z
|
|
}
|
|
}
|
|
|
|
var length = 0
|
|
var current_len = 0
|
|
if(data.normalize_uvs){
|
|
for(i in 0...points.count){
|
|
var from = i<(points.count-1)? points[i+1].pos : pos
|
|
var to = points[i].pos
|
|
var dist = Math.dist(from, to)
|
|
length = length + (i != (points.count-1) ? dist : dist * (1 - instance_data.progress_since_last_point / (data.length / data.subdivisions_length)))
|
|
}
|
|
|
|
current_len = points.count > 1 ? Math.dist(points[points.count-1].pos, pos) : 0
|
|
}
|
|
|
|
var step = data.length / data.subdivisions_length
|
|
var t = 1 - instance_data.progress_since_last_point / step
|
|
|
|
var point_index = points.count - 1
|
|
while(true){
|
|
if(point_index < 0) break
|
|
|
|
var p:Point
|
|
var next:Point
|
|
|
|
point_index = point_index - 1
|
|
if(point_index < 0) break
|
|
p = points[point_index]
|
|
next = points[point_index + 1]
|
|
|
|
var to = p.pos
|
|
var to_up = p.up
|
|
|
|
var from = next.pos
|
|
var from_up = next.up
|
|
|
|
|
|
var pos = [
|
|
Math.lerp(from.x, to.x, t),
|
|
Math.lerp(from.y, to.y, t),
|
|
Math.lerp(from.z, to.z, t)
|
|
]
|
|
|
|
var up = [
|
|
Math.lerp(from_up.x, to_up.x, t),
|
|
Math.lerp(from_up.y, to_up.y, t),
|
|
Math.lerp(from_up.z, to_up.z, t)
|
|
]
|
|
|
|
Math.normalize(up)
|
|
|
|
i = i + 1
|
|
for(y in 0...data.subdivisions_width){
|
|
var t = y / (data.subdivisions_width-1)
|
|
var offset_x = Math.lerp(-up.x, up.x, t)
|
|
var offset_y = Math.lerp(-up.y, up.y, t)
|
|
var offset_z = Math.lerp(-up.z, up.z, t)
|
|
positions[i*4*data.subdivisions_width + y*4 + 0] = pos.x + offset_x * data.edge_length * 0.5
|
|
positions[i*4*data.subdivisions_width + y*4 + 1] = pos.y + offset_y * data.edge_length * 0.5
|
|
positions[i*4*data.subdivisions_width + y*4 + 2] = pos.z + offset_z * data.edge_length * 0.5
|
|
}
|
|
|
|
if(data.normalize_uvs){
|
|
var segment_len = Math.dist(from, to)
|
|
current_len = current_len + segment_len * t
|
|
var x = current_len / length
|
|
for(ii in 0...data.subdivisions_width){
|
|
var y = ii / (data.subdivisions_width - 1)
|
|
uvs[i*2*data.subdivisions_width + ii*2 + 0] = x
|
|
uvs[i*2*data.subdivisions_width + ii*2 + 1] = y
|
|
}
|
|
current_len = current_len + segment_len * (1-t)
|
|
}
|
|
}
|
|
|
|
Render.vertex_buffer_replace(instance_data.position_buffer, positions, positions.length)
|
|
if(data.normalize_uvs){
|
|
Render.vertex_buffer_replace(instance_data.uv_buffer, uvs, uvs.length)
|
|
}
|
|
Geometry.set_vert_count(instance_data.geometry, i.max(0) * 6 * (data.subdivisions_width-1))
|
|
}
|
|
}
|
|
|
|
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]
|
|
var points = instance_data.points
|
|
|
|
if(points.count > 1){
|
|
Draw.path3D(_draw, points.map{|p:Point|p.pos}.toList, _debug_path_style, false)
|
|
}
|
|
|
|
points.each{|point: Point|
|
|
var from_x = point.pos.x + point.up.x * data.edge_length * 0.5
|
|
var from_y = point.pos.y + point.up.y * data.edge_length * 0.5
|
|
var from_z = point.pos.x + point.up.x * data.edge_length * 0.5
|
|
|
|
var to_x = point.pos.x - point.up.x * data.edge_length * 0.5
|
|
var to_y = point.pos.y - point.up.y * data.edge_length * 0.5
|
|
var to_z = point.pos.z - point.up.z * data.edge_length * 0.5
|
|
|
|
Draw.path3D(_draw, [[from_x, from_y, from_z], [to_x, to_y, to_z]], _debug_path_style, false)
|
|
}
|
|
|
|
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)
|
|
var indices = Uint16.new(Render.index_buffer_get_size(instance_data.index_buffer) / 2)
|
|
Render.index_buffer_get_data(instance_data.index_buffer, indices, indices.length, 0)
|
|
for(i in 0...(Geometry.get_vert_count(instance_data.geometry) / 3)){
|
|
var i1 = indices[i * 3 + 0]
|
|
var i2 = indices[i * 3 + 1]
|
|
var i3 = indices[i * 3 + 2]
|
|
|
|
var v1 = [positions[i1 * 4 + 0], positions[i1 * 4 + 1], positions[i1 * 4 + 2]]
|
|
var v2 = [positions[i2 * 4 + 0], positions[i2 * 4 + 1], positions[i2 * 4 + 2]]
|
|
var v3 = [positions[i3 * 4 + 0], positions[i3 * 4 + 1], positions[i3 * 4 + 2]]
|
|
|
|
Draw.path3D(_draw, [v1, v2, v3], _debug_mesh_style, true)
|
|
}
|
|
}
|
|
Draw.commit(_draw)
|
|
}
|
|
|
|
} //TrailSystem
|
|
|
|
var Modifier = TrailSystem //required
|