Post Burning Man 22 Cleanup

This commit is contained in:
Peter Slattery 2022-10-24 14:05:47 -07:00
parent bf8ff5e506
commit 685ac245cc
333 changed files with 14 additions and 37201 deletions

View File

@ -2,7 +2,7 @@ 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"
const OUT_FILE_PATH = "../src/user_space/incenter_gen_cities.h"
function print_city_desc (city, prefix, dest, gets_own_universe)
{

View File

@ -3,7 +3,3 @@ set -e
SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}")
$SCRIPT_REL_DIR/build_.sh debug osx arm64
# $SCRIPT_REL_DIR/build_.sh debug wasm intel
# pushd "run_tree/raspi/arm64/debug"
# clang -o lumenarium /home/pi/dev/Lumenarium/src_v2/platform/raspi/lumenarium_first_raspi.c -lm
# popd

View File

@ -95,11 +95,11 @@ 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"
PlatformEntry_win32="src/platform/win32/lumenarium_first_win32.cpp"
PlatformEntry_osx="src/platform/osx/lumenarium_first_osx.c"
PlatformEntry_wasm="src/platform/wasm/lumenarium_first_wasm.cpp"
PlatformEntry_linux="src/platform/linux/lumenarium_first_linux.cpp"
PlatformEntry_raspi="src/platform/raspi/lumenarium_first_raspi.c"
# Intermediate Outputs
@ -118,7 +118,7 @@ LinkerOutput_linux=""
LinkerOutput_raspi="lumenarium"
# Wasm Sys Root
WasmSysRoot="${PROJECT_PATH}/src_v2/platform/wasm/sysroot/"
WasmSysRoot="${PROJECT_PATH}/src/platform/wasm/sysroot/"
# Compiler Flags
@ -197,7 +197,7 @@ LinkerFlags_PROD=""
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_osx="-framework OpenGL -framework Cocoa -framework IOKit ${PROJECT_PATH}/src/libs/glfw_osx/lib-universal/libglfw3.a"
LinkerLibs_wasm=""
LinkerLibs_linux=""
LinkerLibs_raspi=""
@ -354,13 +354,13 @@ then
-o $LinkerOutput \
$EntryPath
cp \
"${PROJECT_PATH}/src_v2/platform/wasm/lumenarium_wasm_imports.js" \
"${PROJECT_PATH}/src/platform/wasm/lumenarium_wasm_imports.js" \
./lumenarium_wasm_imports.js
else
# Preprocessing Steps
ConvertCsvEntry="${PROJECT_PATH}/src_v2/tools/convert_csv.c"
ConvertCsvEntry="${PROJECT_PATH}/src/tools/convert_csv.c"
$Compiler \
-o convert_csv \
$CompilerFlags \

View File

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

Binary file not shown.

Binary file not shown.

View File

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

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

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

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

@ -1,46 +0,0 @@
/* 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

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

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

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

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

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

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

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

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

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

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

View File

@ -1,238 +0,0 @@
//
// File: foldhaus_assembly_debug.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef FOLDHAUS_ASSEMBLY_DEBUG_H
enum override_type
{
ADS_Override_None,
ADS_Override_Strip,
ADS_Override_SoloStrip,
ADS_Override_AllRed,
ADS_Override_AllGreen,
ADS_Override_AllBlue,
ADS_Override_AllOff,
ADS_Override_AllWhite,
ADS_Override_AllHue,
ADS_Override_TagWhite,
ADS_Override_TagStripWhite,
ADS_Override_ChannelWhite,
ADS_Override_Count,
};
global gs_const_string OverrideTypeStrings[] = {
LitString("Override_None"),
LitString("Override_Strip"),
LitString("Override_SoloStrip" ),
LitString("Override_AllRed" ),
LitString("Override_AllGreen" ),
LitString("Override_AllBlue" ),
LitString("ADS_Override_AllOff" ),
LitString("ADS_Override_AllWhite" ),
LitString("ADS_Override_AllHue" ),
LitString("ADS_Override_TagWhite" ),
LitString("ADS_Override_TagStripWhite" ),
LitString("ADS_Override_ChannelWhite," ),
LitString("Override_Count"),
};
struct assembly_debug_state
{
override_type Override;
bool AllAssemblies;
u32 TargetAssembly;
u32 TargetStrip;
gs_string TagName;
gs_string TagValue;
u32 TargetHue;
pixel TargetColor;
u32 TargetChannel;
u8 Brightness;
};
internal assembly_debug_state
AssemblyDebug_Create(gs_memory_arena* Storage)
{
assembly_debug_state Result = {};
Result.TagName = PushString(Storage, 256);
Result.TagValue = PushString(Storage, 256);
return Result;
}
internal void
AssemblyDebug_OverrideStripWithColor(v2_strip Strip, led_buffer LedBuffer, pixel Color)
{
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIdx = Strip.LedLUT[i];
LedBuffer.Colors[LedIdx] = Color;
}
}
internal void
AssemblyDebug_OverrideWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color)
{
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}
internal void
AssemblyDebug_OverrideTagValueWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color, gs_string TagName, gs_string TagValue)
{
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = HashDJB2ToU32(StringExpand(TagValue));
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash))
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}
}
internal void
AssemblyDebug_OverrideOutputForAssembly(assembly_debug_state State, led_system LedSystem,
assembly Assembly)
{
led_buffer LedBuffer = LedSystem.Buffers[Assembly.LedBufferIndex];
u8 V = State.Brightness;
switch (State.Override)
{
case ADS_Override_Strip:
{
v2_strip Strip = Assembly.Strips[State.TargetStrip];
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, State.TargetColor);
}break;
case ADS_Override_SoloStrip:
{
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
pixel Color = pixel{0,0,0};
if (s == State.TargetStrip)
{
Color = State.TargetColor;
}
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}break;
case ADS_Override_AllRed:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, 0, 0});
}break;
case ADS_Override_AllGreen:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, V, 0});
}break;
case ADS_Override_AllBlue:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, V});
}break;
case ADS_Override_AllOff:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
}break;
case ADS_Override_AllWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, V, V});
}break;
case ADS_Override_AllHue:
{
v4 HSV = v4{(r32)State.TargetHue, 1, 1, 1};
v4 RGB = HSVToRGB(HSV);
pixel P = V4ToRGBPixel(RGB);
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, P);
}break;
case ADS_Override_TagWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
AssemblyDebug_OverrideTagValueWithColor(Assembly, LedBuffer, pixel{255, 255, 255}, State.TagName, State.TagValue);
}break;
case ADS_Override_TagStripWhite:
{
u64 NameHash = HashDJB2ToU32(StringExpand(State.TagName));
u64 ValueHash = HashDJB2ToU32(StringExpand(State.TagValue));
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
v2_strip Strip = Assembly.Strips[State.TargetStrip];
if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash))
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer,
pixel{255, 255, 255});
}
}break;
case ADS_Override_ChannelWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
if (Strip.UARTAddr.Channel == State.TargetChannel)
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, pixel{255, 255, 255});
}
}
}break;
case ADS_Override_None:
{
}break;
InvalidDefaultCase;
}
}
internal void
AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assemblies, led_system LedSystem)
{
if (State.Override == ADS_Override_None) return;
State.TargetColor = pixel{255,255,255};
if (State.AllAssemblies)
{
for (u32 i = 0; i < Assemblies.Count; i++)
{
assembly Assembly = Assemblies.Values[i];
AssemblyDebug_OverrideOutputForAssembly(State, LedSystem, Assembly);
}
}
else
{
assembly Assembly = Assemblies.Values[State.TargetAssembly];
AssemblyDebug_OverrideOutputForAssembly(State, LedSystem, Assembly);
}
}
#define FOLDHAUS_ASSEMBLY_DEBUG_H
#endif // FOLDHAUS_ASSEMBLY_DEBUG_H

View File

@ -1,336 +0,0 @@
//
// File: foldhaus_assembly_parser.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_PARSER_CPP
// TODO(pjs): This is good for meta generation
// ie. It would be great to have
// // enum ident enum prefix
// BEGIN_GEN_ENUM(assembly_field, AssemblyField_)
// // value name gen string of the value name the paired string identifier
// ADD_ENUM_VALUE(AssemblyName, DO_GEN_STRING, "assembly_name")
// ADD_ENUM_VALUE(AssemblyScale, DO_GEN_STRING, "assembly_scale")
// END_GEN_ENUM(assembly_field)
enum assembly_field
{
AssemblyField_AssemblyName,
AssemblyField_AssemblyScale,
AssemblyField_AssemblyCenter,
AssemblyField_LedStripCount,
AssemblyField_OutputMode,
AssemblyField_LedStrip,
AssemblyField_OutputSACN,
AssemblyField_SACN_StartUniverse,
AssemblyField_SACN_StartChannel,
AssemblyField_OutputUART,
AssemblyField_UART_Channel,
AssemblyField_UART_ComPort,
AssemblyField_PointPlacementType,
AssemblyField_InterpolatePoints,
AssemblyField_Start,
AssemblyField_End,
AssemblyField_LedCount,
AssemblyField_SegmentSequence,
AssemblyField_SegmentSequenceLength,
AssemblyField_Segment,
AssemblyField_TagsCount,
AssemblyField_Tag,
AssemblyField_Name,
AssemblyField_Value,
AssemblyField_Count,
};
global gs_const_string AssemblyFieldIdentifiers[] = {
ConstString("assembly_name"), // AssemblyField_AssemblyName
ConstString("assembly_scale"), // AssemblyField_AssemblyScale
ConstString("assembly_center"), // AssemblyField_AssemblyCenter
ConstString("led_strip_count"), // AssemblyField_LedStripCount
ConstString("output_mode"), // AssemblyField_OutputMode
ConstString("led_strip"), // AssemblyField_LedStrip
ConstString("output_sacn"), // AssemblyField_OutputSACN
ConstString("start_universe"), // AssemblyField_SACN_StartUniverse
ConstString("start_channel"), // AssemblyField_SACN_StartChannel
ConstString("output_uart"), // AssemblyField_OutputUART
ConstString("channel"), // AssemblyField_UART_Channel
ConstString("com_port"), // AssemblyField_UART_ComPort
ConstString("point_placement_type"), // AssemblyField_PointPlacementType
ConstString("interpolate_points"), // AssemblyField_InterpolatePoints
ConstString("start"), // AssemblyField_Start
ConstString("end"), // AssemblyField_End
ConstString("led_count"), // AssemblyField_LedCount
ConstString("segment_sequence"), // AssemblyField_SegmentSequence
ConstString("segment_count"), // AssemblyField_SegmentSequenceLength
ConstString("segment"), // AssemblyField_Segment
ConstString("tags_count"), // AssemblyField_TagCount
ConstString("tag"), // AssemblyField_Tag
ConstString("name"), // AssemblyField_Name
ConstString("value"), // AssemblyField_Value
};
internal void
StripSetTag(v2_strip* Strip, u32 TagIndex, gs_const_string TagName, gs_const_string TagValue)
{
Assert(TagIndex < Strip->TagsCount);
v2_tag* TagAt = &Strip->Tags[TagIndex];
TagAt->NameHash = HashDJB2ToU32(StringExpand(TagName));
TagAt->ValueHash = HashDJB2ToU32(StringExpand(TagValue));
}
internal strip_sacn_addr
AssemblyParser_ReadSACNAddr(parser* Parser, assembly Assembly)
{
strip_sacn_addr Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputSACN))
{
Result.StartUniverse = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartUniverse);
Result.StartChannel = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartChannel);
if (!Parser_ReadCloseStruct(Parser))
{
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
return Result;
}
internal strip_uart_addr
AssemblyParser_ReadUARTAddr(parser* Parser, assembly Assembly)
{
strip_uart_addr Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputUART))
{
Result.Channel = (u8)Parser_ReadU32Value(Parser, AssemblyField_UART_Channel);
bool HasNetPort = Parser_ReadStringValue(Parser, AssemblyField_UART_ComPort, &Result.ComPort, true);
if (Assembly.NetPortMode == NetworkPortMode_PortPerStrip && !HasNetPort)
{
Parser_PushErrorF(Parser, "NetPortMode for assembly is PortPerStrip, but this strip doesn't have an output port.");
}
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Struct doesn't close where expected");
}
}
return Result;
}
internal void
AssemblyParser_ReadTag(parser* Parser, v2_strip* StripAt, u32 TagIndex)
{
if (Parser_ReadOpenStruct(Parser, AssemblyField_Tag))
{
// TODO(Peter): Need to store the gs_string somewhere we can look it up for display in the interface
// right now they are stored in temp memory and won't persist
gs_string TagName = Parser_ReadStringValue(Parser, AssemblyField_Name);
gs_string TagValue = Parser_ReadStringValue(Parser, AssemblyField_Value);
StripSetTag(StripAt, TagIndex, TagName.ConstString, TagValue.ConstString);
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Tag struct doesn't close where expected");
}
}
else
{
Parser_PushErrorF(Parser, "Expected a tag struct, but none was found.");
}
}
internal void
AssemblyParser_ReadTagList(parser* Parser, v2_strip* StripAt, assembly* Assembly)
{
StripAt->TagsCount = Parser_ReadU32Value(Parser, AssemblyField_TagsCount);
// NOTE(pjs): Always add one tag to the input to leave room for the assembly name
StripAt->TagsCount += 1;
StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount);
StripSetTag(StripAt, 0, ConstString("assembly"), Assembly->Name.ConstString);
for (u32 Tag = 1; Tag < StripAt->TagsCount; Tag++)
{
AssemblyParser_ReadTag(Parser, StripAt, Tag);
}
}
internal strip_gen_data AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly);
internal strip_gen_interpolate_points
AssemblyParser_ReadInterpolatePoints(parser* Parser)
{
strip_gen_interpolate_points Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_InterpolatePoints))
{
Result.StartPosition = Parser_ReadV3Value(Parser, AssemblyField_Start);
Result.EndPosition = Parser_ReadV3Value(Parser, AssemblyField_End);
Result.LedCount = Parser_ReadU32Value(Parser, AssemblyField_LedCount);
if (!Parser_ReadCloseStruct(Parser))
{
// TODO(pjs):
}
}
else
{
// TODO(pjs):
}
return Result;
}
internal strip_gen_sequence
AssemblyParser_ReadSequence(parser* Parser, assembly* Assembly)
{
strip_gen_sequence Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_SegmentSequence))
{
Result.ElementsCount = Parser_ReadU32Value(Parser, AssemblyField_SegmentSequenceLength);
Result.Elements = PushArray(&Assembly->Arena, strip_gen_data, Result.ElementsCount);
for (u32 i = 0; i < Result.ElementsCount; i++)
{
Result.Elements[i] = AssemblyParser_ReadStripGenData(Parser, Assembly);
}
if (!Parser_ReadCloseStruct(Parser))
{
// TODO(pjs):
}
}
else
{
// TODO(pjs):
}
return Result;
}
internal strip_gen_data
AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly)
{
strip_gen_data Result = {};
if (Parser_ReadOpenStruct(Parser, AssemblyField_Segment))
{
gs_string PointPlacementType = Parser_ReadStringValue(Parser, AssemblyField_PointPlacementType);
// TODO(pjs): We want to store enum strings in some unified way
// :EnumStringsGen
if (StringsEqual(PointPlacementType.ConstString, ConstString("InterpolatePoints")))
{
Result.Method = StripGeneration_InterpolatePoints;
Result.InterpolatePoints = AssemblyParser_ReadInterpolatePoints(Parser);
}
else if (StringsEqual(PointPlacementType.ConstString,
ConstString("SegmentSequence")))
{
Result.Method = StripGeneration_Sequence;
Result.Sequence = AssemblyParser_ReadSequence(Parser, Assembly);
}
else
{
Parser_PushErrorF(Parser, "Incorrect Point Placement Type found for segment");
}
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Strip Gen Data did not close the struct where expected");
}
}
return Result;
}
internal parser
ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient)
{
Assembly->LedCountTotal = 0;
parser Parser = {0};
Parser.FileName = FileName;
Parser.String = FileText;
Parser.Identifiers = &AssemblyFieldIdentifiers[0];
Parser.IdentifiersCount = AssemblyField_Count;
Parser.At = Parser.String.Str;
Parser.LineStart = Parser.At;
Parser.Arena = &Assembly->Arena;
Parser.Transient = Transient;
Parser.Success = true;
Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName);
Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale);
Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter) * Assembly->Scale;
Assembly->StripCount = Parser_ReadU32Value(&Parser, AssemblyField_LedStripCount);
Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount);
gs_string OutputModeString = Parser_ReadStringValue(&Parser, AssemblyField_OutputMode);
if (StringsEqual(OutputModeString.ConstString, ConstString("UART")))
{
Assembly->OutputMode = NetworkProtocol_UART;
if (Parser_ReadStringValue(&Parser, AssemblyField_UART_ComPort, &Assembly->UARTComPort, true))
{
Assembly->NetPortMode = NetworkPortMode_GlobalPort;
}
else
{
Assembly->NetPortMode = NetworkPortMode_PortPerStrip;
}
}
else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN")))
{
Assembly->OutputMode = NetworkProtocol_SACN;
}
else
{
Parser_PushErrorF(&Parser, "Invalid output mode specified for assembly.");
Parser.Success = false;
}
for (u32 i = 0; i < Assembly->StripCount; i++)
{
v2_strip* StripAt = Assembly->Strips + i;
if (Parser_ReadOpenStruct(&Parser, AssemblyField_LedStrip))
{
StripAt->SACNAddr = AssemblyParser_ReadSACNAddr(&Parser, *Assembly);
StripAt->UARTAddr = AssemblyParser_ReadUARTAddr(&Parser, *Assembly);
StripAt->GenerationData = AssemblyParser_ReadStripGenData(&Parser, Assembly);
StripAt->LedCount = StripGenData_CountLeds(StripAt->GenerationData);
AssemblyParser_ReadTagList(&Parser, StripAt, Assembly);
Assembly->LedCountTotal += StripAt->LedCount;
if (!Parser_ReadCloseStruct(&Parser))
{
Parser_PushErrorF(&Parser, "Strip struct doesn't close where expected");
Parser.Success = false;
}
}
else
{
Parser_PushErrorF(&Parser, "Expected a strip struct but none was found");
Parser.Success = false;
}
}
return Parser;
}
#define FOLDHAUS_ASSEMBLY_PARSER_CPP
#endif // FOLDHAUS_ASSEMBLY_PARSER_CPP

View File

@ -1,108 +0,0 @@
//
// File: foldhaus_addressed_data.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
// addressed_data_buffer is a generic buffer of data that also contains information
// regarding how it should be sent to a sculpture.
// This decouples the encoding step from the sending step.
//
#ifndef FOLDHAUS_ADDRESSED_DATA_H
enum data_buffer_address_type
{
AddressType_NetworkIP,
AddressType_ComPort,
AddressType_Invalid,
};
struct addressed_data_buffer
{
union
{
struct
{
u8* Memory;
u32 MemorySize;
};
gs_data Data;
};
data_buffer_address_type AddressType;
// IP Address
platform_socket_handle SendSocket;
u32 V4SendAddress;
u32 SendPort;
// COM
gs_const_string ComPort;
addressed_data_buffer* Next;
};
struct addressed_data_buffer_list
{
gs_memory_arena* Arena;
addressed_data_buffer* Root;
addressed_data_buffer* Head;
};
internal void
AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
{
List->Root = 0;
List->Head = 0;
MemoryArenaClear(List->Arena);
}
internal addressed_data_buffer*
AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List)
{
addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer);
*Result = {0};
Result->Next = 0;
Result->MemorySize = 0;
Result->Memory = 0;
SLLPushOrInit(List->Root, List->Head, Result);
return Result;
}
internal addressed_data_buffer*
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize)
{
addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List);
Result->MemorySize = BufferSize;
Result->Memory = PushArray(List->Arena, u8, Result->MemorySize);
return Result;
}
internal void
AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort)
{
Buffer->AddressType = AddressType_NetworkIP;
Buffer->SendSocket = SendSocket;
Buffer->V4SendAddress = V4SendAddress;
Buffer->SendPort = SendPort;
}
internal void
AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort)
{
Buffer->AddressType = AddressType_ComPort;
Buffer->ComPort = ComPort;
}
internal addressed_data_buffer_list
AddressedDataBufferList_Create(gs_thread_context TC)
{
addressed_data_buffer_list Result = {};
Result.Arena = AllocStruct(TC.Allocator, gs_memory_arena, "Addressed Data");
*Result.Arena = MemoryArenaCreate(KB(256), Bytes(8), TC.Allocator, 0, 0, "Addressed Data Buffer List Arena");
return Result;
}
#define FOLDHAUS_ADDRESSED_DATA_H
#endif // FOLDHAUS_ADDRESSED_DATA_H

View File

@ -1,126 +0,0 @@
/* date = April 12th 2021 4:25 pm */
#ifndef FOLDHAUS_LOG_H
#define FOLDHAUS_LOG_H
enum log_entry_type
{
LogEntry_Message,
LogEntry_Error,
};
struct log_entry
{
log_entry_type Type;
gs_string String;
};
struct log_buffer
{
gs_memory_arena* Arena;
u64 EntriesCount;
u64 NextEntry;
log_entry* Entries;
};
struct log_buffer_iter
{
log_buffer* Buffer;
u64 Start;
u64 IndexAt;
log_entry* At;
};
internal log_buffer
Log_Init(gs_memory_arena* A, u64 Count)
{
log_buffer Result = {};
Result.Arena = A;
Result.EntriesCount = Count;
Result.Entries = PushArray(A, log_entry, Result.EntriesCount);
u64 LogStringLength = 512;
u64 LogStringBufferSize = LogStringLength * Result.EntriesCount;
char* LogStringBuffer = PushArray(A, char, LogStringBufferSize);
char* LogStringBufferAt = LogStringBuffer;
for (u32 i = 0; i < Result.EntriesCount; i++)
{
Result.Entries[i].String = MakeString(LogStringBufferAt, 0, LogStringLength);
LogStringBufferAt += LogStringLength;
}
return Result;
}
internal u64
Log_GetNextIndex(log_buffer Log, u64 At)
{
u64 Result = At + 1;
if (Result >= Log.EntriesCount)
{
Result = 0;
}
return Result;
}
internal log_entry*
Log_TakeNextEntry(log_buffer* Log)
{
log_entry* Result = Log->Entries + Log->NextEntry;
Log->NextEntry = Log_GetNextIndex(*Log, Log->NextEntry);
return Result;
}
internal void
Log_PrintFVarArgs(log_buffer* Log, log_entry_type Type, char* Format, va_list Args)
{
log_entry* NextEntry = Log_TakeNextEntry(Log);
NextEntry->String.Length = 0;
NextEntry->Type = Type;
PrintFArgsList(&NextEntry->String, Format, Args);
NullTerminate(&NextEntry->String);
#if DEBUG
OutputDebugStringA(NextEntry->String.Str);
#endif
}
#define Log_Message(log, fmt, ...) Log_PrintF(log, LogEntry_Message, fmt, __VA_ARGS__)
#define Log_Error(log, fmt, ...) Log_PrintF(log, LogEntry_Error, fmt, __VA_ARGS__)
internal void
Log_PrintF(log_buffer* Log, log_entry_type Type, char* Format, ...)
{
va_list Args;
va_start(Args, Format);
Log_PrintFVarArgs(Log, Type, Format, Args);
va_end(Args);
}
internal log_buffer_iter
Log_GetIter(log_buffer* Buffer)
{
log_buffer_iter Result = {};
Result.Buffer = Buffer;
Result.Start = Buffer->NextEntry;
Result.IndexAt = Result.Start;
Result.At = Result.Buffer->Entries + Result.IndexAt;
return Result;
}
internal bool
LogIter_CanAdvance(log_buffer_iter Iter)
{
u64 Next = Log_GetNextIndex(*Iter.Buffer, Iter.IndexAt);
bool Result = Next != Iter.Start;
return Result;
}
internal void
LogIter_Advance(log_buffer_iter* Iter)
{
Iter->IndexAt = Log_GetNextIndex(*Iter->Buffer, Iter->IndexAt);
Iter->At = Iter->Buffer->Entries + Iter->IndexAt;
}
#endif //FOLDHAUS_LOG_H

View File

@ -1,154 +0,0 @@
//
// File: foldhaus_network_ordering.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_NETWORK_ORDERING_H
// Packs a u8 to a known big endian buffer
inline u8*
PackB1(u8* ptr, u8 val)
{
*ptr = val;
return ptr + sizeof(val);
}
//Unpacks a u8 from a known big endian buffer
inline u8
UpackB1(const u8* ptr)
{
return *ptr;
}
//Packs a u8 to a known little endian buffer
inline u8*
PackL1(u8* ptr, u8 val)
{
*ptr = val;
return ptr + sizeof(val);
}
//Unpacks a u8 from a known little endian buffer
inline u8
UpackL1(const u8* ptr)
{
return *ptr;
}
//Packs a u16 to a known big endian buffer
inline u16
PackB2(u16 Value)
{
u16 Result = 0;
u8* Array = (u8*)&Result;
Array[1] = (u8)(Value & 0xFF);
Array[0] = (u8)((Value & 0xFF00) >> 8);
return Result;
}
inline u8*
PackB2(u8* ptr, u16 val)
{
ptr[1] = (u8)(val & 0xff);
ptr[0] = (u8)((val & 0xff00) >> 8);
return ptr + sizeof(val);
}
//Unpacks a u16 from a known big endian buffer
inline u16
UpackB2(const u8* ptr)
{
return (u16)(ptr[1] | ptr[0] << 8);
}
//Packs a u16 to a known little endian buffer
inline u8*
PackL2(u8* ptr, u16 val)
{
*((u16*)ptr) = val;
return ptr + sizeof(val);
}
//Unpacks a u16 from a known little endian buffer
inline u16
UpackL2(const u8* ptr)
{
return *((u16*)ptr);
}
//Packs a u32 to a known big endian buffer
inline u8*
PackB4(u8* ptr, u32 val)
{
ptr[3] = (u8) (val & 0xff);
ptr[2] = (u8)((val & 0xff00) >> 8);
ptr[1] = (u8)((val & 0xff0000) >> 16);
ptr[0] = (u8)((val & 0xff000000) >> 24);
return ptr + sizeof(val);
}
//Unpacks a u32 from a known big endian buffer
inline u32
UpackB4(const u8* ptr)
{
return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24));
}
//Packs a u32 to a known little endian buffer
inline u8*
PackL4(u8* ptr, u32 val)
{
*((u32*)ptr) = val;
return ptr + sizeof(val);
}
//Unpacks a u32 from a known little endian buffer
inline u32
UpackL4(const u8* ptr)
{
return *((u32*)ptr);
}
//Packs a u64 to a known big endian buffer
inline u8*
PackB8(u8* ptr, u64 val)
{
ptr[7] = (u8) (val & 0xff);
ptr[6] = (u8)((val & 0xff00) >> 8);
ptr[5] = (u8)((val & 0xff0000) >> 16);
ptr[4] = (u8)((val & 0xff000000) >> 24);
ptr[3] = (u8)((val & 0xff00000000) >> 32);
ptr[2] = (u8)((val & 0xff0000000000) >> 40);
ptr[1] = (u8)((val & 0xff000000000000) >> 48);
ptr[0] = (u8)((val & 0xff00000000000000) >> 56);
return ptr + sizeof(val);
}
//Unpacks a uint64 from a known big endian buffer
inline u64
UpackB8(const u8* ptr)
{
return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) |
(((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) |
(((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) |
(((u64)ptr[0]) << 56);
}
//Packs a u64 to a known little endian buffer
inline u8*
PackL8(u8* ptr, u64 val)
{
*((u64*)ptr) = val;
return ptr + sizeof(val);
}
//Unpacks a u64 from a known little endian buffer
inline u64
UpackL8(const u8* ptr)
{
return *((u64*)ptr);
}
#define FOLDHAUS_NETWORK_ORDERING_H
#endif // FOLDHAUS_NETWORK_ORDERING_H

View File

@ -1,588 +0,0 @@
//
// File: foldhaus_serializer.h
// Author: Peter Slattery
// Creation Date: 2020-10-09
//
#ifndef FOLDHAUS_SERIALIZER_H
struct serializer
{
gs_string String;
u32 Indent;
gs_const_string* Identifiers;
u32 IdentifiersCount;
};
internal gs_const_string
Serializer_GetIdent(serializer* Serializer, u32 Index)
{
gs_const_string Result = Serializer->Identifiers[Index];
return Result;
}
// Serializing
internal void
Serializer_WriteIndent(serializer* Serializer)
{
for (u32 i = 0; i < Serializer->Indent; i++)
{
AppendPrintF(&Serializer->String, " ");
}
}
internal void
Serializer_WriteF(serializer* Serializer, char* Format, ...)
{
Serializer_WriteIndent(Serializer);
va_list Args;
va_start(Args, Format);
PrintFArgsList(&Serializer->String, Format, Args);
va_end(Args);
}
internal void
Serializer_OpenStruct(serializer* Serializer, gs_const_string StructName)
{
Serializer_WriteF(Serializer, "%S:{\n", StructName);
Serializer->Indent++;
}
internal void
Serializer_OpenStruct(serializer* Serializer, u32 StructIdentifier)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, StructIdentifier);
Serializer_WriteF(Serializer, "%S:{\n", Ident);
Serializer->Indent++;
}
internal void
Serializer_CloseStruct(serializer* Serializer)
{
Serializer->Indent--;
Serializer_WriteF(Serializer, "};\n");
}
internal void
Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, gs_const_string Value)
{
Serializer_WriteF(Serializer, "%S: %S;\n", Ident, Value);
}
internal void
Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, gs_const_string Value)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex);
Serializer_WriteValue(Serializer, Ident, Value);
}
internal void
Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, u32 Value)
{
Serializer_WriteF(Serializer, "%S: %d;\n", Ident, Value);
}
internal void
Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, u32 Value)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex);
Serializer_WriteValue(Serializer, Ident, Value);
}
internal void
Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, r32 Value)
{
Serializer_WriteF(Serializer, "%S: %f;\n", Ident, Value);
}
internal void
Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, r32 Value)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex);
Serializer_WriteValue(Serializer, Ident, Value);
}
internal void
Serializer_WriteStringValue(serializer* Serializer, gs_const_string Ident, gs_const_string Value)
{
Serializer_WriteF(Serializer, "%S: \"%S\";\n", Ident, Value);
}
internal void
Serializer_WriteStringValue(serializer* Serializer, u32 IdentIndex, gs_const_string Value)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex);
Serializer_WriteStringValue(Serializer, Ident, Value);
}
internal void
Serializer_WriteV3Value(serializer* Serializer, gs_const_string Ident, v3 Value)
{
Serializer_WriteF(Serializer, "%S: (%f, %f, %f);\n", Ident, Value.x, Value.y, Value.z);
}
internal void
Serializer_WriteV3Value(serializer* Serializer, u32 IdentIndex, v3 Value)
{
gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex);
Serializer_WriteV3Value(Serializer, Ident, Value);
}
// Parsing
struct parser_error
{
gs_string Message;
gs_const_string FileName;
u32 LineNumber;
parser_error* Next;
};
struct parser
{
gs_const_string FileName;
gs_string String;
gs_const_string* Identifiers;
u32 IdentifiersCount;
u32 Line;
char* LineStart;
char* At;
gs_memory_arena* Arena;
gs_memory_arena* Transient;
parser_error* ErrorsRoot;
parser_error* ErrorsHead;
bool Success;
};
internal void
Parser_PushErrorF(parser* Parser, char* Format, ...)
{
parser_error* Error = PushStruct(Parser->Transient, parser_error);
Error->FileName = Parser->FileName;
Error->LineNumber = Parser->Line;
Error->Message = PushString(Parser->Transient, 1024);
PrintF(&Error->Message, "Error:\n");
va_list Args;
va_start(Args, Format);
PrintFArgsList(&Error->Message, Format, Args);
va_end(Args);
AppendPrintF(&Error->Message, "\n\tFile: %S\n\tLine: %d\n",
Error->FileName, Error->LineNumber);
NullTerminate(&Error->Message);
SLLPushOrInit(Parser->ErrorsRoot, Parser->ErrorsHead, Error);
}
internal gs_const_string
Parser_GetIdent(parser Parser, u32 Index)
{
gs_const_string Result = Parser.Identifiers[Index];
return Result;
}
internal bool
Parser_AtValidPosition(parser Parser)
{
u64 Offset = Parser.At - Parser.String.Str;
bool Result = (Offset < Parser.String.Length);
return Result;
}
internal void
Parser_AdvanceChar(parser* P)
{
if (IsNewline(P->At[0]))
{
P->Line += 1;
P->LineStart = P->At + 1;
if ((P->At[0] == '\n' && P->At[1] == '\r') ||
(P->At[0] == '\r' && P->At[1] == '\n'))
{
P->At++;
P->At++;
}
else if (P->At[0] == '\n')
{
P->At++;
}
else
{
// TODO(pjs): Not sure this is actually invalid
InvalidCodePath;
}
}
else
{
P->At++;
}
}
internal void
Parser_EatWhitespace(parser* P)
{
while(Parser_AtValidPosition(*P) && IsNewlineOrWhitespace(P->At[0]))
{
Parser_AdvanceChar(P);
}
}
internal void
Parser_EatToNewLine(parser* P)
{
while(Parser_AtValidPosition(*P) && !IsNewline(P->At[0]))
{
Parser_AdvanceChar(P);
}
Parser_EatWhitespace(P);
}
internal bool
Parser_AdvanceIfTokenEquals(parser* P, gs_const_string Value)
{
bool Result = true;
char* PAt = P->At;
char* VAt = Value.Str;
while (*VAt != 0)
{
if (*PAt != *VAt)
{
Result = false;
break;
}
PAt += 1;
VAt += 1;
}
// TODO(Peter): What if the token is a subset of Value? ie. this would return true for
// T->At = hello_world and Value = hello_
// But the next token we read would fail
if (Result)
{
P->At = PAt;
Parser_EatWhitespace(P);
}
return Result;
}
internal bool
Parser_AdvanceIfLineEnd(parser* P)
{
bool Result = Parser_AdvanceIfTokenEquals(P, ConstString(";"));
return Result;
}
internal bool
Parser_ReadString(parser* P, gs_const_string String)
{
// string;
bool Result = Parser_AdvanceIfTokenEquals(P, String);
Result &= Parser_AdvanceIfLineEnd(P);
return Result;
}
internal bool
Parser_ReadString(parser* P, u32 IdentIndex)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadString(P, Ident);
}
internal bool
Parser_ReadStringValue(parser* P, gs_const_string Ident, gs_string* Output, bool ShouldNullTerminate = false)
{
Assert(Output != 0);
// ident: "value";
bool Result = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")) &&
Parser_AdvanceIfTokenEquals(P, ConstString("\"")))
{
gs_const_string FileString = {0};
FileString.Str = P->At;
while (Parser_AtValidPosition(*P) && P->At[0] != '"')
{
Parser_AdvanceChar(P);
}
FileString.Length = P->At - FileString.Str;
if (Parser_AdvanceIfTokenEquals(P, ConstString("\"")) &&
Parser_AdvanceIfLineEnd(P))
{
u32 StringLength = FileString.Length;
if (ShouldNullTerminate)
{
StringLength += 1;
}
Result = true;
*Output = PushStringF(P->Arena, StringLength, "%S", FileString);
if (ShouldNullTerminate)
{
NullTerminate(Output);
}
}
else
{
Parser_PushErrorF(P, "String doesn't have a closing quote, or line doesn't end with a semicolon");
}
}
return Result;
}
internal bool
Parser_ReadStringValue(parser* P, u32 IdentIndex, gs_string* Result, bool ShouldNullTerminate = false)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadStringValue(P, Ident, Result, ShouldNullTerminate);
}
internal gs_string
Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminate = false)
{
gs_string Result = {0};
Parser_ReadStringValue(P, Ident, &Result, ShouldNullTerminate);
return Result;
}
internal gs_string
Parser_ReadStringValue(parser* P, u32 IdentIndex, bool ShouldNullTerminate = false)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadStringValue(P, Ident, ShouldNullTerminate);
}
internal bool
Parser_ReadOpenStruct(parser* P, gs_const_string Ident)
{
// ident: {
bool Result = Parser_AdvanceIfTokenEquals(P, Ident);
Result &= Parser_AdvanceIfTokenEquals(P, ConstString(":"));
Result &= Parser_AdvanceIfTokenEquals(P, ConstString("{"));
return Result;
}
internal bool
Parser_ReadOpenStruct(parser* P, u32 IdentIndex)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadOpenStruct(P, Ident);
}
internal bool
Parser_ReadCloseStruct(parser* P)
{
// }
bool Result = Parser_AdvanceIfTokenEquals(P, ConstString("}"));
Result &= Parser_AdvanceIfLineEnd(P);
return Result;
}
internal bool
Parser_ReadNumberString(parser* P, gs_const_string* Output)
{
Assert(Output != 0);
bool Success = false;
if (IsNumericExtended(P->At[0]))
{
char* NumStart = P->At;
while(Parser_AtValidPosition(*P) && IsNumericExtended(P->At[0]))
{
Parser_AdvanceChar(P);
}
Output->Str = NumStart;
Output->Length = P->At - NumStart;
Success = true;
}
return Success;
}
internal gs_const_string
Parser_ReadNumberString(parser* P)
{
gs_const_string Result = {0};
Parser_ReadNumberString(P, &Result);
return Result;
}
internal bool
Parser_ReadU32Value(parser* P, gs_const_string Ident, u32* Result)
{
// ident: value;
bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")))
{
gs_const_string NumStr = Parser_ReadNumberString(P);
if (Parser_AdvanceIfLineEnd(P))
{
*Result = (u32)ParseInt(NumStr);
Success = true;
}
else
{
Parser_PushErrorF(P, "U32 Value doesn't end with semicolon");
}
}
return Success;
}
internal u32
Parser_ReadU32Value(parser* P, gs_const_string Ident)
{
u32 Result = 0;
Parser_ReadU32Value(P, Ident, &Result);
return Result;
}
internal u32
Parser_ReadU32Value(parser* P, u32 IdentIndex)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadU32Value(P, Ident);
}
internal bool
Parser_ReadR32(parser* P, r32* Result)
{
bool Success = false;
gs_const_string NumStr = {0};
if (Parser_ReadNumberString(P, &NumStr))
{
*Result = (r32)ParseFloat(NumStr);
Success = true;
}
return Success;
}
internal r32
Parser_ReadR32(parser* P)
{
r32 Result = 0;
Parser_ReadR32(P, &Result);
return Result;
}
internal bool
Parser_ReadR32Value(parser* P, gs_const_string Ident, r32* Result)
{
// ident: value;
bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")))
{
r32 Value = Parser_ReadR32(P);
if (Parser_AdvanceIfLineEnd(P))
{
*Result = Value;
Success = true;
}
else
{
Parser_PushErrorF(P, "R32 Value doesn't end with semicolon");
}
}
return Success;
}
internal r32
Parser_ReadR32Value(parser* P, gs_const_string Ident)
{
r32 Result = 0;
Parser_ReadR32Value(P, Ident, &Result);
return Result;
}
internal r32
Parser_ReadR32Value(parser* P, u32 IdentIndex)
{
r32 Result = 0;
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
Parser_ReadR32Value(P, Ident, &Result);
return Result;
}
internal bool
Parser_ReadV3Value(parser* P, gs_const_string Ident, v3* Result)
{
Assert(Result != 0);
bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")) &&
Parser_AdvanceIfTokenEquals(P, ConstString("(")))
{
r32 X = Parser_ReadR32(P);
if (!Parser_AdvanceIfTokenEquals(P, ConstString(",")))
{
Parser_PushErrorF(P, "V3 Value doesn't have comma separated values");
}
r32 Y = Parser_ReadR32(P);
if (!Parser_AdvanceIfTokenEquals(P, ConstString(",")))
{
Parser_PushErrorF(P, "V3 Value doesn't have comma separated values");
}
r32 Z = Parser_ReadR32(P);
if (Parser_AdvanceIfTokenEquals(P, ConstString(")")) &&
Parser_AdvanceIfLineEnd(P))
{
Result->x = X;
Result->y = Y;
Result->z = Z;
Success = true;
}
else
{
Parser_PushErrorF(P, "V3 Value doesn't end correctly");
}
}
return Success;
}
internal v3
Parser_ReadV3Value(parser* P, gs_const_string Ident)
{
v3 Result = {0};
Parser_ReadV3Value(P, Ident, &Result);
return Result;
}
internal v3
Parser_ReadV3Value(parser* P, u32 IdentIndex)
{
v3 Result = {0};
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
Parser_ReadV3Value(P, Ident, &Result);
return Result;
}
#define FOLDHAUS_SERIALIZER_H
#endif // FOLDHAUS_SERIALIZER_H

