Compare commits

..

No commits in common. "master" and "v2_incenter" have entirely different histories.

395 changed files with 100689 additions and 941 deletions

8
.gitignore vendored
View File

@ -9,11 +9,7 @@ working_data/
nssm_log.log
sysroot/
*.DS_Store
*.vscode
*.vscode/*
*.dSYM
run_tree/data/live_data
run_tree/osx/*
run_tree/win32/*
run_tree/wasm/*
run_tree/webgl/*
run_tree/raspi/*
build_local.sh

35
.vscode/launch.json vendored
View File

@ -1,35 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "C++ Launch",
"type": "cppdbg",
"request": "launch",
"windows": {
"program": "${workspaceRoot}/run_tree/win32/intel/debug/lumenarium",
},
"osx": {
"program": "${workspaceRoot}/run_tree/osx/arm64/debug/lumenarium",
"MIMode": "lldb"
},
"linux": {
"program": "${workspaceRoot}/run_tree/raspi/intel/debug/lumenarium",
},
"internalConsoleOptions": "openOnSessionStart",
"logging": {
"moduleLoad": false,
"programOutput": true,
"trace": false
},
"showDisplayString": false,
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/run_tree",
"environment": [],
"externalConsole": false, // set true to enable keyboard input
}
]
}

48
.vscode/settings.json vendored
View File

@ -1,48 +0,0 @@
{
"files.associations": {
"lumenarium_osx_file.h": "c",
"__bit_reference": "cpp",
"__functional_base": "cpp",
"__node_handle": "cpp",
"algorithm": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"__memory": "cpp",
"functional": "cpp",
"iterator": "cpp",
"limits": "cpp",
"optional": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"memory": "cpp",
"dyld.h": "c",
"lumenarium_first.h": "c",
"__locale": "c",
"lumenarium_editor_opengl.h": "c",
"complex": "c",
"locale": "c",
"string": "c",
"lumenarium_editor_sculpture_visualizer_shaders.h": "c",
"lumenarium_shared_file_async_work_on_job.h": "c",
"lumenarium_engine_assembly.h": "c",
"lumenarium_engine_output.h": "c",
"ios": "cpp",
"lumenarium_os.h": "c",
"__hash_table": "c",
"__split_buffer": "c",
"array": "c",
"initializer_list": "c",
"string_view": "c",
"unordered_map": "c",
"typeinfo": "c",
"cmath": "c",
"lumenarium_editor_geometry.h": "c",
"question_3.h": "c",
"question_14.h": "c",
"incenter_user_space.h": "c"
},
"C_Cpp.errorSquiggles": "Disabled"
}

44
.vscode/tasks.json vendored
View File

@ -1,44 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"windows": {
"command": "git-bash ./build/build.sh",
"args": ["debug", "win32", "intel" ],
},
"osx": {
"command": "./build/build.sh",
"args": ["debug", "osx", "arm64", ],
//"args": ["debug", "osx", "intel", ],
},
"linux": {
"command": "./build/build.sh",
"args": ["debug", "raspi", "intel" ],
},
"presentation": {
"echo": true,
"reveal": "always",
"panel": "shared"
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceRoot}"
],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
]
}

View File

@ -1,32 +1,34 @@
# Lumenarium by Foldhaus
![Lumenarium Banner](./docs/images/splash_new.png)
![Lumenarium Banner](./docs/images/splash.png)
## Build Lumenarium
Build Dependencies:
- clang
- bash
- Note for Windows Users: You can still run bash scripts using git-bash (my recommendation) or WSL
Building Lumenarium requires having MSVC installed (sorry, Windows only for now!).
1. clone the repo onto your computer
2. Run the appropriate build batch file
- for Windows: use `build\build_app_msvc_win32_debug.bat`
- other platforms coming soon
3. Build scripts will output executables into the app_run_tree directory, by platform
To build Lumenarium:
1. Clone the repo onto your computer
2. Run `build\build.sh` with the appropriate platform, architecture, and release mode flags
- Example: `build\build.sh debug osx arm64`
- You can see the full list of supported flags by running `build\build.sh` with no arguments
3. Build scripts will output executables into the run_tree directory.
- The above example will output the following executable: `run_tree\osx\arm64\debug\lumenarium`
## Run Lumenarium
Windows - Debug
1. Run `app_run_tree\win32_msvc\debug\win32_foldhaus.exe`
This repository features a .vscode directory which has been set up with a build task and launch.json to work out of the box.
- *Note: I have not been able to test the configuration on Windows or Linux. Feel free to open a PR if you find something is wrong with the vscode setup*
If you want to run in headless mode:
1. Run `app_run_tree\win32_msvc\debug\win32_foldhaus.exe -headless`
## Debug Lumenarium
### Windows
Building in debug mode outputs pdb file info that can be read by Visual Studio or RemedyBG (preferred debugging solution, but ymmv). You can just open the exe in either application and it'll find the pdb file in the same directory
## What Is Lumenarium?
Lumenarium is our custom build light and motion control software. It allows us to design light and motion patterns for our sculptures, visualize the output long before the sculpture is built, and iterate in real time to achieve the best visual results quickly.
Lumenarium has been used in several sculptures in museums, permanent installations, and at Burning Man. Lumenarium was developed in collaboration with [Foldhaus](https://www.foldhaus.com). The current iteration of Lumenarium was developed while working on Incenter for Burning Man '22.
## Features
*NOTE: These were features from an earlier version of Lumenarium and are still being ported over to the v2 codebase*
[Foldhaus can be found here.](https://www.foldhaus.com)
![Image of Lumenarium](./docs/images/hero-0.PNG)
## Features
The following features are under active development for integration in Lumenarium
* [Sculpture File Format](#sculpture-file-format)
* [DMX Output](#dmx-output)
@ -43,7 +45,7 @@ Documentation coming soon.
***
### DMX Output
Lumenarium supports sACN output, and ArtNet is in development, via a DMX system which underlies them both.
Lumenarium supports SACN output, and ArtNet is in development, via a DMX system which underlies them both.
***
### Live Visualization

28
admin.txt Normal file
View File

@ -0,0 +1,28 @@
# Project Admin Stuff
## Priorities
1. Upgrade Lumenarium's plumbing
2. Begin work on Incenter
## TODO
1. Upgrade Lumenarium's plumbing
x. switch over to compiling with clang & bash based build scripts
x. better platform layer separation
3. osx and webgl layers, possibly linux?
x. remove dll compiling, just build all in one go
5. improve ui
[ ] get widgets and widget ids working
- see a trick of fate
[ ] clip widgets to regions
[ ] text rendering
[ ] interaction
[ ] layout manager
- do layout the way youre doing styling - optional pointer to a struct
and fallback on some global default
2. Incenter
1. Sculpture generation from list of lat-long coordinates
2.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,56 @@
lumenarium_animation_file;
animation_name: "digital_fire";
layers_count: 3;
blocks_count: 4;
playable_range:{
min: 0;
max: 10000;
};
layers:{
layer:{
name: "mask1";
blend: "Add";
};
layer:{
name: "mask2";
blend: "Add";
};
layer:{
name: "color";
blend: "Multiply";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 19;
};
layer_index: 0;
animation_name: "Pattern_BulbMask";
};
block:{
frame_range:{
min: 0;
max: 10000;
};
layer_index: 1;
animation_name: "Pattern_Leafy";
};
block:{
frame_range:{
min: 0;
max: 5156;
};
layer_index: 2;
animation_name: "Pattern_Rainbow";
};
block:{
frame_range:{
min: 5040;
max: 10000;
};
layer_index: 2;
animation_name: "Pattern_Wavy";
};
};

View File

@ -0,0 +1,48 @@
lumenarium_animation_file;
animation_name: "fishy_0";
layers_count: 3;
blocks_count: 3;
playable_range:{
min: 0;
max: 3600;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "Color";
blend: "Multiply";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 2;
animation_name: "Pattern_HueShift";
};
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 1;
animation_name: "Pattern_StemSolid";
};
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 0;
animation_name: "Pattern_VerticalLines";
};
};

View File

@ -0,0 +1,36 @@
lumenarium_animation_file;
animation_name: "patchy_loading_bar_0";
layers_count: 2;
blocks_count: 2;
playable_range:{
min: 0;
max: 3350;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Multiply";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 1;
animation_name: "Pattern_Patchy";
};
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 0;
animation_name: "Pattern_GrowFadeMask";
};
};

View File

@ -0,0 +1,28 @@
lumenarium_animation_file;
animation_name: "primary_hue_0";
layers_count: 2;
blocks_count: 1;
playable_range:{
min: 0;
max: 360;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Add";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 36000;
};
layer_index: 1;
animation_name: "Pattern_PrimaryHue";
};
};

View File

@ -0,0 +1,32 @@
lumenarium_animation_file;
animation_name: "rainbow";
layers_count: 3;
blocks_count: 1;
playable_range:{
min: 0;
max: 36000;
};
layers:{
layer:{
name: "Mask";
blend: "Add";
};
layer:{
name: "Color";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Add";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 36000;
};
layer_index: 1;
animation_name: "Pattern_Rainbow";
};
};

View File

@ -0,0 +1,28 @@
lumenarium_animation_file;
animation_name: "rainbow_loading_bar_0";
layers_count: 2;
blocks_count: 1;
playable_range:{
min: 0;
max: 9000;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Add";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 9000;
};
layer_index: 1;
animation_name: "Pattern_RainbowLoadingBar";
};
};

View File

@ -0,0 +1,36 @@
lumenarium_animation_file;
animation_name: "wavy_0";
layers_count: 2;
blocks_count: 2;
playable_range:{
min: 0;
max: 7200;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Overwrite";
};
layer:{
name: "Color";
blend: "Multiply";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 7200;
};
layer_index: 1;
animation_name: "Pattern_Wavy";
};
block:{
frame_range:{
min: 78;
max: 3571;
};
layer_index: 0;
animation_name: "Pattern_Leafy";
};
};

View File

@ -0,0 +1,36 @@
lumenarium_animation_file;
animation_name: "voice_anim";
layers_count: 2;
blocks_count: 2;
playable_range:{
min: 0;
max: 3600;
};
layers:{
layer:{
name: "Base";
blend: "Add";
};
layer:{
name: "Add In";
blend: "Overwrite";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 0;
animation_name: "Pattern_VoicePattern";
};
block:{
frame_range:{
min: 0;
max: 3600;
};
layer_index: 1;
animation_name: "Pattern_VoiceAddIns";
};
};

View File

@ -0,0 +1,88 @@
lumenarium_animation_file;
animation_name: "awaken";
layers_count: 3;
blocks_count: 8;
playable_range:{
min: 0;
max: 7200;
};
layers:{
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Add";
};
layer:{
name: "[New Layer]";
blend: "Multiply";
};
};
blocks:{
block:{
frame_range:{
min: 0;
max: 1363;
};
layer_index: 0;
animation_name: "Pattern_Leafy";
};
block:{
frame_range:{
min: 1169;
max: 7200;
};
layer_index: 0;
animation_name: "Pattern_BulbMask";
};
block:{
frame_range:{
min: 5525;
max: 7200;
};
layer_index: 2;
animation_name: "Pattern_Wavy";
};
block:{
frame_range:{
min: 2135;
max: 2555;
};
layer_index: 1;
animation_name: "Pattern_None";
};
block:{
frame_range:{
min: 2470;
max: 7200;
};
layer_index: 1;
animation_name: "Pattern_StemSolid";
};
block:{
frame_range:{
min: 0;
max: 1917;
};
layer_index: 2;
animation_name: "Pattern_Blue";
};
block:{
frame_range:{
min: 1823;
max: 3803;
};
layer_index: 2;
animation_name: "Pattern_RainbowLoadingBar";
};
block:{
frame_range:{
min: 3670;
max: 5720;
};
layer_index: 2;
animation_name: "Pattern_Rainbow";
};
};

View File

@ -0,0 +1,12 @@
lumenarium_animation_file;
animation_name: "off_anim";
layers_count: 0;
blocks_count: 0;
playable_range:{
min: 0;
max: 2;
};
layers:{
};
blocks:{
};

View File

@ -0,0 +1,15 @@
led_strip_count 12
led_strip { 0, 2, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.000000, 0.050000, 1.000000), 346 }
led_strip { 0, 4, 0, INTERPOLATE_POINTS, (0.500000, 0.866025, 0.000000), (0.025000, 0.043301, 1.000000), 346 }
led_strip { 0, 6, 0, INTERPOLATE_POINTS, (0.866025, 0.499999, 0.000000), (0.043301, 0.024999, 1.000000), 346 }
led_strip { 0, 8, 0, INTERPOLATE_POINTS, (1.000000, -0.000000, 0.000000), (0.050000, -0.000000, 1.000000), 346 }
led_strip { 0, 10, 0, INTERPOLATE_POINTS, (0.866025, -0.500000, 0.000000), (0.043301, -0.025000, 1.000000), 346 }
led_strip { 0, 12, 0, INTERPOLATE_POINTS, (0.500000, -0.866025, 0.000000), (0.025000, -0.043301, 1.000000), 346 }
led_strip { 0, 14, 0, INTERPOLATE_POINTS, (-0.000000, -1.000000, 0.000000), (-0.000000, -0.050000, 1.000000), 346 }
led_strip { 0, 7, 0, INTERPOLATE_POINTS, (-0.500000, -0.866025, 0.000000), (-0.025000, -0.043301, 1.000000), 346 }
led_strip { 0, 8, 0, INTERPOLATE_POINTS, (-0.866025, -0.499999, 0.000000), (-0.043301, -0.024999, 1.000000), 346 }
led_strip { 0, 9, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.050000, 0.000000, 1.000000), 346 }
led_strip { 0, 10, 0, INTERPOLATE_POINTS, (-0.866025, 0.499999, 0.000000), (-0.043301, 0.024999, 1.000000), 346 }
led_strip { 0, 11, 0, INTERPOLATE_POINTS, (-0.499999, 0.866025, 0.000000), (-0.024999, 0.043301, 1.000000), 346 }
END_OF_ASSEMBLY_FILE

View File

@ -0,0 +1,21 @@
// NOTE(Peter): stuff this in a function and itll print out the code needed to generate a blumen
// TODO(Peter): Modify this when you get actual blumen measurements
MakeStringBuffer(Buffer, 256);
v3 InnerVectors[12];
v3 OuterVectors[12];
for (s32 i = 0; i < 12; i++)
{
r32 Theta = ((r32)i / 12.0f) * 2 * PI;
v3 Direction = v3{GSSin(Theta), GSCos(Theta), 0};
InnerVectors[i] = Direction;
OuterVectors[i] = v3{Direction.x * 0.05f, Direction.y * 0.05f, 1};
PrintF(&Buffer, "led_strip { 0, %d, 0, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 70 }\n",
i,
InnerVectors[i].x, InnerVectors[i].y, InnerVectors[i].z,
OuterVectors[i].x, OuterVectors[i].y, OuterVectors[i].z);
NullTerminate(&Buffer);
OutputDebugStringA(Buffer.Memory);
}

View File

@ -0,0 +1,5 @@
Peter : 10000
Andrew : 2500
Kim : 2000
Felicia : 1000
Skye : 200

BIN
app_run_tree/data/main.exe Normal file

Binary file not shown.

View File

@ -0,0 +1,338 @@
{
neighbors: [16, 14, 12, 13, 15];
ip: 192.168.1.200;
x: 0;
y: 0.525731086730957;
z: 0.8506507873535156;
id: 0;
};
{
neighbors: [20, 17, 12, 18, 19];
ip: 192.168.1.201;
x: 0;
y: -0.525731086730957;
z: 0.8506507873535156;
id: 1;
};
{
neighbors: [24, 22, 21, 23, 25];
ip: 192.168.1.202;
x: 0;
y: -0.525731086730957;
z: -0.8506507873535156;
id: 2;
};
{
neighbors: [28, 27, 21, 26, 29];
ip: 192.168.1.203;
x: 0;
y: 0.525731086730957;
z: -0.8506507873535156;
id: 3;
};
{
neighbors: [31, 13, 17, 32, 30];
ip: 192.168.1.204;
x: 0.8506507873535156;
y: 0;
z: 0.525731086730957;
id: 4;
};
{
neighbors: [14, 34, 33, 35, 18];
ip: 192.168.1.205;
x: -0.8506507873535156;
y: 0;
z: 0.525731086730957;
id: 5;
};
{
neighbors: [36, 26, 22, 37, 33];
ip: 192.168.1.206;
x: -0.8506507873535156;
y: 0;
z: -0.525731086730957;
id: 6;
};
{
neighbors: [30, 39, 23, 27, 38];
ip: 192.168.1.207;
x: 0.8506507873535156;
y: 0;
z: -0.525731086730957;
id: 7;
};
{
neighbors: [38, 28, 40, 15, 31];
ip: 192.168.1.208;
x: 0.525731086730957;
y: 0.8506507873535156;
z: 0;
id: 8;
};
{
neighbors: [36, 34, 16, 40, 29];
ip: 192.168.1.209;
x: -0.525731086730957;
y: 0.8506507873535156;
z: 0;
id: 9;
};
{
neighbors: [35, 37, 24, 41, 19];
ip: 192.168.1.210;
x: -0.525731086730957;
y: -0.8506507873535156;
z: 0;
id: 10;
};
{
neighbors: [32, 20, 41, 25, 39];
ip: 192.168.1.211;
x: 0.525731086730957;
y: -0.8506507873535156;
z: 0;
id: 11;
};
{
neighbors: [0, 14, 18, 1, 17, 13];
ip: 192.168.1.212;
x: 0;
y: 0;
z: 1;
id: 12;
};
{
neighbors: [4, 31, 15, 0, 12, 17];
ip: 192.168.1.213;
x: 0.5;
y: 0.30901700258255005;
z: 0.80901700258255;
id: 13;
};
{
neighbors: [0, 16, 34, 5, 18, 12];
ip: 192.168.1.214;
x: -0.5;
y: 0.30901700258255005;
z: 0.80901700258255;
id: 14;
};
{
neighbors: [8, 40, 16, 0, 13, 31];
ip: 192.168.1.215;
x: 0.30901700258255005;
y: 0.80901700258255;
z: 0.5;
id: 15;
};
{
neighbors: [9, 34, 14, 0, 15, 40];
ip: 192.168.1.216;
x: -0.30901700258255005;
y: 0.80901700258255;
z: 0.5;
id: 16;
};
{
neighbors: [4, 13, 12, 1, 20, 32];
ip: 192.168.1.217;
x: 0.5;
y: -0.30901700258255005;
z: 0.80901700258255;
id: 17;
};
{
neighbors: [5, 35, 19, 1, 12, 14];
ip: 192.168.1.218;
x: -0.5;
y: -0.30901700258255005;
z: 0.80901700258255;
id: 18;
};
{
neighbors: [1, 18, 35, 10, 41, 20];
ip: 192.168.1.219;
x: -0.30901700258255005;
y: -0.80901700258255;
z: 0.5;
id: 19;
};
{
neighbors: [11, 32, 17, 1, 19, 41];
ip: 192.168.1.220;
x: 0.30901700258255005;
y: -0.80901700258255;
z: 0.5;
id: 20;
};
{
neighbors: [3, 27, 23, 2, 22, 26];
ip: 192.168.1.221;
x: 0;
y: 0;
z: -1;
id: 21;
};
{
neighbors: [6, 26, 21, 2, 24, 37];
ip: 192.168.1.222;
x: -0.5;
y: -0.30901700258255005;
z: -0.80901700258255;
id: 22;
};
{
neighbors: [7, 39, 25, 2, 21, 27];
ip: 192.168.1.223;
x: 0.5;
y: -0.30901700258255005;
z: -0.80901700258255;
id: 23;
};
{
neighbors: [10, 37, 22, 2, 25, 41];
ip: 192.168.1.224;
x: -0.30901700258255005;
y: -0.80901700258255;
z: -0.5;
id: 24;
};
{
neighbors: [11, 41, 24, 2, 23, 39];
ip: 192.168.1.225;
x: 0.30901700258255005;
y: -0.80901700258255;
z: -0.5;
id: 25;
};
{
neighbors: [3, 21, 22, 6, 36, 29];
ip: 192.168.1.226;
x: -0.5;
y: 0.30901700258255005;
z: -0.80901700258255;
id: 26;
};
{
neighbors: [3, 28, 38, 7, 23, 21];
ip: 192.168.1.227;
x: 0.5;
y: 0.30901700258255005;
z: -0.80901700258255;
id: 27;
};
{
neighbors: [8, 38, 27, 3, 29, 40];
ip: 192.168.1.228;
x: 0.30901700258255005;
y: 0.80901700258255;
z: -0.5;
id: 28;
};
{
neighbors: [9, 40, 28, 3, 26, 36];
ip: 192.168.1.229;
x: -0.30901700258255005;
y: 0.80901700258255;
z: -0.5;
id: 29;
};
{
neighbors: [7, 38, 31, 4, 32, 39];
ip: 192.168.1.230;
x: 1;
y: 0;
z: 0;
id: 30;
};
{
neighbors: [8, 15, 13, 4, 30, 38];
ip: 192.168.1.231;
x: 0.80901700258255;
y: 0.5;
z: 0.30901700258255005;
id: 31;
};
{
neighbors: [11, 39, 30, 4, 17, 20];
ip: 192.168.1.232;
x: 0.80901700258255;
y: -0.5;
z: 0.30901700258255005;
id: 32;
};
{
neighbors: [5, 34, 36, 6, 37, 35];
ip: 192.168.1.233;
x: -1;
y: 0;
z: 0;
id: 33;
};
{
neighbors: [5, 14, 16, 9, 36, 33];
ip: 192.168.1.234;
x: -0.80901700258255;
y: 0.5;
z: 0.30901700258255005;
id: 34;
};
{
neighbors: [5, 33, 37, 10, 19, 18];
ip: 192.168.1.235;
x: -0.80901700258255;
y: -0.5;
z: 0.30901700258255005;
id: 35;
};
{
neighbors: [9, 29, 26, 6, 33, 34];
ip: 192.168.1.236;
x: -0.80901700258255;
y: 0.5;
z: -0.30901700258255005;
id: 36;
};
{
neighbors: [10, 35, 33, 6, 22, 24];
ip: 192.168.1.237;
x: -0.80901700258255;
y: -0.5;
z: -0.30901700258255005;
id: 37;
};
{
neighbors: [8, 31, 30, 7, 27, 28];
ip: 192.168.1.238;
x: 0.80901700258255;
y: 0.5;
z: -0.30901700258255005;
id: 38;
};
{
neighbors: [11, 25, 23, 7, 30, 32];
ip: 192.168.1.239;
x: 0.80901700258255;
y: -0.5;
z: -0.30901700258255005;
id: 39;
};
{
neighbors: [8, 28, 29, 9, 16, 15];
ip: 192.168.1.240;
x: 0;
y: 1;
z: 0;
id: 40;
};
{
neighbors: [11, 20, 19, 10, 24, 25];
ip: 192.168.1.241;
x: 0;
y: -1;
z: 0;
id: 41;
};
EOF

View File

@ -0,0 +1,408 @@
led_strip_count 406
led_strip { 0, 0, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 0, 1, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 0, 2, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 0, 3, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 0, 4, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 1, 25, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 1, 26, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 1, 27, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 1, 28, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 1, 29, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 2, 50, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 2, 51, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 2, 52, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 2, 53, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 2, 54, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 3, 75, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 3, 76, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 3, 77, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 3, 78, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 3, 79, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 4, 100, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 4, 101, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 4, 102, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 4, 103, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 4, 104, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 5, 125, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 5, 126, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 5, 127, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 5, 128, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 5, 129, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 6, 150, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 6, 151, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 6, 152, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 6, 153, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 6, 154, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 7, 175, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 7, 176, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 7, 177, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 7, 178, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 7, 179, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 8, 200, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 8, 201, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 8, 202, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 8, 203, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 8, 204, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 9, 225, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 9, 226, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 9, 227, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 9, 228, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 9, 229, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 10, 250, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 10, 251, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 10, 252, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 10, 253, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 10, 254, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 11, 275, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 11, 276, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 11, 277, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 11, 278, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 11, 279, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 12, 300, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 12, 301, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 12, 302, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 12, 303, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 12, 304, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 12, 305, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 13, 325, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 13, 326, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 13, 327, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 13, 328, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 13, 329, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 13, 330, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 14, 350, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 14, 351, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 14, 352, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 14, 353, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 14, 354, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 14, 355, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 15, 375, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 15, 376, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 15, 377, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 15, 378, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 15, 379, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 15, 380, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 16, 400, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 16, 401, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 16, 402, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 16, 403, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 16, 404, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 16, 405, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 17, 425, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 17, 426, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 17, 427, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 17, 428, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 17, 429, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 17, 430, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 18, 450, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 18, 451, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 18, 452, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 18, 453, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 18, 454, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 18, 455, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 19, 475, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 19, 476, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 19, 477, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 19, 478, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 19, 479, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 19, 480, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 20, 500, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 20, 501, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 20, 502, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 20, 503, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 20, 504, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 20, 505, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 21, 525, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 21, 526, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 21, 527, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 21, 528, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 21, 529, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 21, 530, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 22, 550, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 22, 551, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 22, 552, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 22, 553, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 22, 554, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 22, 555, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 23, 575, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 23, 576, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 23, 577, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 23, 578, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 23, 579, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 23, 580, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 24, 600, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 24, 601, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 24, 602, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 24, 603, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 24, 604, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 24, 605, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 25, 625, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 25, 626, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 25, 627, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 25, 628, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 25, 629, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 25, 630, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 26, 650, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 26, 651, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 26, 652, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 26, 653, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 26, 654, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 26, 655, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 27, 675, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 27, 676, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 27, 677, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 27, 678, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 27, 679, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 27, 680, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 28, 700, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 28, 701, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 28, 702, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 28, 703, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 28, 704, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 28, 705, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 29, 725, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 29, 726, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 29, 727, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 29, 728, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 29, 729, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 29, 730, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 30, 750, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 30, 751, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 30, 752, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 30, 753, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 30, 754, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 30, 755, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 31, 775, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 31, 776, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 31, 777, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 31, 778, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 31, 779, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 31, 780, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 32, 800, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 32, 801, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 32, 802, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 32, 803, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 32, 804, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 32, 805, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 33, 825, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 33, 826, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 33, 827, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, 0.500000, -0.309017), 144 } led_strip { 33, 829, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 33, 830, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 34, 850, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 34, 851, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 34, 852, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 34, 853, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 34, 854, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 34, 855, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 35, 875, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 35, 876, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 35, 877, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 35, 878, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 35, 879, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.309017, -0.809017, 0.500000), 144 } led_strip { 36, 900, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 36, 901, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 36, 902, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 36, 903, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 36, 904, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 36, 905, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 37, 925, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 37, 926, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 37, 927, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 37, 928, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 37, 929, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 37, 930, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 38, 950, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 38, 951, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 38, 952, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 38, 953, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 38, 954, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 38, 955, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 39, 975, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 39, 976, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 39, 977, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 39, 978, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 39, 979, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 39, 980, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 40, 1000, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 40, 1001, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 40, 1002, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 40, 1003, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 40, 1004, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 40, 1005, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 41, 1025, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 41, 1026, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 41, 1027, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 41, 1028, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 41, 1029, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 41, 1030, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 0, 5, 0, INTERPOLATE_POINTS, (-0.005654, 0.530914, 0.844235), (-0.005654, 0.662347, 1.056898), 144 }
led_strip { 0, 6, 0, INTERPOLATE_POINTS, (0.005654, 0.651981, 1.069729), (0.005654, 0.520548, 0.857067), 144 }
led_strip { 0, 7, 0, INTERPOLATE_POINTS, (-0.009149, 0.521766, 0.849889), (-0.009149, 0.653199, 1.062552), 144 }
led_strip { 0, 8, 0, INTERPOLATE_POINTS, (0.002160, 0.642832, 1.075384), (0.002160, 0.511399, 0.862721), 144 }
led_strip { 1, 30, 0, INTERPOLATE_POINTS, (0.005654, -0.530914, 0.844235), (0.005654, -0.662347, 1.056898), 144 }
led_strip { 1, 31, 0, INTERPOLATE_POINTS, (-0.005654, -0.651981, 1.069729), (-0.005654, -0.520548, 0.857067), 144 }
led_strip { 1, 32, 0, INTERPOLATE_POINTS, (0.009149, -0.521766, 0.849889), (0.009149, -0.653199, 1.062552), 144 }
led_strip { 1, 33, 0, INTERPOLATE_POINTS, (-0.002160, -0.642832, 1.075384), (-0.002160, -0.511399, 0.862721), 144 }
led_strip { 2, 55, 0, INTERPOLATE_POINTS, (-0.005654, -0.530914, -0.844235), (-0.005654, -0.662347, -1.056898), 144 }
led_strip { 2, 56, 0, INTERPOLATE_POINTS, (0.005654, -0.651981, -1.069729), (0.005654, -0.520548, -0.857067), 144 }
led_strip { 2, 57, 0, INTERPOLATE_POINTS, (-0.009149, -0.521766, -0.849889), (-0.009149, -0.653199, -1.062552), 144 }
led_strip { 2, 58, 0, INTERPOLATE_POINTS, (0.002160, -0.642832, -1.075384), (0.002160, -0.511399, -0.862721), 144 }
led_strip { 3, 80, 0, INTERPOLATE_POINTS, (0.005654, 0.530914, -0.844235), (0.005654, 0.662347, -1.056898), 144 }
led_strip { 3, 81, 0, INTERPOLATE_POINTS, (-0.005654, 0.651981, -1.069729), (-0.005654, 0.520548, -0.857067), 144 }
led_strip { 3, 82, 0, INTERPOLATE_POINTS, (0.009149, 0.521766, -0.849889), (0.009149, 0.653199, -1.062552), 144 }
led_strip { 3, 83, 0, INTERPOLATE_POINTS, (-0.002160, 0.642832, -1.075384), (-0.002160, 0.511399, -0.862721), 144 }
led_strip { 4, 105, 0, INTERPOLATE_POINTS, (0.849889, 0.009149, 0.521766), (1.062552, 0.009149, 0.653199), 144 }
led_strip { 4, 106, 0, INTERPOLATE_POINTS, (1.064075, -0.009149, 0.661129), (0.851413, -0.009149, 0.529696), 144 }
led_strip { 4, 107, 0, INTERPOLATE_POINTS, (0.844235, 0.005654, 0.530914), (1.056898, 0.005654, 0.662347), 144 }
led_strip { 4, 108, 0, INTERPOLATE_POINTS, (1.058421, -0.012643, 0.670278), (0.845758, -0.012643, 0.538845), 144 }
led_strip { 5, 130, 0, INTERPOLATE_POINTS, (-0.844235, 0.005654, 0.530914), (-1.056898, 0.005654, 0.662347), 144 }
led_strip { 5, 131, 0, INTERPOLATE_POINTS, (-1.069729, -0.005654, 0.651981), (-0.857067, -0.005654, 0.520548), 144 }
led_strip { 5, 132, 0, INTERPOLATE_POINTS, (-0.849889, 0.009149, 0.521766), (-1.062552, 0.009149, 0.653199), 144 }
led_strip { 5, 133, 0, INTERPOLATE_POINTS, (-1.075384, -0.002160, 0.642832), (-0.862721, -0.002160, 0.511399), 144 }
led_strip { 6, 155, 0, INTERPOLATE_POINTS, (-0.849889, 0.009149, -0.521766), (-1.062552, 0.009149, -0.653199), 144 }
led_strip { 6, 156, 0, INTERPOLATE_POINTS, (-1.064075, -0.009149, -0.661129), (-0.851413, -0.009149, -0.529696), 144 }
led_strip { 6, 157, 0, INTERPOLATE_POINTS, (-0.844235, 0.005654, -0.530914), (-1.056898, 0.005654, -0.662347), 144 }
led_strip { 6, 158, 0, INTERPOLATE_POINTS, (-1.058421, -0.012643, -0.670278), (-0.845758, -0.012643, -0.538845), 144 }
led_strip { 7, 180, 0, INTERPOLATE_POINTS, (0.853383, 0.000000, -0.516112), (1.066046, 0.000000, -0.647545), 144 }
led_strip { 7, 181, 0, INTERPOLATE_POINTS, (1.060581, 0.000000, -0.666783), (0.847918, 0.000000, -0.535351), 144 }
led_strip { 7, 182, 0, INTERPOLATE_POINTS, (0.849889, -0.009149, -0.521766), (1.062552, -0.009149, -0.653199), 144 }
led_strip { 7, 183, 0, INTERPOLATE_POINTS, (1.057086, -0.009149, -0.672437), (0.844424, -0.009149, -0.541005), 144 }
led_strip { 8, 205, 0, INTERPOLATE_POINTS, (0.530914, 0.844235, -0.005654), (0.662347, 1.056898, -0.005654), 144 }
led_strip { 8, 206, 0, INTERPOLATE_POINTS, (0.651981, 1.069729, 0.005654), (0.520548, 0.857067, 0.005654), 144 }
led_strip { 8, 207, 0, INTERPOLATE_POINTS, (0.521766, 0.849889, -0.009149), (0.653199, 1.062552, -0.009149), 144 }
led_strip { 8, 208, 0, INTERPOLATE_POINTS, (0.642832, 1.075384, 0.002160), (0.511399, 0.862721, 0.002160), 144 }
led_strip { 9, 230, 0, INTERPOLATE_POINTS, (-0.530914, 0.844235, -0.005654), (-0.662347, 1.056898, -0.005654), 144 }
led_strip { 9, 231, 0, INTERPOLATE_POINTS, (-0.651981, 1.069729, 0.005654), (-0.520548, 0.857067, 0.005654), 144 }
led_strip { 9, 232, 0, INTERPOLATE_POINTS, (-0.530914, 0.844235, 0.005654), (-0.662347, 1.056898, 0.005654), 144 }
led_strip { 9, 233, 0, INTERPOLATE_POINTS, (-0.651981, 1.069729, 0.016962), (-0.520548, 0.857067, 0.016962), 144 }
led_strip { 10, 255, 0, INTERPOLATE_POINTS, (-0.530914, -0.844235, 0.005654), (-0.662347, -1.056898, 0.005654), 144 }
led_strip { 10, 256, 0, INTERPOLATE_POINTS, (-0.651981, -1.069729, -0.005654), (-0.520548, -0.857067, -0.005654), 144 }
led_strip { 10, 257, 0, INTERPOLATE_POINTS, (-0.530914, -0.844235, -0.005654), (-0.662347, -1.056898, -0.005654), 144 }
led_strip { 10, 258, 0, INTERPOLATE_POINTS, (-0.651981, -1.069729, -0.016962), (-0.520548, -0.857067, -0.016962), 144 }
led_strip { 11, 280, 0, INTERPOLATE_POINTS, (0.530914, -0.844235, 0.005654), (0.662347, -1.056898, 0.005654), 144 }
led_strip { 11, 281, 0, INTERPOLATE_POINTS, (0.651981, -1.069729, -0.005654), (0.520548, -0.857067, -0.005654), 144 }
led_strip { 11, 282, 0, INTERPOLATE_POINTS, (0.521766, -0.849889, 0.009149), (0.653199, -1.062552, 0.009149), 144 }
led_strip { 11, 283, 0, INTERPOLATE_POINTS, (0.642832, -1.075384, -0.002160), (0.511399, -0.862721, -0.002160), 144 }
led_strip { 12, 306, 0, INTERPOLATE_POINTS, (0.000000, 0.009619, 0.997267), (0.000000, 0.009619, 1.247267), 144 }
led_strip { 12, 307, 0, INTERPOLATE_POINTS, (0.000000, -0.009619, 1.252733), (0.000000, -0.009619, 1.002733), 144 }
led_strip { 12, 308, 0, INTERPOLATE_POINTS, (-0.008090, 0.005000, 0.996910), (-0.008090, 0.005000, 1.246910), 144 }
led_strip { 12, 309, 0, INTERPOLATE_POINTS, (-0.008090, -0.014239, 1.252375), (-0.008090, -0.014239, 1.002375), 144 }
led_strip { 13, 331, 0, INTERPOLATE_POINTS, (0.506416, 0.303363, 0.803834), (0.631416, 0.380617, 1.006088), 144 }
led_strip { 13, 332, 0, INTERPOLATE_POINTS, (0.618584, 0.391925, 1.016455), (0.493584, 0.314671, 0.814200), 144 }
led_strip { 13, 333, 0, INTERPOLATE_POINTS, (0.505000, 0.312107, 0.800927), (0.630000, 0.389361, 1.003181), 144 }
led_strip { 13, 334, 0, INTERPOLATE_POINTS, (0.617168, 0.400670, 1.013548), (0.492168, 0.323415, 0.811293), 144 }
led_strip { 14, 356, 0, INTERPOLATE_POINTS, (-0.490851, 0.312982, 0.809779), (-0.615851, 0.390236, 1.012033), 144 }
led_strip { 14, 357, 0, INTERPOLATE_POINTS, (-0.634149, 0.382306, 1.010509), (-0.509149, 0.305052, 0.808255), 144 }
led_strip { 14, 358, 0, INTERPOLATE_POINTS, (-0.496910, 0.317107, 0.804017), (-0.621910, 0.394361, 1.006271), 144 }
led_strip { 14, 359, 0, INTERPOLATE_POINTS, (-0.640207, 0.386431, 1.004748), (-0.515207, 0.309177, 0.802493), 144 }
led_strip { 15, 381, 0, INTERPOLATE_POINTS, (0.312982, 0.809779, 0.490851), (0.390236, 1.012033, 0.615851), 144 }
led_strip { 15, 382, 0, INTERPOLATE_POINTS, (0.382306, 1.010509, 0.634149), (0.305052, 0.808255, 0.509149), 144 }
led_strip { 15, 383, 0, INTERPOLATE_POINTS, (0.304017, 0.812107, 0.491910), (0.381271, 1.014361, 0.616910), 144 }
led_strip { 15, 384, 0, INTERPOLATE_POINTS, (0.373341, 1.012838, 0.635207), (0.296086, 0.810584, 0.510207), 144 }
led_strip { 16, 406, 0, INTERPOLATE_POINTS, (-0.312982, 0.809779, 0.490851), (-0.390236, 1.012033, 0.615851), 144 }
led_strip { 16, 407, 0, INTERPOLATE_POINTS, (-0.382306, 1.010509, 0.634149), (-0.305052, 0.808255, 0.509149), 144 }
led_strip { 16, 408, 0, INTERPOLATE_POINTS, (-0.317107, 0.804017, 0.496910), (-0.394361, 1.006271, 0.621910), 144 }
led_strip { 16, 409, 0, INTERPOLATE_POINTS, (-0.386431, 1.004748, 0.640207), (-0.309177, 0.802493, 0.515207), 144 }
led_strip { 17, 431, 0, INTERPOLATE_POINTS, (0.506416, -0.303363, 0.803834), (0.631416, -0.380617, 1.006088), 144 }
led_strip { 17, 432, 0, INTERPOLATE_POINTS, (0.618584, -0.391925, 1.016455), (0.493584, -0.314671, 0.814200), 144 }
led_strip { 17, 433, 0, INTERPOLATE_POINTS, (0.500000, -0.299017, 0.809017), (0.625000, -0.376271, 1.011271), 144 }
led_strip { 17, 434, 0, INTERPOLATE_POINTS, (0.612168, -0.387580, 1.021638), (0.487168, -0.310325, 0.819384), 144 }
led_strip { 18, 456, 0, INTERPOLATE_POINTS, (-0.506416, -0.303363, 0.803834), (-0.631416, -0.380617, 1.006088), 144 }
led_strip { 18, 457, 0, INTERPOLATE_POINTS, (-0.618584, -0.391925, 1.016455), (-0.493584, -0.314671, 0.814200), 144 }
led_strip { 18, 458, 0, INTERPOLATE_POINTS, (-0.505000, -0.312107, 0.800927), (-0.630000, -0.389361, 1.003181), 144 }
led_strip { 18, 459, 0, INTERPOLATE_POINTS, (-0.617168, -0.400670, 1.013548), (-0.492168, -0.323415, 0.811293), 144 }
led_strip { 19, 481, 0, INTERPOLATE_POINTS, (-0.303363, -0.803834, 0.506416), (-0.380617, -1.006088, 0.631416), 144 }
led_strip { 19, 482, 0, INTERPOLATE_POINTS, (-0.391925, -1.016455, 0.618584), (-0.314671, -0.814200, 0.493584), 144 }
led_strip { 19, 483, 0, INTERPOLATE_POINTS, (-0.312107, -0.800927, 0.505000), (-0.389361, -1.003181, 0.630000), 144 }
led_strip { 19, 484, 0, INTERPOLATE_POINTS, (-0.400670, -1.013548, 0.617168), (-0.323415, -0.811293, 0.492168), 144 }
led_strip { 20, 506, 0, INTERPOLATE_POINTS, (0.312982, -0.809779, 0.490851), (0.390236, -1.012033, 0.615851), 144 }
led_strip { 20, 507, 0, INTERPOLATE_POINTS, (0.382306, -1.010509, 0.634149), (0.305052, -0.808255, 0.509149), 144 }
led_strip { 20, 508, 0, INTERPOLATE_POINTS, (0.317107, -0.804017, 0.496910), (0.394361, -1.006271, 0.621910), 144 }
led_strip { 20, 509, 0, INTERPOLATE_POINTS, (0.386431, -1.004748, 0.640207), (0.309177, -0.802493, 0.515207), 144 }
led_strip { 21, 531, 0, INTERPOLATE_POINTS, (0.000000, 0.009619, -0.997267), (0.000000, 0.009619, -1.247267), 144 }
led_strip { 21, 532, 0, INTERPOLATE_POINTS, (0.000000, -0.009619, -1.252733), (0.000000, -0.009619, -1.002733), 144 }
led_strip { 21, 533, 0, INTERPOLATE_POINTS, (0.008090, 0.005000, -0.996910), (0.008090, 0.005000, -1.246910), 144 }
led_strip { 21, 534, 0, INTERPOLATE_POINTS, (0.008090, -0.014239, -1.252375), (0.008090, -0.014239, -1.002375), 144 }
led_strip { 22, 556, 0, INTERPOLATE_POINTS, (-0.506416, -0.303363, -0.803834), (-0.631416, -0.380617, -1.006088), 144 }
led_strip { 22, 557, 0, INTERPOLATE_POINTS, (-0.618584, -0.391925, -1.016455), (-0.493584, -0.314671, -0.814200), 144 }
led_strip { 22, 558, 0, INTERPOLATE_POINTS, (-0.500000, -0.299017, -0.809017), (-0.625000, -0.376271, -1.011271), 144 }
led_strip { 22, 559, 0, INTERPOLATE_POINTS, (-0.612168, -0.387580, -1.021638), (-0.487168, -0.310325, -0.819384), 144 }
led_strip { 23, 581, 0, INTERPOLATE_POINTS, (0.506416, -0.303363, -0.803834), (0.631416, -0.380617, -1.006088), 144 }
led_strip { 23, 582, 0, INTERPOLATE_POINTS, (0.618584, -0.391925, -1.016455), (0.493584, -0.314671, -0.814200), 144 }
led_strip { 23, 583, 0, INTERPOLATE_POINTS, (0.505000, -0.312107, -0.800927), (0.630000, -0.389361, -1.003181), 144 }
led_strip { 23, 584, 0, INTERPOLATE_POINTS, (0.617168, -0.400670, -1.013548), (0.492168, -0.323415, -0.811293), 144 }
led_strip { 24, 606, 0, INTERPOLATE_POINTS, (-0.312982, -0.809779, -0.490851), (-0.390236, -1.012033, -0.615851), 144 }
led_strip { 24, 607, 0, INTERPOLATE_POINTS, (-0.382306, -1.010509, -0.634149), (-0.305052, -0.808255, -0.509149), 144 }
led_strip { 24, 608, 0, INTERPOLATE_POINTS, (-0.317107, -0.804017, -0.496910), (-0.394361, -1.006271, -0.621910), 144 }
led_strip { 24, 609, 0, INTERPOLATE_POINTS, (-0.386431, -1.004748, -0.640207), (-0.309177, -0.802493, -0.515207), 144 }
led_strip { 25, 631, 0, INTERPOLATE_POINTS, (0.312982, -0.809779, -0.490851), (0.390236, -1.012033, -0.615851), 144 }
led_strip { 25, 632, 0, INTERPOLATE_POINTS, (0.382306, -1.010509, -0.634149), (0.305052, -0.808255, -0.509149), 144 }
led_strip { 25, 633, 0, INTERPOLATE_POINTS, (0.304017, -0.812107, -0.491910), (0.381271, -1.014361, -0.616910), 144 }
led_strip { 25, 634, 0, INTERPOLATE_POINTS, (0.373341, -1.012838, -0.635207), (0.296086, -0.810584, -0.510207), 144 }
led_strip { 26, 656, 0, INTERPOLATE_POINTS, (-0.490851, 0.312982, -0.809779), (-0.615851, 0.390236, -1.012033), 144 }
led_strip { 26, 657, 0, INTERPOLATE_POINTS, (-0.634149, 0.382306, -1.010509), (-0.509149, 0.305052, -0.808255), 144 }
led_strip { 26, 658, 0, INTERPOLATE_POINTS, (-0.491910, 0.304017, -0.812107), (-0.616910, 0.381271, -1.014361), 144 }
led_strip { 26, 659, 0, INTERPOLATE_POINTS, (-0.635207, 0.373341, -1.012838), (-0.510207, 0.296086, -0.810584), 144 }
led_strip { 27, 681, 0, INTERPOLATE_POINTS, (0.490851, 0.312982, -0.809779), (0.615851, 0.390236, -1.012033), 144 }
led_strip { 27, 682, 0, INTERPOLATE_POINTS, (0.634149, 0.382306, -1.010509), (0.509149, 0.305052, -0.808255), 144 }
led_strip { 27, 683, 0, INTERPOLATE_POINTS, (0.496910, 0.317107, -0.804017), (0.621910, 0.394361, -1.006271), 144 }
led_strip { 27, 684, 0, INTERPOLATE_POINTS, (0.640207, 0.386431, -1.004748), (0.515207, 0.309177, -0.802493), 144 }
led_strip { 28, 706, 0, INTERPOLATE_POINTS, (0.312982, 0.809779, -0.490851), (0.390236, 1.012033, -0.615851), 144 }
led_strip { 28, 707, 0, INTERPOLATE_POINTS, (0.382306, 1.010509, -0.634149), (0.305052, 0.808255, -0.509149), 144 }
led_strip { 28, 708, 0, INTERPOLATE_POINTS, (0.317107, 0.804017, -0.496910), (0.394361, 1.006271, -0.621910), 144 }
led_strip { 28, 709, 0, INTERPOLATE_POINTS, (0.386431, 1.004748, -0.640207), (0.309177, 0.802493, -0.515207), 144 }
led_strip { 29, 731, 0, INTERPOLATE_POINTS, (-0.312982, 0.809779, -0.490851), (-0.390236, 1.012033, -0.615851), 144 }
led_strip { 29, 732, 0, INTERPOLATE_POINTS, (-0.382306, 1.010509, -0.634149), (-0.305052, 0.808255, -0.509149), 144 }
led_strip { 29, 733, 0, INTERPOLATE_POINTS, (-0.304017, 0.812107, -0.491910), (-0.381271, 1.014361, -0.616910), 144 }
led_strip { 29, 734, 0, INTERPOLATE_POINTS, (-0.373341, 1.012838, -0.635207), (-0.296086, 0.810584, -0.510207), 144 }
led_strip { 30, 756, 0, INTERPOLATE_POINTS, (0.997267, 0.000000, -0.009619), (1.247267, 0.000000, -0.009619), 144 }
led_strip { 30, 757, 0, INTERPOLATE_POINTS, (1.252733, 0.000000, 0.009619), (1.002733, 0.000000, 0.009619), 144 }
led_strip { 30, 758, 0, INTERPOLATE_POINTS, (0.996910, 0.008090, -0.005000), (1.246910, 0.008090, -0.005000), 144 }
led_strip { 30, 759, 0, INTERPOLATE_POINTS, (1.252375, 0.008090, 0.014239), (1.002375, 0.008090, 0.014239), 144 }
led_strip { 31, 781, 0, INTERPOLATE_POINTS, (0.803834, 0.506416, 0.303363), (1.006088, 0.631416, 0.380617), 144 }
led_strip { 31, 782, 0, INTERPOLATE_POINTS, (1.016455, 0.618584, 0.391925), (0.814200, 0.493584, 0.314671), 144 }
led_strip { 31, 783, 0, INTERPOLATE_POINTS, (0.800927, 0.505000, 0.312107), (1.003181, 0.630000, 0.389361), 144 }
led_strip { 31, 784, 0, INTERPOLATE_POINTS, (1.013548, 0.617168, 0.400670), (0.811293, 0.492168, 0.323415), 144 }
led_strip { 32, 806, 0, INTERPOLATE_POINTS, (0.803834, -0.506416, 0.303363), (1.006088, -0.631416, 0.380617), 144 }
led_strip { 32, 807, 0, INTERPOLATE_POINTS, (1.016455, -0.618584, 0.391925), (0.814200, -0.493584, 0.314671), 144 }
led_strip { 32, 808, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.299017), (1.011271, -0.625000, 0.376271), 144 }
led_strip { 32, 809, 0, INTERPOLATE_POINTS, (1.021638, -0.612168, 0.387580), (0.819384, -0.487168, 0.310325), 144 }
led_strip { 33, 831, 0, INTERPOLATE_POINTS, (-0.997267, 0.000000, 0.009619), (-1.247267, 0.000000, 0.009619), 144 }
led_strip { 33, 832, 0, INTERPOLATE_POINTS, (-1.252733, 0.000000, -0.009619), (-1.002733, 0.000000, -0.009619), 144 }
led_strip { 33, 833, 0, INTERPOLATE_POINTS, (-0.996910, 0.008090, 0.005000), (-1.246910, 0.008090, 0.005000), 144 }
led_strip { 33, 834, 0, INTERPOLATE_POINTS, (-1.252375, 0.008090, -0.014239), (-1.002375, 0.008090, -0.014239), 144 }
led_strip { 34, 856, 0, INTERPOLATE_POINTS, (-0.809779, 0.490851, 0.312982), (-1.012033, 0.615851, 0.390236), 144 }
led_strip { 34, 857, 0, INTERPOLATE_POINTS, (-1.010509, 0.634149, 0.382306), (-0.808255, 0.509149, 0.305052), 144 }
led_strip { 34, 858, 0, INTERPOLATE_POINTS, (-0.804017, 0.496910, 0.317107), (-1.006271, 0.621910, 0.394361), 144 }
led_strip { 34, 859, 0, INTERPOLATE_POINTS, (-1.004748, 0.640207, 0.386431), (-0.802493, 0.515207, 0.309177), 144 }
led_strip { 35, 881, 0, INTERPOLATE_POINTS, (-0.809779, -0.490851, 0.312982), (-1.012033, -0.615851, 0.390236), 144 }
led_strip { 35, 882, 0, INTERPOLATE_POINTS, (-1.010509, -0.634149, 0.382306), (-0.808255, -0.509149, 0.305052), 144 }
led_strip { 35, 883, 0, INTERPOLATE_POINTS, (-0.812107, -0.491910, 0.304017), (-1.014361, -0.616910, 0.381271), 144 }
led_strip { 35, 884, 0, INTERPOLATE_POINTS, (-1.012838, -0.635207, 0.373341), (-0.810584, -0.510207, 0.296086), 144 }
led_strip { 36, 906, 0, INTERPOLATE_POINTS, (-0.803834, 0.506416, -0.303363), (-1.006088, 0.631416, -0.380617), 144 }
led_strip { 36, 907, 0, INTERPOLATE_POINTS, (-1.016455, 0.618584, -0.391925), (-0.814200, 0.493584, -0.314671), 144 }
led_strip { 36, 908, 0, INTERPOLATE_POINTS, (-0.800927, 0.505000, -0.312107), (-1.003181, 0.630000, -0.389361), 144 }
led_strip { 36, 909, 0, INTERPOLATE_POINTS, (-1.013548, 0.617168, -0.400670), (-0.811293, 0.492168, -0.323415), 144 }
led_strip { 37, 931, 0, INTERPOLATE_POINTS, (-0.803834, -0.506416, -0.303363), (-1.006088, -0.631416, -0.380617), 144 }
led_strip { 37, 932, 0, INTERPOLATE_POINTS, (-1.016455, -0.618584, -0.391925), (-0.814200, -0.493584, -0.314671), 144 }
led_strip { 37, 933, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.299017), (-1.011271, -0.625000, -0.376271), 144 }
led_strip { 37, 934, 0, INTERPOLATE_POINTS, (-1.021638, -0.612168, -0.387580), (-0.819384, -0.487168, -0.310325), 144 }
led_strip { 38, 956, 0, INTERPOLATE_POINTS, (0.803834, 0.506416, -0.303363), (1.006088, 0.631416, -0.380617), 144 }
led_strip { 38, 957, 0, INTERPOLATE_POINTS, (1.016455, 0.618584, -0.391925), (0.814200, 0.493584, -0.314671), 144 }
led_strip { 38, 958, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.299017), (1.011271, 0.625000, -0.376271), 144 }
led_strip { 38, 959, 0, INTERPOLATE_POINTS, (1.021638, 0.612168, -0.387580), (0.819384, 0.487168, -0.310325), 144 }
led_strip { 39, 981, 0, INTERPOLATE_POINTS, (0.803834, -0.506416, -0.303363), (1.006088, -0.631416, -0.380617), 144 }
led_strip { 39, 982, 0, INTERPOLATE_POINTS, (1.016455, -0.618584, -0.391925), (0.814200, -0.493584, -0.314671), 144 }
led_strip { 39, 983, 0, INTERPOLATE_POINTS, (0.800927, -0.505000, -0.312107), (1.003181, -0.630000, -0.389361), 144 }
led_strip { 39, 984, 0, INTERPOLATE_POINTS, (1.013548, -0.617168, -0.400670), (0.811293, -0.492168, -0.323415), 144 }
led_strip { 40, 1006, 0, INTERPOLATE_POINTS, (0.009619, 0.997267, 0.000000), (0.009619, 1.247267, 0.000000), 144 }
led_strip { 40, 1007, 0, INTERPOLATE_POINTS, (-0.009619, 1.252733, 0.000000), (-0.009619, 1.002733, 0.000000), 144 }
led_strip { 40, 1008, 0, INTERPOLATE_POINTS, (0.005000, 0.996910, -0.008090), (0.005000, 1.246910, -0.008090), 144 }
led_strip { 40, 1009, 0, INTERPOLATE_POINTS, (-0.014239, 1.252375, -0.008090), (-0.014239, 1.002375, -0.008090), 144 }
led_strip { 41, 1031, 0, INTERPOLATE_POINTS, (0.009619, -0.997267, 0.000000), (0.009619, -1.247267, 0.000000), 144 }
led_strip { 41, 1032, 0, INTERPOLATE_POINTS, (-0.009619, -1.252733, 0.000000), (-0.009619, -1.002733, 0.000000), 144 }
led_strip { 41, 1033, 0, INTERPOLATE_POINTS, (0.005000, -0.996910, 0.008090), (0.005000, -1.246910, 0.008090), 144 }
led_strip { 41, 1034, 0, INTERPOLATE_POINTS, (-0.014239, -1.252375, 0.008090), (-0.014239, -1.002375, 0.008090), 144 }
END_OF_ASSEMBLY_FILE

Binary file not shown.

View File

@ -0,0 +1,452 @@
control_box_count 42
led_strip_count 240
control_box { 0, "192.168.1.200", (0.000000, 0.525731, 0.850651) }
control_box { 1, "192.168.1.201", (0.000000, -0.525731, 0.850651) }
control_box { 2, "192.168.1.202", (0.000000, -0.525731, -0.850651) }
control_box { 3, "192.168.1.203", (0.000000, 0.525731, -0.850651) }
control_box { 4, "192.168.1.204", (0.850651, 0.000000, 0.525731) }
control_box { 5, "192.168.1.205", (-0.850651, 0.000000, 0.525731) }
control_box { 6, "192.168.1.206", (-0.850651, 0.000000, -0.525731) }
control_box { 7, "192.168.1.207", (0.850651, 0.000000, -0.525731) }
control_box { 8, "192.168.1.208", (0.525731, 0.850651, 0.000000) }
control_box { 9, "192.168.1.209", (-0.525731, 0.850651, 0.000000) }
control_box { 10, "192.168.1.210", (-0.525731, -0.850651, 0.000000) }
control_box { 11, "192.168.1.211", (0.525731, -0.850651, 0.000000) }
control_box { 12, "192.168.1.212", (0.000000, 0.000000, 1.000000) }
control_box { 13, "192.168.1.213", (0.500000, 0.309017, 0.809017) }
control_box { 14, "192.168.1.214", (-0.500000, 0.309017, 0.809017) }
control_box { 15, "192.168.1.215", (0.309017, 0.809017, 0.500000) }
control_box { 16, "192.168.1.216", (-0.309017, 0.809017, 0.500000) }
control_box { 17, "192.168.1.217", (0.500000, -0.309017, 0.809017) }
control_box { 18, "192.168.1.218", (-0.500000, -0.309017, 0.809017) }
control_box { 19, "192.168.1.219", (-0.309017, -0.809017, 0.500000) }
control_box { 20, "192.168.1.220", (0.309017, -0.809017, 0.500000) }
control_box { 21, "192.168.1.221", (0.000000, 0.000000, -1.000000) }
control_box { 22, "192.168.1.222", (-0.500000, -0.309017, -0.809017) }
control_box { 23, "192.168.1.223", (0.500000, -0.309017, -0.809017) }
control_box { 24, "192.168.1.224", (-0.309017, -0.809017, -0.500000) }
control_box { 25, "192.168.1.225", (0.309017, -0.809017, -0.500000) }
control_box { 26, "192.168.1.226", (-0.500000, 0.309017, -0.809017) }
control_box { 27, "192.168.1.227", (0.500000, 0.309017, -0.809017) }
control_box { 28, "192.168.1.228", (0.309017, 0.809017, -0.500000) }
control_box { 29, "192.168.1.229", (-0.309017, 0.809017, -0.500000) }
control_box { 30, "192.168.1.230", (1.000000, 0.000000, 0.000000) }
control_box { 31, "192.168.1.231", (0.809017, 0.500000, 0.309017) }
control_box { 32, "192.168.1.232", (0.809017, -0.500000, 0.309017) }
control_box { 33, "192.168.1.233", (-1.000000, 0.000000, 0.000000) }
control_box { 34, "192.168.1.234", (-0.809017, 0.500000, 0.309017) }
control_box { 35, "192.168.1.235", (-0.809017, -0.500000, 0.309017) }
control_box { 36, "192.168.1.236", (-0.809017, 0.500000, -0.309017) }
control_box { 37, "192.168.1.237", (-0.809017, -0.500000, -0.309017) }
control_box { 38, "192.168.1.238", (0.809017, 0.500000, -0.309017) }
control_box { 39, "192.168.1.239", (0.809017, -0.500000, -0.309017) }
control_box { 40, "192.168.1.240", (0.000000, 1.000000, 0.000000) }
control_box { 41, "192.168.1.241", (0.000000, -1.000000, 0.000000) }
led_strip { 0, 0, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 0, 1, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 0, 2, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 0, 3, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 0, 4, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, 0.850651), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 1, 25, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 1, 26, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 1, 27, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 1, 28, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 1, 29, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, 0.850651), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 2, 50, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 2, 51, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 2, 52, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 2, 53, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 2, 54, 0, INTERPOLATE_POINTS, (0.000000, -0.525731, -0.850651), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 3, 75, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 3, 76, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 3, 77, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 3, 78, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 3, 79, 0, INTERPOLATE_POINTS, (0.000000, 0.525731, -0.850651), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 4, 100, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 4, 101, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 4, 102, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 4, 103, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 4, 104, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, 0.525731), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 5, 125, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 5, 126, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 5, 127, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 5, 128, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 5, 129, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, 0.525731), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 6, 150, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 6, 151, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 6, 152, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 6, 153, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 6, 154, 0, INTERPOLATE_POINTS, (-0.850651, 0.000000, -0.525731), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 7, 175, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 7, 176, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 7, 177, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 7, 178, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 7, 179, 0, INTERPOLATE_POINTS, (0.850651, 0.000000, -0.525731), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 8, 200, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 8, 201, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 8, 202, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 8, 203, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 8, 204, 0, INTERPOLATE_POINTS, (0.525731, 0.850651, 0.000000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 9, 225, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 9, 226, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 9, 227, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 9, 228, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 9, 229, 0, INTERPOLATE_POINTS, (-0.525731, 0.850651, 0.000000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 10, 250, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 10, 251, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 10, 252, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 10, 253, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 10, 254, 0, INTERPOLATE_POINTS, (-0.525731, -0.850651, 0.000000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 11, 275, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 11, 276, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 11, 277, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 11, 278, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 11, 279, 0, INTERPOLATE_POINTS, (0.525731, -0.850651, 0.000000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 12, 300, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 12, 301, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 12, 302, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 12, 303, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 12, 304, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 12, 305, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, 1.000000), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 13, 325, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 13, 326, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 13, 327, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 13, 328, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 13, 329, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 13, 330, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, 0.809017), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 14, 350, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 14, 351, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 14, 352, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 14, 353, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 14, 354, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 14, 355, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 15, 375, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 15, 376, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 15, 377, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 15, 378, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 15, 379, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 15, 380, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, 0.500000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 16, 400, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 16, 401, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 16, 402, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 16, 403, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.000000, 0.525731, 0.850651), 144 }
led_strip { 16, 404, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 16, 405, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, 0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 17, 425, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 17, 426, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 17, 427, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 17, 428, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 17, 429, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 17, 430, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, 0.809017), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 18, 450, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 18, 451, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 18, 452, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 18, 453, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 18, 454, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (0.000000, 0.000000, 1.000000), 144 }
led_strip { 18, 455, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, 0.809017), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 19, 475, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 19, 476, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.500000, -0.309017, 0.809017), 144 }
led_strip { 19, 477, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 19, 478, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 19, 479, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 19, 480, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, 0.500000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 20, 500, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 20, 501, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 20, 502, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 20, 503, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.000000, -0.525731, 0.850651), 144 }
led_strip { 20, 504, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 20, 505, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, 0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 21, 525, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 21, 526, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 21, 527, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 21, 528, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 21, 529, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 21, 530, 0, INTERPOLATE_POINTS, (0.000000, 0.000000, -1.000000), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 22, 550, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 22, 551, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 22, 552, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 22, 553, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 22, 554, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 22, 555, 0, INTERPOLATE_POINTS, (-0.500000, -0.309017, -0.809017), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 23, 575, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 23, 576, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 23, 577, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 23, 578, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 23, 579, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 23, 580, 0, INTERPOLATE_POINTS, (0.500000, -0.309017, -0.809017), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 24, 600, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 24, 601, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 24, 602, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 24, 603, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 24, 604, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 24, 605, 0, INTERPOLATE_POINTS, (-0.309017, -0.809017, -0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 25, 625, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 25, 626, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.000000, -1.000000, 0.000000), 144 }
led_strip { 25, 627, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 25, 628, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.000000, -0.525731, -0.850651), 144 }
led_strip { 25, 629, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 25, 630, 0, INTERPOLATE_POINTS, (0.309017, -0.809017, -0.500000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 26, 650, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 26, 651, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 26, 652, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 26, 653, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 26, 654, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 26, 655, 0, INTERPOLATE_POINTS, (-0.500000, 0.309017, -0.809017), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 27, 675, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 27, 676, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 27, 677, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 27, 678, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 27, 679, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 27, 680, 0, INTERPOLATE_POINTS, (0.500000, 0.309017, -0.809017), (0.000000, 0.000000, -1.000000), 144 }
led_strip { 28, 700, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 28, 701, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 28, 702, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 28, 703, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 28, 704, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 28, 705, 0, INTERPOLATE_POINTS, (0.309017, 0.809017, -0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 29, 725, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 29, 726, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.000000, 1.000000, 0.000000), 144 }
led_strip { 29, 727, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 29, 728, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (0.000000, 0.525731, -0.850651), 144 }
led_strip { 29, 729, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 29, 730, 0, INTERPOLATE_POINTS, (-0.309017, 0.809017, -0.500000), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 30, 750, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 30, 751, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 30, 752, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 30, 753, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 30, 754, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 30, 755, 0, INTERPOLATE_POINTS, (1.000000, 0.000000, 0.000000), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 31, 775, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 31, 776, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 31, 777, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.500000, 0.309017, 0.809017), 144 }
led_strip { 31, 778, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 31, 779, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 31, 780, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, 0.309017), (0.809017, 0.500000, -0.309017), 144 }
led_strip { 32, 800, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 32, 801, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.809017, -0.500000, -0.309017), 144 }
led_strip { 32, 802, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 32, 803, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.850651, 0.000000, 0.525731), 144 }
led_strip { 32, 804, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.500000, -0.309017, 0.809017), 144 }
led_strip { 32, 805, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.309017), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 33, 825, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 33, 826, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 33, 827, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, 0.500000, -0.309017), 144 } led_strip { 33, 829, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 33, 830, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 34, 850, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 34, 851, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.500000, 0.309017, 0.809017), 144 }
led_strip { 34, 852, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 34, 853, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 34, 854, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-0.809017, 0.500000, -0.309017), 144 }
led_strip { 34, 855, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, 0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 35, 875, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.850651, 0.000000, 0.525731), 144 }
led_strip { 35, 876, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 35, 877, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.809017, -0.500000, -0.309017), 144 }
led_strip { 35, 878, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 35, 879, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, 0.309017), (-0.309017, -0.809017, 0.500000), 144 } led_strip { 36, 900, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 36, 901, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 36, 902, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.500000, 0.309017, -0.809017), 144 }
led_strip { 36, 903, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 36, 904, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 36, 905, 0, INTERPOLATE_POINTS, (-0.809017, 0.500000, -0.309017), (-0.809017, 0.500000, 0.309017), 144 }
led_strip { 37, 925, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 37, 926, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.809017, -0.500000, 0.309017), 144 }
led_strip { 37, 927, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-1.000000, 0.000000, 0.000000), 144 }
led_strip { 37, 928, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.850651, 0.000000, -0.525731), 144 }
led_strip { 37, 929, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.500000, -0.309017, -0.809017), 144 }
led_strip { 37, 930, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.309017), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 38, 950, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 38, 951, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.809017, 0.500000, 0.309017), 144 }
led_strip { 38, 952, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 38, 953, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 38, 954, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.500000, 0.309017, -0.809017), 144 }
led_strip { 38, 955, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.309017), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 39, 975, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 39, 976, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 39, 977, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.500000, -0.309017, -0.809017), 144 }
led_strip { 39, 978, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.850651, 0.000000, -0.525731), 144 }
led_strip { 39, 979, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (1.000000, 0.000000, 0.000000), 144 }
led_strip { 39, 980, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, -0.309017), (0.809017, -0.500000, 0.309017), 144 }
led_strip { 40, 1000, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.525731, 0.850651, 0.000000), 144 }
led_strip { 40, 1001, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.309017, 0.809017, -0.500000), 144 }
led_strip { 40, 1002, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.309017, 0.809017, -0.500000), 144 }
led_strip { 40, 1003, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.525731, 0.850651, 0.000000), 144 }
led_strip { 40, 1004, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (-0.309017, 0.809017, 0.500000), 144 }
led_strip { 40, 1005, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.309017, 0.809017, 0.500000), 144 }
led_strip { 41, 1025, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.525731, -0.850651, 0.000000), 144 }
led_strip { 41, 1026, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.309017, -0.809017, 0.500000), 144 }
led_strip { 41, 1027, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.309017, -0.809017, 0.500000), 144 }
led_strip { 41, 1028, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.525731, -0.850651, 0.000000), 144 }
led_strip { 41, 1029, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (-0.309017, -0.809017, -0.500000), 144 }
led_strip { 41, 1030, 0, INTERPOLATE_POINTS, (0.000000, -1.000000, 0.000000), (0.309017, -0.809017, -0.500000), 144 }
led_strip { 0, 5, 0, INTERPOLATE_POINTS, (-0.005654, 0.530914, 0.844235), (-0.005654, 0.662347, 1.056898), 144 }
led_strip { 0, 6, 0, INTERPOLATE_POINTS, (0.005654, 0.651981, 1.069729), (0.005654, 0.520548, 0.857067), 144 }
led_strip { 0, 7, 0, INTERPOLATE_POINTS, (-0.009149, 0.521766, 0.849889), (-0.009149, 0.653199, 1.062552), 144 }
led_strip { 0, 8, 0, INTERPOLATE_POINTS, (0.002160, 0.642832, 1.075384), (0.002160, 0.511399, 0.862721), 144 }
led_strip { 1, 30, 0, INTERPOLATE_POINTS, (0.005654, -0.530914, 0.844235), (0.005654, -0.662347, 1.056898), 144 }
led_strip { 1, 31, 0, INTERPOLATE_POINTS, (-0.005654, -0.651981, 1.069729), (-0.005654, -0.520548, 0.857067), 144 }
led_strip { 1, 32, 0, INTERPOLATE_POINTS, (0.009149, -0.521766, 0.849889), (0.009149, -0.653199, 1.062552), 144 }
led_strip { 1, 33, 0, INTERPOLATE_POINTS, (-0.002160, -0.642832, 1.075384), (-0.002160, -0.511399, 0.862721), 144 }
led_strip { 2, 55, 0, INTERPOLATE_POINTS, (-0.005654, -0.530914, -0.844235), (-0.005654, -0.662347, -1.056898), 144 }
led_strip { 2, 56, 0, INTERPOLATE_POINTS, (0.005654, -0.651981, -1.069729), (0.005654, -0.520548, -0.857067), 144 }
led_strip { 2, 57, 0, INTERPOLATE_POINTS, (-0.009149, -0.521766, -0.849889), (-0.009149, -0.653199, -1.062552), 144 }
led_strip { 2, 58, 0, INTERPOLATE_POINTS, (0.002160, -0.642832, -1.075384), (0.002160, -0.511399, -0.862721), 144 }
led_strip { 3, 80, 0, INTERPOLATE_POINTS, (0.005654, 0.530914, -0.844235), (0.005654, 0.662347, -1.056898), 144 }
led_strip { 3, 81, 0, INTERPOLATE_POINTS, (-0.005654, 0.651981, -1.069729), (-0.005654, 0.520548, -0.857067), 144 }
led_strip { 3, 82, 0, INTERPOLATE_POINTS, (0.009149, 0.521766, -0.849889), (0.009149, 0.653199, -1.062552), 144 }
led_strip { 3, 83, 0, INTERPOLATE_POINTS, (-0.002160, 0.642832, -1.075384), (-0.002160, 0.511399, -0.862721), 144 }
led_strip { 4, 105, 0, INTERPOLATE_POINTS, (0.849889, 0.009149, 0.521766), (1.062552, 0.009149, 0.653199), 144 }
led_strip { 4, 106, 0, INTERPOLATE_POINTS, (1.064075, -0.009149, 0.661129), (0.851413, -0.009149, 0.529696), 144 }
led_strip { 4, 107, 0, INTERPOLATE_POINTS, (0.844235, 0.005654, 0.530914), (1.056898, 0.005654, 0.662347), 144 }
led_strip { 4, 108, 0, INTERPOLATE_POINTS, (1.058421, -0.012643, 0.670278), (0.845758, -0.012643, 0.538845), 144 }
led_strip { 5, 130, 0, INTERPOLATE_POINTS, (-0.844235, 0.005654, 0.530914), (-1.056898, 0.005654, 0.662347), 144 }
led_strip { 5, 131, 0, INTERPOLATE_POINTS, (-1.069729, -0.005654, 0.651981), (-0.857067, -0.005654, 0.520548), 144 }
led_strip { 5, 132, 0, INTERPOLATE_POINTS, (-0.849889, 0.009149, 0.521766), (-1.062552, 0.009149, 0.653199), 144 }
led_strip { 5, 133, 0, INTERPOLATE_POINTS, (-1.075384, -0.002160, 0.642832), (-0.862721, -0.002160, 0.511399), 144 }
led_strip { 6, 155, 0, INTERPOLATE_POINTS, (-0.849889, 0.009149, -0.521766), (-1.062552, 0.009149, -0.653199), 144 }
led_strip { 6, 156, 0, INTERPOLATE_POINTS, (-1.064075, -0.009149, -0.661129), (-0.851413, -0.009149, -0.529696), 144 }
led_strip { 6, 157, 0, INTERPOLATE_POINTS, (-0.844235, 0.005654, -0.530914), (-1.056898, 0.005654, -0.662347), 144 }
led_strip { 6, 158, 0, INTERPOLATE_POINTS, (-1.058421, -0.012643, -0.670278), (-0.845758, -0.012643, -0.538845), 144 }
led_strip { 7, 180, 0, INTERPOLATE_POINTS, (0.853383, 0.000000, -0.516112), (1.066046, 0.000000, -0.647545), 144 }
led_strip { 7, 181, 0, INTERPOLATE_POINTS, (1.060581, 0.000000, -0.666783), (0.847918, 0.000000, -0.535351), 144 }
led_strip { 7, 182, 0, INTERPOLATE_POINTS, (0.849889, -0.009149, -0.521766), (1.062552, -0.009149, -0.653199), 144 }
led_strip { 7, 183, 0, INTERPOLATE_POINTS, (1.057086, -0.009149, -0.672437), (0.844424, -0.009149, -0.541005), 144 }
led_strip { 8, 205, 0, INTERPOLATE_POINTS, (0.530914, 0.844235, -0.005654), (0.662347, 1.056898, -0.005654), 144 }
led_strip { 8, 206, 0, INTERPOLATE_POINTS, (0.651981, 1.069729, 0.005654), (0.520548, 0.857067, 0.005654), 144 }
led_strip { 8, 207, 0, INTERPOLATE_POINTS, (0.521766, 0.849889, -0.009149), (0.653199, 1.062552, -0.009149), 144 }
led_strip { 8, 208, 0, INTERPOLATE_POINTS, (0.642832, 1.075384, 0.002160), (0.511399, 0.862721, 0.002160), 144 }
led_strip { 9, 230, 0, INTERPOLATE_POINTS, (-0.530914, 0.844235, -0.005654), (-0.662347, 1.056898, -0.005654), 144 }
led_strip { 9, 231, 0, INTERPOLATE_POINTS, (-0.651981, 1.069729, 0.005654), (-0.520548, 0.857067, 0.005654), 144 }
led_strip { 9, 232, 0, INTERPOLATE_POINTS, (-0.530914, 0.844235, 0.005654), (-0.662347, 1.056898, 0.005654), 144 }
led_strip { 9, 233, 0, INTERPOLATE_POINTS, (-0.651981, 1.069729, 0.016962), (-0.520548, 0.857067, 0.016962), 144 }
led_strip { 10, 255, 0, INTERPOLATE_POINTS, (-0.530914, -0.844235, 0.005654), (-0.662347, -1.056898, 0.005654), 144 }
led_strip { 10, 256, 0, INTERPOLATE_POINTS, (-0.651981, -1.069729, -0.005654), (-0.520548, -0.857067, -0.005654), 144 }
led_strip { 10, 257, 0, INTERPOLATE_POINTS, (-0.530914, -0.844235, -0.005654), (-0.662347, -1.056898, -0.005654), 144 }
led_strip { 10, 258, 0, INTERPOLATE_POINTS, (-0.651981, -1.069729, -0.016962), (-0.520548, -0.857067, -0.016962), 144 }
led_strip { 11, 280, 0, INTERPOLATE_POINTS, (0.530914, -0.844235, 0.005654), (0.662347, -1.056898, 0.005654), 144 }
led_strip { 11, 281, 0, INTERPOLATE_POINTS, (0.651981, -1.069729, -0.005654), (0.520548, -0.857067, -0.005654), 144 }
led_strip { 11, 282, 0, INTERPOLATE_POINTS, (0.521766, -0.849889, 0.009149), (0.653199, -1.062552, 0.009149), 144 }
led_strip { 11, 283, 0, INTERPOLATE_POINTS, (0.642832, -1.075384, -0.002160), (0.511399, -0.862721, -0.002160), 144 }
led_strip { 12, 306, 0, INTERPOLATE_POINTS, (0.000000, 0.009619, 0.997267), (0.000000, 0.009619, 1.247267), 144 }
led_strip { 12, 307, 0, INTERPOLATE_POINTS, (0.000000, -0.009619, 1.252733), (0.000000, -0.009619, 1.002733), 144 }
led_strip { 12, 308, 0, INTERPOLATE_POINTS, (-0.008090, 0.005000, 0.996910), (-0.008090, 0.005000, 1.246910), 144 }
led_strip { 12, 309, 0, INTERPOLATE_POINTS, (-0.008090, -0.014239, 1.252375), (-0.008090, -0.014239, 1.002375), 144 }
led_strip { 13, 331, 0, INTERPOLATE_POINTS, (0.506416, 0.303363, 0.803834), (0.631416, 0.380617, 1.006088), 144 }
led_strip { 13, 332, 0, INTERPOLATE_POINTS, (0.618584, 0.391925, 1.016455), (0.493584, 0.314671, 0.814200), 144 }
led_strip { 13, 333, 0, INTERPOLATE_POINTS, (0.505000, 0.312107, 0.800927), (0.630000, 0.389361, 1.003181), 144 }
led_strip { 13, 334, 0, INTERPOLATE_POINTS, (0.617168, 0.400670, 1.013548), (0.492168, 0.323415, 0.811293), 144 }
led_strip { 14, 356, 0, INTERPOLATE_POINTS, (-0.490851, 0.312982, 0.809779), (-0.615851, 0.390236, 1.012033), 144 }
led_strip { 14, 357, 0, INTERPOLATE_POINTS, (-0.634149, 0.382306, 1.010509), (-0.509149, 0.305052, 0.808255), 144 }
led_strip { 14, 358, 0, INTERPOLATE_POINTS, (-0.496910, 0.317107, 0.804017), (-0.621910, 0.394361, 1.006271), 144 }
led_strip { 14, 359, 0, INTERPOLATE_POINTS, (-0.640207, 0.386431, 1.004748), (-0.515207, 0.309177, 0.802493), 144 }
led_strip { 15, 381, 0, INTERPOLATE_POINTS, (0.312982, 0.809779, 0.490851), (0.390236, 1.012033, 0.615851), 144 }
led_strip { 15, 382, 0, INTERPOLATE_POINTS, (0.382306, 1.010509, 0.634149), (0.305052, 0.808255, 0.509149), 144 }
led_strip { 15, 383, 0, INTERPOLATE_POINTS, (0.304017, 0.812107, 0.491910), (0.381271, 1.014361, 0.616910), 144 }
led_strip { 15, 384, 0, INTERPOLATE_POINTS, (0.373341, 1.012838, 0.635207), (0.296086, 0.810584, 0.510207), 144 }
led_strip { 16, 406, 0, INTERPOLATE_POINTS, (-0.312982, 0.809779, 0.490851), (-0.390236, 1.012033, 0.615851), 144 }
led_strip { 16, 407, 0, INTERPOLATE_POINTS, (-0.382306, 1.010509, 0.634149), (-0.305052, 0.808255, 0.509149), 144 }
led_strip { 16, 408, 0, INTERPOLATE_POINTS, (-0.317107, 0.804017, 0.496910), (-0.394361, 1.006271, 0.621910), 144 }
led_strip { 16, 409, 0, INTERPOLATE_POINTS, (-0.386431, 1.004748, 0.640207), (-0.309177, 0.802493, 0.515207), 144 }
led_strip { 17, 431, 0, INTERPOLATE_POINTS, (0.506416, -0.303363, 0.803834), (0.631416, -0.380617, 1.006088), 144 }
led_strip { 17, 432, 0, INTERPOLATE_POINTS, (0.618584, -0.391925, 1.016455), (0.493584, -0.314671, 0.814200), 144 }
led_strip { 17, 433, 0, INTERPOLATE_POINTS, (0.500000, -0.299017, 0.809017), (0.625000, -0.376271, 1.011271), 144 }
led_strip { 17, 434, 0, INTERPOLATE_POINTS, (0.612168, -0.387580, 1.021638), (0.487168, -0.310325, 0.819384), 144 }
led_strip { 18, 456, 0, INTERPOLATE_POINTS, (-0.506416, -0.303363, 0.803834), (-0.631416, -0.380617, 1.006088), 144 }
led_strip { 18, 457, 0, INTERPOLATE_POINTS, (-0.618584, -0.391925, 1.016455), (-0.493584, -0.314671, 0.814200), 144 }
led_strip { 18, 458, 0, INTERPOLATE_POINTS, (-0.505000, -0.312107, 0.800927), (-0.630000, -0.389361, 1.003181), 144 }
led_strip { 18, 459, 0, INTERPOLATE_POINTS, (-0.617168, -0.400670, 1.013548), (-0.492168, -0.323415, 0.811293), 144 }
led_strip { 19, 481, 0, INTERPOLATE_POINTS, (-0.303363, -0.803834, 0.506416), (-0.380617, -1.006088, 0.631416), 144 }
led_strip { 19, 482, 0, INTERPOLATE_POINTS, (-0.391925, -1.016455, 0.618584), (-0.314671, -0.814200, 0.493584), 144 }
led_strip { 19, 483, 0, INTERPOLATE_POINTS, (-0.312107, -0.800927, 0.505000), (-0.389361, -1.003181, 0.630000), 144 }
led_strip { 19, 484, 0, INTERPOLATE_POINTS, (-0.400670, -1.013548, 0.617168), (-0.323415, -0.811293, 0.492168), 144 }
led_strip { 20, 506, 0, INTERPOLATE_POINTS, (0.312982, -0.809779, 0.490851), (0.390236, -1.012033, 0.615851), 144 }
led_strip { 20, 507, 0, INTERPOLATE_POINTS, (0.382306, -1.010509, 0.634149), (0.305052, -0.808255, 0.509149), 144 }
led_strip { 20, 508, 0, INTERPOLATE_POINTS, (0.317107, -0.804017, 0.496910), (0.394361, -1.006271, 0.621910), 144 }
led_strip { 20, 509, 0, INTERPOLATE_POINTS, (0.386431, -1.004748, 0.640207), (0.309177, -0.802493, 0.515207), 144 }
led_strip { 21, 531, 0, INTERPOLATE_POINTS, (0.000000, 0.009619, -0.997267), (0.000000, 0.009619, -1.247267), 144 }
led_strip { 21, 532, 0, INTERPOLATE_POINTS, (0.000000, -0.009619, -1.252733), (0.000000, -0.009619, -1.002733), 144 }
led_strip { 21, 533, 0, INTERPOLATE_POINTS, (0.008090, 0.005000, -0.996910), (0.008090, 0.005000, -1.246910), 144 }
led_strip { 21, 534, 0, INTERPOLATE_POINTS, (0.008090, -0.014239, -1.252375), (0.008090, -0.014239, -1.002375), 144 }
led_strip { 22, 556, 0, INTERPOLATE_POINTS, (-0.506416, -0.303363, -0.803834), (-0.631416, -0.380617, -1.006088), 144 }
led_strip { 22, 557, 0, INTERPOLATE_POINTS, (-0.618584, -0.391925, -1.016455), (-0.493584, -0.314671, -0.814200), 144 }
led_strip { 22, 558, 0, INTERPOLATE_POINTS, (-0.500000, -0.299017, -0.809017), (-0.625000, -0.376271, -1.011271), 144 }
led_strip { 22, 559, 0, INTERPOLATE_POINTS, (-0.612168, -0.387580, -1.021638), (-0.487168, -0.310325, -0.819384), 144 }
led_strip { 23, 581, 0, INTERPOLATE_POINTS, (0.506416, -0.303363, -0.803834), (0.631416, -0.380617, -1.006088), 144 }
led_strip { 23, 582, 0, INTERPOLATE_POINTS, (0.618584, -0.391925, -1.016455), (0.493584, -0.314671, -0.814200), 144 }
led_strip { 23, 583, 0, INTERPOLATE_POINTS, (0.505000, -0.312107, -0.800927), (0.630000, -0.389361, -1.003181), 144 }
led_strip { 23, 584, 0, INTERPOLATE_POINTS, (0.617168, -0.400670, -1.013548), (0.492168, -0.323415, -0.811293), 144 }
led_strip { 24, 606, 0, INTERPOLATE_POINTS, (-0.312982, -0.809779, -0.490851), (-0.390236, -1.012033, -0.615851), 144 }
led_strip { 24, 607, 0, INTERPOLATE_POINTS, (-0.382306, -1.010509, -0.634149), (-0.305052, -0.808255, -0.509149), 144 }
led_strip { 24, 608, 0, INTERPOLATE_POINTS, (-0.317107, -0.804017, -0.496910), (-0.394361, -1.006271, -0.621910), 144 }
led_strip { 24, 609, 0, INTERPOLATE_POINTS, (-0.386431, -1.004748, -0.640207), (-0.309177, -0.802493, -0.515207), 144 }
led_strip { 25, 631, 0, INTERPOLATE_POINTS, (0.312982, -0.809779, -0.490851), (0.390236, -1.012033, -0.615851), 144 }
led_strip { 25, 632, 0, INTERPOLATE_POINTS, (0.382306, -1.010509, -0.634149), (0.305052, -0.808255, -0.509149), 144 }
led_strip { 25, 633, 0, INTERPOLATE_POINTS, (0.304017, -0.812107, -0.491910), (0.381271, -1.014361, -0.616910), 144 }
led_strip { 25, 634, 0, INTERPOLATE_POINTS, (0.373341, -1.012838, -0.635207), (0.296086, -0.810584, -0.510207), 144 }
led_strip { 26, 656, 0, INTERPOLATE_POINTS, (-0.490851, 0.312982, -0.809779), (-0.615851, 0.390236, -1.012033), 144 }
led_strip { 26, 657, 0, INTERPOLATE_POINTS, (-0.634149, 0.382306, -1.010509), (-0.509149, 0.305052, -0.808255), 144 }
led_strip { 26, 658, 0, INTERPOLATE_POINTS, (-0.491910, 0.304017, -0.812107), (-0.616910, 0.381271, -1.014361), 144 }
led_strip { 26, 659, 0, INTERPOLATE_POINTS, (-0.635207, 0.373341, -1.012838), (-0.510207, 0.296086, -0.810584), 144 }
led_strip { 27, 681, 0, INTERPOLATE_POINTS, (0.490851, 0.312982, -0.809779), (0.615851, 0.390236, -1.012033), 144 }
led_strip { 27, 682, 0, INTERPOLATE_POINTS, (0.634149, 0.382306, -1.010509), (0.509149, 0.305052, -0.808255), 144 }
led_strip { 27, 683, 0, INTERPOLATE_POINTS, (0.496910, 0.317107, -0.804017), (0.621910, 0.394361, -1.006271), 144 }
led_strip { 27, 684, 0, INTERPOLATE_POINTS, (0.640207, 0.386431, -1.004748), (0.515207, 0.309177, -0.802493), 144 }
led_strip { 28, 706, 0, INTERPOLATE_POINTS, (0.312982, 0.809779, -0.490851), (0.390236, 1.012033, -0.615851), 144 }
led_strip { 28, 707, 0, INTERPOLATE_POINTS, (0.382306, 1.010509, -0.634149), (0.305052, 0.808255, -0.509149), 144 }
led_strip { 28, 708, 0, INTERPOLATE_POINTS, (0.317107, 0.804017, -0.496910), (0.394361, 1.006271, -0.621910), 144 }
led_strip { 28, 709, 0, INTERPOLATE_POINTS, (0.386431, 1.004748, -0.640207), (0.309177, 0.802493, -0.515207), 144 }
led_strip { 29, 731, 0, INTERPOLATE_POINTS, (-0.312982, 0.809779, -0.490851), (-0.390236, 1.012033, -0.615851), 144 }
led_strip { 29, 732, 0, INTERPOLATE_POINTS, (-0.382306, 1.010509, -0.634149), (-0.305052, 0.808255, -0.509149), 144 }
led_strip { 29, 733, 0, INTERPOLATE_POINTS, (-0.304017, 0.812107, -0.491910), (-0.381271, 1.014361, -0.616910), 144 }
led_strip { 29, 734, 0, INTERPOLATE_POINTS, (-0.373341, 1.012838, -0.635207), (-0.296086, 0.810584, -0.510207), 144 }
led_strip { 30, 756, 0, INTERPOLATE_POINTS, (0.997267, 0.000000, -0.009619), (1.247267, 0.000000, -0.009619), 144 }
led_strip { 30, 757, 0, INTERPOLATE_POINTS, (1.252733, 0.000000, 0.009619), (1.002733, 0.000000, 0.009619), 144 }
led_strip { 30, 758, 0, INTERPOLATE_POINTS, (0.996910, 0.008090, -0.005000), (1.246910, 0.008090, -0.005000), 144 }
led_strip { 30, 759, 0, INTERPOLATE_POINTS, (1.252375, 0.008090, 0.014239), (1.002375, 0.008090, 0.014239), 144 }
led_strip { 31, 781, 0, INTERPOLATE_POINTS, (0.803834, 0.506416, 0.303363), (1.006088, 0.631416, 0.380617), 144 }
led_strip { 31, 782, 0, INTERPOLATE_POINTS, (1.016455, 0.618584, 0.391925), (0.814200, 0.493584, 0.314671), 144 }
led_strip { 31, 783, 0, INTERPOLATE_POINTS, (0.800927, 0.505000, 0.312107), (1.003181, 0.630000, 0.389361), 144 }
led_strip { 31, 784, 0, INTERPOLATE_POINTS, (1.013548, 0.617168, 0.400670), (0.811293, 0.492168, 0.323415), 144 }
led_strip { 32, 806, 0, INTERPOLATE_POINTS, (0.803834, -0.506416, 0.303363), (1.006088, -0.631416, 0.380617), 144 }
led_strip { 32, 807, 0, INTERPOLATE_POINTS, (1.016455, -0.618584, 0.391925), (0.814200, -0.493584, 0.314671), 144 }
led_strip { 32, 808, 0, INTERPOLATE_POINTS, (0.809017, -0.500000, 0.299017), (1.011271, -0.625000, 0.376271), 144 }
led_strip { 32, 809, 0, INTERPOLATE_POINTS, (1.021638, -0.612168, 0.387580), (0.819384, -0.487168, 0.310325), 144 }
led_strip { 33, 831, 0, INTERPOLATE_POINTS, (-0.997267, 0.000000, 0.009619), (-1.247267, 0.000000, 0.009619), 144 }
led_strip { 33, 832, 0, INTERPOLATE_POINTS, (-1.252733, 0.000000, -0.009619), (-1.002733, 0.000000, -0.009619), 144 }
led_strip { 33, 833, 0, INTERPOLATE_POINTS, (-0.996910, 0.008090, 0.005000), (-1.246910, 0.008090, 0.005000), 144 }
led_strip { 33, 834, 0, INTERPOLATE_POINTS, (-1.252375, 0.008090, -0.014239), (-1.002375, 0.008090, -0.014239), 144 }
led_strip { 34, 856, 0, INTERPOLATE_POINTS, (-0.809779, 0.490851, 0.312982), (-1.012033, 0.615851, 0.390236), 144 }
led_strip { 34, 857, 0, INTERPOLATE_POINTS, (-1.010509, 0.634149, 0.382306), (-0.808255, 0.509149, 0.305052), 144 }
led_strip { 34, 858, 0, INTERPOLATE_POINTS, (-0.804017, 0.496910, 0.317107), (-1.006271, 0.621910, 0.394361), 144 }
led_strip { 34, 859, 0, INTERPOLATE_POINTS, (-1.004748, 0.640207, 0.386431), (-0.802493, 0.515207, 0.309177), 144 }
led_strip { 35, 881, 0, INTERPOLATE_POINTS, (-0.809779, -0.490851, 0.312982), (-1.012033, -0.615851, 0.390236), 144 }
led_strip { 35, 882, 0, INTERPOLATE_POINTS, (-1.010509, -0.634149, 0.382306), (-0.808255, -0.509149, 0.305052), 144 }
led_strip { 35, 883, 0, INTERPOLATE_POINTS, (-0.812107, -0.491910, 0.304017), (-1.014361, -0.616910, 0.381271), 144 }
led_strip { 35, 884, 0, INTERPOLATE_POINTS, (-1.012838, -0.635207, 0.373341), (-0.810584, -0.510207, 0.296086), 144 }
led_strip { 36, 906, 0, INTERPOLATE_POINTS, (-0.803834, 0.506416, -0.303363), (-1.006088, 0.631416, -0.380617), 144 }
led_strip { 36, 907, 0, INTERPOLATE_POINTS, (-1.016455, 0.618584, -0.391925), (-0.814200, 0.493584, -0.314671), 144 }
led_strip { 36, 908, 0, INTERPOLATE_POINTS, (-0.800927, 0.505000, -0.312107), (-1.003181, 0.630000, -0.389361), 144 }
led_strip { 36, 909, 0, INTERPOLATE_POINTS, (-1.013548, 0.617168, -0.400670), (-0.811293, 0.492168, -0.323415), 144 }
led_strip { 37, 931, 0, INTERPOLATE_POINTS, (-0.803834, -0.506416, -0.303363), (-1.006088, -0.631416, -0.380617), 144 }
led_strip { 37, 932, 0, INTERPOLATE_POINTS, (-1.016455, -0.618584, -0.391925), (-0.814200, -0.493584, -0.314671), 144 }
led_strip { 37, 933, 0, INTERPOLATE_POINTS, (-0.809017, -0.500000, -0.299017), (-1.011271, -0.625000, -0.376271), 144 }
led_strip { 37, 934, 0, INTERPOLATE_POINTS, (-1.021638, -0.612168, -0.387580), (-0.819384, -0.487168, -0.310325), 144 }
led_strip { 38, 956, 0, INTERPOLATE_POINTS, (0.803834, 0.506416, -0.303363), (1.006088, 0.631416, -0.380617), 144 }
led_strip { 38, 957, 0, INTERPOLATE_POINTS, (1.016455, 0.618584, -0.391925), (0.814200, 0.493584, -0.314671), 144 }
led_strip { 38, 958, 0, INTERPOLATE_POINTS, (0.809017, 0.500000, -0.299017), (1.011271, 0.625000, -0.376271), 144 }
led_strip { 38, 959, 0, INTERPOLATE_POINTS, (1.021638, 0.612168, -0.387580), (0.819384, 0.487168, -0.310325), 144 }
led_strip { 39, 981, 0, INTERPOLATE_POINTS, (0.803834, -0.506416, -0.303363), (1.006088, -0.631416, -0.380617), 144 }
led_strip { 39, 982, 0, INTERPOLATE_POINTS, (1.016455, -0.618584, -0.391925), (0.814200, -0.493584, -0.314671), 144 }
led_strip { 39, 983, 0, INTERPOLATE_POINTS, (0.800927, -0.505000, -0.312107), (1.003181, -0.630000, -0.389361), 144 }
led_strip { 39, 984, 0, INTERPOLATE_POINTS, (1.013548, -0.617168, -0.400670), (0.811293, -0.492168, -0.323415), 144 }
led_strip { 40, 1006, 0, INTERPOLATE_POINTS, (0.009619, 0.997267, 0.000000), (0.009619, 1.247267, 0.000000), 144 }
led_strip { 40, 1007, 0, INTERPOLATE_POINTS, (-0.009619, 1.252733, 0.000000), (-0.009619, 1.002733, 0.000000), 144 }
led_strip { 40, 1008, 0, INTERPOLATE_POINTS, (0.005000, 0.996910, -0.008090), (0.005000, 1.246910, -0.008090), 144 }
led_strip { 40, 1009, 0, INTERPOLATE_POINTS, (-0.014239, 1.252375, -0.008090), (-0.014239, 1.002375, -0.008090), 144 }
led_strip { 41, 1031, 0, INTERPOLATE_POINTS, (0.009619, -0.997267, 0.000000), (0.009619, -1.247267, 0.000000), 144 }
led_strip { 41, 1032, 0, INTERPOLATE_POINTS, (-0.009619, -1.252733, 0.000000), (-0.009619, -1.002733, 0.000000), 144 }
led_strip { 41, 1033, 0, INTERPOLATE_POINTS, (0.005000, -0.996910, 0.008090), (0.005000, -1.246910, 0.008090), 144 }
led_strip { 41, 1034, 0, INTERPOLATE_POINTS, (-0.014239, -1.252375, 0.008090), (-0.014239, -1.002375, 0.008090), 144 }
END_OF_ASSEMBLY_FILE

View File

@ -0,0 +1,20 @@
led_strip_count 16
led_strip { 0, 1, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (1.0, 0.75, 0.0), 90 }
led_strip { 0, 2, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.66, 0.75, 0.33), 90 }
led_strip { 0, 3, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.33, 0.75, 0.66), 90 }
led_strip { 0, 4, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.0, 0.75, 1.0), 90 }
led_strip { 0, 5, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (-0.33, 0.75, 0.66), 90 }
led_strip { 0, 6, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (-0.66, 0.75, 0.33), 90 }
led_strip { 0, 7, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (-1.0, 0.75, 0.0), 90 }
led_strip { 0, 8, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (-0.66, 0.75, -0.33), 90 }
led_strip { 0, 9, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (-0.33, 0.75, -0.66), 90 }
led_strip { 0, 10, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.0, 0.75, -1.0), 90 }
led_strip { 0, 11, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.33, 0.75, -0.66), 90 }
led_strip { 0, 12, 0, INTERPOLATE_POINTS, (0.0, 0.75, 0.0), (0.66, 0.75, -0.33), 90 }
led_strip { 0, 41, 0, INTERPOLATE_POINTS, (0.05, -0.75, 0.0), (0.05, 0.0, 0.0), 170 }
led_strip { 0, 42, 0, INTERPOLATE_POINTS, (0.05, 0.0, 0.0), (0.05, 0.75, 0.0), 130 }
led_strip { 0, 43, 0, INTERPOLATE_POINTS, (-0.05, -0.75, 0.0), (-0.05, 0.0, 0.0), 170 }
led_strip { 0, 44, 0, INTERPOLATE_POINTS, (-0.05, 0.0, 0.0), (-0.05, 0.75, 0.0), 130 }
END_OF_ASSEMBLY_FILE

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -0,0 +1,14 @@
control_box_count 4
led_strip_count 4
control_box { 0, "192.168.0.1", (1, 1, 1) }
control_box { 1, "192.168.0.2", (-1, 1, 1) }
control_box { 2, "192.168.0.3", (-1, 1, -1) }
control_box { 3, "192.168.0.4", (1, 1, -1) }
led_strip { 0, 1, 0, INTERPOLATE_POINTS, (1.0, 1.0, 1.0), (-1.0, 1.0, 1.0), 144 }
led_strip { 1, 2, 0, INTERPOLATE_POINTS, (-1.0, 1.0, 1.0), (-1.0, 1.0, -1.0), 144 }
led_strip { 2, 3, 0, INTERPOLATE_POINTS, (-1.0, 1.0, -1.0), (1.0, 1.0, -1.0), 144 }
led_strip { 3, 4, 0, INTERPOLATE_POINTS, (1.0, 1.0, -1.0), (1.0, 1.0, 1.0), 144 }
END_OF_ASSEMBLY_FILE

View File

@ -0,0 +1,23 @@
struct hello_struct_t
{
const int x;
float* y;
char hello;
};
union Vector
{
struct {
int X;
int Y;
int Z;
};
int E[3];
};
struct test_def;
int main (int ArgCount, char* Args[])
{
return 0;
}

2
bin/compile.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
build\build_app_msvc_win32_debug.bat

2
bin/debug.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
call remedybg.bat ./app_run_tree/win32_msvc/debug/session.rdbg

View File

@ -0,0 +1,89 @@
const fs = require("fs");
const IN_FILE_PATH_PRIMARY = "../run_tree/data/cities_final.json";
const IN_FILE_PATH_SECONDARY = "../run_tree/data/cities_secondary_final.json";
const OUT_FILE_PATH = "../src_v2/user_space/incenter_gen_cities.h"
function print_city_desc (city, prefix, dest, gets_own_universe)
{
const city_ascii = city.city_ascii
.toLowerCase()
.replaceAll(' ', '_')
.replaceAll('-', '_')
.replaceAll('\'', '')
.replaceAll('`', '');
const city_id = `${prefix}_${city_ascii}`;
const { lat, lng } = city;
dest.enum_out += ` ${city_id} = ${dest.enum_counter++},\n`;
const universe = gets_own_universe ? city_id : "incenter_secondary_city_universe";
dest.desc_out += ` [${city_id}] = {
.id = ${city_id},
.lat = ${lat},
.lon = ${lng},
.sacn_universe = ${universe},
},\n`;
dest.strings_out += ` [${city_id}] = "${city_id}",\n`;
}
function main ()
{
const primary_file = fs.readFileSync(IN_FILE_PATH_PRIMARY, {});
const primary_json = JSON.parse(primary_file);
const secondary_file = fs.readFileSync(IN_FILE_PATH_SECONDARY, {});
const secondary_json = JSON.parse(secondary_file);
let out = "// NOTE: This file is autogenerated by csv_to_cstruct.js\n";
let enum_counter = 0;
let enum_out = "// NOTE: These are values for Incenter_City_Id\nenum {\n";
enum_out += ` city_black_rock = ${enum_counter++},\n`;
let desc_out = "global Incenter_City_Desc city_descs[] = {\n";
let strings_out = "global char* city_strings[] = {\n";
let dest = {
enum_counter,
enum_out,
desc_out,
strings_out,
};
primary_json.forEach((city) => {
print_city_desc(city, "city", dest, true);
});
// Add Black Rock City
dest.desc_out += `\n // Black Rock City\n [city_black_rock] = {
.id = city_black_rock,
.lat = -90.0f,
.lon = 0,
.sacn_universe = city_black_rock,
},\n`;
dest.strings_out += ` [city_black_rock] = "city_black_rock",\n`;
dest.enum_out += " city_count,\n";
dest.enum_out += " city_secondary_first = city_count + 1,\n";
secondary_json.forEach((city) => {
print_city_desc(city, "city_secondary", dest, false);
});
dest.enum_out += " city_secondary_count,\n";
dest.enum_out += "};\n\n";
dest.desc_out += "};\n\n";
dest.strings_out += "};\n\n";
out += dest.enum_out;
out += dest.desc_out;
out += dest.strings_out;
fs.writeFileSync(OUT_FILE_PATH, out, {});
}
main();

4
bin/run.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
pushd app_run_tree
start win32_msvc\debug\win32_foldhaus.exe
popd

View File

@ -0,0 +1,11 @@
@echo off
IF NOT "%PrebuildCalled%"=="1" GOTO error
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -end %StatsPath%\%StatsFile% %LastError% )
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -stats %StatsPath%\%StatsFile% )
set PrebuildCalled=0
GOTO:eof
:error
echo ERROR: _prebuild_win32.bat was not called before _postbuild_win32.bat.

31
build/_prebuild_win32.bat Normal file
View File

@ -0,0 +1,31 @@
@echo off
REM This file takes three arguments
REM 1 = "app" or "meta"
REM 2 = "debug" or "release"
REM 3 = "msvc" or "clang"
set PrebuildCalled=1
set ProjectDevFolder=%~dp0
set ProjectDevPath=%ProjectDevFolder:~0,-7%
set SourceCodePath=%ProjectDevPath%\src\%1
set MetaProgramPath=%ProjectDevPath%\meta_run_tree\win32_%3\%2
set ProjectRunTree=%ProjectDevPath%\%1_run_tree\win32_%3
set BuildPath=%ProjectRunTree%\%2
set StatsPath=%ProjectRunTree%\stats
set StatsFile=%1_win32_%3_%2_build_time.ctm
IF NOT EXIST %BuildPath% mkdir %BuildPath%
IF NOT EXIST %StatsPath% mkdir %StatsPath%
set CTimePath=C:\apps\ctime
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -begin %StatsPath%\%StatsFile% )
echo.
echo BUILDING TO %BuildPath%
echo STATS IN %StatsPath%\%StatsFile%
echo.

View File

@ -1,412 +1,9 @@
#!/bin/bash
set -e
# --------------------------------------------
# Usage
SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}")
$SCRIPT_REL_DIR/build_.sh debug osx arm64
# $SCRIPT_REL_DIR/build_.sh debug wasm intel
VALID_VALUES_COMPILER=("clang" "clang++" "msvc")
VALID_VALUES_MODE=("debug" "release")
VALID_VALUES_PLATFORM=("win32" "osx" "linux" "raspi" "wasm")
VALID_VALUES_ARCH=("x64" "arm64")
VALID_VALUES_PACKAGE=("true" "false")
printf_r () {
printf "\e[31m$@\e[0m\n"
}
printf_g () {
printf "\e[32m%s\e[0m\n" "$@"
}
print_usage () {
printf "\n"
printf "Build Command Syntax:\n"
printf_g " $0 [compiler] [mode] [platform] [arch] [package]"
printf "\n"
printf "Compiler Options:\n"
printf " \e[32m%s\e[m\n" "${VALID_VALUES_COMPILER[@]}"
printf "\n"
printf "Release Mode Options:\n"
printf " \e[32m%s\e[m\n" "${VALID_VALUES_MODE[@]}"
printf "\n"
printf "Platform Options:\n"
printf " \e[32m%s\e[m\n" "${VALID_VALUES_PLATFORM[@]}"
printf "\n"
printf "Arch Options: \n"
printf " \e[32m%s\e[m\n" "${VALID_VALUES_ARCH[@]}"
printf "\n"
printf "Package Options:\n"
printf_g " 'package' or no flag to omit packaging\n"
printf "\n"
printf "Examples:\n"
printf " $0 clang debug osx arm64\n"
printf " $0 msvc release win32 x64 package\n"
}
OPTS=()
for ((i=1; i<=$#; i+=1)); do
OPTS+=(${!i})
done
if [ "${OPTS[0]}" == "-h" ] || [ "${OPTS[0]}" == "--help" ]
then
print_usage
exit 0
fi
# --------------------------------------------
# Utilities
pushdir () {
command pushd "$@" > /dev/null
}
popdir () {
command popd "$@" > /dev/null
}
# --------------------------------------------
# Project Directory Identification
OLD_PATH=$(pwd)
BUILD_SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
pushdir $BUILD_SCRIPT_DIR
pushdir ..
PROJECT_PATH=$(pwd)
popdir
popdir
BLD_DIR="${PROJECT_PATH}/build"
SRC_DIR="${PROJECT_PATH}/src"
OUT_DIR="${PROJECT_PATH}/run_tree"
# --------------------------------------------
# Input Flag Settings
INPUT_FLAG_UNSET="unset"
COMPILER=$INPUT_FLAG_UNSET
MODE=$INPUT_FLAG_UNSET
PLATFORM=$INPUT_FLAG_UNSET
ARCH=$INPUT_FLAG_UNSET
PACKAGE=$INPUT_FLAG_UNSET
# --------------------------------------------
# Create a local build file if there isn't one
# using local context to determine defaults
BLD_LOCAL_FILE="${BLD_DIR}/build_local.sh"
if [ ! -f $BLD_LOCAL_FILE ]
then
printf "Creating a build/build_local.sh file for you."
printf " Path: ${BLD_LOCAL_FILE}"
printf "This file is excluded in the .gitignore. It is for you to set local compilation targets"
touch $BLD_LOCAL_FILE
printf "#!/bin/bash\n" >> $BLD_LOCAL_FILE
printf "\n" >> $BLD_LOCAL_FILE
printf "COMPILER=\"clang\"\n" >> $BLD_LOCAL_FILE
printf "MODE=\"debug\"\n" >> $BLD_LOCAL_FILE
printf "PLATFORM=\"osx\"\n" >> $BLD_LOCAL_FILE
printf "ARCH=\"arm64\"\n" >> $BLD_LOCAL_FILE
printf "PACKAGE=\"false\"\n" >> $BLD_LOCAL_FILE
printf "TEST_FILE=\"\"\n" >> $BLD_LOCAL_FILE
fi
# --------------------------------------------
# Call Local Build File
source ${BLD_LOCAL_FILE}
# --------------------------------------------
# Use command line arguments to override local
# build file
if [ "${#OPTS[@]}" -gt "0" ]; then
OPTS_COUNT="${#OPTS[@]}"
if [ $OPTS_COUNT -lt "4" ] || [ $OPTS_COUNT -gt "5" ]; then
printf_r "Error: Incorrect number of arguments supplied"
printf " You must either supply all or none of the build script arguments\n"
print_usage
exit 1
fi
COMPILER=${OPTS[0]}
MODE=${OPTS[1]}
PLATFORM=${OPTS[2]}
ARCH=${OPTS[3]}
PACkaGE="false"
if [ $OPTS_COUNT -eq "5" ]; then
if [ "${OPTS[4]}" == "package" ]; then
PACKAGE="true"
else
printf_r "Error: Invalid package command provided: ${PACKAGE}"
printf " You must either supply the 'package' flag or omit it"
exit 1
fi
fi
fi
# --------------------------------------------
# Verify valid values for all inputs
ALL_VALID_VALUES="true"
check_valid_flag () {
local VALID_VALUES_NAME=$1[@]
local VALID_VALUES=("${!VALID_VALUES_NAME}")
local VALUE_GIVEN=$2
local VALUE_ID=$3
if [[ ! " ${VALID_VALUES[*]} " =~ " ${VALUE_GIVEN} " ]]; then
printf_r "Error: Invalid ${VALUE_ID} provided: ${VALUE_GIVEN}"
printf " Must be one of: "
printf_g "${VALID_VALUES[*]}\n"
ALL_VALID_VALUES="false"
fi
}
check_valid_flag VALID_VALUES_COMPILER $COMPILER "compiler"
check_valid_flag VALID_VALUES_MODE $MODE "mode"
check_valid_flag VALID_VALUES_PLATFORM $PLATFORM "platform"
check_valid_flag VALID_VALUES_ARCH $ARCH "arch"
if [[ ! " ${VALID_VALUES_PACKAGE[*]} " =~ " ${PACKAGE} " ]]; then
printf_r "Error: Invalid package provided: ${PACKAGE}"
printf " You must either supply the 'package' flag or omit it"
ALL_VALID_VALUES="false"
fi
if [ "${ALL_VALID_VALUES}" != "true" ]; then
exit 1
fi
if [ "${COMPILER}" == "clang" ] || [ "${COMPILER}" == "clang++" ]; then
LINKER=${COMPILER}
elif [ "${COMPILER}" == "msvc" ]; then
LINKER="link"
fi
printf "Compiler: "
printf_g "${COMPILER}"
printf "Mode: "
printf_g "${MODE}"
printf "Platform: "
printf_g "${PLATFORM}"
printf "Arch: "
printf_g "${ARCH}"
printf "Package: "
printf_g "${PACKAGE}"
# --------------------------------------------
# Hooks Identification
HOOK_PREBUILD="${BLD_DIR}/hook_prebuild.sh"
HOOK_POSTBUILD="${BLD_DIR}/hook_postbuild.sh"
HOOK_PRELINK="${BLD_DIR}/hook_prelink.sh"
HOOK_POSTLINK="${BLD_DIR}/hook_postlink.sh"
printf "\nBuild Hooks:\n"
if [ -f "${HOOK_PREBUILD}" ]; then
printf " Pre Build: ${HOOK_PREBUILD##*/}\n"
else
HOOK_PREBUILD=""
fi
if [ -f "${HOOK_POSTBUILD}" ]; then
printf " Post Build: ${HOOK_POSTBUILD##*/}\n"
else
HOOK_POSTBUILD=""
fi
if [ -f "${HOOK_PRELINK}" ]; then
printf " Pre Link: ${HOOK_PRELINK##*/}\n"
else
HOOK_PRELINK=""
fi
if [ -f "${HOOK_POSTLINK}" ]; then
printf " Post Link: ${HOOK_POSTLINK##*/}\n"
else
HOOK_POSTLINK=""
fi
# --------------------------------------------
# File Parsing Helpers
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo "${var}"
}
load_file_into_lines_array() {
FILE=$1
local FILE_LINES_RAW=()
IFS=$'\r\n'
GLOBIGNORE='*'
command eval 'FILE_LINES_RAW=($(cat $FILE))'
FILE_LINES=()
for i in "${FILE_LINES_RAW[@]}"; do
if [ "${i:0:1}" != "#" ]; then
# strip any trailing comments off the end
# this lets you do things like:
# "compiler>msvc>-FC # full path error"
# where you want to explain a flag
local LINE=$i
local LINE_NO_TRAILING_COMMENT="${LINE% #*}"
FILE_LINES+=($LINE_NO_TRAILING_COMMENT)
fi
done
}
parse_flags_from_selectors() {
SELECTORS=()
for ((i=1; i<=$#; i+=1)); do
SELECTORS+=(${!i})
done
FLAGS=()
for i in "${FILE_LINES[@]}"; do
LINE=$i
FLAG="${LINE##*>}"
INCLUDE_FLAG="true"
while [ "${LINE}" != "${FLAG}" ]; do
NEXT_SELECTOR="${LINE%%>*}"
LINE="${LINE#*>}"
if [[ ! " ${SELECTORS[@]} " =~ " ${NEXT_SELECTOR} " ]]; then
INCLUDE_FLAG="false"
break
fi
done
if [ "${INCLUDE_FLAG}" == "true" ]; then
FLAG=$(trim "${FLAG}")
FLAG=$(eval "echo $FLAG")
FLAGS+=($FLAG)
fi
done
}
load_file_into_lines_array "${BLD_DIR}/build_flags.sh"
# --------------------------------------------
# Assemble Flags
parse_flags_from_selectors "compiler" $COMPILER $MODE $PLATFORM $ARCH
COMPILER_FLAGS=(${FLAGS[@]})
parse_flags_from_selectors "compiler" "input" $PLATFORM $ARCH
COMPILER_INPUTS=(${FLAGS[@]})
parse_flags_from_selectors "linker" "flags" $MODE $PLATFORM $ARCH
LINKER_FLAGS=(${FLAGS[@]})
parse_flags_from_selectors "linker" "libs" $LINKER $MODE $PLATFORM $ARCH
LINKER_LIBRARIES=(${FLAGS[@]})
parse_flags_from_selectors "linker" "output" $LINKER $MODE $PLATFORM $ARCH
LINKER_OUTPUT=(${FLAGS[@]})
# --------------------------------------------
# Create the Run Tree path
OUT_PATH="${OUT_DIR}/${PLATFORM}/${ARCH}/${MODE}"
if [ ! -d $OUT_PATH ]; then
mkdir -p $OUT_PATH
fi
# --------------------------------------------
# Compile The Program
printf "\nBeginning Compilation...\n"
pushdir $OUT_PATH
find . -name "*" -delete > /dev/null
if [[ -f ${HOOK_PREBUILD} ]]; then
source "${HOOK_PREBUILD}"
fi
COMPILATION_SUCCESS="true"
COMPILER_OUTPUT=()
FAILED_COMPILES=()
for i in "${COMPILER_INPUTS[@]}"; do
INPUT="${i}"
INPUT_FILE="${INPUT##*/}"
INPUT_EXTENSION="${INPUT_FILE##*.}"
INPUT_NAME="${INPUT_FILE%.*}"
OUTPUT_FILE="${INPUT_NAME}_${INPUT_EXTENSION}.o"
COMPILER_ARGS="-o ${OUTPUT_FILE} -c ${COMPILER_FLAGS[@]} -DPLATFORM_$PLATFORM=1 -DMODE_$MODE=1 -DARCH_$ARCH=1 $INPUT"
# echo $COMPILER $COMPILER_ARGS
eval $COMPILER $COMPILER_ARGS
if [ $? -eq 0 ]; then
COMPILER_OUTPUT+=(${OUTPUT_FILE})
else
COMPILATION_SUCCESS="false"
FAILED_COMPILES+=(${OUTPUT_FILE})
fi
# TODO: if the output file was a .dll or .lib we don't want to include
# those in the final compilation gather
done
printf "\nCompiler Output\n"
if [ ${#COMPILER_OUTPUT[@]} -gt 0 ]; then
printf " %s \e[32m[SUCCESS]\e[0m\n" "${COMPILER_OUTPUT[@]}"
fi
if [ ${#FAILED_COMPILES[@]} -gt 0 ]; then
printf " %s \e[31m[FAILED]\e[0m\n" "${FAILED_COMPILES[@]}"
fi
printf "\n"
if [[ -f ${HOOK_POSTBUILD} ]]; then
source "${HOOK_POSTBUILD}"
fi
if [ $COMPILATION_SUCCESS != "true" ]; then
printf "Compilation Failed.\n Exiting..."
exit 1
fi
if [[ -f ${HOOK_PRELINK} ]]; then
source "${HOOK_PRELINK}"
fi
LINKER_ARGS="-o ${LINKER_OUTPUT} ${COMPILER_OUTPUT[@]} ${LINKER_FLAGS[@]} ${LINKER_LIBRARIES[@]}"
printf "Linking...\n"
# echo $LINKER $LINKER_ARGS
eval $LINKER $LINKER_ARGS
if [ $? -eq 0 ]; then
printf " Link: "
printf_g "[SUCCEEDED]"
else
printf "\n Link: "
printf_r "[FAILED]"
fi
if [[ -f ${HOOK_POSTLINK} ]]; then
source "${HOOK_POSTLINK}"
fi
popdir
printf "\n"
exit 0
# pushd "run_tree/raspi/arm64/debug"
# clang -o lumenarium /home/pi/dev/Lumenarium/src_v2/platform/raspi/lumenarium_first_raspi.c -lm
# popd

378
build/build_.sh Executable file
View File

@ -0,0 +1,378 @@
#!/bin/bash
# Ensure an error makes the script bail
set -e
# --------------------------------------------
# Usage
print_usage () {
echo
echo Build Command Syntax:
echo " $0 [mode] [platform] [arch]"
echo
echo "Release Mode Options:"
echo " debug"
echo " prod"
echo
echo "Platform Options:"
echo " win32"
echo " osx"
echo " wasm"
echo " raspi"
echo
echo "Arch Options: (architecture)"
echo " intel (valid with Platform Win32 and OSX) (default)"
echo " arm64 (only valid for Platform OSX)"
}
# --------------------------------------------
# Arguments
MODE=$1
PLATFORM=$2
ARCH=$3
PACKAGE=$4
if [ "${MODE}" == "" ] | [ "${PLATFORM}" == "" ]
then
print_usage
exit 0
fi
# Default to Intel architecture if none provided
if [ "${ARCH}" == "" ]
then
ARCH="intel"
fi
if [ "${ARCH}" != "intel" ] && [ "${ARCH}" != "arm64" ]
then
echo "Uknown target architecture: ${ARCH}"
print_usage
exit 0
fi
# --------------------------------------------
# Utilities
pushdir () {
command pushd "$@" > /dev/null
}
popdir () {
command popd "$@" > /dev/null
}
add_flag () {
local -n ref=$1
ref="$ref $2"
}
# --------------------------------------------
# Getting Project Path
#
# Project is stored in PROJECT_PATH
SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}")
pushdir $SCRIPT_REL_DIR
pushdir ..
PROJECT_PATH=$(pwd)
popdir
popdir
# --------------------------------------------
# Platform/Mode Specific Variables
# Compiler Selection
Compiler_win32="cl"
Compiler_osx="clang"
Compiler_raspi="clang"
WasiSdk="/c/drive/apps/wasi-sdk"
Compiler_wasm="$WasiSdk/bin/clang++"
Compiler_linux="clang++"
# Platform Entry Points
PlatformEntry_win32="src_v2/platform/win32/lumenarium_first_win32.cpp"
PlatformEntry_osx="src_v2/platform/osx/lumenarium_first_osx.c"
PlatformEntry_wasm="src_v2/platform/wasm/lumenarium_first_wasm.cpp"
PlatformEntry_linux="src_v2/platform/linux/lumenarium_first_linux.cpp"
PlatformEntry_raspi="src_v2/platform/raspi/lumenarium_first_raspi.c"
# Intermediate Outputs
CompilerOutput_win32="lumenarium.o"
CompilerOutput_osx="lumenarium"
CompilerOutput_wasm="lumenarium.wasm"
CompilerOutput_linux=""
CompilerOutput_raspi="lumenarium"
# Executables
LinkerOutput_win32="lumenarium.exe"
LinkerOutput_osx="lumenarium"
LinkerOutput_wasm="lumenarium.wasm"
LinkerOutput_linux=""
LinkerOutput_raspi="lumenarium"
# Wasm Sys Root
WasmSysRoot="${PROJECT_PATH}/src_v2/platform/wasm/sysroot/"
# Compiler Flags
CompilerFlags_win32="-nologo"
CompilerFlags_win32+=" -FC" # display errors with full path
CompilerFlags_win32+=" -WX" # treat warnings as errors
CompilerFlags_win32+=" -W4" # output warning level
CompilerFlags_win32+=" -Z7" # generate C compatible debug info
# CompilerFlags_win32+="-Oi" # generate intrinsic functions
# CompilerFlags_win32+="-MTd" # create a debug multithreaded exe w/ Libcmtd.lib
# CompilerFlags_win32+="-fp:fast" # fast floating point model
CompilerFlags_win32+=" -wd4505" #
CompilerFlags_win32+=" -wd4100" #
CompilerFlags_win32+=" -wd4189" #
CompilerFlags_win32+=" -wd4702" #
CompilerFlags_win32+=" -wd4996" # _CRT_SECURE_NO_WARNINGS
CompilerFlags_osx=""
CompilerFlags_wasm=""
CompilerFlags_wasm+=" -Wno-writable-strings" #
CompilerFlags_wasm+=" --target=wasm32" #
CompilerFlags_wasm+=" -nostdlib" #
CompilerFlags_wasm+=" -Wl,--no-entry" #
CompilerFlags_wasm+=" -Wl,--allow-undefined" #
CompilerFlags_wasm+=" -Wl,--export-all" #
CompilerFlags_linux=" -pthread"
CompilerFlags_raspi=" -pthread" # "--target=arm-rpi-linux-gnueabihf" # "--target=arm-linux-gnueabihf" #target
CompilerFlags_raspi+=" -lm" # link with local system math libraries
CompilerFlags_DEBUG_win32=""
CompilerFlags_DEBUG_win32+=" -Od" #
CompilerFlags_DEBUG_win32+=" -Zi" #
CompilerFlags_DEBUG_win32+=" -DDEBUG" #
# add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
CompilerFlags_DEBUG="-O0"
CompilerFlags_DEBUG+=" -g" #
CompilerFlags_DEBUG+=" -DDEBUG" #
if [ "${PLATFORM}" != "raspi" ]
then
CompilerFlags_DEBUG+=" -fsanitize=address" #address sanitizer
fi
CompilerFlags_PROD=" -O3"
# Compiler flags that no matter what, we want to define
# for the most part these pass the build parameters into the executable
CompilerFlags_common=" -DPLATFORM_${PLATFORM}=1 -DMODE_${MODE}=1 -DARCH_${ARCH}=1"
# Linker Flags
LinkerFlags_win32=" -NOLOGO"
LinkerFlags_win32+=" -incremental:no" #
LinkerFlags_win32+=" -subsystem:windows" #
# add_flag LinkerFlags_win32 "-entry:WinMain" #
LinkerFlags_win32+=" -opt:ref" # eliminate functions that are never referenced
LinkerFlags_osx=""
LinkerFlags_wasm="--no-entry"
LinkerFlags_wasm+=" --export-dynamic" #
LinkerFlags_wasm+=" --unresolved-symbols=import-functions" #
LinkerFlags_linux=""
LinkerFlags_raspi="-fuse-ld=lld"
LinkerFlags_DEBUG="-debug"
LinkerFlags_PROD=""
# Linker Libs
LinkerLibs_win32="user32.lib kernel32.lib gdi32.lib opengl32.lib"
# winmm.lib gdi32.lib dsound.lib Ws2_32.lib Comdlg32.lib Winspool.lib"
LinkerLibs_osx="-framework OpenGL -framework Cocoa -framework IOKit ${PROJECT_PATH}/src_v2/libs/glfw_osx/lib-universal/libglfw3.a"
LinkerLibs_wasm=""
LinkerLibs_linux=""
LinkerLibs_raspi=""
# --------------------------------------------
# Varible Selection
# Select Platform Variables
if [ "${PLATFORM}" == "win32" ]
then
Compiler=$Compiler_win32
PlatformEntry=$PlatformEntry_win32
CompilerFlags=$CompilerFlags_win32
CompilerOutput=$CompilerOutput_win32
LinkerOutput=$LinkerOutput_win32
LinkerFlags=$LinkerFlags_win32
LinkerLibs=$LinkerLibs_win32
elif [ "${PLATFORM}" == "osx" ]
then
Compiler=$Compiler_osx
PlatformEntry=$PlatformEntry_osx
CompilerFlags=$CompilerFlags_osx
CompilerOutput=$CompilerOutput_osx
LinkerOutput=$LinkerOutput_osx
LinkerFlags=$LinkerFlags_osx
LinkerLibs=$LinkerLibs_osx
if [ "${ARCH}" == "arm64" ]
then
CompilerFlags="${CompilerFlags} -arch arm64"
elif [ "${ARCH}" == "intel" ]
then
CompilerFlags="${CompilerFlags} -arch x86_64"
else
echo "ERROR: Unrecognized Arch: ${ARCH}"
exit 0
fi
elif [ "${PLATFORM}" == "wasm" ]
then
Compiler=$Compiler_wasm
PlatformEntry=$PlatformEntry_wasm
CompilerFlags=$CompilerFlags_wasm
CompilerOutput=$CompilerOutput_wasm
LinkerOutput=$LinkerOutput_wasm
LinkerFlags=$LinkerFlags_wasm
LinkerLibs=$LinkerLibs_wasm
elif [ "${PLATFORM}" == "linux" ]
then
Compiler=$Compiler_linux
PlatformEntry=$PlatformEntry_linux
CompilerFlags=$CompilerFlags_linux
CompilerOutput=$CompilerOutput_linux
LinkerOutput=$LinkerOutput_linux
LinkerFlags=$LinkerFlags_linux
LinkerLibs=$LinkerLibs_linux
elif [ "${PLATFORM}" == "raspi" ]
then
Compiler=$Compiler_raspi
PlatformEntry=$PlatformEntry_raspi
CompilerFlags=$CompilerFlags_raspi
CompilerOutput=$CompilerOutput_raspi
LinkerOutput=$LinkerOutput_raspi
LinkerFlags=$LinkerFlags_raspi
LinkerLibs=$LinkerLibs_raspi
else
echo "Attempting to build for an unknown platform: ${PLATFORM}"
print_usage
exit 0
fi
# Select Release Mode Variables
if [ "${MODE}" == "debug" ]
then
if [ $PLATFORM == "win32" ]
then
CompilerFlags="${CompilerFlags} ${CompilerFlags_DEBUG_win32}"
else
CompilerFlags="${CompilerFlags} ${CompilerFlags_DEBUG}"
fi
LinkerFlags="${LinkerFlags} ${LinkerFlags_DEBUG}"
elif [ "${MODE}" == "prod" ]
then
CompilerFlags="${CompilerFlags} ${CompilerFlags_PROD}"
LinkerFlags="${LinkerFlags} ${LinkerFlags_PROD}"
else
echo "Attempting to build for an unknown release mode: ${MODE}"
print_usage
exit 0
fi
# Common Flags
CompilerFlags="${CompilerFlags} ${CompilerFlags_common}"
# --------------------------------------------
# Build Path Construction
#
# This determines where the generated executable will
# be located. In general, it can be found at
# project_path/run_tree/platform/arch/release_mode/lumenarium.exe
#
# This section also ensures that the path requested actually exists
BuildDir="${PROJECT_PATH}/run_tree/${PLATFORM}/${ARCH}/${MODE}"
EntryPath="${PROJECT_PATH}/${PlatformEntry}"
# Exception for wasm, which doesn't care about cpu architecture
if [ $PLATFORM == "wasm" ]
then
BuildDir="${PROJECT_PATH}/run_tree/${PLATFORM}/${MODE}"
fi
# Make the build directory,
# "-p" flag makes it make the entire tree, and not emit errors if it
# exists.
mkdir -p "${BuildDir}"
# --------------------------------------------
# Compilation
echo "Building To: ${BuildDir}/${LinkerOutput}"
echo
pushdir $BuildDir
echo "Cleaning: ${CompilerOutput} and ${LinkerOutput}"
rm -rf ${CompilerOutput} ${LinkerOutput}
echo "COMPILING..."
if [ $PLATFORM == "win32" ]
then
$Compiler \
$CompilerFlags \
$EntryPath \
-link \
$LinkerFlags \
$LinkerLibs \
-OUT:${LinkerOutput}
elif [ $PLATFORM == "wasm" ]
then
$Compiler \
$CompilerFlags \
-o $LinkerOutput \
$EntryPath
cp \
"${PROJECT_PATH}/src_v2/platform/wasm/lumenarium_wasm_imports.js" \
./lumenarium_wasm_imports.js
else
# Preprocessing Steps
ConvertCsvEntry="${PROJECT_PATH}/src_v2/tools/convert_csv.c"
$Compiler \
-o convert_csv \
$CompilerFlags \
$ConvertCsvEntry \
$LinkerLibs
./convert_csv
echo "$Compiler -o $LinkerOutput $CompilerFlags $EntryPath $LinkerLibs"
$Compiler -o $LinkerOutput $CompilerFlags $EntryPath $LinkerLibs
fi
echo "Finished..."
popdir

View File

@ -0,0 +1,7 @@
pushd build
clang++ ../src/gs_osx.mm \
-g \
-Wno-c11-extensions -Wno-unused-variable -Wno-unused-function \
-framework Cocoa -framework OpenGL \
-o osx_foldhaus.out
popd

View File

@ -0,0 +1,26 @@
@echo off
SET MyPath=%~dp0
SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat app debug clang
set CommonCompilerFlags=-std=c++11 -Wno-writable-strings -Wno-unused-value -Wno-varargs -Wno-switch -Wno-microsoft-enum-forward-reference -DDEBUG=1
pushd %BuildPath%
del *.pdb > NUL 2> NUL
echo WAITING FOR PDB TO WRITE > lock.tmp
clang++ %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp -shared -o
set LastError=%ERRORLEVEL%
del lock.tmp
clang++ -c %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp
link win32_foldhaus.o user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib
popd
call %MyPath%\_postbuild_win32.bat

View File

@ -0,0 +1,46 @@
@echo off
SET MyPath=%~dp0
SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat app debug msvc
call %MyPath%\setup_cl.bat
SET CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
SET CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -Od %CommonCompilerFlags%
SET CommonLinkerFlags= -opt:ref -incremental:no
SET DLLExports=/EXPORT:InitializeApplication /EXPORT:UpdateAndRender /EXPORT:CleanupApplication /EXPORT:ReloadStaticData
pushd %BuildPath%
del *.pdb > NUL 2> NUL
echo WAITING FOR PDB TO WRITE > lock.tmp
cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp /Fefoldhaus.dll /LD /link %CommoLinkerFlags% %DLLExports%
SET LastError=%ERRORLEVEL%
del lock.tmp
cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib Winspool.lib
REM COMPILE UTILITY EXES
cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib Winspool.lib
cl %CommonCompilerFlags% %ProjectDevPath%\src\sculpture_gen\gen_blumen_lumen.cpp /Fegen_blumen_lumen.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib
REM COMPILE AND RUN TESTS
cl %CommonCompilerFlags% %ProjectDevPath%\src\tests\sanity_tests.cpp /Fesanity_tests.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib
ECHO SANITY TESTS BEGIN
sanity_tests.exe
ECHO SANITY TESTS END
popd
call %MyPath%\_postbuild_win32.bat

View File

@ -1,88 +0,0 @@
################# COMPILER #################
# Compiler: Global
compiler>input>win32> ${SRC_DIR}/platform/win32/lumenarium_first_win32.c
compiler>input>osx> ${SRC_DIR}/platform/osx/lumenarium_first_osx.c
compiler>input>raspi> ${SRC_DIR}/platform/raspi/lumenarium_first_raspi.c
msvc>-nologo
msvc>-FC # full path errors
msvc>-WX # treat warnings as errors
msvc>-W4 # output warning level
msvc>-Z7 # generate C compatible debug info
# msvc>-Oi # generate intrinsic functions
# msvc>-MTd # create a debug multithreaded exe w/ Libcmtd.lib
#msvc>-fp:fast # fast floating point model
msvc>-wd4505 #
msvc>-wd4100 #
msvc>-wd4189 #
msvc>-wd4702 #
msvc>-wd4996 # _CRT_SECURE_NO_WARNINGS
compiler>wasm>-Wno-writable-strings #
compiler>wasm>--target=wasm32 #
compiler>wasm>-nostdlib #
compiler>wasm>-Wl,--no-entry #
compiler>wasm>-Wl,--allow-undefined #
compiler>wasm>-Wl,--export-all #
compiler>clang>linux>-pthread
compiler>raspi>-pthread
compiler>raspi>-lm # link with local system math libraries
compiler>clang>arm64>-arch arm64
# Compiler: Debug
compiler>debug>msvc>win32>-Od #
compiler>debug>msvc>win32>-Zi #
compiler>debug>msvc>win32>-DDEBUG=1 #
# compiler>debug>msvc>win32>-DPRINT_ASSERTS=1
compiler>debug>clang>-O0
compiler>debug>clang>-g
compiler>debug>compiler>-DDEBUG=1
compiler>debug>clang>-fsanitize=address
# Compiler: Prod
compiler>release>clang>-O3
################# LINKER #################
linker>output>osx>lumenarium
linker>output>win32>lumenarium.exe
linker>win32>-NOLOGO
linker>win32>-incremental:no
linker>win32>-subsystem:windows
linker>win32>-opt:ref # link time optimization - eliminate dead code
linker>wasm>--no-entry
linker>wasm>--export-dynamic
linker>wasm>--unresolved-symbols=import-functions
# TODO: I don't think the build system supports this right now
linker>raspi>-fuse-ld=lld
# linker>flags>debug>-debug
linker>flags>debug>-fsanitize=address
################# LIBRARIES #################
linker>libs>win32>user32.lib
linker>libs>win32>kernel32.lib
linker>libs>win32>gdi32.lib
linker>libs>win32>opengl32.lib
linker>libs>win32>winmm.lib
linker>libs>win32>gdi32.lib
linker>libs>win32>dsound.lib
linker>libs>win32>Ws2_32.lib
linker>libs>win32>Comdlg32.lib
linker>libs>win32>Winspool.lib
linker>libs>osx>-framework OpenGL
linker>libs>osx>-framework Cocoa
linker>libs>osx>-framework IOKit
linker>libs>osx>${SRC_DIR}/libs/glfw_osx/lib-universal/libglfw3.a

View File

@ -0,0 +1,17 @@
@echo off
SET MyPath=%~dp0
SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat meta debug msvc
set CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except-
set CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -O2 %CommonCompilerFlags%
set CommonLinkerFlags= -opt:ref
pushd %BuildPath%
cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_meta.cpp /link %CommonLinkerFlags%
popd
call %MyPath%\_postbuild_win32.bat

40
build/setup_cl.bat Normal file
View File

@ -0,0 +1,40 @@
@echo off
ECHO SETUP CL
SET "LIB="
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 13.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
ECHO SETUP CL COMPLETE

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

View File

@ -16,7 +16,8 @@ blacklist_patterns = {
load_paths_base = {
{ ".", .relative = true, .recursive = false, },
{ "build", .relative = true, .recursive = false, },
{ "src", .relative = true, .recursive = true, },
// { "src", .relative = true, .recursive = true, },
{ "src_v2", .relative = true, .recursive = true, },
{ "meta", .relative = true, .recursive = true, },
{ "gs_libs", .relative = true, .recursive = true, },
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
</head>
<body>
<canvas id="gl_canvas" width="640" height="480"></canvas>
<script type="text/javascript" src="lumenarium_wasm_imports.js"></script>
<script type="text/javascript" src="loader.js"></script>
</body>
</html>

View File

@ -0,0 +1,39 @@
let module = null;
let instance = null;
async function load_webassembly_module ()
{
lumenarium_wasm_imports = webgl_add_imports("#gl_canvas", lumenarium_wasm_imports);
const path = "lumenarium.wasm";
const promise = fetch(path);
const module = await WebAssembly.compileStreaming(promise);
let memory = new WebAssembly.Memory({ initial: 2 });
const env = {
memory,
...lumenarium_wasm_imports,
};
let table = new WebAssembly.Table({ element: "anyfunc", initial: 32, });
instance = await WebAssembly.instantiate(module, { env })
.then((res, err) => {
return res;
})
.catch((a, b) => {
console.log(a,b);
});
lumenarium_wasm_instance = instance;
// If function '__wasm_call_ctors' (global C++ constructors) exists, call it
if (instance.exports.__wasm_call_ctors) instance.exports.__wasm_call_ctors();
// If function 'main' exists, call it with dummy arguments
let result = 0;
if (instance.exports.main) result = instance.exports.main();
}
window.addEventListener("load", load_webassembly_module)

Binary file not shown.

View File

@ -0,0 +1,167 @@
var lumenarium_wasm_module = null;
var lumenarium_wasm_instance = null;
var WASM_PAGE_SIZE = 65536;
function wasm_mem_get_u8_arr(inst, ptr, size)
{
let view = new Uint8Array(inst.exports.memory.buffer, ptr, size);
return view;
}
function wasm_read_string(inst, ptr, len)
{
let view = wasm_mem_get_u8_arr(inst, ptr, len);
let string = '';
for (let i = 0; i < len; i++)
{
string += String.fromCharCode(view[i]);
}
return string;
}
function wasm_write_bytes(inst, src, ptr, len)
{
let view = wasm_mem_get_u8_arr(inst, ptr, len);
for (let i = 0; i < len; i++) view[i] = src[i];
}
function wasm_get_proc(inst, proc_ptr)
{
let result = inst.exports.__indirect_function_table.get(proc_ptr);
return result;
}
function fract (v) { return v % 1; }
var lumenarium_wasm_imports = {
memset: (dst, size, value) => {
let view_dst = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dst, size);
for (let i = 0; i < size; i++)
{
view_dst[i] = value;
}
},
memcpy: (dst, src, size) => {
let view_dst = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dst, size);
let view_src = wasm_mem_get_u8_arr(lumenarium_wasm_instance, src, size);
for (let i = 0; i < size; i++)
{
view_dst[i] = view_src[i];
}
},
wasm_assert_always: () => {
console.assert(false);
},
wasm_get_memory_size: () => {
return instance.exports.memory.buffer.byteLength;
},
wasm_mem_grow: (new_size) => {
let pages = new_size / WASM_PAGE_SIZE;
let pages_rem = fract(pages);
if (pages_rem > 0) pages = Math.floor(pages) + 1;
let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength;
let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages);
console.log("mem_grow\n",
"req size: ", new_size, "\n",
"old size: ", (old_page_count * WASM_PAGE_SIZE), "\n",
"old size: ", size_before, "\n",
"grew by: ", (pages * WASM_PAGE_SIZE), "\n",
"new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, "");
},
wasm_performance_now: () => {
return performance.now();
},
wasm_sleep: (milliseconds) => {
let start = Date.now();
for (let at = Date.now(); (at - start) < milliseconds; at = Date.now()) {}
},
wasm_fetch: async (file_path, file_path_len, dest, dest_size) => {
let path = wasm_read_string(lumenarium_wasm_instance, file_path, file_path_len);
fetch(path)
.then(async (res) => {
// TODO(PS): success checking
let reader = res.body.getReader();
let read_res = { done: false };
let view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dest, dest_size);
let last_write = 0;
while (!read_res.done)
{
read_res = await reader.read();
if (read_res.done) break;
let len = read_res.value.length;
let write_end = last_write + len;
for (let i = last_write; i < write_end; i++)
{
view[i] = read_res.value[i - last_write];
}
last_write = write_end + 1;
}
});
return 0;
},
wasm_request_animation_frame: (cb) => {
let cb_proc = wasm_get_proc(lumenarium_wasm_instance, cb);
window.requestAnimationFrame(cb_proc);
},
print: (str_base, len) => {
let string = wasm_read_string(lumenarium_wasm_instance, str_base, len);
console.log(string);
},
};
let gl = null;
function glClearColor (r, g, b, a) { gl.clearColor(r,g,b,a); }
function glEnable(v) { gl.enable(v); }
function glDisable(v) { gl.disable(v); }
function glBlendFunc(a,b) { gl.blendFunc(a,b); }
function glViewport(xmin, ymin, xmax, ymax) { gl.viewport(xmin,ymin,xmax,ymax); }
function glDepthFunc(v) { gl.depthFunc(v); }
function glClear(mask) { gl.clear(mask); }
function webgl_add_imports (canvas_selector, imports) {
const canvas = document.querySelector(canvas_selector);
if (!canvas) return console.error("no canvas");
gl = canvas.getContext("webgl");
if (gl === null) return console.error("no webgl ctx");
///////////////////////////////////////
// Constants
imports.GL_TEXTURE_2D = gl.TEXTURE_2D;
imports.GL_BLEND = gl.BLEND;
imports.GL_SRC_ALPHA = gl.SRC_ALPHA;
imports.GL_ONE_MINUS_SRC_ALPHA = gl.ONE_MINUS_SRC_ALPHA;
imports.GL_DEPTH_TEST = gl.DEPTH_TEST;
imports.GL_LESS = gl.LESS;
imports.GL_COLOR_BUFFER_BIT = gl.COLOR_BUFFER_BIT;
imports.GL_DEPTH_BUFFER_BIT = gl.DEPTH_BUFFER_BIT;
///////////////////////////////////////
// Functions
imports.glClearColor = glClearColor;
imports.glEnable = glEnable;
imports.glDisable = glDisable;
imports.glBlendFunc = glBlendFunc;
imports.glViewport = glViewport;
imports.glDepthFunc = glDepthFunc;
imports.glClear = glClear;
return imports;
}

Binary file not shown.

View File

@ -0,0 +1 @@
OpenGL Version: 3.3.0 - Build 27.20.100.9778

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,159 @@
//
// File: foldhaus_default_nodes.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_DEFAULT_NODES_H
//////////////////////////////////
//
// Values
//
/////////////////////////////////
NODE_STRUCT(float_value_data)
{
NODE_IN(r32, Value);
NODE_OUT(r32, Result);
};
NODE_PROC(FloatValue, float_value_data)
{
Data->Result = Data->Value;
}
NODE_STRUCT(vector_data)
{
NODE_IN(r32, X);
NODE_IN(r32, Y);
NODE_IN(r32, Z);
NODE_IN(r32, W);
NODE_OUT(v4, Result);
};
NODE_PROC(VectorValue, vector_data)
{
Data->Result = v4{Data->X, Data->Y, Data->Z, Data->W};
}
//////////////////////////////////
//
// Arithmetic
//
/////////////////////////////////
NODE_STRUCT(multiply_data)
{
NODE_IN(r32, A);
NODE_IN(r32, B);
NODE_OUT(r32, Result);
};
NODE_PROC(MultiplyNodeProc, multiply_data)
{
Data->Result = Data->A * Data->B;
}
NODE_STRUCT(add_data)
{
NODE_IN(v4, A);
NODE_IN(v4, B);
NODE_OUT(v4, Result);
};
NODE_PROC(AddNodeProc, add_data)
{
Data->Result = Data->A + Data->B;
}
//////////////////////////////////
//
// Animators
//
/////////////////////////////////
GSMetaTag(node_struct);
struct sin_wave_data
{
GSMetaTag(node_input);
r32 Period;
GSMetaTag(node_input);
r32 Min;
GSMetaTag(node_input);
r32 Max;
GSMetaTag(node_input);
r32 Result;
r32 Accumulator;
};
NODE_PROC(SinWave, sin_wave_data)
{
Data->Accumulator += DeltaTime;
if (Data->Period > 0)
{
while (Data->Accumulator > Data->Period)
{
Data->Accumulator -= Data->Period;
}
r32 ActualMin = Min(Data->Min, Data->Max);
r32 ActualMax = Max(Data->Min, Data->Max);
r32 SinResult = SinR32((Data->Accumulator / Data->Period) * PiR32 * 2);
Data->Result = RemapR32(SinResult, -1.f, 1.f, ActualMin, ActualMax);
}
else
{
Data->Result = 0;
}
}
//////////////////////////////////
//
// Pattern Mixing
//
/////////////////////////////////
GSMetaTag(node_struct);
struct multiply_patterns_data
{
GSMetaTag(node_input);
color_buffer A;
GSMetaTag(node_input);
color_buffer B;
GSMetaTag(node_output);
color_buffer Result;
};
NODE_PROC(MultiplyPatterns, multiply_patterns_data)
{
for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++)
{
Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount);
s32 AR = Data->A.Colors[LedIndex].R;
s32 AG = Data->A.Colors[LedIndex].G;
s32 AB = Data->A.Colors[LedIndex].B;
s32 BR = Data->B.Colors[LedIndex].R;
s32 BG = Data->B.Colors[LedIndex].G;
s32 BB = Data->B.Colors[LedIndex].B;
s32 RCombined = (AR * BR) / 255;
s32 GCombined = (AG * BG) / 255;
s32 BCombined = (AB * BB) / 255;
Data->Result.Colors[LedIndex].R = (u8)RCombined;
Data->Result.Colors[LedIndex].G = (u8)GCombined;
Data->Result.Colors[LedIndex].B = (u8)BCombined;
}
}
#define FOLDHAUS_DEFAULT_NODES_H
#endif // FOLDHAUS_DEFAULT_NODES_H

View File

@ -0,0 +1,188 @@
//
// File: foldhaus_node.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_NODE_CPP
internal b32
MemberIsInput(gsm_struct_member_type_info Member)
{
b32 Result = (0 <= gsm_GetMetaTagIndex(MetaTag_node_input, Member.Tags, Member.TagsCount));
return Result;
}
internal b32
MemberIsOutput(gsm_struct_member_type_info Member)
{
b32 Result = (0 <= gsm_GetMetaTagIndex(MetaTag_node_output, Member.Tags, Member.TagsCount));
return Result;
}
internal void
ClearNodeWorkspaceStorage(pattern_node_workspace* Workspace)
{
ClearArena(&Workspace->Storage);
Workspace->SparseToSortedNodeMap = 0;
Workspace->SortedNodeHandles = 0;
}
struct adjacency_list
{
// TODO(Peter): Can make these as buffers, not single digits later
gs_list_handle NodeHandle;
adjacency_list* Next;
};
internal u32
SortNodeNeighbors(u32 ContiguousNodeIndex, gs_list_handle NodeHandle, adjacency_list** NeighborsLists, b8* NodesVisited, gs_list_handle* SortedNodeHandles, u32 SortedNodesCount, s32* SparseToContiguousNodeMap)
{
NodesVisited[ContiguousNodeIndex] = true;
adjacency_list* Neighbor = NeighborsLists[ContiguousNodeIndex];
while (Neighbor)
{
u32 ContiguousNeighborNodeIndex = SparseToContiguousNodeMap[Neighbor->NodeHandle.Index];
if (!NodesVisited[ContiguousNeighborNodeIndex])
{
SortedNodesCount = SortNodeNeighbors(ContiguousNeighborNodeIndex, Neighbor->NodeHandle, NeighborsLists, NodesVisited, SortedNodeHandles, SortedNodesCount, SparseToContiguousNodeMap);
}
Neighbor = Neighbor->Next;
}
SortedNodeHandles[SortedNodesCount++] = NodeHandle;
return SortedNodesCount;
}
internal s32*
CreateSparseToContiguousMap (pattern_node_workspace Workspace, gs_memory_arena* Scratch)
{
s32* Result = PushArray(Scratch, s32, Workspace.Nodes.OnePastLastUsed);
s32 ContiguousIndex = 0;
for (u32 SparseNodeIndex = 0; SparseNodeIndex < Workspace.Nodes.OnePastLastUsed; SparseNodeIndex++)
{
gs_list_entry<pattern_node>* Entry = Workspace.Nodes.GetEntryAtIndex(SparseNodeIndex);
if (!EntryIsFree(Entry))
{
Result[SparseNodeIndex] = ContiguousIndex++;
}
}
return Result;
}
internal void
UpdateSortedNodes(pattern_node_workspace* Workspace, gs_memory_arena* Scratch)
{
ClearNodeWorkspaceStorage(Workspace);
u32 NodeCount = Workspace->Nodes.Used;
u32 SparseNodeCount = Workspace->Nodes.OnePastLastUsed;
s32* SparseToContiguousNodeMap = CreateSparseToContiguousMap(*Workspace, &Workspace->Storage);
// NOTE(Peter): We need to sort this later on so I'm just storing list lengths in this format
// to begin with.
// NeighborsListLengths[n].Radix = the number of neighbors for the node
// NeighborsListLengths[n].ID = the sparse array index of the node
gs_radix_entry* NeighborsListLengths = PushArray(Scratch, gs_radix_entry, NodeCount);
adjacency_list** NeighborsLists = PushArray(Scratch, adjacency_list*, NodeCount);
GSZeroArray(NeighborsLists, adjacency_list*, SparseNodeCount);
// Fill Radix
for (u32 n = 0; n < SparseNodeCount; n++)
{
s32 ContiguousIndex = SparseToContiguousNodeMap[n];
if (ContiguousIndex >= 0)
{
NeighborsListLengths[ContiguousIndex].Radix = 0;
NeighborsListLengths[ContiguousIndex].ID = n;
}
}
// Construct Adjaceny List
for (u32 c = 0; c < Workspace->Connections.Used; c++)
{
pattern_node_connection Connection = *Workspace->Connections.GetElementAtIndex(c);
adjacency_list* ListAddition = PushStruct(Scratch, adjacency_list);
ListAddition->NodeHandle = Connection.DownstreamNodeHandle;
s32 ContiguousNodeIndex = SparseToContiguousNodeMap[Connection.UpstreamNodeHandle.Index];
ListAddition->Next = NeighborsLists[ContiguousNodeIndex];
NeighborsLists[ContiguousNodeIndex] = ListAddition;
// Increment the number of neighbors - stored in Radix
NeighborsListLengths[ContiguousNodeIndex].Radix++;
}
// Sort by number of neighbors
RadixSortInPlace(NeighborsListLengths, Workspace->Nodes.Used);
char* OutputCharArray = PushArray(Scratch, char, 1024);
gs_string Outputgs_string = MakeString(OutputCharArray, 0, 1024);
PrintF(&Outputgs_string, "Neighbors Lists: \n");
for (u32 d = 0; d < Workspace->Nodes.Used; d++)
{
PrintF(&Outputgs_string, " %d: Node [ %d ] : neighbors { ", d, NeighborsListLengths[d].ID);
adjacency_list* Neighbors = NeighborsLists[d];
while (Neighbors)
{
PrintF(&Outputgs_string, "%d, ", Neighbors->NodeHandle.Index);
Neighbors = Neighbors->Next;
}
PrintF(&Outputgs_string, " }\n");
}
NullTerminate(&Outputgs_string);
// This is a contiguous array.
b8* NodesVisited = PushArray(Scratch, b8, NodeCount);
GSZeroArray(NodesVisited, b8, NodeCount);
Workspace->SortedNodeHandles = PushArray(&Workspace->Storage, gs_list_handle, NodeCount);
u32 SortedSparseNodeIndeciesUsed = 0;
for (u32 n = 0; n < Workspace->Nodes.Used; n++)
{
gs_radix_entry SortedNeighborsCount = NeighborsListLengths[n];
u32 NeighborCount = SortedNeighborsCount.Radix;
u32 NodeIndex = SortedNeighborsCount.ID;
gs_list_handle NodeHandle = Workspace->Nodes.GetEntryAtIndex(NodeIndex)->Handle;
u32 ContiguousNodeIndex = SparseToContiguousNodeMap[NodeIndex];
SortedSparseNodeIndeciesUsed = SortNodeNeighbors(ContiguousNodeIndex, NodeHandle, NeighborsLists, NodesVisited, Workspace->SortedNodeHandles, SortedSparseNodeIndeciesUsed, SparseToContiguousNodeMap);
}
Workspace->SparseToSortedNodeMap = SparseToContiguousNodeMap;
for (u32 SortedIndex = 0; SortedIndex < NodeCount; SortedIndex++)
{
gs_list_handle SortedHandle = Workspace->SortedNodeHandles[SortedIndex];
Workspace->SparseToSortedNodeMap[SortedHandle.Index] = SortedIndex;
}
}
internal void
PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspace, gs_memory_arena* Scratch)
{
pattern_node* NewNode = Workspace->Nodes.TakeElement();
NewNode->SpecificationIndex = NodeSpecificationIndex;
UpdateSortedNodes(Workspace, Scratch);
}
internal void
PushNodeConnectionOnWorkspace(gs_list_handle UpstreamNodeHandle, u32 UpstreamPortIndex, gs_list_handle DownstreamNodeHandle, u32 DownstreamPortIndex, pattern_node_workspace* Workspace, gs_memory_arena* Scratch)
{
pattern_node_connection Connection = {};
Connection.UpstreamNodeHandle = UpstreamNodeHandle;
Connection.DownstreamNodeHandle = DownstreamNodeHandle;
Connection.UpstreamPortIndex = UpstreamPortIndex;
Connection.DownstreamPortIndex = DownstreamPortIndex;
Workspace->Connections.PushElementOnBucket(Connection);
UpdateSortedNodes(Workspace, Scratch);
}
#define FOLDHAUS_NODE_CPP
#endif // FOLDHAUS_NODE_CPP

View File

@ -0,0 +1,134 @@
//
// File: foldhaus_node.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_NODE_H
typedef enum node_type node_type;
#define IsInputMember 1 << 0
#define IsOutputMember 1 << 1
#define DEFAULT_NODE_DIMENSION v2{125, 150}
struct color_buffer
{
v4* LedPositions;
pixel* Colors;
s32 LEDCount;
};
// TODO(Peter): Use the Meta RTTI
// :UseMetaInfo
enum struct_member_type
{
MemberType_Invalid,
MemberType_s32,
MemberType_r32,
MemberType_v4,
MemberType_NODE_COLOR_BUFFER,
MemberTypeCount,
};
// TODO(Peter): Use the Meta RTTI
// :UseMetaInfo
struct node_struct_member
{
struct_member_type Type;
char* Name;
u64 Offset;
b32 IsInput;
};
// :UseMetaInfo
struct node_specification
{
node_type Type;
char* Name;
s32 NameLength;
node_struct_member* MemberList;
u32 DataStructSize;
u32 MemberListLength;
b32 IsPattern;
};
struct node_specification_
{
node_type Type;
gs_string Identifier;
gsm_struct_type DataType;
};
struct pattern_node
{
// TODO(Peter): Something to think about further down the line is the fact that
// SpecificationIndex doesn't have to stay static throughout a single instance of
// an application, let alone across separate runs. If you recompile (hot load or not)
// with a new specification, the indecies all get thrown off. Should we hash the spec
// names or something?
// TODO(Peter): A more immediate thing to handle is that u32 should really be node_type
u32 SpecificationIndex;
};
struct pattern_node_connection
{
gs_list_handle UpstreamNodeHandle;
gs_list_handle DownstreamNodeHandle;
u32 UpstreamPortIndex;
u32 DownstreamPortIndex;
};
struct pattern_node_workspace
{
gs_list<pattern_node> Nodes;
gs_bucket<pattern_node_connection> Connections;
// This is storage for all the structures which follow.
// It is cleared when new nodes are added so that the
// acceleration structures can be recalculated
gs_memory_arena Storage;
s32* SparseToSortedNodeMap;
gs_list_handle* SortedNodeHandles;
};
///////////////////////////////////////////////
// Pre Processor Macros
///////////////////////////////////////////////
#define NODE_STRUCT(data_name) \
struct data_name
#define NODE_PATTERN_STRUCT(data_name) \
struct data_name
#define NODE_PROC(proc_name, input_type) \
void proc_name(input_type* Data, r32 DeltaTime)
#define NODE_IN(type, name) type name
#define NODE_OUT(type, name) type name
///////////////////////////////////////////////
// OUTPUT NODE
///////////////////////////////////////////////
struct output_node_data
{
GSMetaTag(node_input);
color_buffer Result;
};
void OutputNode(output_node_data* Data, r32 DeltaTime)
{
}
#define FOLDHAUS_NODE_H
#endif // FOLDHAUS_NODE_H

View File

@ -0,0 +1,24 @@
//
// File: foldhaus_node_gui.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_NODE_GUI_H
struct gui_node
{
s32 Handle;
node_type Type;
v2 Min, Dim;
};
#define GUI_NODES_MAX 256
struct gui_node_list
{
s32 NodesUsed;
gui_node Nodes[GUI_NODES_MAX];
};
#define FOLDHAUS_NODE_GUI_H
#endif // FOLDHAUS_NODE_GUI_H

View File

@ -0,0 +1,546 @@
//
// File: foldhaus_panel_node_graph.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_NODE_GRAPH_H
struct visual_node
{
node_specification_ Spec;
v2 Position;
};
struct visual_port
{
gs_list_handle SparseNodeHandle;
u32 PortIndex;
rect2 PortBounds;
};
struct visual_connection
{
u32 UpstreamVisualPortIndex;
u32 DownstreamVisualPortIndex;
v2 UpstreamPosition;
v2 DownstreamPosition;
};
struct node_layout
{
// NOTE(Peter): This Map is a sparse array.
// index i corresponds to index i in some list of nodes
// the value at index i is the index of that node in a compressed list
// if the value at i is -1, that means the entry is free
s32* SparseToContiguousNodeMap;
u32 SparseToContiguousNodeMapCount;
visual_node* VisualNodes;
u32* VisualNodeLayers;
u32 VisualNodesCount;
visual_port* VisualPorts;
u32 VisualPortsCount;
visual_connection* VisualConnections;
u32 VisualConnectionsCount;
u32 LayerCount;
v2* LayerPositions;
b32 ConnectionIsInProgress;
v2 InProgressConnectionStart;
v2 InProgressConnectionEnd;
};
struct node_graph_state
{
v2 ViewOffset;
gs_memory_arena LayoutMemory;
node_layout Layout;
b32 LayoutIsDirty;
};
//
// Pan Node Graph
//
OPERATION_STATE_DEF(pan_node_graph_operation_state)
{
v2 InitialViewOffset;
// TODO(Peter): I DON"T LIKE THIS!!!!
// We should have a way to access the panel that created an operation mode or something
v2* ViewOffset;
};
OPERATION_RENDER_PROC(UpdatePanNodeGraph)
{
pan_node_graph_operation_state* OpState = (pan_node_graph_operation_state*)Operation.OpStateMemory;
v2 MouseDelta = Mouse.Pos - Mouse.DownPos;
*OpState->ViewOffset = MouseDelta + OpState->InitialViewOffset;
}
input_command PanNodeGraphCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode },
};
FOLDHAUS_INPUT_COMMAND_PROC(BeginPanNodeGraph)
{
operation_mode* PanNodeGraph = ActivateOperationModeWithCommands(&State->Modes, PanNodeGraphCommands, UpdatePanNodeGraph);
pan_node_graph_operation_state* OpState = CreateOperationState(PanNodeGraph, &State->Modes, pan_node_graph_operation_state);
panel* NodeGraphPanel = State->HotPanel;
node_graph_state* NodeGraphState = (node_graph_state*)NodeGraphPanel->PanelStateMemory;
OpState->InitialViewOffset = NodeGraphState->ViewOffset;
OpState->ViewOffset = &NodeGraphState->ViewOffset;
}
//
// Connect Nodes
//
OPERATION_STATE_DEF(connect_nodes_operation_state)
{
visual_port VisualPort;
u32 VisualPortIndex;
b32 IsInput;
};
OPERATION_RENDER_PROC(UpdateConnectNodeOperation)
{
panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.InProgressConnectionEnd = Mouse.Pos;
}
FOLDHAUS_INPUT_COMMAND_PROC(EndConnectNodesOperation)
{
connect_nodes_operation_state* OpState = GetCurrentOperationState(State->Modes, connect_nodes_operation_state);
panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.ConnectionIsInProgress = false;
for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++)
{
visual_port VisualPort = GraphState->Layout.VisualPorts[p];
rect2 ViewAdjustedBounds = gs_RectOffsetByVector(VisualPort.PortBounds, GraphState->ViewOffset);
if (gs_PointIsInRect(Mouse.Pos, ViewAdjustedBounds))
{
visual_port UpstreamPort = (OpState->IsInput & IsInputMember) ? VisualPort : OpState->VisualPort;
visual_port DownstreamPort = (OpState->IsInput & IsInputMember) ? OpState->VisualPort : VisualPort;
PushNodeConnectionOnWorkspace(UpstreamPort.SparseNodeHandle, UpstreamPort.PortIndex,
DownstreamPort.SparseNodeHandle, DownstreamPort.PortIndex,
&State->NodeWorkspace, &State->Transient);
GraphState->LayoutIsDirty = true;
}
}
EndCurrentOperationMode(State, Event, Mouse);
}
input_command ConnectNodesOperationCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndConnectNodesOperation },
};
internal void
BeginConnectNodesOperation(visual_port VisualPort, u32 VisualPortIndex, mouse_state Mouse, app_state* State)
{
operation_mode* ConnectNodesOperation = ActivateOperationModeWithCommands(&State->Modes, ConnectNodesOperationCommands, UpdateConnectNodeOperation);
connect_nodes_operation_state* OpState = CreateOperationState(ConnectNodesOperation, &State->Modes, connect_nodes_operation_state);
OpState->VisualPort = VisualPort;
OpState->VisualPortIndex = VisualPortIndex;
panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.ConnectionIsInProgress = true;
GraphState->Layout.InProgressConnectionStart = gs_CalculateRectCenter(VisualPort.PortBounds);
}
//
// Node Graph Panel
//
GSMetaTag(panel_commands);
input_command NodeGraph_Commands[] = {{}};
s32 NodeGraph_CommandsCount = 0;
GSMetaTag(panel_init);
GSMetaTag(panel_type_node_graph);
internal void
NodeGraph_Init(panel* Panel, app_state* State)
{
// TODO(Peter): We aren't able to free this memory. We need a system for
// taking fixed size chunks off the Memory stack and then reusing them. THis
// should probably live outside the paneling system.
// TODO: :FreePanelMemory
Panel->PanelStateMemory = (u8*)PushStruct(&State->Permanent, node_graph_state);
node_graph_state* GraphState = (node_graph_state*)Panel->PanelStateMemory;
GraphState->LayoutIsDirty = true;
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_node_graph);
internal void
NodeGraph_Cleanup(panel* Panel, app_state* State)
{
node_graph_state* GraphState = (node_graph_state*)Panel->PanelStateMemory;
FreeMemoryArena(&GraphState->LayoutMemory);
}
internal void
DrawGrid (v2 Offset, v2 GridSquareDim, rect2 PanelBounds, render_command_buffer* RenderBuffer)
{
r32 LineValue = .16f;
v4 LineColor = v4{LineValue, LineValue, LineValue, 1.f};
v2 GridSquareOffset = v2{
GSModF(Offset.x, GridSquareDim.x),
GSModF(Offset.y, GridSquareDim.y),
};
v2 GridOrigin = PanelBounds.Min + GridSquareOffset;
// Draw Vertical Lines
r32 XOffset = 0;
while (GridOrigin.x + XOffset < PanelBounds.Max.x)
{
v2 LineMin = v2{ GridOrigin.x + XOffset, PanelBounds.Min.y };
v2 LineMax = v2{ LineMin.x + 1, PanelBounds.Max.y };
PushRenderQuad2D(RenderBuffer, LineMin, LineMax, LineColor);
XOffset += GridSquareDim.x;
}
// Draw Horizontal Lines
r32 YOffset = 0;
while (GridOrigin.y + YOffset < PanelBounds.Max.y)
{
v2 LineMin = v2{ PanelBounds.Min.x, GridOrigin.y + YOffset };
v2 LineMax = v2{ PanelBounds.Max.x, LineMin.y + 1, };
PushRenderQuad2D(RenderBuffer, LineMin, LineMax, LineColor);
YOffset += GridSquareDim.y;
}
}
internal void
DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, r32 LineHeight, gs_string_alignment TextAlign, v2 TextOffset, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse)
{
rect2 PortBounds = rect2{v2{0, 0}, v2{6, 6}};
v2 LinePosition = Position;
for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++)
{
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i];
if (MemberIsInput(Member))
{
// TODO(Peter): Can we make this rely on the same data that we use to
// render the actual connection points?
gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength);
DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, TextAlign);
LinePosition.y -= LineHeight;
}
}
}
internal void
DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle NodeHandle, r32 NodeWidth, r32 LineHeight, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse, gs_memory_arena* Scratch)
{
gsm_struct_type_info NodeDataTypeInfo = StructTypes[NodeSpecification.DataType];
u32 InputMembers = 0;
u32 OutputMembers = 0;
for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++)
{
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i];
if (MemberIsInput(Member)) { InputMembers++; }
if (MemberIsOutput(Member)) { OutputMembers++; }
}
u32 LineCount = 1 + Max(InputMembers, OutputMembers);
v2 NodeDim = v2{
NodeWidth,
(LineHeight * LineCount) + Interface.Margin.y,
};
rect2 NodeBounds = rect2{
v2{ Position.x, Position.y - NodeDim.y },
v2{ Position.x + NodeDim.x, Position.y },
};
PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.16f, .16f, .16f, 1.f});
v2 LinePosition = v2{ NodeBounds.Min.x, NodeBounds.Max.y - LineHeight };
v2 TextOffset = v2{Interface.Margin.x, 0};
PushRenderQuad2D(RenderBuffer, LinePosition, LinePosition + v2{NodeWidth, LineHeight}, v4{1.f, .24f, .39f, 1.f});
gs_string NodePrintName = MakeString(PushArray(Scratch, char, 256), 0, 256);
PrintF(&NodePrintName, "%S [%d]", NodeSpecification.Identifier, NodeHandle.Index);
DrawString(RenderBuffer, NodePrintName, Interface.Font, LinePosition + TextOffset, WhiteV4);
LinePosition.y -= LineHeight;
v2 InputLinePosition = LinePosition;
v2 OutputLinePosition = v2{LinePosition.x + NodeDim.x, LinePosition.y };
v2 OutputTextOffset = v2{-TextOffset.x, TextOffset.y};
for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++)
{
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i];
gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength);
// TODO(Peter): Can we make this rely on the same data that we use to
// render the actual connection points?
if (MemberIsInput(Member))
{
DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, Align_Left);
InputLinePosition.y -= LineHeight;
}
else if (MemberIsOutput(Member))
{
DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, Align_Right);
OutputLinePosition.y -= LineHeight;
}
}
}
internal s32
GetVisualPortIndexForNode(gs_list_handle SparseNodeHandle, u32 PortIndex, node_layout Layout)
{
s32 Result = -1;
for (u32 i = 0; i < Layout.VisualPortsCount; i++)
{
visual_port Port = Layout.VisualPorts[i];
if (GSListHandlesAreEqual(Port.SparseNodeHandle, SparseNodeHandle) && Port.PortIndex == PortIndex)
{
Result = i;
break;
}
}
return Result;
}
internal node_layout
ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, r32 LineHeight, gs_memory_arena* Storage, app_state* State)
{
node_layout Result = {};
for (u32 n = 0; n < Workspace.Nodes.Used; n++)
{
gs_list_handle NodeHandle = Workspace.SortedNodeHandles[n];
pattern_node Node = *Workspace.Nodes.GetElementWithHandle(NodeHandle);
u32 SpecIndex = Node.SpecificationIndex;
node_specification_ Spec = NodeSpecifications[SpecIndex];
gsm_struct_type_info NodeDataTypeInfo = StructTypes[Spec.DataType];
Result.VisualPortsCount += NodeDataTypeInfo.MembersCount;;
}
// Place nodes and connections
Result.VisualNodesCount = Workspace.Nodes.Used;
Result.VisualNodes = PushArray(Storage, visual_node, Result.VisualNodesCount);
u32 VisualPortsUsed = 0;
Result.VisualPorts = PushArray(Storage, visual_port, Result.VisualPortsCount);
for (u32 n = 0; n < Workspace.Nodes.Used; n++)
{
gs_list_handle NodeHandle = Workspace.SortedNodeHandles[n];
pattern_node Node = *Workspace.Nodes.GetElementWithHandle(NodeHandle);
u32 SpecIndex = Node.SpecificationIndex;
node_specification_ Spec = NodeSpecifications[SpecIndex];
gsm_struct_type_info NodeDataTypeInfo = StructTypes[Spec.DataType];
visual_node* VisualNode = Result.VisualNodes + n;
VisualNode->Spec = Spec;
VisualNode->Position = v2{(1.5f * NodeWidth) * n, 0};
// NOTE(Peter): These start at 2 to account for the offset past the node title
s32 InputsCount = 2;
s32 OutputsCount = 2;
for (u32 p = 0; p < NodeDataTypeInfo.MembersCount; p++)
{
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[p];
rect2 PortBounds = {0};
v2 PortDim = v2{8, 8};
PortBounds.Min = VisualNode->Position + v2{0, PortDim.y / 2};
if (MemberIsInput(Member))
{
PortBounds.Min.y -= LineHeight * InputsCount++;
PortBounds.Min.x -= PortDim.x;
}
else if (MemberIsOutput(Member))
{
PortBounds.Min.y -= LineHeight * OutputsCount++;
PortBounds.Min.x += NodeWidth;
}
PortBounds.Max = PortBounds.Min + v2{8, 8};
visual_port* VisualPort = Result.VisualPorts + VisualPortsUsed++;
VisualPort->SparseNodeHandle = NodeHandle;
VisualPort->PortIndex = p;
VisualPort->PortBounds = PortBounds;
}
}
Result.VisualConnectionsCount = 0;
Result.VisualConnectionsCount = Workspace.Connections.Used;
Result.VisualConnections = PushArray(Storage, visual_connection, Result.VisualConnectionsCount);
for (u32 c = 0; c < Workspace.Connections.Used; c++)
{
pattern_node_connection* Connection = Workspace.Connections.GetElementAtIndex(c);
visual_connection* VisualConnection = Result.VisualConnections + c;
VisualConnection->UpstreamVisualPortIndex = GetVisualPortIndexForNode(Connection->UpstreamNodeHandle, Connection->UpstreamPortIndex, Result);
VisualConnection->DownstreamVisualPortIndex = GetVisualPortIndexForNode(Connection->DownstreamNodeHandle, Connection->DownstreamPortIndex, Result);
visual_port UpstreamPort = Result.VisualPorts[VisualConnection->UpstreamVisualPortIndex];
visual_port DownstreamPort = Result.VisualPorts[VisualConnection->DownstreamVisualPortIndex];
VisualConnection->UpstreamPosition = gs_CalculateRectCenter(UpstreamPort.PortBounds);
VisualConnection->DownstreamPosition = gs_CalculateRectCenter(DownstreamPort.PortBounds);
}
return Result;
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_node_graph);
internal void
NodeGraph_Render(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
node_graph_state* GraphState = (node_graph_state*)Panel.PanelStateMemory;
b32 MouseHandled = false;
rect2 NodeSelectionWindowBounds = rect2{
PanelBounds.Min,
v2{PanelBounds.Min.x + 300, PanelBounds.Max.y},
};
rect2 GraphBounds = rect2{
v2{NodeSelectionWindowBounds.Max.x, PanelBounds.Min.y},
PanelBounds.Max,
};
r32 NodeWidth = 150;
r32 LayerDistance = 100;
r32 LineHeight = ui_GetTextLineHeight(State->Interface);
if (GraphState->LayoutIsDirty)
{
// NOTE(Peter): Resset the LayoutMemory arena so we can use it again.
// If LayoutIsDirty, then we need to recalculate all the members of GraphState->Layout
// so we might as well just clear the whole thing (we aren't freeing, just reusing)
ClearArena(&GraphState->LayoutMemory);
GraphState->Layout = {};
GraphState->Layout = ArrangeNodes(State->NodeWorkspace, NodeWidth, LayerDistance, LineHeight, &GraphState->LayoutMemory, State);
GraphState->LayoutIsDirty = false;
}
DrawGrid(GraphState->ViewOffset, v2{100, 100}, GraphBounds, RenderBuffer);
for (u32 i = 0; i < GraphState->Layout.VisualConnectionsCount; i++)
{
visual_connection Connection = GraphState->Layout.VisualConnections[i];
v2 Start = GraphState->ViewOffset + Connection.UpstreamPosition;
v2 End = GraphState->ViewOffset + Connection.DownstreamPosition;
PushRenderLine2D(RenderBuffer, Start, End, 1.5f, WhiteV4);
v2 TempDim = v2{6, 6};
PushRenderQuad2D(RenderBuffer, Start - TempDim, Start + TempDim, PinkV4);
PushRenderQuad2D(RenderBuffer, End - TempDim, End + TempDim, YellowV4);
}
if (GraphState->Layout.ConnectionIsInProgress)
{
PushRenderLine2D(RenderBuffer,
GraphState->Layout.InProgressConnectionStart,
GraphState->Layout.InProgressConnectionEnd,
1.5f, WhiteV4);
}
for (u32 i = 0; i < GraphState->Layout.VisualNodesCount; i++)
{
visual_node VisualNode = GraphState->Layout.VisualNodes[i];
gs_list_handle NodeHandle = State->NodeWorkspace.SortedNodeHandles[i];
DrawNode(VisualNode.Position + GraphState->ViewOffset, VisualNode.Spec, NodeHandle, NodeWidth, LineHeight, State->Interface.Style, RenderBuffer, Context.Mouse, &State->Transient);
}
for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++)
{
visual_port VisualPort = GraphState->Layout.VisualPorts[p];
VisualPort.PortBounds.Min += GraphState->ViewOffset;
VisualPort.PortBounds.Max += GraphState->ViewOffset;
v4 PortColor = WhiteV4;
if (PointIsInRange(Context.Mouse.Pos, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max))
{
PortColor = PinkV4;
if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState))
{
BeginConnectNodesOperation(VisualPort, p, Context.Mouse, State);
MouseHandled = true;
}
}
PushRenderQuad2D(RenderBuffer, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max, PortColor);
}
// Node Selection Panel
v4 LineBGColors[] = {
{ .16f, .16f, .16f, 1.f },
{ .18f, .18f, .18f, 1.f },
};
interface_list List = {};
List.LineBGColors = LineBGColors;
List.LineBGColorsCount = sizeof(LineBGColors) / sizeof(LineBGColors[0]);
List.LineBGHoverColor = v4{ .22f, .22f, .22f, 1.f };
List.TextColor = WhiteV4;
List.ListBounds = NodeSelectionWindowBounds;
List.ListElementDimensions = v2{
Rect2Width(NodeSelectionWindowBounds),
ui_GetTextLineHeight(State->Interface)
};
List.ElementLabelIndent = v2{10, 4};
gs_string Titlegs_string = MakeStringLiteral("Available Nodes");
DrawListElement(Titlegs_string, &List, Context.Mouse, RenderBuffer, State->Interface.Style);
for (u32 i = 0; i < NodeType_Count; i++)
{
node_specification_ Spec = NodeSpecifications[i];
rect2 ElementBounds = DrawListElement(Spec.Identifier, &List, Context.Mouse, RenderBuffer, State->Interface.Style);
if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState)
&& gs_PointIsInRect(Context.Mouse.DownPos, ElementBounds))
{
PushNodeOnWorkspace(i, &State->NodeWorkspace, &State->Transient);
GraphState->LayoutIsDirty = true;
MouseHandled = true;
}
}
if (!MouseHandled && MouseButtonTransitionedDown(Context.Mouse.LeftButtonState))
{
BeginPanNodeGraph(State, {}, Context.Mouse);
}
}
#define FOLDHAUS_PANEL_NODE_GRAPH_H
#endif // FOLDHAUS_PANEL_NODE_GRAPH_H

View File

@ -0,0 +1,55 @@
//
// File: foldhaus_search_lister.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_SEARCH_LISTER_CPP
internal b32
NamePassesFilter (gs_string Target, gs_string Filter)
{
return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter));
}
internal void
FilterSearchLister (search_lister* SearchLister)
{
Assert(SearchLister->FilteredIndexLUT != 0);
Assert(SearchLister->FilteredListMax == SearchLister->SourceListCount);
SearchLister->FilteredListCount = 0;
for (s32 i = 0; i < SearchLister->SourceListCount; i++)
{
gs_string* Namegs_string = SearchLister->SourceList + i;
if (NamePassesFilter(*Namegs_string, SearchLister->Filter))
{
SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i;
}
}
SearchLister->HotItem = Clamp(0, SearchLister->HotItem, SearchLister->FilteredListCount - 1);
if (SearchLister->FilteredListCount == 0)
{
SearchLister->HotItem = -1;
}
}
internal s32
GetNextFilteredItem (search_lister SearchLister)
{
s32 Result = Min(SearchLister.HotItem + 1, SearchLister.FilteredListCount - 1);
return Result;
}
internal s32
GetPrevFilteredItem (search_lister SearchLister)
{
s32 Result = Max(SearchLister.HotItem - 1, 0);
return Result;
}
#define FOLDHAUS_SEARCH_LISTER_CPP
#endif // FOLDHAUS_SEARCH_LISTER_CPP

View File

@ -0,0 +1,31 @@
//
// File: foldhaus_search_lister.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_SEARCH_LISTER_H
struct search_lister
{
// TODO(Peter): Giving up trying to just use the source list for now. At the moment
// we are copying the gs_strings you want to filter from and storing them here. Come back
// once its working and make the memory efficient version (ie store the existing memory
// location, the element stride and the offset to the char*)
s32 SourceListCount;
gs_string* SourceList;
// NOTE(Peter): stores the source indecies of each filtered item
// For example:
// Index 0 in this array contains 3. This means the first item that passes the filter
// is index 3 in ListMemory
s32 FilteredListMax;
s32 FilteredListCount;
s32* FilteredIndexLUT;
s32 HotItem;
gs_string Filter;
};
#define FOLDHAUS_SEARCH_LISTER_H
#endif // FOLDHAUS_SEARCH_LISTER_H

View File

@ -0,0 +1,249 @@
//
// File: foldhaus_text_entry.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_TEXT_ENTRY_CPP
internal void
ResetTextInput (text_entry* Input)
{
Input->CursorPosition = 0;
Input->Buffer.Length = 0;
}
internal void
PipeSearchStringToDestination (text_entry* Input)
{
switch (Input->Destination.Type)
{
case TextTranslateTo_gs_string:
{
PrintF(Input->Destination.StringDest, "%S", Input->Buffer);
}break;
case TextTranslateTo_R32:
{
*Input->Destination.FloatDest = (r32)ParseFloat(Input->Buffer.ConstString);
}break;
InvalidDefaultCase;
}
}
internal void
RemoveCharacterAtCursor (text_entry* TextEntry)
{
if (TextEntry->CursorPosition > 0)
{
for (u32 i = TextEntry->CursorPosition - 1; i < TextEntry->Buffer.Length; i++)
{
Assert(i + 1 < TextEntry->Buffer.Size);
TextEntry->Buffer.Str[i] = TextEntry->Buffer.Str[i + 1];
}
TextEntry->CursorPosition--;
}
}
internal void
SetTextInputDestinationToString (text_entry* TextInput, gs_string* DestinationString)
{
ResetTextInput(TextInput);
TextInput->Destination.Type = TextTranslateTo_gs_string;
TextInput->Destination.StringDest = DestinationString;
PrintF(&TextInput->Buffer, "%S", *DestinationString);
}
internal void
SetTextInputDestinationToFloat (text_entry* TextInput, r32* DestinationFloat)
{
ResetTextInput(TextInput);
TextInput->Destination.Type = TextTranslateTo_R32;
TextInput->Destination.FloatDest = DestinationFloat;
PrintF(&TextInput->Buffer, "%f", *DestinationFloat);
if (*DestinationFloat == 0.0f)
{
TextInput->CursorPosition = 1;
}
}
internal void
MoveCursorRight (text_entry* TextEntry)
{
TextEntry->CursorPosition = Min(TextEntry->Buffer.Length, TextEntry->CursorPosition + 1);
}
internal void
MoveCursorLeft (text_entry* TextEntry)
{
TextEntry->CursorPosition = Max(0, TextEntry->CursorPosition - 1);
}
FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar)
{
char Char = CharacterFromKeyCode(Event.Key);
if (Event.Key >= KeyCode_A && Event.Key <= KeyCode_Z && (Event.Modifiers & Modifier_Shift) == 0)
{
Char += ('a' - 'A');
}
// Shift string forward
Assert(State->ActiveTextEntry.Buffer.Length < State->ActiveTextEntry.Buffer.Size);
for (u32 i = State->ActiveTextEntry.Buffer.Length;
i > (u32)State->ActiveTextEntry.CursorPosition;
i--)
{
State->ActiveTextEntry.Buffer.Str[i] = State->ActiveTextEntry.Buffer.Str[i - 1];
}
// Insert new Character
State->ActiveTextEntry.Buffer.Str[State->ActiveTextEntry.CursorPosition] = Char;
State->ActiveTextEntry.CursorPosition++;
PipeSearchStringToDestination(&State->ActiveTextEntry);
}
FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntrygs_string)
{
RemoveCharacterAtCursor(&State->ActiveTextEntry);
}
FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorRight)
{
MoveCursorRight(&State->ActiveTextEntry);
}
FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorLeft)
{
MoveCursorLeft(&State->ActiveTextEntry);
}
internal void
InitializeTextInputCommands (input_command_registry* Commands, gs_memory_arena* PermanentStorage)
{
if (Commands->Size > 0)
{
RegisterKeyPressCommand(Commands, KeyCode_Backspace, Command_Began | Command_Held, KeyCode_Invalid, RemoveCharacterFromEntrygs_string);
RegisterKeyPressCommand(Commands, KeyCode_LeftArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorLeft);
RegisterKeyPressCommand(Commands, KeyCode_RightArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorRight);
for (s32 i = KeyCode_a; i < KeyCode_UpArrow; i++)
{
RegisterKeyPressCommand(Commands, (key_code)i, Command_Began | Command_Held, KeyCode_Invalid, TextEntryInsertChar);
}
}
}
#define DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY \
{ KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, RemoveCharacterFromEntrygs_string }, \
{ KeyCode_LeftArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorLeft }, \
{ KeyCode_RightArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorRight }, \
{ KeyCode_a, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_b, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_c, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_d, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_e, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_f, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_g, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_h, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_i, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_j, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_k, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_l, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_m, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_n, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_o, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_p, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_q, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_r, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_s, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_t, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_u, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_v, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_w, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_x, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_y, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_z, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_A, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_B, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_C, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_D, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_E, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_F, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_G, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_H, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_I, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_J, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_K, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_L, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_M, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_N, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_O, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_P, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Q, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_R, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_S, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_T, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_U, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_V, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_W, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_X, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Y, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Z, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_0, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_1, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_2, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_3, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_4, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_5, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_6, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_7, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_8, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_9, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num0, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num1, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num2, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num3, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num4, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num5, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num6, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num7, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num8, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Num9, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Bang, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_At, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Pound, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Dollar, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Percent, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Carrot, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Ampersand, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Star, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_LeftParen, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_RightParen, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Minus, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Plus, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Equals, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Underscore, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_LeftBrace, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_RightBrace, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_LeftBracket, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_RightBracket, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Colon, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_SemiColon, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_SingleQuote, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_DoubleQuote, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_ForwardSlash, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Backslash, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Pipe, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Comma, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Period, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_QuestionMark, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_LessThan, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_GreaterThan, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_Tilde, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \
{ KeyCode_BackQuote, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }
#define FOLDHAUS_TEXT_ENTRY_CPP
#endif // FOLDHAUS_TEXT_ENTRY_CPP

View File

@ -0,0 +1,36 @@
//
// File: foldhaus_text_entry.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_TEXT_ENTRY_H
enum text_translation_type
{
TextTranslateTo_gs_string,
TextTranslateTo_R32,
TextTranslateTo_S32,
TextTranslateTo_U32,
};
struct text_entry_destination
{
text_translation_type Type;
union {
gs_string* StringDest;
r32* FloatDest;
s32* SignedIntDest;
u32* UnsignedIntDest;
};
};
struct text_entry
{
gs_string Buffer;
s32 CursorPosition;
text_entry_destination Destination;
};
#define FOLDHAUS_TEXT_ENTRY_H
#endif // FOLDHAUS_TEXT_ENTRY_H

View File

@ -0,0 +1,377 @@
//
// File: foldhaus_util_radialumia_file_converter.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_UTIL_RADIALUMIA_FILE_CONVERTER_CPP
#define DEBUG
#define DEBUG_TRACK_SCOPE(name)
#include <stdlib.h>
#include <stdio.h>
#include <gs_string.h>
#include "gs/gs_language.h"
#include "gs/gs_string.h"
#include "../meta/gs_meta_lexer.h"
#include "gs/gs_vector.h"
#define gs_string_BUFFER_SIZE 512
struct gs_string_buffer
{
char* Memory;
s32 Size;
gs_string_buffer* Next;
};
struct gs_string_writer
{
char* Cursor;
s32 UsedIngs_string;
gs_string_buffer* Buffer;
};
internal gs_string_buffer*
Growgs_stringBuffer (gs_string_buffer* Buffer)
{
gs_string_buffer* Result;
if (Buffer->Next)
{
Result = Growgs_stringBuffer(Buffer->Next);
}
else
{
Result = (gs_string_buffer*)malloc(sizeof(gs_string_buffer));
Result->Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE);
memset(Result->Memory, 0, gs_string_BUFFER_SIZE);
Result->Size = gs_string_BUFFER_SIZE;
Result->Next = 0;
Buffer->Next = Result;
}
return Result;
}
internal void
Writegs_string(gs_string_writer* Writer, char* gs_string, s32 Length)
{
char* Src = gs_string;
char* Dst = Writer->Cursor;
s32 LengthWritten = 0;
while (*Src && Writer->UsedIngs_string < Writer->Buffer->Size &&LengthWritten < Length)
{
LengthWritten++;
*Dst++ = *Src++;
Writer->UsedIngs_string++;
}
Writer->Cursor = Dst;
if (*Src && Writer->UsedIngs_string == Writer->Buffer->Size)
{
*(Dst - 1) = 0; // Null terminate the buffer
Writer->Buffer = Growgs_stringBuffer(Writer->Buffer);
Writer->Cursor = Writer->Buffer->Memory;
Writer->UsedIngs_string = 0;
Writegs_string(Writer, (Src - 1), (Length - LengthWritten) + 1);
}
}
struct control_box_pairs
{
s32 Start;
s32 End;
};
struct extra_strips
{
s32 BoxID;
v3 Start;
v3 End;
};
struct control_box
{
s32 ID;
s32 Neighbors[6];
r32 X;
r32 Y;
r32 Z;
char* Address;
};
int main(int ArgCount, char* Args[])
{
FILE* OldFilePtr = fopen("F:/data/radia_old.fold", "r");
if (!OldFilePtr)
{
InvalidCodePath;
}
fseek(OldFilePtr, 0, SEEK_END);
s32 OldFileSize = ftell(OldFilePtr);
fseek(OldFilePtr, 0, SEEK_SET);
char* OldFile = (char*)malloc(sizeof(char) * OldFileSize);
fread(OldFile, 1, OldFileSize, OldFilePtr);
fclose(OldFilePtr);
s32 ControlBoxPairsUsed = 0;
control_box_pairs* ControlBoxPairs = (control_box_pairs*)malloc(sizeof(control_box_pairs) * 512);
s32 ControlBoxesUsed = 0;
control_box* ControlBoxes = (control_box*)malloc(sizeof(control_box) * 64);
s32 ExtraStripsUsed = 0;
extra_strips* ExtraStrips = (extra_strips*)malloc(sizeof(extra_strips) * (42 * 4));
control_box_pairs* NextControlBoxPair = &ControlBoxPairs[0];
control_box* NextControlBox = &ControlBoxes[0];
extra_strips* NextStrip = &ExtraStrips[0];
tokenizer Tokenizer = {};
Tokenizer.At = OldFile;
while(*Tokenizer.At)
{
// Parse a Control Box
memset(NextControlBox->Neighbors, -1, 6);
s32 NeighborsAdded = 0;
control_box_pairs* StartPair = NextControlBoxPair;
s32 PairsCount = 0;
if (gs_stringsEqual(Tokenizer.At, "EOF"))
{
break;
}
EatToCharacterInclusive(&Tokenizer, '{');
EatWhitespace(&Tokenizer);
Assert(gs_stringsEqual(Tokenizer.At, "neighbors: ["));
Tokenizer.At += gs_stringLength("neighbors: [");
// Parse Neighbors
while(*Tokenizer.At && *Tokenizer.At != ']')
{
s32 NeighborIndex = ParseSignedInt(Tokenizer.At);
NextControlBox->Neighbors[NeighborsAdded++] = NeighborIndex;
NextControlBoxPair->End = NeighborIndex;
NextControlBoxPair++;
PairsCount++;
ControlBoxPairsUsed++;
EatNumber(&Tokenizer);
if (*Tokenizer.At == ']')
{
Tokenizer.At += 2; // Eat past "];"
break;
}
else
{
EatToCharacterInclusive(&Tokenizer, ',');
EatWhitespace(&Tokenizer);
}
}
EatWhitespace(&Tokenizer);
//Parse IP
Assert(gs_stringsEqual(Tokenizer.At, "ip: "));
Tokenizer.At += gs_stringLength("ip: ");
NextControlBox->Address = (char*)malloc(sizeof(char) * 13);
memcpy(NextControlBox->Address, Tokenizer.At, 13);
Tokenizer.At += 13;
Tokenizer.At++; // Eat past ";"
// Parse X
EatWhitespace(&Tokenizer);
Assert(gs_stringsEqual(Tokenizer.At, "x: "));
Tokenizer.At += gs_stringLength("x: ");
NextControlBox->X = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';');
// Parse Y
EatWhitespace(&Tokenizer);
Assert(gs_stringsEqual(Tokenizer.At, "y: "));
Tokenizer.At += gs_stringLength("y: ");
NextControlBox->Y = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';');
// Parse Z
EatWhitespace(&Tokenizer);
Assert(gs_stringsEqual(Tokenizer.At, "z: "));
Tokenizer.At += gs_stringLength("z: ");
NextControlBox->Z = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';');
// Parse ID
EatWhitespace(&Tokenizer);
Assert(gs_stringsEqual(Tokenizer.At, "id: "));
Tokenizer.At += gs_stringLength("id: ");
NextControlBox->ID = ParseSignedInt(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';');
control_box_pairs* PairCursor = StartPair;
for(s32 i = 0; i < PairsCount; i++)
{
PairCursor->Start = NextControlBox->ID;
PairCursor++;
}
NextControlBox++;
ControlBoxesUsed++;
EatToCharacterInclusive(&Tokenizer, ';');
EatWhitespace(&Tokenizer);
}
// Add Spikes
#define SPIKE_LEDS 346
for (s32 sp = 0; sp < ControlBoxesUsed; sp++)
{
control_box* Box = &ControlBoxes[sp];
control_box* NeighborA = &ControlBoxes[Box->Neighbors[0]];
control_box* NeighborB = &ControlBoxes[Box->Neighbors[1]];
v3 SpikeCenter = v3{Box->X, Box->Y, Box->Z};
v3 StripPitch = Normalize(SpikeCenter) * ((2.f/8.f) / SPIKE_LEDS);
v3 ToNA = Normalize(v3{NeighborA->X, NeighborA->Y, NeighborA->Z} - SpikeCenter);
v3 ToNB = Normalize(v3{NeighborB->X, NeighborB->Y, NeighborB->Z} - SpikeCenter);
v3 StripAOutStart = SpikeCenter + (ToNA * .01f);
v3 StripAOutEnd = StripAOutStart + (StripPitch * SPIKE_LEDS);
v3 StripBOutStart = SpikeCenter + (ToNB * .01f);
v3 StripBOutEnd = StripBOutStart + (StripPitch * SPIKE_LEDS);
v3 StripAInStart = StripAOutEnd - (ToNA * .02f);
v3 StripAInEnd = StripAOutStart - (ToNA * .02f);
v3 StripBInStart = StripBOutEnd - (ToNA * .02f);
v3 StripBInEnd = StripBOutStart - (ToNA * .02f);
NextStrip->BoxID = Box->ID;
NextStrip->Start = StripAOutStart;
NextStrip->End = StripAOutEnd;
NextStrip++;
ExtraStripsUsed++;
NextStrip->BoxID = Box->ID;
NextStrip->Start = StripAInStart;
NextStrip->End = StripAInEnd;
NextStrip++;
ExtraStripsUsed++;
NextStrip->BoxID = Box->ID;
NextStrip->Start = StripBOutStart;
NextStrip->End = StripBOutEnd;
NextStrip++;
ExtraStripsUsed++;
NextStrip->BoxID = Box->ID;
NextStrip->Start = StripBInStart;
NextStrip->End = StripBInEnd;
NextStrip++;
ExtraStripsUsed++;
}
gs_string_buffer OutputFileBuffer = {};
OutputFileBuffer.Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE);
OutputFileBuffer.Size = gs_string_BUFFER_SIZE;
OutputFileBuffer.Next = 0;
gs_string_writer RefWriter = {};
RefWriter.Cursor = OutputFileBuffer.Memory;
RefWriter.UsedIngs_string = 0;
RefWriter.Buffer = &OutputFileBuffer;
gs_string_writer* Writer = &RefWriter;
char gs_stringBuffer[512];
s32 Len = 0;
Len = sprintf_s(gs_stringBuffer, 512, "control_box_count %d\n", ControlBoxesUsed);
Writegs_string(Writer, gs_stringBuffer, Len);
Len = sprintf_s(gs_stringBuffer, 512, "led_strip_count %d\n\n", ControlBoxPairsUsed);
Writegs_string(Writer, gs_stringBuffer, Len);
for (s32 c = 0; c < ControlBoxesUsed; c++)
{
control_box* Box = ControlBoxes + c;
Len = sprintf_s(gs_stringBuffer, 512,
"control_box { %d, \"%s\", (%f, %f, %f) }\n",
Box->ID, Box->Address,
Box->X, Box->Y, Box->Z);
Writegs_string(Writer, gs_stringBuffer, Len);
}
Writegs_string(Writer, "\n", 1);
#define UNIVERSES_PER_BOX 25
s32 UniversesPerBox[64];
for (s32 u = 0; u < 64; u++)
{
UniversesPerBox[u] = UNIVERSES_PER_BOX * u;
}
char LEDStripFormatgs_string[] = "led_strip { %d, %d, %d, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 144 } \n";
for (s32 s = 0; s < ControlBoxPairsUsed; s++)
{
control_box_pairs* Pair = ControlBoxPairs + s;
s32 Universe = UniversesPerBox[Pair->Start];
UniversesPerBox[Pair->Start]++;
r32 StartX = ControlBoxes[Pair->Start].X;
r32 StartY = ControlBoxes[Pair->Start].Y;
r32 StartZ = ControlBoxes[Pair->Start].Z;
r32 EndX = ControlBoxes[Pair->End].X;
r32 EndY = ControlBoxes[Pair->End].Y;
r32 EndZ = ControlBoxes[Pair->End].Z;
Len = sprintf_s(gs_stringBuffer, 512,
LEDStripFormatgs_string,
Pair->Start, Universe, 0,
StartX, StartY, StartZ,
EndX, EndY, EndZ);
Writegs_string(Writer, gs_stringBuffer, Len);
}
Writegs_string(Writer, "\n", 1);
for (s32 sp = 0; sp < ExtraStripsUsed; sp++)
{
extra_strips* Strip = ExtraStrips + sp;
s32 Universe = UniversesPerBox[Strip->BoxID];
UniversesPerBox[Strip->BoxID]++;
Len = sprintf_s(gs_stringBuffer, 512,
LEDStripFormatgs_string,
Strip->BoxID, Universe, 0,
Strip->Start.x, Strip->Start.y, Strip->Start.z,
Strip->End.x, Strip->End.y, Strip->End.z);
Writegs_string(Writer, gs_stringBuffer, Len);
}
Writegs_string(Writer, "END_OF_ASSEMBLY_FILE", gs_stringLength("END_OF_ASSEMBLY_FILE"));
*Writer->Cursor = 0;
FILE* OutputFile = fopen("F:/data/radialumia.fold", "w");
gs_string_buffer* BufferCursor = &OutputFileBuffer;
while(BufferCursor)
{
fprintf(OutputFile, BufferCursor->Memory);
BufferCursor = BufferCursor->Next;
}
fclose(OutputFile);
return 0;
}
#define FOLDHAUS_UTIL_RADIALUMIA_FILE_CONVERTER_CPP
#endif // FOLDHAUS_UTIL_RADIALUMIA_FILE_CONVERTER_CPP

View File

@ -0,0 +1,513 @@
//
// File: foldhaus_node_interface.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLHAUS_NODE_INTERFACE_CPP
////////////////////////////////////////
//
// Node Lister
//
///////////////////////////////////////
struct node_lister_operation_state
{
search_lister SearchLister;
v2 ListPosition;
};
internal void
RenderNodeLister(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory;
v2 TopLeft = OpState->ListPosition;
v2 Dimension = v2{300, 30};
// Filter the lister
OpState->SearchLister.Filter = State->ActiveTextEntry.Buffer;
FilterSearchLister(&OpState->SearchLister);
// Display Search Lister
search_lister_result NodeListerResult = EvaluateSearchLister (&State->Interface_, TopLeft, Dimension,
MakeStringLiteral("Nodes List"),
OpState->SearchLister.SourceList,
OpState->SearchLister.FilteredIndexLUT,
OpState->SearchLister.FilteredListCount,
OpState->SearchLister.HotItem,
&State->ActiveTextEntry.Buffer,
State->ActiveTextEntry.CursorPosition);
}
FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem)
{
node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state);
OpState->SearchLister.HotItem = GetNextFilteredItem(OpState->SearchLister);
}
FOLDHAUS_INPUT_COMMAND_PROC(NodeListerPrevItem)
{
node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state);
OpState->SearchLister.HotItem = GetPrevFilteredItem(OpState->SearchLister);
}
FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeLister)
{
DeactivateCurrentOperationMode(&State->Modes);
}
FOLDHAUS_INPUT_COMMAND_PROC(SelectAndCloseNodeLister)
{
node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state);
s32 FilteredNodeIndex = OpState->SearchLister.HotItem;
if (FilteredNodeIndex >= 0)
{
s32 NodeIndex = OpState->SearchLister.FilteredIndexLUT[FilteredNodeIndex];
PushNodeOnListFromSpecification(State->NodeList, (node_type)NodeIndex,
Mouse.Pos, State->Permanent);
}
CloseNodeLister(State, Event, Mouse);
}
input_command UniverseViewCommads [] = {
{ KeyCode_DownArrow, KeyCode_Invalid, Command_Began, NodeListerNextItem },
{ KeyCode_UpArrow, KeyCode_Invalid, Command_Began, NodeListerPrevItem },
{ KeyCode_Enter, KeyCode_Invalid, Command_Began, SelectAndCloseNodeLister },
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, CloseNodeLister },
{ KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseNodeLister },
DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY,
};
FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister)
{
operation_mode* AddNodeOperation = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommads);
AddNodeOperation->Render = RenderNodeLister;
node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation,
&State->Modes,
node_lister_operation_state);
{
OpState->SearchLister.SourceListCount = NodeSpecificationsCount;
OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, gs_string, OpState->SearchLister.SourceListCount);
{
for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++)
{
OpState->SearchLister.SourceList[i] = MakeString(
NodeSpecifications[i].Name,
NodeSpecifications[i].NameLength);
}
}
OpState->SearchLister.Filter = MakeString(PushArray(&State->Modes.Arena, char, 64), 0, 64);
OpState->SearchLister.FilteredListMax = OpState->SearchLister.SourceListCount;
OpState->SearchLister.FilteredListCount = 0;
OpState->SearchLister.FilteredIndexLUT = PushArray(&State->Modes.Arena, s32, OpState->SearchLister.SourceListCount);
}
OpState->ListPosition = Mouse.Pos;
SetTextInputDestinationTogs_string(&State->ActiveTextEntry, &OpState->SearchLister.Filter);
}
////////////////////////////////////////
//
// Node Color Picker
//
///////////////////////////////////////
struct color_picker_operation_state
{
v4* ValueAddr;
};
internal void
CloseColorPicker(app_state* State)
{
DeactivateCurrentOperationMode(&State->Modes);
}
FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand)
{
CloseColorPicker(State);
}
internal void
RenderColorPicker(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory;
b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr,
v2{200, 200}, State->Interface, Mouse);
if (ShouldClose)
{
CloseColorPicker(State);
}
}
input_command ColorPickerCommands [] = {
{ KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseColorPickerCommand },
};
internal void
OpenColorPicker(app_state* State, node_connection* Connection)
{
operation_mode* ColorPickerMode = ActivateOperationModeWithCommands(&State->Modes, ColorPickerCommands);
ColorPickerMode->Render = RenderColorPicker;
color_picker_operation_state* OpState = CreateOperationState(ColorPickerMode,
&State->Modes,
color_picker_operation_state);
OpState->ValueAddr = Connection->V4ValuePtr;
}
////////////////////////////////////////
//
// Node Field Text Edit
//
///////////////////////////////////////
FOLDHAUS_INPUT_COMMAND_PROC(EndNodeFieldTextEdit)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command NodeFieldTextEditCommands [] = {
{ KeyCode_Enter, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit },
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit },
DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY,
};
internal void
BeginNodeFieldTextEdit(app_state* State, node_connection* Connection)
{
operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes,
NodeFieldTextEditCommands);
SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr);
}
////////////////////////////////////////
//
// Node Port Mouse Drag
//
///////////////////////////////////////
struct drag_node_port_operation_state
{
node_interaction Interaction;
};
internal void
RenderDraggingNodePort(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory;
UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList,
State->NodeRenderSettings, RenderBuffer);
}
FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNodePort)
{
drag_node_port_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_port_operation_state);
TryConnectNodes(OpState->Interaction, Mouse.Pos, State->NodeList, State->NodeRenderSettings);
DeactivateCurrentOperationMode(&State->Modes);
}
input_command DragNodePortInputCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNodePort },
};
internal void
BeginDraggingNodePort(app_state* State, node_interaction Interaction)
{
operation_mode* DragNodePortMode = ActivateOperationModeWithCommands(
&State->Modes,
DragNodePortInputCommands);
DragNodePortMode->Render = RenderDraggingNodePort;
drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode,
&State->Modes,
drag_node_port_operation_state);
OpState->Interaction = Interaction;
}
////////////////////////////////////////
//
// Node Field Mouse Drag
//
///////////////////////////////////////
internal void
RenderDragNodeField(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
// TODO(Peter):
//UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State);
}
internal void
BeginInteractWithNodeField(app_state* State, node_interaction Interaction)
{
// TODO(Peter):
}
////////////////////////////////////////
//
// Node Mouse Drag
//
///////////////////////////////////////
struct drag_node_operation_state
{
node_interaction Interaction;
};
internal void
RenderDraggingNode(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state);
UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList,
State->NodeRenderSettings);
}
FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNode)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command DragNodeInputCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNode },
};
internal void
BeginDraggingNode(app_state* State, node_interaction Interaction)
{
operation_mode* DragNodeMode = ActivateOperationModeWithCommands(
&State->Modes,
DragNodeInputCommands);
DragNodeMode->Render = RenderDraggingNode;
drag_node_operation_state* OpState = CreateOperationState(DragNodeMode,
&State->Modes,
drag_node_operation_state);
OpState->Interaction = Interaction;
}
////////////////////////////////////////
//
// Node View
//
///////////////////////////////////////
struct node_view_operation_state
{
s32 SelectedNodeHandle;
};
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction)
{
node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state);
node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings);
if (Node)
{
node_interaction NewInteraction = GetNodeInteractionType(Node,
Mouse.Pos,
State->NodeRenderSettings);
if (IsDraggingNodePort(NewInteraction))
{
BeginDraggingNodePort(State, NewInteraction);
}
else if(IsDraggingNodeValue(NewInteraction))
{
// TODO(Peter): This probably wants to live in a mouse held action
// the first frame we realize we're held over a field, just transition to
// drag node field
//BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings);
}
else // IsDraggingNode
{
OpState->SelectedNodeHandle = Node->Handle;
BeginDraggingNode(State, NewInteraction);
}
}
else
{
OpState->SelectedNodeHandle = 0;
}
}
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction)
{
node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state);
node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings);
if (Node)
{
node_interaction NewInteraction = GetNodeInteractionType(Node,
Mouse.Pos,
State->NodeRenderSettings);
if(IsDraggingNodeValue(NewInteraction))
{
node_connection* Connection = Node->Connections + NewInteraction.InputValue;
struct_member_type InputType = Connection->Type;
if (InputType == MemberType_r32)
{
BeginNodeFieldTextEdit(State, Connection);
}
else if (InputType == MemberType_v4)
{
OpenColorPicker(State, Connection);
}
}
}
}
internal void
RenderNodeView(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{
node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory;
DEBUG_TRACK_FUNCTION;
MakeStringBuffer(NodeHeaderBuffer, 128);
node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle);
node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList);
while (NodeIteratorIsValid(NodeIter))
{
node_header* Node = NodeIter.At;
rect2 NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings);
b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds);
if (Node == SelectedNode)
{
PushRenderQuad2D(RenderBuffer, NodeBounds.Min - v2{2, 2}, NodeBounds.Max + v2{2, 2}, WhiteV4);
}
PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f});
// TODO(Peter): This is just for debug purposes. We can remove and go back to just having
// Node->Name in Drawgs_string
gs_string NodeName = GetNodeName(*Node);
PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle);
DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font,
v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)},
WhiteV4);
for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++)
{
v4 PortColor = State->NodeRenderSettings.PortColors[Node->Connections[Connection].Type];
// Inputs
if (ConnectionIsInput(Node, Connection))
{
rect2 PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings);
DrawPort(RenderBuffer, PortBounds, PortColor);
//
// TODO(Peter): I don't like excluding OutputNode, feels too much like a special case
// but I don't want to get in to the meta programming right now.
// We should just generate a spec and struct member types for NodeType_OutputNode
//
// :ExcludingOutputNodeSpecialCase
//
if (Node->Type != NodeType_OutputNode && DrawFields)
{
node_specification Spec = NodeSpecifications[Node->Type];
node_struct_member Member = Spec.MemberList[Connection];
DrawString(RenderBuffer, MakeString(Member.Name),
State->NodeRenderSettings.Font,
v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right);
}
rect2 ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings);
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font);
// NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship,
// whereas output ports might have many connections, they really only know about the most recent one
// Not sure if this is a problem. We mostly do everything backwards here, starting at the
// most downstream node and working back up to find dependencies.
if (ConnectionHasUpstreamConnection(Node, Connection))
{
rect2 ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings);
v2 InputCenter = CalculateRectCenter(PortBounds);
v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds);
PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4);
}
}
// Outputs
if (ConnectionIsOutput(Node, Connection))
{
rect2 PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings);
DrawPort(RenderBuffer, PortBounds, PortColor);
if (DrawFields)
{
node_specification Spec = NodeSpecifications[Node->Type];
node_struct_member Member = Spec.MemberList[Connection];
DrawString(RenderBuffer, MakeString(Member.Name),
State->NodeRenderSettings.Font,
v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4);
}
rect2 ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings);
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font);
}
for (s32 Button = 0; Button < 3; Button++)
{
rect2 ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings);
PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]);
}
}
Next(&NodeIter);
}
}
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewDeleteNode)
{
node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state);
if (OpState->SelectedNodeHandle > 0)
{
node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle);
FreeNodeOnList(State->NodeList, SelectedNode);
}
}
FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command NodeViewCommands [] = {
{ KeyCode_Tab, KeyCode_Invalid, Command_Began, CloseNodeView},
{ KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister},
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction},
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction},
{ KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode},
};
FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView)
{
operation_mode* NodeViewMode = ActivateOperationModeWithCommands(&State->Modes, NodeViewCommands);
NodeViewMode->Render = RenderNodeView;
node_view_operation_state* OpState = CreateOperationState(NodeViewMode,
&State->Modes,
node_view_operation_state);
OpState->SelectedNodeHandle = 0;
}
#define FOLHAUS_NODE_INTERFACE_CPP
#endif // FOLHAUS_NODE_INTERFACE_CPP

View File

@ -0,0 +1,206 @@
//
// File: foldhaus_command_dispatch.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_COMMAND_DISPATCH_H
#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse, context Context, panel* Panel)
typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc);
// NOTE(Peter): Helper function so I don't have to remember the parameters to this define
#define ExecFoldhausCommand(cmd) cmd(State, Event, Mouse)
enum input_command_flags
{
Command_Began = 1 << 0,
Command_Held = 1 << 1,
Command_Ended = 1 << 2,
};
#define Command_Any Command_Began | Command_Held | Command_Ended
// TODO(Peter): At the moment these are all key press commands. Need a way to differentiate between
// press and hold. Probably add a second array to input_command_Registry
struct input_command
{
key_code Key;
key_code Mdfr;
b32 Flags;
input_command_proc* Proc;
};
struct input_command_registry
{
input_command* Commands;
s32 Size;
s32 Used;
input_command_proc* MouseWheelCommand;
};
struct command_queue_entry
{
input_command Command;
input_entry Event;
};
struct input_command_queue
{
s32 Size;
s32 Used;
command_queue_entry* Commands;
};
internal void
InitializeInputCommandRegistry (input_command_registry* CommandRegistry,
s32 Size,
gs_memory_arena* Storage)
{
CommandRegistry->Commands = PushArray(Storage, input_command, Size);
CommandRegistry->Size = Size;
CommandRegistry->Used = 0;
}
internal void
RegisterMouseWheelCommand (input_command_registry* CommandRegistry,
input_command_proc* Proc)
{
CommandRegistry->MouseWheelCommand = Proc;
}
internal s32
GetCommandIndexInQueue(input_command_queue* Queue, input_command Command, input_entry Event)
{
s32 Result = -1;
for (s32 CommandIndex = 0; CommandIndex < Queue->Used; CommandIndex++)
{
command_queue_entry* Entry = Queue->Commands + CommandIndex;
if(Entry->Event.Key == Event.Key)
{
Result = CommandIndex;
break;
}
}
return Result;
}
internal input_command_queue
CommandQueue_Create(gs_memory_arena* Storage, u64 CommandMaxCount)
{
input_command_queue Result = {};
Result.Size = CommandMaxCount;
Result.Used = 0;
Result.Commands = PushArray(Storage, command_queue_entry, CommandMaxCount);
return Result;
}
internal void
ClearCommandQueue(input_command_queue* Queue)
{
Queue->Used = 0;
}
internal void
PushCommandOnQueue(input_command_queue* Queue, input_command Command, input_entry Event)
{
Assert(Queue->Used < Queue->Size);
command_queue_entry Entry = {};
Entry.Command = Command;
Entry.Event = Event;
Queue->Commands[Queue->Used++] = Entry;
}
internal void
RemoveCommandFromQueue(input_command_queue* Queue, s32 Index)
{
s32 CommandIndex = Index;
if (CommandIndex < Queue->Used)
{
Queue->Used -= 1;
for (; CommandIndex < Queue->Used; CommandIndex++)
{
Queue->Commands[CommandIndex] = Queue->Commands[CommandIndex + 1];
}
}
}
internal void
RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_entry Event)
{
s32 CommandIndex = GetCommandIndexInQueue(Queue, Command, Event);
// NOTE(Peter): If we made it through the queue without finding an event, there wasn't one
// to remove. This happens when we've changed command registries as a result of an input command,
// and the command exists in the new registry.
// For example:
// clicking a mouse button triggers a command to switch registries
// the new registry tracks mouse drag (persist until release)
// when the mouse is released, the event fires, but there is no mouse down event to remove
// For this reason, I'm allowing the case where we try and remove a command where non exists
// I don't think this is a great solution but Im not super familiar with the codebase right now
// so leaving it as is. revisit if it becomes a problem.
RemoveCommandFromQueue(Queue, CommandIndex);
}
internal input_command*
FindExistingCommand (input_command_registry CommandRegistry, key_code Key, key_code Mdfr, b32 Flags)
{
input_command* Result = 0;
for (s32 Cmd = 0; Cmd < CommandRegistry.Used; Cmd++)
{
input_command* Command = CommandRegistry.Commands + Cmd;
if (Command->Key == Key && Command->Mdfr == Mdfr)
{
b32 FlagsOverlap = Flags & Command->Flags;
if (FlagsOverlap)
{
Result = Command;
break;
}
}
}
return Result;
}
internal b32
FindAndPushExistingCommand(input_command_registry CommandRegistry, input_entry Event, b32 Flags, input_command_queue* CommandQueue)
{
b32 CommandFound = false;
input_command* Command = FindExistingCommand(CommandRegistry, Event.Key, (key_code)0, Flags);
if (Command)
{
PushCommandOnQueue(CommandQueue, *Command, Event);
CommandFound = true;
}
return CommandFound;
}
internal void
RegisterKeyPressCommand (input_command_registry* CommandRegistry,
key_code Key,
b32 Flags,
key_code Mdfr,
input_command_proc* Proc)
{
input_command* Command = FindExistingCommand(*CommandRegistry, Key, Mdfr, Flags);
if (!Command)
{
Assert(CommandRegistry->Size > CommandRegistry->Used);
Assert(Mdfr == KeyCode_Invalid || Mdfr == KeyCode_LeftShift || Mdfr == KeyCode_RightShift ||
Mdfr == KeyCode_LeftCtrl || Mdfr == KeyCode_RightCtrl || Mdfr == KeyCode_Alt);
Command = CommandRegistry->Commands + CommandRegistry->Used++;
}
Command->Key = Key;
Command->Flags = Flags;
Command->Mdfr = Mdfr;
Command->Proc = Proc;
}
#define FOLDHAUS_COMMAND_DISPATCH_H
#endif // FOLDHAUS_COMMAND_DISPATCH_H

View File

@ -0,0 +1,156 @@
//
// File: foldhaus_editor.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-24
//
#ifndef FOLDHAUS_EDITOR_CPP
internal void
Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context)
{
DEBUG_TRACK_FUNCTION;
b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State);
gs_string TextInputString = PushString(State->Transient, 32);
panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos);
if (ActivePanel)
{
panel_definition ActiveDef = State->PanelSystem.PanelDefs[ActivePanel->TypeIndex];
input_command_registry ActiveCommands = {};
if (State->Modes.ActiveModesCount > 0)
{
ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands;
}
else if (ActiveDef.InputCommands)
{
ActiveCommands.Commands = ActiveDef.InputCommands;
ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]);
ActiveCommands.Used = ActiveCommands.Size;
}
// Fill up the command queue
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
{
input_entry Event = InputQueue.Entries[EventIdx];
bool IsMouseEvent = (Event.Key == KeyCode_MouseLeftButton ||
Event.Key == KeyCode_MouseMiddleButton ||
Event.Key == KeyCode_MouseRightButton);
if (IsMouseEvent && MouseInputHandled)
{
continue;
}
// NOTE(Peter): These are in the order Down, Up, Held because we want to privalege
// Down and Up over Held. In other words, we don't want to call a Held command on the
// frame when the button was released, even if the command is registered to both events
if (KeyTransitionedDown(Event))
{
if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue))
{
char KeyASCII = KeyCodeToChar(Event.Key);
if (KeyASCII)
{
OutChar(&TextInputString, KeyASCII);
}
}
}
else if (KeyTransitionedUp(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue);
}
else if (KeyHeldDown(Event))
{
if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue))
{
char KeyASCII = KeyCodeToChar(Event.Key);
if (KeyASCII)
{
OutChar(&TextInputString, KeyASCII);
}
}
}
}
}
// Execute all commands in CommandQueue
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
{
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
if (Entry->Command.Proc)
{
Entry->Command.Proc(State, Entry->Event, Mouse, Context, ActivePanel);
}
else
{
EndCurrentOperationMode(State);
}
}
State->Interface.TempInputString = TextInputString.ConstString;
ClearCommandQueue(&State->CommandQueue);
}
internal void
Editor_Update(app_state* State, context* Context, input_queue InputQueue)
{
Context->Mouse.CursorType = CursorType_Arrow;
State->WindowBounds = Context->WindowBounds;
State->Interface.Mouse = Context->Mouse;
State->Interface.HotWidgetFramesSinceUpdate += 1;
if (State->Interface.HotWidgetFramesSinceUpdate > 1)
{
State->Interface.HotWidget = {};
}
Assert(State->Interface.PerFrameMemory &&
(u64)State->Interface.PerFrameMemory != 0x5);
PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds);
Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
}
internal void
Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
{
State->Interface.WindowBounds = Context->WindowBounds;
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
PushRenderClearScreen(RenderBuffer);
ui_InterfaceReset(&State->Interface);
State->Interface.RenderBuffer = RenderBuffer;
ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout"));
{
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{
operation_mode OperationMode = State->Modes.ActiveModes[m];
if (OperationMode.Render != 0)
{
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
}
}
}
ui_PopLayout(&State->Interface, MakeString("Editor Layout"));
// Draw the Interface
if (State->Interface.DrawOrderRoot != 0)
{
ui_widget* Widget = State->Interface.DrawOrderRoot;
Editor_DrawWidgetList(State, Context, RenderBuffer, Widget, Context->WindowBounds);
}
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
}
#define FOLDHAUS_EDITOR_CPP
#endif // FOLDHAUS_EDITOR_CPP

View File

@ -0,0 +1,170 @@
//
// File: foldhaus_editor_draw.h
// Author: Peter Slattery
// Creation Date: 2021-01-16
//
#ifndef FOLDHAUS_EDITOR_DRAW_H
internal void
Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color, s32 CursorPosition)
{
gs_string Temp = PushString(State->Transient, 256);
PrintF(&Temp, "%d", Widget.Id.Id);
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer,
Widget.String.Length + 1,
State->Interface.Style.Font->BitmapMemory,
State->Interface.Style.Font->BitmapTextureHandle,
State->Interface.Style.Font->BitmapWidth,
State->Interface.Style.Font->BitmapHeight,
State->Interface.Style.Font->BitmapBytesPerPixel,
State->Interface.Style.Font->BitmapStride);
v2 RegisterPosition = Widget.Bounds.Min + State->Interface.Style.Margin;
switch (Widget.Alignment)
{
case Align_Left:
{
RegisterPosition = DrawStringLeftAligned(RenderBuffer,
&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color, CursorPosition, GreenV4);
}break;
case Align_Right:
{
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color);
}break;
InvalidDefaultCase;
}
}
enum widget_fill_dir
{
WidgetFill_Horizontal = 0,
WidgetFill_Vertical = 1,
};
internal rect2
Editor_GetWidgetFillBounds(ui_widget Widget)
{
Assert(ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill));
rect2 Result = {};
widget_fill_dir Dir = WidgetFill_Horizontal;
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) { Dir = WidgetFill_Vertical; }
widget_fill_dir OtherDir = (widget_fill_dir)(WidgetFill_Vertical - Dir);
Result.Min.E[Dir] = Widget.Bounds.Min.E[Dir];
Result.Max.E[Dir] = Widget.Bounds.Max.E[Dir];
r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.E[OtherDir], Widget.Bounds.Max.E[OtherDir]);
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed))
{
Result.Min.E[OtherDir] = FillToPoint;
Result.Max.E[OtherDir] = Widget.Bounds.Max.E[OtherDir];
}
else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle))
{
Result.Min.E[OtherDir] = FillToPoint - 5;
Result.Max.E[OtherDir] = FillToPoint + 5;
}
else
{
Result.Min.E[OtherDir] = Widget.Bounds.Min.E[OtherDir];
Result.Max.E[OtherDir] = FillToPoint;
}
return Result;
}
internal void Editor_DrawWidgetList(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds);
internal void
Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 WidgetParentUnion)
{
bool IsActiveWidget = ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget);
;
if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0))
{
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
{
v4 Color = State->Interface.Style.ButtonColor_Inactive;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget))
{
Color = State->Interface.Style.ButtonColor_Active;
}
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = State->Interface.Style.ButtonColor_Selected;
}
PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color);
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
{
v4 Color = State->Interface.Style.TextColor;
s32 CursorPosition = -1;
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_Typable) && IsActiveWidget)
{
CursorPosition = State->Interface.CursorPosition;
}
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color, CursorPosition);
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) ||
ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill))
{
v4 Color = State->Interface.Style.ButtonColor_Selected;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) ||
ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = WhiteV4;
}
rect2 FillBounds = Editor_GetWidgetFillBounds(Widget);
rect2 ClippedFillBounds = Rect2Union(FillBounds, WidgetParentUnion);
PushRenderQuad2D(RenderBuffer, ClippedFillBounds, Color);
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
{
v4 TextColor = BlackV4;
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, ClippedFillBounds, TextColor, -1);
}
}
bool DrawOutline = ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline);
DrawOutline |= ui_WidgetIsFlagSet(Widget, UIWidgetFlag_Typable) && IsActiveWidget;
if (DrawOutline)
{
// TODO(pjs): replace these with values from the style
r32 Thickness = 1.0f;
v4 Color = WhiteV4;
PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color);
}
}
}
internal void Editor_DrawWidgetList(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget* Widget, rect2 ParentClipBounds)
{
ui_widget* WidgetAt = Widget;
while (WidgetAt)
{
rect2 WidgetParentUnion = WidgetAt->Bounds;
WidgetParentUnion = Rect2Union(WidgetAt->Bounds, ParentClipBounds);
Editor_DrawWidget(State, Context, RenderBuffer, *WidgetAt, WidgetParentUnion);
if (WidgetAt->ChildrenRoot)
{
Editor_DrawWidgetList(State, Context, RenderBuffer, WidgetAt->ChildrenRoot, WidgetParentUnion);
}
WidgetAt = WidgetAt->Next;
}
}
#define FOLDHAUS_EDITOR_DRAW_H
#endif // FOLDHAUS_EDITOR_DRAW_H

View File

@ -0,0 +1,463 @@
//
// File: foldhaus_interface.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_INTERFACE_CPP
////////////////////////////////////////
//
// Panels
//
///////////////////////////////////////
enum panel_edit_mode
{
PanelEdit_Invalid,
PanelEdit_Modify,
PanelEdit_Destroy,
PanelEdit_Count,
};
//
// Drag Panel Border Operation Mode
OPERATION_STATE_DEF(drag_panel_border_operation_state)
{
panel* Panel;
// NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying,
// it stores the value calculated when the operation mode is kicked off.
rect2 InitialPanelBounds;
panel_split_direction PanelEdgeDirection;
panel_edit_mode PanelEditMode;
};
OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder)
{
drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory;
rect2 PanelBounds = OpState->InitialPanelBounds;
if (OpState->PanelEditMode == PanelEdit_Modify)
{
v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f};
v2 EdgePreviewMin = {};
v2 EdgePreviewMax = {};
if (OpState->PanelEdgeDirection == PanelSplit_Horizontal)
{
EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y};
EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1};
}
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
{
EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y};
EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y};
}
PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor);
}
else if (OpState->PanelEditMode == PanelEdit_Destroy)
{
rect2 PanelToDeleteBounds = {};
if (OpState->PanelEdgeDirection == PanelSplit_Horizontal)
{
r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
if (Mouse.Pos.y > SplitY)
{
PanelToDeleteBounds = GetTopPanelBounds(OpState->Panel, PanelBounds);
}
else
{
PanelToDeleteBounds = GetBottomPanelBounds(OpState->Panel, PanelBounds);
}
}
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
{
r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
if (Mouse.Pos.x > SplitX)
{
PanelToDeleteBounds = GetRightPanelBounds(OpState->Panel, PanelBounds);
}
else
{
PanelToDeleteBounds = GetLeftPanelBounds(OpState->Panel, PanelBounds);
}
}
v4 OverlayColor = v4{0, 0, 0, .3f};
PushRenderQuad2D(RenderBuffer, PanelToDeleteBounds.Min, PanelToDeleteBounds.Max, OverlayColor);
}
}
FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
{
drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state);
rect2 PanelBounds = OpState->InitialPanelBounds;
if (OpState->PanelEditMode == PanelEdit_Modify)
{
if (OpState->Panel->SplitDirection == PanelSplit_Horizontal)
{
r32 NewSplitY = Mouse.Pos.y;
if (NewSplitY <= PanelBounds.Min.y)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem);
}
else if (NewSplitY >= PanelBounds.Max.y)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem);
}
else
{
OpState->Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
Panel_UpdateLayout(OpState->Panel, PanelBounds);
}
}
else if (OpState->Panel->SplitDirection == PanelSplit_Vertical)
{
r32 NewSplitX = Mouse.Pos.x;
if (NewSplitX <= PanelBounds.Min.x)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem);
}
else if (NewSplitX >= PanelBounds.Max.x)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem);
}
else
{
OpState->Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds);
Panel_UpdateLayout(OpState->Panel, PanelBounds);
}
}
}
else // PanelEdit_Destroy
{
if (OpState->PanelEdgeDirection == PanelSplit_Horizontal)
{
r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
if (Mouse.Pos.y > SplitY)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem);
}
else
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem);
}
}
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
{
r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
if (Mouse.Pos.x > SplitX)
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem);
}
else
{
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem);
}
}
}
DeactivateCurrentOperationMode(&State->Modes);
}
input_command DragPanelBorderCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragPanelBorderOperation },
{ KeyCode_MouseRightButton, KeyCode_Invalid, Command_Ended, EndDragPanelBorderOperation },
};
internal void
BeginDragPanelBorder(panel* Panel, panel_edit_mode PanelEditMode, rect2 PanelBounds, panel_split_direction PanelEdgeDirection, mouse_state Mouse, app_state* State)
{
operation_mode* DragPanelBorder = ActivateOperationModeWithCommands(&State->Modes, DragPanelBorderCommands, UpdateAndRenderDragPanelBorder);
drag_panel_border_operation_state* OpState = CreateOperationState(DragPanelBorder, &State->Modes, drag_panel_border_operation_state);
OpState->Panel = Panel;
OpState->InitialPanelBounds = PanelBounds;
OpState->PanelEdgeDirection = PanelEdgeDirection;
OpState->PanelEditMode = PanelEditMode;
}
// ----------------
//
// Drag To Split Panel Operation
OPERATION_STATE_DEF(split_panel_operation_state)
{
panel* Panel;
// NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying,
// it stores the value calculated when the operation mode is kicked off.
rect2 InitialPanelBounds;
};
OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel)
{
split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory;
rect2 PanelBounds = OpState->InitialPanelBounds;
v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f};
r32 MouseDeltaX = Abs(Mouse.Pos.x - Mouse.DownPos.x);
r32 MouseDeltaY = Abs(Mouse.Pos.y - Mouse.DownPos.y);
v2 EdgePreviewMin = {};
v2 EdgePreviewMax = {};
if (MouseDeltaY > MouseDeltaX) // Horizontal Split
{
EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y};
EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1};
}
else // Vertical Split
{
EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y};
EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y};
}
PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor);
}
FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation)
{
split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state);
rect2 PanelBounds = OpState->InitialPanelBounds;
r32 XDistance = Abs(Mouse.Pos.x - Mouse.DownPos.x);
r32 YDistance = Abs(Mouse.Pos.y - Mouse.DownPos.y);
if (XDistance > YDistance)
{
r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Rect2Width(PanelBounds);
SplitPanelVertically(Panel, XPercent, &State->PanelSystem, State, Context);
}
else
{
r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Rect2Height(PanelBounds);
SplitPanelHorizontally(Panel, YPercent, &State->PanelSystem, State, Context);
}
s32 PanelTypeIndex = Panel->TypeIndex;
gs_data PanelStateMemory = Panel->StateMemory;
Panel_SetCurrentType(Panel->Left, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context);
Panel_SetType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context);
DeactivateCurrentOperationMode(&State->Modes);
}
input_command SplitPanelCommands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndSplitPanelOperation },
};
internal void
BeginSplitPanelOperation(panel* Panel, mouse_state Mouse, app_state* State)
{
operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel);
split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state);
OpState->Panel = Panel;
OpState->InitialPanelBounds = Panel->Bounds;
}
// ----------------
#define PANEL_EDGE_CLICK_MAX_DISTANCE 6
internal b32
HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, mouse_state Mouse, app_state* State)
{
b32 HandledMouseInput = false;
// TODO(pjs): this can probably live in panel_with_layout
rect2 PanelSplitButtonBounds = rect2{ Panel->Bounds.Min, Panel->Bounds.Min + v2{25, 25} };
if (Panel->SplitDirection == PanelSplit_NoSplit
&& PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos))
{
BeginSplitPanelOperation(Panel, Mouse, State);
HandledMouseInput = true;
}
else if (Panel->SplitDirection != PanelSplit_NoSplit)
{
u32 ElementIndex = 0;
switch(Panel->SplitDirection)
{
case PanelSplit_Vertical: { ElementIndex = 0; } break;
case PanelSplit_Horizontal: { ElementIndex = 1; } break;
InvalidDefaultCase;
}
r32 SplitPosition = LerpR32(Panel->SplitPercent, Panel->Bounds.Min.E[ElementIndex], Panel->Bounds.Max.E[ElementIndex]);
r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.E[ElementIndex] - SplitPosition);
if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
BeginDragPanelBorder(Panel, PanelEditMode, Panel->Bounds, Panel->SplitDirection, Mouse, State);
}
else
{
if (PointIsInRect(Panel->Bottom->Bounds, Mouse.DownPos))
{
HandleMouseDownPanelInteractionOrRecurse(Panel->Bottom, PanelEditMode, Mouse, State);
}
else if (PointIsInRect(Panel->Top->Bounds, Mouse.DownPos))
{
HandleMouseDownPanelInteractionOrRecurse(Panel->Top, PanelEditMode, Mouse, State);
}
}
}
return HandledMouseInput;
}
internal b32
HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse_state Mouse, app_state* State)
{
b32 HandledMouseInput = false;
panel* FirstPanel = PanelSystem->Panels + 0;
panel_edit_mode EditMode = PanelEdit_Invalid;
if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
{
EditMode = PanelEdit_Modify;
}
else if (MouseButtonTransitionedDown(Mouse.RightButtonState))
{
EditMode = PanelEdit_Destroy;
}
if (EditMode != PanelEdit_Invalid)
{
HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, EditMode, Mouse, State);
}
return HandledMouseInput;
}
internal void
DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, mouse_state* Mouse, render_command_buffer* RenderBuffer)
{
r32 MouseLeftEdgeDistance = Abs(Mouse->Pos.x - PanelMin.x);
r32 MouseRightEdgeDistance = Abs(Mouse->Pos.x - PanelMax.x);
r32 MouseTopEdgeDistance = Abs(Mouse->Pos.y - PanelMax.y);
r32 MouseBottomEdgeDistance = Abs(Mouse->Pos.y - PanelMin.y);
v4 Color = BlackV4;
PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color);
v4 HighlightColor = v4{.3f, .3f, .3f, 1.f};
r32 HighlightThickness = 1;
if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 LeftEdgeMin = PanelMin;
v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y};
PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_HArrows;
}
else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y};
v2 RightEdgeMax = PanelMax;
PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_HArrows;
}
else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness};
v2 TopEdgeMax = PanelMax;
PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_VArrows;
}
else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 BottomEdgeMin = PanelMin;
v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness};
PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_VArrows;
}
}
internal void
DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterBounds, mouse_state Mouse, app_state* State, context Context)
{
PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f});
PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4);
rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23});
panel_definition CurrentDef = State->PanelSystem.PanelDefs[Panel->TypeIndex];
if (ui_BeginDropdown(&State->Interface, MakeString(CurrentDef.PanelName, CurrentDef.PanelNameLength), PanelSelectBtnBounds))
{
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{
panel_definition Def = State->PanelSystem.PanelDefs[i];
gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
if (ui_Button(&State->Interface, DefName))
{
Panel_SetType(Panel, &State->PanelSystem, i, State, Context);
}
}
}
ui_EndDropdown(&State->Interface);
}
internal void
RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
u32 PanelType = Panel->TypeIndex;
Assert(PanelType >= 0);
Assert(PanelType < State->PanelSystem.PanelDefsCount);
rect2 FooterBounds = rect2{
PanelBounds.Min,
v2{PanelBounds.Max.x, PanelBounds.Min.y + 25},
};
rect2 PanelViewBounds = rect2{
v2{PanelBounds.Min.x, FooterBounds.Max.y},
PanelBounds.Max,
};
panel_definition Definition = State->PanelSystem.PanelDefs[PanelType];
Definition.Render(Panel, PanelViewBounds, RenderBuffer, State, Context);
PushRenderOrthographic(RenderBuffer, WindowBounds);
DrawPanelFooter(Panel, RenderBuffer, FooterBounds, Mouse, State, Context);
}
internal void
DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context)
{
rect2 Bounds = Panel->Bounds;
switch (Panel->SplitDirection)
{
case PanelSplit_Horizontal:
case PanelSplit_Vertical:
{
DrawPanelRecursive(Panel->Left, RenderBuffer, Mouse, State, Context);
DrawPanelRecursive(Panel->Right, RenderBuffer, Mouse, State, Context);
}break;
case PanelSplit_NoSplit:
{
panel* OverridePanel = Panel_GetModalOverride(Panel);
RenderPanel(OverridePanel, Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*OverridePanel, Bounds.Min, Bounds.Max, Mouse, RenderBuffer);
}break;
InvalidDefaultCase;
}
}
internal void
DrawAllPanels(panel_system System, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context)
{
panel* PanelAt = System.Panels + 0;
DrawPanelRecursive(PanelAt, RenderBuffer, Mouse, State, Context);
}
#define FOLDHAUS_INTERFACE_CPP
#endif // FOLDHAUS_INTERFACE_CPP

View File

@ -0,0 +1,142 @@
//
// File: foldhaus_operation_mode.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_OPERATION_MODE_H
typedef struct operation_mode operation_mode;
#define OPERATION_STATE_DEF(name) struct name
#define OPERATION_RENDER_PROC(name) void name(app_state* State, render_command_buffer* RenderBuffer, operation_mode Operation, mouse_state Mouse, context Context)
typedef OPERATION_RENDER_PROC(operation_render_proc);
struct operation_mode
{
input_command_registry Commands;
operation_render_proc* Render;
gs_memory_cursor Memory;
u8* OpStateMemory;
};
#define OPERATION_MODES_MAX 32
struct operation_mode_system
{
s32 ActiveModesCount;
operation_mode ActiveModes[OPERATION_MODES_MAX];
//arena_snapshot ModeMemorySnapshots[OPERATION_MODES_MAX];
gs_data_array ModeMemoryPagesFreeList;
// NOTE(Peter): This acts as mode scoped memory. When a mode gets activated, it can allocate
// temporary memory which then gets freed when the mode is deactivated
gs_memory_arena Arena;
};
internal operation_mode_system
OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContext)
{
operation_mode_system Result = {0};
// TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint?
Result.Arena.Allocator = ThreadContext.Allocator;
Result.ModeMemoryPagesFreeList.CountMax = 8;
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
{
Result.ModeMemoryPagesFreeList.Data[Page] = PushSize(Storage, KB(4));
}
Result.ModeMemoryPagesFreeList.Count = Result.ModeMemoryPagesFreeList.CountMax;
return Result;
}
internal gs_data
OperationModeTakeMemoryPage(operation_mode_system* System)
{
Assert(System->ModeMemoryPagesFreeList.Count > 0);
gs_data Result = {0};
System->ModeMemoryPagesFreeList.Count -= 1;
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
Result = System->ModeMemoryPagesFreeList.Data[LastIndex];
return Result;
}
internal void
OperationModeFreeMemoryPage(operation_mode_system* System, gs_data Data)
{
Assert(System->ModeMemoryPagesFreeList.Count < System->ModeMemoryPagesFreeList.CountMax);
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
System->ModeMemoryPagesFreeList.Count += 1;
System->ModeMemoryPagesFreeList.Data[LastIndex] = Data;
}
internal operation_mode*
ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc)
{
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
operation_mode* Result = 0;
s32 ModeIndex = System->ActiveModesCount++;
//System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
Result = &System->ActiveModes[ModeIndex];
Result->Memory = MemoryCursorCreateFromData(OperationModeTakeMemoryPage(System));
Result->Render = RenderProc;
return Result;
}
#define ActivateOperationModeWithCommands(sys, cmds, render) \
ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0])), render);
internal operation_mode*
ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount, operation_render_proc* RenderProc)
{
operation_mode* NewMode = ActivateOperationMode(System, RenderProc);
#if 0
InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena);
for (s32 i = 0; i < CommandsCount; i++)
{
input_command Command = Commands[i];
RegisterKeyPressCommand(&NewMode->Commands, Command.Key, Command.Flags, Command.Mdfr, Command.Proc);
}
#else
NewMode->Commands.Commands = Commands;
NewMode->Commands.Size = CommandsCount;
NewMode->Commands.Used = CommandsCount;
#endif
return NewMode;
}
internal void
DeactivateCurrentOperationMode (operation_mode_system* System)
{
Assert(System->ActiveModesCount > 0);
s32 ModeIndex = --System->ActiveModesCount;
OperationModeFreeMemoryPage(System, System->ActiveModes[ModeIndex].Memory.Data);
//ClearArenaToSnapshot(&System->Arena, System->ModeMemorySnapshots[ModeIndex]);
}
#define CreateOperationState(mode, modeSystem, stateType) \
(stateType*)CreateOperationState_(mode, modeSystem, sizeof(stateType))
#define GetCurrentOperationState(modeSystem, stateType) \
(stateType*)(modeSystem).ActiveModes[(modeSystem).ActiveModesCount - 1].OpStateMemory;
internal u8*
CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32 StateSize)
{
// NOTE(Peter): This isn't a problem if this fires, it just means our page size is too small,
// and its time to make the pages dynamically sized
Assert(Mode->Memory.Data.Size >= StateSize);
u8* Result = MemoryCursorPushSize(&Mode->Memory, StateSize).Memory;
Mode->OpStateMemory = Result;
return Result;
}
#define FOLDHAUS_OPERATION_MODE_H
#endif // FOLDHAUS_OPERATION_MODE_H

View File

@ -0,0 +1,442 @@
//
// File: foldhaus_panel.h
// Author: Peter Slattery
// Creation Date: 2019-12-26
//
// Usage:
// Include this file in ONE file in your project.
// Define SetPanelDefinitionExternal
//
#ifndef FOLDHAUS_PANEL_H
enum panel_split_direction
{
PanelSplit_NoSplit,
PanelSplit_Horizontal,
PanelSplit_Vertical,
PanelSplit_Count,
};
typedef struct panel panel;
#define PANEL_MODAL_OVERRIDE_CALLBACK(name) void name(panel* ReturningFrom, app_state* State, context Context)
typedef PANEL_MODAL_OVERRIDE_CALLBACK(panel_modal_override_callback);
struct panel
{
s32 TypeIndex;
gs_data StateMemory;
panel* ModalOverride;
panel* IsModalOverrideFor;
panel_modal_override_callback* ModalOverrideCB;
rect2 Bounds;
panel_split_direction SplitDirection;
r32 SplitPercent;
panel* Parent;
union{
panel* Left;
panel* Top;
};
union{
panel* Right;
panel* Bottom;
};
};
struct free_panel
{
free_panel* Next;
};
#define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context)
typedef PANEL_INIT_PROC(panel_init_proc);
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel, app_state* State)
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
#define PANEL_RENDER_PROC(name) void name(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
typedef PANEL_RENDER_PROC(panel_render_proc);
// NOTE(Peter): This is used by the meta system to generate panel type info
struct panel_definition
{
char* PanelName;
s32 PanelNameLength;
panel_init_proc* Init;
panel_cleanup_proc* Cleanup;
panel_render_proc* Render;
input_command* InputCommands;
s32 InputCommandsCount;
};
#define PANELS_MAX 16
struct panel_system
{
panel_definition* PanelDefs;
u32 PanelDefsCount;
panel* Panels;
u32 PanelsUsed;
free_panel* FreeList;
};
/////////////////////////////////
//
// Book-Keeping
//
/////////////////////////////////
internal void
PanelSystem_Init(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount, gs_memory_arena* Storage)
{
PanelSystem->FreeList = 0;
PanelSystem->PanelDefs = PanelDefs;
PanelSystem->PanelDefsCount = PanelDefsCount;
PanelSystem->Panels = PushArray(Storage, panel, PANELS_MAX);
}
internal panel*
PanelSystem_TakePanel(panel_system* PanelSystem)
{
panel* FreeEntry = 0;
if (PanelSystem->FreeList != 0)
{
free_panel* FreePanel = PanelSystem->FreeList;
PanelSystem->FreeList = FreePanel->Next;
FreeEntry = (panel*)FreePanel;
}
else
{
Assert(PanelSystem->PanelsUsed < PANELS_MAX);
FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++;
}
return FreeEntry;
}
internal void
PanelSystem_FreePanel(panel* Panel, panel_system* PanelSystem)
{
Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX);
free_panel* FreeEntry = (free_panel*)Panel;
FreeEntry->Next = PanelSystem->FreeList;
PanelSystem->FreeList = FreeEntry;
}
internal void
PanelSystem_FreePanelRecursive(panel* Panel, panel_system* PanelSystem)
{
if (Panel->SplitDirection != PanelSplit_NoSplit)
{
PanelSystem_FreePanelRecursive(Panel->Left, PanelSystem);
PanelSystem_FreePanelRecursive(Panel->Right, PanelSystem);
}
PanelSystem_FreePanel(Panel, PanelSystem);
}
internal panel*
Panel_GetModalOverride(panel* Panel)
{
panel* Result = Panel;
if (Panel->ModalOverride != 0)
{
Result = Panel_GetModalOverride(Panel->ModalOverride);
}
return Result;
}
internal void
Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callback* Callback)
{
Root->ModalOverride = Override;
Root->ModalOverrideCB = Callback;
Override->IsModalOverrideFor = Root;
Override->Bounds = Root->Bounds;
}
internal void
Panel_PopModalOverride(panel* Parent, panel_system* System)
{
// TODO(pjs): Free the overrided panel
PanelSystem_FreePanel(Parent->ModalOverride, System);
Parent->ModalOverride = 0;
}
internal void
Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_data TypeStateMemory, app_state* State, context Context)
{
s32 OldTypeIndex = Panel->TypeIndex;
Panel->TypeIndex = NewPanelType;
Panel->StateMemory = TypeStateMemory;
if(OldTypeIndex >= 0)
{
System->PanelDefs[OldTypeIndex].Cleanup(Panel, State);
}
}
internal void
Panel_SetType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context)
{
gs_data EmptyStateData = {0};
Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context);
System->PanelDefs[NewPanelTypeIndex].Init(Panel, State, Context);
}
#define Panel_GetStateStruct(p, type) (type*)Panel_GetStateMemory((p), sizeof(type)).Memory
internal gs_data
Panel_GetStateMemory(panel* Panel, u64 Size)
{
Assert(Panel->StateMemory.Size == Size);
gs_data Result = Panel->StateMemory;
return Result;
}
internal panel*
PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context)
{
panel* Panel = PanelSystem_TakePanel(PanelSystem);
Panel_SetType(Panel, PanelSystem, PanelTypeIndex, State, Context);
return Panel;
}
internal void
SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, panel_system* PanelSystem, app_state* State, context Context)
{
if (Percent >= 0.0f && Percent <= 1.0f)
{
Parent->SplitDirection = SplitDirection;
Parent->SplitPercent = Percent;
s32 ParentTypeIndex = Parent->TypeIndex;
gs_data ParentStateMemory = Parent->StateMemory;
Parent->Left = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Left->Parent = Parent;
Parent->Right = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Right->Parent = Parent;
}
}
internal void
SplitPanelVertically(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context)
{
SplitPanel(Parent, Percent, PanelSplit_Vertical, PanelSystem, State, Context);
}
internal void
SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context)
{
SplitPanel(Parent, Percent, PanelSplit_Horizontal, PanelSystem, State, Context);
}
internal void
ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelSystem)
{
panel* LeftChild = Parent->Left;
panel* RightChild = Parent->Right;
panel* PanelToDestroy = PanelToKeep == LeftChild ? RightChild : LeftChild;
*Parent = *PanelToKeep;
PanelSystem_FreePanel(PanelToKeep, PanelSystem);
PanelSystem_FreePanelRecursive(PanelToDestroy, PanelSystem);
}
/////////////////////////////////
//
// Rendering And Interaction
//
/////////////////////////////////
internal rect2
GetTopPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = v2{
Panel->Bounds.Min.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
};
Result.Max = Panel->Bounds.Max;
return Result;
}
internal rect2
GetBottomPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = Panel->Bounds.Min;
Result.Max = v2{
Panel->Bounds.Max.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
};
return Result;
}
internal rect2
GetRightPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Min.y
};
Result.Max = Panel->Bounds.Max;
return Result;
}
internal rect2
GetLeftPanelBounds(panel* Panel)
{
rect2 Result = {};
Result.Min = Panel->Bounds.Min;
Result.Max = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Max.y
};
return Result;
}
internal rect2
GetTopPanelBounds(panel* Panel, rect2 PanelBounds)
{
rect2 Result = {};
Result.Min = v2{
PanelBounds.Min.x,
LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y)
};
Result.Max = PanelBounds.Max;
return Result;
}
internal rect2
GetBottomPanelBounds(panel* Panel, rect2 PanelBounds)
{
rect2 Result = {};
Result.Min = PanelBounds.Min;
Result.Max = v2{
PanelBounds.Max.x,
LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y)
};
return Result;
}
internal rect2
GetRightPanelBounds(panel* Panel, rect2 PanelBounds)
{
rect2 Result = {};
Result.Min = v2{
LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x),
PanelBounds.Min.y
};
Result.Max = PanelBounds.Max;
return Result;
}
internal rect2
GetLeftPanelBounds(panel* Panel, rect2 PanelBounds)
{
rect2 Result = {};
Result.Min = PanelBounds.Min;
Result.Max = v2{
LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x),
PanelBounds.Max.y
};
return Result;
}
internal void
Panel_UpdateLayout(panel* Panel, rect2 Bounds)
{
Panel->Bounds = Bounds;
if (Panel->SplitDirection != PanelSplit_NoSplit)
{
rect2 LeftOrTopBounds = {};
rect2 RightOrBottomBounds = {};
switch (Panel->SplitDirection)
{
case PanelSplit_Horizontal:
{
LeftOrTopBounds = GetTopPanelBounds(Panel);
RightOrBottomBounds = GetBottomPanelBounds(Panel);
} break;
case PanelSplit_Vertical:
{
LeftOrTopBounds = GetLeftPanelBounds(Panel);
RightOrBottomBounds = GetRightPanelBounds(Panel);
} break;
InvalidDefaultCase;
}
Panel_UpdateLayout(Panel->Left, LeftOrTopBounds);
Panel_UpdateLayout(Panel->Right, RightOrBottomBounds);
}
}
internal void
PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds)
{
panel* Root = System->Panels;
Panel_UpdateLayout(Root, WindowBounds);
}
internal panel*
GetPanelContainingPoint(panel* Panel, v2 Point)
{
panel* Result = 0;
if (PointIsInRect(Panel->Bounds, Point))
{
switch (Panel->SplitDirection)
{
case PanelSplit_NoSplit:
{
Result = Panel;
}break;
case PanelSplit_Vertical:
case PanelSplit_Horizontal:
{asdfasdfasdfasdfasdf
if (PointIsInRect(Panel->Left->Bounds, Point))
{
Result = GetPanelContainingPoint(Panel->Left, Point);
}
else if (PointIsInRect(Panel->Right->Bounds, Point))
{
Result = GetPanelContainingPoint(Panel->Right, Point);
}
}break;
InvalidDefaultCase;
}
}
return Result;
}
internal panel*
PanelSystem_GetPanelContainingPoint(panel_system* System, v2 Point)
{
panel* Result = 0;
panel* Root = System->Panels;
Result = GetPanelContainingPoint(Root, Point);
return Result;
}
#define FOLDHAUS_PANEL_H
#endif // FOLDHAUS_PANEL_H

1677
src/app/editor/interface.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
//
// File: foldhaus_panel_assembly_debug.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H
GSMetaTag(panel_init);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Cleanup(panel* Panel, app_state* State)
{
}
// TODO(pjs): This is really blumen specific
#define FSC(f,c) FlowerStripToChannel((f), (c))
internal u8
FlowerStripToChannel(u8 Flower, u8 Channel)
{
Assert(Flower < 3);
Assert(Channel < 8);
u8 Result = 0;
Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07);
return Result;
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Assembly Debug Layout"));
ui_BeginRow(Interface, 2);
{
if (ui_Button(Interface, MakeString("Assembly")))
{
State->ShowingUserSpaceDebug = false;
}
if (ui_Button(Interface, MakeString("User Space")))
{
State->ShowingUserSpaceDebug = true;
}
}
ui_EndRow(Interface);
if (State->ShowingUserSpaceDebug && State->UserSpaceDesc.CustomDebugUI)
{
US_CustomDebugUI(&State->UserSpaceDesc, Panel, PanelBounds, RenderBuffer,
State, Context);
}
else
{
InterfaceAssert(Interface->PerFrameMemory);
State->AssemblyDebugState.AllAssemblies = ui_ToggleText(Interface, MakeString("All Assemblies"), State->AssemblyDebugState.AllAssemblies);
gs_string OverrideStr = MakeString(OverrideTypeStrings[State->AssemblyDebugState.Override]);
if (ui_BeginLabeledDropdown(Interface, MakeString("Override"), OverrideStr))
{
for (u32 i = 0; i < ADS_Override_Count; i++)
{
if (ui_Button(Interface, MakeString(OverrideTypeStrings[i])))
{
State->AssemblyDebugState.Override = (override_type)i;
}
}
}
ui_EndLabeledDropdown(Interface);
InterfaceAssert(Interface->PerFrameMemory);
switch (State->AssemblyDebugState.Override)
{
case ADS_Override_TagWhite:
case ADS_Override_TagStripWhite:
{
ui_LabeledTextEntry(Interface, MakeString("Tag Name"), &State->AssemblyDebugState.TagName);
ui_LabeledTextEntry(Interface, MakeString("Tag Value"), &State->AssemblyDebugState.TagValue);
if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite)
{
State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly);
State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip);
}
}break;
case ADS_Override_ChannelWhite:
{
u64 Board = 0;
u64 Strip = 0;
Board = ui_LabeledTextEntryU64(Interface, MakeString("Board"), Board);
Strip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), Strip);
State->AssemblyDebugState.TargetChannel = FSC(Board, Strip);
}break;
case ADS_Override_AllOff:
case ADS_Override_AllRed:
case ADS_Override_AllGreen:
case ADS_Override_AllBlue:
case ADS_Override_AllWhite:
{
State->AssemblyDebugState.Brightness = (u8)ui_LabeledRangeSlider(Interface, MakeString("Brightness"), (r32)State->AssemblyDebugState.Brightness, 0, 255);
State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly);
}break;
case ADS_Override_AllHue:
{
State->AssemblyDebugState.TargetHue = (u32)ui_LabeledRangeSlider(Interface, MakeString("Hue"), (r32)State->AssemblyDebugState.TargetHue, 0, 360);
}break;
default:
{
InterfaceAssert(Interface->PerFrameMemory);
State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly);
InterfaceAssert(Interface->PerFrameMemory);
State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip);
InterfaceAssert(Interface->PerFrameMemory);
}break;
}
}
State->SendEmptyPackets = ui_LabeledToggle(Interface, MakeString("Send Empty Packets"), State->SendEmptyPackets);
ui_PopLayout(Interface, MakeString("Assembly Debug Layout"));
}
#define FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H
#endif // FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H

View File

@ -0,0 +1,148 @@
//
// File: foldhaus_panel_dmx_view.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_DMX_VIEW_H
struct universe_view_operation_state
{
b32 MouseDown;
v2 DisplayOffset;
r32 Zoom;
};
input_command DMXView_Commands[] = {{}};
s32 DMXView_CommandsCount = 0;
GSMetaTag(panel_init);
GSMetaTag(panel_type_dmx_view);
internal void
DMXView_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_dmx_view);
internal void
DMXView_Cleanup(panel* Panel, app_state* State)
{
}
#if 0
// NOTE(Peter): Here to illustrate what old SACN Universe drawing looked like
// This won't actually function
// :NoLongerFunctionalSACNCodeButThatsOk
internal void
DrawSACNUniversePixels (render_command_buffer* RenderBuffer, sacn_universe* ToDraw,
v2 TopLeft, v2 Dimension)
{
Assert(ToDraw);
s32 PixelsPerRow = 21;
r32 PixelDim = Dimension.x / PixelsPerRow;
v2 PixelSize = v2{PixelDim, PixelDim};
v2 PixelRegister = TopLeft;
v4 DisplayColor = {0, 0, 0, 1};
s32 PixelsToDraw = ToDraw->SizeInSendBuffer - STREAM_HEADER_SIZE;
render_quad_batch_constructor BatchConstructor = PushRenderQuad2DBatch(RenderBuffer, PixelsToDraw);
u8* ColorCursor = (u8*)ToDraw->StartPositionInSendBuffer + STREAM_HEADER_SIZE;
s32 PixelsDrawn = 0;
for (s32 i = 0; i < PixelsToDraw; i++)
{
PixelRegister.x = TopLeft.x + (PixelsDrawn % PixelsPerRow) * PixelDim;
PixelRegister.y = TopLeft.y - (PixelsDrawn / PixelsPerRow) * PixelDim;
r32 Value = *ColorCursor++ / 255.f;
DisplayColor.r = Value;
DisplayColor.g = Value;
DisplayColor.b = Value;
PushQuad2DOnBatch(&BatchConstructor, PixelRegister, PixelRegister + PixelSize, DisplayColor);
++PixelsDrawn;
}
}
#endif
GSMetaTag(panel_render);
GSMetaTag(panel_type_dmx_view);
internal void
DMXView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
#if 0
// :NoLongerFunctionalSACNCodeButThatsOk
DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay);
universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory;
gs_string TitleBargs_string = InitializeEmptygs_string(PushArray(State->Transient, char, 64), 64);
v2 DisplayArea_Dimension = v2{600, 600};
v2 DisplayContents_Offset = OpState->DisplayOffset;
//
// TODO(Peter): I don't like this. Dragging the Universe view should be an operation mode, just
// like rotating the 3D view, but modes don't have access to the state of modes above them in the stack
// (and attempting to cast those states to the appropriate type seems risky)
//
// :NeedToPassStateDownModeChain
//
if (OpState->MouseDown)
{
DisplayContents_Offset += (Mouse.Pos - Mouse.DownPos);
}
v2 DisplayArea_TopLeft = v2{300, (r32)RenderBuffer->ViewHeight - 50} + DisplayContents_Offset;
v2 UniverseDisplayDimension = v2{100, 100} * OpState->Zoom;
v2 Padding = v2{25, 50} * OpState->Zoom;
v2 UniverseDisplayTopLeft = DisplayArea_TopLeft;
sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer;
while(UniverseList)
{
for (s32 UniverseIdx = 0;
UniverseIdx < UniverseList->Used;
UniverseIdx++)
{
sacn_universe* Universe = UniverseList->Universes + UniverseIdx;
DrawSACNUniversePixels(RenderBuffer, Universe, UniverseDisplayTopLeft, UniverseDisplayDimension);
if (OpState->Zoom > .5f)
{
v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12};
PrintF(&TitleBargs_string, "Universe %d", Universe->Universe);
DrawString(RenderBuffer, TitleBargs_string, State->Interface.Font,
TitleDisplayStart, WhiteV4);
}
UniverseDisplayTopLeft.x += UniverseDisplayDimension.x + Padding.x;
if (UniverseDisplayTopLeft.x > DisplayArea_TopLeft.x + DisplayArea_Dimension.x)
{
UniverseDisplayTopLeft.x = DisplayArea_TopLeft.x;
UniverseDisplayTopLeft.y -= UniverseDisplayDimension.y + Padding.y;
}
if (UniverseDisplayTopLeft.y < DisplayArea_TopLeft.y - DisplayArea_Dimension.y)
{
break;
}
}
UniverseList = UniverseList->Next;
}
#endif
}
#define FOLDHAUS_PANEL_DMX_VIEW_H
#endif // FOLDHAUS_PANEL_DMX_VIEW_H

View File

@ -0,0 +1,200 @@
//
// File: foldhaus_panel_file_view.h
// Author: Peter Slattery
// Creation Date: 2020-03-08
//
#ifndef FOLDHAUS_PANEL_FILE_VIEW_H
enum file_view_mode
{
FileViewMode_Load,
FileViewMode_Save,
};
struct file_view_state
{
file_view_mode Mode;
gs_string WorkingDirectory;
gs_string DisplayDirectory;
gs_memory_arena FileNamesArena;
gs_file_info_array FileNames;
gs_file_info SelectedFile;
};
internal void
FileView_SetMode(panel* Panel, file_view_mode Mode)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
FileViewState->Mode = Mode;
}
internal void
FileView_Exit_(panel* FileViewPanel, app_state* State, context Context)
{
// TODO(pjs): Free State->FileNamesArena
Assert(FileViewPanel->IsModalOverrideFor != 0);
panel* ReturnTo = FileViewPanel->IsModalOverrideFor;
if (ReturnTo->ModalOverrideCB)
{
ReturnTo->ModalOverrideCB(FileViewPanel, State, Context);
}
Panel_PopModalOverride(ReturnTo, &State->PanelSystem);
}
global input_command* FileView_Commands = 0;
s32 FileView_CommandsCount = 0;
internal void
FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context)
{
// NOTE(pjs): make sure we're only passing valid directory paths to the
// function
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
Assert(LastChar == '\\' || LastChar == '/');
MemoryArenaClear(&State->FileNamesArena);
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
{
AppendPrintF(&SanitizedDir, "\\");
}
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
if (NewWorkingDir.IsDirectory)
{
AppendPrintF(&SanitizedDir, "*");
NullTerminate(&SanitizedDir);
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, SanitizedDir.ConstString, EnumerateDirectory_IncludeDirectories);
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
// in some cases. Shouldn't be a problem but it is unnecessary
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir);
}
}
GSMetaTag(panel_init);
GSMetaTag(panel_type_file_view);
internal void
FileView_Init(panel* Panel, app_state* State, context Context)
{
// TODO: :FreePanelMemory
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
Panel->StateMemory = StructToData(FileViewState, file_view_state);
FileViewState->FileNamesArena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "File View - File Names Arena");
// TODO(pjs): this shouldn't be stored in permanent
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);
FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024);
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_file_view);
internal void
FileView_Cleanup(panel* Panel, app_state* State)
{
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_file_view);
internal void
FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
{
ui_BeginRow(&State->Interface, 3);
{
if (FileViewState->Mode == FileViewMode_Save)
{
if (ui_Button(&State->Interface, MakeString("Save")))
{
if (!FileViewState->SelectedFile.Path.Str)
{
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
}
FileView_Exit_(Panel, State, Context);
}
}
if (ui_Button(&State->Interface, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
}
ui_EndRow(&State->Interface);
// Header
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->DisplayDirectory))
{
// if last character is a slash, update pwd, and clear the filter string
// otherwise update the filter string
gs_string Pwd = FileViewState->DisplayDirectory;
char LastChar = Pwd.Str[Pwd.Length - 1];
if (LastChar == '\\' || LastChar == '/')
{
FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context);
}
else
{
}
}
// File Display
ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count);
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
{
gs_file_info File = FileViewState->FileNames.Values[i];
u32 LastSlashIndex = FindLast(File.Path, File.Path.Length - 2, '\\');
gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length);
gs_string PathString = PushString(State->Transient, FileName.Length);
PrintF(&PathString, "%S", FileName);
if (ui_LayoutListButton(&State->Interface, PathString, i))
{
if (File.IsDirectory)
{
FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context);
}
else
{
FileViewState->SelectedFile = File;
switch (FileViewState->Mode)
{
case FileViewMode_Load:
{
FileView_Exit_(Panel, State, Context);
} break;
case FileViewMode_Save:
{
} break;
}
}
}
}
ui_EndList(&State->Interface);
}
ui_PopLayout(&State->Interface, MakeString("FileView Layout"));
}
#define FOLDHAUS_PANEL_FILE_VIEW_H
#endif // FOLDHAUS_PANEL_FILE_VIEW_H

View File

@ -0,0 +1,83 @@
//
// File: foldhaus_panel_hierarchy.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_HIERARCHY_H
input_command HierarchyView_Commands[] = {{}};
s32 HierarchyView_CommandsCount = 0;
GSMetaTag(panel_init);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Cleanup(panel* Panel, app_state* State)
{
}
PANEL_MODAL_OVERRIDE_CALLBACK(LoadAssemblyCallback)
{
Assert(ReturningFrom->TypeIndex == PanelType_FileView);
file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state);
gs_file_info FileInfo = FileViewState->SelectedFile;
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, FileInfo.Path, GlobalLogBuffer);
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
gs_string TempString = PushString(State->Transient, 256);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout"));
ui_BeginList(&State->Interface, MakeString("Hierarchy List"), 10, State->Assemblies.Count + 1);
{
ui_column_spec Cols[2] = {
ui_column_spec{ UIColumnSize_Fill, 0 },
ui_column_spec{ UIColumnSize_MaxWidth, 128 }
};
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
ui_BeginRow(&State->Interface, 2, &Cols[0]);
assembly Assembly = State->Assemblies.Values[i];
PrintF(&TempString, "%S", Assembly.Name);
ui_Label(&State->Interface, TempString);
if (ui_Button(&State->Interface, MakeString("X")))
{
UnloadAssembly(i, State, Context);
}
ui_EndRow(&State->Interface);
}
ui_BeginRow(&State->Interface, 2, &Cols[0]);
ui_Label(&State->Interface, MakeString(" "));
if (ui_Button(&State->Interface, MakeString("+ Add Assembly")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
FileView_SetMode(FileBrowser, FileViewMode_Load);
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
}
ui_EndRow(&State->Interface);
}
ui_EndList(&State->Interface);
ui_PopLayout(&State->Interface, MakeString("Hierarchy Layout"));
}
#define FOLDHAUS_PANEL_HIERARCHY_H
#endif // FOLDHAUS_PANEL_HIERARCHY_H

View File

@ -0,0 +1,46 @@
/* date = April 12th 2021 4:47 pm */
#ifndef FOLDHAUS_PANEL_MESSAGE_LOG_H
#define FOLDHAUS_PANEL_MESSAGE_LOG_H
GSMetaTag(panel_init);
GSMetaTag(panel_type_file_view);
internal void
MessageLog_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_file_view);
internal void
MessageLog_Cleanup(panel* Panel, app_state* State)
{
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_file_view);
internal void
MessageLog_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
ui_widget* Layout = ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Message Log Layout"));
ui_BeginList(Interface, MakeString("Message Log List"), 10, GlobalLogBuffer->EntriesCount);
log_buffer_iter Iter = Log_GetIter(GlobalLogBuffer);
while (true)
{
log_entry* At = Iter.At;
ui_Label(Interface, At->String);
if (!LogIter_CanAdvance(Iter))
{
break;
}
LogIter_Advance(&Iter);
}
ui_EndList(Interface);
ui_PopLayout(Interface, MakeString("Message Log Layout"));
}
#endif //FOLDHAUS_PANEL_MESSAGE_LOG_H

View File

@ -0,0 +1,360 @@
//
// File: foldhaus_panel_profiler.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_PROFILER_H
input_command ProfilerView_Commands[] = {{}};
s32 ProfilerView_CommandsCount = 0;
GSMetaTag(panel_init);
GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Cleanup(panel* Panel, app_state* State)
{
}
internal void
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient)
{
rect2 Bounds = ui_LayoutRemaining(*Layout);
r32 Width = Rect2Width(Bounds);
r32 DepthHeight = 32;
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
r32 FrameTotalCycles = (r32)(VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles);
r32 NextThreadTop = Bounds.Max.y;
for (s32 t = 0; t < VisibleFrame->ThreadCount; t++)
{
debug_scope_record_list ThreadCalls = VisibleFrame->ThreadCalls[t];
gs_string String = PushString(Transient, 256);
r32 ThreadScopeMin = Bounds.Max.y;
//PrintF(&String, "Thread %d", ThreadCalls.ThreadId);
//ui_Label(Interface, String, rect2{ThreadScopeMin);
r32 Hue = (r32)(t) / (r32)(VisibleFrame->ThreadCount);
Hue += (.5f * (t % 2));
v4 ThreadHSV = v4{ 360.0f * Hue, .5f, 1.0f, 1.0f };
v4 ThreadRGB = HSVToRGB(ThreadHSV);
for (s32 i = 0; i < ThreadCalls.Count; i++)
{
scope_record* Record = ThreadCalls.Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
s64 OffsetStart = Record->StartCycles - FrameStartCycles;
s64 OffsetEnd = Record->EndCycles - FrameStartCycles;
r32 PercentStart = (r32)(OffsetStart) / FrameTotalCycles;
r32 PercentEnd = (r32)(OffsetEnd) / FrameTotalCycles;
r32 PercentWidth = PercentEnd - PercentStart;
rect2 ScopeBounds = {
v2{0, 0},
v2{PercentWidth * Width, DepthHeight - 4},
};
v2 Offset = {
Bounds.Min.x + (PercentStart * Width),
NextThreadTop - ((Record->CallDepth + 1) * DepthHeight)
};
ScopeBounds = Rect2Translate(ScopeBounds, Offset);
ThreadScopeMin = Min(ScopeBounds.Min.y, ThreadScopeMin);
if (Rect2Width(ScopeBounds) >= 1)
{
v4 Color = ThreadRGB;
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
{
Color = GreenV4;
ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover"));
{
s64 Cycles = (Record->EndCycles - Record->StartCycles);
r32 PercentFrame = (r32)(Cycles) / FrameTotalCycles;
PrintF(&String, "%S : %.2f%% frame | %dcy",
Name->Name,
PercentFrame,
Cycles);
ui_Label(Interface, String);
}
ui_EndMousePopup(Interface);
}
ui_FillRect(Interface, ScopeBounds, Color);
ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4);
}
}
NextThreadTop = ThreadScopeMin;
}
}
internal void
RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
{
char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fixed, 256 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 }};
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
{
ui_Label(Interface, MakeString("Procedure"));
ui_Label(Interface, MakeString("% Frame"));
ui_Label(Interface, MakeString("Seconds"));
ui_Label(Interface, MakeString("Cycles"));
ui_Label(Interface, MakeString("Calls"));
}
ui_EndRow(Interface);
s32 CountedScopes = 0;
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
CountedScopes += 1;
}
}
ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes);
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
PrintF(&String, "%S", NameEntry.Name);
ui_Label(Interface, String);
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
ui_Label(Interface, String);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
ui_Label(Interface, String);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
ui_Label(Interface, String);
PrintF(&String, "%d", CollatedRecord->CallCount);
ui_Label(Interface, String);
}
}
ui_EndRow(Interface);
ui_EndList(Interface);
}
struct mem_amt
{
u64 OrigSize;
r64 Size;
char* Units;
};
internal mem_amt
GetMemAmt (u64 BytesCount)
{
mem_amt Result = {};
Result.OrigSize = BytesCount;
Result.Size = (r64)BytesCount;
Result.Units = "bytes";
u32 i = 0;
char* UnitList[] = { "kb", "mb", "gb", "tb" };
while (Result.Size > 1024) {
Result.Size /= 1024.0;
Result.Units = UnitList[i++];
}
return Result;
}
internal void
RenderProfiler_MemoryView(ui_interface* Interface, ui_widget* Layout, app_state* State, context Context, gs_memory_arena* Memory)
{
gs_debug_allocations_list* DA = Context.ThreadContext.Allocator.DEBUGAllocList;
gs_string TempString = PushString(State->Transient, 256);
mem_amt MemFootprint = GetMemAmt(DA->AllocationsSizeTotal);
u64 AllocCount = DA->AllocationsCount;
PrintF(&TempString, "Total Memory Size: %.2f %s | Allocations: %lld", MemFootprint.Size, MemFootprint.Units, AllocCount);
ui_Label(Interface, TempString);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fill, 0 },
{ UIColumnSize_Fixed,256 },
};
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
{
ui_Label(Interface, MakeString("Location"));
ui_Label(Interface, MakeString("Alloc Size"));
}
ui_EndRow(Interface);
ui_BeginList(Interface, MakeString("Alloc List"), 10, DA->AllocationsCount);
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
for (gs_debug_memory_allocation* A = DA->Root;
A && A->Next != 0;
A = A->Next)
{
gs_const_string Str = ConstString(A->Loc.File);
u64 LastSlash = FindLastFromSet(Str, "\\/");
gs_const_string JustFileName = Substring(Str, LastSlash + 1, Str.Length);
PrintF(&TempString, "%s:%s(%d)", JustFileName.Str, A->Loc.Function, A->Loc.Line);
ui_Label(Interface, TempString);
mem_amt Amt = GetMemAmt(A->Size);
PrintF(&TempString, "%.2f %s", Amt.Size, Amt.Units);
ui_Label(Interface, TempString);
}
ui_EndRow(Interface);
ui_EndList(Interface);
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
gs_memory_arena* Memory = State->Transient;
gs_string String = PushString(Memory, 256);
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
r32 FrameListHeight = 64;
rect2 FrameListBounds, ProcListBounds;
RectHSplitAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds);
rect2 FrameListInner = RectInset(FrameListBounds, 4);
s32 FramesToDisplay = DEBUG_FRAME_COUNT;
if (FramesToDisplay != 0)
{
r32 SingleFrameStep = Rect2Width(FrameListInner) / FramesToDisplay;
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
ui_OutlineRect(&State->Interface, FrameListBounds, 2, WhiteV4);
if (MouseButtonHeldDown(Context.Mouse.LeftButtonState))
{
if (PointIsInRect(FrameListBounds, Context.Mouse.Pos))
{
v2 LocalMouse = Rect2GetRectLocalPoint(FrameListBounds, Context.Mouse.Pos);
s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < FramesToDisplay)
{
GlobalDebugServices->RecordFrames = false;
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
}
}
}
rect2 FrameBounds = MakeRect2MinDim(FrameListInner.Min, v2{SingleFrameWidth, Rect2Height(FrameListInner)});
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
{
rect2 PositionedFrameBounds = Rect2TranslateX(FrameBounds, F * SingleFrameStep);
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
v4 Color = FrameColors[Clamp(0, FramesAgo, 3)];
ui_FillRect(&State->Interface, PositionedFrameBounds, Color);
}
}
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
if (VisibleFrame)
{
ui_BeginRow(&State->Interface, 4);
{
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_Label(&State->Interface, String);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_Label(&State->Interface, String);
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
// be removed, or used for something else
ui_ReserveBounds(&State->Interface, Layout, true);
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
{
GlobalDebugServices->RecordFrames = true;
}
}
ui_EndRow(&State->Interface);
}
ui_BeginRow(&State->Interface, 8);
{
if (ui_Button(&State->Interface, MakeString("Profiler")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_Profiler;
}
if (ui_Button(&State->Interface, MakeString("List View")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_ScopeList;
}
if (ui_Button(&State->Interface, MakeString("Memory")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_MemoryView;
}
}
ui_EndRow(&State->Interface);
switch (GlobalDebugServices->Interface.FrameView)
{
case DebugUI_Profiler:
{
if (VisibleFrame)
{
RenderProfiler_ScopeVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
case DebugUI_ScopeList:
{
if (VisibleFrame)
{
RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
case DebugUI_MemoryView:
{
RenderProfiler_MemoryView(&State->Interface, Layout, State, Context, Memory);
}break;
InvalidDefaultCase;
}
ui_PopLayout(&State->Interface, MakeString("Profiler Layout"));
}
#define FOLDHAUS_PANEL_PROFILER_H
#endif // FOLDHAUS_PANEL_PROFILER_H

View File

@ -0,0 +1,244 @@
//
// File: foldhaus_panel_sculpture_view.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H
// Definitions
#define PIXEL_TO_WORLD_SCALE 0.01f
//
struct sculpture_view_panel_state
{
camera Camera;
};
// 3D Mouse View
OPERATION_STATE_DEF(mouse_rotate_view_operation_state)
{
v4 CameraStartPos;
camera* Camera;
};
OPERATION_RENDER_PROC(Update3DViewMouseRotate)
{
mouse_rotate_view_operation_state* OpState = (mouse_rotate_view_operation_state*)Operation.OpStateMemory;
v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos;
m44 XRotation = M44RotationX(-TotalDeltaPos.y * PIXEL_TO_WORLD_SCALE);
m44 YRotation = M44RotationY(TotalDeltaPos.x * PIXEL_TO_WORLD_SCALE);
m44 Combined = XRotation * YRotation;
OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz;
}
FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command MouseRotateViewCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate},
};
FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
{
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate);
mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode,
&State->Modes,
mouse_rotate_view_operation_state);
OpState->CameraStartPos = ToV4Point(PanelState->Camera.Position);
OpState->Camera = &PanelState->Camera;
}
// ----------------
GSMetaTag(panel_commands);
GSMetaTag(panel_type_sculpture_view);
global input_command SculptureView_Commands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate },
};
global s32 SculptureView_CommandsCount = 1;
GSMetaTag(panel_init);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Init(panel* Panel, app_state* State, context Context)
{
sculpture_view_panel_state* PanelState = PushStruct(&State->Permanent, sculpture_view_panel_state);
PanelState->Camera.FieldOfView = 45.0f;
PanelState->Camera.AspectRatio = RectAspectRatio(State->WindowBounds);
PanelState->Camera.Near = .1f;
PanelState->Camera.Far = 800.0f;
PanelState->Camera.Position = v3{0, 0, 400};
PanelState->Camera.LookAt = v3{0, 0, 0};
Panel->StateMemory = StructToData(PanelState, sculpture_view_panel_state);
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Cleanup(panel* Panel, app_state* State)
{
}
struct draw_leds_job_data
{
v4 CameraPosition;
led_buffer LedBuffer;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
quad_batch_constructor_reserved_range BatchReservedRange;
r32 LEDHalfWidth;
};
internal void
DrawLedsInBuffer(led_buffer LedBuffer, s32 StartIndex, s32 OnePastLastIndex, render_quad_batch_constructor* Batch, quad_batch_constructor_reserved_range ReservedRange, r32 LedHalfWidth)
{
s32 TrisUsed = 0;
v4 P0_In = v4{-LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P1_In = v4{LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P2_In = v4{LedHalfWidth, LedHalfWidth, 0, 1};
v4 P3_In = v4{-LedHalfWidth, LedHalfWidth, 0, 1};
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
Assert(OnePastLastIndex <= (s32)LedBuffer.LedCount);
for (s32 LedIndex = StartIndex; LedIndex < OnePastLastIndex; LedIndex++)
{
pixel PixelColor = LedBuffer.Colors[LedIndex];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 Position = LedBuffer.Positions[LedIndex];
v4 PositionOffset = ToV4Vec(Position.xyz);
v4 P0 = P0_In + PositionOffset;
v4 P1 = P1_In + PositionOffset;
v4 P2 = P2_In + PositionOffset;
v4 P3 = P3_In + PositionOffset;
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
}
}
internal void
DrawLEDsInBufferRangeJob (gs_thread_context Context, gs_data JobData)
{
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData.Memory;
DrawLedsInBuffer(Data->LedBuffer, Data->StartIndex, Data->OnePastLastIndex, Data->Batch, Data->BatchReservedRange, Data->LEDHalfWidth);
}
internal void
DrawQuad(render_command_buffer* RenderBuffer, v4 C, r32 Rad, v4 Color)
{
v4 P0 = C + v4{-Rad,-Rad,0,0};
v4 P1 = C + v4{ Rad,-Rad,0,0};
v4 P2 = C + v4{ Rad,Rad,0,0};
v4 P3 = C + v4{ -Rad,Rad,0,0};
PushRenderQuad3D(RenderBuffer, P0, P1, P2, P3, Color);
}
internal v2
SculptureView_WorldToScreenPosition(v4 WorldPosition, camera Camera, rect2 PanelBounds)
{
v2 Result = {0};
r32 PanelW = Rect2Width(PanelBounds);
r32 PanelH = Rect2Height(PanelBounds);
m44 Matrix = GetCameraPerspectiveProjectionMatrix(Camera) * GetCameraModelViewMatrix(Camera);
v4 WorldPos = Matrix * WorldPosition;
// this is the Perspective Divide
v2 ProjectedPos = WorldPos.xy / WorldPos.w;
// Projection gets us in a range [-1, 1], and we want [0, width]
ProjectedPos.x = ((ProjectedPos.x / 2) * PanelW) + (PanelW / 2);
ProjectedPos.y = ((ProjectedPos.y / 2) * PanelH) + (PanelH / 2);
Result = ProjectedPos + PanelBounds.Min;
return Result;
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
DEBUG_TRACK_SCOPE(RenderSculpture);
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
PanelState->Camera.AspectRatio = RectAspectRatio(PanelBounds);
PushRenderPerspective(RenderBuffer, PanelBounds, PanelState->Camera);
u32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal);
u32 FocusPixel = 100;
for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++)
{
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, BufferIndex);
u32 JobsNeeded = U32DivideRoundUp(LedBuffer->LedCount, MaxLEDsPerJob);
u32 NextLEDIndex = 0;
for (u32 Job = 0; Job < JobsNeeded; Job++)
{
gs_data Data = PushSize(State->Transient, sizeof(draw_leds_job_data));
draw_leds_job_data* JobData = (draw_leds_job_data*)Data.Memory;
JobData->LedBuffer = *LedBuffer;
JobData->StartIndex = NextLEDIndex;
JobData->OnePastLastIndex = Min(JobData->StartIndex + MaxLEDsPerJob, LedBuffer->LedCount);
s32 JobLedCount = JobData->OnePastLastIndex - JobData->StartIndex;
JobData->Batch = &RenderLEDsBatch;
JobData->BatchReservedRange = ReserveRangeInQuadConstructor(JobData->Batch, JobLedCount * 2);
JobData->LEDHalfWidth = .5f;
JobData->CameraPosition = ToV4Point(PanelState->Camera.Position);
#if 1
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, (thread_proc*)DrawLEDsInBufferRangeJob, Data, ConstString("Sculpture Draw LEDS"));
#else
DrawLedsInBuffer(JobData->LedBuffer, JobData->StartIndex, JobData->OnePastLastIndex, JobData->Batch, JobData->BatchReservedRange, JobData->LEDHalfWidth);
#endif
NextLEDIndex = JobData->OnePastLastIndex;
}
}
// TODO(Peter): I don't like the fact that setting an orthographic view inside a panel render function
// needs to relyon the window bounds rather than the panel bounds. Ideally the panel only needs to know where
// itself is, and nothing else.
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
if (State->Assemblies.Count > 0)
{
assembly Assembly = State->Assemblies.Values[0];
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly.LedBufferIndex);
v4 LedPosition = LedBuffer->Positions[FocusPixel];
v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, PanelState->Camera, PanelBounds);
gs_string Tempgs_string = PushString(State->Transient, 256);
PrintF(&Tempgs_string, "Hot Id: %u, ZIndex: %u | Active Id: %u", State->Interface.HotWidget.Id,
State->Interface.HotWidget.ZIndex,State->Interface.ActiveWidget.Id);
DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4, -1, GreenV4);
}
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H
#endif // FOLDHAUS_PANEL_SCULPTURE_VIEW_H

View File

@ -0,0 +1,19 @@
//
// File: foldhaus_panel_types.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-17
//
#ifndef FOLDHAUS_PANEL_TYPES_CPP
global s32 GlobalPanelDefsCount = 8;
global panel_definition GlobalPanelDefs[] = {
{ "File View", 9, FileView_Init, FileView_Cleanup, FileView_Render, FileView_Commands, FileView_CommandsCount },
{ "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands, SculptureView_CommandsCount },
{ "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render, AnimationTimeline_Commands, AnimationTimeline_CommandsCount },
{ "Dmx View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, DMXView_Commands, DMXView_CommandsCount },
{ "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, HierarchyView_Commands, HierarchyView_CommandsCount },
{ "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, ProfilerView_Commands, ProfilerView_CommandsCount },
{ "Assembly Debug", 14, AssemblyDebug_Init, AssemblyDebug_Cleanup, AssemblyDebug_Render, 0, 0 },
{ "Message Log", 11, MessageLog_Init, MessageLog_Cleanup, MessageLog_Render, 0, 0 },
};
#define FOLDHAUS_PANEL_TYPES_CPP
#endif // FOLDHAUS_PANEL_TYPES_CPP

View File

@ -0,0 +1,18 @@
//
// File: foldhaus_panel_types.h
// Author: Peter Slattery
// Creation Date: 2020-10-17
//
#ifndef FOLDHAUS_PANEL_TYPES_H
enum panel_type {
PanelType_FileView,
PanelType_SculptureView,
PanelType_AnimationTimeline,
PanelType_DMXView,
PanelType_HierarchyView,
PanelType_ProfilerView,
PanelType_AssemblyDebug,
PanelType_MessageLog
};
#define FOLDHAUS_PANEL_TYPES_H
#endif // FOLDHAUS_PANEL_TYPES_H

View File

@ -0,0 +1,843 @@
//
// File: foldhaus_animation.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ANIMATION
#define ANIMATION_PROC(name) void name(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
typedef ANIMATION_PROC(animation_proc);
struct frame_range
{
s32 Min;
s32 Max;
};
struct animation_pattern_handle
{
s32 IndexPlusOne;
};
// NOTE(pjs): An animation block is a time range paired with an
// animation_pattern (see below). While a timeline's current time
// is within the range of a block, that particular block's animation
// will run
struct animation_block
{
frame_range Range;
animation_pattern_handle AnimationProcHandle;
u32 Layer;
};
struct animation_block_array
{
u32* Generations;
animation_block* Values;
u32 Count;
u32 CountMax;
};
enum blend_mode
{
BlendMode_Overwrite,
BlendMode_Add,
BlendMode_Multiply,
BlendMode_Count,
};
// TODO(pjs): This really doesn't belong here
global gs_string BlendModeStrings[] = {
MakeString("Overwrite"),
MakeString("Add"),
MakeString("Multiply"),
MakeString("Count"),
};
struct anim_layer
{
gs_string Name;
blend_mode BlendMode;
};
struct anim_layer_array
{
anim_layer* Values;
u32 Count;
u32 CountMax;
};
// NOTE(pjs): An animation is a stack of layers, each of which
// is a timeline of animation blocks.
struct animation
{
gs_string Name;
anim_layer_array Layers;
animation_block_array Blocks_;
frame_range PlayableRange;
// The information / path to the file where this animation is to be saved / where it is loaded from
gs_file_info FileInfo;
};
struct animation_handle
{
s32 Index;
};
struct animation_handle_array
{
u32 Count;
animation_handle* Handles;
};
internal animation_handle InvalidAnimHandle () { return { -1 }; }
internal bool IsValid (animation_handle H) { return H.Index >= 0; }
internal void Clear (animation_handle* H) { H->Index = -1; }
internal bool AnimHandlesAreEqual (animation_handle A, animation_handle B)
{
return A.Index == B.Index;
}
struct animation_array
{
animation* Values;
u32 Count;
u32 CountMax;
};
struct animation_layer_frame
{
animation_block Hot;
bool HasHot;
animation_block NextHot;
bool HasNextHot;
r32 NextHotOpacity;
blend_mode BlendMode;
};
// NOTE(pjs): This is an evaluated frame - across all layers in an
// animation, these are the blocks that need to be run
struct animation_frame
{
animation_layer_frame* Layers;
u32 LayersCount;
};
enum animation_repeat_mode
{
AnimationRepeat_Single,
AnimationRepeat_Loop,
AnimationRepeat_Invalid,
};
global gs_const_string AnimationRepeatModeStrings[] = {
ConstString("Repeat Single"),
ConstString("Loop"),
ConstString("Invalid"),
};
struct animation_fade_group
{
animation_handle From;
animation_handle To;
r32 FadeElapsed;
r32 FadeDuration;
};
#define ANIMATION_SYSTEM_LAYERS_MAX 128
#define ANIMATION_SYSTEM_BLOCKS_MAX 128
struct animation_system
{
gs_memory_arena* Storage;
animation_array Animations;
animation_repeat_mode RepeatMode;
animation_handle_array Playlist;
u32 PlaylistAt;
r32 PlaylistFadeTime;
// NOTE(Peter): The frame currently being displayed/processed. you
// can see which frame you're on by looking at the time slider on the timeline
// panel
animation_fade_group ActiveFadeGroup;
r32 SecondsOnCurrentFrame;
s32 CurrentFrame;
s32 LastUpdatedFrame;
r32 SecondsPerFrame;
b32 TimelineShouldAdvance;
u32 UpdatesThisFrame;
// Settings
bool Multithreaded;
};
// NOTE(pjs): A Pattern is a named procedure which can be used as
// an element of an animation. Patterns are sequenced on a timeline
// and blended via layers to create an animation
struct animation_pattern
{
char* Name;
s32 NameLength;
animation_proc* Proc;
bool Multithreaded;
};
struct animation_pattern_array
{
animation_pattern* Values;
u32 Count;
u32 CountMax;
};
// Serialization
enum animation_field
{
AnimField_FileIdent,
AnimField_AnimName,
AnimField_LayersCount,
AnimField_BlocksCount,
AnimField_PlayableRange,
AnimField_PlayableRangeMin,
AnimField_PlayableRangeMax,
AnimField_LayersArray,
AnimField_Layer,
AnimField_LayerName,
AnimField_LayerBlendMode,
AnimField_BlocksArray,
AnimField_Block,
AnimField_BlockFrameRange,
AnimField_BlockFrameRangeMin,
AnimField_BlockFrameRangeMax,
AnimField_BlockLayerIndex,
AnimField_BlockAnimName,
AnimField_Count,
};
global gs_const_string AnimationFieldStrings[] = {
ConstString("lumenarium_animation_file"), // AnimField_FileIdent
ConstString("animation_name"),// AnimField_AnimName
ConstString("layers_count"),// AnimField_LayersCount
ConstString("blocks_count"),// AnimField_BlocksCount
ConstString("playable_range"),// AnimField_PlayableRange
ConstString("min"),// AnimField_PlayableRangeMin
ConstString("max"),// AnimField_PlayableRangeMax
ConstString("layers"),// AnimField_LayersArray
ConstString("layer"),// AnimField_Layer
ConstString("name"),// AnimField_LayerName
ConstString("blend"),// AnimField_LayerBlendMode
ConstString("blocks"),// AnimField_BlocksArray
ConstString("block"),// AnimField_Block
ConstString("frame_range"),// AnimField_BlockFrameRange
ConstString("min"),// AnimField_BlockFrameRangeMin
ConstString("max"),// AnimField_BlockFrameRangeMax
ConstString("layer_index"),// AnimField_BlockLayerIndex
ConstString("animation_name"),// AnimField_BlockAnimName
};
//////////////////////////
//
// Patterns List
internal animation_pattern_array
Patterns_Create(gs_memory_arena* Arena, s32 CountMax)
{
animation_pattern_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Arena, animation_pattern, Result.CountMax);
return Result;
}
#define PATTERN_MULTITHREADED true
#define PATTERN_SINGLETHREADED false
#define Patterns_PushPattern(array, proc, multithread) \
Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)) - 1, (multithread))
internal void
Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength, bool Multithreaded)
{
Assert(Array->Count < Array->CountMax);
animation_pattern Pattern = {0};
Pattern.Name = Name;
Pattern.NameLength = NameLength;
Pattern.Proc = Proc;
Pattern.Multithreaded = Multithreaded;
Array->Values[Array->Count++] = Pattern;
}
internal animation_pattern_handle
Patterns_IndexToHandle(s32 Index)
{
animation_pattern_handle Result = {};
Result.IndexPlusOne = Index + 1;
return Result;
}
internal bool
IsValid(animation_pattern_handle Handle)
{
bool Result = Handle.IndexPlusOne > 0;
return Result;
}
internal animation_pattern
Patterns_GetPattern(animation_pattern_array Patterns, animation_pattern_handle Handle)
{
animation_pattern Result = {0};
if (Handle.IndexPlusOne > 0)
{
u32 Index = Handle.IndexPlusOne - 1;
Assert(Index < Patterns.Count);
Result = Patterns.Values[Index];
}
return Result;
}
//////////////////////////
//
// Anim Block Array
internal animation_block_array
AnimBlockArray_Create(gs_memory_arena* Storage, u32 CountMax)
{
animation_block_array Result = {0};
Result.CountMax = Max(CountMax, 32);
Result.Values = PushArray(Storage, animation_block, Result.CountMax);
Result.Generations = PushArray(Storage, u32, Result.CountMax);
return Result;
}
internal handle
AnimBlockArray_Push(animation_block_array* Array, animation_block Value)
{
Assert(Array->Count < Array->CountMax);
handle Result = {0};
Result.Index = Array->Count++;
// NOTE(pjs): pre-increment so that generation 0 is always invalid
Result.Generation = ++Array->Generations[Result.Index];
Array->Values[Result.Index] = Value;
return Result;
}
internal void
AnimBlockArray_Remove(animation_block_array* Array, handle Handle)
{
Assert(Handle.Index < Array->Count);
Assert(Handle_IsValid(Handle));
Array->Generations[Handle.Index]++;
}
internal void
AnimBlockArray_RemoveAt(animation_block_array* Array, u32 Index)
{
Assert(Index < Array->Count);
handle Handle = {};
Handle.Index = Index;
Handle.Generation = Array->Generations[Index];
AnimBlockArray_Remove(Array, Handle);
}
//////////////////////////
//
// Anim Layers Array
internal anim_layer_array
AnimLayerArray_Create(gs_memory_arena* Storage, u32 CountMax)
{
anim_layer_array Result = {0};
Result.CountMax = Max(CountMax, 32);
Result.Values = PushArray(Storage, anim_layer, Result.CountMax);
return Result;
}
internal u32
AnimLayerArray_Push(anim_layer_array* Array, anim_layer Value)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Value;
return Index;
}
internal void
AnimLayerArray_Remove(anim_layer_array* Array, u32 Index)
{
Assert(Index < Array->Count);
for (u32 i = Index; i < Array->Count - 1; i++)
{
Array->Values[i] = Array->Values[i + 1];
}
}
//////////////////////////
//
// Animation Array
internal animation_array
AnimationArray_Create(gs_memory_arena* Storage, u32 CountMax)
{
animation_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, animation, Result.CountMax);
return Result;
}
internal animation_handle
AnimationArray_Push(animation_array* Array, animation Value)
{
Assert(Array->Count < Array->CountMax);
animation_handle Result = {0};
Result.Index = Array->Count++;
Array->Values[Result.Index] = Value;
return Result;
}
internal animation*
AnimationArray_Get(animation_array Array, animation_handle Handle)
{
DEBUG_TRACK_FUNCTION;
animation* Result = 0;
if (IsValid(Handle) && Handle.Index < (s32)Array.Count)
{
Result = Array.Values + Handle.Index;
}
return Result;
}
internal animation*
AnimationArray_GetSafe(animation_array Array, animation_handle Handle)
{
Assert(IsValid(Handle));
Assert(Handle.Index < (s32)Array.Count);
return AnimationArray_Get(Array, Handle);
}
//////////////////////////
//
// Animation
typedef struct animation_desc
{
u32 NameSize;
char* Name;
u32 LayersCount;
u32 BlocksCount;
u32 MinFrames;
u32 MaxFrames;
} animation_desc;
internal animation
Animation_Create(animation_desc Desc, animation_system* System)
{
animation Result = {};
u32 NameLen = Desc.NameSize;
if (Desc.Name)
{
NameLen = Max(CStringLength(Desc.Name), NameLen);
Result.Name = PushStringF(System->Storage, NameLen, "%s", Desc.Name);
} else {
Result.Name = PushStringF(System->Storage, NameLen, "[New Animation]");
}
Result.Layers = AnimLayerArray_Create(System->Storage, Desc.LayersCount);
Result.Blocks_ = AnimBlockArray_Create(System->Storage, Desc.BlocksCount);
Result.PlayableRange.Min = Desc.MinFrames;
Result.PlayableRange.Max = Desc.MaxFrames;
return Result;
}
internal handle
Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, animation_pattern_handle AnimationProcHandle, u32 LayerIndex)
{
Assert(LayerIndex < Animation->Layers.Count);
animation_block NewBlock = {0};
NewBlock.Range.Min = StartFrame;
NewBlock.Range.Max = EndFrame;
NewBlock.AnimationProcHandle = AnimationProcHandle;
NewBlock.Layer = LayerIndex;
handle Handle = AnimBlockArray_Push(&Animation->Blocks_, NewBlock);
return Handle;
}
internal void
Animation_RemoveBlock(animation* Animation, handle AnimHandle)
{
AnimBlockArray_Remove(&Animation->Blocks_, AnimHandle);
}
internal animation_block*
Animation_GetBlockFromHandle(animation* Animation, handle AnimHandle)
{
animation_block* Result = 0;
if (AnimHandle.Generation != 0 &&
Animation->Blocks_.Generations[AnimHandle.Index] == AnimHandle.Generation)
{
Result = Animation->Blocks_.Values + AnimHandle.Index;
}
return Result;
}
internal u32
Animation_AddLayer(animation* Animation, anim_layer Layer)
{
return AnimLayerArray_Push(&Animation->Layers, Layer);
}
internal u32
Animation_AddLayer (animation* Animation, gs_string Name, blend_mode BlendMode, animation_system* System)
{
anim_layer NewLayer = {0};
NewLayer.Name = PushStringF(System->Storage, 256, "%S", Name);
NewLayer.BlendMode = BlendMode;
return Animation_AddLayer(Animation, NewLayer);
}
internal void
Animation_RemoveLayer (animation* Animation, u32 LayerIndex)
{
AnimLayerArray_Remove(&Animation->Layers, LayerIndex);
for (u32 i = Animation->Blocks_.Count - 1; i >= 0; i--)
{
animation_block* Block = Animation->Blocks_.Values + i;
if (Block->Layer > LayerIndex)
{
Block->Layer -= 1;
}
else if (Block->Layer == LayerIndex)
{
AnimBlockArray_RemoveAt(&Animation->Blocks_, i);
}
}
}
//////////////////////////
//
//
internal u32
SecondsToFrames(r32 Seconds, animation_system System)
{
u32 Result = Seconds * (1.0f / System.SecondsPerFrame);
return Result;
}
inline frame_range
FrameRange_Overlap(frame_range A, frame_range B)
{
frame_range Result = {};
}
inline bool
FrameIsInRange(frame_range Range, s32 Frame)
{
bool Result = (Frame >= Range.Min) && (Frame <= Range.Max);
return Result;
}
internal u32
GetFrameCount(frame_range Range)
{
u32 Result = (u32)Max(0, Range.Max - Range.Min);
return Result;
}
internal r32
FrameToPercentRange(s32 Frame, frame_range Range)
{
r32 Result = (r32)(Frame - Range.Min);
Result = Result / GetFrameCount(Range);
return Result;
}
internal s32
PercentToFrameInRange(r32 Percent, frame_range Range)
{
s32 Result = Range.Min + (s32)(Percent * GetFrameCount(Range));
return Result;
}
internal s32
ClampFrameToRange(s32 Frame, frame_range Range)
{
s32 Result = Frame;
if (Result < Range.Min)
{
Result = Range.Min;
}
else if (Result > Range.Max)
{
Result = Range.Max;
}
return Result;
}
// Blocks
// Layers
// Fade Group
internal bool
AnimationFadeGroup_ShouldRender (animation_fade_group FadeGroup)
{
return IsValid(FadeGroup.From);
}
internal void
AnimationFadeGroup_Advance(animation_fade_group* Group)
{
Group->From = Group->To;
Clear(&Group->To);
Group->FadeElapsed = 0;
Group->FadeDuration = 0;
}
internal void
AnimationFadeGroup_Update(animation_fade_group* Group, r32 DeltaTime)
{
if (IsValid(Group->To))
{
r32 FadeBefore = Group->FadeElapsed;
Group->FadeElapsed += DeltaTime;
if (Group->FadeElapsed >= Group->FadeDuration)
{
AnimationFadeGroup_Advance(Group);
}
}
}
internal void
AnimationFadeGroup_FadeTo(animation_fade_group* Group, animation_handle To, r32 Duration)
{
if (IsValid(Group->From))
{
// complete current fade if there is one in progress
if (IsValid(Group->To))
{
AnimationFadeGroup_Advance(Group);
}
Group->To = To;
Group->FadeDuration = Duration;
}
else
{
Group->From = To;
}
}
// System
struct animation_system_desc
{
gs_memory_arena* Storage;
u32 AnimArrayCount;
r32 SecondsPerFrame;
};
internal animation_system
AnimationSystem_Init(animation_system_desc Desc)
{
animation_system Result = {};
Result.Storage = Desc.Storage;
Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount);
Result.SecondsPerFrame = Desc.SecondsPerFrame;
Clear(&Result.ActiveFadeGroup.From);
Clear(&Result.ActiveFadeGroup.To);
Result.ActiveFadeGroup.FadeElapsed = 0;
// Settings
Result.Multithreaded = false;
return Result;
}
internal animation*
AnimationSystem_GetActiveAnimation(animation_system* System)
{
return AnimationArray_Get(System->Animations, System->ActiveFadeGroup.From);
}
internal animation_frame
AnimationSystem_CalculateAnimationFrame(animation_system* System,
animation* Animation,
gs_memory_arena* Arena)
{
DEBUG_TRACK_FUNCTION;
animation_frame Result = {0};
Result.LayersCount = Animation->Layers.Count;
Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount);
ZeroArray(Result.Layers, animation_layer_frame, Result.LayersCount);
for (u32 l = 0; l < Animation->Layers.Count; l++)
{
animation_layer_frame* Layer = Result.Layers + l;
Layer->BlendMode = Animation->Layers.Values[l].BlendMode;
}
for (u32 i = 0; i < Animation->Blocks_.Count; i++)
{
animation_block Block = Animation->Blocks_.Values[i];
if (FrameIsInRange(Block.Range, System->CurrentFrame))
{
animation_layer_frame* Layer = Result.Layers + Block.Layer;
if (Layer->HasHot)
{
// NOTE(pjs): With current implementation, we don't allow
// animations to hvae more than 2 concurrent blocks in the
// timeline
Assert(!Layer->HasNextHot);
// NOTE(pjs): Make sure that Hot comes before NextHot
if (Layer->Hot.Range.Min < Block.Range.Min)
{
Layer->NextHot = Block;
}
else
{
Layer->NextHot = Layer->Hot;
Layer->Hot = Block;
}
Layer->HasNextHot = true;
frame_range BlendRange = {};
BlendRange.Min = Layer->NextHot.Range.Min;
BlendRange.Max = Layer->Hot.Range.Max;
Layer->NextHotOpacity = FrameToPercentRange(System->CurrentFrame, BlendRange);
}
else
{
Layer->Hot = Block;
Layer->NextHotOpacity = 0.0f;
Layer->HasHot = true;
}
}
}
return Result;
}
internal void
AnimationSystem_Update(animation_system* System, r32 DeltaTime)
{
if (!System->TimelineShouldAdvance) { return; }
if (!AnimationFadeGroup_ShouldRender(System->ActiveFadeGroup)) { return; }
System->UpdatesThisFrame = 0;
AnimationFadeGroup_Update(&System->ActiveFadeGroup, DeltaTime);
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
if (ActiveAnim)
{
System->SecondsOnCurrentFrame += DeltaTime;
while (System->SecondsOnCurrentFrame > System->SecondsPerFrame)
{
System->CurrentFrame += 1;
System->SecondsOnCurrentFrame -= System->SecondsPerFrame;
System->UpdatesThisFrame += 1;
}
// Loop back to the beginning
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
{
// NOTE(PS): There's no long term reason why this needs to be true
// but I don't want to implement dealing with PlayableRanges that
// don't start at zero right now becuse there's literally no reason
// I can think of where that's useful.
Assert(ActiveAnim->PlayableRange.Min == 0);
s32 FramesPastEnd = System->CurrentFrame;
while (FramesPastEnd > ActiveAnim->PlayableRange.Max)
{
FramesPastEnd -= ActiveAnim->PlayableRange.Max;
}
switch (System->RepeatMode)
{
case AnimationRepeat_Single:
{
System->CurrentFrame = 0;
}break;
case AnimationRepeat_Loop:
{
Assert(System->Playlist.Count > 0);
u32 NextIndex = System->PlaylistAt;
System->PlaylistAt = (System->PlaylistAt + 1) % System->Playlist.Count;
animation_handle Next = System->Playlist.Handles[NextIndex];
AnimationFadeGroup_FadeTo(&System->ActiveFadeGroup,
Next,
System->PlaylistFadeTime);
System->CurrentFrame = 0;
}break;
InvalidDefaultCase;
}
}
}
}
internal void
AnimationSystem_FadeToPlaylist(animation_system* System, animation_handle_array Playlist)
{
System->Playlist = Playlist;
System->PlaylistAt = 0;
if (System->Playlist.Count > 0)
{
AnimationFadeGroup_FadeTo(&System->ActiveFadeGroup, Playlist.Handles[0], System->PlaylistFadeTime);
}
}
inline bool
AnimationSystem_NeedsRender(animation_system System)
{
bool Result = (System.CurrentFrame != System.LastUpdatedFrame);
return Result;
}
inline r32
AnimationSystem_GetCurrentTime(animation_system System)
{
r32 Result = System.CurrentFrame * System.SecondsPerFrame;
return Result;
}
#define FOLDHAUS_ANIMATION
#endif // FOLDHAUS_ANIMATION

View File

@ -0,0 +1,375 @@
//
// File: foldhaus_animation_renderer.cpp
// Author: Peter Slattery
// Creation Date: 2020-11-14
//
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
internal pixel
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData)
{
r32 MagB = (r32)(PixelB.R + PixelB.G + PixelB.B) / (255 * 3);
pixel Result = {};
Result.R = (u8)LerpR32(MagB, PixelA.R, PixelB.R);
Result.G = (u8)LerpR32(MagB, PixelA.G, PixelB.G);
Result.B = (u8)LerpR32(MagB, PixelA.B, PixelB.B);
#if 0
pixel Result = PixelB;
if (PixelB.R == 0 &&
PixelB.G == 0 &&
PixelB.B == 0)
{
Result = PixelA;
}
#endif
return Result;
}
internal pixel
LedBlend_Lerp(pixel PixelA, pixel PixelB, u8* UserData)
{
r32 BOpacity = *(r32*)UserData;
pixel Result = {};
r32 AOpacity = 1.0f - BOpacity;
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
return Result;
}
internal pixel
LedBlend_Add(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
u32 R = (u32)PixelA.R + (u32)PixelB.R;
u32 G = (u32)PixelA.G + (u32)PixelB.G;
u32 B = (u32)PixelA.B + (u32)PixelB.B;
Result.R = (u8)Min(R, (u32)255);
Result.G = (u8)Min(G, (u32)255);
Result.B = (u8)Min(B, (u32)255);
return Result;
}
internal pixel
LedBlend_Multiply(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
r32 DR = (r32)PixelA.R / 255.f;
r32 DG = (r32)PixelA.G / 255.f;
r32 DB = (r32)PixelA.B / 255.f;
r32 SR = (r32)PixelB.R / 255.f;
r32 SG = (r32)PixelB.G / 255.f;
r32 SB = (r32)PixelB.B / 255.f;
Result.R = (u8)((DR * SR) * 255.f);
Result.G = (u8)((DG * SG) * 255.f);
Result.B = (u8)((DB * SB) * 255.f);
return Result;
}
internal pixel
LedBlend_Overlay(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
return Result;
}
internal led_blend_proc*
LedBlend_GetProc(blend_mode BlendMode)
{
led_blend_proc* Result = 0;
switch (BlendMode)
{
case BlendMode_Overwrite: { Result = LedBlend_Overwrite; }break;
case BlendMode_Add: { Result = LedBlend_Add; }break;
case BlendMode_Multiply: { Result = LedBlend_Multiply; }break;
InvalidDefaultCase;
}
return Result;
}
struct pattern_args
{
assembly Assembly;
gs_memory_arena* Transient;
u8* UserData;
};
struct render_anim_to_led_buffer_job_data
{
animation_pattern Pattern;
led_buffer Buffer;
led_buffer_range BufferRange;
pattern_args PatternArgs;
r32 SecondsIntoBlock;
};
internal void
AnimationSystem_RenderAnimationToLedBufferJob(gs_thread_context Context, gs_data Data)
{
render_anim_to_led_buffer_job_data JobData = *(render_anim_to_led_buffer_job_data*)Data.Memory;
JobData.Pattern.Proc(&JobData.Buffer,
JobData.BufferRange,
JobData.PatternArgs.Assembly,
JobData.SecondsIntoBlock,
JobData.PatternArgs.Transient,
JobData.PatternArgs.UserData);
}
#define MULTITHREAD_PATTERN_RENDERING 1
internal void
AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs,
context Context)
{
DEBUG_TRACK_FUNCTION;
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
Assert(Pattern.Proc);
if (System->Multithreaded && Pattern.Multithreaded)
{
u32 JobsCount = 4;
u32 LedsPerJob = Buffer->LedCount / JobsCount;
for (u32 i = 0; i < JobsCount; i++)
{
gs_data Data = PushSize(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data));
render_anim_to_led_buffer_job_data* JobData = (render_anim_to_led_buffer_job_data*)Data.Memory;
JobData->Pattern = Pattern;
JobData->Buffer = *Buffer;
JobData->BufferRange.First = LedsPerJob * i;
JobData->BufferRange.OnePastLast = LedsPerJob * (i + 1);
JobData->PatternArgs = PatternArgs;
JobData->SecondsIntoBlock = SecondsIntoBlock;
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue,
(thread_proc*)AnimationSystem_RenderAnimationToLedBufferJob,
Data,
ConstString("Render Pattern To Buffer"));
}
}
else
{
led_buffer_range Range = {};
Range.First = 0;
Range.OnePastLast = Buffer->LedCount;
Pattern.Proc(Buffer, Range, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData);
}
}
internal void
AnimationSystem_EndRenderBlockToLedBuffer (animation_system* System, context Context)
{
if (System->Multithreaded)
{
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
}
// NOTE(pjs): This mirrors animation_layer_frame to account
// for overlapping
struct layer_led_buffer
{
led_buffer HotBuffer;
led_buffer NextHotBuffer;
};
internal led_buffer
RenderAnimationToLedBuffer (animation_system* System,
pattern_args PatternArgs,
animation_frame CurrFrame,
layer_led_buffer* LayerBuffers,
led_buffer* AssemblyLedBuffer,
animation_pattern_array Patterns,
gs_memory_arena* Transient,
context Context)
{
DEBUG_TRACK_FUNCTION;
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
// Create the LayerLEDBuffers
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
layer_led_buffer TempBuffer = {};
if (CurrFrame.Layers[Layer].HasHot)
{
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
if (CurrFrame.Layers[Layer].HasNextHot)
{
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
}
}
LayerBuffers[Layer] = TempBuffer;
}
// Render Each layer's block to the appropriate temp buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
if (LayerFrame.HasHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
animation_block Block = LayerFrame.Hot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
if (LayerFrame.HasNextHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
animation_block Block = LayerFrame.NextHot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
AnimationSystem_EndRenderBlockToLedBuffer(System, Context);
}
// Blend together any layers that have a hot and next hot buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
if (LayerFrame.HasNextHot)
{
LedBuffer_Blend(LayerBuffer.HotBuffer,
LayerBuffer.NextHotBuffer,
&LayerBuffer.HotBuffer,
LedBlend_Lerp,
(u8*)&LayerFrame.NextHotOpacity);
}
}
// Consolidate Temp Buffers back into AssemblyLedBuffer
// We do this in reverse order so that they go from top to bottom
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
if (CurrFrame.Layers[Layer].HasHot)
{
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
LedBuffer_Blend(AccBuffer,
LayerBuffers[Layer].HotBuffer,
&AccBuffer,
Blend,
0);
}
}
return AccBuffer;
}
internal void
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
led_system* LedSystem,
animation_pattern_array Patterns,
gs_memory_arena* Transient,
context Context,
u8* UserData)
{
DEBUG_TRACK_FUNCTION;
r32 FrameTime = AnimationSystem_GetCurrentTime(*System);
#if 1
animation_array Animations = System->Animations;
animation_fade_group FadeGroup = System->ActiveFadeGroup;
animation* FromAnim = AnimationArray_Get(Animations, FadeGroup.From);
animation_frame FromFrame = AnimationSystem_CalculateAnimationFrame(System, FromAnim, Transient);
layer_led_buffer* FromLayerBuffers = PushArray(Transient, layer_led_buffer, FromFrame.LayersCount);
animation* ToAnim = AnimationArray_Get(Animations, FadeGroup.To);
animation_frame ToFrame = {0};
layer_led_buffer* ToLayerBuffers = 0;
if (ToAnim)
{
ToFrame = AnimationSystem_CalculateAnimationFrame(System, ToAnim, Transient);
ToLayerBuffers = PushArray(Transient, layer_led_buffer, ToFrame.LayersCount);
}
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
led_buffer FromBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
FromFrame,
FromLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
led_buffer ConsolidatedBuffer = FromBuffer;
if (ToAnim) {
led_buffer ToBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
ToFrame,
ToLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
}
LedBuffer_Copy(ConsolidatedBuffer, AssemblyLedBuffer);
}
#else
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, ActiveAnim, Transient);
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
led_buffer AccBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
CurrFrame,
LayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient);
LedBuffer_Copy(AccBuffer, AssemblyLedBuffer);
}
#endif
System->LastUpdatedFrame = System->CurrentFrame;
}
#define FOLDHAUS_ANIMATION_RENDERER_CPP
#endif // FOLDHAUS_ANIMATION_RENDERER_CPP

View File

@ -0,0 +1,207 @@
//
// File: foldhaus_animation_serializer.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-04
//
#ifndef FOLDHAUS_ANIMATION_SERIALIZER_CPP
internal gs_string
AnimSerializer_Serialize(animation Anim, animation_pattern_array Patterns, gs_memory_arena* Arena)
{
serializer Serializer = {0};
Serializer.String = PushString(Arena, 4096);
Serializer.Identifiers = AnimationFieldStrings;
Serializer.IdentifiersCount = AnimField_Count;
Serializer_WriteF(&Serializer, "%S;\n", AnimationFieldStrings[AnimField_FileIdent]);
Serializer_WriteStringValue(&Serializer, AnimField_AnimName, Anim.Name.ConstString);
Serializer_WriteValue(&Serializer, AnimField_LayersCount, Anim.Layers.Count);
Serializer_WriteValue(&Serializer, AnimField_BlocksCount, Anim.Blocks_.Count);
Serializer_OpenStruct(&Serializer, AnimField_PlayableRange);
{
Serializer_WriteValue(&Serializer, AnimField_PlayableRangeMin, (u32)Anim.PlayableRange.Min);
Serializer_WriteValue(&Serializer, AnimField_PlayableRangeMax, (u32)Anim.PlayableRange.Max);
}
Serializer_CloseStruct(&Serializer);
Serializer_OpenStruct(&Serializer, AnimField_LayersArray);
for (u32 i = 0; i < Anim.Layers.Count; i++)
{
anim_layer LayerAt = Anim.Layers.Values[i];
Serializer_OpenStruct(&Serializer, AnimField_Layer);
{
Serializer_WriteStringValue(&Serializer, AnimField_LayerName, LayerAt.Name.ConstString);
Serializer_WriteStringValue(&Serializer, AnimField_LayerBlendMode, BlendModeStrings[LayerAt.BlendMode].ConstString);
}
Serializer_CloseStruct(&Serializer);
}
Serializer_CloseStruct(&Serializer);
Serializer_OpenStruct(&Serializer, AnimField_BlocksArray);
for (u32 i = 0; i < Anim.Blocks_.Count; i++)
{
// TODO(pjs): Handle free'd animation blocks
animation_block AnimationBlockAt = Anim.Blocks_.Values[i];
animation_pattern Animation = Patterns_GetPattern(Patterns, AnimationBlockAt.AnimationProcHandle);
Serializer_OpenStruct(&Serializer, AnimField_Block);
{
Serializer_OpenStruct(&Serializer, AnimField_BlockFrameRange);
{
Serializer_WriteValue(&Serializer, AnimField_BlockFrameRangeMin, (u32)AnimationBlockAt.Range.Min);
Serializer_WriteValue(&Serializer, AnimField_BlockFrameRangeMax, (u32)AnimationBlockAt.Range.Max);
}
Serializer_CloseStruct(&Serializer);
Serializer_WriteValue(&Serializer, AnimField_BlockLayerIndex, AnimationBlockAt.Layer);
Serializer_WriteStringValue(&Serializer, AnimField_BlockAnimName, ConstString(Animation.Name));
}
Serializer_CloseStruct(&Serializer);
}
Serializer_CloseStruct(&Serializer);
return Serializer.String;
}
internal animation
AnimParser_Parse(gs_string File, gs_memory_arena* Arena, animation_pattern_array AnimPatterns)
{
animation Result = {0};
parser Parser = {0};
Parser.String = File;
Parser.At = Parser.String.Str;
Parser.Identifiers = AnimationFieldStrings;
Parser.IdentifiersCount = AnimField_Count;
Parser.Arena = Arena;
if (Parser_ReadString(&Parser, AnimationFieldStrings[AnimField_FileIdent]))
{
Result.Name = Parser_ReadStringValue(&Parser, AnimField_AnimName);
u32 LayersNeeded = Parser_ReadU32Value(&Parser, AnimField_LayersCount);
u32 BlocksNeeded = Parser_ReadU32Value(&Parser, AnimField_BlocksCount);
Result.Layers = AnimLayerArray_Create(Arena, LayersNeeded);
Result.Blocks_ = AnimBlockArray_Create(Arena, BlocksNeeded);
if (Parser_ReadOpenStruct(&Parser, AnimField_PlayableRange))
{
Result.PlayableRange.Min = Parser_ReadU32Value(&Parser, AnimField_PlayableRangeMin);
Result.PlayableRange.Max = Parser_ReadU32Value(&Parser, AnimField_PlayableRangeMax);
if (Parser_ReadCloseStruct(&Parser))
{
// TODO(pjs): Error
}
}
else
{
// TODO(pjs): Error
}
if (Parser_ReadOpenStruct(&Parser, AnimField_LayersArray))
{
while (!Parser_ReadCloseStruct(&Parser))
{
anim_layer Layer = {0};
if (Parser_ReadOpenStruct(&Parser, AnimField_Layer))
{
Layer.Name = Parser_ReadStringValue(&Parser, AnimField_LayerName);
gs_string BlendModeName = Parser_ReadStringValue(&Parser, AnimField_LayerBlendMode);
for (u32 i = 0; i < BlendMode_Count; i++)
{
if (StringsEqual(BlendModeName, BlendModeStrings[i]))
{
Layer.BlendMode = (blend_mode)i;
break;
}
}
if (Parser_ReadCloseStruct(&Parser))
{
Animation_AddLayer(&Result, Layer);
}
else
{
// TODO(pjs): Error
}
}
}
}
if (Parser_ReadOpenStruct(&Parser, AnimField_BlocksArray))
{
while(!Parser_ReadCloseStruct(&Parser))
{
animation_block Block = {0};
if (Parser_ReadOpenStruct(&Parser, AnimField_Block))
{
if (Parser_ReadOpenStruct(&Parser, AnimField_BlockFrameRange))
{
Block.Range.Min = Parser_ReadU32Value(&Parser, AnimField_BlockFrameRangeMin);
Block.Range.Max = Parser_ReadU32Value(&Parser, AnimField_BlockFrameRangeMax);
Parser_ReadCloseStruct(&Parser);
}
else
{
// TODO(pjs): Error
}
Block.Layer = Parser_ReadU32Value(&Parser, AnimField_BlockLayerIndex);
// TODO(pjs): AnimName -> Animation Proc Handle
gs_string AnimName = Parser_ReadStringValue(&Parser, AnimField_BlockAnimName);
Block.AnimationProcHandle = {0};
for (u32 i = 0; i < AnimPatterns.Count; i++)
{
animation_pattern Pattern = AnimPatterns.Values[i];
if (StringEqualsCharArray(AnimName.ConstString, Pattern.Name, Pattern.NameLength))
{
Block.AnimationProcHandle = Patterns_IndexToHandle(i);
break;
}
}
Assert(IsValid(Block.AnimationProcHandle));
if (Parser_ReadCloseStruct(&Parser))
{
AnimBlockArray_Push(&Result.Blocks_, Block);
}
else
{
// TODO(pjs): Error
}
}
}
}
}
return Result;
}
internal animation
AnimParser_Parse(gs_data File, gs_memory_arena* Arena, animation_pattern_array AnimPatterns)
{
gs_string FileString = MakeString((char*)File.Memory, File.Size);
return AnimParser_Parse(FileString, Arena, AnimPatterns);
}
internal animation_handle
AnimationSystem_LoadAnimationFromFile(animation_system* System, animation_pattern_array AnimPatterns, context Context, gs_const_string FilePath)
{
animation_handle NewAnimHandle = InvalidAnimHandle();
gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FilePath);
if (AnimFile.Size > 0)
{
animation NewAnim = AnimParser_Parse(AnimFile.Data, System->Storage, AnimPatterns);
NewAnim.FileInfo = AnimFile.FileInfo;
NewAnim.FileInfo.Path = PushStringF(System->Storage, AnimFile.FileInfo.Path.Length, "%S", AnimFile.FileInfo.Path).ConstString;
NewAnimHandle = AnimationArray_Push(&System->Animations, NewAnim);
}
return NewAnimHandle;
}
#define FOLDHAUS_ANIMATION_SERIALIZER_CPP
#endif // FOLDHAUS_ANIMATION_SERIALIZER_CPP

View File

@ -0,0 +1,10 @@
//
// File: artnet.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
/* For future artnet implementation */
#ifndef ARTNET_H
#define ARTNET_H
#endif // ARTNET_H

View File

@ -0,0 +1,283 @@
//
// File: foldhaus_assembly.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_CPP
///////////////////////////
//
// Assembly Array
//
///////////////////////////
internal assembly_array
AssemblyArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
assembly_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, assembly, Result.CountMax);
return Result;
}
internal u32
AssemblyArray_Push(assembly_array* Array, assembly Assembly)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Assembly;
Array->Values[Index].AssemblyIndex = Index;
return Index;
}
internal assembly*
AssemblyArray_Take(assembly_array* Array)
{
u32 Index = AssemblyArray_Push(Array, {});
assembly* Result = Array->Values + Index;
return Result;
}
internal void
AssemblyArray_RemoveAt(assembly_array* Array, u32 Index)
{
u32 LastAssemblyIndex = --Array->Count;
Array->Values[Index] = Array->Values[LastAssemblyIndex];
}
typedef bool assembly_array_filter_proc(assembly A);
bool AssemblyFilter_OutputsViaSACN(assembly A) { return A.OutputMode == NetworkProtocol_SACN; }
bool AssemblyFilter_OutputsViaUART(assembly A) { return A.OutputMode == NetworkProtocol_UART; }
internal assembly_array
AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, gs_memory_arena* Storage)
{
assembly_array Result = AssemblyArray_Create(Array.Count, Storage);
for (u32 i = 0; i < Array.Count; i++)
{
assembly At = Array.Values[i];
if (Filter(At))
{
AssemblyArray_Push(&Result, At);
}
}
return Result;
}
///////////////////////////
//
// LedSystem
//
///////////////////////////
internal led_system
LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
{
led_system Result = {};
Result.PlatformMemory = PlatformMemory;
// TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up
Result.BuffersCountMax = BuffersMax;
Result.Buffers = AllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax, "led system");
return Result;
}
internal u32
LedSystemTakeFreeBuffer(led_system* System, u32 LedCount)
{
s32 Result = -1;
if (System->BuffersCount < System->BuffersCountMax)
{
Result = System->BuffersCount++;
}
else
{
// NOTE(Peter): Look for a buffer that's flagged as empty
for (u32 i = 0; i < System->BuffersCount; i++)
{
if (System->Buffers[i].LedCount == 0
&& System->Buffers[i].Colors == 0
&& System->Buffers[i].Positions == 0)
{
Result = i;
break;
}
}
Assert(Result >= 0); // NOTE(Peter): We ran out of room for led buffers
}
led_buffer* Buffer = &System->Buffers[Result];
Buffer->A = MemoryArenaCreate(KB(16),Bytes(8),System->PlatformMemory,0,0,"Led Buffer Arena");
Buffer->LedCount = LedCount;
Buffer->Colors = PushArray(&Buffer->A, pixel, Buffer->LedCount);
Buffer->Positions = PushArray(&Buffer->A, v4, Buffer->LedCount);
System->LedsCountTotal += LedCount;
return (u32)Result;
}
internal void
LedSystemFreeBuffer(led_system* System, u32 BufferIndex)
{
Assert(BufferIndex < System->BuffersCountMax);
led_buffer* Buffer = &System->Buffers[BufferIndex];
MemoryArenaFree(&Buffer->A);
System->LedsCountTotal -= Buffer->LedCount;
*Buffer = {};
}
internal void
LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position)
{
Assert(Led < Buffer->LedCount);
Buffer->Positions[Led] = Position;
}
internal u32
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex, u32 LedLUTStartIndex)
{
u32 LedsAdded = 0;
switch (GenData.Method)
{
case StripGeneration_InterpolatePoints:
{
strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints;
v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale);
v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount;
for (u32 Step = 0; Step < InterpPoints.LedCount; Step++)
{
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex;
}
}break;
case StripGeneration_Sequence:
{
strip_gen_sequence Sequence = GenData.Sequence;
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded);
}
}break;
InvalidDefaultCase;
}
return LedsAdded;
}
internal void
ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
{
Assembly->LedBufferIndex = LedSystemTakeFreeBuffer(LedSystem, Assembly->LedCountTotal);
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
v4 RootPosition = ToV4Vec(Assembly->Center);
// Add Leds
u32 LedsAdded = 0;
for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++)
{
v2_strip* StripAt = &Assembly->Strips[StripIdx];
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
strip_gen_data GenData = StripAt->GenerationData;
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0);
}
}
internal assembly*
LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena* Scratch, context Context, gs_const_string Path, log_buffer* GlobalLog)
{
assembly* NewAssembly = 0;
gs_file AssemblyFile = ReadEntireFile(Context.ThreadContext.FileHandler, Path);
if (FileNoError(AssemblyFile))
{
gs_string AssemblyFileText = MakeString((char*)AssemblyFile.Memory);
s32 IndexOfLastSlash = FindLast(Path, '\\');
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Assembly Arena");
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
if (AssemblyParser.Success)
{
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
else
{
MemoryArenaFree(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
for (parser_error* ErrorAt = AssemblyParser.ErrorsRoot;
ErrorAt != 0;
ErrorAt = ErrorAt->Next)
{
Log_Error(GlobalLogBuffer, ErrorAt->Message.Str);
}
}
else
{
Log_Error(GlobalLog, "Unable to load assembly file");
}
return NewAssembly;
}
internal void
UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
{
Assert(AssemblyIndex < State->Assemblies.Count);
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
MemoryArenaFree(&Assembly->Arena);
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
}
// Querying Assemblies
internal led_strip_list
AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_const_string TagValue, gs_memory_arena* Storage)
{
led_strip_list Result = {0};
// TODO(pjs): @Optimization
// We can probably come back here and do this allocation procedurally, or in buckets, or with
// a linked list. But for now, I just want to get this up and running
Result.CountMax = Assembly.StripCount;
Result.StripIndices = PushArray(Storage, u32, Result.CountMax);
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = 0;
if (TagValue.Length > 0)
{
ValueHash = HashDJB2ToU32(StringExpand(TagValue));
}
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip StripAt = Assembly.Strips[StripIndex];
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
{
Result.StripIndices[Result.Count++] = StripIndex;
}
}
return Result;
}
#define FOLDHAUS_ASSEMBLY_CPP
#endif // FOLDHAUS_ASSEMBLY_CPP

View File

@ -0,0 +1,298 @@
//
// File: foldhaus_assembly.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_H
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_UART,
NetworkProtocol_Count,
};
union pixel
{
struct
{
u8 R;
u8 G;
u8 B;
};
u8 Channels[3];
};
struct led_buffer
{
// NOTE(PS): This is just a tracking structure,
// that enables allocations for a particular buffer
// to occur all in contiguous memory
// and should not be pushed to after the initial
// allocation
gs_memory_arena A;
u32 LedCount;
pixel* Colors;
v4* Positions;
};
struct led_buffer_range
{
u32 First;
u32 OnePastLast;
};
struct led_system
{
gs_allocator PlatformMemory;
u32 BuffersCountMax;
u32 BuffersCount;
led_buffer* Buffers;
u32 LedsCountTotal;
};
struct v2_tag
{
u64 NameHash;
u64 ValueHash;
};
struct strip_sacn_addr
{
s32 StartUniverse;
s32 StartChannel;
};
struct strip_uart_addr
{
u8 Channel;
gs_string ComPort;
// This may not be used based on the value of the parent
// assembly's NetworkPortMode field
};
enum strip_gen_method
{
StripGeneration_InterpolatePoints,
StripGeneration_Sequence,
StripGeneration_Count,
};
typedef struct strip_gen_data strip_gen_data;
struct strip_gen_interpolate_points
{
v3 StartPosition;
v3 EndPosition;
u32 LedCount;
};
struct strip_gen_sequence
{
strip_gen_data* Elements;
u32 ElementsCount;
};
struct strip_gen_data
{
strip_gen_method Method;
strip_gen_interpolate_points InterpolatePoints;
strip_gen_sequence Sequence;
};
struct v2_strip
{
s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore
strip_sacn_addr SACNAddr;
strip_uart_addr UARTAddr;
strip_gen_data GenerationData;
u32 LedCount;
u32* LedLUT;
u32 TagsCount;
v2_tag* Tags;
};
struct led_strip_list
{
u32 Count;
u32 CountMax;
u32* StripIndices;
};
enum network_port_mode
{
// This enum defines the scope which contains what network
// port each address should be sent over.
NetworkPortMode_GlobalPort,
// GlobalPort means that the port is defined in the assembly structure
NetworkPortMode_PortPerStrip,
// PortPerStrip means that the address stored in the strip structure
// should be used, and each strip might have a different port
NetworkPortMode_Count,
};
struct assembly
{
gs_memory_arena Arena;
u32 AssemblyIndex;
gs_string Name;
gs_string FilePath;
r32 Scale;
v3 Center;
v3 MinLedPos, MaxLedPos;
s32 LedCountTotal;
u32 LedBufferIndex;
u32 StripCount;
v2_strip* Strips;
network_protocol OutputMode;
network_port_mode NetPortMode;
gs_string UARTComPort;
};
struct assembly_array
{
u32 CountMax;
u32 Count;
assembly* Values;
};
typedef pixel led_blend_proc(pixel A, pixel B, u8* UserData);
internal led_buffer*
LedSystemGetBuffer(led_system* System, u32 Index)
{
led_buffer* Result = &System->Buffers[Index];
return Result;
}
internal void
LedBuffer_ClearToBlack(led_buffer* Buffer)
{
for (u32 i = 0; i < Buffer->LedCount; i++)
{
Buffer->Colors[i].R = 0;
Buffer->Colors[i].G = 0;
Buffer->Colors[i].B = 0;
}
}
internal void
LedBuffer_Copy(led_buffer From, led_buffer* To)
{
DEBUG_TRACK_FUNCTION;
Assert(From.LedCount == To->LedCount);
u32 LedCount = To->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
To->Colors[i] = From.Colors[i];
}
}
internal void
LedBuffer_Blend(led_buffer A, led_buffer B, led_buffer* Dest, led_blend_proc* BlendProc, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
Assert(A.LedCount == B.LedCount);
Assert(Dest->LedCount == A.LedCount);
Assert(BlendProc);
u32 LedCount = Dest->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
pixel PA = A.Colors[i];
pixel PB = B.Colors[i];
Dest->Colors[i] = BlendProc(PA, PB, UserData);
}
}
internal led_buffer
LedBuffer_CreateCopyCleared (led_buffer Buffer, gs_memory_arena* Arena)
{
DEBUG_TRACK_FUNCTION;
led_buffer Result = {};
Result.LedCount = Buffer.LedCount;
Result.Positions = Buffer.Positions;
Result.Colors = PushArray(Arena, pixel, Buffer.LedCount);
LedBuffer_ClearToBlack(&Result);
return Result;
}
internal u32
StripGenData_CountLeds(strip_gen_data Data)
{
u32 Result = 0;
switch (Data.Method)
{
case StripGeneration_InterpolatePoints:
{
Result += Data.InterpolatePoints.LedCount;
}break;
case StripGeneration_Sequence:
{
for (u32 i = 0; i < Data.Sequence.ElementsCount; i++)
{
Result += StripGenData_CountLeds(Data.Sequence.Elements[i]);
}
}break;
InvalidDefaultCase;
}
return Result;
}
internal bool
AssemblyStrip_HasTagValue(v2_strip Strip, u64 NameHash, u64 ValueHash)
{
bool Result = false;
for (u32 i = 0; i < Strip.TagsCount; i++)
{
v2_tag TagAt = Strip.Tags[i];
if (TagAt.NameHash == NameHash)
{
// NOTE(pjs): We can pass an empty string to the Value parameter,
// and it will match all values of Tag
if (ValueHash == 0 || ValueHash == TagAt.ValueHash)
{
Result = true;
break;
}
}
}
return Result;
}
internal bool
AssemblyStrip_HasTagValueSLOW(v2_strip Strip, char* Name, char* Value)
{
u64 NameHash = HashDJB2ToU32(Name);
u64 ValueHash = HashDJB2ToU32(Value);
return AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash);
}
#define FOLDHAUS_ASSEMBLY_H
#endif // FOLDHAUS_ASSEMBLY_H

Some files were not shown because too many files have changed in this diff Show More