From 70edf6d86419b8fe600fdf2519a5874d7c5c03a6 Mon Sep 17 00:00:00 2001 From: Ronja Date: Sat, 10 Jul 2021 19:43:40 +0200 Subject: [PATCH] early experimentation, no modifiers yet --- .vscode/tasks.json | 17 - .../snowplayers_skeleton.prototype.lx | 188 +++++++ modifiers/spine_renderer.modifier.lx | 15 + modifiers/spine_renderer.modifier.wren | 473 ++++++++++++++++ modifiers/spine_renderer.wren | 51 ++ modifiers/test_modifier.modifier.lx | 18 + modifiers/test_modifier.modifier.wren | 514 ++++++++++++++++++ modifiers/test_modifier.wren | 51 ++ project.luxe | 28 +- project.modules.lx | 2 +- spine.wren | 40 +- 11 files changed, 1372 insertions(+), 25 deletions(-) delete mode 100644 .vscode/tasks.json create mode 100644 assets/down_the_mountain/snowplayers_data/snowplayers_skeleton.prototype.lx create mode 100644 modifiers/spine_renderer.modifier.lx create mode 100644 modifiers/spine_renderer.modifier.wren create mode 100644 modifiers/spine_renderer.wren create mode 100644 modifiers/test_modifier.modifier.lx create mode 100644 modifiers/test_modifier.modifier.wren create mode 100644 modifiers/test_modifier.wren diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 4f2c46b..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "tasks": [ - { - "type": "luxe", - "script": "run", - "problemMatcher": [ - "$luxe-absolute", - "$luxe-relative" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "label": "luxe: run - Build & Run the project" - } - ] -} \ No newline at end of file diff --git a/assets/down_the_mountain/snowplayers_data/snowplayers_skeleton.prototype.lx b/assets/down_the_mountain/snowplayers_data/snowplayers_skeleton.prototype.lx new file mode 100644 index 0000000..1f58ae1 --- /dev/null +++ b/assets/down_the_mountain/snowplayers_data/snowplayers_skeleton.prototype.lx @@ -0,0 +1,188 @@ +prototype = { + elements = { + bone4 = { + modifiers = { + transform = { + pos = [79.12 -28.1 0] //pos + link = "f715d4cc-48e0-4296-8307-bacbf2cac978" + type = "luxe: modifier/transform" + rotation = [0 0 33.19] //rotation + } //transform + } //modifiers + uuid = "c69a08b1-a28b-4761-956b-636d298bffc6" + } //bone4 + ekorn = { + modifiers = { + transform = { + pos = [-44.72 35.68 0] //pos + link = "45852121-f880-44de-8490-b8dad645a7b0" + type = "luxe: modifier/transform" + rotation = [0 0 73.74] //rotation + } //transform + } //modifiers + uuid = "91621243-27fb-437b-b200-13e3746af7f3" + } //ekorn + root = { + modifiers = { + transform = { + type = "luxe: modifier/transform" + } //transform + } //modifiers + uuid = "45852121-f880-44de-8490-b8dad645a7b0" + } //root + bone2 = { + modifiers = { + transform = { + pos = [80.92 -0.23 0] //pos + link = "91621243-27fb-437b-b200-13e3746af7f3" + type = "luxe: modifier/transform" + rotation = [0 0 25.16] //rotation + } //transform + } //modifiers + uuid = "f715d4cc-48e0-4296-8307-bacbf2cac978" + } //bone2 + bone7 = { + modifiers = { + transform = { + pos = [45.52 0 0] //pos + link = "c51c3eb5-0406-4431-8bfb-6eeffb528e70" + type = "luxe: modifier/transform" + rotation = [0 0 -10.57] //rotation + } //transform + } //modifiers + uuid = "bad44ae5-9512-48fe-ae74-3dcf23478347" + } //bone7 + bone14 = { + modifiers = { + transform = { + pos = [63.28 1.15 0] //pos + link = "8605bf9f-4a59-409c-8eb4-d0b74959151f" + type = "luxe: modifier/transform" + rotation = [0 0 23.82] //rotation + } //transform + } //modifiers + uuid = "f85ae39a-98a3-4c53-bd4c-269888f87b8b" + } //bone14 + bone13 = { + modifiers = { + transform = { + pos = [88.99 3.78 0] //pos + link = "9adfb00a-555e-4582-ba8e-1a0e234af982" + type = "luxe: modifier/transform" + rotation = [0 0 39.58] //rotation + } //transform + } //modifiers + uuid = "8605bf9f-4a59-409c-8eb4-d0b74959151f" + } //bone13 + bone5 = { + modifiers = { + transform = { + pos = [113.11 84.9 0] //pos + link = "91621243-27fb-437b-b200-13e3746af7f3" + type = "luxe: modifier/transform" + rotation = [0 0 75.02] //rotation + } //transform + } //modifiers + uuid = "f50404e9-8c32-4dac-a2d3-95fb2edbeac9" + } //bone5 + pinnsvin = { + modifiers = { + transform = { + pos = [23.09 38.13 0] //pos + link = "45852121-f880-44de-8490-b8dad645a7b0" + type = "luxe: modifier/transform" + rotation = [0 0 68.96] //rotation + } //transform + } //modifiers + uuid = "c51c3eb5-0406-4431-8bfb-6eeffb528e70" + } //pinnsvin + bone11 = { + modifiers = { + transform = { + pos = [73.6 32.01 0] //pos + link = "9adfb00a-555e-4582-ba8e-1a0e234af982" + type = "luxe: modifier/transform" + rotation = [0 0 48.43] //rotation + } //transform + } //modifiers + uuid = "7113588f-f121-496a-8da2-b765c867685f" + } //bone11 + ekorn2 = { + modifiers = { + transform = { + pos = [-79.85 57.74 0] //pos + link = "45852121-f880-44de-8490-b8dad645a7b0" + type = "luxe: modifier/transform" + rotation = [0 0 90] //rotation + } //transform + } //modifiers + uuid = "f0d5d66c-9477-44f3-b4f2-abf87703fcd2" + } //ekorn2 + bone3 = { + modifiers = { + transform = { + pos = [62.87 26.54 0] //pos + link = "f715d4cc-48e0-4296-8307-bacbf2cac978" + type = "luxe: modifier/transform" + rotation = [0 0 49.88] //rotation + } //transform + } //modifiers + uuid = "cae3d09e-9117-4e1c-98dd-624e204300df" + } //bone3 + bone8 = { + modifiers = { + transform = { + pos = [34.49 -19.12 0] //pos + link = "c51c3eb5-0406-4431-8bfb-6eeffb528e70" + type = "luxe: modifier/transform" + rotation = [0 0 -101.82] //rotation + } //transform + } //modifiers + uuid = "9477662d-bbb8-44a4-ba0c-de84ddef8544" + } //bone8 + bone12 = { + modifiers = { + transform = { + pos = [62.44 0.08 0] //pos + link = "7113588f-f121-496a-8da2-b765c867685f" + type = "luxe: modifier/transform" + rotation = [0 0 22.8] //rotation + } //transform + } //modifiers + uuid = "da3f7d83-b150-451d-9b63-1c9291b27941" + } //bone12 + bone15 = { + modifiers = { + transform = { + pos = [148.91 92.05 0] //pos + link = "45852121-f880-44de-8490-b8dad645a7b0" + type = "luxe: modifier/transform" + rotation = [0 0 -43.36] //rotation + } //transform + } //modifiers + uuid = "3aa06ed0-f0cc-4ab9-b19a-2f9bcdfe1b0a" + } //bone15 + bone10 = { + modifiers = { + transform = { + pos = [72.36 -0.35 0] //pos + link = "9bb58df9-660a-4ee4-afb1-a237b29ea342" + type = "luxe: modifier/transform" + rotation = [0 0 23.75] //rotation + } //transform + } //modifiers + uuid = "9adfb00a-555e-4582-ba8e-1a0e234af982" + } //bone10 + bunny = { + modifiers = { + transform = { + pos = [106.42 38.95 0] //pos + link = "45852121-f880-44de-8490-b8dad645a7b0" + type = "luxe: modifier/transform" + rotation = [0 0 64.87] //rotation + } //transform + } //modifiers + uuid = "9bb58df9-660a-4ee4-afb1-a237b29ea342" + } //bunny + } //elements +} //prototype diff --git a/modifiers/spine_renderer.modifier.lx b/modifiers/spine_renderer.modifier.lx new file mode 100644 index 0000000..5a137ab --- /dev/null +++ b/modifiers/spine_renderer.modifier.lx @@ -0,0 +1,15 @@ +modifier = { + description = "Renders Spine asets" + field = "spine_renderer" + display = "Spine Renderer" + class = "SpineRenderer" + dependency = [] + + blocks = { + data = { + fields = [ + { name="asset" type="string" default="" } + ] + } + } +} \ No newline at end of file diff --git a/modifiers/spine_renderer.modifier.wren b/modifiers/spine_renderer.modifier.wren new file mode 100644 index 0000000..6440653 --- /dev/null +++ b/modifiers/spine_renderer.modifier.wren @@ -0,0 +1,473 @@ + +//-- 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/spine_renderer > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/spine_renderer > 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/spine_renderer > 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/spine_renderer > runtime` block types + + class BlockModifierRuntime { + + field { "spine_renderer" } + source { "modifiers/spine_renderer > 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/spine_renderer > 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/spine_renderer > data` types + + class ModifierData { + + construct new() { + _asset = "" + } //new + + asset { _asset } + asset=(vvv) { _asset = vvv } + + } //ModifierData + +//`modifiers/spine_renderer > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 4 //asset length + var asset = instance["asset"] + if(asset == null) asset = "" + var asset_len = asset.bytes.count + var asset_size = asset_len + Bytes.padding(asset_len) + size = size + asset_size + + 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 + "asset": 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 asset = instance["asset"] + if(asset == null) asset = "" + out.write_int32(asset.bytes.count) + out.write_string_aligned4(asset) + + + return out + + } //write + + bytes_count_block() { + + return 16 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/spine_renderer > data")) + + //fields count + out.write_int32(1) + + // asset + out.write_uint32(compiler.string.hash("asset")) + out.write_uint32(398550328) //type string + var asset_default = "" + out.write_int32(asset_default.bytes.count) + out.write_string_aligned4(asset_default) + + + } //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/spine_renderer > data` block types + + class BlockModifierData { + + field { "spine_renderer" } + source { "modifiers/spine_renderer > 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, "asset", "string", "") + Block.set_type(_block, "modifiers/spine_renderer > data") + } //new + + instance_type { + + class BlockInstModifierData { + asset { Block.get(_block, "asset", _slot) } + asset=(v) { Block.set(_block, "asset", _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/spine_renderer > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/spine_renderer > 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/spine_renderer > 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/spine_renderer > world` block types + + class BlockModifierWorld { + + field { "spine_renderer" } + source { "modifiers/spine_renderer > 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/spine_renderer > 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 + diff --git a/modifiers/spine_renderer.wren b/modifiers/spine_renderer.wren new file mode 100644 index 0000000..4dfc6ce --- /dev/null +++ b/modifiers/spine_renderer.wren @@ -0,0 +1,51 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem + +//User facing API +//This is what the user of your modifier will interact with +class SpineRenderer { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + +} //SpineRenderer + +//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 SpineRendererSystem is ModifierSystem { + + construct new() { + //called when your system is first created. + } + + init(world) { + _world = world + //called when your modifier is created in a world + } + + destroy() { + //called when your modifier is removed from a world + } + + attach(entity, data) { + //called when attached to an entity + } + + detach(entity, data) { + //called when detached from an entity, like on destroy + } + + tick(delta) { + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + each {|entity, data| + //use data.* + } + } //tick + +} //SpineRendererSystem + +var Modifier = SpineRendererSystem //required diff --git a/modifiers/test_modifier.modifier.lx b/modifiers/test_modifier.modifier.lx new file mode 100644 index 0000000..407890d --- /dev/null +++ b/modifiers/test_modifier.modifier.lx @@ -0,0 +1,18 @@ +modifier = { + description = "A slot on the playing field" + field = "slot" + display = "Slot" + class = "Slot" + dependency = [] + + blocks = { + data = { + fields = [ + { name="coord" type="float3" default=[0, 0, 0] } + { name="auto_naming" type="boolean" default=false } + { name="field" type="id32" editor="entity" default="" } + ] + } + } +} + diff --git a/modifiers/test_modifier.modifier.wren b/modifiers/test_modifier.modifier.wren new file mode 100644 index 0000000..caaec1d --- /dev/null +++ b/modifiers/test_modifier.modifier.wren @@ -0,0 +1,514 @@ + +//-- 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/test_modifier > runtime` types + + class ModifierRuntime { + + construct new() { + } //new + + } //ModifierRuntime + +//`modifiers/test_modifier > 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/test_modifier > 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/test_modifier > runtime` block types + + class BlockModifierRuntime { + + field { "slot" } + source { "modifiers/test_modifier > 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/test_modifier > 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/test_modifier > data` types + + class ModifierData { + + construct new() { + _coord = [0, 0, 0] + _auto_naming = false + _field = "" + } //new + + coord { _coord } + coord=(vvv) { _coord = vvv } + + auto_naming { _auto_naming } + auto_naming=(vvv) { _auto_naming = vvv } + + field { _field } + field=(vvv) { _field = vvv } + + } //ModifierData + +//`modifiers/test_modifier > data` compilers + + class ModifierDataCompiler { + + construct new() { + } + + bytes_count(instance) { + + var size = 4 //version + + size = size + 12 // coord + + size = size + 4 // auto_naming + + size = size + 4 // field + + 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 + "coord": false, + "auto_naming": false, + "field": 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 coord = instance["coord"] + if(coord == null) coord = [0, 0, 0] + out.write_float32(coord[0]) + out.write_float32(coord[1]) + out.write_float32(coord[2]) + + + var auto_naming = instance["auto_naming"] + if(auto_naming == null) auto_naming = false + out.write_int32(auto_naming ? 1 : 0) + + + var field = instance["field"] + if(field == null) field = "" + out.write_uint32((field && field != "") ? compiler.string.hash(field) : 0) + + + return out + + } //write + + bytes_count_block() { + + return 52 + + } //bytes_count_block + + write_block(compiler, out) { + + //source id + out.write_uint32(compiler.string.hash("modifiers/test_modifier > data")) + + //fields count + out.write_int32(3) + + // coord + out.write_uint32(compiler.string.hash("coord")) + out.write_uint32(1025475970) //type float3 + var coord_default = [0, 0, 0] + out.write_float32(coord_default[0]) + out.write_float32(coord_default[1]) + out.write_float32(coord_default[2]) + + + // auto_naming + out.write_uint32(compiler.string.hash("auto_naming")) + out.write_uint32(1710517951) //type boolean + var auto_naming_default = false + out.write_int32(auto_naming_default ? 1 : 0) + + + // field + out.write_uint32(compiler.string.hash("field")) + out.write_uint32(2729592961) //type id32 + var field_default = "" + out.write_uint32((field_default && field_default != "") ? compiler.string.hash(field_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/test_modifier > data` block types + + class BlockModifierData { + + field { "slot" } + source { "modifiers/test_modifier > 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, "coord", "float3", [0, 0, 0]) + Block.add(_block, "auto_naming", "boolean", false) + Block.add(_block, "field", "id32", "") + Block.set_type(_block, "modifiers/test_modifier > data") + } //new + + instance_type { + + class BlockInstModifierData { + coord { Block.get(_block, "coord", _slot) } + coord=(v) { Block.set(_block, "coord", _slot, v) } + auto_naming { Block.get(_block, "auto_naming", _slot) } + auto_naming=(v) { Block.set(_block, "auto_naming", _slot, v) } + field { Block.get(_block, "field", _slot) } + field=(v) { Block.set(_block, "field", _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/test_modifier > world` types + + class ModifierWorld { + + construct new() { + } //new + + } //ModifierWorld + +//`modifiers/test_modifier > 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/test_modifier > 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/test_modifier > world` block types + + class BlockModifierWorld { + + field { "slot" } + source { "modifiers/test_modifier > 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/test_modifier > 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 + diff --git a/modifiers/test_modifier.wren b/modifiers/test_modifier.wren new file mode 100644 index 0000000..737df96 --- /dev/null +++ b/modifiers/test_modifier.wren @@ -0,0 +1,51 @@ +import "luxe: io" for IO +import "luxe: world" for World, Entity, Modifiers, ModifierSystem + +//User facing API +//This is what the user of your modifier will interact with +class Slot { + + static create(entity) { Modifiers.create(This, entity) } + static destroy(entity) { Modifiers.destroy(This, entity) } + static has(entity) { Modifiers.has(This, entity) } + +} //Slot + +//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 SlotSystem is ModifierSystem { + + construct new() { + //called when your system is first created. + } + + init(world) { + _world = world + //called when your modifier is created in a world + } + + destroy() { + //called when your modifier is removed from a world + } + + attach(entity, data) { + //called when attached to an entity + } + + detach(entity, data) { + //called when detached from an entity, like on destroy + } + + tick(delta) { + //called usually once every frame. + //called when the world that this modifier lives in, is ticked + each {|entity, data| + //use data.* + } + } //tick + +} //SlotSystem + +var Modifier = SlotSystem //required diff --git a/project.luxe b/project.luxe index 8105e5d..b54f261 100644 --- a/project.luxe +++ b/project.luxe @@ -1,14 +1,34 @@ -import "luxe: project" for Entry +import "luxe: project" for Entry, Parcels, ProjectPaths +import "luxe: io" for IO +import "luxe: regex" for Regex +import "luxe: lx" for LX class Project is Entry { construct entry(target) { - - name = "game" + name = "spine module" version = "0.0.0" renderer = "outline/renderer" settings = "outline/settings" - } //new + entry() { + import "spine" for Spine + + //todo: only update files with changes (check file timestamp) + var spine_files = IO.list_recursive(".", [], [ProjectPaths.dev], [".","..",ProjectPaths.dev, ProjectPaths.deploy]) + .where{|file| file.path.endsWith(".spine.lx") } + var directory_regex = Regex.new("^[\\w\\s./]*[\\|/]", Regex.gim) + var name_regex = Regex.new("[^\\|/]*$", Regex.gim) + for(file in spine_files){ + var base_file_path = file.path[0..-10] + var name = name_regex.exec(base_file_path)[0].string + var directory = directory_regex.exec(base_file_path)[0].string[0..-1] + var data_directory = "%(directory)/%(name)_data" + IO.make_directory(data_directory) + var spine = Spine.parse(base_file_path) + LX.stringify_to_file({"prototype":spine.prototype_skeleton()}, "%(data_directory)/%(name)_skeleton.prototype.lx") + } + } //entry + } //Project \ No newline at end of file diff --git a/project.modules.lx b/project.modules.lx index 0858dd2..baece25 100644 --- a/project.modules.lx +++ b/project.modules.lx @@ -1,3 +1,3 @@ modules = { - luxe = "2021.0.3" + luxe = "2021.0.4" } //modules diff --git a/spine.wren b/spine.wren index ea0aea8..302d8ce 100644 --- a/spine.wren +++ b/spine.wren @@ -4,6 +4,8 @@ import "luxe: string" for Str import "luxe: render" for Geometry import "luxe: draw" for Draw, PathStyle, LineJoin, LineCap import "luxe: math" for Math +import "luxe: lx" for LX +import "luxe: id" for ID class Spine{ @@ -11,9 +13,9 @@ class Spine{ bones_by_name{_bones_by_name} static parse(id: String) : Spine{ - var asset = Assets.lx(id + ".spine.lx")["spine"] - var skeleton = Assets.lx(asset["skeleton"]+".json") - var atlas = Assets.bytes(asset["atlas"]+".atlas") + var asset = LX.read(id + ".spine.lx")["spine"] + var skeleton = LX.read(asset["skeleton"]+".json") + var atlas = LX.read(asset["atlas"]+".atlas") var spine_asset = Spine.from_data(skeleton) return spine_asset @@ -45,6 +47,23 @@ class Spine{ _active_animation = "" //todo: tie this into Anim system } + prototype_skeleton():Map{ + var elements = {} + + for(bone in _bones_by_index){ + var transform = {"type": "luxe: modifier/transform"} + if(!Util.approximately_vec(bone.position, [0, 0])) transform["pos"] = [bone.position.x, bone.position.y, 0] + if(!Util.approximately_num(bone.rotation, 0)) transform["rotation"] = [0, 0, bone.rotation] + if(!Util.approximately_vec(bone.scale, [1, 1])) transform["scale"] = [bone.scale.x, bone.scale.y, 1] + if(bone.parent != null) transform["link"] = bone.parent.uuid + var modifiers = {"transform": transform} + var entity = {"modifiers": modifiers, "uuid": bone.uuid} + elements[bone.name] = entity + } + + return {"elements":elements} + } + load_skeleton(skeleton_data: Map){ _pos = [skeleton_data["x"], skeleton_data["y"]] _size = [skeleton_data["width"], skeleton_data["height"]] @@ -108,6 +127,20 @@ class Spine{ } } +class Util{ + static approximately_vec(vec1:List, vec2:List):Boolean{ + if(vec1.count != vec2.count) return false + for(i in 0...vec1.count){ + if(!approximately_num(vec1[i], vec2[i])) return false + } + return true + } + + static approximately_num(value1:Num, value2:Num):Boolean{ + return (value1 - value2).abs < 0.00001 + } +} + class SpineSkin{ name{_name} @@ -269,6 +302,7 @@ class SpineBone{ scale{_scale} parent{_parent} length{_length} + uuid{_uuid || (_uuid = ID.uuid())} //assign on first access //todo: get good information out of bones