View File

@ -1,411 +0,0 @@
//
// File: sacn.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef SACN_H
#define NETWORKINTID_INVALID -1
#define DEFAULT_STREAMING_ACN_PORT 5568
#define IP_ADDRESS_BYTES 16
#define STARTCODE_DMX 0
/*
* a description of the address space being used
*/
#define PREAMBLE_SIZE_ADDR 0
#define POSTAMBLE_SIZE_ADDR 2
#define ACN_IDENTIFIER_ADDR 4
#define ROOT_FLAGS_AND_LENGTH_ADDR 16
#define ROOT_VECTOR_ADDR 18
#define CID_ADDR 22
#define FRAMING_FLAGS_AND_LENGTH_ADDR 38
#define FRAMING_VECTOR_ADDR 40
#define SOURCE_NAME_ADDR 44
#define PRIORITY_ADDR 108
#define RESERVED_ADDR 109
#define SEQ_NUM_ADDR 111
#define OPTIONS_ADDR 112
#define UNIVERSE_ADDR 113
#define DMP_FLAGS_AND_LENGTH_ADDR 115
#define DMP_VECTOR_ADDR 117
#define DMP_ADDRESS_AND_DATA_ADDR 118
#define FIRST_PROPERTY_ADDRESS_ADDR 119
#define ADDRESS_INC_ADDR 121
#define PROP_COUNT_ADDR 123
#define START_CODE_ADDR 125
#define PROP_VALUES_ADDR (START_CODE_ADDR + 1)
/*
* common sizes
*/
#define STREAM_HEADER_SIZE 126
#define STREAM_BODY_SIZE 512
#define SOURCE_NAME_SIZE 64
#define RLP_PREAMBLE_SIZE 16
#define RLP_POSTAMBLE_SIZE 0
#define ACN_IDENTIFIER_SIZE 12
/*
* data definitions
*/
#define ACN_IDENTIFIER "ASC-E1.17\0\0\0"
#define ROOT_VECTOR 4
#define FRAMING_VECTOR 2
#define DMP_VECTOR 2
#define ADDRESS_AND_DATA_FORMAT 0xa1
#define ADDRESS_INC 1
#define DMP_FIRST_PROPERTY_ADDRESS_FORCE 0
#define RESERVED_VALUE 0
//for support of the early draft
#define DRAFT_STREAM_HEADER_SIZE 90
#define DRAFT_SOURCE_NAME_SIZE 32
//for support of the early draft
#define DRAFT_ROOT_VECTOR 3
const u32 VHD_MAXFLAGBYTES = 7; //The maximum amount of bytes used to pack the flags, len, and vector
const u32 VHD_MAXLEN = 0x0fffff; //The maximum packet length is 20 bytes long
const u32 VHD_MAXMINLENGTH = 4095; //The highest length that will fit in the "smallest" length pack
//Defines for the VHD flags
const u8 VHD_L_FLAG = 0x80;
const u8 VHD_V_FLAG = 0x40;
const u8 VHD_H_FLAG = 0x20;
const u8 VHD_D_FLAG = 0x10;
#define CID_Bytes 16
struct cid
{
u8 Bytes[CID_Bytes];
};
struct streaming_acn
{
platform_socket_handle SendSocket;
cid CID;
s32 SequenceIterator;
};
///////////////////////////////////////////////
//
// SACN Data Header Functions
//
///////////////////////////////////////////////
internal void
SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft)
{
DEBUG_TRACK_FUNCTION;
PackB1(Buffer + SEQ_NUM_ADDR, Sequence);
}
internal void
VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData)
{
u8* Cursor = Buffer;
u8 NewByte = UpackB1(Cursor) & 0x8f;
if (!InheritVec) { NewByte |= VHD_V_FLAG; }
if (!InheritHead) { NewByte |= VHD_H_FLAG; }
if (!InheritData) { NewByte |= VHD_D_FLAG; }
PackB1(Cursor, NewByte);
}
internal u8*
VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
{
u8* Cursor = Buffer;
u32 AdjustedLength = Length;
if (IncludeLength)
{
if (Length + 1 > VHD_MAXMINLENGTH)
{
AdjustedLength += 2;
}
else
{
AdjustedLength += 1;
}
}
// Mask out the length bits to keep flags intact
u8 NewByte = UpackB1(Cursor) & 0x70;
if (AdjustedLength > VHD_MAXMINLENGTH)
{
NewByte |= VHD_L_FLAG;
}
u8 PackBuffer[4];
PackB4(PackBuffer, AdjustedLength);
if (AdjustedLength <= VHD_MAXMINLENGTH)
{
NewByte |= (PackBuffer[2] & 0x0f);
Cursor = PackB1(Cursor, NewByte);
Cursor = PackB1(Cursor, PackBuffer[3]);
}
else
{
NewByte |= (PackBuffer[1] & 0x0f);
Cursor = PackB1(Cursor, PackBuffer[2]);
Cursor = PackB1(Cursor, PackBuffer[3]);
}
return Cursor;
}
internal cid
gs_stringToCID_ (const char* gs_string)
{
cid Result = {};
const char* Src = gs_string;
u8* Dest = &Result.Bytes[0];
b32 FirstNibble = true;
while(*Src && (Dest - &Result.Bytes[0] < CID_Bytes))
{
u8 Offset = 0;
if ((*Src >= 0x30) && (*Src <= 0x39)){ Offset = 0x30; }
else if ((*Src >= 0x41) && (*Src <= 0x46)) { Offset = 0x37; }
else if ((*Src >= 0x61) && (*Src <= 0x66)) { Offset = 0x66; }
if (Offset != 0)
{
if (FirstNibble)
{
*Dest = (u8)(*Src - Offset);
*Dest <<= 4;
FirstNibble = false;
}
else
{
*Dest |= (*Src - Offset);
Dest++;
FirstNibble = true;
}
}
Src++;
}
return Result;
}
internal void
InitStreamHeader (u8* Buffer, s32 BufferSize,
u16 SlotCount,
u8 StartCode,
u16 Universe,
u8 Priority,
u16 Reserved,
u8 Options,
const char* SourceName,
cid CID
)
{
// TODO(pjs): Replace packing with gs_memory_cursor
u8* Cursor = Buffer;
// Preamble Size
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
CopyMemoryTo(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE);
Cursor += ACN_IDENTIFIER_SIZE;
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount,
false);
// root vector
Cursor = PackB4(Cursor, ROOT_VECTOR);
// CID Pack
for (s32 i = 0; i < CID_Bytes; i++)
{
*Cursor++ = CID.Bytes[i];
}
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount,
false);
// framing vector
Cursor = PackB4(Cursor, FRAMING_VECTOR);
// framing source name
// :Check
CopyMemoryTo(SourceName, (char*)Cursor, SOURCE_NAME_SIZE);
Cursor[SOURCE_NAME_SIZE - 1] = '\0';
Cursor += SOURCE_NAME_SIZE;
// priority
Cursor = PackB1(Cursor, Priority);
// reserved
Cursor = PackB2(Cursor, Reserved);
// Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data
Cursor = PackB1(Cursor, 0);
// Options
Cursor = PackB1(Cursor, Options);
// Universe
Cursor = PackB2(Cursor, Universe);
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount,
false);
// DMP Vector
Cursor = PackB1(Cursor, DMP_VECTOR);
// DMP Address and data type
Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT);
// DMP first property address
Cursor = PackB1(Cursor, 0);
// DMP Address Increment
Cursor = PackB1(Cursor, ADDRESS_INC);
// Property Value Count -- Includes one byte for start code
Cursor = PackB2(Cursor, SlotCount + 1);
Cursor = PackB1(Cursor, StartCode);
Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
}
//
// New SACN
//
internal streaming_acn
SACN_Initialize (context Context)
{
streaming_acn SACN = {};
s32 Multicast_TimeToLive = 20;
SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive);
SACN.CID = gs_stringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
return SACN;
}
internal void
SACN_Cleanup(streaming_acn* SACN, context Context)
{
}
internal void
SACN_UpdateSequence (streaming_acn* SACN)
{
// Never use 0 after the first one
if (++SACN->SequenceIterator == 0)
{
++SACN->SequenceIterator;
}
}
internal void
SACN_PrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN)
{
Assert(SizeReservedForHeader == STREAM_HEADER_SIZE);
Assert(Buffer && BufferSize > 0);
s32 Priority = 0;
InitStreamHeader(Buffer, BufferSize, STREAM_BODY_SIZE, STARTCODE_DMX, Universe, Priority, 0, 0, "Lumenarium", SACN.CID);
SetStreamHeaderSequence_(Buffer, SACN.SequenceIterator, false);
}
internal u32
SACN_GetUniverseSendAddress(s32 Universe)
{
u8 MulticastAddressBuffer[4] = {};
MulticastAddressBuffer[0] = 239;
MulticastAddressBuffer[1] = 255;
MulticastAddressBuffer[2] = (u8)((Universe & 0xff00) >> 8); // high bit
MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff)); // low bit
u32 V4Address = (u32)UpackB4(MulticastAddressBuffer);
return V4Address;
}
internal u64
SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, u64 LedsPlaced, led_buffer LedBuffer)
{
u8* DestChannel = BufferStart;
u64 FirstLed = LedsPlaced;
u64 LedsToAdd = Min(Strip.LedCount - LedsPlaced, STREAM_BODY_SIZE / 3);
u64 OnePastLastLed = FirstLed + LedsToAdd;
for (u32 i = FirstLed; i < OnePastLastLed; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
DestChannel[0] = Color.R;
DestChannel[1] = Color.G;
DestChannel[2] = Color.B;
DestChannel += 3;
}
return LedsToAdd;
}
internal void
SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
{
SACN_UpdateSequence(SACN);
// TODO(pjs): 512 is a magic number - make it a constant?
s32 BufferHeaderSize = STREAM_HEADER_SIZE;
s32 BufferBodySize = STREAM_BODY_SIZE;
s32 BufferSize = BufferHeaderSize + BufferBodySize;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
// NOTE(PS): This isn't actually invalid, we just haven't needed to implement
// something more complex than only allowing strips to start at the first
// channel of a universe
Assert(StripAt.SACNAddr.StartChannel == 1);
u32 UniverseAt = StripAt.SACNAddr.StartUniverse;
u64 LedsPlaced = 0;
while (LedsPlaced < StripAt.LedCount)
{
u32 V4SendAddress = SACN_GetUniverseSendAddress(UniverseAt);
u32 SendPort = DEFAULT_STREAMING_ACN_PORT;
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize);
AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort);
SACN_PrepareBufferHeader(UniverseAt, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN);
LedsPlaced += SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, LedsPlaced, *LedBuffer);
UniverseAt += 1;
}
}
}
}
#define SACN_H
#endif // SACN_H

View File

@ -1,173 +0,0 @@
//
// File: foldhaus_uart.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-10
//
#ifndef FOLDHAUS_UART_CPP
internal void
UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer)
{
// NOTE(pjs): This is just here because the information is duplicated and I want to be sure
// to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = MemoryCursorPushStruct(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = MemoryCursorPushArray(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask
#if 1
OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B;
#else
OutputPixel[0] = 255;
OutputPixel[1] = 255;
OutputPixel[2] = 255;
#endif
if (Channel->ElementsCount == 4)
{
// TODO(pjs): Calculate white from the RGB components?
// Generally we just need a good way to handle the white channel,
// both in the renderer and in output
//OutputPixel[Channel->WhiteIndex] = Color.W;
}
}
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
{
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient)
{
uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3;
ChannelSettings.ColorPackingOrder = 36;
// NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will
// be bigger than this, but their size is based on the number of pixels in each channel
u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
struct strips_to_data_buffer
{
gs_const_string ComPort;
u32* StripIndices;
u32 StripIndicesCount;
u32 StripIndicesCountMax;
u64 LedCount;
u8** ChannelsStart;
strips_to_data_buffer* Next;
};
u32 BuffersNeededCount = 0;
strips_to_data_buffer* BuffersNeededHead = 0;
strips_to_data_buffer* BuffersNeededTail = 0;
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
// If there is a buffer for this com port already created
// we use that
strips_to_data_buffer* BufferSelected = 0;
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
if (StringsEqual(At->ComPort, StripAt.UARTAddr.ComPort.ConstString))
{
BufferSelected = At;
break;
}
}
// if no existing buffer for this com port
// create a new one
if (!BufferSelected)
{
BufferSelected = PushStruct(Transient, strips_to_data_buffer);
*BufferSelected = {};
BufferSelected->ComPort = StripAt.UARTAddr.ComPort.ConstString;
// we don't know at this point how many indices per
// com port so just make enough room to fit all the strips
// if necessary
BufferSelected->StripIndicesCountMax = Assembly.StripCount;
BufferSelected->StripIndices = PushArray(Transient, u32, BufferSelected->StripIndicesCountMax);
BufferSelected->LedCount = 0;
BufferSelected->Next = 0;
SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected);
BuffersNeededCount += 1;
}
Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax);
u32 Index = BufferSelected->StripIndicesCount++;
BufferSelected->StripIndices[Index] = StripIdx;
BufferSelected->LedCount += StripAt.LedCount;
}
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel
At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount);
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
gs_const_string ComPort = At->ComPort;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
gs_memory_cursor WriteCursor = MemoryCursorCreate(Buffer->Memory, Buffer->MemorySize);
for (u32 i = 0; i < At->StripIndicesCount; i++)
{
u32 StripIdx = At->StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIdx];
ChannelSettings.PixelsCount = StripAt.LedCount;
UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer);
}
UART_DrawAll_Create(&WriteCursor);
}
}
}
#define FOLDHAUS_UART_CPP
#endif // FOLDHAUS_UART_CPP

View File

@ -1,88 +0,0 @@
//
// File: foldhaus_uart.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef FOLDHAUS_UART_H
enum uart_record_type
{
UART_SET_CHANNEL_WS2812 = 1,
UART_DRAW_ALL = 2,
};
// NOTE(pjs): these are data packet structures and need to have 1 byte packing
#pragma pack(push, 1)
struct uart_header
{
s8 MagicNumber[4];
u8 Channel;
u8 RecordType;
};
struct uart_channel
{
u8 ElementsCount;
u8 ColorPackingOrder;
u16 PixelsCount;
};
struct uart_footer
{
u32 CRC;
};
#pragma pack(pop)
#define UART_MESSAGE_MIN_SIZE sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer)
global u32 UART_CRCTable[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
internal void
UART_FillHeader(uart_header* Header, u8 Channel, u8 RecordType)
{
Header->MagicNumber[0] = 'U';
Header->MagicNumber[1] = 'P';
Header->MagicNumber[2] = 'X';
Header->MagicNumber[3] = 'L';
Header->Channel = Channel;
Header->RecordType = RecordType;
}
internal u32
UART_CalculateCRC(u8* BufferStart, u8* BufferEnd)
{
// Calculate the CRC
u32 CRC = 0xFFFFFFFF;
u32 BytesCount = (u8*)BufferEnd - BufferStart;
for (u32 i = 0; i < BytesCount; i++)
{
u8 At = BufferStart[i];
#if 0
// Cameron's Version
CRC = UART_CRCTable[(CRC ^ At) & 0x0F] ^ (CRC >> 4);
CRC = UART_CRCTable[(CRC ^ (At >> 4)) & 0x0F] ^ (CRC >> 4);
#else
// https://github.com/simap/pixelblaze_output_expander/blob/master/firmware/Core/Src/uart.c
u32 TableIndex = (CRC ^ At) & 0xFF;
CRC = (UART_CRCTable[TableIndex] ^ (CRC >> 8)) & 0xFFFFFFFF;
#endif
}
CRC = CRC ^ 0xFFFFFFFF;
return CRC;
}
internal void
UART_FillFooter(uart_footer* Footer, u8* BufferStart)
{
Footer->CRC = UART_CalculateCRC(BufferStart, (u8*)Footer);
}
#define FOLDHAUS_UART_H
#endif // FOLDHAUS_UART_H

View File

@ -1,56 +0,0 @@
//
// File: userspace.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-30
//
#ifndef USERSPACE_CPP
internal void
US_LoadPatterns(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->LoadPatterns)
{
Desc->LoadPatterns(State);
}
}
internal void
US_CustomInit(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->CustomInit)
{
Desc->UserData = Desc->CustomInit(State, Context);
}
}
internal void
US_CustomUpdate(user_space_desc* Desc, app_state* State, context* Context)
{
if (Desc->CustomUpdate)
{
Desc->CustomUpdate(Desc->UserData, State, Context);
}
}
internal void
US_CustomDebugUI(user_space_desc* Desc, panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer,
app_state* State, context Context)
{
if (Desc->CustomDebugUI)
{
Desc->CustomDebugUI(Desc->UserData, Panel, PanelBounds, RenderBuffer, State, Context);
}
}
internal void
US_CustomCleanup(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->CustomCleanup)
{
Desc->CustomCleanup(Desc->UserData, State, Context);
}
}
#define USERSPACE_CPP
#endif // USERSPACE_CPP

View File

@ -1,35 +0,0 @@
//
// File: userspace.h
// Author: Peter Slattery
// Creation Date: 2021-01-30
//
#ifndef USERSPACE_H
#define US_LOAD_PATTERNS(name) void name(app_state* State)
typedef US_LOAD_PATTERNS(us_load_patterns_proc);
#define US_CUSTOM_INIT(name) gs_data name (app_state* State, context Context)
typedef US_CUSTOM_INIT(us_custom_init_proc);
#define US_CUSTOM_UPDATE(name) void name(gs_data UserData, app_state* State, context* Context)
typedef US_CUSTOM_UPDATE(us_custom_update_proc);
#define US_CUSTOM_DEBUG_UI(name) void name(gs_data UserData, panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
typedef US_CUSTOM_DEBUG_UI(us_custom_debug_ui);
#define US_CUSTOM_CLEANUP(name) void name(gs_data UserData, app_state* State, context Context)
typedef US_CUSTOM_CLEANUP(us_custom_cleanup_proc);
typedef struct user_space_desc
{
us_load_patterns_proc* LoadPatterns;
us_custom_init_proc* CustomInit;
us_custom_update_proc* CustomUpdate;
us_custom_debug_ui* CustomDebugUI;
us_custom_cleanup_proc* CustomCleanup;
gs_data UserData;
} user_space_desc;
#define USERSPACE_H
#endif // USERSPACE_H

View File

@ -1,200 +0,0 @@
//
// File: foldhaus_app.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_APP_CPP
#include "foldhaus_platform.h"
#include "foldhaus_app.h"
RELOAD_STATIC_DATA(ReloadStaticData)
{
GlobalDebugServices = DebugServices;
GlobalLogBuffer = LogBuffer;
if (AppReady)
{
app_state* State = (app_state*)Context.MemoryBase;
State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
gs_data UserData = State->UserSpaceDesc.UserData;
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
if (UserData.Memory && !State->UserSpaceDesc.UserData.Memory)
{
State->UserSpaceDesc.UserData = UserData;
}
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
}
}
INITIALIZE_APPLICATION(InitializeApplication)
{
Context->MemorySize = sizeof(app_state);
Context->MemoryBase = Alloc(Context->ThreadContext.Allocator, Context->MemorySize, "Memory Base");
app_state* State = (app_state*)Context->MemoryBase;
*State = {};
State->Permanent = MemoryArenaCreate(MB(4), Bytes(8), Context->ThreadContext.Allocator,0, 0, "Permanent");
State->Transient = Context->ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
State->CommandQueue = CommandQueue_Create(&State->Permanent, 32);
animation_system_desc AnimSysDesc = {};
AnimSysDesc.Storage = &State->Permanent;
AnimSysDesc.AnimArrayCount = 32;
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
if (!Context->Headless)
{
interface_config IConfig = {0};
IConfig.FontSize = 14;
IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f };
IConfig.ButtonColor_Inactive = BlackV4;
IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f };
IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f };
IConfig.TextColor = WhiteV4;
IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f };
IConfig.Margin = v2{5, 5};
State->Interface = ui_InterfaceCreate(*Context, IConfig, &State->Permanent);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
}
State->SACN = SACN_Initialize(*Context);
State->LedSystem = LedSystem_Create(Context->ThreadContext.Allocator, 128);
State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent);
State->AssemblyDebugState.Brightness = 255;
State->AssemblyDebugState.Override = ADS_Override_None;
State->Modes = OperationModeSystemInit(&State->Permanent, Context->ThreadContext);
ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, true);
US_CustomInit(&State->UserSpaceDesc, State, *Context);
if (!Context->Headless)
{
// NOTE(pjs): This just sets up the default panel layout
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, *Context);
SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, *Context);
panel* AnimPanel = RootPanel->Bottom;
Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, *Context);
panel* TopPanel = RootPanel->Top;
SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* LeftPanel = TopPanel->Left;
SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* Profiler = LeftPanel->Right;
Panel_SetType(Profiler, &State->PanelSystem, PanelType_MessageLog, State, *Context);
panel* Hierarchy = LeftPanel->Left;
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, *Context);
}
State->RunEditor = !Context->Headless;
}
internal void
BuildAssemblyData (app_state* State, context Context, addressed_data_buffer_list* OutputData)
{
#define SEND_DATA
#ifdef SEND_DATA
// NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information
assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
#endif
}
UPDATE_AND_RENDER(UpdateAndRender)
{
DEBUG_TRACK_FUNCTION;
app_state* State = (app_state*)Context->MemoryBase;
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient,
// and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't
// zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically
// incorrect to clear the arena, and then access the memory later.
MemoryArenaClear(State->Transient);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
if (State->RunEditor)
{
Editor_Update(State, Context, InputQueue);
}
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
if (AnimationSystem_NeedsRender(State->AnimationSystem))
{
Assert(State->UserSpaceDesc.UserData.Memory != 0);
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
State->Assemblies,
&State->LedSystem,
State->Patterns,
State->Transient,
*Context,
State->UserSpaceDesc.UserData.Memory);
}
Assert(State->UserSpaceDesc.UserData.Memory != 0);
US_CustomUpdate(&State->UserSpaceDesc, State, Context);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
AssemblyDebug_OverrideOutput(State->AssemblyDebugState,
State->Assemblies,
State->LedSystem);
if (State->RunEditor)
{
Editor_Render(State, Context, RenderBuffer);
}
ResetWorkQueue(Context->GeneralWorkQueue);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
BuildAssemblyData(State, *Context, OutputData);
// NOTE(PS): We introduced this in order to test some things on the
// blumen lumen circuit boards, to see if they were getting out
// of sync
if (State->SendEmptyPackets) {
for (addressed_data_buffer* At = OutputData->Root;
At != 0;
At = At->Next)
{
ZeroMemoryBlock(At->Memory, At->MemorySize);
}
}
}
CLEANUP_APPLICATION(CleanupApplication)
{
app_state* State = (app_state*)Context.MemoryBase;
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
assembly Assembly = State->Assemblies.Values[i];
led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex];
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
}
BuildAssemblyData(State, Context, OutputData);
US_CustomCleanup(&State->UserSpaceDesc, State, Context);
SACN_Cleanup(&State->SACN, Context);
}
#define FOLDHAUS_APP_CPP
#endif // FOLDHAUS_APP_CPP

View File

