Initial Commit

first implementation of distance based trail
This commit is contained in:
Ronja 2022-01-23 11:01:09 +01:00
commit 3c95c9e5f3
13 changed files with 1205 additions and 0 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
*/.DS_Store
.DS_Store
.DS_Store?
*/thumbs.db
thumbs.db
.thumbs.db?
.luxe/
_luxe.data/
_luxe.deploy/
log*.txt

1
.luxeignore Normal file
View file

@ -0,0 +1 @@
preview.png

61
game.wren Normal file
View file

@ -0,0 +1,61 @@
import "luxe: game" for Ready
import "luxe: assets" for Assets
import "luxe: input" for Input, Key
import "luxe: world" for World, Entity, Transform, Sprite, Values, Tags, Camera
import "luxe: math" for Math
import "luxe: draw" for Draw
import "luxe: io" for IO
import "outline/app" for App
import "modifiers/trail/trail" for Trail
class Game is Ready {
construct ready() {
super("ready!")
app = App.new()
app.color = [0,0,0,1]
System.print("render size: %(app.width) x %(app.height) @ %(app.scale)x")
_blade = Entity.create(app.world)
Transform.create(_blade)
Transform.set_pos(_blade, 100, 100)
Trail.create(_blade)
_prev_pos = [0,0,0]
} //ready
tick(delta) {
var pos = Camera.screen_point_to_world(app.camera, Input.mouse_x(), Input.mouse_y())
var t = delta * 30
pos = [Math.lerp(_prev_pos.x, pos.x, t), Math.lerp(_prev_pos.y, pos.y, t)]
if(Math.dist2D(pos, _prev_pos) > 0.1){
var angle = Math.angle2D(_prev_pos, pos)
Transform.set_angle2D(_blade, angle)
_prev_pos = pos
}
Transform.set_pos(_blade, pos.x, pos.y)
if(Input.key_state_released(Key.escape)) {
IO.shutdown()
}
if(Input.key_state_released(Key.space)) {
Trail.reset(_blade)
}
// app.color.r = app.color.g = app.color.b = (IO.timestamp()/20 % 1)
} //tick
destroy() {
System.print("unready!")
app.destroy()
} //destroy
app { _app }
app=(v) { _app=v }
} //Game

View file

@ -0,0 +1,16 @@
modifier = {
script = "modifiers/trail/trail"
description = "Trail go brrr."
field = "trail"
display = "Trail" //the display in the editor
class = "Trail" //The code generated name for the modifier API
block = { //The data for the modifier
fields = [
{ name="edge_length" type="number" default=100 }
{ name="time_based" type="boolean" default=false }
{ name="length" type="number" default=100 }
{ name="subdivisions" type="number" default=20 }
{ name="material" type="id32" editor="material" default="luxe: material/solid"}
]
}
}

View file