@ -1,128 +0,0 @@
//
// File: foldhaus_app.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_APP_H
#include "../meta/gs_meta_include.h"
#include "../meta/gs_meta_lexer.h"
#include "engine/foldhaus_serializer.h"
#include "../gs_libs/gs_font.h"
#include "editor/interface.h"
#include "engine/foldhaus_network_ordering.h"
#include "engine/assembly/foldhaus_assembly.h"
#include "ss_blumen_lumen/gfx_math.h"
#include "engine/assembly/foldhaus_assembly_parser.cpp"
#include "engine/assembly/foldhaus_assembly_debug.h"
#include "engine/sacn/foldhaus_sacn.h"
#include "engine/uart/foldhaus_uart.h"
#include "engine/uart/foldhaus_uart.cpp"
typedef struct app_state app_state;
typedef struct panel panel;
#include "editor/foldhaus_command_dispatch.h"
#include "editor/foldhaus_operation_mode.h"
// TODO(Peter): something we can do later is to remove all reliance on app_state and context
// from foldhaus_pane.h. It should just emit lists of things that the app can iterate over and
// perform operations on, like panel_draw_requests = { bounds, panel* } etc.
#include "editor/foldhaus_panel.h"
#include "engine/animation/foldhaus_animation.h"
#include "engine/animation/foldhaus_animation_serializer.cpp"
#include "engine/animation/foldhaus_animation_renderer.cpp"
#include "engine/user_space.h"
#include "ss_blumen_lumen/phrase_hue_map.h"
#include "ss_blumen_lumen/blumen_lumen.h"
struct app_state
{
gs_memory_arena Permanent;
gs_memory_arena* Transient;
// Engine
//
network_protocol NetworkProtocol;
streaming_acn SACN;
led_system LedSystem;
assembly_array Assemblies;
assembly_debug_state AssemblyDebugState;
animation_system AnimationSystem;
animation_pattern_array Patterns;
// Interface
//
rect2 WindowBounds;
operation_mode_system Modes;
input_command_queue CommandQueue;
ui_interface Interface;
panel_system PanelSystem;
panel* HotPanel;
user_space_desc UserSpaceDesc;
bool ShowingUserSpaceDebug;
bool RunEditor;
bool SendEmptyPackets;
};
internal void OpenColorPicker(app_state* State, v4* Address);
#include "engine/assembly/foldhaus_assembly.cpp"
internal assembly*
LoadAssembly(gs_const_string Path, app_state* State, context Context)
{
return LoadAssembly(&State->Assemblies,
&State->LedSystem,
State->Transient,
Context,
Path,
GlobalLogBuffer);
}
#include "engine/user_space.cpp"
#include "ss_blumen_lumen/sdf.h"
#include "patterns/blumen_patterns.h"
#include "ss_blumen_lumen/blumen_lumen.cpp"
internal void
EndCurrentOperationMode(app_state* State)
{
DeactivateCurrentOperationMode(&State->Modes);
}
#include "editor/panels/foldhaus_panel_types.h"
#include "editor/panels/foldhaus_panel_file_view.h"
#include "editor/panels/foldhaus_panel_sculpture_view.h"
#include "editor/panels/foldhaus_panel_profiler.h"
#include "editor/panels/foldhaus_panel_dmx_view.h"
#include "editor/panels/foldhaus_panel_animation_timeline.h"
#include "editor/panels/foldhaus_panel_hierarchy.h"
#include "editor/panels/foldhaus_panel_assembly_debug.h"
#include "editor/panels/foldhaus_panel_message_log.h"
#include "editor/panels/foldhaus_panel_types.cpp"
#include "editor/foldhaus_interface.cpp"
#include "editor/foldhaus_editor_draw.h"
#include "editor/foldhaus_editor.cpp"
#define FOLDHAUS_APP_H
#endif // FOLDHAUS_APP_H

View File

@ -1,474 +0,0 @@
//
// File: foldhaus_debug.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
// DESCRIPTION:
// This file contains profiling capabilities for both the engine and app
//
#ifndef FOLDHAUS_DEBUG_H
#define SCOPE_NAME_LENGTH 256
struct scope_record
{
u32 NameHash;
s64 StartCycles;
s64 EndCycles;
s32 CallDepth;
};
struct collated_scope_record
{
u32 NameHash;
s64 TotalCycles;
s32 CallCount;
r32 PercentFrameTime;
r32 TotalSeconds;
r32 AverageSecondsPerCall;
};
#define SCOPE_NAME_BUFFER_LENGTH 128
struct scope_name
{
u32 Hash;
gs_string Name;
char Buffer[SCOPE_NAME_BUFFER_LENGTH];
};
struct debug_scope_record_list
{
s32 ThreadId;
s32 Max;
s32 Count;
scope_record* Calls;
s32 CurrentScopeCallDepth;
};
#define DEBUG_FRAME_GROW_SIZE 8102
struct debug_frame
{
s64 FrameStartCycles;
s64 FrameEndCycles;
s32 ScopeNamesMax;
s32 ScopeNamesCount;
scope_name* ScopeNamesHash;
s32 ThreadCount;
debug_scope_record_list* ThreadCalls;
s32 CollatedScopesMax;
collated_scope_record* CollatedScopes;
};
enum debug_ui_view
{
DebugUI_Profiler,
DebugUI_ScopeList,
DebugUI_MemoryView,
DebugUI_Count,
};
struct debug_interface
{
s32 FrameView;
};
typedef s32 debug_get_thread_id();
typedef s64 debug_timing_proc();
typedef u8* debug_alloc(s32 ElementSize, s32 ElementCount);
typedef u8* debug_realloc(u8* Memory, s32 OldSize, s32 NewSize);
#define HISTOGRAM_DEPTH 10
struct debug_histogram_entry
{
char ScopeName_[SCOPE_NAME_LENGTH];
gs_string ScopeName;
u32 PerFrame_Cycles[HISTOGRAM_DEPTH];
u32 PerFrame_CallCount[HISTOGRAM_DEPTH];
s32 CurrentFrame;
// NOTE(Peter): Cached Values, recalculated ever frame
u32 Average_Cycles;
u32 Average_CallCount;
u32 Total_Cycles;
u32 Total_CallCount;
};
#if DEBUG
# define DEBUG_FRAME_COUNT 128
#else
# define DEBUG_FRAME_COUNT 0
#endif
struct debug_services
{
s64 PerformanceCountFrequency;
b32 RecordFrames;
s32 CurrentDebugFrame;
debug_frame* Frames;
debug_interface Interface;
gs_thread_context Ctx;
gs_memory_arena A;
debug_get_thread_id* GetThreadId;
debug_timing_proc* GetWallClock;
};
internal void
InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32 ScopeCallsMax, debug_services* Services)
{
Frame->ScopeNamesMax = NameHashMax;
Frame->ScopeNamesHash = PushArray(&Services->A, scope_name, NameHashMax);
// NOTE(Peter): We use the same size as scope names because we're only storing a single instance
// per scope. If ScopeNamesMax can't hold all the scopes, this will never get filled and
// we should assert and recompile with a resized NameHashMax
Frame->CollatedScopesMax = NameHashMax;
Frame->CollatedScopes = PushArray(&Services->A, collated_scope_record, NameHashMax);
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
{
scope_name* Entry = Frame->ScopeNamesHash + i;
Entry->Name = MakeString(Entry->Buffer, 0, SCOPE_NAME_BUFFER_LENGTH);
}
Frame->ThreadCount = ThreadCount;
Frame->ThreadCalls = PushArray(&Services->A, debug_scope_record_list, ThreadCount);
for (s32 i = 0; i < ThreadCount; i++)
{
Frame->ThreadCalls[i].Max = ScopeCallsMax;
Frame->ThreadCalls[i].Count = 0;
Frame->ThreadCalls[i].Calls = PushArray(&Services->A, scope_record, ScopeCallsMax);
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
Frame->ThreadCalls[i].ThreadId = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
Frame->CollatedScopes[c].NameHash = 0;
}
}
internal void
StartDebugFrame(debug_frame* Frame, debug_services* Services)
{
Frame->FrameStartCycles = Services->GetWallClock();
for (s32 i = 0; i < Frame->ThreadCount; i++)
{
Frame->ThreadCalls[i].Count = 0;
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
s32 Hash = Frame->CollatedScopes[c].NameHash;
Frame->CollatedScopes[c] = {};
Frame->CollatedScopes[c].NameHash = Hash;
}
}
internal void
InitDebugServices_OffMode (debug_services* Services,
s64 PerformanceCountFrequency,
debug_timing_proc* GetWallClock,
debug_get_thread_id* GetThreadId,
gs_thread_context Ctx,
s32 ThreadCount)
{
*Services = {0};
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
Services->RecordFrames = false;
Services->Frames = 0;
Services->CurrentDebugFrame = 0;
Services->PerformanceCountFrequency = PerformanceCountFrequency;
}
internal void
InitDebugServices_DebugMode (debug_services* Services,
s64 PerformanceCountFrequency,
debug_timing_proc* GetWallClock,
debug_get_thread_id* GetThreadId,
gs_thread_context Ctx,
s32 ThreadCount)
{
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
Services->RecordFrames = true;
Services->CurrentDebugFrame = 0;
Services->A = MemoryArenaCreate(MB(64), Bytes(8), Ctx.Allocator, 0, 0, "Debug Services Allocator");
s32 NameHashMax = 4096;
s32 ScopeCallsMax = 4096;
Services->Frames = PushArray(&Services->A, debug_frame, DEBUG_FRAME_COUNT);
for (s32 i = 0; i < DEBUG_FRAME_COUNT; i++)
{
InitializeDebugFrame(&Services->Frames[i], NameHashMax, ThreadCount, ScopeCallsMax, Services);
}
Services->PerformanceCountFrequency = PerformanceCountFrequency;
}
internal debug_frame*
GetCurrentDebugFrame (debug_services* Services)
{
debug_frame* Result = Services->Frames + Services->CurrentDebugFrame;
return Result;
}
internal debug_frame*
GetLastDebugFrame(debug_services* Services)
{
if (!Services->Frames) return 0;
s32 Index = (Services->CurrentDebugFrame - 1);
if (Index < 0) { Index += DEBUG_FRAME_COUNT; }
debug_frame* Result = Services->Frames + Index;
return Result;
}
internal s32
GetIndexForNameHash(debug_frame* Frame, u32 NameHash)
{
s32 Result = -1;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if (Frame->ScopeNamesHash[Index].Hash == NameHash)
{
Result = Index;
break;
}
}
// NOTE(Peter): Its not technically wrong to return a -1 here, just means we didn't find it.
// At the time of writing however, this function is only being called in contexts where we
// know there should be an entry in the Name table, so a -1 actually indicates a problem.
Assert(Result >= 0);
return Result;
}
internal debug_scope_record_list*
GetScopeListForThreadInFrame(debug_services* Services, debug_frame* Frame)
{
debug_scope_record_list* List = 0;
s32 CurrentThreadId = Services->GetThreadId();
for (s32 Offset = 0; Offset < Frame->ThreadCount; Offset++)
{
s32 Index = (CurrentThreadId + Offset) % Frame->ThreadCount;
if (Frame->ThreadCalls[Index].ThreadId == CurrentThreadId)
{
List = Frame->ThreadCalls + Index;
break;
}
else if (Frame->ThreadCalls[Index].ThreadId == 0)
{
Frame->ThreadCalls[Index].ThreadId = CurrentThreadId;
List = Frame->ThreadCalls + Index;
break;
}
}
Assert(List);
return List;
}
internal void
CollateThreadScopeCalls (debug_scope_record_list* ThreadRecords, debug_frame* Frame)
{
for (s32 i = 0; i < ThreadRecords->Count; i++)
{
scope_record Record = ThreadRecords->Calls[i];
s32 Index = GetIndexForNameHash (Frame, Record.NameHash);
collated_scope_record* CollatedRecord = Frame->CollatedScopes + Index;
if (CollatedRecord->NameHash != Record.NameHash)
{
CollatedRecord->NameHash = Record.NameHash;
CollatedRecord->TotalCycles = 0;
CollatedRecord->CallCount = 0;
}
CollatedRecord->TotalCycles += Record.EndCycles - Record.StartCycles;
CollatedRecord->CallCount += 1;
}
}
internal void
EndDebugFrame (debug_services* Services)
{
debug_frame* ClosingFrame = GetCurrentDebugFrame(Services);
ClosingFrame->FrameEndCycles = Services->GetWallClock();
s64 FrameTotalCycles = ClosingFrame->FrameEndCycles - ClosingFrame->FrameStartCycles;
for (s32 t = 0; t < ClosingFrame->ThreadCount; t++)
{
CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame);
}
s32 ScopeNamesCount = 0;
for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++)
{
if (ClosingFrame->ScopeNamesHash[n].Hash != 0)
{
collated_scope_record* CollatedRecord = ClosingFrame->CollatedScopes + n;
CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency;
CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles;
CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount;
ScopeNamesCount += 1;
}
}
ClosingFrame->ScopeNamesCount = ScopeNamesCount;
s32 FramesCount = DEBUG_FRAME_COUNT;
if (FramesCount > 0)
{
Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % FramesCount;
}
StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services);
}
internal u32
HashScopeName (char* ScopeName)
{
// djb2 hash
u32 Hash = 5381;
char* C = ScopeName;
while(*C)
{
Hash = ((Hash << 5) + Hash) + *C;
C++;
}
return Hash;
}
internal scope_name*
GetOrAddNameHashEntry(debug_frame* Frame, u32 NameHash)
{
scope_name* Result = 0;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if ((Frame->ScopeNamesHash[Index].Hash == 0) || (Frame->ScopeNamesHash[Index].Hash == NameHash))
{
Result = Frame->ScopeNamesHash + Index;
break;
}
}
return Result;
}
internal u32
BeginTrackingScopeAndGetNameHash (debug_services* Services, char* ScopeName)
{
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
ThreadList->CurrentScopeCallDepth++;
u32 NameHash = HashScopeName(ScopeName);
scope_name* Entry = GetOrAddNameHashEntry(CurrentFrame, NameHash);
if (Entry->Hash == 0) // If its new
{
Entry->Hash = NameHash;
// TODO(Peter): need to initialize all entry name gs_strings to point at the buffer
// This will break eventually. when it does, do this ^^^^ when on startup
PrintF(&Entry->Name, "%s", ScopeName);
}
return NameHash;
}
internal void
PushScopeTimeOnFrame (debug_services* Services, s32 NameHash, u64 StartCycles, u64 EndCycles)
{
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
if (ThreadList->Count >= ThreadList->Max)
{
s32 NewMax = (ThreadList->Max + DEBUG_FRAME_GROW_SIZE);
FreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
ThreadList->Calls = AllocArray(Services->Ctx.Allocator, scope_record, NewMax, "Debug Frame");
ThreadList->Max = NewMax;
}
Assert(ThreadList->Count < ThreadList->Max);
s32 EntryIndex = ThreadList->Count++;
scope_record* Record = ThreadList->Calls + EntryIndex;
Record->NameHash = NameHash;
Record->StartCycles = StartCycles;
Record->EndCycles = EndCycles;
Record->CallDepth = --ThreadList->CurrentScopeCallDepth;
}
internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFrequency)
{
r32 Result = ((r32)(End - Start) / (r32)PerformanceCountFrequency);
return Result;
}
#if DEBUG
#define DEBUG_TRACK_FUNCTION scope_tracker ScopeTracker ((char*)__func__, GlobalDebugServices)
#define DEBUG_TRACK_SCOPE(name) scope_tracker ScopeTracker_##name (#name, GlobalDebugServices)
#else
#define DEBUG_TRACK_FUNCTION
#define DEBUG_TRACK_SCOPE(name)
#endif
struct scope_tracker
{
s64 ScopeStart;
u32 ScopeNameHash;
debug_services* DebugServices;
scope_tracker(char* ScopeName, debug_services* DebugServices)
{
if (DebugServices->RecordFrames)
{
this->ScopeNameHash = BeginTrackingScopeAndGetNameHash(DebugServices, ScopeName);
this->ScopeStart = DebugServices->GetWallClock();
this->DebugServices = DebugServices;
}
else
{
this->DebugServices = 0;
}
}
~scope_tracker()
{
if (this->DebugServices) // NOTE(Peter): If DebugServices == 0, then we werent' recording this frame
{
s64 ScopeEnd = this->DebugServices->GetWallClock();
PushScopeTimeOnFrame(this->DebugServices, this->ScopeNameHash, this->ScopeStart, ScopeEnd);
}
}
};
#define FOLDHAUS_DEBUG_H
#endif // FOLDHAUS_DEBUG_H

View File

@ -1,46 +0,0 @@
//
// File: foldhaus_log.h
// Author: Peter Slattery
// Creation Date: 2020-02-05
//
#ifndef FOLDHAUS_LOG_H
enum log_entry_type
{
LogEntry_Message,
LogEntry_Error,
};
struct log_entry
{
gs_string Message;
log_entry_type Type;
};
#define LOG_ENTRIES_MAX 256
struct event_log
{
log_entry Entries[LOG_ENTRIES_MAX];
// Circular buffer head position
u32 NextEntry;
};
#define LogMessage(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Message)
#define LogError(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Error)
internal void
PushLogEntry(event_log* Log, gs_string Message, log_entry_type Type)
{
u32 NewLogIndex = Log->NextEntry++;
if (Log->NextEntry >= LOG_ENTRIES_MAX)
{
Log->NextEntry = 0;
}
log_entry* NewEntry = Log->Entries + NewLogIndex;
NewEntry->Message = Message;
NewEntry->Type = Type;
}
#define FOLDHAUS_LOG_H
#endif // FOLDHAUS_LOG_H

View File

@ -1,255 +0,0 @@
//
// File: foldhaus_platform.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PLATFORM_H
// TODO Remove
#include <math.h>
#include <windows.h>
#include "..\gs_libs\gs_types.h"
#include "..\gs_libs\gs_types.cpp"
#include "..\gs_libs\gs_path.h"
struct handle
{
u32 Generation;
u32 Index;
};
inline bool
Handle_IsValid(handle Handle)
{
bool Result = (Handle.Generation != 0);
return Result;
}
#include "..\gs_libs\gs_string.h"
#include "..\gs_libs\gs_csv.h"
#include "engine/foldhaus_log.h"
global log_buffer* GlobalLogBuffer;
#include "foldhaus_debug.h"
global debug_services* GlobalDebugServices;
//#include "..\gs_libs\gs_vector_matrix.h"
#include "..\gs_libs\gs_input.h"
struct platform_network_address
{
s32 Family;
u16 Port;
u32 Address;
};
typedef s32 platform_socket_handle;
typedef s32 platform_network_address_handle;
#include "foldhaus_renderer.h"
#include "engine/foldhaus_addressed_data.h"
typedef struct context context;
// Application Functions
// TODO(pjs): TEMP
typedef void temp_job_req_proc(gs_thread_context* Ctx, u8* Memory);
struct temp_job_req
{
temp_job_req_proc* Proc;
u8* Memory;
};
// This isn't necessarily temp but I'm not sure it goes here
#define PACKETS_MAX 32
struct packet_ringbuffer
{
gs_data Values[PACKETS_MAX];
u32 ReadHead;
u32 WriteHead;
};
#define INITIALIZE_APPLICATION(name) void name(context* Context)
typedef INITIALIZE_APPLICATION(initialize_application);
#define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer, addressed_data_buffer_list* OutputData)
typedef UPDATE_AND_RENDER(update_and_render);
#define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices, log_buffer* LogBuffer, bool AppReady)
typedef RELOAD_STATIC_DATA(reload_static_data);
#define CLEANUP_APPLICATION(name) void name(context Context, addressed_data_buffer_list* OutputData)
typedef CLEANUP_APPLICATION(cleanup_application);
// Platform Functions
struct window_info
{
char* Name;
s32 Width;
s32 Height;
};
typedef struct window window;
#define PLATFORM_MEMORY_NO_ERROR 0
enum platform_memory_error
{
PlatformMemory_NoError,
PlatformMemory_FileNotFound,
PlatformMemory_UnknownError, // You should implement handling this when you see it
};
struct data
{
u8* Base;
u64 Size;
};
struct platform_memory_result
{
data Data;
platform_memory_error Error;
};
struct system_path
{
char* Path;
s32 PathLength;
s32 IndexOfLastSlash;
};
struct texture_buffer
{
u8* Memory;
s32 Width;
s32 Height;
s32 Pitch;
s32 BytesPerPixel;
};
#define PLATFORM_GET_GPU_TEXTURE_HANDLE(name) s32 name(u8* Memory, s32 Width, s32 Height)
typedef PLATFORM_GET_GPU_TEXTURE_HANDLE(platform_get_gpu_texture_handle);
#define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive)
typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle);
// Font
struct platform_font_info
{
s32 PixelHeight;
s32 Ascent, Descent, Leading;
s32 MaxCharWidth;
s32 CodepointStart;
s32 CodepointOnePastLast;
};
enum font_weight
{
FontWeight_Invalid = 0,
FontWeight_Thin = 100,
FontWeight_ExtraLight = 200,
FontWeight_Light = 300,
FontWeight_Normal = 400,
FontWeight_Medium = 500,
FontWeight_SemiBold = 600,
FontWeight_Bold = 700,
FontWeight_ExtraBold = 800,
FontWeight_Heavy = 900,
};
#define GET_FONT_INFO(name) platform_font_info name(char* FontName, s32 PixelHeight, font_weight FontWeight, b32 Italic, b32 Underline, b32 Strikeout)
typedef GET_FONT_INFO(platform_get_font_info);
#define DRAW_FONT_CODEPOINT(name) void name(u8* DestBuffer, s32 DestBufferWidth, s32 DestBufferHeight, u32 XOffset, u32 YOffset, char Codepoint, platform_font_info FontInfo, u32* OutWidth, u32* OutHeight)
typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint);
// Worker Threads
#define PLATFORM_THREAD_COUNT 3
RESET_WORK_QUEUE(ResetWorkQueue)
{
for (u32 i = 0; i < Queue->JobsMax; i++)
{
Queue->Jobs[i].Data = {0};
Queue->Jobs[i].WorkProc = 0;
}
Queue->JobsCount = 0;
Queue->NextJobIndex = 0;
Queue->JobsCompleted = 0;
}
// Time
internal r32
GetSecondsElapsed (s64 Start, s64 End, s64 PerformanceCountFrequency)
{
r32 Result = ((r32)(End - Start) / (r32) PerformanceCountFrequency);
return Result;
}
typedef struct system_time
{
u64 NanosSinceEpoch;
s32 Year;
s32 Month;
s32 Day;
s32 Hour; // [0:23]
s32 Minute;
s32 Second;
} system_time;
internal r64
SecondsElapsed(system_time Start, system_time End)
{
u64 N = End.NanosSinceEpoch - Start.NanosSinceEpoch;
r64 S = (r64)N * NanosToSeconds;
return S;
}
struct context
{
gs_thread_context ThreadContext;
u8* MemoryBase;
u32 MemorySize;
b32 WindowIsVisible;
rect2 WindowBounds;
r64 TotalTime;
r32 DeltaTime;
mouse_state Mouse;
// Application Services
initialize_application* InitializeApplication;
reload_static_data* ReloadStaticData;
update_and_render* UpdateAndRender;
cleanup_application* CleanupApplication;
platform_thread_manager* ThreadManager;
platform_socket_manager* SocketManager;
// Platform Services
gs_work_queue* GeneralWorkQueue;
platform_get_gpu_texture_handle* PlatformGetGPUTextureHandle;
platform_get_font_info* PlatformGetFontInfo;
platform_draw_font_codepoint* PlatformDrawFontCodepoint;
platform_get_socket_handle* PlatformGetSocketHandle;
system_time SystemTime_Last;
system_time SystemTime_Current;
//
bool Headless;
};
#define FOLDHAUS_PLATFORM_H
#endif // FOLDHAUS_PLATFORM_H

View File

@ -1,198 +0,0 @@
//
// File: foldhaus_renderer.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_RENDERER_CPP
internal render_command_buffer
AllocateRenderCommandBuffer (u8* Memory, s32 Size, gs_thread_context Ctx)
{
render_command_buffer Result = {};
Result.CommandMemory = Memory;
Result.CommandMemorySize = Size;
Result.CommandMemoryUsed = 0;
Result.Ctx = Ctx;
return Result;
}
internal render_command_buffer
AllocateRenderCommandBuffer(u32 MemorySize,
gs_memory_arena* Arena,
gs_thread_context Ctx)
{
u8* Memory = PushSize(Arena, MemorySize).Memory;
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
}
internal void
Render3DQuadBatch (u8* CommandData, s32 TriCount)
{
DEBUG_TRACK_FUNCTION;
v4* Vertecies = (v4*)(CommandData + BATCH_3D_VERTECIES_OFFSET(TriCount));
v2* UVs = (v2*)(CommandData + BATCH_3D_UVS_OFFSET(TriCount));
v4* Colors = (v4*)(CommandData + BATCH_3D_COLORS_OFFSET(TriCount));
#if IMMEDIATE_MODE_RENDERING
for (s32 Tri = 0; Tri < TriCount; Tri++)
{
v4 P0 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)];
v4 P1 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)];
v4 P2 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)];
v2 UV0 = UVs[BATCH_3D_UV_INDEX(Tri, 0)];
v2 UV1 = UVs[BATCH_3D_UV_INDEX(Tri, 1)];
v2 UV2 = UVs[BATCH_3D_UV_INDEX(Tri, 2)];
v4 C0 = Colors[BATCH_3D_COLOR_INDEX(Tri, 0)];
v4 C1 = Colors[BATCH_3D_COLOR_INDEX(Tri, 1)];
v4 C2 = Colors[BATCH_3D_COLOR_INDEX(Tri, 2)];
OpenGLDraw3DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
#else
OpenGLRenderTriBuffer((u8*)Vertecies, 4, (u8*)UVs, 2, (u8*)Colors, 4, TriCount * 3);
#endif
}
internal void
Render2DQuadBatch (u8* CommandData, s32 QuadCount)
{
DEBUG_TRACK_FUNCTION;
v2* Vertecies = (v2*)(CommandData + BATCH_2D_VERTECIES_OFFSET(QuadCount));
v2* UVs = (v2*)(CommandData + BATCH_2D_UVS_OFFSET(QuadCount));
v4* Colors = (v4*)(CommandData + BATCH_2D_COLORS_OFFSET(QuadCount));
#if IMMEDIATE_MODE_RENDERING
for (s32 Quad = 0; Quad < QuadCount; Quad++)
{
for (s32 Tri = 0; Tri < 2; Tri++)
{
v2 P0 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 0)];
v2 P1 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 1)];
v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)];
v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)];
v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)];
v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)];
v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)];
v4 C1 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 1)];
v4 C2 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 2)];
OpenGLDraw2DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
}
#else
OpenGLRenderTriBuffer((u8*)Vertecies, 2, (u8*)UVs, 2, (u8*)Colors, 4, QuadCount * 2 * 3);
#endif
}
internal void
RenderCommandBuffer (render_command_buffer CommandBuffer)
{
DEBUG_TRACK_FUNCTION;
glMatrixMode(GL_TEXTURE_2D);
glLoadIdentity();
glClearColor(0.1f, 0.1f, 0.1f, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
b32 GLTextureEnabled = false;
u8* CurrentPosition = CommandBuffer.CommandMemory;
while(CurrentPosition < CommandBuffer.CommandMemory + CommandBuffer.CommandMemoryUsed)
{
render_command_header* CommandHeader = (render_command_header*)CurrentPosition;
CurrentPosition += sizeof(render_command_header);
switch (CommandHeader->Type)
{
case RenderCommand_render_command_set_render_mode:
{
DEBUG_TRACK_SCOPE(SetRenderMode);
render_command_set_render_mode* Command = (render_command_set_render_mode*)(CommandHeader + 1);
glViewport(Command->ViewOffsetX, Command->ViewOffsetY,
Command->ViewWidth, Command->ViewHeight);
LoadModelView(Command->ModelView.Array);
LoadProjection(Command->Projection.Array);
if (Command->UseDepthBuffer)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
else
{
glDisable(GL_DEPTH_TEST);
}
CurrentPosition += sizeof(render_command_set_render_mode);
}break;
case RenderCommand_render_command_clear_screen:
{
DEBUG_TRACK_SCOPE(RendererClearScreen);
render_command_clear_screen* Command = (render_command_clear_screen*)(CommandHeader + 1);
ClearRenderBuffer();
CurrentPosition += sizeof(render_command_clear_screen);
}break;
case RenderCommand_render_batch_command_quad_2d:
{
render_batch_command_quad_2d* Command = (render_batch_command_quad_2d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_quad_2d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_quad_3d:
{
render_batch_command_quad_3d* Command = (render_batch_command_quad_3d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render3DQuadBatch(CommandData, Command->QuadCount * 2);
CurrentPosition += sizeof(render_batch_command_quad_3d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_texture_2d:
{
render_batch_command_texture_2d* Command = (render_batch_command_texture_2d*)(CommandHeader + 1);
if (!GLTextureEnabled) { glEnable(GL_TEXTURE_2D); GLTextureEnabled = true; }
Assert(Command->Texture.Handle > 0);
glBindTexture(GL_TEXTURE_2D, Command->Texture.Handle);
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_texture_2d) + Command->DataSize;
}break;
default:
{
InvalidCodePath;
}break;
}
}
}
internal void
ClearRenderBuffer (render_command_buffer* Buffer)
{
Buffer->CommandMemoryUsed = 0;
}
#define FOLDHAUS_RENDERER_CPP
#endif // FOLDHAUS_RENDERER_CPP

View File

@ -1,719 +0,0 @@
//
// File: foldhaus_renderer.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_RENDERER_H
#define IMMEDIATE_MODE_RENDERING 0
struct camera
{
r32 FieldOfView;
r32 AspectRatio;
r32 Near, Far;
v3 Position;
v3 LookAt;
};
inline m44
GetCameraModelViewMatrix (camera Camera)
{
m44 RotationMatrix = M44LookAt(ToV4Point(Camera.Position), ToV4Point(Camera.LookAt));
m44 PositionMatrix = M44Translation(ToV4Point(-Camera.Position));
m44 ModelViewMatrix = RotationMatrix * PositionMatrix;
return ModelViewMatrix;
}
inline m44
GetCameraPerspectiveProjectionMatrix(camera Camera)
{
m44 Result = M44ProjectionPerspective(Camera.FieldOfView, Camera.AspectRatio, Camera.Near, Camera.Far);
return Result;
}
internal m44
GetCameraMatrix(camera Camera)
{
m44 ModelView = GetCameraModelViewMatrix(Camera);
m44 Projection = GetCameraPerspectiveProjectionMatrix(Camera);
m44 Result = Projection * ModelView;
return Result;
}
internal v2
ProjectWorldPointToScreen(v4 WorldSpacePoint, camera Camera, rect2 WindowBounds)
{
v2 WindowExtents = v2{Rect2Width(WindowBounds), Rect2Height(WindowBounds)};
v4 ProjectedPosition = GetCameraMatrix(Camera) * WorldSpacePoint;
ProjectedPosition.xyz /= ProjectedPosition.w;
v2 ScreenPosition = V2MultiplyPairwise(ProjectedPosition.xy, (WindowExtents / 2)) + (WindowExtents / 2);
return ScreenPosition;
}
internal v4_ray
ProjectScreenPointToWorldRay(v2 ScreenPoint, camera Camera, rect2 WindowBounds)
{
v4_ray Result = {0};
r32 TanFOVOverTwo = TanR32(DegToRadR32(Camera.FieldOfView / 2.0f));
r32 Aspect = RectAspectRatio(WindowBounds);
r32 NormalizedX = ScreenPoint.x / Rect2Width(WindowBounds);
r32 NormalizedY = ScreenPoint.y / Rect2Height(WindowBounds);
r32 CenteredX = (2.0f * NormalizedX) - 1.0f;
r32 CenteredY = (2.0f * NormalizedY) - 1.0f;
r32 ScaledX = CenteredX * Aspect;
r32 ScaledY = CenteredY;
r32 CameraX = ScaledX * TanFOVOverTwo;
r32 CameraY = ScaledY * TanFOVOverTwo;
r32 Near = Camera.Near;
r32 Far = Camera.Far;
v3 MousePointOnNearPlane = v3{CameraX, CameraY, -1} * Near;
v3 MousePointOnFarPlane = v3{CameraX, CameraY, -1} * Far;
v4 MouseRayDirection = ToV4Vec(V3Normalize(MousePointOnFarPlane - MousePointOnNearPlane));
m44 CameraTransform = M44Transpose(M44LookAt(ToV4Point(Camera.Position), ToV4Point(Camera.LookAt)));
Result.Origin = ToV4Point(Camera.Position);
Result.Direction = CameraTransform * MouseRayDirection;
return Result;
}
// Render Commands
// Discriminated Union
enum render_command_type
{
RenderCommand_Invalid,
RenderCommand_render_command_clear_screen,
RenderCommand_render_command_set_render_mode,
RenderCommand_render_batch_command_quad_2d,
RenderCommand_render_batch_command_quad_3d,
RenderCommand_render_batch_command_texture_2d,
RenderCommand_render_command_texture_3d,
RenderCommand_Count
};
struct render_command_header
{
render_command_type Type;
};
// NOTE(Peter): Just to keep with the rest of the system
struct render_command_clear_screen {};
struct render_quad_2d
{
v2 Min, Max;
};
struct render_quad_3d
{
v4 P0, P1, P2, P3;
};
struct render_texture
{
u8* Memory;
s32 Handle;
s32 Width;
s32 Height;
s32 BytesPerPixel;
s32 Stride;
};
#define BATCH_3D_SIZE(tricount) (((sizeof(v4) + sizeof(v2) + sizeof(v4)) * 3) * tricount)
#define BATCH_3D_VERTECIES_OFFSET(tricount) (0 * tricount)
#define BATCH_3D_UVS_OFFSET(tricount) (BATCH_3D_VERTECIES_OFFSET(tricount) + ((sizeof(v4) * 3) * tricount))
#define BATCH_3D_COLORS_OFFSET(tricount) (BATCH_3D_UVS_OFFSET(tricount) + ((sizeof(v2) * 3) * tricount))
#define BATCH_3D_VERTEX_INDEX(tri, v) ((tri * 3) + v)
#define BATCH_3D_UV_INDEX(tri, v) ((tri * 3) + v)
#define BATCH_3D_COLOR_INDEX(tri, v) ((tri * 3) + v)
#define BATCH_2D_SIZE(quadcount) (((sizeof(v2) + sizeof(v2) + sizeof(v4)) * 3) * 2 * quadcount)
#define BATCH_2D_VERTECIES_OFFSET(quadcount) (0 * quadcount)
#define BATCH_2D_UVS_OFFSET(quadcount) (BATCH_2D_VERTECIES_OFFSET(quadcount) + ((sizeof(v2) * 3) * 2 * quadcount))
#define BATCH_2D_COLORS_OFFSET(quadcount) (BATCH_2D_UVS_OFFSET(quadcount) + ((sizeof(v2) * 3) * 2 * quadcount))
#define BATCH_2D_VERTEX_INDEX(quad, tri, v) ((quad * 6) + (tri * 3) + v)
#define BATCH_2D_UV_INDEX(quad, tri, v) ((quad * 6) + (tri * 3) + v)
#define BATCH_2D_COLOR_INDEX(quad, tri, v) ((quad * 6) + (tri * 3) + v)
struct render_quad_batch_constructor
{
s32 Max;
s32 Count;
v4* Vertecies;
v2* UVs;
v4* ColorsV;
};
struct render_batch_command_quad_2d
{
s32 QuadCount;
s32 DataSize;
// NOTE(Peter): The data immediately follows the command in memory
};
struct render_batch_command_quad_3d
{
s32 QuadCount;
s32 DataSize;
// NOTE(Peter): The data immediately follows the command in memory
};
struct render_command_texture_2d
{
render_quad_2d Quad;
render_quad_2d UV;
v4 Color;
render_texture Texture;
};
struct render_batch_command_texture_2d
{
s32 QuadCount;
s32 DataSize;
render_texture Texture;
};
struct render_command_texture_3d
{
render_quad_3d Quad;
v4 Color;
render_texture Texture;
};
struct render_command_set_render_mode
{
m44 ModelView;
m44 Projection;
r32 ViewOffsetX, ViewOffsetY;
r32 ViewWidth, ViewHeight;
b32 UseDepthBuffer;
};
typedef u8* renderer_realloc(u8* Base, s32 CurrentSize, s32 NewSize);
#define COMMAND_BUFFER_MIN_GROW_SIZE MB(2)
struct render_command_buffer
{
u8* CommandMemory;
s32 CommandMemoryUsed;
s32 CommandMemorySize;
gs_thread_context Ctx;
s32 ViewWidth;
s32 ViewHeight;
};
///
// Utility
///
internal u32
PackColorStructU8 (u8 R, u8 G, u8 B, u8 A)
{
u32 Result = (u32)(A << 24 |
R << 16 |
G << 8 |
B<< 0);
return Result;
}
internal u32
PackColorStructR32 (r32 In_R, r32 In_G, r32 In_B, r32 In_A)
{
Assert ((In_R >= 0.0f && In_R <= 1.0f) &&
(In_G >= 0.0f && In_G <= 1.0f) &&
(In_B >= 0.0f && In_B <= 1.0f) &&
(In_A >= 0.0f && In_A <= 1.0f));
u8 R = (u8)(255 * In_R);
u8 G = (u8)(255 * In_G);
u8 B = (u8)(255 * In_B);
u8 A = (u8)(255 * In_A);
u32 Result = (u32)(A << 24 |
R << 16 |
G << 8 |
B<< 0);
return Result;
}
internal void
ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize)
{
if (Buffer->CommandMemoryUsed + DataSize > Buffer->CommandMemorySize)
{
// NOTE(Peter): If this becomes a problem just go back to the original solution of
// NewSize = Buffer->CommandMemorySize + (2 * DataSize);
s32 SpaceAvailable = Buffer->CommandMemorySize - Buffer->CommandMemoryUsed;
s32 SpaceNeeded = DataSize - SpaceAvailable; // This is known to be positive at this point
s32 AdditionSize = Max(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE);
s32 NewSize = Buffer->CommandMemorySize + AdditionSize;
Free(Buffer->Ctx.Allocator, Buffer->CommandMemory, Buffer->CommandMemorySize);
Buffer->CommandMemory = Alloc(Buffer->Ctx.Allocator, NewSize, "Renderer");
Buffer->CommandMemorySize = NewSize;
}
}
// Batch
internal s32
PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, u8* MemStart, s32 TriCount, s32 DataSize, b32 UseIntegerColor = false)
{
Constructor->Max = TriCount;
Constructor->Count = 0;
Constructor->Vertecies = (v4*)(MemStart + BATCH_3D_VERTECIES_OFFSET(TriCount));
Constructor->UVs = (v2*)(MemStart + BATCH_3D_UVS_OFFSET(TriCount));
Constructor->ColorsV = (v4*)(MemStart + BATCH_3D_COLORS_OFFSET(TriCount));
Buffer->CommandMemoryUsed += DataSize;
return DataSize;
}
internal s32
PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, s32 DataSize, u8* MemStart)
{
ZeroMemoryBlock(MemStart, DataSize);
Constructor->Max = QuadCount;
Constructor->Count = 0;
Constructor->Vertecies = (v4*)(MemStart + BATCH_2D_VERTECIES_OFFSET(QuadCount));
Constructor->UVs = (v2*)(MemStart + BATCH_2D_UVS_OFFSET(QuadCount));
Constructor->ColorsV = (v4*)(MemStart + BATCH_2D_COLORS_OFFSET(QuadCount));
Buffer->CommandMemoryUsed += DataSize;
return DataSize;
}
internal s32
ThreadSafeIncrementQuadConstructorCount (render_quad_batch_constructor* Constructor)
{
s32 Result = InterlockedIncrement((long*)&Constructor->Count);
// NOTE(Peter): Have to decrement the value by one.
// Interlocked Increment acts as (++Constructor->Count), not (Constructor->Count++) which
// is what we wanted;
// This was causing the first triangle to be garbage data.
Result -= 1;
return Result;
}
struct quad_batch_constructor_reserved_range
{
s32 Start;
s32 OnePastLast;
};
internal quad_batch_constructor_reserved_range
ReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded)
{
quad_batch_constructor_reserved_range Result = {};
Result.OnePastLast = Constructor->Count + TrisNeeded;
Constructor->Count = Result.OnePastLast;
Result.Start = Result.OnePastLast - TrisNeeded;
return Result;
}
internal quad_batch_constructor_reserved_range
ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded)
{
quad_batch_constructor_reserved_range Result = {};
Result.OnePastLast = InterlockedAdd((long*)&Constructor->Count, TrisNeeded);
Result.Start = Result.OnePastLast - TrisNeeded;
return Result;
}
inline void
SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex,
v4 P0, v4 P1, v4 P2,
v2 UV0, v2 UV1, v2 UV2,
v4 C0, v4 C1, v4 C2)
{
//Assert(P0.w != 0 && P1.w != 0 && P2.w != 0); // Passing vectors, rather than positions. Will draw wrong
// Vertecies
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 0)] = P0;
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 1)] = P1;
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 2)] = P2;
// UVs
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 0)] = UV0;
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 1)] = UV1;
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 2)] = UV1;
// Color V0
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 0)] = C0;
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 1)] = C1;
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 2)] = C2;
}
inline void
PushTri3DOnBatch (render_quad_batch_constructor* Constructor,
v4 P0, v4 P1, v4 P2,
v2 UV0, v2 UV1, v2 UV2,
v4 C0, v4 C1, v4 C2)
{
DEBUG_TRACK_FUNCTION;
// TODO(Peter): I think we avoid doing cross thread filling of a batch so do we need this?
s32 Tri = ThreadSafeIncrementQuadConstructorCount(Constructor);
SetTri3DInBatch(Constructor, Tri, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
};
internal void
PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 P2, v4 P3, v2 UVMin, v2 UVMax, v4 Color)
{
Assert(Constructor->Count + 2 <= Constructor->Max);
PushTri3DOnBatch(Constructor, P0, P1, P2, UVMin, v2{UVMax.x, UVMin.y}, UVMax, Color, Color, Color);
PushTri3DOnBatch(Constructor, P0, P2, P3, UVMin, UVMax, v2{UVMin.x, UVMax.y}, Color, Color, Color);
}
internal void
PushQuad3DOnBatch (render_quad_batch_constructor* Constructor,
v4 P0, v4 P1, v4 P2, v4 P3,
v2 UV0, v2 UV1, v2 UV2, v2 UV3,
v4 C0, v4 C1, v4 C2, v4 C3)
{
Assert(Constructor->Count <= Constructor->Max);
PushTri3DOnBatch(Constructor, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
PushTri3DOnBatch(Constructor, P0, P2, P3, UV0, UV2, UV3, C0, C2, C3);
}
internal void
PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 P2, v4 P3, v4 Color)
{
PushQuad3DOnBatch(Constructor, P0, P1, P2, P3, v2{0, 0}, v2{1, 1}, Color);
}
internal void
PushQuad2DOnBatch (render_quad_batch_constructor* Constructor,
v2 P0, v2 P1, v2 P2, v2 P3,
v2 UV0, v2 UV1, v2 UV2, v2 UV3,
v4 C0, v4 C1, v4 C2, v4 C3)
{
DEBUG_TRACK_FUNCTION;
s32 Quad = ThreadSafeIncrementQuadConstructorCount(Constructor);
v2* Vertecies = (v2*)Constructor->Vertecies;
// Tri 1
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 0)] = P0;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 1)] = P1;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 2)] = P2;
// Tri 2
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 0)] = P0;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 1)] = P2;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 2)] = P3;
// Tri 1 UVs
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 0)] = UV0;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 1)] = UV1;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 2)] = UV2;
// Tri 2 UVs
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 0)] = UV0;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 1)] = UV2;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 2)] = UV3;
// Tri 1 Colors
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 0)] = C0;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 1)] = C1;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 2)] = C2;
// Tri 2 Colors
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 0)] = C0;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 1)] = C2;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 2)] = C3;
}
internal void
PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, v2 P2, v2 P3, v2 UVMin, v2 UVMax, v4 Color)
{
DEBUG_TRACK_FUNCTION;
s32 Quad = ThreadSafeIncrementQuadConstructorCount(Constructor);
v2* Vertecies = (v2*)Constructor->Vertecies;
// Tri 1
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 0)] = P0;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 1)] = P1;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 0, 2)] = P2;
// Tri 2
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 0)] = P0;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 1)] = P2;
Vertecies[BATCH_2D_VERTEX_INDEX(Quad, 1, 2)] = P3;
// Tri 1 UVs
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 0)] = UVMin;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 1)] = v2{UVMax.x, UVMin.y};
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 0, 2)] = UVMax;
// Tri 2 UVs
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 0)] = UVMin;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 1)] = UVMax;
Constructor->UVs[BATCH_2D_UV_INDEX(Quad, 1, 2)] = v2{UVMin.x, UVMax.y};
// Tri 1 Colors
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 0)] = Color;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 1)] = Color;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 0, 2)] = Color;
// Tri 2 Colors
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 0)] = Color;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 1)] = Color;
Constructor->ColorsV[BATCH_2D_COLOR_INDEX(Quad, 1, 2)] = Color;
}
internal void
PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, v2 Min, v2 Max, v4 Color)
{
PushQuad2DOnBatch(Constructor, v2{Min.x, Min.y}, v2{Max.x, Min.y}, v2{Max.x, Max.y}, v2{Min.x, Max.y},
v2{0, 0}, v2{1, 1}, Color);
}
internal void
PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, rect2 Rect, v4 Color)
{
PushQuad2DOnBatch(Constructor, v2{Rect.Min.x, Rect.Min.y}, v2{Rect.Max.x, Rect.Min.y}, v2{Rect.Max.x, Rect.Max.y}, v2{Rect.Min.x, Rect.Max.y},
v2{0, 0}, v2{1, 1}, Color);
}
internal void
PushLine2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, r32 Thickness, v4 Color)
{
r32 HalfThickness = Thickness / 2.0f;
v2 Perpendicular = V2Normalize(V2PerpendicularCCW(P1 - P0)) * HalfThickness;
PushQuad2DOnBatch(Constructor, P0 - Perpendicular, P1 - Perpendicular, P1 + Perpendicular, P0 + Perpendicular,
v2{0, 0}, v2{1, 1}, Color);
}
// Commands
#define PushRenderCommand(buffer, type) (type*) PushRenderCommand_(buffer, RenderCommand_##type, sizeof(type) + sizeof(render_command_header))
internal u8*
PushRenderCommand_ (render_command_buffer* CommandBuffer, render_command_type CommandType, s32 CommandSize)
{
ResizeBufferIfNecessary(CommandBuffer, CommandSize);
Assert(CommandBuffer->CommandMemoryUsed + CommandSize <= CommandBuffer->CommandMemorySize);
render_command_header* Header = (render_command_header*)(CommandBuffer->CommandMemory + CommandBuffer->CommandMemoryUsed);
Header->Type = CommandType;
u8* Result = (u8*)(Header + 1);
CommandBuffer->CommandMemoryUsed += CommandSize;
return Result;
}
internal render_command_set_render_mode*
PushRenderPerspective (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, s32 ViewWidth, s32 ViewHeight, camera Camera)
{
render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode);
Command->ModelView = M44Transpose(GetCameraModelViewMatrix(Camera));
Command->Projection = M44Transpose(GetCameraPerspectiveProjectionMatrix(Camera));
Command->ViewOffsetX = (r32)OffsetX;
Command->ViewOffsetY = (r32)OffsetY;
Command->ViewWidth = (r32)ViewWidth;
Command->ViewHeight = (r32)ViewHeight;
Command->UseDepthBuffer = true;
return Command;
}
internal void
PushRenderPerspective(render_command_buffer* Buffer, rect2 Viewport, camera Camera)
{
PushRenderPerspective(Buffer, Viewport.Min.x, Viewport.Min.y, Rect2Width(Viewport), Rect2Height(Viewport), Camera);
}
internal void
PushRenderOrthographic (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, s32 ViewWidth, s32 ViewHeight)
{
render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode);
Command->ModelView = M44Identity();
Command->Projection = M44ProjectionOrtho((r32)ViewWidth, (r32)ViewHeight, 0, 100, ViewWidth, 0, ViewHeight, 0);
Command->ViewOffsetX = (r32)OffsetX;
Command->ViewOffsetY = (r32)OffsetY;
Command->ViewWidth = ViewWidth;
Command->ViewHeight = ViewHeight;
Command->UseDepthBuffer = false;;
}
internal void
PushRenderOrthographic(render_command_buffer* Buffer, rect2 Viewport)
{
PushRenderOrthographic(Buffer, Viewport.Min.x, Viewport.Min.y, Rect2Width(Viewport), Rect2Height(Viewport));
}
internal void
PushRenderClearScreen (render_command_buffer* Buffer)
{
render_command_clear_screen* Command = PushRenderCommand(Buffer, render_command_clear_screen);
}
internal render_quad_batch_constructor
PushRenderQuad2DBatch(render_command_buffer* Buffer, s32 QuadCount)
{
s32 DataSize = BATCH_2D_SIZE(QuadCount);
ResizeBufferIfNecessary(Buffer, DataSize + sizeof(render_batch_command_quad_2d));
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
render_quad_batch_constructor Result = {};
render_batch_command_quad_2d* Command = PushRenderCommand(Buffer, render_batch_command_quad_2d);
Command->QuadCount = QuadCount;
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, DataSize, (u8*)(Command + 1));
return Result;
}
internal void
PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, Min, Max, Color);
}
internal void
PushRenderQuad2D (render_command_buffer* Buffer, rect2 Rect, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, Rect.Min, Rect.Max, Color);
}
internal void
PushRenderQuad2DClipped (render_command_buffer* Buffer, rect2 Rect, rect2 ClippingBox, v4 Color)
{
rect2 Clipped = Rect2Union(Rect, ClippingBox);
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, Clipped.Min, Clipped.Max, Color);
}
internal void
PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, P0, P1, P2, P3, v2{0,0}, v2{1,1}, Color);
}
internal void
PushRenderLine2D (render_command_buffer* Buffer, v2 P0, v2 P1, r32 Thickness, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushLine2DOnBatch(&Batch, P0, P1, Thickness, Color);
}
internal render_quad_batch_constructor
PushRenderQuad3DBatch(render_command_buffer* Buffer, s32 QuadCount)
{
s32 TriCount = QuadCount * 2;
s32 DataSize = BATCH_3D_SIZE(TriCount);
ResizeBufferIfNecessary(Buffer, DataSize + sizeof(render_batch_command_quad_3d));
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
render_quad_batch_constructor Result = {};
render_batch_command_quad_3d* Command = PushRenderCommand(Buffer, render_batch_command_quad_3d);
Command->QuadCount = QuadCount;
Command->DataSize = PushQuad3DBatch(Buffer, &Result, (u8*)(Command + 1), TriCount, DataSize);
return Result;
}
internal void
PushRenderQuad3D (render_command_buffer* Buffer, v4 A, v4 B, v4 C, v4 D, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad3DBatch(Buffer, 1);
PushQuad3DOnBatch(&Batch, A, B, C, D, Color);
}
internal void
PushRenderCameraFacingQuad (render_command_buffer* Buffer, v4 Center, v2 Dimensions, v4 Color)
{
// TODO(Peter): Turn this into an actual camera facing quad
v4 A = v4{Center.x - Dimensions.x, Center.y - Dimensions.y, Center.z, Center.w};
v4 B = v4{Center.x + Dimensions.x, Center.y - Dimensions.y, Center.z, Center.w};
v4 C = v4{Center.x + Dimensions.x, Center.y + Dimensions.y, Center.z, Center.w};
v4 D = v4{Center.x - Dimensions.x, Center.y + Dimensions.y, Center.z, Center.w};
PushRenderQuad3D(Buffer, A, B, C, D, Color);
}
internal render_quad_batch_constructor
PushRenderTexture2DBatch(render_command_buffer* Buffer, s32 QuadCount,
render_texture Texture)
{
s32 DataSize = BATCH_2D_SIZE(QuadCount);
ResizeBufferIfNecessary(Buffer, DataSize);
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
render_quad_batch_constructor Result = {};
render_batch_command_texture_2d* Command = PushRenderCommand(Buffer, render_batch_command_texture_2d);
Command->QuadCount = QuadCount;
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, DataSize, (u8*)(Command + 1));
Command->Texture = Texture;
return Result;
}
internal render_quad_batch_constructor
PushRenderTexture2DBatch (render_command_buffer* Buffer, s32 QuadCount,
u8* TextureMemory, s32 TextureHandle, s32 TextureWidth, s32 TextureHeight,
s32 TextureBytesPerPixel, s32 TextureStride)
{
render_texture Texture = render_texture{
TextureMemory,
TextureHandle,
TextureWidth,
TextureHeight,
TextureBytesPerPixel,
TextureStride};
return PushRenderTexture2DBatch(Buffer, QuadCount, Texture);
}
internal void
PushRenderTexture2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color,
v2 UVMin, v2 UVMax,
render_texture* Texture)
{
render_quad_batch_constructor Batch = PushRenderTexture2DBatch(Buffer, 1, *Texture);
PushQuad2DOnBatch(&Batch, v2{Min.x, Min.y}, v2{Max.x, Min.y}, v2{Max.x, Max.y}, v2{Min.x, Max.y},
UVMin, UVMax, Color);
}
internal void
PushRenderBoundingBox2D (render_command_buffer* Buffer, v2 Min, v2 Max, r32 Thickness, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 4);
PushQuad2DOnBatch(&Batch, Min, v2{Min.x + Thickness, Max.y}, Color);
PushQuad2DOnBatch(&Batch, v2{Min.x, Max.y - Thickness}, Max, Color);
PushQuad2DOnBatch(&Batch, v2{Max.x - Thickness, Min.y}, Max, Color);
PushQuad2DOnBatch(&Batch, Min, v2{Max.x, Min.y + Thickness}, Color);
}
#define FOLDHAUS_RENDERER_H
#endif // FOLDHAUS_RENDERER_H

View File

@ -1,32 +0,0 @@
enum node_type
{
NodeType_SolidColorProc,
NodeType_RevolvingDiscs,
NodeType_VerticalColorFadeProc,
NodeType_Count,
};
static node_specification_ NodeSpecifications[] = {
{ NodeType_SolidColorProc, {"SolidColorProc", 14}, gsm_StructType_solid_color_data },
{ NodeType_RevolvingDiscs, {"RevolvingDiscs", 14}, gsm_StructType_revolving_discs_data },
{ NodeType_VerticalColorFadeProc, {"VerticalColorFadeProc", 21}, gsm_StructType_vertical_color_fade_data },
};
void CallNodeProc(node_type Type, u8* NodeData)
{
switch(Type) {
case NodeType_SolidColorProc:
{
SolidColorProc((solid_color_data*)NodeData);
} break;
case NodeType_RevolvingDiscs:
{
RevolvingDiscs((revolving_discs_data*)NodeData);
} break;
case NodeType_VerticalColorFadeProc:
{
VerticalColorFadeProc((vertical_color_fade_data*)NodeData);
} break;
}
}

View File

@ -1,110 +0,0 @@
enum gsm_meta_tag_type
{
MetaTag_panel_type_file_view,
MetaTag_panel_type_node_graph,
MetaTag_node_output,
MetaTag_node_struct,
MetaTag_panel_cleanup,
MetaTag_node_input,
MetaTag_panel_init,
MetaTag_panel_type_animation_timeline,
MetaTag_panel_commands,
MetaTag_panel_type_sculpture_view,
MetaTag_node_proc,
MetaTag_panel_type_hierarchy,
MetaTag_panel_type_profiler,
MetaTag_panel_render,
MetaTag_panel_type_dmx_view,
};
gsm_meta_tag MetaTaggs_strings[] = {
{ "panel_type_file_view", 20 },
{ "panel_type_node_graph", 21 },
{ "node_output", 11 },
{ "node_struct", 11 },
{ "panel_cleanup", 13 },
{ "node_input", 10 },
{ "panel_init", 10 },
{ "panel_type_animation_timeline", 29 },
{ "panel_commands", 14 },
{ "panel_type_sculpture_view", 25 },
{ "node_proc", 9 },
{ "panel_type_hierarchy", 20 },
{ "panel_type_profiler", 19 },
{ "panel_render", 12 },
{ "panel_type_dmx_view", 19 },
};
enum gsm_struct_type
{
gsm_StructType_r32,
gsm_StructType_solid_color_data,
gsm_StructType_v4,
gsm_StructType_float,
gsm_StructType_color_buffer,
gsm_StructType_pixel,
gsm_StructType_u8,
gsm_StructType_s32,
gsm_StructType_revolving_discs_data,
gsm_StructType_vertical_color_fade_data,
gsm_StructType_Count,
};
static gsm_struct_member_type_info StructMembers_v4[] = {
{ "x", 1, (u64)&((v4*)0)->x, {}, 0},
{ "y", 1, (u64)&((v4*)0)->y, {}, 0},
{ "z", 1, (u64)&((v4*)0)->z, {}, 0},
{ "w", 1, (u64)&((v4*)0)->w, {}, 0},
{ "r", 1, (u64)&((v4*)0)->r, {}, 0},
{ "g", 1, (u64)&((v4*)0)->g, {}, 0},
{ "b", 1, (u64)&((v4*)0)->b, {}, 0},
{ "a", 1, (u64)&((v4*)0)->a, {}, 0},
{ "xy", 2, (u64)&((v4*)0)->xy, {}, 0},
{ "yz", 2, (u64)&((v4*)0)->yz, {}, 0},
{ "xyz", 3, (u64)&((v4*)0)->xyz, {}, 0},
{ "z", 1, (u64)&((v4*)0)->z, {}, 0},
{ "E", 1, (u64)&((v4*)0)->E, {}, 0},
};
static gsm_struct_member_type_info StructMembers_pixel[] = {
{ "R", 1, (u64)&((pixel*)0)->R, {}, 0},
{ "G", 1, (u64)&((pixel*)0)->G, {}, 0},
{ "B", 1, (u64)&((pixel*)0)->B, {}, 0},
{ "Channels", 8, (u64)&((pixel*)0)->Channels, {}, 0},
};
static gsm_struct_member_type_info StructMembers_color_buffer[] = {
{ "LedPositions", 12, (u64)&((color_buffer*)0)->LedPositions, {}, 0},
{ "Colors", 6, (u64)&((color_buffer*)0)->Colors, {}, 0},
{ "LEDCount", 8, (u64)&((color_buffer*)0)->LEDCount, {}, 0},
};
static gsm_struct_member_type_info StructMembers_solid_color_data[] = {
{ "Color", 5, (u64)&((solid_color_data*)0)->Color, {MetaTag_node_input, }, 1},
{ "Result", 6, (u64)&((solid_color_data*)0)->Result, {MetaTag_node_output, }, 1},
};
static gsm_struct_member_type_info StructMembers_revolving_discs_data[] = {
{ "Rotation", 8, (u64)&((revolving_discs_data*)0)->Rotation, {MetaTag_node_input, }, 1},
{ "ThetaZ", 6, (u64)&((revolving_discs_data*)0)->ThetaZ, {MetaTag_node_input, }, 1},
{ "ThetaY", 6, (u64)&((revolving_discs_data*)0)->ThetaY, {MetaTag_node_input, }, 1},
{ "DiscWidth", 9, (u64)&((revolving_discs_data*)0)->DiscWidth, {MetaTag_node_input, }, 1},
{ "InnerRadius", 11, (u64)&((revolving_discs_data*)0)->InnerRadius, {MetaTag_node_input, }, 1},
{ "OuterRadius", 11, (u64)&((revolving_discs_data*)0)->OuterRadius, {MetaTag_node_input, }, 1},
{ "Color", 5, (u64)&((revolving_discs_data*)0)->Color, {MetaTag_node_input, }, 1},
{ "Result", 6, (u64)&((revolving_discs_data*)0)->Result, {MetaTag_node_output, }, 1},
};
static gsm_struct_member_type_info StructMembers_vertical_color_fade_data[] = {
{ "Color", 5, (u64)&((vertical_color_fade_data*)0)->Color, {MetaTag_node_input, }, 1},
{ "Min", 3, (u64)&((vertical_color_fade_data*)0)->Min, {MetaTag_node_input, }, 1},
{ "Max", 3, (u64)&((vertical_color_fade_data*)0)->Max, {MetaTag_node_input, }, 1},
{ "Result", 6, (u64)&((vertical_color_fade_data*)0)->Result, {MetaTag_node_output, }, 1},
};
static gsm_struct_type_info StructTypes[] = {
{ gsm_StructType_r32, "r32", 3, 4, 0, 0, 0, 0 },
{ gsm_StructType_solid_color_data, "solid_color_data", 16, 32, 0, 0, StructMembers_solid_color_data, 2 },
{ gsm_StructType_v4, "v4", 2, 16, 0, 0, StructMembers_v4, 5 },
{ gsm_StructType_float, "float", 5, 4, 0, 0, 0, 0 },
{ gsm_StructType_color_buffer, "color_buffer", 12, 16, 0, 0, StructMembers_color_buffer, 3 },
{ gsm_StructType_pixel, "pixel", 5, 0, 0, 0, StructMembers_pixel, 2 },
{ gsm_StructType_u8, "u8", 2, 0, 0, 0, 0, 0 },
{ gsm_StructType_s32, "s32", 3, 0, 0, 0, 0, 0 },
{ gsm_StructType_revolving_discs_data, "revolving_discs_data", 20, 56, 0, 0, StructMembers_revolving_discs_data, 8 },
{ gsm_StructType_vertical_color_fade_data, "vertical_color_fade_data", 24, 40, 0, 0, StructMembers_vertical_color_fade_data, 4 },
};
static gsm_u32 StructTypesCount = 12;

View File