@ -0,0 +1,554 @@
//-- this file is generated! don't try editing it.
import "luxe: io" for IO
import "luxe: bytes" for Byter, Bytes
import "luxe: world" for Block
//`modifiers/trail/trail > runtime` types
class ModifierRuntime {
construct new() {
} //new
} //ModifierRuntime
//`modifiers/trail/trail > runtime` compilers
class ModifierRuntimeCompiler {
construct new() {
}
bytes_count(instance) {
var size = 4 //version
size = size + 0
return size
} //bytes_count
validate(from_source_id, elements) {
var fields = {
"type": false, //:luxe:internal
"uuid": false, //:luxe:internal
"luxe.self.modifier": false, //:luxe:internal
}
for(element in elements) {
var instance = element.value
for(field in instance) {
if(fields[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`")
} //if not found
} //each field
for(field in fields) {
var required = field.value
if(required && instance[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)")
}
} //each field
} //each element
} //validate
write(compiler, instance, out) {
//version
out.write_int32(0)
return out
} //write
bytes_count_block() {
return 8
} //bytes_count_block
write_block(compiler, out) {
//source id
out.write_uint32(compiler.string.hash("modifiers/trail/trail > runtime"))
//fields count
out.write_int32(0)
} //write_block
write(instance) {
var size = bytes_count(instance)
var out = Byter.new(size+8)
out.write_string("LUXEMRTM")
write(instance, out)
return out
} //write
} //ModifierRuntimeCompiler
//`modifiers/trail/trail > runtime` block types
class BlockModifierRuntime {
field { "trail" }
source { "modifiers/trail/trail > runtime" }
construct new(block) {
_block = block
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
}
construct new() {
_block = Block.create()
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
Block.set_type(_block, "modifiers/trail/trail > runtime")
} //new
instance_type {
class BlockInstModifierRuntime {
slot { _slot }
entity { Block.get_handle(_block, _slot) }
block_set_slot(value) {
_slot=value
return this
}
construct new(block, slot) {
_block = block
_slot = slot
} //new
block { _block }
} //BlockInstModifierRuntime
return BlockInstModifierRuntime
} //instance_type
block { _block }
count { Block.get_count(_block) }
add() { Block.add(_block) }
append(other_block) { Block.append(_block, other_block) }
each(c, fn) {
for(i in 0 ... c) {
fn.call(0, _inst.block_set_slot(i))
}
} //each
[slot, inst] { _inst.block_set_slot(slot) }
[slot] { _inst_type.new(_block, slot) }
} //BlockModifierRuntime
//`modifiers/trail/trail > data` types
class ModifierData {
construct new() {
_edge_length = 100
_time_based = false
_length = 100
_subdivisions = 20
_material = "luxe: material/solid"
} //new
edge_length { _edge_length }
edge_length=(vvv) { _edge_length = vvv }
time_based { _time_based }
time_based=(vvv) { _time_based = vvv }
length { _length }
length=(vvv) { _length = vvv }
subdivisions { _subdivisions }
subdivisions=(vvv) { _subdivisions = vvv }
material { _material }
material=(vvv) { _material = vvv }
} //ModifierData
//`modifiers/trail/trail > data` compilers
class ModifierDataCompiler {
construct new() {
}
bytes_count(instance) {
var size = 4 //version
size = size + 8 // edge_length
size = size + 4 // time_based
size = size + 8 // length
size = size + 8 // subdivisions
size = size + 4 // material
size = size + 0
return size
} //bytes_count
validate(from_source_id, elements) {
var fields = {
"type": false, //:luxe:internal
"uuid": false, //:luxe:internal
"luxe.self.modifier": false, //:luxe:internal
"edge_length": false,
"time_based": false,
"length": false,
"subdivisions": false,
"material": false,
}
for(element in elements) {
var instance = element.value
for(field in instance) {
if(fields[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`")
} //if not found
} //each field
for(field in fields) {
var required = field.value
if(required && instance[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)")
}
} //each field
} //each element
} //validate
write(compiler, instance, out) {
//version
out.write_int32(0)
var edge_length = instance["edge_length"]
if(edge_length == null) edge_length = 100
out.write_float64(edge_length)
var time_based = instance["time_based"]
if(time_based == null) time_based = false
out.write_int32(time_based ? 1 : 0)
var length = instance["length"]
if(length == null) length = 100
out.write_float64(length)
var subdivisions = instance["subdivisions"]
if(subdivisions == null) subdivisions = 20
out.write_float64(subdivisions)
var material = instance["material"]
if(material == null) material = "luxe: material/solid"
out.write_uint32((material && material != "") ? compiler.string.hash(material) : 0)
return out
} //write
bytes_count_block() {
return 80
} //bytes_count_block
write_block(compiler, out) {
//source id
out.write_uint32(compiler.string.hash("modifiers/trail/trail > data"))
//fields count
out.write_int32(5)
// edge_length
out.write_uint32(compiler.string.hash("edge_length"))
out.write_uint32(467038368) //type number
var edge_length_default = 100
out.write_float64(edge_length_default)
// time_based
out.write_uint32(compiler.string.hash("time_based"))
out.write_uint32(1710517951) //type boolean
var time_based_default = false
out.write_int32(time_based_default ? 1 : 0)
// length
out.write_uint32(compiler.string.hash("length"))
out.write_uint32(467038368) //type number
var length_default = 100
out.write_float64(length_default)
// subdivisions
out.write_uint32(compiler.string.hash("subdivisions"))
out.write_uint32(467038368) //type number
var subdivisions_default = 20
out.write_float64(subdivisions_default)
// material
out.write_uint32(compiler.string.hash("material"))
out.write_uint32(2729592961) //type id32
var material_default = "luxe: material/solid"
out.write_uint32((material_default && material_default != "") ? compiler.string.hash(material_default) : 0)
} //write_block
write(instance) {
var size = bytes_count(instance)
var out = Byter.new(size+8)
out.write_string("LUXEMDTA")
write(instance, out)
return out
} //write
} //ModifierDataCompiler
//`modifiers/trail/trail > data` block types
class BlockModifierData {
field { "trail" }
source { "modifiers/trail/trail > data" }
construct new(block) {
_block = block
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
}
construct new() {
_block = Block.create()
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
Block.add(_block, "edge_length", "number", 100)
Block.add(_block, "time_based", "boolean", false)
Block.add(_block, "length", "number", 100)
Block.add(_block, "subdivisions", "number", 20)
Block.add(_block, "material", "id32", "luxe: material/solid")
Block.set_type(_block, "modifiers/trail/trail > data")
} //new
instance_type {
class BlockInstModifierData {
edge_length { Block.get(_block, "edge_length", _slot) }
edge_length=(v) { Block.set(_block, "edge_length", _slot, v) }
time_based { Block.get(_block, "time_based", _slot) }
time_based=(v) { Block.set(_block, "time_based", _slot, v) }
length { Block.get(_block, "length", _slot) }
length=(v) { Block.set(_block, "length", _slot, v) }
subdivisions { Block.get(_block, "subdivisions", _slot) }
subdivisions=(v) { Block.set(_block, "subdivisions", _slot, v) }
material { Block.get(_block, "material", _slot) }
material=(v) { Block.set(_block, "material", _slot, v) }
slot { _slot }
entity { Block.get_handle(_block, _slot) }
block_set_slot(value) {
_slot=value
return this
}
construct new(block, slot) {
_block = block
_slot = slot
} //new
block { _block }
} //BlockInstModifierData
return BlockInstModifierData
} //instance_type
block { _block }
count { Block.get_count(_block) }
add() { Block.add(_block) }
append(other_block) { Block.append(_block, other_block) }
each(c, fn) {
for(i in 0 ... c) {
fn.call(0, _inst.block_set_slot(i))
}
} //each
[slot, inst] { _inst.block_set_slot(slot) }
[slot] { _inst_type.new(_block, slot) }
} //BlockModifierData
//`modifiers/trail/trail > world` types
class ModifierWorld {
construct new() {
} //new
} //ModifierWorld
//`modifiers/trail/trail > world` compilers
class ModifierWorldCompiler {
construct new() {
}
bytes_count(instance) {
var size = 4 //version
size = size + 0
return size
} //bytes_count
validate(from_source_id, elements) {
var fields = {
"type": false, //:luxe:internal
"uuid": false, //:luxe:internal
"luxe.self.modifier": false, //:luxe:internal
}
for(element in elements) {
var instance = element.value
for(field in instance) {
if(fields[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` has extra field `%(field.key)`")
} //if not found
} //each field
for(field in fields) {
var required = field.value
if(required && instance[field.key] == null) {
Fiber.abort("node `%(element.key)` in `%(from_source_id)` is missing a required field `%(field.key)` (and the field has no default value)")
}
} //each field
} //each element
} //validate
write(compiler, instance, out) {
//version
out.write_int32(0)
return out
} //write
bytes_count_block() {
return 8
} //bytes_count_block
write_block(compiler, out) {
//source id
out.write_uint32(compiler.string.hash("modifiers/trail/trail > world"))
//fields count
out.write_int32(0)
} //write_block
write(instance) {
var size = bytes_count(instance)
var out = Byter.new(size+8)
out.write_string("LUXEMWLD")
write(instance, out)
return out
} //write
} //ModifierWorldCompiler
//`modifiers/trail/trail > world` block types
class BlockModifierWorld {
field { "trail" }
source { "modifiers/trail/trail > world" }
construct new(block) {
_block = block
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
}
construct new() {
_block = Block.create()
_inst_type = instance_type
_inst = _inst_type.new(_block, 0)
Block.set_type(_block, "modifiers/trail/trail > world")
} //new
instance_type {
class BlockInstModifierWorld {
slot { _slot }
entity { Block.get_handle(_block, _slot) }
block_set_slot(value) {
_slot=value
return this
}
construct new(block, slot) {
_block = block
_slot = slot
} //new
block { _block }
} //BlockInstModifierWorld
return BlockInstModifierWorld
} //instance_type
block { _block }
count { Block.get_count(_block) }
add() { Block.add(_block) }
append(other_block) { Block.append(_block, other_block) }
each(c, fn) {
for(i in 0 ... c) {
fn.call(0, _inst.block_set_slot(i))
}
} //each
[slot, inst] { _inst.block_set_slot(slot) }
[slot] { _inst_type.new(_block, slot) }
} //BlockModifierWorld

324
modifiers/trail/trail.wren Normal file
View file

@ -0,0 +1,324 @@
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

74
outline/app.wren Normal file
View file

@ -0,0 +1,74 @@
import "luxe: world" for World, Camera, Entity, Transform
import "luxe: render" for Render
import "luxe: game" for Frame
class App {
world { _world }
ui { _ui_world }
camera { _camera }
ui_camera { _ui_camera }
color { _color }
color=(v) { _color = v }
width { Render.window_w() }
height { Render.window_h() }
scale { Render.drawable_ratio() }
construct new() {
_color = [1,1,1,1]
//create worlds
_world = World.create("game")
_ui_world = World.create("ui")
//create cameras
_camera = Entity.create(_world, "app.camera")
Transform.create(_camera)
Camera.create(_camera)
Camera.set_default(_world, _camera)
_ui_camera = Entity.create(_ui_world, "app.ui_camera")
Transform.create(_ui_camera)
Camera.create(_ui_camera)
Camera.set_default(_ui_world, _ui_camera)
//update our worlds
Frame.on(Frame.sim) {|delta|
World.tick(_world, delta)
World.tick(_ui_world, delta)
}
//render our worlds
Frame.on(Frame.visual) {|delta|
World.render(_world, _camera, "game", {"clear_color":_color})
World.render(_ui_world, _ui_camera, "ui")
}
} //new
destroy() {
//destroy cameras
Camera.destroy(_camera)
Camera.destroy(_ui_camera)
Entity.destroy(_camera)
Entity.destroy(_ui_camera)
//destroy worlds
World.destroy(_ui_world)
World.destroy(_world)
} //destroy
} //

23
outline/inputs.input.lx Normal file
View file

@ -0,0 +1,23 @@
input = {
nodes = [
{ name = "ui" where = "front" channels = ["c01"] }
{ name = "game" where = "after: ui" channels = ["c02"] }
]
map = {
left = { keys = ["key_a", "left"] }
right = { keys = ["key_d", "right"] }
up = { keys = ["key_w", "up"] }
down = { keys = ["key_s", "down"] }
jump = {
keys = ["key_x", "up", "key_w", "space"]
mouse = ["left"]
gamepad = [0]
}
next = {
keys = ["key_x", "up", "key_w", "space", "enter", "escape"]
mouse = ["left", "right"]
}
}
}

51
outline/renderer.wren Normal file
View file

@ -0,0 +1,51 @@
import "luxe: render" for Render, RenderLayerDesc, PassLayerDesc, LoadAction
import "luxe: render" for SortType, ImageDesc, ImageType, PixelFormat
class Renderer {
construct new() {
System.print("game / render / init / ok")
} //new
ready() {
}
tick(delta) {
}
render_path(ctx) {
if(ctx.path == "game") {
game_render_path(ctx)
} else if(ctx.path == "ui") {
ui_render_path(ctx)
}
} //render_path
game_render_path(ctx) {
var layer = RenderLayerDesc.new()
layer.dest.color[0].clear_color = ctx.get("clear_color", [1,1,1,1])
layer.dest.color[0].load_action = LoadAction.clear
layer.dest.depth.load_action = LoadAction.clear
ctx.layer_render("default", layer)
} //game_render_path
ui_render_path(ctx) {
var layer = RenderLayerDesc.new()
layer.dest.color[0].load_action = LoadAction.dont_care
layer.dest.depth.load_action = LoadAction.clear
ctx.layer_render("default", layer)
} //ui_render_path
} //Renderer

View file

@ -0,0 +1,17 @@
engine = {
input.entry = "outline/inputs"
runtime = {
window = {
width = 960
height = 640
resizable = false
fullscreen = false
}
}
render = {
antialiasing = 2
stencil = 8
depth = 24
}
}

14
project.luxe Normal file
View file

@ -0,0 +1,14 @@
import "luxe: project" for Entry
class Project is Entry {
construct entry(target) {
name = "Trail Test"
version = "0.0.0"
renderer = "outline/renderer"
settings = "outline/settings"
} //new
} //Project

3
project.modules.lx Normal file
View file

@ -0,0 +1,3 @@
modules = {
luxe = "dev"
} //modules

57
queue.wren Normal file
View file

@ -0,0 +1,57 @@
class Queue is Sequence{
data{_data}
count{_count}
construct new(){
_data = []
_count = 0
_head = -1
}
clear(){
_count = 0
_head = -1
}
enqueue(value){
_count = _count + 1
_head = _head + 1
if(_data.count >= _count){
if(_head >= _data.count){
_head = _head - _data.count
}
_data[_head] = value
} else {
_data.insert(_head, value)
}
return value
}
dequeue(){
if(_count == 0) return null
var res = peek()
_count = _count - 1
return res
}
peek(){
if(_count == 0) return null
var tail = _head - _count + 1
if(tail < 0) tail = _data.count + tail
return _data[tail]
}
empty(){_count == 0}
iterate(iter){
if(!iter) return _count > 0 ? 0 : false
if(iter >= _count - 1) return false
return iter + 1
}
iteratorValue(iter){
var index = _head - _count + 1 + iter
if(index < 0) index = _data.count + index
return _data[index]
}
}