@ -1,879 +0,0 @@
//
// File: blumen_patterns.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef BLUMEN_PATTERNS_H
#define FLOWER_COLORS_COUNT 12
internal void
Pattern_None(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
// just here so you can fade in from black
}
internal void
Pattern_AltBloomMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
v3 SphereCenter = Assembly.Center - v3{0, -150, 0};
r32 SphereRadius = Time;
r32 SphereBrightness = 1;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Sphere = SDF_SphereNormalized(P, SphereCenter, SphereRadius);
Sphere = Clamp01(-Sphere);
Leds->Colors[LedIndex] = V4ToRGBPixel(WhiteV4 * Sphere);
}
}
internal void
Pattern_HueShift(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
r32 Height = SinR32(Time) * 25;
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
#if 0
phrase_hue Hue = BLState->AssemblyColors[Assembly.AssemblyIndex % 3];
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
v4 HSV = {};
if (CycleProgress < .25f)
{
r32 P = CycleProgress * 4;
HSV = V4Lerp(C0,
}
else if (CycleProgress >= .25f && CycleProgress < .5f)
{
}
else if (CycleProgress >= .5f && CycleProgress < .75f)
{
}
else if (CycleProgress >= .75f)
{
}
#endif
v4 HSV = { CycleProgress * 360, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Dist = Pos.y - Height;
//v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 };
//v4 RGB = HSVToRGB(HSV);
u8 R = (u8)(RGB.x * 255);
u8 G = (u8)(RGB.y * 255);
u8 B = (u8)(RGB.z * 255);
Leds->Colors[LedIndex].R = R;
Leds->Colors[LedIndex].G = G;
Leds->Colors[LedIndex].B = B;
}
}
internal void
Pattern_Rainbow(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
r32 HueBase = ModR32(Time * 50, 360);
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Hue = HueBase + Pos.y + Pos.x;
v4 HSV = { Hue, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal void
Pattern_RadialRainbow(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) });
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v2 Vector = v2{
Leds->Positions[LedIndex].x,
Leds->Positions[LedIndex].z
};
Vector = V2Normalize(Vector);
r32 Angle = V2Dot(RefVector, Vector);
v4 HSV = { (Angle * 30) + (Time * 10), 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal void
Pattern_BasicFlowers(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
phrase_hue Hue = BLState->AssemblyColors[Assembly.AssemblyIndex % 3];
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
r32 CycleT = ModR32(Time, 10) * 20;
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
v4 P = Leds->Positions[LedIndex];
r32 T = ModR32(P.y + CycleT, 200) / 200.f;
T = Clamp01(T);
v4 Color = {};
if (T < 0.5f)
{
Color = V4Lerp(T * 2, C0, C1);
}
else
{
Color = V4Lerp((T - 0.5f) * 2, C1, C2);
}
Leds->Colors[LedIndex] = V4ToRGBPixel(Color);
}
}
}
internal void
Pattern_WavyOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2)
{
r32 Top = 120 + (SinR32(Time) * 10);
r32 Mid = 70 + (CosR32(Time * 2.13) * 20);
r32 Bot = 0;
r32 TopD = Top - Mid;
r32 BotD = Mid - Bot;
r32 MidD = Min(TopD, BotD);
//r32 MaxFadeDistance = 10;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 PercentTop = Clamp01(1.0f - ((Top - P.y) / TopD));
r32 PercentMid = Clamp01(1.0f - Abs(P.y - Mid) / MidD);
r32 N = Noise3D((P / 17) + v3{Time, -Time, 0});
N = Clamp01(N) * 2;
N = Smoothstep(N);
N *= N;
N = Smoothstep(N);
N *= 1.0f - PowR32(1.0f - PercentMid, 4);
PercentMid = Clamp01(PercentMid + N);
r32 PercentBot = Clamp01(1.0f - ((P.y - Bot) / BotD));
v4 TopC = (C0 * PercentTop);
v4 MidC = (C1 * PercentMid);
v4 BotC = (C2 * PercentBot);
v4 C = {};
if (PercentTop > PercentMid && PercentTop > PercentBot)
{
C = C0;
}
else if (PercentMid > PercentBot)
{
C = C1;
}
else
{
C = C2;
}
r32 ScaleFactor = PercentTop + PercentMid + PercentBot;
C = (TopC + MidC + BotC) / ScaleFactor;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
Pattern_WavyOptions(Leds, Range, Assembly, Time, Transient, UserData, 1, C0, C1, C2);
}
internal void
Pattern_PatchyOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
r32 BaseGA = 50.000f * (1 / Granularity);
r32 BaseGB = 135.20f * (1 / Granularity);
r32 BaseGC = 260.74f * (1 / Granularity);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
r32 LedRange = 300.0f;
r32 ScaleFactor = 1.0f / LedRange;
v3 Pp = P.xyz + v3{150, 100, 0};
r32 NoiseA = Noise3D((Pp / BaseGA) + v3{0, 0, Time});
NoiseA = PowR32(NoiseA, 3);
NoiseA = Smoothstep(NoiseA);
r32 NoiseB = Noise3D((Pp / BaseGB) + v3{Time * 0.5f, 0, 0});
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB);
#if 1
r32 NoiseC = Noise3D((Pp / BaseGC) + v3{Time * 0.5f, 0, 0});
NoiseC = PowR32(NoiseC, 3);
NoiseC = Smoothstep(NoiseC);
#else
r32 NoiseC = 0;
#endif
v4 C = (C0 * NoiseA) + (C1 * NoiseB) + (C2 * NoiseC);
C /= (NoiseA + NoiseB + NoiseC);
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
Time = Time * BLState->PatternSpeed;
Pattern_PatchyOptions(Leds, Range, Assembly, Time, Transient, UserData, 5, C0, C1, C2);
}
internal r32
Leafy_BandSDF(v3 P, gs_random_series* Random, r32 Time)
{
r32 MinBandThickness = 5;
r32 MaxBandThickness = 10;
r32 MaxTransitionPeriod = 120.0f;
r32 BandTransitionPeriod = NextRandomUnilateral(Random) * MaxTransitionPeriod;
r32 BandTransitionBias = (1 - Clamp(0, (Time / (MaxTransitionPeriod / 2)), 0.7f)); // approaches 0.5 over time
BandTransitionPeriod *= BandTransitionBias;
r32 BandPercent = ModR32(Time, BandTransitionPeriod) / BandTransitionPeriod;
BandPercent = Smoothstep(BandPercent);
r32 BandY = -150 + (BandPercent * 290);
r32 ThickRand = NextRandomUnilateral(Random);
// 1 - 4((ThickRand - .5)^2) - distribution curve
ThickRand = 1.0f - ((4 * PowR32(ThickRand, 2)) - (4 * ThickRand) + 1);
r32 BandThickness = MinBandThickness + (ThickRand * (MaxBandThickness - MinBandThickness));
// BandBrightness = 1 - ((2x - 1) ^ 8) where x is BandPercent
r32 BandBrightness = 1.0f - PowR32((2 * BandPercent) - 1, 8);
BandBrightness *= RemapR32(NextRandomUnilateral(Random), 0, 1, .25f, 1);
r32 Result = 1 - Clamp01(Abs(P.y - BandY) / BandThickness);
Result *= BandBrightness;
return Result;
}
internal void
Pattern_Leafy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed * .3f;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
v4 C = {};
r32 B = 0;
// NOTE(PS): initializing the Random seed inside the Led Loop
// so that the bands are consistently calculated for each led
// ie. each time you calculate a band, the random numbers requested
// will always be the same
gs_random_series Random = InitRandomSeries(24601);
u32 BandCount = 25;
for (u32 Band = 0; Band < BandCount; Band++)
{
B += Leafy_BandSDF(P.xyz, &Random, Time);
}
B = Clamp01(B);
C = WhiteV4 * B;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_LeafyPatchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
v3 Pp = P.xyz + v3{150, 100, 0};
r32 NoiseA = Fbm3D((Pp / 18), Time * 0.25f);
NoiseA = Smoothstep(NoiseA);
r32 NoiseB = Noise3D((Pp / 35) + v3{0, 0, Time * 0.5f});
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB);
r32 NoiseC = Noise3D((Pp / 25) + v3{0, 0, Time * 4});
r32 CPresence = SinR32((P.y / 50) - Time) + (0.8f * SinR32((P.y / 25) - (Time * 5.0f)));
CPresence = RemapR32(CPresence, -1.8, 1.8, 0, 1);
CPresence = PowR32(CPresence, 4);
NoiseC *= CPresence;
v4 C = (C0 * NoiseA * 0.5f) + (C1 * NoiseB) + (C2 * NoiseC);
C *= 1.0f / (NoiseA + NoiseB + NoiseC);
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_WavyPatchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
}
internal void
Pattern_VerticalLines(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
gs_random_series Random = InitRandomSeries(24601);
r32 LightSpeedMin = 1;
r32 LightSpeedMax = 5;
s32 LightTailLength = 60;
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
r32 LightStartHeight = NextRandomUnilateral(&Random);
r32 LightSpeed = LerpR32(NextRandomUnilateral(&Random),
LightSpeedMin,
LightSpeedMax);
r32 LightCurrentHeight = LightStartHeight + (LightSpeed * Time * 0.1f);
s32 StartIndex = (s32)(LightCurrentHeight * (r32)Strip.LedCount) % Strip.LedCount;
for (s32 i = 0; i < LightTailLength; i++)
{
s32 StripLedIndex = StartIndex + i;
if (StripLedIndex >= (s32)Strip.LedCount) continue;
u32 LedIndex = Strip.LedLUT[StripLedIndex];
r32 PctTail = ((r32)i / (r32)LightTailLength);
v4 C = WhiteV4 * PctTail;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
}
internal void
Pattern_RotaryOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 BGColor, v4 FGColor)
{
DEBUG_TRACK_FUNCTION;
gs_random_series Random = InitRandomSeries((u32)(24601 * (Assembly.Center.x + 1.032f)));
#define SphereCount 32
v3 SphereCenter[SphereCount];
r32 G = RemapR32(Granularity, 1, 5, .75f, 2);
r32 MaxHeightOffset = 250;
r32 MaxSpeed = 10;
r32 SphereRotationRadius = 3.0f;
r32 SphereRadius = 2.0f / G;
for (u32 i = 0; i < SphereCount; i++)
{
r32 SphereSeedA = NextRandomUnilateral(&Random);
SphereSeedA = PowR32(SphereSeedA, 2);
r32 SphereSeedB = NextRandomBilateral(&Random);
r32 SphereSpeed = NextRandomUnilateral(&Random) * MaxSpeed;
r32 SphereTime = Time + SphereSpeed;
r32 HeightOffset = 150 - (SphereSeedA * MaxHeightOffset);
r32 RotationOffset = SphereTime + SphereSeedB * TauR32;
r32 SphereRotationDir = NextRandomBilateral(&Random) < 0 ? -1 : 1;
v3 SpherePosOffset = v3{
SinR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2),
HeightOffset,
CosR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2)
};
SphereCenter[i] = Assembly.Center + SpherePosOffset;
}
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Dist = 10000000;
for (u32 i = 0; i < SphereCount; i++)
{
r32 SphereSDF = Abs(SDF_Sphere(P, SphereCenter[i], SphereRadius));
SphereSDF = SphereSDF / SphereRadius;
Dist = Min(Dist, SphereSDF);
}
v4 C = BGColor;
if (Dist <= 1)
{
r32 Brightness = Clamp01(SphereRadius - Dist);
C = V4Lerp(Brightness, BGColor, FGColor);
}
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_Rotary(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
Pattern_RotaryOptions(Leds, Range, Assembly, Time, Transient, UserData, .25f, BlackV4, WhiteV4);
}
internal void
Pattern_AllOnMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
pixel White = V4ToRGBPixel(WhiteV4);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
Leds->Colors[LedIndex] = White;
}
}
internal void
Pattern_BulbMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
r32 Top = 141;
r32 BulbRange = 50;
pixel White = V4ToRGBPixel(WhiteV4);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 BulbSDF = 1 - Clamp01(((Top - P.y) - BulbRange) / BulbRange);
r32 N = Noise3D((P / 17) + v3{Time, -Time, 0});
N = Clamp01(N) * 2;
N = Smoothstep(N);
N *= N;
N = Smoothstep(N);
N *= 1.0f - PowR32(1.0f - BulbSDF, 4);
BulbSDF += N;
BulbSDF = Clamp01(BulbSDF);
v4 C = WhiteV4 * BulbSDF;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal v4
GenPatchyColor(v3 P, r32 Time, v4 C0, v4 C1, v4 C2)
{
r32 LedRange = 300.0f;
r32 ScaleFactor = 1.0f / LedRange;
v3 Pp = P + v3{150, 100, 0};
r32 ScaleA = 1;
r32 NoiseA = Noise3D(((Pp / 38) + v3{0, 0, Time}) * ScaleA);
NoiseA = PowR32(NoiseA, 3);
NoiseA = Smoothstep(NoiseA);
r32 ScaleBP = 2;
r32 ScaleB = 15;
r32 NoiseBP = Noise3D(((Pp / 13) + v3{ 0, Time * -0.33f, 0}) * ScaleBP);
NoiseBP = PowR32(NoiseBP, 3);
r32 NoiseB = Noise3D(((Pp / 75) + v3{Time * 0.5f, 0, 0}) * ScaleB);
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB) * NoiseBP;
r32 ScaleC = 1.5;
r32 NoiseCP = Noise3D(((Pp / 132) + v3{Time * -0.33f, 0, 0}) * 0.5f);
r32 NoiseC = Noise3D(((Pp / 164) + v3{Time * 0.25f, 0, 0}) * ScaleC);
NoiseC = PowR32(NoiseC, 3);
NoiseC = Smoothstep(NoiseC) * NoiseCP;
v4 C = (C0 * NoiseA) + (C1 * NoiseB) + (C2 * NoiseC);
C /= (NoiseA + NoiseB + NoiseC);
return C;
}
internal r32
GenVerticalStrips(v3 P, r32 Time)
{
v2 Right = v2{1, 0};
v2 Pa = V2Normalize(v2{P.x, P.z});
r32 Angle = .5f + (.5f * V2Dot(Pa, Right));
r32 HOffset = 70.0f;
r32 O = 50.0f;
r32 C = 10.0f;
r32 X = Angle;
r32 Y = P.y;
r32 I = FloorR32(Y / C) * C;
I += (X * HOffset) + (Time * 25);
r32 V = FractR32(I / O);
V = 2.0f * (0.5f - Abs(V - 0.5f));
Assert(V >= 0 && V <= 1);
return V;
}
internal v4
GenVerticalLeaves(v3 P, r32 Time, v4 C0, v4 C1, v4 C2)
{
r32 A = GenVerticalStrips(P, Time * .25f);
r32 B = GenVerticalStrips(P * .3f, Time);
r32 C = GenVerticalStrips(P * .25f, Time * 2);
v4 R = (C0 * A) + (C1 * B) + (C2 * C);
R /= A + B + C;
return R;
}
internal void
AddIn_WavesPattern(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2)
{
DEBUG_TRACK_FUNCTION;
v4 C2P = C2 * 255;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
v4 C = v4{
(r32)Leds->Colors[LedIndex].R,
(r32)Leds->Colors[LedIndex].G,
(r32)Leds->Colors[LedIndex].B,
1
};
r32 Offset = -250;
r32 Width = 30;
r32 Bands = 0;
for (u32 i = 1; i <= 1; i++)
{
P.x = FloorR32(P.x);
P.z = FloorR32(P.z);
v3 P0 = v3{P.x + (23.124f * i), 0, P.z - (-12.34f * i) + Time};
r32 S = Fbm3D(P0 * .005f, Time) * 250;
S += ModR32((Time * 100) - (150 * i), 400);
r32 Y = (P.y - Offset);
r32 V = (Width - Abs(Y - S)) / Width;
V = Clamp01(V);
Bands += V;
}
C = V4Lerp(Bands, C * .5f, C2P);
Leds->Colors[LedIndex] = pixel{(u8)C.r, (u8)C.g, (u8)C.b};
}
}
internal r32
GenDotBands(v3 P, r32 Time)
{
r32 RowHeight = 25;
r32 DotRadius = 20;
r32 Y = P.y + 150;
s32 Row = (s32)FloorR32(Y / RowHeight);
r32 RowH = Abs(FractR32(Y / RowHeight));
r32 DotDistY = Max(0, .5f - RowH) * 2;
r32 Angle = (V2Dot(V2Normalize(v2{P.x, P.z}), v2{1,0}) * .5f) + .5f;
r32 DotDistX = Abs(ModR32(Angle, .2f));
r32 DotDist = SqrtR32(PowR32(DotDistX, 2) + PowR32(RowH, 2));
r32 B = (DotRadius - DotDist) / DotRadius;
B = Clamp01(DotDist);
return DotDistY;
}
internal void
Pattern_VoicePattern(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
Time = Time * BLState->PatternSpeed * Hue.Speed;;
switch (Hue.Pattern)
{
case HuePattern_Wavy:
{
Pattern_WavyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C0);
}break;
default:
{
Pattern_PatchyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2);
}break;
}
}
internal void
Pattern_VoiceAddIns(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
Time = Time * BLState->PatternSpeed * Hue.Speed;;
switch (Hue.AddIn)
{
case AddIn_Rotary:
{
Pattern_RotaryOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, BlackV4, C2);
}break;
case AddIn_Waves:
{
AddIn_WavesPattern(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2);
}break;
case AddIn_None:
default:
{
}break;
}
}
internal void
Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
pixel WhiteMask = V4ToRGBPixel(WhiteV4);
led_strip_list Stem = BLState->StemStrips[Assembly.AssemblyIndex];
for (u32 s = 0; s < Stem.Count; s++)
{
u32 StripIndex = Stem.StripIndices[s];
v2_strip Strip = Assembly.Strips[StripIndex];
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
Leds->Colors[LedIndex] = WhiteMask;
}
}
}
internal void
Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
pixel HueOut = V4ToRGBPixel(C0);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
Leds->Colors[LedIndex] = HueOut;
}
}
internal void
Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
r32 Period = 10.0f; // seconds
r32 ElapsedPct = FractR32(Time / Period);
r32 ElapsedPctGrow = PowR32(ElapsedPct * 2, 2);
r32 ElapsedPctFade = Clamp01((ElapsedPct * 2) - 1);
r32 Radius = 300 * ElapsedPctGrow;
v3 Origin = Assembly.Center - v3{0, 150, 0};
r32 Brightness = Smoothstep(1.0f - ElapsedPctFade);
pixel COutside = V4ToRGBPixel(BlackV4);
pixel CInside = V4ToRGBPixel(WhiteV4 * Brightness);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Dist = V3Mag(P - Origin);
if (Dist < Radius)
{
Leds->Colors[LedIndex] = CInside;
}
else
{
Leds->Colors[LedIndex] = COutside;
}
}
}
internal void
Pattern_RainbowLoadingBar(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
// constants
r32 Period = 5.0f; // seconds
r32 CSpeed = 16.0f;
r32 HIncrement = CSpeed * Period;
r32 HOffset = CSpeed * Period;
r32 MaxSphereRadius = 300;
// sphere
r32 ElapsedPct = FractR32(Time / Period);
r32 ElapsedPctGrow = PowR32(ElapsedPct, 2);
r32 Radius = MaxSphereRadius * ElapsedPctGrow;
v3 Origin = Assembly.Center - v3{0, 150, 0};
// colors
r32 T = Time * CSpeed;
r32 TimeStep0 = T;
r32 TimeStep1 = T + HOffset;
r32 Hue0 = FloorR32(TimeStep0 / HIncrement) * HIncrement;
r32 Hue1 = FloorR32(TimeStep1 / HIncrement) * HIncrement;
v4 H0 = v4{ModR32(Hue0, 360), 1, 1, 1};
v4 H1 = v4{ModR32(Hue1, 360), 1, 1, 1};
pixel C0 = V4ToRGBPixel(HSVToRGB(H0));
pixel C1 = V4ToRGBPixel(HSVToRGB(H1));
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Dist = V3Mag(P - Origin);
if (Dist < Radius)
{
Leds->Colors[LedIndex] = C1;
}
else
{
Leds->Colors[LedIndex] = C0;
}
}
}
internal void
Pattern_Blue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
pixel Blue = pixel{0, 0, 255};
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
Leds->Colors[LedIndex] = Blue;
}
}
#define BLUMEN_PATTERNS_H
#endif // BLUMEN_PATTERNS_H

View File

@ -1,76 +0,0 @@
#include <Cocoa/Cocoa.h>
#include "gs_osx_memory.mm"
#include "gs_osx_window.mm"
#include "gs_osx_fileio.mm"
#include "gs_osx_lib.mm"
#include "gs_osx_opengl.mm"
#include "gs_osx_time.mm"
static void
gsosx_ProcessWindowEvents(NSApplication* App, NSWindow* Window)
{
// Process Events
while (true)
{
NSEvent* Event = [App nextEventMatchingMask: NSEventMaskAny untilDate: [NSDate distantPast] inMode: NSDefaultRunLoopMode dequeue: YES];
if (!Event) { break; }
switch([Event type])
{
case NSEventTypeKeyUp:
case NSEventTypeKeyDown:
{
// TODO: Handle Key Presses
}break;
// TODO: Mouse Input
default:
{
[App sendEvent: Event];
}break;
}
}
}
int main(int ArgCount, char** Args)
{
NSApplication* Application = [NSApplication sharedApplication];
[Application setActivationPolicy: NSApplicationActivationPolicyRegular];
gsosx_ApplicationDelegate* Delegate = [[gsosx_ApplicationDelegate alloc] init];
[Application setDelegate: Delegate];
int WindowWidth = 1024;
int WindowHeight = 768;
id AppName = @"Lumenarium";
NSWindow* Window = gsosx_CreateWindow(Application, WindowWidth, WindowHeight, AppName);
// A really cryptic way of asking the window to open
[Window makeKeyAndOrderFront: Application];
NSOpenGLContext* OpenGLContext = gsoo_CreateOpenGLContext(Window, WindowWidth, WindowHeight, true);
gsosx_time_info TimeInfo = gsosx_InitTime();
double TargetSecondsPerFrame = 1.0 / 60;
uint64_t LastFrameEnd = gsosx_GetTime(TimeInfo);
while (true)
{
gsosx_ProcessWindowEvents(Application, Window);
glClearColor(1, 0, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gsoo_SwapBuffers(OpenGLContext);
uint64_t ThisFrameEnd = gsosx_GetTime(TimeInfo);
double FrameSeconds = gsosx_GetSecondsElapsed(LastFrameEnd, ThisFrameEnd, TimeInfo);
double SleepSeconds = TargetSecondsPerFrame - FrameSeconds;
if (SleepSeconds > 0)
{
gsosx_Sleep(SleepSeconds, TimeInfo);
}
}
return (0);
}

View File

@ -1,63 +0,0 @@
#include <sys/stat.h>
static uint32_t
gsosx_GetLastFileWriteTime(char* Path)
{
int32_t Result = 0;
struct stat FileStat = {0};
if (stat(Path, &FileStat) == 0)
{
Result = FileStat.st_mtimespec.tv_sec;
}
else
{
// TODO: Asserts
}
return Result;
}
static uint32_t
gsosx_GetFilesize(char* Path)
{
uint32_t Result = 0;
int FileHandle = open(Path, O_RDONLY);
struct stat FileStat = {0};
fstat(FileHandle, &FileStat);
close(FileHandle);
Result = (uint32_t)FileStat.st_size;
return Result;
}
static bool
gsosx_LoadFileIntoMemory(char* Path, uint32_t FileSize, uint8_t* FileMemory)
{
bool Result = false;
int FileHandle = open(Path, O_RDONLY);
struct stat FileStat = {0};
fstat(FileHandle, &FileStat);
if (FileStat.st_size <= FileSize)
{
read(FileHandle, FileMemory, FileSize);
Result = true;
}
close(FileHandle);
return Result;
}
static bool
gsosx_WriteEntireFile(char* Path, uint32_t FileSize, uint8_t* FileMemory)
{
bool Result = false;
int FileHandle = open(Path, O_WRONLY | O_CREAT, 0777);
ssize_t SizeWritten = write(FileHandle, FileMemory, FileSize);
if (SizeWritten == FileSize)
{
Result = true;
}
close(FileHandle);
return Result;
}

View File

@ -1,30 +0,0 @@
#include <dlfcn.h>
static void*
gsosx_LoadDLL(char* Path)
{
void* LibHandle = 0;
LibHandle = dlopen(Path, RTLD_LAZY);
if (LibHandle)
{
dlerror(); // Clear Last Error
}
else
{
LibHandle = 0;
}
return LibHandle;
}
#define gsosx_GetProcAddress(libHandle, type, name) (type*)dlsym((libHandle), name)
static void
gsosx_UnloadDLL(void* LibHandle)
{
if (LibHandle)
{
dlclose(LibHandle);
}
}

View File

@ -1,30 +0,0 @@
#include <stdlib.h>
static uint8_t*
gsosx_Alloc(size_t Size)
{
uint8_t* Result = 0;
char* StartAddress = (char*)0;
int Prot = PROT_READ | PROT_WRITE;
int Flags = MAP_PRIVATE | MAP_ANON;
Result = (uint8_t*)mmap(StartAddress, Size, Prot, Flags, -1, 0);
return Result;
}
static void
gsosx_Free(uint8_t* Base, uint32_t Size)
{
munmap((void*)Base, (size_t)Size);
}
static uint8_t*
gsosx_Realloc(uint8_t* Base, uint32_t OldSize, uint32_t NewSize)
{
uint8_t* Result = gsosx_Alloc(NewSize);
for (int32_t i = 0; i < OldSize; i++)
{
Result[i] = Base[i];
}
gsosx_Free(Base, OldSize );
return Result;
}

View File

@ -1,65 +0,0 @@
#include <OpenGL/gl.h>
struct gsoo_opengl_state
{
NSOpenGLContext* Context;
};
@interface gsoo_OpenGLView: NSOpenGLView @end
@implementation gsoo_OpenGLView : NSOpenGLView
- (void)
reshape
{
// TODO: framebufferWidth and Height were globals in the code I was pulling from
// Need some way to get the new window height in here.
CGRect FrameRect = self.frame;
glViewport(0, 0, FrameRect.size.width, FrameRect.size.height);
//glViewport(0, 0, framebufferWidth, framebufferHeight);
}
@end
static NSOpenGLContext*
gsoo_CreateOpenGLContext(NSWindow* Window, uint32_t Width, uint32_t Height, int32_t EnableVSync)
{
NSOpenGLContext* Result = 0;
NSOpenGLPixelFormatAttribute PixelFormatAttributes[] = {
NSOpenGLPFAClosestPolicy,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFASampleBuffers,
0,
0
};
NSOpenGLPixelFormat* PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: PixelFormatAttributes];
Result = [[NSOpenGLContext alloc] initWithFormat: PixelFormat shareContext: 0];
if (!Result)
{
// TODO: Assert/Handle
return 0;
}
[Result makeCurrentContext];
GLint VSync = EnableVSync;
[Result setValues: &VSync forParameter: NSOpenGLCPSwapInterval];
// Set Backbuffer Resolution
GLint BackbufferDimensions[] = { Width, Height };
CGLSetParameter(Result.CGLContextObj, kCGLCPSurfaceBackingSize, BackbufferDimensions);
CGLEnable(Result.CGLContextObj, kCGLCESurfaceBackingSize);
//
gsoo_OpenGLView* View = [[gsoo_OpenGLView alloc] init];
[Window setContentView: View];
[View setOpenGLContext: Result];
[View setPixelFormat: PixelFormat];
[Result setView: View];
return Result;
}
static void
gsoo_SwapBuffers(NSOpenGLContext* OpenGLContext)
{
[OpenGLContext flushBuffer];
}

View File

@ -1,46 +0,0 @@
#include <mach/mach_time.h>
static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC;
struct gsosx_time_info
{
uint64_t StartTimeAbsolute;
mach_timebase_info_data_t MachTimeInfo;
};
static gsosx_time_info
gsosx_InitTime()
{
gsosx_time_info Result = {0};
Result.StartTimeAbsolute = mach_absolute_time();
mach_timebase_info(&Result.MachTimeInfo);
return Result;
}
static uint64_t
gsosx_GetTime(gsosx_time_info TimeInfo)
{
uint64_t Result = mach_absolute_time() - TimeInfo.StartTimeAbsolute;
return Result;
}
static double
gsosx_GetSecondsElapsed(uint64_t Start, uint64_t End, gsosx_time_info TimeInfo)
{
double Result = 0;
double Elapsed = (double)(End - Start);
Result = Elapsed * (double)(TimeInfo.MachTimeInfo.numer) / (double)NANOS_PER_SEC / (double)TimeInfo.MachTimeInfo.denom;
return Result;
}
static void
gsosx_Sleep(double Seconds, gsosx_time_info TimeInfo)
{
// NOTE(Peter): This isn't entirely precise, and can vary by up to 500 microseconds. We could implement a sleep combined witha busy wait
// to get more precise sleeping. Do this if necessary
uint64_t WaitTimeAbs = Seconds / (double)TimeInfo.MachTimeInfo.numer * (double)NANOS_PER_SEC * (double)TimeInfo.MachTimeInfo.denom;
uint64_t NowAbs = mach_absolute_time();
mach_wait_until(NowAbs + WaitTimeAbs);
}

View File

@ -1,78 +0,0 @@
@interface gsosx_ApplicationDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> @end
@implementation gsosx_ApplicationDelegate : NSObject
- (void)
applicationDidFinishLaunching: (NSNotification *)notification
{
[NSApp stop: nil];
NSAutoreleasePool* Pool = [[NSAutoreleasePool alloc] init];
[Pool drain];
}
- (NSApplicationTerminateReply)
applicationShouldTerminate: (NSApplication*) sender
{
return NO;
}
- (void)
dealloc
{
[super dealloc];
}
@end
@interface gsosx_WindowDelegate: NSObject<NSWindowDelegate> @end
@implementation gsosx_WindowDelegate : NSObject
- (BOOL)
windowShouldClose: (id)sender
{
// TODO(Peter): Stop Application Running?
NSLog(@"Close button pressed");
return NO;
}
- (void)
windowDidBecomeKey: (NSNotification*)notification
{
// TODO: ???
}
- (void)
windowDisResignKey: (NSNotification*)notification
{
// TODO: ???
}
@end
static NSWindow*
gsosx_CreateWindow(NSApplication* App, int Width, int Height, id Title)
{
int WindowStyleMask = NSWindowStyleMaskClosable;
NSRect WindowRect = NSMakeRect(0, 0, Width, Height);
NSWindow* Window = [[NSWindow alloc] initWithContentRect: WindowRect styleMask: WindowStyleMask backing: NSBackingStoreBuffered defer: YES];
Window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
gsosx_WindowDelegate* WindowDelegate = [[gsosx_WindowDelegate alloc] init];
[Window setOpaque: YES];
[Window setDelegate: WindowDelegate];
[Window setTitle: Title];
NSMenu* MenuBar = [NSMenu alloc];
NSMenuItem* AppMenuItem = [NSMenuItem alloc];
[MenuBar addItem: AppMenuItem];
[App setMainMenu: MenuBar];
NSMenu* AppMenu = [NSMenu alloc];
id QuitTitle = [@"Quit " gs_stringByAppendinggs_string: Title];
id QuitMenuItem = [[NSMenuItem alloc] initWithTitle: QuitTitle action: @selector(terminate:) keyEquivalent: @"q"];
[AppMenu addItem: QuitMenuItem];
[AppMenuItem setSubmenu: AppMenu];
[App activateIgnoringOtherApps: YES];
return Window;
}

View File

@ -1,786 +0,0 @@
//
// File: win32_foldhaus.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef WIN32_FOLDHAUS_CPP
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <intrin.h>
#include <windowsx.h>
#include <gl/gl.h>
#include "../../meta/gs_meta_include.h"
#include "../foldhaus_platform.h"
#include "../../gs_libs/gs_win32.cpp"
#include "win32_foldhaus_utils.h"
#include "win32_foldhaus_memory.h"
#include "win32_foldhaus_fileio.h"
#include "win32_foldhaus_dll.h"
#include "win32_foldhaus_timing.h"
#include "win32_foldhaus_work_queue.h"
#include "win32_foldhaus_serial.h"
#include "win32_foldhaus_socket.h"
#include "win32_foldhaus_mouse.h"
#include "../foldhaus_renderer.cpp"
#include "win32_test_code.cpp"
global b32 Running = false;
global b32 WindowIsActive = false;
char DLLName[] = "foldhaus.dll";
char WorkingDLLName[] = "foldhaus_temp.dll";
char DLLLockFileName[] = "lock.tmp";
window MainWindow;
PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle)
{
s32 Handle = SubmitTexture(Memory, Width, Height);
return Handle;
}
HDC FontDrawingDC;
HBITMAP FontBitmap;
HFONT CurrentFont;
GET_FONT_INFO(Win32GetFontInfo)
{
platform_font_info Result = {};
FontDrawingDC = CreateCompatibleDC(NULL);
SetBkColor(FontDrawingDC, RGB(0, 0, 0));
SetTextColor(FontDrawingDC, RGB(255, 255, 255));
FontBitmap = CreateCompatibleBitmap(FontDrawingDC, PixelHeight * 2, PixelHeight * 2);
HGDIOBJ SelectObjectResult = SelectObject(FontDrawingDC, FontBitmap);
CurrentFont = CreateFont(PixelHeight, 0, 0, 0,
FontWeight,
Italic,
Underline,
Strikeout,
ANSI_CHARSET,
OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,
PROOF_QUALITY,
FIXED_PITCH,
FontName);
SelectFont(FontDrawingDC, CurrentFont);
TEXTMETRIC WindowsFontMetrics = {};
if (GetTextMetrics(FontDrawingDC, &WindowsFontMetrics))
{
Result.PixelHeight = WindowsFontMetrics.tmHeight;
Result.Ascent = WindowsFontMetrics.tmAscent;
Result.Descent = WindowsFontMetrics.tmDescent;
Result.Leading = WindowsFontMetrics.tmExternalLeading;
Result.MaxCharWidth = WindowsFontMetrics.tmMaxCharWidth;
Result.CodepointStart = WindowsFontMetrics.tmFirstChar;
Result.CodepointOnePastLast = WindowsFontMetrics.tmLastChar + 1;
}
return Result;
}
DRAW_FONT_CODEPOINT(Win32DrawFontCodepoint)
{
SIZE CodepointSize = {};
if (GetTextExtentPoint32(FontDrawingDC, &Codepoint, 1, &CodepointSize))
{
*OutWidth = CodepointSize.cx;
*OutHeight = CodepointSize.cy;
RECT TextRect = {};
TextRect.left = 0;
TextRect.right = *OutWidth;
TextRect.top = 0;
TextRect.bottom = *OutHeight;
int Error = DrawText(FontDrawingDC, &Codepoint, 1, &TextRect, DT_LEFT | DT_NOCLIP | DT_TOP);
u8* Row = DestBuffer + (YOffset * (DestBufferWidth * 4));
COLORREF PixelColor;
for (u32 Y = 0; Y < *OutHeight; Y++)
{
// NOTE(Peter): XOffset * 4 b/c its 4 bytes per pixel.
u8* Channel = (u8*)Row + (XOffset * 4);
for (u32 X = 0; X < *OutWidth; X++)
{
PixelColor = GetPixel(FontDrawingDC, X + TextRect.left, TextRect.bottom - Y);
Assert(PixelColor != CLR_INVALID);
u8 RValue = GetRValue(PixelColor);
*Channel++ = RValue;
*Channel++ = RValue;
*Channel++ = RValue;
*Channel++ = RValue;
}
Row += DestBufferWidth * 4;
}
}
}
LRESULT CALLBACK
HandleWindowEvents (HWND WindowHandle, UINT Msg, WPARAM WParam, LPARAM LParam)
{
LRESULT Result = 0;
switch (Msg)
{
case WM_SIZE:
{
Win32UpdateWindowDimension(&MainWindow);
//Win32ResizeDIBSection(&GlobalBackbuffer, MainWindow.Info.Width, MainWindow.Info.Height);
}break;
case WM_CLOSE:
{
Result = DefWindowProc(WindowHandle, Msg, WParam, LParam);
Running = false;
}break;
case WM_DESTROY:
{
}break;
case WM_PAINT:
{
PAINTSTRUCT PaintStruct;
HDC DeviceContext;
b32 PaintResult;
DeviceContext = BeginPaint(WindowHandle, &PaintStruct);
PaintResult = EndPaint(WindowHandle, &PaintStruct);
}break;
case WM_ACTIVATE:
{
WindowIsActive = (LOWORD(WParam) == WA_ACTIVE || LOWORD(WParam) == WA_CLICKACTIVE);
}break;
default:
{
Result = DefWindowProc(WindowHandle, Msg, WParam, LParam);
}
}
return Result;
}
internal void
HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse_state* Mouse)
{
switch (Message.message)
{
case WM_MOUSEWHEEL:
{
Mouse->Scroll = GET_WHEEL_DELTA_WPARAM(Message.wParam);
}break;
case WM_LBUTTONDOWN:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true,
ShiftDown, AltDown, CtrlDown, false);
Mouse->LeftButtonState |= KeyState_IsDown;
Mouse->DownPos = Mouse->Pos;
// :Win32MouseEventCapture
// NOTE(Peter): We capture events when the mouse goes down so that
// if the user drags outside the window, we still get the mouse up
// event and can process it. Otherwise, we can get into cases where
// an event was started, didn't end, but the user can click again and
// try to start the event again.
// We relase event capture on mouse up.
SetCapture(Window->Handle);
}break;
case WM_MBUTTONDOWN:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, false, true,
ShiftDown, AltDown, CtrlDown, false);
Mouse->MiddleButtonState = KeyState_IsDown & ~KeyState_WasDown;
// :Win32MouseEventCapture
SetCapture(Window->Handle);
}break;
case WM_RBUTTONDOWN:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, false, true,
ShiftDown, AltDown, CtrlDown, false);
Mouse->RightButtonState = KeyState_IsDown & ~KeyState_WasDown;
Mouse->DownPos = Mouse->Pos;
// :Win32MouseEventCapture
SetCapture(Window->Handle);
}break;
case WM_LBUTTONUP:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false,
ShiftDown, AltDown, CtrlDown, false);
Mouse->LeftButtonState &= ~KeyState_IsDown;
// :Win32MouseEventCapture
ReleaseCapture();
}break;
case WM_MBUTTONUP:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, true, false,
ShiftDown, AltDown, CtrlDown, false);
Mouse->MiddleButtonState = ~KeyState_IsDown & KeyState_WasDown;
// :Win32MouseEventCapture
ReleaseCapture();
}break;
case WM_RBUTTONUP:
{
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, true, false,
ShiftDown, AltDown, CtrlDown, false);
Mouse->RightButtonState = ~KeyState_IsDown & KeyState_WasDown;
// :Win32MouseEventCapture
ReleaseCapture();
}break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
{
#if 0
int VirtualKey = (int)Message.wParam;
key_code Key = Win32GetKeyCode(VirtualKey, true, false);
s32 KeyIndex = (int)Key;
b32 KeyWasDown = (Message.lParam & (1 << 30)) != 0;
b32 KeyIsDown = (Message.lParam & (1 << 31)) == 0;
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
// New Input Queue
AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown,
ShiftDown, AltDown, CtrlDown, false);
#endif
TranslateMessage(&Message);
DispatchMessage(&Message);
}break;
case WM_CHAR:
{
char VirtualKey = (char)Message.wParam;
key_code Key = CharToKeyCode(VirtualKey);
s32 KeyIndex = (int)Key;
b32 KeyWasDown = (Message.lParam & (1 << 30)) != 0;
b32 KeyIsDown = (Message.lParam & (1 << 31)) == 0;
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
// New Input Queue
AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown,
ShiftDown, AltDown, CtrlDown, false);
}break;
default:
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}break;
}
}
internal void
DebugPrint (char* Format, ...)
{
char Buffer[256];
gs_string StringBuffer = MakeString(Buffer, 256);
va_list Args;
va_start(Args, Format);
Log_PrintFVarArgs(GlobalLogBuffer, LogEntry_Message, Format, Args);
va_end(Args);
}
internal void
SetApplicationLinks (context* Context, win32_dll_refresh DLL, gs_work_queue* WorkQueue)
{
if (DLL.IsValid)
{
Context->InitializeApplication = (initialize_application*)GetProcAddress(DLL.DLL, "InitializeApplication");
Context->ReloadStaticData = (reload_static_data*)GetProcAddress(DLL.DLL, "ReloadStaticData");
Context->UpdateAndRender = (update_and_render*)GetProcAddress(DLL.DLL, "UpdateAndRender");
Context->CleanupApplication = (cleanup_application*)GetProcAddress(DLL.DLL, "CleanupApplication");
}
else
{
Context->InitializeApplication = 0;
Context->ReloadStaticData = 0;
Context->UpdateAndRender = 0;
Context->CleanupApplication = 0;
}
}
internal void
Win32_SendAddressedDataBuffer(gs_thread_context Context, addressed_data_buffer* BufferAt)
{
DEBUG_TRACK_FUNCTION;
u32 BuffersSent = 0;
u32 DataSizeSent = 0;
switch(BufferAt->AddressType)
{
case AddressType_NetworkIP:
{
Win32Socket_SendTo(BufferAt->SendSocket,
BufferAt->V4SendAddress,
BufferAt->SendPort,
(const char*)BufferAt->Memory,
BufferAt->MemorySize,
0);
}break;
case AddressType_ComPort:
{
if (BufferAt->ComPort.Length > 0)
{
HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1, Context.Transient);
if (SerialPort != INVALID_HANDLE_VALUE)
{
if (Win32SerialPort_Write(SerialPort, BufferAt->Data))
{
BuffersSent += 1;
DataSizeSent += BufferAt->Data.Size;
}
else
{
Win32SerialArray_Close(BufferAt->ComPort);
}
}
}
else
{
#if 0
Log_Message(GlobalLogBuffer,
"Skipping data buffer because its COM Port isn't set");
#endif
}
}break;
InvalidDefaultCase;
}
}
internal void
Win32_SendAddressedDataBuffer_Job(gs_thread_context Context, gs_data Arg)
{
addressed_data_buffer* OutputData = (addressed_data_buffer*)Arg.Memory;
Win32_SendAddressedDataBuffer(Context, OutputData);
}
internal bool
ReloadAndLinkDLL(win32_dll_refresh* DLL, context* Context, gs_work_queue* WorkQueue, bool ShouldError, bool AppReady)
{
bool Success = false;
if (HotLoadDLL(DLL))
{
SetApplicationLinks(Context, *DLL, WorkQueue);
Context->ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, AppReady);
Success = true;
Log_Message(GlobalLogBuffer, "Reloaded DLL\n");
}
else if(ShouldError)
{
Log_Error(GlobalLogBuffer, "Unable to load application DLL at startup.\nAborting\n");
}
return Success;
}
internal gs_const_string
GetExePath(HINSTANCE HInstance, gs_thread_context ThreadContext)
{
gs_const_string Result = {};
u32 Error = 0;
u32 PathSize = MAX_PATH;
char* Path = PushArray(ThreadContext.Transient, char, PathSize);
DWORD Length = GetModuleFileNameA(HInstance, Path, PathSize);
if (Length)
{
Error = GetLastError();
if (Error == ERROR_INSUFFICIENT_BUFFER) {
// PathSize wasn't long enough
// TODO(pjs): handle this case
InvalidCodePath;
}
Result.Str = Path;
Result.Length = (u64)Length;
}
else
{
Error = GetLastError();
InvalidCodePath;
}
return Result;
}
internal bool
SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext)
{
bool Result = false;
gs_const_string ExePath = GetExePath(HInstance, ThreadContext);
gs_string ScratchPath = PushString(ThreadContext.Transient, ExePath.Length + 128);
gs_string WorkingDirectory = PushString(ThreadContext.Transient, ExePath.Length + 128);
while (WorkingDirectory.Length == 0)
{
s64 LastSlash = FindLastFromSet(ExePath, "\\/");
if (LastSlash < 0) break;
ExePath = Substring(ExePath, 0, LastSlash);
PrintF(&ScratchPath, "%S\\data", ExePath);
NullTerminate(&ScratchPath);
gs_file_info PathInfo = GetFileInfo(ThreadContext.FileHandler, ScratchPath.ConstString);
if (PathInfo.Path.Length > 0 &&
PathInfo.IsDirectory) {
PrintF(&WorkingDirectory, "%S", ExePath);
NullTerminate(&WorkingDirectory);
}
}
if (WorkingDirectory.Length > 0)
{
Log_Message(GlobalLogBuffer,
"Setting Working Directory \n%S \n",
WorkingDirectory.ConstString);
Result = SetCurrentDirectory(WorkingDirectory.Str);
if (!Result)
{
u32 Error = GetLastError();
InvalidCodePath;
}
}
else
{
Log_Error(GlobalLogBuffer, "Error, no data folder found\n");
}
return Result;
}
#include "../../gs_libs/gs_path.h"
internal void
Win32_SendOutputData(gs_thread_context ThreadContext, addressed_data_buffer_list OutputData)
{
bool Multithread = true;
if (Multithread)
{
for (addressed_data_buffer* At = OutputData.Root;
At != 0;
At = At->Next)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)At;
ProcArg.Size = sizeof(addressed_data_buffer);
Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffer_Job, ProcArg, ConstString("Send UART Data"));
}
}
else
{
for (addressed_data_buffer* At = OutputData.Root;
At != 0;
At = At->Next)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)At;
ProcArg.Size = sizeof(addressed_data_buffer);
Win32_SendAddressedDataBuffer_Job(ThreadContext, ProcArg);
}
}
}
// Time
internal system_time
Win32GetSystemTime()
{
system_time Result = {};
SYSTEMTIME WinLocalTime;
GetLocalTime(&WinLocalTime);
SYSTEMTIME WinSysTime;
FILETIME WinSysFileTime;
GetSystemTime(&WinSysTime);
if (SystemTimeToFileTime((const SYSTEMTIME*)&WinSysTime, &WinSysFileTime))
{
ULARGE_INTEGER SysTime = {};
SysTime.LowPart = WinSysFileTime.dwLowDateTime;
SysTime.HighPart = WinSysFileTime.dwHighDateTime;
Result.NanosSinceEpoch = SysTime.QuadPart;
Result.Year = WinLocalTime.wYear;
Result.Month = WinLocalTime.wMonth;
Result.Day = WinLocalTime.wDay;
Result.Hour = WinLocalTime.wHour;
Result.Minute = WinLocalTime.wMinute;
Result.Second = WinLocalTime.wSecond;
}
else
{
u32 Error = GetLastError();
InvalidCodePath;
}
return Result;
}
int WINAPI
WinMain (
HINSTANCE HInstance,
HINSTANCE HPrevInstance,
PSTR CmdLineArgs,
INT NCmdShow
)
{
gs_thread_context ThreadContext = Win32CreateThreadContext();
gs_memory_arena PlatformPermanent = MemoryArenaCreate(MB(4),
Bytes(8), ThreadContext.Allocator,
0,
0,
"Platform Memory");
GlobalLogBuffer = AllocStruct(ThreadContext.Allocator, log_buffer, "Global Log Buffer");
*GlobalLogBuffer = Log_Init(&PlatformPermanent, 32);
if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1;
context Context = {};
Context.ThreadContext = ThreadContext;
Context.SystemTime_Current = Win32GetSystemTime();
gs_const_string Args = ConstString((char*)CmdLineArgs);
if (StringsEqual(Args, ConstString("-headless")))
{
Log_Message(GlobalLogBuffer, "Running Headless\n");
Context.Headless = true;
}
if (!Context.Headless)
{
MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents);
Win32UpdateWindowDimension(&MainWindow);
win32_opengl_window_info OpenGLWindowInfo = {};
OpenGLWindowInfo.ColorBits = 32;
OpenGLWindowInfo.AlphaBits = 8;
OpenGLWindowInfo.DepthBits = 0;
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
}
s64 PerformanceCountFrequency = GetPerformanceFrequency();
s64 LastFrameEnd = GetWallClock();
r32 TargetSecondsPerFrame = 1 / 30.0f;
r32 LastFrameSecondsElapsed = 0.0f;
GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services);
#if DEBUG
InitDebugServices_DebugMode(GlobalDebugServices,
PerformanceCountFrequency,
GetWallClock,
Win32GetThreadId,
Context.ThreadContext,
PLATFORM_THREAD_COUNT + 1);
#else
InitDebugServices_OffMode(GlobalDebugServices,
PerformanceCountFrequency,
GetWallClock,
Win32GetThreadId,
Context.ThreadContext,
PLATFORM_THREAD_COUNT + 1);
#endif
input_queue InputQueue = InputQueue_Create(&PlatformPermanent, 32);
Win32WorkQueue_Init(&PlatformPermanent, PLATFORM_THREAD_COUNT);
// Platform functions
Context.GeneralWorkQueue = &Win32WorkQueue.WorkQueue;
Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle;
Context.PlatformGetSocketHandle = Win32GetSocketHandle;
Context.PlatformGetFontInfo = Win32GetFontInfo;
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
Context.ThreadManager = PushStruct(&PlatformPermanent, platform_thread_manager);
*Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread);
Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager);
*Context.SocketManager = CreatePlatformSocketManager(Win32ConnectSocket, Win32CloseSocket, Win32SocketQueryStatus, Win32SocketPeek, Win32SocketReceive, Win32SocketSend);
win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName);
if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true, false)) { return -1; }
Mouse_Init();
Win32SocketSystem_Init(&PlatformPermanent);
Win32SerialArray_Create(&PlatformPermanent);
render_command_buffer RenderBuffer = {};
if (!Context.Headless)
{
RenderBuffer = AllocateRenderCommandBuffer(MB(12), &PlatformPermanent, ThreadContext);
}
addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext);
Context.InitializeApplication(&Context);
system_time StartTime = Win32GetSystemTime();
Running = true;
Context.WindowIsVisible = true;
while (Running)
{
if (GlobalDebugServices->RecordFrames)
{
EndDebugFrame(GlobalDebugServices);
}
DEBUG_TRACK_SCOPE(MainLoop);
{
Context.SystemTime_Last = Context.SystemTime_Current;
Context.SystemTime_Current = Win32GetSystemTime();
#define PRINT_SYSTEM_TIME 0
#if PRINT_SYSTEM_TIME
gs_string T = PushStringF(Context.ThreadContext.Transient,
256,
"%d %d %d - %lld\n",
Context.SystemTime_Current.Hour,
Context.SystemTime_Current.Minute,
Context.SystemTime_Current.Second,
Context.SystemTime_Current.NanosSinceEpoch);
u64 NanosElapsed = Context.SystemTime_Current.NanosSinceEpoch - StartTime.NanosSinceEpoch;
r64 SecondsElapsed = (r64)NanosElapsed * NanosToSeconds;
Log_Message(GlobalLogBuffer,
"%lld %f Seconds \n",
NanosElapsed,
SecondsElapsed);
#endif
}
ResetInputQueue(&InputQueue);
ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false, true);
AddressedDataBufferList_Clear(&OutputData);
if (!Context.Headless)
{
Mouse_Update(MainWindow, &Context);
MSG Message;
while (PeekMessageA(&Message, MainWindow.Handle, 0, 0, PM_REMOVE))
{
DEBUG_TRACK_SCOPE(PeekWindowsMessages);
HandleWindowMessage(Message, &MainWindow, &InputQueue, &Context.Mouse);
}
Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
RenderBuffer.ViewWidth = MainWindow.Width;
RenderBuffer.ViewHeight = MainWindow.Height;
}
Context.DeltaTime = LastFrameSecondsElapsed;
Context.TotalTime += (r64)Context.DeltaTime;
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData);
Win32_SendOutputData(ThreadContext, OutputData);
if (!Context.Headless)
{
RenderCommandBuffer(RenderBuffer);
ClearRenderBuffer(&RenderBuffer);
Mouse_Advance(&Context);
HDC DeviceContext = GetDC(MainWindow.Handle);
SwapBuffers(DeviceContext);
ReleaseDC(MainWindow.Handle, DeviceContext);
}
Win32DoQueueWorkUntilDone(&Win32WorkQueue.WorkQueue, Context.ThreadContext);
s64 FinishedWorkTime = GetWallClock();
r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency);
while (SecondsElapsed < TargetSecondsPerFrame)
{
DEBUG_TRACK_SCOPE(UnusedTime);
u32 SleepTime = 1000.0f * (TargetSecondsPerFrame - SecondsElapsed);
Sleep(SleepTime);
SecondsElapsed = GetSecondsElapsed(LastFrameEnd, GetWallClock(), PerformanceCountFrequency);
}
LastFrameSecondsElapsed = SecondsElapsed;
LastFrameEnd = GetWallClock();
}
Context.CleanupApplication(Context, &OutputData);
Win32_SendOutputData(ThreadContext, OutputData);
Win32DoQueueWorkUntilDone(&Win32WorkQueue.WorkQueue, Context.ThreadContext);
Win32WorkQueue_Cleanup();
Win32SocketSystem_Cleanup();
return 0;
}
#define WIN32_FOLDHAUS_CPP
#endif // WIN32_FOLDHAUS_CPP

View File

@ -1,162 +0,0 @@
//
// File: win32_foldhaus_dll.h
// Author: Peter Slattery
// Creation Date: 2020-02-04
//
//
// NOTE: Relies on having imported foldhaus_platform.h prior to this file
//
#ifndef WIN32_FOLDHAUS_DLL_H
// DLL
struct win32_dll_refresh
{
FILETIME LastWriteTime;
HMODULE DLL;
bool IsValid;
char SourceDLLPath[MAX_PATH];
char WorkingDLLPath[MAX_PATH];
char LockFilePath[MAX_PATH];
};
internal int
Win32DLLgs_stringLength(char* gs_string)
{
char* At = gs_string;
while (*At) { At++; };
return At - gs_string;
}
internal int
Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest)
{
char* Dst = Dest;
char* AAt = A;
int ALengthToCopy = ALength < DestLength ? ALength : DestLength;
for (s32 a = 0; a < ALength; a++)
{
*Dst++ = *AAt++;
}
char* BAt = B;
int DestLengthRemaining = DestLength - (Dst - Dest);
int BLengthToCopy = BLength < DestLengthRemaining ? BLength : DestLength;
for (s32 b = 0; b < BLengthToCopy; b++)
{
*Dst++ = *BAt++;
}
int DestLengthOut = Dst - Dest;
int NullTermIndex = DestLengthOut < DestLength ? DestLengthOut : DestLength;
Dest[NullTermIndex] = 0;
return DestLengthOut;
}
internal void
GetApplicationPath(system_path* Result)
{
Assert(Result->Path);
Result->PathLength = GetModuleFileNameA(0, Result->Path, Result->PathLength);
u32 CharactersScanned = 0;
u32 IndexOfLastSlash = 0;
char *Scan = Result->Path;
while(*Scan)
{
if (*Scan == '\\')
{
Result->IndexOfLastSlash = CharactersScanned + 1;
}
Scan++;
CharactersScanned++;
}
}
internal b32
LoadApplicationDLL(char* DLLName, win32_dll_refresh* DLLResult)
{
b32 Success = false;
Assert(DLLResult->DLL == 0);
DLLResult->DLL = LoadLibraryA(DLLName);
if (DLLResult->DLL)
{
Success = true;
DLLResult->IsValid = true;
}
return Success;
}
internal void
UnloadApplicationDLL(win32_dll_refresh* DLL)
{
if (DLL->DLL)
{
FreeLibrary(DLL->DLL);
}
DLL->DLL = 0;
DLL->IsValid = false;
}
internal win32_dll_refresh
InitializeDLLHotReloading(char* SourceDLLName,
char* WorkingDLLFileName,
char* LockFileName)
{
win32_dll_refresh Result = {};
Result.IsValid = false;
system_path ExePath = {};
ExePath.PathLength = MAX_PATH;
ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
GetApplicationPath(&ExePath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(SourceDLLName), SourceDLLName,
MAX_PATH, Result.SourceDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName,
MAX_PATH, Result.WorkingDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength, 0);
return Result;
}
internal b32
HotLoadDLL(win32_dll_refresh* DLL)
{
b32 DidReload = false;
FILETIME UpdatedLastWriteTime = {};
WIN32_FIND_DATA FindData = {};
HANDLE FileHandle = FindFirstFileA(DLL->SourceDLLPath, &FindData);
if (FileHandle != INVALID_HANDLE_VALUE)
{
UpdatedLastWriteTime = FindData.ftLastWriteTime;
FindClose(FileHandle);
}
if (CompareFileTime(&UpdatedLastWriteTime, &DLL->LastWriteTime))
{
WIN32_FILE_ATTRIBUTE_DATA Ignored;
if (!GetFileAttributesEx(DLL->LockFilePath, GetFileExInfoStandard, &Ignored))
{
UnloadApplicationDLL(DLL);
CopyFileA(DLL->SourceDLLPath, DLL->WorkingDLLPath, FALSE);
LoadApplicationDLL(DLL->WorkingDLLPath, DLL);
DLL->LastWriteTime = UpdatedLastWriteTime;
DidReload = true;
}
}
return DidReload;
}
#define WIN32_FOLDHAUS_DLL_H
#endif // WIN32_FOLDHAUS_DLL_H

View File

@ -1,283 +0,0 @@
//
// File: win32_foldhaus_fileio.h
// Author: Peter Slattery
// Creation Date: 2020-02-04
//
//
// NOTE: Relies on having imported foldhaus_platform.h prior to this file
//
#ifndef WIN32_FOLDHAUS_FILEIO_H
internal u64
Win32HighLowToU64(u32 LowPart, u32 HighPart)
{
ULARGE_INTEGER Time = {};
Time.LowPart = LowPart;
Time.HighPart = HighPart;
u64 Result = Time.QuadPart;
return Result;
}
internal u64
Win32FileTimeToU64(FILETIME FileTime)
{
u64 Result = Win32HighLowToU64(FileTime.dwLowDateTime, FileTime.dwHighDateTime);
return Result;
}
GET_FILE_INFO(Win32GetFileInfo)
{
Assert(IsNullTerminated(Path));
gs_file_info Result = {};
HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
Result.Path = Path;
Result.FileSize = (u64)GetFileSize(FileHandle, NULL) + 1;
FILETIME CreationTime, LastWriteTime;
if (GetFileTime(FileHandle, &CreationTime, (LPFILETIME)0, &LastWriteTime))
{
Result.CreationTime = Win32FileTimeToU64(CreationTime);
Result.LastWriteTime = Win32FileTimeToU64(LastWriteTime);
}
else
{
PrintLastError();
}
CloseHandle(FileHandle);
}
else
{
DWORD FileAttr = GetFileAttributes(Path.Str);
if (FileAttr != INVALID_FILE_ATTRIBUTES &&
(FileAttr & FILE_ATTRIBUTE_DIRECTORY))
{
Result.Path = Path;
Result.IsDirectory = true;
}
else
{
// Path is not a file or directory
}
}
return Result;
}
READ_ENTIRE_FILE(Win32ReadEntireFile)
{
Assert(DataIsNonEmpty(Memory));
Assert(IsNullTerminated(Path));
gs_file Result = {0};
u32 Error = 0;
Result.FileInfo.Path = Path;
HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesRead = 0;
if (ReadFile(FileHandle, (LPVOID)Memory.Memory, Memory.Size - 1, (LPDWORD)(&BytesRead), NULL))
{
Memory.Memory[Memory.Size - 1] = 0;
Result.Data = Memory;
gs_string AbsolutePath = PushString(FileHandler.Transient, 512);
AbsolutePath.Length = GetFullPathNameA(Path.Str, AbsolutePath.Size, AbsolutePath.Str, NULL);
if (AbsolutePath.Length == 0)
{
Error = GetLastError();
InvalidCodePath;
}
Result.FileInfo.AbsolutePath = AbsolutePath.ConstString;
}
else
{
// NOTE(Peter): If we get to this error case, it means that the file exists,
// and was successfully opened, but we can't read from it. I'm choosing to
// treat this as a legitimate error at this point.
gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to read file: %S", Path);
if (MessageBox(NULL, Message.Str, "Error", MB_OK) == IDOK)
{
PostQuitMessage(-1);
}
}
CloseHandle(FileHandle);
}
else
{
}
return Result;
}
WRITE_ENTIRE_FILE(Win32WriteEntireFile)
{
Assert(DataIsNonEmpty(Data));
Assert(IsNullTerminated(Path));
bool Success = false;
HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten = 0;
if (WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL))
{
Success = (BytesWritten == Data.Size);
}
else
{
gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to write to file: %S", Path);
MessageBox(NULL, Message.Str, "Error", MB_OK);
}
CloseHandle(FileHandle);
}
else
{
}
return Success;
}
internal FILETIME
GetFileLastWriteTime(char* Path)
{
FILETIME Result = {};
WIN32_FIND_DATA FindData = {};
HANDLE FileHandle = FindFirstFileA(Path, &FindData);
if (FileHandle != INVALID_HANDLE_VALUE)
{
Result = FindData.ftLastWriteTime;
FindClose(FileHandle);
}
else
{
// TODO(Peter): :ErrorLogging
}
return Result;
}
struct temp_file_list_entry
{
gs_file_info Info;
temp_file_list_entry* Next;
};
struct temp_file_list
{
temp_file_list_entry* First;
temp_file_list_entry* Last;
};
internal void
Win32SetFileInfoFromFindFileData(gs_file_info* Info, WIN32_FIND_DATA FindFileData, gs_const_string SearchPath, gs_memory_arena* Storage)
{
u32 FileNameLength = CharArrayLength(FindFileData.cFileName);
Info->FileSize = Win32HighLowToU64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh);
Info->CreationTime = Win32FileTimeToU64(FindFileData.ftCreationTime);
Info->LastWriteTime = Win32FileTimeToU64(FindFileData.ftLastWriteTime);
Info->IsDirectory = HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
// NOTE(Peter): String Storage
// Storing the string in the final storage means we don't have to copy the string later, and all
// strings will be continguous in memory at the calling site, though they will be before the array
gs_string FileName = PushString(Storage, SearchPath.Length + FileNameLength + 2);
PrintF(&FileName, "%S%.*s", SearchPath, FileName.Size, FindFileData.cFileName);
if (Info->IsDirectory)
{
AppendPrintF(&FileName, "\\");
}
NullTerminate(&FileName);
Info->Path = FileName.ConstString;
}
internal u32
Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list* TempList, gs_const_string Path, gs_memory_arena* Storage, b32 Flags)
{
u32 FilesCount = 0;
Assert(Path.Str[Path.Length - 1] != '\\' &&
Path.Str[Path.Length - 1] != '/');
gs_const_string SearchPath = Path;
gs_const_string SearchPathDir = SearchPath;
s64 LastSlash = FindLastFromSet(SearchPath, "\\/");
if (LastSlash >= 0)
{
SearchPathDir = Substring(SearchPath, 0, LastSlash + 1);
}
WIN32_FIND_DATA FindFileData;
HANDLE SearchHandle = FindFirstFile(Path.Str, &FindFileData);
if (SearchHandle != INVALID_HANDLE_VALUE)
{
do
{
b32 AddFile = true;
if (HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
{
gs_const_string SubDirName = ConstString(FindFileData.cFileName);
bool IsNav = (StringsEqual(SubDirName, ConstString(".")) ||
StringsEqual(SubDirName, ConstString("..")));
if (HasFlag(Flags, EnumerateDirectory_Recurse))
{
if (!IsNav)
{
gs_string SubDirectoryPath = PushString(FileHandler.Transient, SearchPath.Length + SubDirName.Length + 3);
PrintF(&SubDirectoryPath, "%S%S/*\0", SearchPath, SubDirName);
FilesCount += Win32EnumerateDirectoryIntoTempList(FileHandler, TempList, SubDirectoryPath.ConstString,
Storage, Flags);
}
}
AddFile = HasFlag(Flags, EnumerateDirectory_IncludeDirectories);
}
if (AddFile)
{
temp_file_list_entry* File = PushStruct(FileHandler.Transient, temp_file_list_entry);
*File = {0};
Win32SetFileInfoFromFindFileData(&File->Info, FindFileData, SearchPathDir, Storage);
SLLPushOrInit(TempList->First, TempList->Last, File);
FilesCount += 1;
}
}while(FindNextFile(SearchHandle, &FindFileData));
}
else
{
PrintLastError();
}
return FilesCount;
}
ENUMERATE_DIRECTORY(Win32EnumerateDirectory)
{
Assert(IsNullTerminated(Path));
gs_file_info_array Result = {};
temp_file_list TempList = {};
Result.MaxCount = Win32EnumerateDirectoryIntoTempList(FileHandler, &TempList, Path, Storage, Flags);
Result.Values = PushArray(Storage, gs_file_info, Result.MaxCount);
for (temp_file_list_entry* FileAt = TempList.First;
FileAt != 0;
FileAt = FileAt->Next)
{
// NOTE(Peter): We don't copy the file name here because its already in Storage.
// See String Storage note above ^^
Result.Values[Result.Count++] = FileAt->Info;
}
return Result;
}
#define WIN32_FOLDHAUS_FILEIO_H
#endif // WIN32_FOLDHAUS_FILEIO_H

View File

@ -1,26 +0,0 @@
/* date = May 10th 2021 11:48 pm */
#ifndef GS_MEMORY_WIN32_H
#define GS_MEMORY_WIN32_H
PLATFORM_ALLOC(Win32Alloc)
{
u8* Result = (u8*)VirtualAlloc(NULL, Size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if (ResultSize) *ResultSize = Size;
return Result;
}
PLATFORM_FREE(Win32Free)
{
VirtualFree(Base, 0, MEM_RELEASE);
}
internal gs_allocator
CreatePlatformAllocator()
{
return AllocatorCreate(Win32Alloc, Win32Free, 0);
}
#endif //GS_MEMORY_WIN32_H

View File

@ -1,118 +0,0 @@
//
// File: win32_mouse.h
// Author: Peter Slattery
// Creation Date: 2021-01-10
//
#ifndef WIN32_MOUSE_H
HCURSOR CursorArrow;
HCURSOR CursorPointer;
HCURSOR CursorLoading;
HCURSOR CursorHArrows;
HCURSOR CursorVArrows;
HCURSOR CursorDTopLeftArrows;
HCURSOR CursorDTopRightArrows;
HCURSOR CurrentCursor;
// NOTE(Peter): Only meant to take one of the values specified below:
// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM,
// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE,
// IDC_SIZEWE, IDC_UPARROW, IDC_WAIT
internal HCURSOR
Win32LoadSystemCursor(char* CursorIdentifier)
{
u32 Error = 0;
HCURSOR Result = LoadCursorA(NULL, CursorIdentifier);
if (Result == NULL)
{
Error = GetLastError();
InvalidCodePath;
}
return Result;
}
internal void
Mouse_Init()
{
CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
CursorPointer = Win32LoadSystemCursor(IDC_HAND);
CursorLoading = Win32LoadSystemCursor(IDC_WAIT);
CursorHArrows = Win32LoadSystemCursor(IDC_SIZEWE);
CursorVArrows = Win32LoadSystemCursor(IDC_SIZENS);
CursorDTopLeftArrows = Win32LoadSystemCursor(IDC_SIZENWSE);
CursorDTopRightArrows = Win32LoadSystemCursor(IDC_SIZENESW);
}
internal void
Mouse_Update(window Window, context* Context)
{
POINT Pos;
GetCursorPos (&Pos);
ScreenToClient(Window.Handle, &Pos);
Context->Mouse.Scroll = 0;
Context->Mouse.OldPos = Context->Mouse.Pos;
Context->Mouse.Pos = v2{(r32)Pos.x, (r32)Window.Height - Pos.y};
Context->Mouse.DeltaPos = Context->Mouse.Pos - Context->Mouse.OldPos;
if (KeyIsDown(Context->Mouse.LeftButtonState))
{
SetKeyWasDown(Context->Mouse.LeftButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.LeftButtonState);
}
if (KeyIsDown(Context->Mouse.MiddleButtonState))
{
SetKeyWasDown(Context->Mouse.MiddleButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.MiddleButtonState);
}
if (KeyIsDown(Context->Mouse.RightButtonState))
{
SetKeyWasDown(Context->Mouse.RightButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.RightButtonState);
}
}
internal void
Mouse_Advance(context* Context)
{
Context->Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context->Mouse.LeftButtonState);
Context->Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context->Mouse.MiddleButtonState);
Context->Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context->Mouse.RightButtonState);
HCURSOR NewCursor = 0;
switch (Context->Mouse.CursorType)
{
case CursorType_Arrow: { NewCursor = CursorArrow; } break;
case CursorType_Pointer: { NewCursor = CursorPointer; }break;
case CursorType_Loading: { NewCursor = CursorLoading; }break;
case CursorType_HArrows: { NewCursor = CursorHArrows; }break;
case CursorType_VArrows: { NewCursor = CursorVArrows; }break;
case CursorType_DTopLeftArrows: { NewCursor = CursorDTopLeftArrows; }break;
case CursorType_DTopRightArrows: { NewCursor = CursorDTopRightArrows; }break;
InvalidDefaultCase;
}
if (NewCursor != CurrentCursor)
{
CurrentCursor = NewCursor;
SetCursor(NewCursor);
}
}
#define WIN32_MOUSE_H
#endif // WIN32_MOUSE_H

View File

@ -1,380 +0,0 @@
//
// File: win32_serial.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef WIN32_SERIAL_H
global u32 Win32SerialHandlesCountMax;
global HANDLE* Win32SerialHandles;
global gs_string* Win32SerialPortNames;
global s32* Win32SerialPortFilled;
DCB
Win32SerialPort_GetState(HANDLE ComPortHandle)
{
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = {0};
ZeroStruct(&ControlSettings);
ControlSettings.DCBlength = sizeof(ControlSettings);
bool Success = GetCommState(ComPortHandle, &ControlSettings);
Assert(Success);
return ControlSettings;
}
void
Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits)
{
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = Win32SerialPort_GetState(ComPortHandle);
// TODO(pjs): Validate BaudRate - There's only certain rates that are valid right?
ControlSettings.BaudRate = BaudRate;
if (Parity == NOPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 0;
}
if (Parity == EVENPARITY || Parity == ODDPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 1;
}
ControlSettings.StopBits = StopBits;
ControlSettings.ByteSize = ByteSize;
ControlSettings.fBinary = true;
ControlSettings.fOutxCtsFlow = false;
ControlSettings.fOutxDsrFlow = false;
ControlSettings.fDtrControl = DTR_CONTROL_DISABLE;
ControlSettings.fDsrSensitivity = 0;
ControlSettings.fRtsControl = RTS_CONTROL_DISABLE;
ControlSettings.fOutX = false;
ControlSettings.fInX = false;
ControlSettings.fErrorChar = 0;
ControlSettings.fNull = false;
ControlSettings.fAbortOnError = false;
ControlSettings.wReserved = false;
ControlSettings.XonLim = 2;
ControlSettings.XoffLim = 4;
ControlSettings.XonChar = 0x13;
ControlSettings.XoffChar = 0x19;
ControlSettings.EvtChar = 0;
bool Success = SetCommState(ComPortHandle, &ControlSettings);
}
gs_const_string_array
Win32SerialPorts_List(gs_memory_arena* Arena, gs_memory_arena* Transient)
{
gs_const_string_array Result = {};
DWORD SizeNeeded0 = 0;
DWORD CountReturned0 = 0;
EnumPorts(NULL, 1, 0, 0, &SizeNeeded0, &CountReturned0);
Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
DWORD SizeNeeded1 = 0;
DWORD CountReturned1 = 0;
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0).Memory;
if (EnumPorts(NULL,
1,
(u8*)PortsArray,
SizeNeeded0,
&SizeNeeded1,
&CountReturned1))
{
Result.CountMax = (u64)CountReturned1;
Result.Strings = PushArray(Arena, gs_const_string, Result.CountMax);
for (; Result.Count < Result.CountMax; Result.Count++)
{
u64 Index = Result.Count;
u64 StrLen = CStringLength(PortsArray[Index].pName);
gs_string Str = PushString(Arena, StrLen);
PrintF(&Str, "%.*s", StrLen, PortsArray[Index].pName);
Result.Strings[Result.Count] = Str.ConstString;
}
}
return Result;
}
bool
Win32SerialPort_Exists(char* PortName, gs_memory_arena* Transient)
{
bool Result = false;
if (PortName != 0)
{
gs_const_string PortIdent = ConstString(PortName);
u32 IdentBegin = FindLast(PortIdent, '\\') + 1;
PortIdent = Substring(PortIdent, IdentBegin, PortIdent.Length);
gs_const_string_array PortsAvailable = Win32SerialPorts_List(Transient, Transient);
for (u64 i = 0; i < PortsAvailable.Count; i++)
{
gs_const_string AvailablePortName = PortsAvailable.Strings[i];
if (StringsEqualUpToLength(AvailablePortName, PortIdent, PortIdent.Length))
{
Result = true;
break;
}
}
}
return Result;
}
HANDLE
Win32SerialPort_Open(char* PortName, gs_memory_arena* Transient)
{
DEBUG_TRACK_FUNCTION;
HANDLE ComPortHandle = INVALID_HANDLE_VALUE;;
if (Win32SerialPort_Exists(PortName, Transient))
{
ComPortHandle = CreateFile(PortName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // Default Security Attr
OPEN_EXISTING,
0, // Not overlapped I/O
NULL);
bool HasError = false;
if (ComPortHandle != INVALID_HANDLE_VALUE)
{
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadIntervalTimeout = 0; // in milliseconds
Timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds
Timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds
Timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds
Timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds
HasError = !SetCommTimeouts(ComPortHandle, &Timeouts);
}
else
{
HasError = true;
}
if (HasError)
{
// Error
s32 Error = GetLastError();
switch (Error)
{
case ERROR_INVALID_FUNCTION:
case ERROR_NO_SUCH_DEVICE:
case ERROR_FILE_NOT_FOUND:
{
// NOTE(PS): The outer scope should handle these cases
ComPortHandle = INVALID_HANDLE_VALUE;
}break;
InvalidDefaultCase;
}
}
}
return ComPortHandle;
}
void
Win32SerialPort_Close(HANDLE PortHandle)
{
CloseHandle(PortHandle);
}
bool
Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
{
DEBUG_TRACK_FUNCTION;
Assert(PortHandle != INVALID_HANDLE_VALUE);
bool Success = false;
DWORD BytesWritten = 0;
if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL))
{
Success = (BytesWritten == Buffer.Size);
if (!Success)
{
Log_Error(GlobalLogBuffer, "Error: Entire buffer not written.\n");
}
}
else
{
Log_Error(GlobalLogBuffer, "Error: Unable to write to port\n");
s32 Error = GetLastError();
switch (Error)
{
case ERROR_OPERATION_ABORTED:
case ERROR_GEN_FAILURE:
{
// NOTE(pjs): Probably means that the serial port became invalid
// ie. the usb stick was removed
}break;
case ERROR_ACCESS_DENIED:
{
// ??
}break;
case ERROR_NO_SUCH_DEVICE:
{
}break;
case ERROR_INVALID_HANDLE:
InvalidDefaultCase;
}
}
return Success;
}
bool
Win32SerialPort_SetRead(HANDLE PortHandle)
{
bool Status = SetCommMask(PortHandle, EV_RXCHAR);
return Status;
}
u32
Win32SerialPort_ReadMessageWhenReady(HANDLE PortHandle, gs_data Data)
{
u32 ReadSize = 0;
DWORD EventMask = 0;
bool Status = WaitCommEvent(PortHandle, &EventMask, NULL);
if (Status)
{
DWORD NoBytesRead = 0;
do
{
u8 Byte = 0;
Status = ReadFile(PortHandle, &Byte, sizeof(char), &NoBytesRead, NULL);
Data.Memory[ReadSize] = Byte;
ReadSize++;
}
while (NoBytesRead > 0 && ReadSize < Data.Size);
}
//Read data and store in a buffer
return ReadSize;
}
/////////////////////////
// Win32SerialArray
void
Win32SerialArray_Create(gs_memory_arena* A)
{
DEBUG_TRACK_FUNCTION;
Win32SerialHandlesCountMax = 32;
Win32SerialHandles = PushArray(A, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = PushArray(A, gs_string, Win32SerialHandlesCountMax);
Win32SerialPortFilled = PushArray(A, s32, Win32SerialHandlesCountMax);
u64 PortNameSize = 256;
u64 PortNameBufferSize = PortNameSize * Win32SerialHandlesCountMax;
char* PortNameBuffer = PushArray(A, char, PortNameBufferSize);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
char* NameBase = PortNameBuffer + (PortNameSize * i);
Win32SerialPortNames[i] = MakeString(NameBase, 0, PortNameSize);
Win32SerialPortFilled[i] = 0;
}
}
void
Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
bool Found = false;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + i, 1, 0);
if (!WasFilled)
{
Win32SerialHandles[i] = SerialHandle;
PrintF(&Win32SerialPortNames[i], "%S", PortName);
Found = true;
break;
}
}
Assert(Found);
}
void
Win32SerialArray_Pop(u32 Index)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + Index, 0, 1);
Assert(WasFilled);
Win32SerialPortFilled[Index] = false;
Win32SerialHandles[Index] = INVALID_HANDLE_VALUE;
}
HANDLE
Win32SerialArray_Get(gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (Win32SerialPortFilled[i] &&
StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
PortHandle = Win32SerialHandles[i];
break;
}
}
return PortHandle;
}
HANDLE
Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits, gs_memory_arena* Transient)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = Win32SerialArray_Get(PortName);
if (PortHandle == INVALID_HANDLE_VALUE)
{
Assert(IsNullTerminated(PortName));
PortHandle = Win32SerialPort_Open(PortName.Str, Transient);
if (PortHandle != INVALID_HANDLE_VALUE)
{
Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits);
Win32SerialArray_Push(PortHandle, PortName);
}
}
return PortHandle;
}
void
Win32SerialArray_Close(gs_const_string PortName)
{
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (Win32SerialPortFilled[i] && StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
Win32SerialPort_Close(Win32SerialHandles[i]);
Win32SerialArray_Pop(i);
break;
}
}
}
#define WIN32_SERIAL_H
#endif // WIN32_SERIAL_H

View File

@ -1,539 +0,0 @@
//
// File: win32_foldhaus_socket.h
// Author: Peter Slattery
// Creation Date: 2020-10-03
//
#ifndef WIN32_FOLDHAUS_SOCKET_H
struct win32_socket
{
SOCKET Socket;
};
struct win32_socket_array
{
win32_socket* Values;
s32 CountMax;
s32 Count;
};
global WSADATA WSAData;
global win32_socket_array Win32Sockets;
//////////////////////
//
// Win32 Socket Array
internal win32_socket_array
Win32SocketArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
win32_socket_array Result = {};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, win32_socket, CountMax);
return Result;
}
internal s32
Win32SocketArray_Take(win32_socket_array* Array)
{
Assert(Array->Count < Array->CountMax);
s32 Result = Array->Count++;
win32_socket* Socket = Array->Values + Result;
*Socket = {0};
return Result;
}
internal win32_socket*
Win32SocketArray_Get(win32_socket_array Array, s32 Index)
{
Assert(Index < Array.Count);
win32_socket* Result = Array.Values + Index;
return Result;
}
//////////////////////
//
// Win32 Sockets
internal win32_socket
Win32Socket_Create(s32 AddressFamily, s32 Type, s32 Protocol)
{
win32_socket Result = {0};
Result.Socket = socket(AddressFamily, Type, Protocol);
if (Result.Socket == INVALID_SOCKET)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
return Result;
}
internal void
Win32Socket_Bind(win32_socket* Socket, s32 AddressFamily, char* Address, s32 Port)
{
sockaddr_in Service = {0};
Service.sin_family = AddressFamily;
Service.sin_addr.s_addr = inet_addr(Address);
Service.sin_port = htons(Port);
s32 Result = bind(Socket->Socket, (SOCKADDR*)&Service, sizeof(Service));
if (Result == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
}
internal win32_socket
Win32Socket_ConnectToAddress(char* Address, char* DefaultPort)
{
win32_socket Result = {};
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Address, DefaultPort, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
win32_socket Socket = Win32Socket_Create(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (Socket.Socket == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
Error = connect(Socket.Socket, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
closesocket(Socket.Socket);
continue;
}
else
{
Result = Socket;
break;
}
}
}
else
{
Error = WSAGetLastError();
InvalidCodePath;
}
freeaddrinfo(PotentialConnections);
return Result;
}
internal bool
Win32ConnectSocket(platform_socket_manager* Manager, platform_socket* Socket)
{
bool Result = false;
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Socket->Addr, Socket->Port, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
SOCKET SocketHandle = socket(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (SocketHandle == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
// If iMode == 0, blocking is enabled
// if iMode != 0, non-blocking mode is enabled
u_long iMode = 0;
Error = ioctlsocket(SocketHandle, FIONBIO, &iMode);
if (Error != NO_ERROR)
{
InvalidCodePath;
}
Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
u32 Status = WSAGetLastError();
if (Status == WSAEWOULDBLOCK)
{
// Non-blocking sockets
#if 0
TIMEVAL Timeout = { 0, 500 };
fd_set SocketSet = {};
FD_ZERO(&SocketSet);
FD_SET(SocketHandle, &SocketSet);
Assert(FD_ISSET(SocketHandle, &SocketSet));
Status = select(0, &SocketSet, 0, 0, (const TIMEVAL*)&Timeout);
if (Status == SOCKET_ERROR)
{
}
else if (Status == 0)
{
}
else
{
}
#endif
}
else
{
closesocket(SocketHandle);
continue;
}
}
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0, 0);
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
Result = true;
break;
}
}
else
{
Error = WSAGetLastError();
InvalidCodePath;
}
if (!Result)
{
Assert(Socket->PlatformHandle == 0);
}
freeaddrinfo(PotentialConnections);
return Result;
}
internal bool
Win32CloseSocket(platform_socket_manager* Manager, platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
closesocket(*Win32Sock);
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET), 0);
*Socket = {};
return true;
}
internal bool
Win32SocketQueryStatus(platform_socket_manager* Manager, platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
bool Result = (*Win32Sock != INVALID_SOCKET);
return Result;
}
internal u32
Win32SocketPeek(platform_socket_manager* Manager, platform_socket* Socket)
{
u32 Result = 0;
s32 Flags = MSG_PEEK;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
char Temp[4];
u32 TempSize = 4;
//Log_Message(GlobalLogBuffer, "Pre Peek...");
//s32 BytesQueued = recv(*Win32Sock, Temp, TempSize, Flags);
u_long BytesQueued = 0;
ioctlsocket(*Win32Sock, FIONREAD, &BytesQueued);
//Log_Message(GlobalLogBuffer, "Post Peek\n");
if (BytesQueued != SOCKET_ERROR)
{
Result = (u32)BytesQueued;
}
else
{
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAEWOULDBLOCK:
{
// NOTE(PS): This case covers non-blocking sockets
// if we peek and there's nothing there, it returns
// this error code. MSDN says its a non-fatal error
// and the operation should be retried later
Result = 0;
} break;
case WSAENOTCONN:
case WSAECONNRESET:
case WSAECONNABORTED:
{
CloseSocket(Manager, Socket);
}break;
InvalidDefaultCase;
}
}
return (s32)Result;
}
internal gs_data
Win32SocketReceive(platform_socket_manager* Manager, platform_socket* Socket, gs_memory_arena* Storage)
{
// TODO(pjs): Test this first code path when you have data running - it should
// get the actual size of the data packet being sent
#if 0
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
Result.Size = BytesReceived;
return Result;
#endif
}
internal s32
Win32SocketSend(platform_socket_manager* Manager, platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(*Win32Sock, (char*)Data.Memory, Data.Size, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
//Log_Message(GlobalLogBuffer, "Attempting To Send Network Data: ");
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAEWOULDBLOCK:
{
// NOTE(PS): This covers non-blocking sockets
// In this case the message should be tried again
LengthSent = 0;
//Log_Message(GlobalLogBuffer, "Not sent, buffered\n");
}break;
case WSAECONNABORTED:
case WSAENETUNREACH:
case WSAECONNRESET:
case WSAENOTCONN:
{
if (CloseSocket(Manager, Socket))
{
Log_Error(GlobalLogBuffer, "Error: %d\n", Error);
Error = 0;
}
}break;
InvalidDefaultCase;
}
}
else
{
Log_Message(GlobalLogBuffer, "Sent\n");
}
return LengthSent;
}
internal s32
Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
int Error = setsockopt(Socket->Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
}
internal s32
Win32Socket_SetOption(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength);
}
internal s32
Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(Socket->Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAENETUNREACH:
{
Log_Message(GlobalLogBuffer,
"Non Critical Error: WSAENETUNREACH \n");
} break;
default:
{
Log_Error(GlobalLogBuffer, "Error: %d \n", Error);
InvalidCodePath;
} break;
}
}
return LengthSent;
}
internal void
Win32Socket_SetListening(win32_socket* Socket)
{
if (listen(Socket->Socket, SOMAXCONN) == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
}
internal s32
Win32Socket_PeekGetTotalSize(win32_socket* Socket)
{
s32 Flags = MSG_PEEK;
char Temp[4];
s32 BytesQueued = recv(Socket->Socket, Temp, 4, Flags);
if (BytesQueued == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
BytesQueued = 0;
}
return BytesQueued;
}
internal gs_data
Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage)
{
#if 0
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAECONNABORTED:
case WSANOTINITIALISED:
break;
case WSAENOTCONN:
{
}break;
InvalidDefaultCase;
}
}
Result.Size = BytesReceived;
return Result;
#endif
}
internal void
Win32Socket_Close(win32_socket* Socket)
{
closesocket(Socket->Socket);
Socket->Socket = INVALID_SOCKET;
}
internal void
Win32Socket_CloseArray(win32_socket_array Array)
{
for (s32 i = 0; i < Array.Count; i++)
{
win32_socket* Socket = Array.Values + i;
Win32Socket_Close(Socket);
}
}
//////////////////////
//
// Win32 Socket System
internal void
Win32SocketSystem_Init(gs_memory_arena* Arena)
{
WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, Arena);
}
internal void
Win32SocketSystem_Cleanup()
{
Win32Socket_CloseArray(Win32Sockets);
s32 CleanupResult = 0;
do {
CleanupResult = WSACleanup();
}while(CleanupResult == SOCKET_ERROR);
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
s32 Result = Win32SocketArray_Take(&Win32Sockets);
s32 Error = 0;
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result);
*Socket = Win32Socket_Create(AF_INET, SOCK_DGRAM, 0);
Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
return (platform_socket_handle)Result;
}
#define WIN32_FOLDHAUS_SOCKET_H
#endif // WIN32_FOLDHAUS_SOCKET_H

View File

@ -1,46 +0,0 @@
//
// File: win32_foldhaus_timing.h
// Author: Peter Slattery
// Creation Date: 2020-02-04
//
//
// NOTE: Relies on having imported foldhaus_platform.h prior to this file
//
#ifndef WIN32_FOLDHAUS_TIMING_H
internal s64
GetPerformanceFrequency ()
{
LARGE_INTEGER Frequency;
if (!QueryPerformanceFrequency(&Frequency))
{
s32 Error = GetLastError();
// TODO(Peter): I'm waiting to see an error actually occur here
// to know what it could possibly be.
InvalidCodePath;
}
return (s64)Frequency.QuadPart;
}
internal s64
GetWallClock ()
{
#if 0
s64 Result = __rdtsc();
return Result;
#else
LARGE_INTEGER Time;
if (!QueryPerformanceCounter(&Time))
{
s32 Error = GetLastError();
// TODO(Peter): I'm waiting to see an error actually occur here
// to know what it could possibly be.
InvalidCodePath;
}
return (s64)Time.QuadPart;
#endif
}
#define WIN32_FOLDHAUS_TIMING_H
#endif // WIN32_FOLDHAUS_TIMING_H

View File

@ -1,73 +0,0 @@
//
// File: win32_foldhaus_utils.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef WIN32_FOLDHAUS_UTILS_H
internal gs_string
Win32DumpErrorAndPrepareMessageBoxString(gs_memory_arena* Arena, char* Format, ...)
{
s32 Error = GetLastError();
gs_string ErrorDump = PushString(Arena, 4096);
PrintF(&ErrorDump,
R"FOO(Win32 Error: %s\n
Error Code: %d\n
)FOO",
__FUNCTION__,
Error);
va_list Args;
va_start(Args, Format);
PrintFArgsList(&ErrorDump, Format, Args);
va_end(Args);
gs_data ErrorDumpData = StringToData(ErrorDump);
HANDLE FileHandle = CreateFileA("./crashdump.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten = 0;
if (WriteFile(FileHandle, ErrorDumpData.Memory, ErrorDumpData.Size, &BytesWritten, NULL))
{
}
CloseHandle(FileHandle);
}
AppendPrintF(&ErrorDump, "Program will attempt to continue. See crashdump.txt for info");
NullTerminate(&ErrorDump);
return ErrorDump;
}
DEBUG_PRINT(Win32DebugPrint)
{
Log_Message(GlobalLogBuffer, "%S", Message);
}
#define PrintLastError() PrintLastError_(__FILE__, __LINE__)
internal void
PrintLastError_(char* File, u32 Line)
{
char DebugStringData[256];
gs_string DebugString = MakeString(DebugStringData, 0, 256);
u32 Error = GetLastError();
Log_Error(GlobalLogBuffer, "%s Line %d: Win32 Error %d\n\0", File, Line, Error);
}
internal HINSTANCE
GetHInstance()
{
HINSTANCE Result = GetModuleHandle(NULL);
if (Result == NULL)
{
PrintLastError();
}
return Result;
}
#define WIN32_FOLDHAUS_UTILS_H
#endif // WIN32_FOLDHAUS_UTILS_H

View File

@ -1,250 +0,0 @@
//
// File: win32_foldhaus_work_queue.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef WIN32_FOLDHAUS_WORK_QUEUE_H
struct worker_thread_entry
{
b32 IsValid;
u32 Index;
};
struct worker_thread_info
{
gs_thread_context ThreadContext;
HANDLE Handle;
gs_work_queue* Queue;
};
struct win32_work_queue
{
u32 ThreadCount;
worker_thread_info* Threads;
gs_work_queue WorkQueue;
};
worker_thread_info* WorkerThreads;
win32_work_queue Win32WorkQueue;
internal s32
Win32GetThreadId()
{
s32 Result = GetCurrentThreadId();
return Result;
}
internal gs_thread_context
Win32CreateThreadContext(gs_memory_arena* Transient = 0)
{
gs_thread_context Result = {0};
Result.ThreadInfo.ThreadID = Win32GetThreadId();
Result.Allocator = CreatePlatformAllocator();
if (Transient != 0)
{
Result.Transient = Transient;
}
else
{
Result.Transient = AllocStruct(Result.Allocator, gs_memory_arena, "Work Queue");
*Result.Transient = MemoryArenaCreate(MB(4), Bytes(8), Result.Allocator, 0, 0, "Tctx Transient");
}
Result.FileHandler = CreateFileHandler(Win32GetFileInfo,
Win32ReadEntireFile,
Win32WriteEntireFile,
Win32EnumerateDirectory,
Result.Transient);
Result.DebugOutput.Print = Win32DebugPrint;
return Result;
}
PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue)
{
#if DEBUG
// NOTE(Peter): Just prints out the names of all the pending jobs if we end up
// overflowing the buffer
if (Queue->JobsCount >= Queue->JobsMax)
{
gs_string DebugString = MakeString((char*)malloc(256), 256);
for (u32 i = 0; i < Queue->JobsCount; i++)
{
Log_Message(GlobalLogBuffer, "%d %s \n", i, Queue->Jobs[i].JobName);
}
}
#endif
Assert(Queue->JobsCount < Queue->JobsMax);
gs_threaded_job* Job = Queue->Jobs + Queue->JobsCount;
Job->WorkProc = WorkProc;
Job->Data = Data;
#if DEBUG
Job->JobName = JobName;
#endif
// Complete Past Writes before Future Writes
_WriteBarrier();
_mm_sfence();
++Queue->JobsCount;
ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0);
}
internal worker_thread_entry
CompleteAndTakeNextJob(gs_work_queue* Queue, worker_thread_entry Completed, gs_thread_context Context)
{
if (Completed.IsValid)
{
InterlockedIncrement((LONG volatile*)&Queue->JobsCompleted);
}
worker_thread_entry Result = {};
Result.IsValid = false;
u32 OriginalNextJobIndex = Queue->NextJobIndex;
while (OriginalNextJobIndex < Queue->JobsCount)
{
u32 Index = InterlockedCompareExchange((LONG volatile*)&Queue->NextJobIndex,
OriginalNextJobIndex + 1,
OriginalNextJobIndex);
if (Index == OriginalNextJobIndex)
{
Result.Index = Index;
Result.IsValid = true;
break;
}
OriginalNextJobIndex = Queue->NextJobIndex;
}
return Result;
}
COMPLETE_QUEUE_WORK(Win32DoQueueWorkUntilDone)
{
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (Queue->JobsCompleted < Queue->JobsCount)
{
Entry = CompleteAndTakeNextJob(Queue, Entry, Context);
if (Entry.IsValid)
{
Queue->Jobs[Entry.Index].WorkProc(Context, Queue->Jobs[Entry.Index].Data);
}
}
}
DWORD WINAPI
WorkerThreadProc (LPVOID InputThreadInfo)
{
worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo;
ThreadInfo->ThreadContext = Win32CreateThreadContext();
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (true)
{
MemoryArenaClear(ThreadInfo->ThreadContext.Transient);
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext);
if (Entry.IsValid)
{
ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ThreadContext,
ThreadInfo->Queue->Jobs[Entry.Index].Data);
}
else
{
WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0);
}
}
return 0;
}
DWORD WINAPI
Win32ThreadProcWrapper(LPVOID ThreadInfo)
{
platform_thread* Thread = (platform_thread*)ThreadInfo;
gs_thread_context Ctx = Win32CreateThreadContext();
Thread->Proc(&Ctx, Thread->UserData);
// TODO(pjs): Destroy Thread Context
// TODO(pjs): How do we notify the thread manager this thread belongs to that it is free?
// Probaby put a pointer to the thread manager in the platform_thread struct
// so we can update the tracking structure?
return 0;
}
CREATE_THREAD(Win32CreateThread)
{
Thread->Proc = Proc;
Thread->UserData = UserData;
// TODO(pjs): ugh, allocation out in the middle of nowhere
HANDLE* ThreadHandle = AllocStruct(Ctx.Allocator, HANDLE, "Create Thread");
*ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0);
// TODO(pjs): Error checking on the created thread
Thread->PlatformHandle = (u8*)ThreadHandle;
return true;
}
KILL_THREAD(Win32KillThread)
{
HANDLE* ThreadHandle = (HANDLE*)Thread->PlatformHandle;
TerminateThread(ThreadHandle, 0);
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE), 0);
// TODO(pjs): Error checking
return true;
}
internal void
Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount)
{
if (ThreadCount > 0)
{
Win32WorkQueue.ThreadCount = ThreadCount;
Win32WorkQueue.Threads = PushArray(Arena, worker_thread_info, ThreadCount);
}
gs_work_queue WQ = {};
WQ.SemaphoreHandle = CreateSemaphoreEx(0, 0, ThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);;
WQ.JobsMax = 512;
WQ.Jobs = PushArray(Arena, gs_threaded_job, WQ.JobsMax);
WQ.NextJobIndex = 0;
WQ.PushWorkOnQueue = Win32PushWorkOnQueue;
WQ.CompleteQueueWork = Win32DoQueueWorkUntilDone;
Win32WorkQueue.WorkQueue = WQ;
// ID = 0 is reserved for this thread
for (u32 i = 0; i < ThreadCount; i++)
{
worker_thread_info* T = Win32WorkQueue.Threads + i;
T->Queue = &Win32WorkQueue.WorkQueue;
T->Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)T, 0, 0);
}
}
internal void
Win32WorkQueue_Cleanup()
{
u32 Error = 0;
for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++)
{
u32 Success = TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0);
if (!Success)
{
Error = GetLastError();
InvalidCodePath;
}
}
}
#define WIN32_FOLDHAUS_WORK_QUEUE_H
#endif // WIN32_FOLDHAUS_WORK_QUEUE_H

View File

@ -1,86 +0,0 @@
//
// File: win32_test_code.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-10
//
#ifndef WIN32_TEST_CODE_CPP
#if 0
internal void
Win32_TestCode_UART(gs_thread_context ThreadContext)
{
u32 LedCount = 48;
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
MessageBaseSize += sizeof(u8) * 3 * LedCount;
gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient);
gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer);
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < LedCount; i++)
{
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
OutputPixel[Channel->RedIndex] = (u8)(i);
OutputPixel[Channel->GreenIndex] = 0;
OutputPixel[Channel->BlueIndex] = 0;
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
#endif
win32_socket ListenSocket;
HANDLE ListenThread;
DWORD WINAPI
Win32_TestCode_ListenThreadProc(LPVOID ThreadData)
{
gs_thread_context Ctx = Win32CreateThreadContext();
temp_job_req* Req = (temp_job_req*)ThreadData;
while (true)
{
Req->Proc(&Ctx, Req->Memory);
}
}
internal void
Win32_TestCode_SocketReading(gs_thread_context ThreadContext, temp_job_req* Req)
{
ListenSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185");
u8* Arg = (u8*)Req;
ListenThread = CreateThread(0, 0, &Win32_TestCode_ListenThreadProc, Arg, 0, 0);
}
internal void
BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData)
{
packet_ringbuffer* MicPacketBuffer = (packet_ringbuffer*)UserData;
gs_data Data = Win32Socket_Receive(&ListenSocket, Ctx->Transient);
if (Data.Size > 0)
{
OutputDebugStringA("Listened");
MicPacketBuffer->Values[MicPacketBuffer->WriteHead++] = Data;
if (MicPacketBuffer->WriteHead >= PACKETS_MAX)
{
MicPacketBuffer->WriteHead = 0;
}
}
}
internal void
Win32_TestCode_SocketReading_Cleanup()
{
TerminateThread(ListenThread, 0);
Win32Socket_Close(&ListenSocket);
}
#define WIN32_TEST_CODE_CPP
#endif // WIN32_TEST_CODE_CPP

File diff suppressed because it is too large Load Diff

View File

@ -1,393 +0,0 @@
//
// File: blumen_lumen.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef BLUMEN_LUMEN_H
#include "message_queue.h"
enum bl_debug_ui_mode
{
BlumenDebug_Motors,
BlumenDebug_Leds,
BlumenDebug_Awaken,
BlumenDebug_Count,
};
char* BlDebugUiModeStrings[] = {
"Motors",
"Leds",
"Awaken",
};
enum bl_pattern_mode
{
BlumenPattern_Standard,
BlumenPattern_VoiceCommand,
BlumenPattern_NoControl,
BlumenPattern_Count,
};
enum bl_python_packet_type
{
PacketType_Invalid = 0,
PacketType_PatternCommand = 1,
PacketType_MotorState = 2,
PacketType_Temperature = 3,
PacketType_LumenariumStatus = 4,
};
enum bl_motor_state_value
{
MotorState_Invalid = 0,
MotorState_Closed = 1,
MotorState_Open = 2,
MotorState_HalfOpen = 3,
MotorState_MostlyOpen = 4,
};
#pragma pack(push, 1)
typedef struct motor_packet
{
u8 FlowerPositions[3];
} motor_packet;
typedef struct motor_status_packet
{
motor_packet Pos;
u8 MotorStatus[3];
u16 Temperature;
} motor_status_packet;
typedef struct microphone_packet
{
b8 ChangeAnimation;
char AnimationFileName[32];
b8 SetLayer;
char LayerName[32];
r32 LayerOpacity;
b8 SetLayerParamColor;
char LayerParamColor[7];
r32 OverrideDuration;
} microphone_packet;
typedef struct temp_packet
{
s8 Temperature;
} temp_packet;
enum motor_event_type
{
MotorEvent_Close = 0,
MotorEvent_Open = 1,
};
typedef struct status_packet
{
u8 NextMotorEventType;
// u16 Padding;
u32 NextEventTime;
char AnimFileName[32];
} status_packet;
typedef struct blumen_packet
{
u8 Type;
union
{
motor_packet MotorPacket;
motor_status_packet MotorStatusPacket;
microphone_packet MicPacket;
temp_packet TempPacket;
status_packet StatusPacket;
};
} blumen_packet;
#pragma pack(pop)
// TODO(pjs): Refactor this -> blumen_network_job_state
struct mic_listen_job_data
{
bool* Running;
platform_socket_manager* SocketManager;
blumen_network_msg_queue* IncomingMsgQueue;
blumen_network_msg_queue* OutgoingMsgQueue;
// Status
bool IsConnected;
};
typedef struct time_range
{
s32 StartHour;
s32 StartMinute;
s32 EndHour;
s32 EndMinute;
} time_range;
internal bool
SystemTimeIsBeforeTime(system_time SysTime, s32 Hour, s32 Minute)
{
bool Result = false;
if (SysTime.Hour == Hour) {
Result = SysTime.Minute < Minute;
} else {
Result = SysTime.Hour < Hour;
}
return Result;
}
internal bool
SystemTimeIsAfterTime(system_time SysTime, s32 Hour, s32 Minute)
{
bool Result = false;
if (SysTime.Hour == Hour) {
Result = SysTime.Minute >= Minute;
} else {
Result = SysTime.Hour > Hour;
}
return Result;
}
internal bool
SystemTimeIsInTimeRange(system_time SysTime, time_range Range)
{
bool Result = false;
bool IsAfterStartTime = SystemTimeIsAfterTime(SysTime, Range.StartHour, Range.StartMinute);
bool IsBeforeEndTime = SystemTimeIsBeforeTime(SysTime, Range.EndHour, Range.EndMinute);
Result = IsAfterStartTime && IsBeforeEndTime;
return Result;
}
internal bool
SystemTimeIsInTimeRangeList(system_time SysTime, time_range* Ranges, u32 RangesCount, time_range* RangeOut = 0)
{
bool Result = false;
for (u32 i = 0; i < RangesCount; i++)
{
time_range Range = Ranges[i];
bool CurrTimeInRange = SystemTimeIsInTimeRange(SysTime, Range);
if (CurrTimeInRange)
{
Result = true;
if (RangeOut != 0) {
*RangeOut = Range;
}
break;
}
}
return Result;
}
#include "blumen_lumen_settings.h"
struct blumen_lumen_state
{
bool Running;
blumen_network_msg_queue IncomingMsgQueue;
blumen_network_msg_queue OutgoingMsgQueue;
temp_job_req JobReq;
led_strip_list StemStrips[BL_FLOWER_COUNT];
platform_thread_handle MicListenThread;
mic_listen_job_data MicListenJobData;
motor_packet LastKnownMotorState;
u64 LastTimeMotorStateChanged[BL_FLOWER_COUNT];
b8 ShouldDimUpperLeds[BL_FLOWER_COUNT];
// NOTE(pjs): Based on temperature data from weatherman
// dim the leds.
r32 BrightnessPercent;
s8 LastTemperatureReceived;
system_time LastStatusUpdateTime;
system_time LastSendTime;
bl_motor_state_value LastSendState;
phrase_hue StandardPatternHues;
r32 AssemblyColorsTransitionTimeLeft[BL_FLOWER_COUNT];
phrase_hue NextAssemblyColors[BL_FLOWER_COUNT];
phrase_hue AssemblyColors[BL_FLOWER_COUNT];
u32 LastAssemblyColorSet;
// The indices of this array are the index the clear core uses to
// represent a motor.
// The values of the array are the names Lumenarium uses to
// represent assemblies.
//
u32 AssemblyNameToClearCoreMapCount;
u64* AssemblyNameToClearCore_Names;
bl_pattern_mode PatternMode;
animation_handle_array ModeAnimations[BlumenPattern_Count];
animation_handle OffAnimHandle;
animation_handle AwakenHandle;
phrase_hue_map PhraseHueMap;
bool InPhraseReceptionMode;
phrase_hue NextHotHue;
system_time TimePhraseReceptionBegan;
system_time TimeLastPhraseReceived;
system_time TimeLastSetToVoiceMode;
phrase_hue LastHuePhrase;
r32 PatternSpeed;
// Debug
bl_debug_ui_mode DebugMode;
motor_packet DEBUG_PendingMotorPacket;
bool DEBUG_IgnoreWeatherDimmingLeds;
bool ShouldUpdateLog;
bool IgnoreTimeOfDay_LedDimming;
bool IgnoreTimeOfDay_MotorState;
phrase_hue PendingPhrase;
bool DebugOverrideHue;
phrase_hue DebugHue;
};
internal bool
Blumen_TempShouldDimLeds(blumen_lumen_state* BLState)
{
bool Result = BLState->LastTemperatureReceived > MinHighTemperature;
return Result;
}
#include "message_queue.cpp"
internal void
BlumenLumen_SetNextHue(blumen_lumen_state* BLState, u32 AssemblyIndex, phrase_hue Hue)
{
#if 1
BLState->NextAssemblyColors[AssemblyIndex] = Hue;
BLState->AssemblyColorsTransitionTimeLeft[AssemblyIndex] = PhraseHueFadeInDuration;
#else
BLState->AssemblyColors[AssemblyIndex] = Hue;
#endif
}
internal void
BlumenLumen_AdvanceHueFade(blumen_lumen_state* BLState, context Context)
{
for (u32 i = 0; i < BL_FLOWER_COUNT; i++)
{
r32 T = BLState->AssemblyColorsTransitionTimeLeft[i];
if (T > 0)
{
T -= Context.DeltaTime;
if (T <= 0)
{
BLState->AssemblyColors[i] = BLState->NextAssemblyColors[i];
}
BLState->AssemblyColorsTransitionTimeLeft[i] = T;
}
}
}
internal phrase_hue
BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly)
{
phrase_hue Result = {};
switch (BLState->PatternMode)
{
case BlumenPattern_NoControl:
case BlumenPattern_Standard:
{
Result = BLState->StandardPatternHues;
}break;
case BlumenPattern_VoiceCommand:
{
u32 i = Assembly.AssemblyIndex % 3;
r32 T = BLState->AssemblyColorsTransitionTimeLeft[i];
if (T > 0)
{
T = Clamp(T / PhraseHueFadeInDuration, 0, 1);
Result = LerpPhraseHue(T, BLState->NextAssemblyColors[i], BLState->AssemblyColors[i]);
} else {
Result = BLState->AssemblyColors[i];
}
}break;
}
return Result;
}
// If you change anything, exit lumenarium if its running
// then in this application hit f1 to compile then
// go to remedybg (the debugger) and hit f5
// don't touch this
u8 LastPosition = 1;
u8 ClosedValue = 1;
u8 OpenValue = 2;
r64 MotorTimeElapsed = 0;
r64 OpenClosePeriod = 15.0f;
#define BLUMEN_LUMEN_H
#endif // BLUMEN_LUMEN_H

View File

@ -1,135 +0,0 @@
/* date = March 27th 2021 2:50 pm */
#ifndef BLUMEN_LUMEN_SETTINGS_H
#define BLUMEN_LUMEN_SETTINGS_H
// Hey you never know, might need to change this some day lololol
// The number of flowers in the sculpture. Used to size all sorts of
// arrays. Maybe don't touch this unless you really know what you're doing?
#define BL_FLOWER_COUNT 3
// The path to the three flower assembly files
// PS is 90% sure you don't need to touch these ever
gs_const_string Flower0AssemblyPath = ConstString("data/ss_blumen_one.fold");
gs_const_string Flower1AssemblyPath = ConstString("data/ss_blumen_two.fold");
gs_const_string Flower2AssemblyPath = ConstString("data/ss_blumen_three.fold");
// The path to the phrase map CSV. Can be an absolute path, or relative
// to the app_run_tree folder
gs_const_string PhraseMapCSVPath = ConstString("C:/projects/flowers-sound/flower_codes.tsv");
char PhraseMapCSVSeparator = '\t';
// Search Strings for which folders to find ambient animation files and
// voice animation files in.
// these search patterns should always end in *.foldanim so they only
// return valid animation files
gs_const_string AmbientPatternFolder = ConstString("data/blumen_animations/ambient_patterns/*.foldanim");
gs_const_string VoicePatternFolder = ConstString("data/blumen_animations/audio_responses/*.foldanim");
// The times of day when the motors should be open.
//
// @TimeFormat: documentation follows
// these are in the format { Start_Hour, Start_Minute, End_Hour, End_Minute }
// Hours are in the range 0-23 inclusive
// Minutes are in the range 0-59 inclusive
//
// NOTE: There is no need to modify the MotorOpenTimesCount variable -
// it is a compile time constant that gets calculated automatically
global time_range MotorOpenTimes[] = {
{ 8, 00, 12, 00 }, // 8:00am to 12:00pm
{ 12, 30, 18, 00 }, // 12:30pm to 06:00pm
{ 18, 30, 22, 00 }, // 6:30pm to 10:00pm
};
global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit
// Lumenarium repeatedly resends the current motor state to the python
// server. This variable determines how much time elapses between each
// message.
global r32 MotorResendStatePeriod = 90.0f; // seconds
// The times of day when the leds should be on
// Search for @TimeFormat to find documentation
global time_range LedOnTimes[] = {
{ 17, 00, 23, 59 },
{ 00, 00, 06, 30 },
};
global u32 LedOnTimesCount = CArrayLength(LedOnTimes); // do not edit
global b8 DEBUGIgnoreLedOnTimeRange = false;
// How long it takes to fade from the default pattern to the
// voice activated pattern
r32 VoiceCommandFadeDuration = 0.5f; // in seconds
// How long the voice activated pattern will remain active
// without additional voice commands, before fading back to
// default behaviour.
// ie.
// if this is set to 30 seconds, upon receiving a voice command
// lumenarium will fade to the requested pattern/color palette
// and then wait 30 seconds before fading back to the original
// pattern. If, in that 30 second window, another voice command
// is issued, lumenarium will reset the 30 second counter.
r64 VoiceCommandSustainDuration = 120.0; // in seconds
// When we send a Motor Close command, we don't want the upper leds to
// immediately turn off. Instead, we want to wait until the flower is
// at least some of the way closed. This variable dictates how long
// we wait for.
// For example:
// 1. We send a 'motor close' command to the clear core
// 2. the clear core sends back a 'motor closed' state packet
// 3. We begin a timer
// 4. When the timer reaches the value set in this variable,
// we turn the upper leds off.
//
// NOTE: This is not a symmetric operation. When we send a 'motor open'
// command, we want to immediately turn the upper leds on so they appear
// to have been on the whole time.
r64 TurnUpperLedsOffAfterMotorCloseCommandDelay = 120.0; // in seconds
// NOTE: Temperature & Time of Day Based Led Brightness Settings
// The temperature above which we dim the leds to
// HighTemperatureBrightnessPercent (below)
//
// NOTE: this is an 8bit signed integer so its range is
// -128 to 127, not that we should need either of those extremes for
// this, but just a note that you can't just put anything in here.
s8 MinHighTemperature = 26;
// The percent brightness we set leds to during high temperatures.
// A value in the range 0:1 inclusive
// This is multiplied by each pixels R, G, & B channels before being
// sent. So if it is set to .1f, then the maximum brightness value sent
// to any channel of any pixel will be 25 (255 * .1 = 25).
r32 HighTemperatureBrightnessPercent = 0.25f;
// The percent brightness we set leds to when no other conditions apply
// A value in the range 0:1 inclusive.
// Probably wants to be something high like 1 but we might want to
// lower it for heat reasons?
r32 FullBrightnessPercent = 0.50f;
// A global modifier so Joerg can just slow all the patterns right down
// XD
// This is a percent - so 1 is full speed, 0.1f is 1/10 full speed and
// 2 is 2x as fast.
r32 GlobalAnimSpeed = 1.0f;
// How long it takes to fade from one animation to the next.
// This is used both for transitioning between animation files
// as well as transitioning from Standard pattern mode to voice
// activated mode
r32 GlobalAnimTransitionSpeed = 0.0f;
// how long it takes to fade from the old voice hue to the new one
r32 PhraseHueFadeInDuration = 0.01f; // seconds
r64 PhrasePriorityMessageGroupingTime = 0.1f;
// How often should Lumenarium send its status to the python server?
//
#define STATUS_PACKET_FREQ_SECONDS 10 // in seconds
#endif //BLUMEN_LUMEN_SETTINGS_H

View File

@ -1,461 +0,0 @@
/* date = March 31st 2021 2:19 am */
#ifndef GFX_MATH_H
#define GFX_MATH_H
internal r32
Smoothstep(r32 T)
{
r32 Result = (T * T * (3 - (2 * T)));
return Result;
}
internal r32
Smoothstep(r32 T, r32 A, r32 B)
{
return LerpR32(Smoothstep(T), A, B);
}
internal v3
Smoothstep(v3 P)
{
v3 R = {};
R.x = Smoothstep(P.x);
R.y = Smoothstep(P.y);
R.z = Smoothstep(P.z);
return R;
}
internal v3
AbsV3(v3 P)
{
v3 Result = {};
Result.x = Abs(P.x);
Result.y = Abs(P.y);
Result.z = Abs(P.z);
return Result;
}
internal v2
FloorV2(v2 P)
{
v2 Result = {};
Result.x = FloorR32(P.x);
Result.y = FloorR32(P.y);
return Result;
}
internal v3
FloorV3(v3 P)
{
v3 Result = {};
Result.x = FloorR32(P.x);
Result.y = FloorR32(P.y);
Result.z = FloorR32(P.z);
return Result;
}
internal v2
FractV2(v2 P)
{
v2 Result = {};
Result.x = FractR32(P.x);
Result.y = FractR32(P.y);
return Result;
}
internal v3
FractV3(v3 P)
{
v3 Result = {};
Result.x = FractR32(P.x);
Result.y = FractR32(P.y);
Result.z = FractR32(P.z);
return Result;
}
internal v2
SinV2(v2 P)
{
v2 Result = {};
Result.x = SinR32(P.x);
Result.y = SinR32(P.y);
return Result;
}
internal v3
SinV3(v3 P)
{
v3 Result = {};
Result.x = SinR32(P.x);
Result.y = SinR32(P.y);
Result.y = SinR32(P.z);
return Result;
}
internal r32
Hash1(v2 P)
{
v2 Result = FractV2( P * 0.3183099f ) * 50.f;
return FractR32(P.x * P.y * (P.x + P.y));
}
internal r32
Hash1(r32 N)
{
return FractR32(N * 17.0f * FractR32(N * 0.3183099f));
}
internal v2
Hash2(r32 N)
{
v2 P = V2MultiplyPairwise(SinV2(v2{N,N+1.0f}), v2{43758.5453123f,22578.1459123f});
return FractV2(P);
}
internal v2
Hash2(v2 P)
{
v2 K = v2{ 0.3183099f, 0.3678794f };
v2 Kp = v2{K.y, K.x};
v2 R = V2MultiplyPairwise(P, K) + Kp;
return FractV2( K * 16.0f * FractR32( P.x * P.y * (P.x + P.y)));
}
internal v3
Hash3(v2 P)
{
v3 Q = v3{};
Q.x = V2Dot(P, v2{127.1f, 311.7f});
Q.y = V2Dot(P, v2{267.5f, 183.3f});
Q.z = V2Dot(P, v2{419.2f, 371.9f});
return FractV3(SinV3(Q) * 43758.5453f);
}
internal r32
HashV3ToR32(v3 P)
{
v3 Pp = FractV3(P * 0.3183099f + v3{0.1f, 0.1f, 0.1f});
Pp *= 17.0f;
r32 Result = FractR32(Pp.x * Pp.y * Pp.z * (Pp.x + Pp.y + Pp.z));
return Result;
}
internal r32
Random(v2 N)
{
v2 V = v2{12.9898f, 4.1414f};
return FractR32(SinR32(V2Dot(N, V)) * 43758.5453);
}
internal r32
Noise2D(v2 P)
{
v2 IP = FloorV2(P);
v2 U = FractV2(P);
U = V2MultiplyPairwise(U, U);
U = V2MultiplyPairwise(U, ((U * 2.0f) + v2{-3, -3}));
r32 A = LerpR32(U.x, Random(IP), Random(IP + v2{1.0f, 0}));
r32 B = LerpR32(U.x, Random(IP + v2{0, 1}), Random(IP + v2{1, 1}));
r32 Res = LerpR32(U.y, A, B);
return Res * Res;
}
internal r32
Noise3D(v3 P)
{
P = AbsV3(P);
v3 PFloor = FloorV3(P);
v3 PFract = FractV3(P);
v3 F = Smoothstep(PFract);
r32 Result = LerpR32(F.z,
LerpR32(F.y,
LerpR32(F.x,
HashV3ToR32(PFloor + v3{0, 0, 0}),
HashV3ToR32(PFloor + v3{1, 0, 0})),
LerpR32(F.x,
HashV3ToR32(PFloor + v3{0, 1, 0}),
HashV3ToR32(PFloor + v3{1, 1, 0}))),
LerpR32(F.y,
LerpR32(F.x,
HashV3ToR32(PFloor + v3{0, 0, 1}),
HashV3ToR32(PFloor + v3{1, 0, 1})),
LerpR32(F.x,
HashV3ToR32(PFloor + v3{0, 1, 1}),
HashV3ToR32(PFloor + v3{1, 1, 1}))));
Assert(Result >= 0 && Result <= 1);
return Result;
}
internal r32
Noise3D_(v3 Pp)
{
v3 P = FloorV3(Pp);
v3 W = FractV3(Pp);
//v3 U = W * W * W * (W * (W * 6.0f - 15.0f) + 10.0f);
v3 U = V3MultiplyPairwise(W, W * 6.0f - v3{15, 15, 15});
U = U + v3{10, 10, 10};
U = V3MultiplyPairwise(U, W);
U = V3MultiplyPairwise(U, W);
U = V3MultiplyPairwise(U, W);
r32 N = P.x + 317.0f * P.y + 157.0f * P.z;
r32 A = Hash1(N + 0.0f);
r32 B = Hash1(N + 1.0f);
r32 C = Hash1(N + 317.0f);
r32 D = Hash1(N + 317.0f);
r32 E = Hash1(N + 157.0f);
r32 F = Hash1(N + 158.0f);
r32 G = Hash1(N + 474.0f);
r32 H = Hash1(N + 475.0f);
r32 K0 = A;
r32 K1 = B - A;
r32 K2 = C - A;
r32 K3 = E - A;
r32 K4 = A - B - C + D;
r32 K5 = A - C - E + G;
r32 K6 = A - B - E + F;
r32 K7 = A + B + C - D + E - F - G + H;
return -1.0f + 2.0f * (K0 +
K1 * U.x +
K2 * U.y +
K3 * U.z +
K4 * U.x * U.y +
K5 * U.y + U.z +
K6 * U.z * U.x +
K7 * U.x * U.y * U.z);
}
internal r32
Fbm2D(v2 P)
{
r32 R = 0;
r32 Amp = 1.0;
r32 Freq = 1.0;
for (u32 i = 0; i < 3; i++)
{
R += Amp * Noise2D(P * Freq);
Amp *= 0.5f;
Freq *= 1.0f / 0.5f;
}
return R;
}
global m44 M3 = m44{
0.00f, 0.80f, 0.60f, 0,
-0.80f, 0.36f, -0.48f, 0,
-0.60f, -0.48f, 0.64f, 0,
0, 0, 0, 1
};
internal r32
Fbm3D(v3 P)
{
v3 X = P;
r32 F = 2.0f;
r32 S = 0.5f;
r32 A = 0.0f;
r32 B = 0.5f;
for (u32 i = 0; i < 4; i++)
{
r32 N = Noise3D(X);
A += B * N;
B *= S;
v4 Xp = M3 * ToV4Point(X);
X = Xp.xyz * F;
}
return A;
}
internal r32
Fbm3D(v3 P, r32 T)
{
v3 Tt = v3{T, T, T};
r32 SinT = SinR32(T);
v3 Tv = v3{SinT, SinT, SinT};
v3 Pp = P;
r32 F = 0.0;
F += 0.500000f * Noise3D(Pp + Tt); Pp = Pp * 2.02;
//F += 0.031250f * Noise3D(Pp); Pp = Pp * 2.01;
F += 0.300000f * Noise3D(Pp - Tt); Pp = Pp * 2.03;
F += 0.125000f * Noise3D(Pp); Pp = Pp * 2.01;
F += 0.062500f * Noise3D(Pp + Tt); Pp = Pp * 2.04;
//F += 0.015625f * Noise3D(Pp + Tv);
r32 D = 0.9875f;
F = F / D;
return F;
}
internal r32
Voronoise(v2 P, r32 U, r32 V)
{
r32 K = 1.0f + 63.0f + PowR32(1.0f - V, 6.0f);
v2 I = FloorV2(P);
v2 F = FractV2(P);
v2 A = v2{0, 0};
for (s32 y = -2; y <= 2; y++)
{
for (s32 x = -2; x <= 2; x++)
{
v2 G = v2{(r32)x, (r32)y};
v3 O = V3MultiplyPairwise(Hash3(I + G), v3{U, U, 1.0f});
v2 D = G - F + O.xy;
r32 W = PowR32(1.0f - Smoothstep(V2Mag(D), 0.0f, 1.414f), K);
A += v2{O.z * W, W};
}
}
return A.x / A.y;
}
v4 RGBToHSV(v4 In)
{
v4 Result = {};
r32 Min = Min(In.r, Min(In.g, In.b));
r32 Max = Max(In.r, Max(In.g, In.b));
r32 V = Max;
r32 Delta = Max - Min;
r32 S = 0;
r32 H = 0;
if( Max != 0 )
{
S = Delta / Max;
if( In.r == Max )
{
H = ( In.g - In.b ) / Delta; // between yellow & magenta
}
else if( In.g == Max )
{
H = 2 + ( In.b - In.r ) / Delta; // between cyan & yellow
}
else
{
H = 4 + ( In.r - In.g ) / Delta; // between magenta & cyan
}
H *= 60; // degrees
if( H < 0 )
H += 360;
Result = v4{H, S, V, 1};
}
else
{
// r = g = b = 0
// s = 0, v is undefined
S = 0;
H = -1;
Result = v4{H, S, 1, 1};
}
return Result;
}
v4 HSVToRGB (v4 In)
{
float Hue = In.x;
/*
while (Hue > 360.0f) { Hue -= 360.0f; }
while (Hue < 0.0f) { Hue += 360.0f; }
*/
Hue = ModR32(Hue, 360.0f);
if (Hue < 0) { Hue += 360.0f; }
if (Hue == MinR32) { Hue = 0; }
if (Hue == MaxR32) { Hue = 360; }
Assert(Hue >= 0 && Hue < 360);
float Sat = In.y;
float Value = In.z;
float hh, p, q, t, ff;
long i;
v4 Result = {};
Result.a = In.a;
if(Sat <= 0.0f) { // < is bogus, just shuts up warnings
Result.r = Value;
Result.g = Value;
Result.b = Value;
return Result;
}
hh = Hue;
if(hh >= 360.0f) hh = 0.0f;
hh /= 60.0f;
i = (long)hh;
ff = hh - i;
p = Value * (1.0f - Sat);
q = Value * (1.0f - (Sat * ff));
t = Value * (1.0f - (Sat * (1.0f - ff)));
switch(i) {
case 0:
{Result.r = Value;
Result.g = t;
Result.b = p;
}break;
case 1:
{
Result.r = q;
Result.g = Value;
Result.b = p;
}break;
case 2:
{
Result.r = p;
Result.g = Value;
Result.b = t;
}break;
case 3:
{
Result.r = p;
Result.g = q;
Result.b = Value;
}break;
case 4:
{
Result.r = t;
Result.g = p;
Result.b = Value;
}break;
case 5:
default:
{
Result.r = Value;
Result.g = p;
Result.b = q;
}break;
}
return Result;
}
internal pixel
V4ToRGBPixel(v4 C)
{
C.x = Clamp01(C.x);
C.y = Clamp01(C.y);
C.z = Clamp01(C.z);
pixel Result = {};
Result.R = (u8)(C.x * 255);
Result.G = (u8)(C.y * 255);
Result.B = (u8)(C.z * 255);
return Result;
}
#endif //GFX_MATH_H

View File

@ -1,83 +0,0 @@
internal void
MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena)
{
gs_data MessageQueueData = PushSize(Arena, DEFAULT_QUEUE_ENTRY_SIZE * BLUMEN_MESSAGE_QUEUE_COUNT);
gs_memory_cursor C = MemoryCursorCreateFromData(MessageQueueData);
for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++)
{
Queue->Buffers[i] = MemoryCursorPushSize(&C, DEFAULT_QUEUE_ENTRY_SIZE);
}
}
internal bool
MessageQueue_CanWrite(blumen_network_msg_queue Queue)
{
bool Result = ((Queue.WriteHead >= Queue.ReadHead) ||
(Queue.WriteHead < Queue.ReadHead));
return Result;
}
internal bool
MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg)
{
Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE);
u32 Index = Queue->WriteHead;
Assert(Index >= 0 &&
Index < BLUMEN_MESSAGE_QUEUE_COUNT);
gs_data* Dest = Queue->Buffers + Index;
CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size);
Dest->Size = Msg.Size;
// NOTE(pjs): We increment write head at the end of writing so that
// a reader thread doesn't pull the message off before we've finished
// filling it out
Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT;
return true;
}
internal bool
MessageQueue_CanRead(blumen_network_msg_queue Queue)
{
bool Result = (Queue.ReadHead != Queue.WriteHead);
return Result;
}
internal gs_data
MessageQueue_Peek(blumen_network_msg_queue* Queue)
{
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
}
internal gs_data
MessageQueue_Read(blumen_network_msg_queue* Queue)
{
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead++;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
Queue->ReadHead = 0;
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
}
internal void
MessageQueue_Clear(blumen_network_msg_queue* Queue)
{
while (MessageQueue_CanRead(*Queue))
{
MessageQueue_Read(Queue);
}
}

View File

@ -1,17 +0,0 @@
/* date = March 27th 2021 3:07 pm */
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
#define BLUMEN_MESSAGE_QUEUE_COUNT 32
typedef struct blumen_network_msg_queue
{
gs_data Buffers[BLUMEN_MESSAGE_QUEUE_COUNT];
u32 WriteHead;
u32 ReadHead;
} blumen_network_msg_queue;
// KB(1) is just bigger than any packet we send. Good for now
#define DEFAULT_QUEUE_ENTRY_SIZE KB(1)
#endif //MESSAGE_QUEUE_H

View File

@ -1,283 +0,0 @@
/* date = March 27th 2021 1:55 pm */
#ifndef PHRASE_HUE_MAP_H
#define PHRASE_HUE_MAP_H
enum p_hue_flag
{
Hue_Value = 0,
Hue_White = 1,
Hue_Black = 2,
};
enum p_hue_pattern
{
HuePattern_Patchy,
HuePattern_Wavy,
HuePattern_Count,
};
enum p_hue_add_in
{
AddIn_None,
AddIn_Waves,
AddIn_Rotary,
AddIn_Count,
};
typedef struct p_hue
{
v4 HSV;
} p_hue;
typedef struct phrase_hue_map
{
u64 CountMax;
u64 Count;
gs_const_string* Phrases;
u64* PhraseHashes;
p_hue* Hue0;
p_hue* Hue1;
p_hue* Hue2;
u32* Gran; // granularity
r32* Speed;
u8* Pattern;
u8* AddIn;
bool* OverrideAll;
} phrase_hue_map;
typedef struct phrase_hue
{
gs_const_string Phrase;
u64 PhraseHash;
p_hue Hue0;
p_hue Hue1;
p_hue Hue2;
u32 Granularity;
r32 Speed;
u8 Pattern;
u8 AddIn;
bool OverrideAll;
} phrase_hue;
internal p_hue
LerpPHue(r32 T, p_hue A, p_hue B)
{
p_hue Result = {};
if (Abs(A.HSV.x - B.HSV.x) < 180.0f)
{
Result.HSV.x = LerpR64(T, A.HSV.x, B.HSV.x);
}
else if (B.HSV.x > A.HSV.x)
{
Result.HSV.x = LerpR64(T, A.HSV.x, B.HSV.x - 360.0f);
}
else
{
Result.HSV.x = LerpR64(T, A.HSV.x - 360.0f, B.HSV.x);
}
if (Result.HSV.x < 360) Result.HSV.x += 360;
if (Result.HSV.x > 360) Result.HSV.x -= 360;
Result.HSV.x = Clamp(0, Result.HSV.x, 360);
Result.HSV.y = LerpR32(T, A.HSV.y, B.HSV.y);
Result.HSV.z = LerpR32(T, A.HSV.z, B.HSV.z);
Result.HSV.w = LerpR32(T, A.HSV.w, B.HSV.w);
return Result;
}
internal phrase_hue
LerpPhraseHue(r32 T, phrase_hue A, phrase_hue B)
{
phrase_hue Result = {};
Result.Hue0 = LerpPHue(T, A.Hue0, B.Hue0);
Result.Hue1 = LerpPHue(T, A.Hue1, B.Hue1);
Result.Hue2 = LerpPHue(T, A.Hue2, B.Hue2);
Result.Granularity = (u32)LerpR32(T, (r32)A.Granularity, (r32)B.Granularity);
Result.Speed = LerpR32(T, A.Speed, B.Speed);
if (T < .5f) {
Result.Phrase = A.Phrase;
Result.PhraseHash = A.PhraseHash;
Result.Pattern = A.Pattern;
Result.AddIn = A.AddIn;
}
else {
Result.Phrase = B.Phrase;
Result.PhraseHash = B.PhraseHash;
Result.Pattern = B.Pattern;
Result.AddIn = B.AddIn;
}
return Result;
}
internal p_hue
CreateHueFromString(gs_const_string Str)
{
p_hue Result = {};
if (Str.Str[0] == 'b') {
Result.HSV = v4{0, 0, 0, 1 };
} else if (Str.Str[0] == 'w') {
Result.HSV = v4{0, 0, 1, 1 };;
} else {
parse_float_result Parsed = ValidateAndParseFloat(Str);
if (!Parsed.Success)
{
Log_Error(GlobalLogBuffer, "Failed to Parse CSV Float\n");
Parsed.Value = 0.0;
}
Result.HSV = v4{ (r32)Parsed.Value, 1, 1, 1 };
}
return Result;
}
internal v4
RGBFromPhraseHue (p_hue H)
{
v4 Result = H.HSV;
Result = HSVToRGB(Result);
return Result;
}
internal phrase_hue_map
PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
{
phrase_hue_map Result = {};
if (Sheet.RowCount == 0) return Result;
Result.CountMax = Sheet.RowCount - 1; // we don't include the header row
Result.Phrases = PushArray(Arena, gs_const_string, Result.CountMax);
Result.PhraseHashes = PushArray(Arena, u64, Result.CountMax);
Result.Hue0 = PushArray(Arena, p_hue, Result.CountMax);
Result.Hue1 = PushArray(Arena, p_hue, Result.CountMax);
Result.Hue2 = PushArray(Arena, p_hue, Result.CountMax);
Result.Gran = PushArray(Arena, u32, Result.CountMax);
Result.Pattern = PushArray(Arena, u8, Result.CountMax);
Result.Speed = PushArray(Arena, r32, Result.CountMax);
Result.AddIn = PushArray(Arena, u8, Result.CountMax);
Result.OverrideAll = PushArray(Arena, bool, Result.CountMax);
// this lets us tightly pack phrase_hues even if there is a
// row in the csv that is empty or invalid
s32 DestOffset = 0;
for (u32 Row = 1; Row < Sheet.RowCount; Row++)
{
s32 Index = (Row - 1) - DestOffset;
Assert(Index >= 0 && Index < Result.CountMax);
gs_const_string Phrase = CSVSheet_GetCell(Sheet,
0, Row);
gs_const_string Hue0Str = CSVSheet_GetCell(Sheet, 1, Row);
gs_const_string Hue1Str = CSVSheet_GetCell(Sheet, 2, Row);
gs_const_string Hue2Str = CSVSheet_GetCell(Sheet, 3, Row);
gs_const_string Homonyms = CSVSheet_GetCell(Sheet, 4, Row);
gs_const_string Granularity = CSVSheet_GetCell(Sheet, 5, Row);
gs_const_string Speed = CSVSheet_GetCell(Sheet, 6, Row);
gs_const_string Pattern = CSVSheet_GetCell(Sheet, 7, Row);
gs_const_string AddIn = CSVSheet_GetCell(Sheet, 8, Row);
gs_const_string OverrideAll = CSVSheet_GetCell(Sheet, 9, Row);
// essential parameters
if (Phrase.Length == 0 ||
Hue0Str.Length == 0 ||
Hue1Str.Length == 0 ||
Hue2Str.Length == 0)
{
DestOffset++;
continue;
}
Result.Phrases[Index] = PushStringF(Arena, Phrase.Length, "%S", Phrase).ConstString;
for (u64 i = 0; i < Result.Phrases[Index].Length; i++)
{
char C = Result.Phrases[Index].Str[i];
if (IsAlpha(C))
{
Result.Phrases[Index].Str[i] = ToLower(C);
}
}
u64 PhraseHash = HashDJB2ToU32(StringExpand(Result.Phrases[Index]));
Result.PhraseHashes[Index] = PhraseHash;
Result.Hue0[Index] = CreateHueFromString(Hue0Str);
Result.Hue1[Index] = CreateHueFromString(Hue1Str);
Result.Hue2[Index] = CreateHueFromString(Hue2Str);
parse_float_result ParsedSpeed = ValidateAndParseFloat(Speed);
if (!ParsedSpeed.Success)
{
ParsedSpeed.Value = 1.0;
}
Result.Speed[Index] = ParsedSpeed.Value;
if (StringsEqual(Pattern, ConstString("wavy")))
{
Result.Pattern[Index] = HuePattern_Wavy;
} else {
Result.Pattern[Index] = HuePattern_Patchy;
}
if (StringsEqual(AddIn, ConstString("waves")))
{
Result.AddIn[Index] = AddIn_Waves;
} else if (StringsEqual(AddIn, ConstString("rotary"))) {
Result.AddIn[Index] = AddIn_Rotary;
} else {
Result.AddIn[Index] = AddIn_None;
}
parse_uint_result ParsedGranularity = ValidateAndParseUInt(Granularity);
if (!ParsedGranularity.Success)
{
ParsedGranularity.Value = 1;
}
Result.Gran[Index] = ParsedGranularity.Value;
Result.OverrideAll[Index] = StringsEqualUpToLength(OverrideAll, ConstString("yes"), 3);
}
Result.Count = Result.CountMax + DestOffset;
return Result;
}
internal phrase_hue
PhraseHueMap_Get(phrase_hue_map Map, u32 Index)
{
Assert(Index < Map.Count);
phrase_hue Result = {};
Result.Phrase = Map.Phrases[Index];
Result.PhraseHash = Map.PhraseHashes[Index];
Result.Hue0 = Map.Hue0[Index];
Result.Hue1 = Map.Hue1[Index];
Result.Hue2 = Map.Hue2[Index];
Result.Granularity = Map.Gran[Index];
Result.Speed = Map.Speed[Index];
Result.AddIn = Map.AddIn[Index];
Result.Pattern = Map.Pattern[Index];
Result.OverrideAll = Map.OverrideAll[Index];
return Result;
}
internal phrase_hue
PhraseHueMap_Find(phrase_hue_map Map, u64 PhraseHash)
{
phrase_hue Result = {};
for (u32 i = 0; i < Map.Count; i++)
{
if (Map.PhraseHashes[i] == PhraseHash)
{
Result = PhraseHueMap_Get(Map, i);
break;
}
}
return Result;
}
#endif //PHRASE_HUE_MAP_H

View File

@ -1,20 +0,0 @@
/* date = March 29th 2021 10:41 pm */
#ifndef SDF_H
#define SDF_H
internal r32
SDF_Sphere(v3 Point, v3 Center, r32 Radius)
{
r32 Result = V3Mag(Point - Center) - Radius;
return Result;
}
internal r32
SDF_SphereNormalized(v3 Point, v3 Center, r32 Radius)
{
r32 Result = SDF_Sphere(Point, Center, Radius) / Radius;
return Result;
}
#endif //SDF_H

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