merging in dev. Latest Stable Build: October 24, 2020

This commit is contained in:
PS 2020-10-24 13:52:37 -07:00
commit 9847c991d9
100 changed files with 14642 additions and 7087 deletions

View File

@ -15,7 +15,7 @@ pushd %BuildPath%
del *.pdb > NUL 2> NUL del *.pdb > NUL 2> NUL
REM Run the Preprocessor REM Run the Preprocessor
%MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp REM %MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp
echo WAITING FOR PDB TO WRITE > lock.tmp echo WAITING FOR PDB TO WRITE > lock.tmp
@ -24,7 +24,9 @@ set LastError=%ERRORLEVEL%
del lock.tmp del lock.tmp
cl %CommonCompilerFlags% %SourceCodePath%\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib
cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib
popd popd

View File

@ -1,178 +0,0 @@
//
// File: foldhaus_animation.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ANIMATION
#define ANIMATION_PROC(name) void name(assembly_led_buffer* Assembly, r32 Time)
typedef ANIMATION_PROC(animation_proc);
struct frame_range
{
s32 Min;
s32 Max;
};
struct animation_block
{
frame_range Range;
u32 AnimationProcHandle;
u32 Layer;
};
enum blend_mode
{
BlendMode_Overwrite,
BlendMode_Add,
BlendMode_Multiply,
BlendMode_Count,
};
struct anim_layer
{
string Name;
blend_mode BlendMode;
};
#define ANIMATION_SYSTEM_LAYERS_MAX 128
#define ANIMATION_SYSTEM_BLOCKS_MAX 128
struct animation_system
{
memory_arena Storage;
gs_list<animation_block> Blocks;
anim_layer* Layers;
u32 LayersCount;
u32 LayersMax;
// 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
s32 CurrentFrame;
s32 LastUpdatedFrame;
r32 SecondsPerFrame;
b32 TimelineShouldAdvance;
// Timeline
frame_range PlayableRange;
};
internal u32
SecondsToFrames(r32 Seconds, animation_system System)
{
u32 Result = Seconds * (1.0f / System.SecondsPerFrame);
return Result;
}
inline b32
FrameIsInRange(s32 Frame, frame_range Range)
{
b32 Result = (Frame >= Range.Min) && (Frame <= Range.Max);
return Result;
}
internal u32
GetFrameCount(frame_range Range)
{
u32 Result = (u32)GSMax(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
internal gs_list_handle
AddAnimationBlock(u32 StartFrame, s32 EndFrame, u32 AnimationProcHandle, u32 Layer, animation_system* AnimationSystem)
{
gs_list_handle Result = {0};
animation_block NewBlock = {0};
NewBlock.Range.Min = StartFrame;
NewBlock.Range.Max = EndFrame;
NewBlock.AnimationProcHandle = AnimationProcHandle;
NewBlock.Layer = Layer;
Result = AnimationSystem->Blocks.PushElementOnList(NewBlock);
return Result;
}
internal void
RemoveAnimationBlock(gs_list_handle AnimationBlockHandle, animation_system* AnimationSystem)
{
Assert(ListHandleIsValid(AnimationBlockHandle));
AnimationSystem->Blocks.FreeElementWithHandle(AnimationBlockHandle);
}
// Layers
internal u32
AddLayer (string Name, animation_system* AnimationSystem, blend_mode BlendMode = BlendMode_Overwrite)
{
// TODO(Peter): If this assert fires its time to make the layer buffer system
// resizable.
Assert(AnimationSystem->LayersCount < AnimationSystem->LayersMax);
u32 Result = 0;
Result = AnimationSystem->LayersCount++;
anim_layer* NewLayer = AnimationSystem->Layers + Result;
*NewLayer = {0};
NewLayer->Name = MakeString(PushArray(&AnimationSystem->Storage, char, Name.Length), Name.Length);
CopyStringTo(Name, &NewLayer->Name);
NewLayer->BlendMode = BlendMode;
return Result;
}
internal void
RemoveLayer (u32 LayerIndex, animation_system* AnimationSystem)
{
Assert(LayerIndex < AnimationSystem->LayersMax);
Assert(LayerIndex < AnimationSystem->LayersCount);
for (u32 i = LayerIndex; i < AnimationSystem->LayersCount - 1; i++)
{
AnimationSystem->Layers[i] = AnimationSystem->Layers[i + 1];
}
for (u32 i = AnimationSystem->Blocks.Used -= 1; i >= 0; i--)
{
gs_list_entry<animation_block>* Entry = AnimationSystem->Blocks.GetEntryAtIndex(i);
if (EntryIsFree(Entry)) { continue; }
animation_block* Block = &Entry->Value;
if (Block->Layer > LayerIndex)
{
Block->Layer -= 1;
}
else if (Block->Layer == LayerIndex)
{
AnimationSystem->Blocks.FreeElementAtIndex(i);
}
}
AnimationSystem->LayersCount -= 1;
}
#define FOLDHAUS_ANIMATION
#endif // FOLDHAUS_ANIMATION

View File

@ -1,445 +0,0 @@
//
// File: assembly_parser.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef ASSEMBLY_PARSER_CPP
internal assembly_token
ParseToken (tokenizer* Tokenizer)
{
assembly_token Result = {};
Result.Token = Tokenizer->At;
Result.Length = 1;
EatChar(Tokenizer);
if (*Result.Token == ':'){ Result.Type = AssemblyToken_Colon; }
else if (*Result.Token == ';'){ Result.Type = AssemblyToken_SemiColon; }
else if (*Result.Token =='{'){ Result.Type = AssemblyToken_LeftCurlyBrace; }
else if (*Result.Token =='}'){ Result.Type = AssemblyToken_RightCurlyBrace; }
else if (*Result.Token ==','){ Result.Type = AssemblyToken_Comma; }
else if (IsNumericExtended(*Result.Token))
{
while(*Tokenizer->At && IsNumericExtended(*Tokenizer->At)) { EatChar(Tokenizer); }
Result.Type = AssemblyToken_Number;
Result.Length = Tokenizer->At - Result.Token;
}
else if (*Result.Token =='\"')
{
while(*Tokenizer->At && *Tokenizer->At != '\"') { EatChar(Tokenizer); }
Result.Token++; // Skip the quote
Result.Type = AssemblyToken_String;
Result.Length = (Tokenizer->At - Result.Token) - 1;
}
else if (*Result.Token == '(')
{
while(*Tokenizer->At && *Tokenizer->At != ')') { EatChar(Tokenizer); }
Result.Token++; // Skip the paren
Result.Type = AssemblyToken_Vector;
Result.Length = (Tokenizer->At - Result.Token) - 1;
}
else if (CharArraysEqualUpToLength(Result.Token, LED_STRIP_IDENTIFIER, CharArrayLength(LED_STRIP_IDENTIFIER)))
{
Result.Type = AssemblyToken_LEDStrip;
Result.Length = CharArrayLength(LED_STRIP_IDENTIFIER);
Tokenizer->At += Result.Length - 1;
}
else if (CharArraysEqualUpToLength(Result.Token, END_ASSEMBLY_FILE_IDENTIFIER, CharArrayLength(END_ASSEMBLY_FILE_IDENTIFIER)))
{
Result.Type = AssemblyToken_EndOfFile;
Result.Length = CharArrayLength(END_ASSEMBLY_FILE_IDENTIFIER);
Tokenizer->At += Result.Length - 1;
}
else
{
Result.Type = AssemblyToken_Identifier;
while(*Tokenizer->At && !IsWhitespace(*Tokenizer->At)) { EatChar(Tokenizer); }
}
return Result;
}
internal v3
ParseAssemblyVector (char* String)
{
v3 Result = {};
tokenizer Tokenizer = {};
Tokenizer.At = String;
EatWhitespace(&Tokenizer);
Result.x = ParseFloatUnsafe(Tokenizer.At).FloatValue;
EatPastCharacter(&Tokenizer, ',');
EatWhitespace(&Tokenizer);
Result.y = ParseFloatUnsafe(Tokenizer.At).FloatValue;
EatPastCharacter(&Tokenizer, ',');
EatWhitespace(&Tokenizer);
Result.z = ParseFloatUnsafe(Tokenizer.At).FloatValue;
EatPastCharacter(&Tokenizer, ',');
return Result;
}
internal b32
ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer)
{
b32 HeaderIsValid = false;
if (CharArraysEqualUpToLength(Tokenizer->At, LED_STRIP_COUNT_IDENTIFIER, CharArrayLength(LED_STRIP_COUNT_IDENTIFIER)))
{
Tokenizer->At += CharArrayLength(LED_STRIP_COUNT_IDENTIFIER);
EatWhitespace(Tokenizer);
assembly_token CountToken = ParseToken(Tokenizer);
if (CountToken.Type == AssemblyToken_Number)
{
Assembly->LEDStripSize = ParseSignedIntUnsafe(CountToken.Token).SignedIntValue;
HeaderIsValid = true;
}
EatWhitespace(Tokenizer);
}
return HeaderIsValid;
}
internal led_strip_definition
ParseLEDStrip (tokenizer* Tokenizer)
{
led_strip_definition Result = {};
// Control Box Index
while (*Tokenizer->At && !IsNumericExtended(*Tokenizer->At)) { EatChar(Tokenizer); }
assembly_token BoxIDToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number);
Result.ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue;
// Start Universe
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
assembly_token StartUniverseToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number);
Result.StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue;
// Start Channel
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
assembly_token StartChannelToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number);
Result.StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue;
// Strip Type
// TODO(Peter): This is unused for now, and would be a branch point for parsing
// the rest of the info. Fix this.
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
if (CharArraysEqualUpToLength(Tokenizer->At, INTERPOLATE_POINTS_IDENTIFIER, CharArrayLength(INTERPOLATE_POINTS_IDENTIFIER)))
{
Result.InterpolationType = StripInterpolate_Points;
// Start Position
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
assembly_token StartPositionToken = ParseToken(Tokenizer);
Assert(StartPositionToken.Type == AssemblyToken_Vector);
Result.InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token);
// End Position
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
assembly_token EndPositionToken = ParseToken(Tokenizer);
Assert(EndPositionToken.Type == AssemblyToken_Vector);
Result.InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token);
// LEDs Per Strip
EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer);
assembly_token LEDsPerStripToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number);
Result.LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue;
}
EatPastCharacter(Tokenizer, '}');
EatWhitespace(Tokenizer);
return Result;
}
internal void
ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer)
{
EatWhitespace(Tokenizer);
while(*Tokenizer->At)
{
EatWhitespace(Tokenizer);
assembly_token Token = ParseToken(Tokenizer);
if (Token.Type != AssemblyToken_EndOfFile)
{
switch (Token.Type)
{
case AssemblyToken_LEDStrip:
{
led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount;
Assert(Assembly->LEDStripCount < Assembly->LEDStripSize);
*LEDStripDef = ParseLEDStrip(Tokenizer);
Assembly->TotalLEDCount += LEDStripDef->LEDsPerStrip;
Assembly->LEDStripCount++;
} break;
// TODO(Peter): Other cases? What else would need to be in the assembly body?
InvalidDefaultCase;
}
}
else
{
break;
}
}
// NOTE(Peter): Ensure the validity of the assembly file. We probably don't want an assert here,
// more likely we want to load a valid assembly anyways, and just raise this as an error to the user
// so they can fix it.
Assert(Assembly->LEDStripCount == Assembly->LEDStripSize);
}
inline b32
ParseTokenEquals (tokenizer* T, char* Validate)
{
b32 Result = true;
char* TAt = T->At;
char* VAt = Validate;
while (((TAt - T->Memory) < T->MemoryLength) && *VAt)
{
if (*VAt != *TAt)
{
Result = false;
break;
}
TAt++;
*VAt++;
}
if (Result)
{
T->At = TAt;
EatWhitespace(T);
}
return Result;
}
internal b32
ParseComma(tokenizer* T)
{
b32 Result = ParseTokenEquals(T, ",");
return Result;
}
internal b32
ParseOpenCurlyBrace(tokenizer* T)
{
b32 Result = ParseTokenEquals(T, "{");
return Result;
}
internal b32
ParseCloseCurlyBrace(tokenizer* T)
{
b32 Result = ParseTokenEquals(T, "}");
return Result;
}
internal b32
ParseOpenParen(tokenizer* T)
{
b32 Result = ParseTokenEquals(T, "(");
return Result;
}
internal b32
ParseCloseParen(tokenizer* T)
{
b32 Result = ParseTokenEquals(T, ")");
return Result;
}
internal b32
ParseUnsignedInteger(tokenizer* T, u32* Value)
{
parse_result Result = ParseUnsignedIntUnsafe(T->At);
*Value = Result.UnsignedIntValue;
T->At = Result.OnePastLast;
// TODO(Peter): Parse functions in gs_string don't actually check for errors or
// whether or not they actually parsed an int.
// :GSStringParseErrors
return true;
}
internal b32
ParseFloat(tokenizer* T, r32* Value)
{
parse_result ParseResult = ParseFloatUnsafe(T->At);
*Value = ParseResult.FloatValue;
T->At = ParseResult.OnePastLast;
// TODO(Peter):
// :GSStringParseErrors
return true;
}
internal b32
ParseVector(tokenizer* T, v3* Value)
{
b32 Result = true;
if (ParseOpenParen(T))
{
for (u32 i = 0; i < 3; i++)
{
b32 ValueSuccess = ParseFloat(T, &(Value->E[i]));
if (!ValueSuccess)
{
Result = false;
break;
}
b32 CommaSuccess = ParseComma(T);
if (!CommaSuccess)
{
break;
}
}
if (!ParseCloseParen(T))
{
Result = false;
}
}
else
{
Result = false;
}
return Result;
}
// TODO(Peter): :ErrorLogging
#define ParseLEDStripToken(tokenizer, parse_expr, error_msg) \
(parse_expr) && (ParseComma(tokenizer))
internal b32
ParseLEDStripCount (tokenizer* T, u32* Value)
{
b32 Result = false;
if (ParseTokenEquals(T, LED_STRIP_COUNT_IDENTIFIER))
{
EatWhitespace(T);
if (ParseUnsignedInteger(T, Value))
{
Result = true;
}
}
return Result;
}
internal b32
ParseLEDStrip (led_strip_definition* Strip, tokenizer* T, memory_arena* Arena)
{
b32 Result = false;
if (ParseTokenEquals(T, LED_STRIP_IDENTIFIER) &&
ParseOpenCurlyBrace(T))
{
Result = true;
u32 ControlBoxIndex, StartUniverse, StartChannel;
ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->ControlBoxID), "Control Box Error");
ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->StartUniverse), "Start Universe Error");
ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->StartChannel), "Start Channel Error");
if (ParseTokenEquals(T, INTERPOLATE_POINTS_IDENTIFIER) &&
ParseComma(T))
{
Strip->InterpolationType = StripInterpolate_Points;
ParseLEDStripToken(T, ParseVector(T, &Strip->InterpolatePositionStart), "Position Start Error");
ParseLEDStripToken(T, ParseVector(T, &Strip->InterpolatePositionEnd), "Position End Error");
}
ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->LEDsPerStrip), "LEDs Per Strip Error");
EatWhitespace(T);
if (!ParseCloseCurlyBrace(T))
{
Result = false;
}
}
return Result;
}
internal assembly_definition
ParseAssemblyFile (u8* FileBase, s32 FileSize, memory_arena* Arena, event_log* EventLog)
{
assembly_definition Assembly = {};
tokenizer Tokenizer = {};
Tokenizer.At = (char*)FileBase;
Tokenizer.Memory = (char*)FileBase;
Tokenizer.MemoryLength = FileSize;
if (ParseLEDStripCount(&Tokenizer, &Assembly.LEDStripSize))
{
Assembly.LEDStrips = PushArray(Arena, led_strip_definition, Assembly.LEDStripSize);
while (AtValidPosition(Tokenizer))
{
EatWhitespace(&Tokenizer);
if (Assembly.LEDStripCount < Assembly.LEDStripSize)
{
led_strip_definition* LEDStrip = Assembly.LEDStrips + Assembly.LEDStripCount++;
if (ParseLEDStrip(LEDStrip, &Tokenizer, Arena))
{
Assembly.TotalLEDCount += LEDStrip->LEDsPerStrip;
}
else
{
LogError(EventLog, "Unable to parse LED strip in assembly file");
break;
}
}
else
{
if (ParseTokenEquals(&Tokenizer, END_ASSEMBLY_FILE_IDENTIFIER))
{
break;
}
else
{
LogError(EventLog, "Did not find ent of file identifier in assembly file");
break;
}
}
}
}
else
{
// TODO(Peter): :ErrorLoggong
InvalidCodePath;
}
return Assembly;
}
#define ASSEMBLY_PARSER_CPP
#endif // ASSEMBLY_PARSER_CPP

View File

@ -1,76 +0,0 @@
//
// File: assembly_parser.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef ASSEMBLY_PARSER_H
#define LED_STRIP_COUNT_IDENTIFIER "led_strip_count"
#define LED_STRIP_IDENTIFIER "led_strip"
#define INTERPOLATE_POINTS_IDENTIFIER "INTERPOLATE_POINTS"
#define END_ASSEMBLY_FILE_IDENTIFIER "END_OF_ASSEMBLY_FILE"
enum assembly_token_type
{
AssemblyToken_Colon,
AssemblyToken_SemiColon,
AssemblyToken_LeftCurlyBrace,
AssemblyToken_RightCurlyBrace,
AssemblyToken_Comma,
AssemblyToken_Number,
AssemblyToken_String,
AssemblyToken_Vector,
AssemblyToken_LEDStrip,
AssemblyToken_Identifier,
AssemblyToken_EndOfFile
};
struct assembly_token
{
char* Token;
s32 Length;
assembly_token_type Type;
};
enum strip_interpolation_type
{
StripInterpolate_Boxes,
StripInterpolate_Points,
};
struct led_strip_definition
{
u32 ControlBoxID;
u32 StartUniverse;
u32 StartChannel;
strip_interpolation_type InterpolationType;
// Interpolate Boxes
u32 StartBoxIndex;
u32 EndBoxIndex;
// Interpolate Positions
v3 InterpolatePositionStart;
v3 InterpolatePositionEnd;
// Universal Interpolation
u32 LEDsPerStrip;
};
struct assembly_definition
{
u32 LEDStripSize;
u32 LEDStripCount;
u32 TotalLEDCount;
led_strip_definition* LEDStrips;
};
#define ASSEMBLY_PARSER_H
#endif // ASSEMBLY_PARSER_H

View File

@ -100,10 +100,10 @@ NODE_PROC(SinWave, sin_wave_data)
Data->Accumulator -= Data->Period; Data->Accumulator -= Data->Period;
} }
r32 ActualMin = GSMin(Data->Min, Data->Max); r32 ActualMin = Min(Data->Min, Data->Max);
r32 ActualMax = GSMax(Data->Min, Data->Max); r32 ActualMax = Max(Data->Min, Data->Max);
r32 SinResult = GSSin((Data->Accumulator / Data->Period) * PI * 2); r32 SinResult = SinR32((Data->Accumulator / Data->Period) * PiR32 * 2);
Data->Result = GSRemap(SinResult, -1.f, 1.f, ActualMin, ActualMax); Data->Result = RemapR32(SinResult, -1.f, 1.f, ActualMin, ActualMax);
} }
else else
{ {
@ -132,28 +132,25 @@ struct multiply_patterns_data
NODE_PROC(MultiplyPatterns, multiply_patterns_data) NODE_PROC(MultiplyPatterns, multiply_patterns_data)
{ {
led* LED = Data->Result.LEDs; for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++)
for (s32 l = 0; l < Data->Result.LEDCount; l++)
{ {
Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount);
s32 AR = Data->A.Colors[LED->Index].R; s32 AR = Data->A.Colors[LedIndex].R;
s32 AG = Data->A.Colors[LED->Index].G; s32 AG = Data->A.Colors[LedIndex].G;
s32 AB = Data->A.Colors[LED->Index].B; s32 AB = Data->A.Colors[LedIndex].B;
s32 BR = Data->B.Colors[LED->Index].R; s32 BR = Data->B.Colors[LedIndex].R;
s32 BG = Data->B.Colors[LED->Index].G; s32 BG = Data->B.Colors[LedIndex].G;
s32 BB = Data->B.Colors[LED->Index].B; s32 BB = Data->B.Colors[LedIndex].B;
s32 RCombined = (AR * BR) / 255; s32 RCombined = (AR * BR) / 255;
s32 GCombined = (AG * BG) / 255; s32 GCombined = (AG * BG) / 255;
s32 BCombined = (AB * BB) / 255; s32 BCombined = (AB * BB) / 255;
Data->Result.Colors[LED->Index].R = (u8)RCombined; Data->Result.Colors[LedIndex].R = (u8)RCombined;
Data->Result.Colors[LED->Index].G = (u8)GCombined; Data->Result.Colors[LedIndex].G = (u8)GCombined;
Data->Result.Colors[LED->Index].B = (u8)BCombined; Data->Result.Colors[LedIndex].B = (u8)BCombined;
LED++;
} }
} }

View File

@ -55,7 +55,7 @@ SortNodeNeighbors(u32 ContiguousNodeIndex, gs_list_handle NodeHandle, adjacency_
} }
internal s32* internal s32*
CreateSparseToContiguousMap (pattern_node_workspace Workspace, memory_arena* Scratch) CreateSparseToContiguousMap (pattern_node_workspace Workspace, gs_memory_arena* Scratch)
{ {
s32* Result = PushArray(Scratch, s32, Workspace.Nodes.OnePastLastUsed); s32* Result = PushArray(Scratch, s32, Workspace.Nodes.OnePastLastUsed);
s32 ContiguousIndex = 0; s32 ContiguousIndex = 0;
@ -71,7 +71,7 @@ CreateSparseToContiguousMap (pattern_node_workspace Workspace, memory_arena* Scr
} }
internal void internal void
UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch) UpdateSortedNodes(pattern_node_workspace* Workspace, gs_memory_arena* Scratch)
{ {
ClearNodeWorkspaceStorage(Workspace); ClearNodeWorkspaceStorage(Workspace);
@ -119,22 +119,22 @@ UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch)
RadixSortInPlace(NeighborsListLengths, Workspace->Nodes.Used); RadixSortInPlace(NeighborsListLengths, Workspace->Nodes.Used);
char* OutputCharArray = PushArray(Scratch, char, 1024); char* OutputCharArray = PushArray(Scratch, char, 1024);
string OutputString = MakeString(OutputCharArray, 0, 1024); gs_string Outputgs_string = MakeString(OutputCharArray, 0, 1024);
PrintF(&OutputString, "Neighbors Lists: \n"); PrintF(&Outputgs_string, "Neighbors Lists: \n");
for (u32 d = 0; d < Workspace->Nodes.Used; d++) for (u32 d = 0; d < Workspace->Nodes.Used; d++)
{ {
PrintF(&OutputString, " %d: Node [ %d ] : neighbors { ", d, NeighborsListLengths[d].ID); PrintF(&Outputgs_string, " %d: Node [ %d ] : neighbors { ", d, NeighborsListLengths[d].ID);
adjacency_list* Neighbors = NeighborsLists[d]; adjacency_list* Neighbors = NeighborsLists[d];
while (Neighbors) while (Neighbors)
{ {
PrintF(&OutputString, "%d, ", Neighbors->NodeHandle.Index); PrintF(&Outputgs_string, "%d, ", Neighbors->NodeHandle.Index);
Neighbors = Neighbors->Next; Neighbors = Neighbors->Next;
} }
PrintF(&OutputString, " }\n"); PrintF(&Outputgs_string, " }\n");
} }
NullTerminate(&OutputString); NullTerminate(&Outputgs_string);
// This is a contiguous array. // This is a contiguous array.
b8* NodesVisited = PushArray(Scratch, b8, NodeCount); b8* NodesVisited = PushArray(Scratch, b8, NodeCount);
@ -163,7 +163,7 @@ UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch)
} }
internal void internal void
PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspace, memory_arena* Scratch) PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspace, gs_memory_arena* Scratch)
{ {
pattern_node* NewNode = Workspace->Nodes.TakeElement(); pattern_node* NewNode = Workspace->Nodes.TakeElement();
NewNode->SpecificationIndex = NodeSpecificationIndex; NewNode->SpecificationIndex = NodeSpecificationIndex;
@ -172,7 +172,7 @@ PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspac
} }
internal void internal void
PushNodeConnectionOnWorkspace(gs_list_handle UpstreamNodeHandle, u32 UpstreamPortIndex, gs_list_handle DownstreamNodeHandle, u32 DownstreamPortIndex, pattern_node_workspace* Workspace, memory_arena* Scratch) 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 = {}; pattern_node_connection Connection = {};
Connection.UpstreamNodeHandle = UpstreamNodeHandle; Connection.UpstreamNodeHandle = UpstreamNodeHandle;

View File

@ -14,7 +14,7 @@ typedef enum node_type node_type;
struct color_buffer struct color_buffer
{ {
led* LEDs; v4* LedPositions;
pixel* Colors; pixel* Colors;
s32 LEDCount; s32 LEDCount;
}; };
@ -59,7 +59,7 @@ struct node_specification
struct node_specification_ struct node_specification_
{ {
node_type Type; node_type Type;
string Identifier; gs_string Identifier;
gsm_struct_type DataType; gsm_struct_type DataType;
}; };
@ -92,7 +92,7 @@ struct pattern_node_workspace
// This is storage for all the structures which follow. // This is storage for all the structures which follow.
// It is cleared when new nodes are added so that the // It is cleared when new nodes are added so that the
// acceleration structures can be recalculated // acceleration structures can be recalculated
memory_arena Storage; gs_memory_arena Storage;
s32* SparseToSortedNodeMap; s32* SparseToSortedNodeMap;
gs_list_handle* SortedNodeHandles; gs_list_handle* SortedNodeHandles;
}; };

View File

@ -15,7 +15,7 @@ struct visual_port
{ {
gs_list_handle SparseNodeHandle; gs_list_handle SparseNodeHandle;
u32 PortIndex; u32 PortIndex;
rect PortBounds; rect2 PortBounds;
}; };
struct visual_connection struct visual_connection
@ -57,7 +57,7 @@ struct node_graph_state
{ {
v2 ViewOffset; v2 ViewOffset;
memory_arena LayoutMemory; gs_memory_arena LayoutMemory;
node_layout Layout; node_layout Layout;
b32 LayoutIsDirty; b32 LayoutIsDirty;
@ -111,7 +111,7 @@ OPERATION_STATE_DEF(connect_nodes_operation_state)
OPERATION_RENDER_PROC(UpdateConnectNodeOperation) OPERATION_RENDER_PROC(UpdateConnectNodeOperation)
{ {
panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.InProgressConnectionEnd = Mouse.Pos; GraphState->Layout.InProgressConnectionEnd = Mouse.Pos;
@ -121,14 +121,14 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndConnectNodesOperation)
{ {
connect_nodes_operation_state* OpState = GetCurrentOperationState(State->Modes, connect_nodes_operation_state); connect_nodes_operation_state* OpState = GetCurrentOperationState(State->Modes, connect_nodes_operation_state);
panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.ConnectionIsInProgress = false; GraphState->Layout.ConnectionIsInProgress = false;
for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++) for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++)
{ {
visual_port VisualPort = GraphState->Layout.VisualPorts[p]; visual_port VisualPort = GraphState->Layout.VisualPorts[p];
rect ViewAdjustedBounds = gs_RectOffsetByVector(VisualPort.PortBounds, GraphState->ViewOffset); rect2 ViewAdjustedBounds = gs_RectOffsetByVector(VisualPort.PortBounds, GraphState->ViewOffset);
if (gs_PointIsInRect(Mouse.Pos, ViewAdjustedBounds)) if (gs_PointIsInRect(Mouse.Pos, ViewAdjustedBounds))
{ {
visual_port UpstreamPort = (OpState->IsInput & IsInputMember) ? VisualPort : OpState->VisualPort; visual_port UpstreamPort = (OpState->IsInput & IsInputMember) ? VisualPort : OpState->VisualPort;
@ -157,7 +157,7 @@ BeginConnectNodesOperation(visual_port VisualPort, u32 VisualPortIndex, mouse_st
OpState->VisualPort = VisualPort; OpState->VisualPort = VisualPort;
OpState->VisualPortIndex = VisualPortIndex; OpState->VisualPortIndex = VisualPortIndex;
panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds);
node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory;
GraphState->Layout.ConnectionIsInProgress = true; GraphState->Layout.ConnectionIsInProgress = true;
@ -196,7 +196,7 @@ NodeGraph_Cleanup(panel* Panel, app_state* State)
} }
internal void internal void
DrawGrid (v2 Offset, v2 GridSquareDim, rect PanelBounds, render_command_buffer* RenderBuffer) DrawGrid (v2 Offset, v2 GridSquareDim, rect2 PanelBounds, render_command_buffer* RenderBuffer)
{ {
r32 LineValue = .16f; r32 LineValue = .16f;
v4 LineColor = v4{LineValue, LineValue, LineValue, 1.f}; v4 LineColor = v4{LineValue, LineValue, LineValue, 1.f};
@ -232,9 +232,9 @@ DrawGrid (v2 Offset, v2 GridSquareDim, rect PanelBounds, render_command_buffer*
} }
internal void internal void
DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, r32 LineHeight, string_alignment TextAlign, v2 TextOffset, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse) 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)
{ {
rect PortBounds = rect{v2{0, 0}, v2{6, 6}}; rect2 PortBounds = rect2{v2{0, 0}, v2{6, 6}};
v2 LinePosition = Position; v2 LinePosition = Position;
for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++) for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++)
@ -244,7 +244,7 @@ DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position,
{ {
// TODO(Peter): Can we make this rely on the same data that we use to // TODO(Peter): Can we make this rely on the same data that we use to
// render the actual connection points? // render the actual connection points?
string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength);
DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, TextAlign); DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, TextAlign);
LinePosition.y -= LineHeight; LinePosition.y -= LineHeight;
} }
@ -252,7 +252,7 @@ DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position,
} }
internal void 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, memory_arena* Scratch) 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]; gsm_struct_type_info NodeDataTypeInfo = StructTypes[NodeSpecification.DataType];
@ -264,13 +264,13 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod
if (MemberIsInput(Member)) { InputMembers++; } if (MemberIsInput(Member)) { InputMembers++; }
if (MemberIsOutput(Member)) { OutputMembers++; } if (MemberIsOutput(Member)) { OutputMembers++; }
} }
u32 LineCount = 1 + GSMax(InputMembers, OutputMembers); u32 LineCount = 1 + Max(InputMembers, OutputMembers);
v2 NodeDim = v2{ v2 NodeDim = v2{
NodeWidth, NodeWidth,
(LineHeight * LineCount) + Interface.Margin.y, (LineHeight * LineCount) + Interface.Margin.y,
}; };
rect NodeBounds = rect{ rect2 NodeBounds = rect2{
v2{ Position.x, Position.y - NodeDim.y }, v2{ Position.x, Position.y - NodeDim.y },
v2{ Position.x + NodeDim.x, Position.y }, v2{ Position.x + NodeDim.x, Position.y },
}; };
@ -282,7 +282,7 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod
PushRenderQuad2D(RenderBuffer, LinePosition, LinePosition + v2{NodeWidth, LineHeight}, v4{1.f, .24f, .39f, 1.f}); PushRenderQuad2D(RenderBuffer, LinePosition, LinePosition + v2{NodeWidth, LineHeight}, v4{1.f, .24f, .39f, 1.f});
string NodePrintName = MakeString(PushArray(Scratch, char, 256), 0, 256); gs_string NodePrintName = MakeString(PushArray(Scratch, char, 256), 0, 256);
PrintF(&NodePrintName, "%S [%d]", NodeSpecification.Identifier, NodeHandle.Index); PrintF(&NodePrintName, "%S [%d]", NodeSpecification.Identifier, NodeHandle.Index);
DrawString(RenderBuffer, NodePrintName, Interface.Font, LinePosition + TextOffset, WhiteV4); DrawString(RenderBuffer, NodePrintName, Interface.Font, LinePosition + TextOffset, WhiteV4);
LinePosition.y -= LineHeight; LinePosition.y -= LineHeight;
@ -293,7 +293,7 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod
for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++) for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++)
{ {
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i]; gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i];
string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength);
// TODO(Peter): Can we make this rely on the same data that we use to // TODO(Peter): Can we make this rely on the same data that we use to
// render the actual connection points? // render the actual connection points?
@ -329,7 +329,7 @@ GetVisualPortIndexForNode(gs_list_handle SparseNodeHandle, u32 PortIndex, node_l
} }
internal node_layout internal node_layout
ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, r32 LineHeight, memory_arena* Storage, app_state* State) ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, r32 LineHeight, gs_memory_arena* Storage, app_state* State)
{ {
node_layout Result = {}; node_layout Result = {};
@ -373,7 +373,7 @@ ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance,
{ {
gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[p]; gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[p];
rect PortBounds = {0}; rect2 PortBounds = {0};
v2 PortDim = v2{8, 8}; v2 PortDim = v2{8, 8};
PortBounds.Min = VisualNode->Position + v2{0, PortDim.y / 2}; PortBounds.Min = VisualNode->Position + v2{0, PortDim.y / 2};
if (MemberIsInput(Member)) if (MemberIsInput(Member))
@ -420,23 +420,23 @@ ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance,
GSMetaTag(panel_render); GSMetaTag(panel_render);
GSMetaTag(panel_type_node_graph); GSMetaTag(panel_type_node_graph);
internal void internal void
NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) NodeGraph_Render(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
node_graph_state* GraphState = (node_graph_state*)Panel.PanelStateMemory; node_graph_state* GraphState = (node_graph_state*)Panel.PanelStateMemory;
b32 MouseHandled = false; b32 MouseHandled = false;
rect NodeSelectionWindowBounds = rect{ rect2 NodeSelectionWindowBounds = rect2{
PanelBounds.Min, PanelBounds.Min,
v2{PanelBounds.Min.x + 300, PanelBounds.Max.y}, v2{PanelBounds.Min.x + 300, PanelBounds.Max.y},
}; };
rect GraphBounds = rect{ rect2 GraphBounds = rect2{
v2{NodeSelectionWindowBounds.Max.x, PanelBounds.Min.y}, v2{NodeSelectionWindowBounds.Max.x, PanelBounds.Min.y},
PanelBounds.Max, PanelBounds.Max,
}; };
r32 NodeWidth = 150; r32 NodeWidth = 150;
r32 LayerDistance = 100; r32 LayerDistance = 100;
r32 LineHeight = (State->Interface.Font->PixelHeight + (2 * State->Interface.Margin.y)); r32 LineHeight = ui_GetTextLineHeight(State->Interface);
if (GraphState->LayoutIsDirty) if (GraphState->LayoutIsDirty)
{ {
@ -477,7 +477,7 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf
{ {
visual_node VisualNode = GraphState->Layout.VisualNodes[i]; visual_node VisualNode = GraphState->Layout.VisualNodes[i];
gs_list_handle NodeHandle = State->NodeWorkspace.SortedNodeHandles[i]; gs_list_handle NodeHandle = State->NodeWorkspace.SortedNodeHandles[i];
DrawNode(VisualNode.Position + GraphState->ViewOffset, VisualNode.Spec, NodeHandle, NodeWidth, LineHeight, State->Interface, RenderBuffer, Mouse, &State->Transient); 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++) for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++)
@ -487,12 +487,12 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf
VisualPort.PortBounds.Max += GraphState->ViewOffset; VisualPort.PortBounds.Max += GraphState->ViewOffset;
v4 PortColor = WhiteV4; v4 PortColor = WhiteV4;
if (PointIsInRange(Mouse.Pos, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max)) if (PointIsInRange(Context.Mouse.Pos, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max))
{ {
PortColor = PinkV4; PortColor = PinkV4;
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState))
{ {
BeginConnectNodesOperation(VisualPort, p, Mouse, State); BeginConnectNodesOperation(VisualPort, p, Context.Mouse, State);
MouseHandled = true; MouseHandled = true;
} }
} }
@ -513,21 +513,21 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf
List.TextColor = WhiteV4; List.TextColor = WhiteV4;
List.ListBounds = NodeSelectionWindowBounds; List.ListBounds = NodeSelectionWindowBounds;
List.ListElementDimensions = v2{ List.ListElementDimensions = v2{
gs_Width(NodeSelectionWindowBounds), Rect2Width(NodeSelectionWindowBounds),
(r32)(State->Interface.Font->PixelHeight + 8), ui_GetTextLineHeight(State->Interface)
}; };
List.ElementLabelIndent = v2{10, 4}; List.ElementLabelIndent = v2{10, 4};
string TitleString = MakeStringLiteral("Available Nodes"); gs_string Titlegs_string = MakeStringLiteral("Available Nodes");
DrawListElement(TitleString, &List, Mouse, RenderBuffer, State->Interface); DrawListElement(Titlegs_string, &List, Context.Mouse, RenderBuffer, State->Interface.Style);
for (u32 i = 0; i < NodeType_Count; i++) for (u32 i = 0; i < NodeType_Count; i++)
{ {
node_specification_ Spec = NodeSpecifications[i]; node_specification_ Spec = NodeSpecifications[i];
rect ElementBounds = DrawListElement(Spec.Identifier, &List, Mouse, RenderBuffer, State->Interface); rect2 ElementBounds = DrawListElement(Spec.Identifier, &List, Context.Mouse, RenderBuffer, State->Interface.Style);
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState)
&& gs_PointIsInRect(Mouse.DownPos, ElementBounds)) && gs_PointIsInRect(Context.Mouse.DownPos, ElementBounds))
{ {
PushNodeOnWorkspace(i, &State->NodeWorkspace, &State->Transient); PushNodeOnWorkspace(i, &State->NodeWorkspace, &State->Transient);
GraphState->LayoutIsDirty = true; GraphState->LayoutIsDirty = true;
@ -535,9 +535,9 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf
} }
} }
if (!MouseHandled && MouseButtonTransitionedDown(Mouse.LeftButtonState)) if (!MouseHandled && MouseButtonTransitionedDown(Context.Mouse.LeftButtonState))
{ {
BeginPanNodeGraph(State, {}, Mouse); BeginPanNodeGraph(State, {}, Context.Mouse);
} }
} }

View File

@ -6,7 +6,7 @@
#ifndef FOLDHAUS_SEARCH_LISTER_CPP #ifndef FOLDHAUS_SEARCH_LISTER_CPP
internal b32 internal b32
NamePassesFilter (string Target, string Filter) NamePassesFilter (gs_string Target, gs_string Filter)
{ {
return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter)); return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter));
} }
@ -21,14 +21,14 @@ FilterSearchLister (search_lister* SearchLister)
for (s32 i = 0; i < SearchLister->SourceListCount; i++) for (s32 i = 0; i < SearchLister->SourceListCount; i++)
{ {
string* NameString = SearchLister->SourceList + i; gs_string* Namegs_string = SearchLister->SourceList + i;
if (NamePassesFilter(*NameString, SearchLister->Filter)) if (NamePassesFilter(*Namegs_string, SearchLister->Filter))
{ {
SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i; SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i;
} }
} }
SearchLister->HotItem = GSClamp(0, SearchLister->HotItem, SearchLister->FilteredListCount - 1); SearchLister->HotItem = Clamp(0, SearchLister->HotItem, SearchLister->FilteredListCount - 1);
if (SearchLister->FilteredListCount == 0) if (SearchLister->FilteredListCount == 0)
{ {
@ -39,14 +39,14 @@ FilterSearchLister (search_lister* SearchLister)
internal s32 internal s32
GetNextFilteredItem (search_lister SearchLister) GetNextFilteredItem (search_lister SearchLister)
{ {
s32 Result = GSMin(SearchLister.HotItem + 1, SearchLister.FilteredListCount - 1); s32 Result = Min(SearchLister.HotItem + 1, SearchLister.FilteredListCount - 1);
return Result; return Result;
} }
internal s32 internal s32
GetPrevFilteredItem (search_lister SearchLister) GetPrevFilteredItem (search_lister SearchLister)
{ {
s32 Result = GSMax(SearchLister.HotItem - 1, 0); s32 Result = Max(SearchLister.HotItem - 1, 0);
return Result; return Result;
} }

View File

@ -8,11 +8,11 @@
struct search_lister struct search_lister
{ {
// TODO(Peter): Giving up trying to just use the source list for now. At the moment // TODO(Peter): Giving up trying to just use the source list for now. At the moment
// we are copying the strings you want to filter from and storing them here. Come back // 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 // once its working and make the memory efficient version (ie store the existing memory
// location, the element stride and the offset to the char*) // location, the element stride and the offset to the char*)
s32 SourceListCount; s32 SourceListCount;
string* SourceList; gs_string* SourceList;
// NOTE(Peter): stores the source indecies of each filtered item // NOTE(Peter): stores the source indecies of each filtered item
// For example: // For example:
@ -23,7 +23,7 @@ struct search_lister
s32* FilteredIndexLUT; s32* FilteredIndexLUT;
s32 HotItem; s32 HotItem;
string Filter; gs_string Filter;
}; };

View File

@ -17,15 +17,14 @@ PipeSearchStringToDestination (text_entry* Input)
{ {
switch (Input->Destination.Type) switch (Input->Destination.Type)
{ {
case TextTranslateTo_String: case TextTranslateTo_gs_string:
{ {
CopyStringTo(Input->Buffer, Input->Destination.StringDest); PrintF(Input->Destination.StringDest, "%S", Input->Buffer);
}break; }break;
case TextTranslateTo_R32: case TextTranslateTo_R32:
{ {
parse_result FloatParseResult = ParseFloat(StringExpand(Input->Buffer)); *Input->Destination.FloatDest = (r32)ParseFloat(Input->Buffer.ConstString);
*Input->Destination.FloatDest = FloatParseResult.FloatValue;
}break; }break;
InvalidDefaultCase; InvalidDefaultCase;
@ -37,19 +36,22 @@ RemoveCharacterAtCursor (text_entry* TextEntry)
{ {
if (TextEntry->CursorPosition > 0) if (TextEntry->CursorPosition > 0)
{ {
RemoveCharAt(&TextEntry->Buffer, for (u32 i = TextEntry->CursorPosition - 1; i < TextEntry->Buffer.Length; i++)
TextEntry->CursorPosition - 1); {
Assert(i + 1 < TextEntry->Buffer.Size);
TextEntry->Buffer.Str[i] = TextEntry->Buffer.Str[i + 1];
}
TextEntry->CursorPosition--; TextEntry->CursorPosition--;
} }
} }
internal void internal void
SetTextInputDestinationToString (text_entry* TextInput, string* DestinationString) SetTextInputDestinationToString (text_entry* TextInput, gs_string* DestinationString)
{ {
ResetTextInput(TextInput); ResetTextInput(TextInput);
TextInput->Destination.Type = TextTranslateTo_String; TextInput->Destination.Type = TextTranslateTo_gs_string;
TextInput->Destination.StringDest = DestinationString; TextInput->Destination.StringDest = DestinationString;
CopyStringTo(*DestinationString, &TextInput->Buffer); PrintF(&TextInput->Buffer, "%S", *DestinationString);
} }
internal void internal void
@ -69,14 +71,13 @@ SetTextInputDestinationToFloat (text_entry* TextInput, r32* DestinationFloat)
internal void internal void
MoveCursorRight (text_entry* TextEntry) MoveCursorRight (text_entry* TextEntry)
{ {
TextEntry->CursorPosition = GSMin(TextEntry->Buffer.Length, TextEntry->CursorPosition = Min(TextEntry->Buffer.Length, TextEntry->CursorPosition + 1);
TextEntry->CursorPosition + 1);
} }
internal void internal void
MoveCursorLeft (text_entry* TextEntry) MoveCursorLeft (text_entry* TextEntry)
{ {
TextEntry->CursorPosition = GSMax(0, TextEntry->CursorPosition - 1); TextEntry->CursorPosition = Max(0, TextEntry->CursorPosition - 1);
} }
FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar) FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar)
@ -88,12 +89,21 @@ FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar)
Char += ('a' - 'A'); Char += ('a' - 'A');
} }
InsertChar(&State->ActiveTextEntry.Buffer, Char, State->ActiveTextEntry.CursorPosition); // 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++; State->ActiveTextEntry.CursorPosition++;
PipeSearchStringToDestination(&State->ActiveTextEntry); PipeSearchStringToDestination(&State->ActiveTextEntry);
} }
FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntryString) FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntrygs_string)
{ {
RemoveCharacterAtCursor(&State->ActiveTextEntry); RemoveCharacterAtCursor(&State->ActiveTextEntry);
} }
@ -109,11 +119,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorLeft)
} }
internal void internal void
InitializeTextInputCommands (input_command_registry* Commands, memory_arena* PermanentStorage) InitializeTextInputCommands (input_command_registry* Commands, gs_memory_arena* PermanentStorage)
{ {
if (Commands->Size > 0) if (Commands->Size > 0)
{ {
RegisterKeyPressCommand(Commands, KeyCode_Backspace, Command_Began | Command_Held, KeyCode_Invalid, RemoveCharacterFromEntryString); 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_LeftArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorLeft);
RegisterKeyPressCommand(Commands, KeyCode_RightArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorRight); RegisterKeyPressCommand(Commands, KeyCode_RightArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorRight);
@ -126,7 +136,7 @@ InitializeTextInputCommands (input_command_registry* Commands, memory_arena* Per
} }
#define DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY \ #define DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY \
{ KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, RemoveCharacterFromEntryString }, \ { KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, RemoveCharacterFromEntrygs_string }, \
{ KeyCode_LeftArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorLeft }, \ { KeyCode_LeftArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorLeft }, \
{ KeyCode_RightArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorRight }, \ { KeyCode_RightArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorRight }, \
{ KeyCode_a, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \ { KeyCode_a, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \

View File

@ -7,7 +7,7 @@
enum text_translation_type enum text_translation_type
{ {
TextTranslateTo_String, TextTranslateTo_gs_string,
TextTranslateTo_R32, TextTranslateTo_R32,
TextTranslateTo_S32, TextTranslateTo_S32,
TextTranslateTo_U32, TextTranslateTo_U32,
@ -17,7 +17,7 @@ struct text_entry_destination
{ {
text_translation_type Type; text_translation_type Type;
union { union {
string* StringDest; gs_string* StringDest;
r32* FloatDest; r32* FloatDest;
s32* SignedIntDest; s32* SignedIntDest;
u32* UnsignedIntDest; u32* UnsignedIntDest;
@ -26,7 +26,7 @@ struct text_entry_destination
struct text_entry struct text_entry
{ {
string Buffer; gs_string Buffer;
s32 CursorPosition; s32 CursorPosition;
text_entry_destination Destination; text_entry_destination Destination;

View File

@ -10,42 +10,42 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <gs_string.h>
#include "gs/gs_language.h" #include "gs/gs_language.h"
#include "gs/gs_string.h" #include "gs/gs_string.h"
#include "../meta/gs_meta_lexer.h" #include "../meta/gs_meta_lexer.h"
#include "gs/gs_vector.h" #include "gs/gs_vector.h"
#define STRING_BUFFER_SIZE 512 #define gs_string_BUFFER_SIZE 512
struct string_buffer struct gs_string_buffer
{ {
char* Memory; char* Memory;
s32 Size; s32 Size;
string_buffer* Next; gs_string_buffer* Next;
}; };
struct string_writer struct gs_string_writer
{ {
char* Cursor; char* Cursor;
s32 UsedInString; s32 UsedIngs_string;
string_buffer* Buffer; gs_string_buffer* Buffer;
}; };
internal string_buffer* internal gs_string_buffer*
GrowStringBuffer (string_buffer* Buffer) Growgs_stringBuffer (gs_string_buffer* Buffer)
{ {
string_buffer* Result; gs_string_buffer* Result;
if (Buffer->Next) if (Buffer->Next)
{ {
Result = GrowStringBuffer(Buffer->Next); Result = Growgs_stringBuffer(Buffer->Next);
} }
else else
{ {
Result = (string_buffer*)malloc(sizeof(string_buffer)); Result = (gs_string_buffer*)malloc(sizeof(gs_string_buffer));
Result->Memory = (char*)malloc(sizeof(char) * STRING_BUFFER_SIZE); Result->Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE);
memset(Result->Memory, 0, STRING_BUFFER_SIZE); memset(Result->Memory, 0, gs_string_BUFFER_SIZE);
Result->Size = STRING_BUFFER_SIZE; Result->Size = gs_string_BUFFER_SIZE;
Result->Next = 0; Result->Next = 0;
Buffer->Next = Result; Buffer->Next = Result;
@ -54,28 +54,28 @@ GrowStringBuffer (string_buffer* Buffer)
} }
internal void internal void
WriteString(string_writer* Writer, char* String, s32 Length) Writegs_string(gs_string_writer* Writer, char* gs_string, s32 Length)
{ {
char* Src = String; char* Src = gs_string;
char* Dst = Writer->Cursor; char* Dst = Writer->Cursor;
s32 LengthWritten = 0; s32 LengthWritten = 0;
while (*Src && Writer->UsedInString < Writer->Buffer->Size &&LengthWritten < Length) while (*Src && Writer->UsedIngs_string < Writer->Buffer->Size &&LengthWritten < Length)
{ {
LengthWritten++; LengthWritten++;
*Dst++ = *Src++; *Dst++ = *Src++;
Writer->UsedInString++; Writer->UsedIngs_string++;
} }
Writer->Cursor = Dst; Writer->Cursor = Dst;
if (*Src && Writer->UsedInString == Writer->Buffer->Size) if (*Src && Writer->UsedIngs_string == Writer->Buffer->Size)
{ {
*(Dst - 1) = 0; // Null terminate the buffer *(Dst - 1) = 0; // Null terminate the buffer
Writer->Buffer = GrowStringBuffer(Writer->Buffer); Writer->Buffer = Growgs_stringBuffer(Writer->Buffer);
Writer->Cursor = Writer->Buffer->Memory; Writer->Cursor = Writer->Buffer->Memory;
Writer->UsedInString = 0; Writer->UsedIngs_string = 0;
WriteString(Writer, (Src - 1), (Length - LengthWritten) + 1); Writegs_string(Writer, (Src - 1), (Length - LengthWritten) + 1);
} }
} }
@ -141,15 +141,15 @@ int main(int ArgCount, char* Args[])
control_box_pairs* StartPair = NextControlBoxPair; control_box_pairs* StartPair = NextControlBoxPair;
s32 PairsCount = 0; s32 PairsCount = 0;
if (StringsEqual(Tokenizer.At, "EOF")) if (gs_stringsEqual(Tokenizer.At, "EOF"))
{ {
break; break;
} }
EatToCharacterInclusive(&Tokenizer, '{'); EatToCharacterInclusive(&Tokenizer, '{');
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
Assert(StringsEqual(Tokenizer.At, "neighbors: [")); Assert(gs_stringsEqual(Tokenizer.At, "neighbors: ["));
Tokenizer.At += StringLength("neighbors: ["); Tokenizer.At += gs_stringLength("neighbors: [");
// Parse Neighbors // Parse Neighbors
while(*Tokenizer.At && *Tokenizer.At != ']') while(*Tokenizer.At && *Tokenizer.At != ']')
@ -177,8 +177,8 @@ int main(int ArgCount, char* Args[])
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
//Parse IP //Parse IP
Assert(StringsEqual(Tokenizer.At, "ip: ")); Assert(gs_stringsEqual(Tokenizer.At, "ip: "));
Tokenizer.At += StringLength("ip: "); Tokenizer.At += gs_stringLength("ip: ");
NextControlBox->Address = (char*)malloc(sizeof(char) * 13); NextControlBox->Address = (char*)malloc(sizeof(char) * 13);
memcpy(NextControlBox->Address, Tokenizer.At, 13); memcpy(NextControlBox->Address, Tokenizer.At, 13);
Tokenizer.At += 13; Tokenizer.At += 13;
@ -186,27 +186,27 @@ int main(int ArgCount, char* Args[])
// Parse X // Parse X
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
Assert(StringsEqual(Tokenizer.At, "x: ")); Assert(gs_stringsEqual(Tokenizer.At, "x: "));
Tokenizer.At += StringLength("x: "); Tokenizer.At += gs_stringLength("x: ");
NextControlBox->X = ParseFloat(Tokenizer.At); NextControlBox->X = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';'); EatToCharacterInclusive(&Tokenizer, ';');
// Parse Y // Parse Y
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
Assert(StringsEqual(Tokenizer.At, "y: ")); Assert(gs_stringsEqual(Tokenizer.At, "y: "));
Tokenizer.At += StringLength("y: "); Tokenizer.At += gs_stringLength("y: ");
NextControlBox->Y = ParseFloat(Tokenizer.At); NextControlBox->Y = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';'); EatToCharacterInclusive(&Tokenizer, ';');
// Parse Z // Parse Z
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
Assert(StringsEqual(Tokenizer.At, "z: ")); Assert(gs_stringsEqual(Tokenizer.At, "z: "));
Tokenizer.At += StringLength("z: "); Tokenizer.At += gs_stringLength("z: ");
NextControlBox->Z = ParseFloat(Tokenizer.At); NextControlBox->Z = ParseFloat(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';'); EatToCharacterInclusive(&Tokenizer, ';');
// Parse ID // Parse ID
EatWhitespace(&Tokenizer); EatWhitespace(&Tokenizer);
Assert(StringsEqual(Tokenizer.At, "id: ")); Assert(gs_stringsEqual(Tokenizer.At, "id: "));
Tokenizer.At += StringLength("id: "); Tokenizer.At += gs_stringLength("id: ");
NextControlBox->ID = ParseSignedInt(Tokenizer.At); NextControlBox->ID = ParseSignedInt(Tokenizer.At);
EatToCharacterInclusive(&Tokenizer, ';'); EatToCharacterInclusive(&Tokenizer, ';');
@ -278,36 +278,36 @@ int main(int ArgCount, char* Args[])
} }
string_buffer OutputFileBuffer = {}; gs_string_buffer OutputFileBuffer = {};
OutputFileBuffer.Memory = (char*)malloc(sizeof(char) * STRING_BUFFER_SIZE); OutputFileBuffer.Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE);
OutputFileBuffer.Size = STRING_BUFFER_SIZE; OutputFileBuffer.Size = gs_string_BUFFER_SIZE;
OutputFileBuffer.Next = 0; OutputFileBuffer.Next = 0;
string_writer RefWriter = {}; gs_string_writer RefWriter = {};
RefWriter.Cursor = OutputFileBuffer.Memory; RefWriter.Cursor = OutputFileBuffer.Memory;
RefWriter.UsedInString = 0; RefWriter.UsedIngs_string = 0;
RefWriter.Buffer = &OutputFileBuffer; RefWriter.Buffer = &OutputFileBuffer;
string_writer* Writer = &RefWriter; gs_string_writer* Writer = &RefWriter;
char StringBuffer[512]; char gs_stringBuffer[512];
s32 Len = 0; s32 Len = 0;
Len = sprintf_s(StringBuffer, 512, "control_box_count %d\n", ControlBoxesUsed); Len = sprintf_s(gs_stringBuffer, 512, "control_box_count %d\n", ControlBoxesUsed);
WriteString(Writer, StringBuffer, Len); Writegs_string(Writer, gs_stringBuffer, Len);
Len = sprintf_s(StringBuffer, 512, "led_strip_count %d\n\n", ControlBoxPairsUsed); Len = sprintf_s(gs_stringBuffer, 512, "led_strip_count %d\n\n", ControlBoxPairsUsed);
WriteString(Writer, StringBuffer, Len); Writegs_string(Writer, gs_stringBuffer, Len);
for (s32 c = 0; c < ControlBoxesUsed; c++) for (s32 c = 0; c < ControlBoxesUsed; c++)
{ {
control_box* Box = ControlBoxes + c; control_box* Box = ControlBoxes + c;
Len = sprintf_s(StringBuffer, 512, Len = sprintf_s(gs_stringBuffer, 512,
"control_box { %d, \"%s\", (%f, %f, %f) }\n", "control_box { %d, \"%s\", (%f, %f, %f) }\n",
Box->ID, Box->Address, Box->ID, Box->Address,
Box->X, Box->Y, Box->Z); Box->X, Box->Y, Box->Z);
WriteString(Writer, StringBuffer, Len); Writegs_string(Writer, gs_stringBuffer, Len);
} }
WriteString(Writer, "\n", 1); Writegs_string(Writer, "\n", 1);
#define UNIVERSES_PER_BOX 25 #define UNIVERSES_PER_BOX 25
s32 UniversesPerBox[64]; s32 UniversesPerBox[64];
@ -316,7 +316,7 @@ int main(int ArgCount, char* Args[])
UniversesPerBox[u] = UNIVERSES_PER_BOX * u; UniversesPerBox[u] = UNIVERSES_PER_BOX * u;
} }
char LEDStripFormatString[] = "led_strip { %d, %d, %d, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 144 } \n"; 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++) for (s32 s = 0; s < ControlBoxPairsUsed; s++)
{ {
control_box_pairs* Pair = ControlBoxPairs + s; control_box_pairs* Pair = ControlBoxPairs + s;
@ -332,15 +332,15 @@ int main(int ArgCount, char* Args[])
r32 EndY = ControlBoxes[Pair->End].Y; r32 EndY = ControlBoxes[Pair->End].Y;
r32 EndZ = ControlBoxes[Pair->End].Z; r32 EndZ = ControlBoxes[Pair->End].Z;
Len = sprintf_s(StringBuffer, 512, Len = sprintf_s(gs_stringBuffer, 512,
LEDStripFormatString, LEDStripFormatgs_string,
Pair->Start, Universe, 0, Pair->Start, Universe, 0,
StartX, StartY, StartZ, StartX, StartY, StartZ,
EndX, EndY, EndZ); EndX, EndY, EndZ);
WriteString(Writer, StringBuffer, Len); Writegs_string(Writer, gs_stringBuffer, Len);
} }
WriteString(Writer, "\n", 1); Writegs_string(Writer, "\n", 1);
for (s32 sp = 0; sp < ExtraStripsUsed; sp++) for (s32 sp = 0; sp < ExtraStripsUsed; sp++)
{ {
@ -349,20 +349,20 @@ int main(int ArgCount, char* Args[])
s32 Universe = UniversesPerBox[Strip->BoxID]; s32 Universe = UniversesPerBox[Strip->BoxID];
UniversesPerBox[Strip->BoxID]++; UniversesPerBox[Strip->BoxID]++;
Len = sprintf_s(StringBuffer, 512, Len = sprintf_s(gs_stringBuffer, 512,
LEDStripFormatString, LEDStripFormatgs_string,
Strip->BoxID, Universe, 0, Strip->BoxID, Universe, 0,
Strip->Start.x, Strip->Start.y, Strip->Start.z, Strip->Start.x, Strip->Start.y, Strip->Start.z,
Strip->End.x, Strip->End.y, Strip->End.z); Strip->End.x, Strip->End.y, Strip->End.z);
WriteString(Writer, StringBuffer, Len); Writegs_string(Writer, gs_stringBuffer, Len);
} }
WriteString(Writer, "END_OF_ASSEMBLY_FILE", StringLength("END_OF_ASSEMBLY_FILE")); Writegs_string(Writer, "END_OF_ASSEMBLY_FILE", gs_stringLength("END_OF_ASSEMBLY_FILE"));
*Writer->Cursor = 0; *Writer->Cursor = 0;
FILE* OutputFile = fopen("F:/data/radialumia.fold", "w"); FILE* OutputFile = fopen("F:/data/radialumia.fold", "w");
string_buffer* BufferCursor = &OutputFileBuffer; gs_string_buffer* BufferCursor = &OutputFileBuffer;
while(BufferCursor) while(BufferCursor)
{ {
fprintf(OutputFile, BufferCursor->Memory); fprintf(OutputFile, BufferCursor->Memory);

View File

@ -18,7 +18,7 @@ struct node_lister_operation_state
}; };
internal void internal void
RenderNodeLister(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) 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; node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory;
@ -90,7 +90,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister)
node_lister_operation_state); node_lister_operation_state);
{ {
OpState->SearchLister.SourceListCount = NodeSpecificationsCount; OpState->SearchLister.SourceListCount = NodeSpecificationsCount;
OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, string, OpState->SearchLister.SourceListCount); OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, gs_string, OpState->SearchLister.SourceListCount);
{ {
for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++)
{ {
@ -107,7 +107,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister)
} }
OpState->ListPosition = Mouse.Pos; OpState->ListPosition = Mouse.Pos;
SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); SetTextInputDestinationTogs_string(&State->ActiveTextEntry, &OpState->SearchLister.Filter);
} }
//////////////////////////////////////// ////////////////////////////////////////
@ -133,7 +133,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand)
} }
internal void internal void
RenderColorPicker(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) 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; color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory;
@ -202,7 +202,7 @@ struct drag_node_port_operation_state
}; };
internal void internal void
RenderDraggingNodePort(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) 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; drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory;
UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList,
@ -242,7 +242,7 @@ BeginDraggingNodePort(app_state* State, node_interaction Interaction)
/////////////////////////////////////// ///////////////////////////////////////
internal void internal void
RenderDragNodeField(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) RenderDragNodeField(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse)
{ {
// TODO(Peter): // TODO(Peter):
//UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State); //UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State);
@ -266,7 +266,7 @@ struct drag_node_operation_state
}; };
internal void internal void
RenderDraggingNode(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) 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); drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state);
UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList,
@ -368,7 +368,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction)
} }
internal void internal void
RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) 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; node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory;
@ -383,7 +383,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
{ {
node_header* Node = NodeIter.At; node_header* Node = NodeIter.At;
rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); rect2 NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings);
b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds);
if (Node == SelectedNode) if (Node == SelectedNode)
@ -394,8 +394,8 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f}); 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 // TODO(Peter): This is just for debug purposes. We can remove and go back to just having
// Node->Name in DrawString // Node->Name in Drawgs_string
string NodeName = GetNodeName(*Node); gs_string NodeName = GetNodeName(*Node);
PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle); PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle);
DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font, DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font,
v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)}, v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)},
@ -408,7 +408,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
// Inputs // Inputs
if (ConnectionIsInput(Node, Connection)) if (ConnectionIsInput(Node, Connection))
{ {
rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); rect2 PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings);
DrawPort(RenderBuffer, PortBounds, PortColor); DrawPort(RenderBuffer, PortBounds, PortColor);
// //
@ -427,7 +427,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right); v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right);
} }
rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings); rect2 ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings);
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); 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, // NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship,
@ -436,7 +436,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
// most downstream node and working back up to find dependencies. // most downstream node and working back up to find dependencies.
if (ConnectionHasUpstreamConnection(Node, Connection)) if (ConnectionHasUpstreamConnection(Node, Connection))
{ {
rect ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); rect2 ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings);
v2 InputCenter = CalculateRectCenter(PortBounds); v2 InputCenter = CalculateRectCenter(PortBounds);
v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds);
PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4);
@ -446,7 +446,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
// Outputs // Outputs
if (ConnectionIsOutput(Node, Connection)) if (ConnectionIsOutput(Node, Connection))
{ {
rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); rect2 PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings);
DrawPort(RenderBuffer, PortBounds, PortColor); DrawPort(RenderBuffer, PortBounds, PortColor);
if (DrawFields) if (DrawFields)
@ -458,13 +458,13 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer
v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4);
} }
rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); rect2 ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings);
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font);
} }
for (s32 Button = 0; Button < 3; Button++) for (s32 Button = 0; Button < 3; Button++)
{ {
rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); rect2 ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings);
PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]);
} }
} }

View File

@ -1,57 +0,0 @@
//
// File: DMX_H
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef DMX_H
struct dmx_buffer
{
s32 Universe;
u8* Base;
s32 TotalSize;
s32 HeaderSize;
};
struct dmx_buffer_list
{
dmx_buffer Buffer;
dmx_buffer_list* Next;
};
internal dmx_buffer_list*
DMXBufferListGetTail (dmx_buffer_list* List)
{
dmx_buffer_list* Result = 0;
if (List->Next == 0)
{
Result = List;
}
else
{
Result = DMXBufferListGetTail(List->Next);
}
return Result;
}
internal dmx_buffer_list*
DMXBufferListAppend (dmx_buffer_list* AppendTo, dmx_buffer_list* Append)
{
dmx_buffer_list* Result = 0;
if (AppendTo)
{
dmx_buffer_list* Tail = DMXBufferListGetTail(AppendTo);
Tail->Next = Append;
Result = AppendTo;
}
else
{
Result = Append;
}
return Result;
}
#define DMX_H
#endif // DMX_H

View File

@ -5,7 +5,7 @@
// //
#ifndef FOLDHAUS_COMMAND_DISPATCH_H #ifndef FOLDHAUS_COMMAND_DISPATCH_H
#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse) #define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse, context Context)
typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc); typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc);
// NOTE(Peter): Helper function so I don't have to remember the parameters to this define // NOTE(Peter): Helper function so I don't have to remember the parameters to this define
@ -55,7 +55,7 @@ struct input_command_queue
internal void internal void
InitializeInputCommandRegistry (input_command_registry* CommandRegistry, InitializeInputCommandRegistry (input_command_registry* CommandRegistry,
s32 Size, s32 Size,
memory_arena* Storage) gs_memory_arena* Storage)
{ {
CommandRegistry->Commands = PushArray(Storage, input_command, Size); CommandRegistry->Commands = PushArray(Storage, input_command, Size);
CommandRegistry->Size = Size; CommandRegistry->Size = Size;

View File

@ -19,19 +19,6 @@ enum panel_edit_mode
PanelEdit_Count, PanelEdit_Count,
}; };
internal void
SetPanelDefinition(panel* Panel, s32 NewPanelDefinitionIndex, app_state* State)
{
s32 OldPanelDefinitionIndex = Panel->PanelDefinitionIndex;
Panel->PanelDefinitionIndex = NewPanelDefinitionIndex;
if(OldPanelDefinitionIndex >= 0)
{
GlobalPanelDefs[OldPanelDefinitionIndex].Cleanup(Panel, State);
}
GlobalPanelDefs[NewPanelDefinitionIndex].Init(Panel, State);
}
// //
// Drag Panel Border Operation Mode // Drag Panel Border Operation Mode
@ -41,7 +28,7 @@ OPERATION_STATE_DEF(drag_panel_border_operation_state)
// NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying,
// it stores the value calculated when the operation mode is kicked off. // it stores the value calculated when the operation mode is kicked off.
rect InitialPanelBounds; rect2 InitialPanelBounds;
panel_split_direction PanelEdgeDirection; panel_split_direction PanelEdgeDirection;
panel_edit_mode PanelEditMode; panel_edit_mode PanelEditMode;
}; };
@ -49,7 +36,7 @@ OPERATION_STATE_DEF(drag_panel_border_operation_state)
OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder)
{ {
drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory; drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory;
rect PanelBounds = OpState->InitialPanelBounds; rect2 PanelBounds = OpState->InitialPanelBounds;
if (OpState->PanelEditMode == PanelEdit_Modify) if (OpState->PanelEditMode == PanelEdit_Modify)
{ {
@ -72,10 +59,10 @@ OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder)
} }
else if (OpState->PanelEditMode == PanelEdit_Destroy) else if (OpState->PanelEditMode == PanelEdit_Destroy)
{ {
rect PanelToDeleteBounds = {}; rect2 PanelToDeleteBounds = {};
if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) if (OpState->PanelEdgeDirection == PanelSplit_Horizontal)
{ {
r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
if (Mouse.Pos.y > SplitY) if (Mouse.Pos.y > SplitY)
{ {
PanelToDeleteBounds = GetTopPanelBounds(OpState->Panel, PanelBounds); PanelToDeleteBounds = GetTopPanelBounds(OpState->Panel, PanelBounds);
@ -87,7 +74,7 @@ OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder)
} }
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
{ {
r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
if (Mouse.Pos.x > SplitX) if (Mouse.Pos.x > SplitX)
{ {
PanelToDeleteBounds = GetRightPanelBounds(OpState->Panel, PanelBounds); PanelToDeleteBounds = GetRightPanelBounds(OpState->Panel, PanelBounds);
@ -106,7 +93,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
{ {
drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state); drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state);
panel* Panel = OpState->Panel; panel* Panel = OpState->Panel;
rect PanelBounds = OpState->InitialPanelBounds; rect2 PanelBounds = OpState->InitialPanelBounds;
if (OpState->PanelEditMode == PanelEdit_Modify) if (OpState->PanelEditMode == PanelEdit_Modify)
{ {
@ -123,7 +110,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
} }
else else
{ {
Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / gs_Height(PanelBounds); Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
} }
} }
else if (Panel->SplitDirection == PanelSplit_Vertical) else if (Panel->SplitDirection == PanelSplit_Vertical)
@ -139,7 +126,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
} }
else else
{ {
Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / gs_Width(PanelBounds); Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds);
} }
} }
} }
@ -147,7 +134,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
{ {
if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) if (OpState->PanelEdgeDirection == PanelSplit_Horizontal)
{ {
r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
if (Mouse.Pos.y > SplitY) if (Mouse.Pos.y > SplitY)
{ {
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem);
@ -159,7 +146,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
} }
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
{ {
r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
if (Mouse.Pos.x > SplitX) if (Mouse.Pos.x > SplitX)
{ {
ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem);
@ -180,7 +167,7 @@ input_command DragPanelBorderCommands[] = {
}; };
internal void internal void
BeginDragPanelBorder(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, panel_split_direction PanelEdgeDirection, mouse_state Mouse, app_state* State) 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); operation_mode* DragPanelBorder = ActivateOperationModeWithCommands(&State->Modes, DragPanelBorderCommands, UpdateAndRenderDragPanelBorder);
drag_panel_border_operation_state* OpState = CreateOperationState(DragPanelBorder, &State->Modes, drag_panel_border_operation_state); drag_panel_border_operation_state* OpState = CreateOperationState(DragPanelBorder, &State->Modes, drag_panel_border_operation_state);
@ -202,17 +189,17 @@ OPERATION_STATE_DEF(split_panel_operation_state)
// NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying,
// it stores the value calculated when the operation mode is kicked off. // it stores the value calculated when the operation mode is kicked off.
rect InitialPanelBounds; rect2 InitialPanelBounds;
}; };
OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel) OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel)
{ {
split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory; split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory;
rect PanelBounds = OpState->InitialPanelBounds; rect2 PanelBounds = OpState->InitialPanelBounds;
v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f}; v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f};
r32 MouseDeltaX = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); r32 MouseDeltaX = Abs(Mouse.Pos.x - Mouse.DownPos.x);
r32 MouseDeltaY = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); r32 MouseDeltaY = Abs(Mouse.Pos.y - Mouse.DownPos.y);
v2 EdgePreviewMin = {}; v2 EdgePreviewMin = {};
v2 EdgePreviewMax = {}; v2 EdgePreviewMax = {};
@ -234,27 +221,27 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation)
{ {
split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state); split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state);
panel* Panel = OpState->Panel; panel* Panel = OpState->Panel;
rect PanelBounds = OpState->InitialPanelBounds; rect2 PanelBounds = OpState->InitialPanelBounds;
r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); r32 XDistance = Abs(Mouse.Pos.x - Mouse.DownPos.x);
r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); r32 YDistance = Abs(Mouse.Pos.y - Mouse.DownPos.y);
if (XDistance > YDistance) if (XDistance > YDistance)
{ {
r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / gs_Width(PanelBounds); r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Rect2Width(PanelBounds);
SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); SplitPanelVertically(Panel, XPercent, &State->PanelSystem, State, Context);
} }
else else
{ {
r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / gs_Height(PanelBounds); r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Rect2Height(PanelBounds);
SplitPanelHorizontally(Panel, YPercent, PanelBounds, &State->PanelSystem); SplitPanelHorizontally(Panel, YPercent, &State->PanelSystem, State, Context);
} }
Panel->Left->Panel.PanelDefinitionIndex = Panel->PanelDefinitionIndex; s32 PanelTypeIndex = Panel->TypeIndex;
Panel->Left->Panel.PanelStateMemory = Panel->PanelStateMemory; gs_data PanelStateMemory = Panel->StateMemory;
Panel->Left->Panel.PanelStateMemorySize = Panel->PanelStateMemorySize; Panel_SetCurrentType(&Panel->Left->Panel, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context);
SetPanelDefinition(&Panel->Right->Panel, Panel->PanelDefinitionIndex, State); SetAndInitPanelType(&Panel->Right->Panel, &State->PanelSystem, PanelTypeIndex, State, Context);
DeactivateCurrentOperationMode(&State->Modes); DeactivateCurrentOperationMode(&State->Modes);
} }
@ -264,7 +251,7 @@ input_command SplitPanelCommands[] = {
}; };
internal void internal void
BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_state* State) BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app_state* State)
{ {
operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel);
split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state);
@ -278,20 +265,22 @@ BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_
#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 #define PANEL_EDGE_CLICK_MAX_DISTANCE 6
internal b32 internal b32
HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, mouse_state Mouse, app_state* State) HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect2 PanelBounds, mouse_state Mouse, app_state* State)
{ {
b32 HandledMouseInput = false; b32 HandledMouseInput = false;
rect2 PanelSplitButtonBounds = rect2{ PanelBounds.Min, PanelBounds.Min + v2{25, 25} };
if (Panel->SplitDirection == PanelSplit_NoSplit if (Panel->SplitDirection == PanelSplit_NoSplit
&& PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) && PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos))
{ {
BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State); BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State);
HandledMouseInput = true; HandledMouseInput = true;
} }
else if (Panel->SplitDirection == PanelSplit_Horizontal) else if (Panel->SplitDirection == PanelSplit_Horizontal)
{ {
r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); r32 SplitY = LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.y - SplitY);
if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE)
{ {
BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State); BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State);
@ -299,13 +288,13 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit
} }
else else
{ {
rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (gs_PointIsInRect(Mouse.DownPos, BottomPanelBounds)) if (PointIsInRect(BottomPanelBounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State);
} }
if (gs_PointIsInRect(Mouse.DownPos, TopPanelBounds)) if (PointIsInRect(TopPanelBounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State);
} }
@ -313,8 +302,8 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit
} }
else if (Panel->SplitDirection == PanelSplit_Vertical) else if (Panel->SplitDirection == PanelSplit_Vertical)
{ {
r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); r32 SplitX = LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.x - SplitX);
if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE)
{ {
BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State); BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State);
@ -322,13 +311,13 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit
} }
else else
{ {
rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
if (gs_PointIsInRect(Mouse.DownPos, LeftPanelBounds)) if (PointIsInRect(LeftPanelBounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State);
} }
if (gs_PointIsInRect(Mouse.DownPos, RightPanelBounds)) if (PointIsInRect(RightPanelBounds, Mouse.DownPos))
{ {
HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State); HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State);
} }
@ -339,7 +328,7 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit
} }
internal b32 internal b32
HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_state Mouse, app_state* State) HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse_state Mouse, app_state* State)
{ {
b32 HandledMouseInput = false; b32 HandledMouseInput = false;
@ -359,10 +348,10 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_
internal void internal void
DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mouse, render_command_buffer* RenderBuffer) DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mouse, render_command_buffer* RenderBuffer)
{ {
r32 MouseLeftEdgeDistance = GSAbs(Mouse->Pos.x - PanelMin.x); r32 MouseLeftEdgeDistance = Abs(Mouse->Pos.x - PanelMin.x);
r32 MouseRightEdgeDistance = GSAbs(Mouse->Pos.x - PanelMax.x); r32 MouseRightEdgeDistance = Abs(Mouse->Pos.x - PanelMax.x);
r32 MouseTopEdgeDistance = GSAbs(Mouse->Pos.y - PanelMax.y); r32 MouseTopEdgeDistance = Abs(Mouse->Pos.y - PanelMax.y);
r32 MouseBottomEdgeDistance = GSAbs(Mouse->Pos.y - PanelMin.y); r32 MouseBottomEdgeDistance = Abs(Mouse->Pos.y - PanelMin.y);
PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color);
v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; v4 HighlightColor = v4{.3f, .3f, .3f, 1.f};
@ -398,41 +387,46 @@ DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mo
} }
internal void internal void
DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, mouse_state Mouse, app_state* State) 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, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f});
PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4);
rect PanelSelectBtnBounds = gs_MakeRectMinWidth(FooterBounds.Min + v2{30, 1}, v2{100, 23}); rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23});
if (Panel->PanelSelectionMenuOpen) if (Panel->PanelSelectionMenuOpen)
{ {
rect ButtonBounds = gs_MakeRectMinWidth(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 }); rect2 ButtonBounds = MakeRect2MinDim(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 });
rect2 MenuBounds = rect2
{
ButtonBounds.Min,
v2{
ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * GlobalPanelDefsCount)
},
};
v2 MenuMin = ButtonBounds.Min;
v2 MenuMax = v2{ButtonBounds.Min.x + gs_Width(ButtonBounds), ButtonBounds.Min.y + (gs_Height(ButtonBounds) * GlobalPanelDefsCount)};
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) if (MouseButtonTransitionedDown(Mouse.LeftButtonState)
&& !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) && !PointIsInRect(MenuBounds, Mouse.DownPos))
{ {
Panel->PanelSelectionMenuOpen = false; Panel->PanelSelectionMenuOpen = false;
} }
for (s32 i = 0; i < GlobalPanelDefsCount; i++) for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{ {
panel_definition Def = GlobalPanelDefs[i]; panel_definition Def = GlobalPanelDefs[i];
string DefName = MakeString(Def.PanelName, Def.PanelNameLength); gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
if (ui_Button(&State->Interface_, DefName, ButtonBounds)) if (ui_Button(&State->Interface, DefName, ButtonBounds))
{ {
SetPanelDefinition(Panel, i, State); SetAndInitPanelType(Panel, &State->PanelSystem, i, State, Context);
Panel->PanelSelectionMenuOpen = false; Panel->PanelSelectionMenuOpen = false;
} }
ButtonBounds = gs_TranslateRectY(ButtonBounds, gs_Height(ButtonBounds)); ButtonBounds = Rect2TranslateY(ButtonBounds, Rect2Height(ButtonBounds));
} }
} }
if (ui_Button(&State->Interface_, MakeStringLiteral("Select"), PanelSelectBtnBounds)) if (ui_Button(&State->Interface, MakeString("Select"), PanelSelectBtnBounds))
{ {
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
} }
@ -440,24 +434,25 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBo
} }
internal void internal void
RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{ {
Assert(Panel->PanelDefinitionIndex >= 0); s32 PanelType = Panel->TypeIndex;
Assert(PanelType >= 0);
rect FooterBounds = rect{ rect2 FooterBounds = rect2{
PanelBounds.Min, PanelBounds.Min,
v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, v2{PanelBounds.Max.x, PanelBounds.Min.y + 25},
}; };
rect PanelViewBounds = rect{ rect2 PanelViewBounds = rect2{
v2{PanelBounds.Min.x, FooterBounds.Max.y}, v2{PanelBounds.Min.x, FooterBounds.Max.y},
PanelBounds.Max, PanelBounds.Max,
}; };
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; panel_definition Definition = GlobalPanelDefs[PanelType];
Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); Definition.Render(Panel, PanelViewBounds, RenderBuffer, State, Context);
PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); PushRenderOrthographic(RenderBuffer, WindowBounds);
DrawPanelFooter(Panel, RenderBuffer, FooterBounds, Mouse, State); DrawPanelFooter(Panel, RenderBuffer, FooterBounds, Mouse, State, Context);
} }
internal void internal void
@ -467,16 +462,15 @@ DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mou
{ {
panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; panel_with_layout PanelWithLayout = PanelLayout.Panels[i];
panel* Panel = PanelWithLayout.Panel; panel* Panel = PanelWithLayout.Panel;
rect PanelBounds = PanelWithLayout.Bounds; rect2 PanelBounds = PanelWithLayout.Bounds;
RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
v4 BorderColor = v4{0, 0, 0, 1}; v4 BorderColor = v4{0, 0, 0, 1};
PushRenderOrthographic(RenderBuffer, State->WindowBounds.Min.x, State->WindowBounds.Min.y, State->WindowBounds.Max.x, State->WindowBounds.Max.y); PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer);
} }
} }
#define FOLDHAUS_INTERFACE_CPP #define FOLDHAUS_INTERFACE_CPP
#endif // FOLDHAUS_INTERFACE_CPP #endif // FOLDHAUS_INTERFACE_CPP

View File

@ -0,0 +1,143 @@
//
// 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 = 16; // TODO(Peter): Static number of modes that can be active simultaneously
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
{
// TODO(Peter): 4k pages = page size on windows
Result.ModeMemoryPagesFreeList.Data[Page] = PushSizeToData(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 = CreateMemoryCursor(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 = PushSizeOnCursor(&Mode->Memory, StateSize).Memory;
Mode->OpStateMemory = Result;
return Result;
}
#define FOLDHAUS_OPERATION_MODE_H
#endif // FOLDHAUS_OPERATION_MODE_H

View File

@ -0,0 +1,448 @@
//
// 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_entry panel_entry;
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_entry* ModalOverride;
panel* IsModalOverrideFor; // TODO(pjs): I don't like that this is panel* but ModalOverride is panel_entry*
panel_modal_override_callback* ModalOverrideCB;
panel_split_direction SplitDirection;
r32 SplitPercent;
// TODO(Peter): This REALLY doesn't want to live here
// Probably belongs in a more generalized PanelInterfaceState or something
b32 PanelSelectionMenuOpen;
union{
panel_entry* Left;
panel_entry* Top;
};
union{
panel_entry* Right;
panel_entry* Bottom;
};
};
struct free_panel
{
panel_entry* Next;
};
struct panel_entry
{
panel Panel;
free_panel Free;
};
#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_entry Panels[PANELS_MAX];
u32 PanelsUsed;
panel_entry FreeList;
};
// NOTE(Peter): This representation is used to let external code render and interact
// with panels. It shouldn't be stored across frame boundaries as the pointers to
// Panel's are liable to change.
struct panel_with_layout
{
panel* Panel;
rect2 Bounds;
};
struct panel_layout
{
panel_with_layout* Panels;
u32 PanelsCount;
u32 PanelsMax;
};
/////////////////////////////////
//
// Book-Keeping
//
/////////////////////////////////
internal void
InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount)
{
PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList;
PanelSystem->PanelDefs = PanelDefs;
PanelSystem->PanelDefsCount = PanelDefsCount;
}
internal panel_entry*
TakeNewPanelEntry(panel_system* PanelSystem)
{
panel_entry* FreeEntry = 0;
if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList)
{
FreeEntry = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next;
}
else
{
Assert(PanelSystem->PanelsUsed < PANELS_MAX);
FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++;
}
return FreeEntry;
}
internal void
FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem)
{
Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX);
Entry->Panel = {0};
Entry->Free.Next = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = Entry;
}
internal void
FreePanelEntryRecursive(panel_entry* Entry, panel_system* PanelSystem)
{
if (Entry->Panel.SplitDirection != PanelSplit_NoSplit)
{
FreePanelEntryRecursive(Entry->Panel.Left, PanelSystem);
FreePanelEntryRecursive(Entry->Panel.Right, PanelSystem);
}
FreePanelEntry(Entry, PanelSystem);
}
internal void
FreePanelAtIndex(s32 Index, panel_system* PanelSystem)
{
Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed);
panel_entry* EntryToFree = PanelSystem->Panels + Index;
EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = EntryToFree;
}
internal panel_entry*
Panel_GetModalOverride(panel_entry* PanelEntry)
{
panel_entry* Result = PanelEntry;
if (PanelEntry->Panel.ModalOverride != 0)
{
Result = Panel_GetModalOverride(PanelEntry->Panel.ModalOverride);
}
return Result;
}
internal panel*
Panel_GetModalOverride(panel* Panel)
{
panel* Result = Panel;
if (Panel->ModalOverride != 0)
{
Result = &Panel_GetModalOverride(Panel->ModalOverride)->Panel;
}
return Result;
}
internal void
Panel_PushModalOverride(panel* Root, panel_entry* Override, panel_modal_override_callback* Callback)
{
Root->ModalOverride = Override;
Root->ModalOverrideCB = Callback;
Override->Panel.IsModalOverrideFor = Root;
}
internal void
Panel_PopModalOverride(panel* Parent, panel_system* System)
{
// TODO(pjs): Free the overrided panel
FreePanelEntry(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
SetAndInitPanelType(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_entry*
PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context)
{
panel_entry* PanelEntry = TakeNewPanelEntry(PanelSystem);
SetAndInitPanelType(&PanelEntry->Panel, PanelSystem, PanelTypeIndex, State, Context);
return PanelEntry;
}
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 = TakeNewPanelEntry(PanelSystem);
Panel_SetCurrentType(&Parent->Left->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Right = TakeNewPanelEntry(PanelSystem);
Panel_SetCurrentType(&Parent->Right->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
}
}
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_entry* PanelEntryToKeep, panel_system* PanelSystem)
{
panel_entry* LeftChild = Parent->Left;
panel_entry* RightChild = Parent->Right;
panel_entry* PanelEntryToDestroy = PanelEntryToKeep == LeftChild ? RightChild : LeftChild;
*Parent = PanelEntryToKeep->Panel;
FreePanelEntry(PanelEntryToKeep, PanelSystem);
FreePanelEntryRecursive(PanelEntryToDestroy, PanelSystem);
}
/////////////////////////////////
//
// Rendering And Interaction
//
/////////////////////////////////
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
LayoutPanel(panel* Panel, rect2 PanelBounds, panel_layout* Layout)
{
if (Panel->SplitDirection == PanelSplit_NoSplit)
{
panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++;
WithLayout->Panel = Panel_GetModalOverride(Panel);
WithLayout->Bounds = PanelBounds;
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
panel* TopPanel = Panel_GetModalOverride(&Panel->Top->Panel);
panel* BottomPanel = Panel_GetModalOverride(&Panel->Bottom->Panel);
LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout);
LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout);
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
panel* LeftPanel = Panel_GetModalOverride(&Panel->Top->Panel);
panel* RightPanel = Panel_GetModalOverride(&Panel->Bottom->Panel);
LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout);
LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout);
}
}
internal panel_layout
GetPanelLayout(panel_system* System, rect2 WindowBounds, gs_memory_arena* Storage)
{
panel_layout Result = {};
Result.PanelsMax = System->PanelsUsed;
Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax);
LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result);
return Result;
}
internal panel_with_layout
GetPanelContainingPoint(v2 Point, panel* Panel, rect2 PanelBounds)
{
panel_with_layout Result = {0};
if (Panel->SplitDirection == PanelSplit_NoSplit)
{
Result.Panel = Panel;
Result.Bounds = PanelBounds;
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (PointIsInRect(TopPanelBounds, Point))
{
Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds);
}
else if (PointIsInRect(BottomPanelBounds, Point))
{
Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds);
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
if (PointIsInRect(LeftPanelBounds, Point))
{
Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds);
}
else if (PointIsInRect(RightPanelBounds, Point))
{
Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds);
}
}
return Result;
}
internal panel_with_layout
GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect2 WindowBounds)
{
panel_with_layout Result = {0};
if (PanelSystem->PanelsUsed > 0)
{
Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds);
}
return Result;
}
#define FOLDHAUS_PANEL_H
#endif // FOLDHAUS_PANEL_H

View File

@ -0,0 +1,658 @@
//
// File: foldhaus_panel_animation_timeline.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
// Colors
global v4 TimeSliderColor = GreenV4; //v4{.36f, .52f, .78f, 1.f};
//
struct animation_timeline_state
{
frame_range VisibleRange;
handle SelectedAnimationBlockHandle;
u32 SelectedAnimationLayer;
};
inline u32
GetFrameFromPointInAnimationPanel(v2 Point, rect2 PanelBounds, frame_range VisibleRange)
{
r32 HorizontalPercentOfBounds = (Point.x - PanelBounds.Min.x) / (PanelBounds.Max.x - PanelBounds.Min.x);
u32 VisibleFramesCount = GetFrameCount(VisibleRange);
u32 TimeAtPoint = (u32)(HorizontalPercentOfBounds * VisibleFramesCount) + VisibleRange.Min;
return TimeAtPoint;
}
inline s32
GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range VisibleRange)
{
r32 PercentOfTimeline = (r32)(Frame - VisibleRange.Min) / (r32)GetFrameCount(VisibleRange);
s32 XPositionAtFrame = (PercentOfTimeline * Rect2Width(PanelBounds)) + PanelBounds.Min.x;
return XPositionAtFrame;
}
internal handle
AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animation_system* System)
{
u32 NewBlockStart = System->CurrentFrame;
u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System);
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
handle AnimHandle = Animation_AddBlock(ActiveAnim, NewBlockStart, NewBlockEnd, AnimationProcHandle, LayerHandle);
return AnimHandle;
}
internal void
SelectAnimationBlock(handle BlockHandle, app_state* State)
{
State->SelectedAnimationBlockHandle = BlockHandle;
}
internal void
DeselectCurrentAnimationBlock(app_state* State)
{
State->SelectedAnimationBlockHandle = {};
}
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
{
handle SelectedAnimHandle = State->SelectedAnimationBlockHandle;
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
if(SelectedAnimHandle.Index < ActiveAnim->Blocks_.Count &&
ActiveAnim->Blocks_.Generations[SelectedAnimHandle.Index] == SelectedAnimHandle.Generation)
{
Animation_RemoveBlock(ActiveAnim, State->SelectedAnimationBlockHandle);
State->SelectedAnimationBlockHandle = {0};
// TODO(pjs): Introduce an animation_block_selection in this file
// it should have a handle to the animation, block, and a HasSelection flag
// as it is now, you kind of always have the first block selected
}
}
//
// Drag Time Marker
//
OPERATION_STATE_DEF(drag_time_marker_operation_state)
{
rect2 TimelineBounds;
s32 StartFrame;
s32 EndFrame;
};
OPERATION_RENDER_PROC(UpdateDragTimeMarker)
{
drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory;
frame_range Range = { OpState->StartFrame, OpState->EndFrame };
u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, Range);
State->AnimationSystem.CurrentFrame = FrameAtMouseX;
}
FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command DragTimeMarkerCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragTimeMarker },
};
internal void
StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, app_state* State)
{
operation_mode* DragTimeMarkerMode = ActivateOperationModeWithCommands(&State->Modes, DragTimeMarkerCommands, UpdateDragTimeMarker);
drag_time_marker_operation_state* OpState = CreateOperationState(DragTimeMarkerMode,
&State->Modes,
drag_time_marker_operation_state);
OpState->StartFrame = VisibleFrames.Min;
OpState->EndFrame = VisibleFrames.Max;
OpState->TimelineBounds = TimelineBounds;
}
// --------------------
//
// Drag Animation Clip
//
#define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10
OPERATION_STATE_DEF(drag_animation_clip_state)
{
rect2 TimelineBounds;
frame_range VisibleRange;
frame_range ClipRange;
};
internal u32
AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame)
{
u32 Result = SnappingFrame;
s32 SnapDistance = 5;
if (Abs((s32)SnappingFrame - (s32)SnapToFrame) <= SnapDistance)
{
Result = SnapToFrame;
}
return Result;
}
OPERATION_RENDER_PROC(UpdateDragAnimationClip)
{
drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory;
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange);
u32 ClipInitialStartFrameXPosition = LerpR32(ClipInitialStartFrameXPercent,
OpState->TimelineBounds.Min.x,
OpState->TimelineBounds.Max.x);
r32 ClipInitialEndFrameXPercent = FrameToPercentRange(OpState->ClipRange.Max, OpState->VisibleRange);
u32 ClipInitialEndFrameXPosition = LerpR32(ClipInitialEndFrameXPercent,
OpState->TimelineBounds.Min.x,
OpState->TimelineBounds.Max.x);
u32 FrameAtMouseDownX = GetFrameFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->VisibleRange);
u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange);
s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX;
animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, State->SelectedAnimationBlockHandle);
if (!AnimationBlock)
{
EndCurrentOperationMode(State, {}, Mouse, Context);
return;
}
if (Abs(Mouse.DownPos.x - ClipInitialStartFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{
s32 NewStartFrame = OpState->ClipRange.Min + FrameOffset;
if (FrameOffset < 0)
{
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
{
animation_block OtherBlock = ActiveAnim->Blocks_.Values[i];
NewStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max);
}
}
else
{
if (NewStartFrame >= AnimationBlock->Range.Max)
{
NewStartFrame = AnimationBlock->Range.Max - 1;
}
}
AnimationBlock->Range.Min = NewStartFrame;
}
else if (Abs(Mouse.DownPos.x - ClipInitialEndFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{
r32 NewEndFrame = OpState->ClipRange.Max + FrameOffset;
if (FrameOffset > 0)
{
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
{
animation_block OtherBlock = ActiveAnim->Blocks_.Values[i];
NewEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min);
}
}
else
{
if(NewEndFrame <= AnimationBlock->Range.Min)
{
NewEndFrame = AnimationBlock->Range.Min + 1;
}
}
AnimationBlock->Range.Max = NewEndFrame;
}
else
{
u32 NewStartFrame = OpState->ClipRange.Min + FrameOffset;
u32 NewEndFrame = OpState->ClipRange.Max + FrameOffset;
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
{
animation_block OtherBlock = ActiveAnim->Blocks_.Values[i];;
u32 SnapFramesAmount = 0;
if (FrameOffset > 0)
{
u32 FinalEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min);
SnapFramesAmount = FinalEndFrame - NewEndFrame;
}
else if (FrameOffset < 0)
{
u32 FinalStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max);
SnapFramesAmount = FinalStartFrame - NewStartFrame;
}
NewEndFrame += SnapFramesAmount;
NewStartFrame += SnapFramesAmount;
}
AnimationBlock->Range.Min = NewStartFrame;
AnimationBlock->Range.Max = NewEndFrame;
}
s32 PlayableStartFrame = ActiveAnim->PlayableRange.Min;
s32 PlayableEndFrame = ActiveAnim->PlayableRange.Max;
AnimationBlock->Range.Min = (u32)Clamp(PlayableStartFrame, (s32)AnimationBlock->Range.Min, PlayableEndFrame);
AnimationBlock->Range.Max = (u32)Clamp(PlayableStartFrame, (s32)AnimationBlock->Range.Max, PlayableEndFrame);
}
input_command DragAnimationClipCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode },
};
internal void
SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State)
{
SelectAnimationBlock(BlockHandle, State);
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip);
drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode,
&State->Modes,
drag_animation_clip_state);
OpState->TimelineBounds = TimelineBounds;
OpState->VisibleRange = VisibleRange;
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
OpState->ClipRange = SelectedBlock->Range;
}
// -------------------
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
{
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
panel_with_layout ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds);
frame_range Range = ActiveAnim->PlayableRange;
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range);
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer);
SelectAnimationBlock(NewBlockHandle, State);
}
input_command AnimationTimeline_Commands[] = {
{ KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand },
{ KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand },
};
s32 AnimationTimeline_CommandsCount = 2;
GSMetaTag(panel_init);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Init(panel* Panel, app_state* State, context Context)
{
// TODO: :FreePanelMemory
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state);
TimelineState->VisibleRange = ActiveAnim->PlayableRange;
Panel->StateMemory = StructToData(TimelineState, animation_timeline_state);
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Cleanup(panel* Panel, app_state* State)
{
}
internal void
DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_range VisibleFrames, rect2 BarBounds, app_state* State)
{
gs_string TempString = PushString(State->Transient, 256);
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
r32 BarHeight = Rect2Height(BarBounds);
r32 BarWidth = Rect2Width(BarBounds);
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) &&
PointIsInRect(BarBounds, Interface.Mouse.DownPos))
{
StartDragTimeMarker(BarBounds, VisibleFrames, State);
}
PushRenderQuad2D(Interface.RenderBuffer, BarBounds.Min, BarBounds.Max, v4{.16f, .16f, .16f, 1.f});
// Frame Ticks
u32 TickCount = 10;
for (u32 Tick = 0; Tick < TickCount; Tick++)
{
r32 Percent = (r32)Tick / (r32)TickCount;
u32 Frame = PercentToFrameInRange(Percent, VisibleFrames);
PrintF(&TempString, "%d", Frame);
r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames);
r32 FrameX = LerpR32(FramePercent, BarBounds.Min.x, BarBounds.Max.x);
v2 FrameTextPos = v2{FrameX, BarBounds.Min.y + 2};
DrawString(Interface.RenderBuffer, TempString, Interface.Style.Font, FrameTextPos, WhiteV4);
}
// Time Slider
if (FrameIsInRange(VisibleFrames, AnimationSystem->CurrentFrame))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, VisibleFrames);
r32 SliderX = LerpR32(FrameAtPercentVisibleRange, BarBounds.Min.x, BarBounds.Max.x);
PrintF(&TempString, "%d", AnimationSystem->CurrentFrame);
// space for each character + a margin on either side
r32 SliderWidth = (8 * TempString.Length) + 8;
r32 SliderHalfWidth = SliderWidth / 2.f;
v2 HeadMin = v2{SliderX - SliderHalfWidth, BarBounds.Min.y};
v2 HeadMax = v2{SliderX + SliderHalfWidth, BarBounds.Max.y};
PushRenderQuad2D(Interface.RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
DrawString(Interface.RenderBuffer, TempString, Interface.Style.Font, HeadMin + v2{6, 4}, WhiteV4);
}
}
internal bool
MinMaxRangeSlider(v2 HandleValues, rect2 SliderBounds, r32 MinValue, r32 MaxValue, ui_interface Interface, v2* OutHandleValues)
{
// Should Update only gets set to true when the user is finished interacting (ie. on mouse up)
// this allows the continuous use of the value of a handle while it is being dragged, and allows
// for you to know when exactly to update the stored value
bool ShouldUpdate = false;
*OutHandleValues = HandleValues;
v4 BGColor = v4{.16f, .16f, .16f, 1.f};
v4 HandleColor = v4{.8f, .8f, .8f, 1.f};
v2 HandleDim = v2{25, Rect2Height(SliderBounds)};
r32 MinHandleX = RemapR32(HandleValues.x, MinValue, MaxValue, SliderBounds.Min.x, SliderBounds.Max.x);
r32 MaxHandleX = RemapR32(HandleValues.y, MinValue, MaxValue, SliderBounds.Min.x, SliderBounds.Max.x);
rect2 MinHandleBounds = MakeRect2CenterDim(v2{ MinHandleX, Rect2Center(SliderBounds).y }, HandleDim);
rect2 MaxHandleBounds = MakeRect2CenterDim(v2{ MaxHandleX, Rect2Center(SliderBounds).y }, HandleDim);
// Drag the handles
if (MouseButtonHeldDown(Interface.Mouse.LeftButtonState) ||
MouseButtonTransitionedUp(Interface.Mouse.LeftButtonState))
{
v2 MouseDragOffset = Interface.Mouse.Pos - Interface.Mouse.DownPos;
// TODO(pjs): We need to make sure that the min handle is always the lower one, etc.
// TODO(pjs): We need to range clamp the handles
if (PointIsInRect(MinHandleBounds, Interface.Mouse.DownPos))
{
MinHandleBounds = Rect2TranslateX(MinHandleBounds, MouseDragOffset.x);
}
else if (PointIsInRect(MaxHandleBounds, Interface.Mouse.DownPos))
{
MaxHandleBounds = Rect2TranslateX(MaxHandleBounds, MouseDragOffset.x);
}
}
// Draw Background
PushRenderQuad2D(Interface.RenderBuffer, SliderBounds.Min, SliderBounds.Max, BGColor);
// Draw Handles
PushRenderQuad2D(Interface.RenderBuffer, MinHandleBounds.Min, MinHandleBounds.Max, HandleColor);
PushRenderQuad2D(Interface.RenderBuffer, MaxHandleBounds.Min, MaxHandleBounds.Max, HandleColor);
// Update the output range value
r32 MinHandleXOut = Rect2Center(MinHandleBounds).x;
r32 MaxHandleXOut = Rect2Center(MaxHandleBounds).x;
r32 MinHandleValue = RemapR32(MinHandleXOut, SliderBounds.Min.x, SliderBounds.Max.x, MinValue, MaxValue);
r32 MaxHandleValue = RemapR32(MaxHandleXOut, SliderBounds.Min.x, SliderBounds.Max.x, MinValue, MaxValue);
*OutHandleValues = v2{ Min(MinHandleValue, MaxHandleValue), Max(MinHandleValue, MaxHandleValue) };
if (MouseButtonTransitionedUp(Interface.Mouse.LeftButtonState))
{
ShouldUpdate = true;
}
return ShouldUpdate;
}
internal frame_range
DrawTimelineRangeBar (animation_system* AnimationSystem, animation Animation, animation_timeline_state* TimelineState, ui_interface Interface, rect2 BarBounds)
{
frame_range VisibleRangeAfterInteraction = {};
r32 MinFrame = (r32)Animation.PlayableRange.Min;
r32 MaxFrame = (r32)Animation.PlayableRange.Max;
v2 RangeHandles = v2{ (r32)TimelineState->VisibleRange.Min, (r32)TimelineState->VisibleRange.Max };
bool ApplyUpdate = MinMaxRangeSlider(RangeHandles, BarBounds, MinFrame, MaxFrame, Interface, &RangeHandles);
VisibleRangeAfterInteraction.Min = (s32)RangeHandles.x;
VisibleRangeAfterInteraction.Max = (s32)RangeHandles.y;
if (ApplyUpdate)
{
TimelineState->VisibleRange = VisibleRangeAfterInteraction;
}
return VisibleRangeAfterInteraction;
}
#define LAYER_HEIGHT 52
internal void
DrawLayerMenu(animation_system* AnimationSystem, animation ActiveAnim, ui_interface Interface, rect2 PanelDim, u32* SelectedAnimationLayer)
{
v2 LayerDim = { Rect2Width(PanelDim), LAYER_HEIGHT };
v2 LayerListMin = PanelDim.Min + v2{0, 24};
for (u32 i = 0; i < ActiveAnim.Layers.Count; i++)
{
anim_layer* Layer = ActiveAnim.Layers.Values + i;
rect2 LayerBounds = {0};
LayerBounds.Min = { LayerListMin.x, LayerListMin.y + (LayerDim.y * i) };
LayerBounds.Max = LayerBounds.Min + LayerDim;
if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) &&
PointIsInRect(LayerBounds, Interface.Mouse.Pos))
{
*SelectedAnimationLayer = i;
}
v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16};
if (*SelectedAnimationLayer == i)
{
PushRenderBoundingBox2D(Interface.RenderBuffer, LayerBounds.Min, LayerBounds.Max, 1, WhiteV4);
}
DrawString(Interface.RenderBuffer, Layer->Name, Interface.Style.Font, LayerTextPos, WhiteV4);
}
}
internal rect2
DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range VisibleFrames, rect2 TimelineBounds, render_command_buffer* RenderBuffer)
{
rect2 BlockBounds = {};
r32 TimelineWidth = Rect2Width(TimelineBounds);
u32 ClampedBlockStartFrame = ClampFrameToRange(AnimationBlock.Range.Min, VisibleFrames);
r32 StartFramePercent = FrameToPercentRange(ClampedBlockStartFrame, VisibleFrames);
r32 StartPosition = TimelineWidth * StartFramePercent;
u32 ClampedBlockEndFrame = ClampFrameToRange(AnimationBlock.Range.Max, VisibleFrames);
r32 EndFramePercent = FrameToPercentRange(ClampedBlockEndFrame, VisibleFrames);
r32 EndPosition = TimelineWidth * EndFramePercent;
r32 LayerYOffset = LAYER_HEIGHT * AnimationBlock.Layer;
BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, LayerYOffset};
BlockBounds.Max = TimelineBounds.Min + v2{EndPosition, LayerYOffset + LAYER_HEIGHT};
PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor);
PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4);
return BlockBounds;
}
internal handle
DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect2 PanelBounds, handle SelectedBlockHandle, ui_interface* Interface, app_state* State)
{
gs_string Tempgs_string = PushString(State->Transient, 256);
handle Result = SelectedBlockHandle;
animation CurrAnimation = *AnimationSystem_GetActiveAnimation(AnimationSystem);
rect2 LayerMenuBounds, TimelineBounds;
RectVSplitAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds);
// In Top To Bottom Order
rect2 TimelineFrameBarBounds;
rect2 TimelineBlockDisplayBounds;
rect2 TimelineRangeBarBounds;
RectHSplitAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds);
RectHSplitAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds);
DrawLayerMenu(AnimationSystem, CurrAnimation, *Interface, LayerMenuBounds, &State->SelectedAnimationLayer);
frame_range AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, CurrAnimation, TimelineState, *Interface, TimelineRangeBarBounds);
DrawFrameBar(AnimationSystem, *Interface, AdjustedViewRange, TimelineFrameBarBounds, State);
ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f});
// Animation Blocks
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
handle DragBlockHandle = {0};
for (u32 i = 0; i < CurrAnimation.Blocks_.Count; i++)
{
animation_block* AnimationBlockAt = CurrAnimation.Blocks_.Values + i;
// If either end is in the range, we should draw it
b32 RangeIsVisible = (FrameIsInRange(AdjustedViewRange, AnimationBlockAt->Range.Min) ||
FrameIsInRange(AdjustedViewRange, AnimationBlockAt->Range.Max));
// If neither end is in the range, but the ends surround the visible range,
// we should still draw it.
RangeIsVisible |= (AnimationBlockAt->Range.Min <= AdjustedViewRange.Min &&
AnimationBlockAt->Range.Max>= AdjustedViewRange.Max);
if (RangeIsVisible)
{
v4 BlockColor = BlackV4;
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == CurrAnimation.Blocks_.Generations[i])
{
BlockColor = PinkV4;
}
rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer);
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
{
DragBlockHandle.Index = i;
DragBlockHandle.Generation = CurrAnimation.Blocks_.Generations[i];
}
}
}
if (MouseDownAndNotHandled && Handle_IsValid(DragBlockHandle))
{
MouseDownAndNotHandled = false;
SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State);
}
// Time Slider
if (FrameIsInRange(AdjustedViewRange, AnimationSystem->CurrentFrame))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange);
r32 SliderX = LerpR32(FrameAtPercentVisibleRange, TimelineBounds.Min.x, TimelineBounds.Max.x);
rect2 SliderBounds = {
v2{ SliderX, TimelineBounds.Min.y },
v2{ SliderX + 1, TimelineBounds.Max.y }
};
ui_FillRect(Interface, SliderBounds, TimeSliderColor);
}
ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4);
ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4);
ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4);
if (MouseDownAndNotHandled && PointIsInRect(TimelineBounds, Interface->Mouse.Pos))
{
DeselectCurrentAnimationBlock(State);
}
return Result;
}
PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
{
Assert(ReturningFrom->TypeIndex == PanelType_FileView);
file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state);
gs_file_info FileInfo = FileViewState->SelectedFile;
gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path);
gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size);
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips);
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
}
internal void
DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem)
{
ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds);
for (s32 i = 0; i < GlobalAnimationClipsCount; i++)
{
animation_clip Clip = GlobalAnimationClips[i];
gs_string ClipName = MakeString(Clip.Name, Clip.NameLength);
if (ui_LayoutListEntry(Interface, &Layout, ClipName, i))
{
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem);
}
}
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
// TODO(pjs): SelectedAnimationBlockHandle should be a property of animation_timeline_state
// unless its used elsewhere. Audit later
handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
ui_interface* Interface = &State->Interface;
animation_system* AnimationSystem = &State->AnimationSystem;
rect2 TitleBarBounds, PanelContentsBounds;
rect2 AnimationListBounds, TimelineBounds;
RectHSplitAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds);
RectVSplitAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds);
ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]);
ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds);
ui_StartRow(&TitleBarLayout, 4);
{
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Pause")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4))
{
State->AnimationSystem.TimelineShouldAdvance = true;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Stop")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
State->AnimationSystem.CurrentFrame = 0;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load")))
{
panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
}
}
ui_EndRow(&TitleBarLayout);
if (Rect2Height(TimelineBounds) > 0)
{
SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State);
DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem);
}
}
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
#endif // FOLDHAUS_PANEL_ANIMATION_TIMELINE_H

View File

@ -18,7 +18,7 @@ s32 DMXView_CommandsCount = 0;
GSMetaTag(panel_init); GSMetaTag(panel_init);
GSMetaTag(panel_type_dmx_view); GSMetaTag(panel_type_dmx_view);
internal void internal void
DMXView_Init(panel* Panel, app_state* State) DMXView_Init(panel* Panel, app_state* State, context Context)
{ {
} }
@ -74,7 +74,7 @@ DrawSACNUniversePixels (render_command_buffer* RenderBuffer, sacn_universe* ToDr
GSMetaTag(panel_render); GSMetaTag(panel_render);
GSMetaTag(panel_type_dmx_view); GSMetaTag(panel_type_dmx_view);
internal void internal void
DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) DMXView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
#if 0 #if 0
// :NoLongerFunctionalSACNCodeButThatsOk // :NoLongerFunctionalSACNCodeButThatsOk
@ -82,7 +82,7 @@ DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffe
universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory; universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory;
string TitleBarString = InitializeEmptyString(PushArray(State->Transient, char, 64), 64); gs_string TitleBargs_string = InitializeEmptygs_string(PushArray(State->Transient, char, 64), 64);
v2 DisplayArea_Dimension = v2{600, 600}; v2 DisplayArea_Dimension = v2{600, 600};
@ -120,8 +120,8 @@ DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffe
if (OpState->Zoom > .5f) if (OpState->Zoom > .5f)
{ {
v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12}; v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12};
PrintF(&TitleBarString, "Universe %d", Universe->Universe); PrintF(&TitleBargs_string, "Universe %d", Universe->Universe);
DrawString(RenderBuffer, TitleBarString, State->Interface.Font, DrawString(RenderBuffer, TitleBargs_string, State->Interface.Font,
TitleDisplayStart, WhiteV4); TitleDisplayStart, WhiteV4);
} }

View File

@ -0,0 +1,129 @@
//
// File: foldhaus_panel_file_view.h
// Author: Peter Slattery
// Creation Date: 2020-03-08
//
#ifndef FOLDHAUS_PANEL_FILE_VIEW_H
struct file_view_state
{
gs_string WorkingDirectory;
gs_memory_arena FileNamesArena;
gs_file_info_array FileNames;
gs_file_info SelectedFile;
};
internal void
FileView_Exit_(panel* FileViewPanel, app_state* State, context Context)
{
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
FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context)
{
ClearArena(&State->FileNamesArena);
gs_const_string SanitizedDirectory = WorkingDirectory;
u32 LastSlashIndex = FindLast(SanitizedDirectory, '\\');
gs_const_string LastDir = Substring(SanitizedDirectory, LastSlashIndex + 1, SanitizedDirectory.Length);
if (StringsEqual(LastDir, ConstString("..")))
{
u32 SecondLastSlashIndex = FindLast(SanitizedDirectory, LastSlashIndex - 1, '\\');
SanitizedDirectory = Substring(SanitizedDirectory, 0, SecondLastSlashIndex);
}
else if (StringsEqual(LastDir, ConstString(".")))
{
SanitizedDirectory = Substring(SanitizedDirectory, 0, LastSlashIndex);
}
State->WorkingDirectory = PushString(&State->FileNamesArena, WorkingDirectory.Length + 2);
PrintF(&State->WorkingDirectory, "%S", SanitizedDirectory);
if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '\\')
{
AppendPrintF(&State->WorkingDirectory, "\\");
}
if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '*')
{
AppendPrintF(&State->WorkingDirectory, "*");
}
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, State->WorkingDirectory.ConstString, EnumerateDirectory_IncludeDirectories);
}
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 = CreateMemoryArena(Context.ThreadContext.Allocator);
FileViewUpdateWorkingDirectory(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_layout Layout = ui_CreateLayout(State->Interface, PanelBounds);
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
// Header
ui_LayoutDrawString(&State->Interface, &Layout, FileViewState->WorkingDirectory, v4{0, 1, 0, 1});
// File Display
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
{
gs_file_info File = FileViewState->FileNames.Values[i];
u32 LastSlashIndex = FindLast(File.Path, '\\');
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, &Layout, PathString, i))
{
if (File.IsDirectory)
{
FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context);
}
else
{
FileViewState->SelectedFile = File;
FileView_Exit_(Panel, State, Context);
}
}
}
}
#define FOLDHAUS_PANEL_FILE_VIEW_H
#endif // FOLDHAUS_PANEL_FILE_VIEW_H

View File

@ -0,0 +1,86 @@
//
// 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, State->GlobalLog);
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds);
gs_string TempString = PushString(State->Transient, 256);
u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1;
u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count);
rect2* LineBounds = PushArray(State->Transient, rect2, LineCount);
// Fill in alternating color rows for the backgrounds
for (u32 Line = 0; Line < LineCount; Line++)
{
LineBounds[Line] = ui_ReserveElementBounds(&Layout);
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line);
ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor);
}
for (u32 AssemblyIndex = 0; AssemblyIndex < AssembliesToDraw; AssemblyIndex++)
{
assembly Assembly = State->Assemblies.Values[AssemblyIndex];
PrintF(&TempString, "%S", Assembly.Name);
ui_layout ItemLayout = ui_CreateLayout(State->Interface, LineBounds[AssemblyIndex]);
ui_StartRow(&ItemLayout, 2);
{
ui_LayoutDrawString(&State->Interface, &ItemLayout, TempString, State->Interface.Style.TextColor);
if (ui_LayoutListButton(&State->Interface, &ItemLayout, MakeString("X"), AssemblyIndex))
{
UnloadAssembly(AssemblyIndex, State, Context);
}
}
ui_EndRow(&ItemLayout);
}
if (AssembliesToDraw < LineCount)
{
// NOTE(Peter): Add assembly button
PrintF(&TempString, "+ Add Assembly");
if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw))
{
panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
}
}
}
#define FOLDHAUS_PANEL_HIERARCHY_H
#endif // FOLDHAUS_PANEL_HIERARCHY_H

View File

@ -11,7 +11,7 @@ s32 ProfilerView_CommandsCount = 0;
GSMetaTag(panel_init); GSMetaTag(panel_init);
GSMetaTag(panel_type_profiler); GSMetaTag(panel_type_profiler);
internal void internal void
ProfilerView_Init(panel* Panel, app_state* State) ProfilerView_Init(panel* Panel, app_state* State, context Context)
{ {
} }
@ -25,7 +25,7 @@ ProfilerView_Cleanup(panel* Panel, app_state* State)
} }
internal void internal void
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, memory_arena* Memory) RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
{ {
v4 ThreadColors[] = { v4 ThreadColors[] = {
v4{.73f, .33f, .83f, 1}, v4{.73f, .33f, .83f, 1},
@ -35,8 +35,8 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
v4{.74f, .40f, .25f, 1}, v4{.74f, .40f, .25f, 1},
}; };
rect Bounds = ui_LayoutRemaining(Layout); rect2 Bounds = ui_LayoutRemaining(Layout);
r32 Width = gs_Width(Bounds); r32 Width = Rect2Width(Bounds);
r32 DepthHeight = 64; r32 DepthHeight = 64;
s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
@ -48,7 +48,8 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
scope_record* HotRecord = 0; scope_record* HotRecord = 0;
scope_name* HotRecordName = 0; scope_name* HotRecordName = 0;
MakeStringBuffer(String, 256); char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
for (s32 i = 0; i < ThreadScopeCalls->Count; i++) for (s32 i = 0; i < ThreadScopeCalls->Count; i++)
{ {
scope_record* Record = ThreadScopeCalls->Calls + i; scope_record* Record = ThreadScopeCalls->Calls + i;
@ -59,14 +60,14 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
r32 PixelStart = Bounds.Min.x + (Width * PercentStart); r32 PixelStart = Bounds.Min.x + (Width * PercentStart);
r32 PixelEnd = Bounds.Min.x + (Width * PercentEnd); r32 PixelEnd = Bounds.Min.x + (Width * PercentEnd);
r32 MinY = Bounds.Max.y - ((Record->CallDepth + 1) * DepthHeight); r32 MinY = Bounds.Max.y - ((Record->CallDepth + 1) * DepthHeight);
rect ScopeBounds = { rect2 ScopeBounds = {
v2{ PixelStart, MinY }, v2{ PixelStart, MinY },
v2{ PixelEnd, MinY + (DepthHeight - 4) } v2{ PixelEnd, MinY + (DepthHeight - 4) }
}; };
if (gs_Width(ScopeBounds) >= 1) if (Rect2Width(ScopeBounds) >= 1)
{ {
v4 Color = ThreadColors[0]; v4 Color = ThreadColors[0];
if (gs_PointIsInRect(Interface->Mouse.Pos, ScopeBounds)) if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
{ {
Color = GreenV4; Color = GreenV4;
HotRecord = Record; HotRecord = Record;
@ -81,23 +82,26 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
if (HotRecord != 0) if (HotRecord != 0)
{ {
PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles);
ui_TextBox(Interface, gs_MakeRectMinWidth(Interface->Mouse.Pos, v2{256, 32}), String, BlackV4, WhiteV4);
rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32});
ui_TextBox(Interface, TextBounds, String, BlackV4, WhiteV4);
} }
} }
internal void internal void
RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, memory_arena* Memory) RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
{ {
MakeStringBuffer(String, 256); char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
r32 ColumnWidths[] = {256, 128, 128, 128, 128}; r32 ColumnWidths[] = {256, 128, 128, 128, 128};
ui_StartRow(&Layout, 5, &ColumnWidths[0]); ui_StartRow(&Layout, 5, &ColumnWidths[0]);
{ {
ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Procedure"), Interface->Style.TextColor); ui_LayoutDrawString(Interface, &Layout, MakeString("Procedure"), Interface->Style.TextColor);
ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("% Frame"), Interface->Style.TextColor); ui_LayoutDrawString(Interface, &Layout, MakeString("% Frame"), Interface->Style.TextColor);
ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Seconds"), Interface->Style.TextColor); ui_LayoutDrawString(Interface, &Layout, MakeString("Seconds"), Interface->Style.TextColor);
ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Cycles"), Interface->Style.TextColor); ui_LayoutDrawString(Interface, &Layout, MakeString("Cycles"), Interface->Style.TextColor);
ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Calls"), Interface->Style.TextColor); ui_LayoutDrawString(Interface, &Layout, MakeString("Calls"), Interface->Style.TextColor);
} }
ui_EndRow(&Layout); ui_EndRow(&Layout);
@ -133,62 +137,65 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu
GSMetaTag(panel_render); GSMetaTag(panel_render);
GSMetaTag(panel_type_profiler); GSMetaTag(panel_type_profiler);
internal void internal void
ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
memory_arena* Memory = &State->Transient; gs_memory_arena* Memory = State->Transient;
string String = InitializeEmptyString(PushArray(Memory, char, 256), 256); gs_string String = PushString(Memory, 256);
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 }; v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
r32 FrameListHeight = 64; r32 FrameListHeight = 64;
rect FrameListBounds, ProcListBounds; rect2 FrameListBounds, ProcListBounds;
gs_HSplitRectAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds); RectHSplitAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds);
rect FrameListInner = gs_InsetRect(FrameListBounds, 4); rect2 FrameListInner = RectInset(FrameListBounds, 4);
r32 SingleFrameStep = gs_Width(FrameListInner) / DEBUG_FRAME_COUNT; r32 SingleFrameStep = Rect2Width(FrameListInner) / DEBUG_FRAME_COUNT;
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2); r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
ui_OutlineRect(&State->Interface_, FrameListBounds, 2, WhiteV4); ui_OutlineRect(&State->Interface, FrameListBounds, 2, WhiteV4);
if (gs_PointIsInRect(Mouse.Pos, FrameListBounds) && MouseButtonHeldDown(Mouse.LeftButtonState)) if (MouseButtonHeldDown(Context.Mouse.LeftButtonState))
{ {
v2 LocalMouse = gs_TransformPointIntoRectSpace(Mouse.Pos, FrameListBounds); if (PointIsInRect(FrameListBounds, Context.Mouse.Pos))
s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT)
{ {
GlobalDebugServices->RecordFrames = false; v2 LocalMouse = Rect2GetRectLocalPoint(FrameListBounds, Context.Mouse.Pos);
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex; s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT)
{
GlobalDebugServices->RecordFrames = false;
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
}
} }
} }
rect FrameBounds = gs_MakeRectMinWidth(FrameListInner.Min, v2{SingleFrameWidth, gs_Height(FrameListInner)}); rect2 FrameBounds = MakeRect2MinDim(FrameListInner.Min, v2{SingleFrameWidth, Rect2Height(FrameListInner)});
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++) for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
{ {
rect PositionedFrameBounds = gs_TranslateRectX(FrameBounds, F * SingleFrameStep); rect2 PositionedFrameBounds = Rect2TranslateX(FrameBounds, F * SingleFrameStep);
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F); s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; } if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)]; v4 Color = FrameColors[Clamp(0, FramesAgo, 3)];
ui_FillRect(&State->Interface_, PositionedFrameBounds, Color); ui_FillRect(&State->Interface, PositionedFrameBounds, Color);
} }
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
ui_layout Layout = ui_CreateLayout(State->Interface_, ProcListBounds); ui_layout Layout = ui_CreateLayout(State->Interface, ProcListBounds);
ui_StartRow(&Layout, 4); ui_StartRow(&Layout, 4);
{ {
s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame); PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_LayoutDrawString(&State->Interface_, &Layout, String, WhiteV4); ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_LayoutDrawString(&State->Interface_, &Layout, String, WhiteV4); ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4);
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
// be removed, or used for something else // be removed, or used for something else
ui_ReserveElementBounds(&Layout); ui_ReserveElementBounds(&Layout);
if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("Resume Recording"))) if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Resume Recording")))
{ {
GlobalDebugServices->RecordFrames = true; GlobalDebugServices->RecordFrames = true;
} }
@ -197,11 +204,11 @@ ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* Render
ui_StartRow(&Layout, 8); ui_StartRow(&Layout, 8);
{ {
if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("Scope View"))) if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Scope View")))
{ {
GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER;
} }
if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("List View"))) if (ui_LayoutButton(&State->Interface, &Layout, MakeString("List View")))
{ {
GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST;
} }
@ -210,11 +217,11 @@ ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* Render
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
{ {
RenderProfiler_ScopeVisualization(&State->Interface_, Layout, VisibleFrame, Memory); RenderProfiler_ScopeVisualization(&State->Interface, Layout, VisibleFrame, Memory);
} }
else else
{ {
RenderProfiler_ListVisualization(&State->Interface_, Layout, VisibleFrame, Memory); RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
} }
} }

View File

@ -0,0 +1,223 @@
//
// File: foldhaus_panel_sculpture_view.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H
// 3D Mouse View
OPERATION_STATE_DEF(mouse_rotate_view_operation_state)
{
v4 CameraStartPos;
};
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 * State->PixelsToWorldScale);
m44 YRotation = M44RotationY(TotalDeltaPos.x * State->PixelsToWorldScale);
m44 Combined = XRotation * YRotation;
State->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)
{
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(State->Camera.Position);
}
// ----------------
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)
{
}
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);
State->Camera.AspectRatio = RectAspectRatio(PanelBounds);
PushRenderPerspective(RenderBuffer, PanelBounds, State->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 = PushSizeToData(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(State->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, State->Camera, PanelBounds);
gs_string Tempgs_string = PushString(State->Transient, 256);
PrintF(&Tempgs_string, "%f %f", LedOnScreenPosition.x, LedOnScreenPosition.y);
DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4);
v2 BoxHalfDim = v2{ 25, 25 };
v2 BoxMin = LedOnScreenPosition - BoxHalfDim;
v2 BoxMax = LedOnScreenPosition + BoxHalfDim;
PushRenderBoundingBox2D(RenderBuffer, BoxMin, BoxMax, 2.0f, TealV4);
}
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H
#endif // FOLDHAUS_PANEL_SCULPTURE_VIEW_H

View File

@ -0,0 +1,17 @@
//
// File: foldhaus_panel_types.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-17
//
#ifndef FOLDHAUS_PANEL_TYPES_CPP
global s32 GlobalPanelDefsCount = 6;
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 },
};
#define FOLDHAUS_PANEL_TYPES_CPP
#endif // FOLDHAUS_PANEL_TYPES_CPP

View File

@ -0,0 +1,17 @@
//
// 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_NodeGraph,
PanelType_ProfilerView,
};
#define FOLDHAUS_PANEL_TYPES_H
#endif // FOLDHAUS_PANEL_TYPES_H

View File

@ -0,0 +1,435 @@
//
// File: foldhaus_animation.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ANIMATION
#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
typedef ANIMATION_PROC(animation_proc);
struct frame_range
{
s32 Min;
s32 Max;
};
struct animation_block
{
frame_range Range;
u32 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,
};
global gs_const_string BlendModeStrings[] = {
ConstString("Overwrite"),
ConstString("Add"),
ConstString("Multiply"),
ConstString("Count"),
};
struct anim_layer
{
gs_string Name;
blend_mode BlendMode;
};
struct anim_layer_array
{
anim_layer* Values;
u32 Count;
u32 CountMax;
};
struct animation
{
gs_string Name;
anim_layer_array Layers;
animation_block_array Blocks_;
frame_range PlayableRange;
};
struct animation_array
{
animation* Values;
u32 Count;
u32 CountMax;
};
struct animation_frame
{
// NOTE(pjs): These are all parallel arrays of equal length
animation_block* Blocks;
b8* BlocksFilled;
u32 BlocksCountMax;
u32 BlocksCount;
};
#define ANIMATION_SYSTEM_LAYERS_MAX 128
#define ANIMATION_SYSTEM_BLOCKS_MAX 128
struct animation_system
{
gs_memory_arena* Storage;
animation_array Animations;
// 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
u32 ActiveAnimationIndex;
s32 CurrentFrame;
s32 LastUpdatedFrame;
r32 SecondsPerFrame;
b32 TimelineShouldAdvance;
};
// TODO(pjs): Better name - something like animation_prototype
struct animation_clip
{
char* Name;
s32 NameLength;
animation_proc* Proc;
};
// 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
};
//////////////////////////
//
// Anim Block Array
internal animation_block_array
AnimBlockArray_Create(gs_memory_arena* Storage, u32 CountMax)
{
animation_block_array Result = {0};
Result.CountMax = CountMax;
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 = CountMax;
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 u32
AnimationArray_Push(animation_array* Array, animation Value)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Value;
return Index;
}
//////////////////////////
//
// Animation
internal handle
Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, u32 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 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
// System
internal animation*
AnimationSystem_GetActiveAnimation(animation_system* System)
{
// TODO(pjs): need a way to specify the active animation
return System->Animations.Values + System->ActiveAnimationIndex;
}
internal animation_frame
AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_arena* Arena)
{
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame Result = {0};
Result.BlocksCountMax = ActiveAnim->Layers.Count;
Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax);
Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax);
ZeroArray(Result.BlocksFilled, b8, Result.BlocksCountMax);
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
{
animation_block Block = ActiveAnim->Blocks_.Values[i];
if (FrameIsInRange(Block.Range, System->CurrentFrame))
{
Result.BlocksFilled[Block.Layer] = true;
Result.Blocks[Block.Layer] = Block;
Result.BlocksCount++;
}
}
return Result;
}
#define FOLDHAUS_ANIMATION
#endif // FOLDHAUS_ANIMATION

View File

@ -0,0 +1,192 @@
//
// 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_clip* GlobalClips, 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]);
}
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];
// TODO(pjs): Systematize the AnimationProcHandle
// :AnimProcHandle
u32 AnimationProcIndex = AnimationBlockAt.AnimationProcHandle - 1;
animation_clip Animation = GlobalClips[AnimationProcIndex];
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, u32 AnimClipsCount, animation_clip* AnimClips)
{
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);
Result.Layers.CountMax = Parser_ReadU32Value(&Parser, AnimField_LayersCount);
Result.Layers.Values = PushArray(Arena, anim_layer, Result.Layers.CountMax);
Result.Blocks_.CountMax = Parser_ReadU32Value(&Parser, AnimField_BlocksCount);
Result.Blocks_.Generations = PushArray(Arena, u32, Result.Blocks_.CountMax);
Result.Blocks_.Values = PushArray(Arena, animation_block, Result.Blocks_.CountMax);
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.ConstString, 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 < AnimClipsCount; i++)
{
if (StringEqualsCharArray(AnimName.ConstString, AnimClips[i].Name, CStringLength(AnimClips[i].Name)))
{
Block.AnimationProcHandle = i + 1;
break;
}
}
if (Parser_ReadCloseStruct(&Parser))
{
AnimBlockArray_Push(&Result.Blocks_, Block);
}
else
{
// TODO(pjs): Error
}
}
}
}
}
return Result;
}
#define FOLDHAUS_ANIMATION_SERIALIZER_CPP
#endif // FOLDHAUS_ANIMATION_SERIALIZER_CPP

View File

@ -0,0 +1,278 @@
//
// 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;
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
LedSystemInitialize(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 = AllocatorAllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax);
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->LedCount = LedCount;
Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount);
Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, 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];
AllocatorFreeArray(System->PlatformMemory, Buffer->Colors, pixel, Buffer->LedCount);
AllocatorFreeArray(System->PlatformMemory, Buffer->Positions, v4, Buffer->LedCount);
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 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] = 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);
}
}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);
}
}
internal void
LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena* Scratch, context Context, gs_const_string Path, event_log* GlobalLog)
{
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);
assembly* NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch))
{
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
else
{
FreeMemoryArena(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
}
else
{
LogError(GlobalLog, "Unable to load assembly file");
}
}
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);
FreeMemoryArena(&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];
for (u32 j = 0; j < StripAt.TagsCount; j++)
{
v2_tag TagAt = StripAt.Tags[j];
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.StripIndices[Result.Count++] = StripIndex;
}
}
}
}
return Result;
}
#define FOLDHAUS_ASSEMBLY_CPP
#endif // FOLDHAUS_ASSEMBLY_CPP

View File

@ -0,0 +1,198 @@
//
// 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
{
u32 LedCount;
pixel* Colors;
v4* Positions;
};
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;
gs_string Name;
gs_string FilePath;
r32 Scale;
v3 Center;
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;
};
internal led_buffer*
LedSystemGetBuffer(led_system* System, u32 Index)
{
led_buffer* Result = &System->Buffers[Index];
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;
}
#define FOLDHAUS_ASSEMBLY_H
#endif // FOLDHAUS_ASSEMBLY_H

View File

@ -0,0 +1,332 @@
//
// 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 = {0};
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 bool
ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient)
{
Assembly->LedCountTotal = 0;
parser Parser = {0};
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;
Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName);
Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale);
Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter);
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.");
}
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");
}
}
else
{
Parser_PushErrorF(&Parser, "Expected a strip struct but none was found");
}
}
// TODO(pjs): invalidate the file if its incorrect
return true; //Tokenizer.ParsingIsValid;
}
#define FOLDHAUS_ASSEMBLY_PARSER_CPP
#endif // FOLDHAUS_ASSEMBLY_PARSER_CPP

View File

@ -0,0 +1,99 @@
//
// 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;
ClearArena(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;
}
#define FOLDHAUS_ADDRESSED_DATA_H
#endif // FOLDHAUS_ADDRESSED_DATA_H

View File

@ -36,10 +36,20 @@ UpackL1(const u8* ptr)
} }
//Packs a u16 to a known big endian buffer //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* inline u8*
PackB2(u8* ptr, u16 val) PackB2(u8* ptr, u16 val)
{ {
ptr[1] = (u8)(val & 0xff); ptr[1] = (u8)(val & 0xff);
ptr[0] = (u8)((val & 0xff00) >> 8); ptr[0] = (u8)((val & 0xff00) >> 8);
return ptr + sizeof(val); return ptr + sizeof(val);
} }

View File

@ -0,0 +1,563 @@
//
// 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_string FileName;
u32 LineNumber;
parser_error* Next;
};
struct parser
{
gs_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;
};
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, "File: %S Line: %d - ", Error->FileName, Error->LineNumber);
va_list Args;
va_start(Args, Format);
PrintFArgsList(&Error->Message, Format, Args);
va_end(Args);
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;
}
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

@ -160,11 +160,11 @@ VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
} }
internal cid internal cid
StringToCID_ (const char* String) gs_stringToCID_ (const char* gs_string)
{ {
cid Result = {}; cid Result = {};
const char* Src = String; const char* Src = gs_string;
u8* Dest = &Result.Bytes[0]; u8* Dest = &Result.Bytes[0];
b32 FirstNibble = true; b32 FirstNibble = true;
@ -208,6 +208,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
cid CID cid CID
) )
{ {
// TODO(pjs): Replace packing with gs_memory_cursor
u8* Cursor = Buffer; u8* Cursor = Buffer;
@ -215,7 +216,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE); Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE); Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
GSMemCopy(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE); CopyMemoryTo(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE);
Cursor += ACN_IDENTIFIER_SIZE; Cursor += ACN_IDENTIFIER_SIZE;
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters // TODO(Peter): If you never use this anywhere else, go back and remove the parameters
@ -243,7 +244,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
// framing source name // framing source name
// :Check // :Check
GSMemCopy(SourceName, (char*)Cursor, SOURCE_NAME_SIZE); CopyMemoryTo(SourceName, (char*)Cursor, SOURCE_NAME_SIZE);
Cursor[SOURCE_NAME_SIZE - 1] = '\0'; Cursor[SOURCE_NAME_SIZE - 1] = '\0';
Cursor += SOURCE_NAME_SIZE; Cursor += SOURCE_NAME_SIZE;
@ -285,6 +286,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
Cursor = PackB1(Cursor, StartCode); Cursor = PackB1(Cursor, StartCode);
Assert(Cursor - Buffer == STREAM_HEADER_SIZE); Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
} }
// //
@ -292,25 +294,24 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
// //
internal streaming_acn internal streaming_acn
InitializeSACN ( context Context) SACN_Initialize (context Context)
{ {
streaming_acn SACN = {}; streaming_acn SACN = {};
s32 Multicast_TimeToLive = 20; s32 Multicast_TimeToLive = 20;
SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive); SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive);
SACN.CID = StringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}"); SACN.CID = gs_stringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
return SACN; return SACN;
} }
internal void internal void
SACNCleanup(streaming_acn* SACN, context Context) SACN_Cleanup(streaming_acn* SACN, context Context)
{ {
Context.PlatformCloseSocket(SACN->SendSocket);
} }
internal void internal void
SACNUpdateSequence (streaming_acn* SACN) SACN_UpdateSequence (streaming_acn* SACN)
{ {
// Never use 0 after the first one // Never use 0 after the first one
if (++SACN->SequenceIterator == 0) if (++SACN->SequenceIterator == 0)
@ -320,7 +321,7 @@ SACNUpdateSequence (streaming_acn* SACN)
} }
internal void internal void
SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN) SACN_PrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN)
{ {
Assert(SizeReservedForHeader == STREAM_HEADER_SIZE); Assert(SizeReservedForHeader == STREAM_HEADER_SIZE);
Assert(Buffer && BufferSize > 0); Assert(Buffer && BufferSize > 0);
@ -331,7 +332,7 @@ SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReser
} }
internal u32 internal u32
SACNGetUniverseSendAddress(s32 Universe) SACN_GetUniverseSendAddress(s32 Universe)
{ {
u8 MulticastAddressBuffer[4] = {}; u8 MulticastAddressBuffer[4] = {};
MulticastAddressBuffer[0] = 239; MulticastAddressBuffer[0] = 239;
@ -343,6 +344,52 @@ SACNGetUniverseSendAddress(s32 Universe)
return V4Address; return V4Address;
} }
internal void
SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, led_buffer LedBuffer)
{
u8* DestChannel = BufferStart;
for (u32 i = 0; i < Strip.LedCount; 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;
}
}
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 = 512;
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];
u32 V4SendAddress = SACN_GetUniverseSendAddress(StripAt.SACNAddr.StartUniverse);
u32 SendPort = DEFAULT_STREAMING_ACN_PORT;
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize);
AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort);
SACN_PrepareBufferHeader(StripAt.SACNAddr.StartUniverse, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN);
SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, *LedBuffer);
}
}
}
#define SACN_H #define SACN_H
#endif // SACN_H #endif // SACN_H

View File

@ -0,0 +1,95 @@
//
// 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 = 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 < Channel->PixelsCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask
OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B;
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 = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
{
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
UART_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
{
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 = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
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

@ -0,0 +1,86 @@
//
// 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)
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,28 +0,0 @@
#include <stdio.h>
#include <objc/message.h>
#include <objc/runtime.h>
typedef struct AppDel {
Class isa;
id window;
} AppDelegate;
BOOL AppDel_didFinishLaunching(AppDelegate* self, SEL _command, id Notification)
{
return YES;
}
int main(int ArgCount, char** Args)
{
Class NSApplicationClass = (Class)objc_getClass("NSApplication");
Class AppDelegateClass = objc_allocateClassPair(NSApplicationClass, "AppDelegate", 0);
SEL MethodSelector = sel_getUid("applicationDidFinishLaunching:");
// NOTE(Peter): i = int, @ = object, : = method selector (SEL)
char MethodSignature[] = "i@:@";
class_addMethod(AppDelegateClass, MethodSelector, (IMP)AppDel_didFinishLaunching, "i@:@");
objc_registerClassPair(AppDelegateClass);
return 0;
}

View File

@ -8,56 +8,6 @@
#include "foldhaus_platform.h" #include "foldhaus_platform.h"
#include "foldhaus_app.h" #include "foldhaus_app.h"
internal v4
MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, rect WindowBounds)
{
DEBUG_TRACK_SCOPE(MouseToWorldRay);
r32 X = ((2.0f * MouseX) / gs_Width(WindowBounds)) - 1;
r32 Y = ((2.0f * MouseY) / gs_Height(WindowBounds)) - 1;
v4 ScreenPos = v4{X, Y, -1, 1};
m44 InverseProjection = {};
Inverse(GetCameraPerspectiveProjectionMatrix(*Camera), &InverseProjection);
m44 InverseModelView = {};
Inverse(GetCameraModelViewMatrix(*Camera), &InverseModelView);
InverseModelView = Transpose(InverseModelView);
v4 ClipSpacePos = InverseProjection * ScreenPos;
v4 WorldPosition = InverseModelView * ClipSpacePos;
return WorldPosition;
}
struct send_sacn_job_data
{
platform_socket_handle SendSocket;
platform_send_to* SendTo;
dmx_buffer_list* DMXBuffers;
};
internal void
SACNSendDMXBufferListJob (s32 ThreadID, void* JobData)
{
DEBUG_TRACK_FUNCTION;
send_sacn_job_data* Data = (send_sacn_job_data*)JobData;
platform_socket_handle SendSocket = Data->SendSocket;
dmx_buffer_list* DMXBufferAt = Data->DMXBuffers;
while (DMXBufferAt)
{
dmx_buffer Buffer = DMXBufferAt->Buffer;
u32 V4SendAddress = SACNGetUniverseSendAddress(Buffer.Universe);
Data->SendTo(SendSocket, V4SendAddress, DEFAULT_STREAMING_ACN_PORT, (const char*)Buffer.Base, Buffer.TotalSize, 0);
DMXBufferAt = DMXBufferAt->Next;
}
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
RELOAD_STATIC_DATA(ReloadStaticData) RELOAD_STATIC_DATA(ReloadStaticData)
@ -70,15 +20,14 @@ RELOAD_STATIC_DATA(ReloadStaticData)
INITIALIZE_APPLICATION(InitializeApplication) INITIALIZE_APPLICATION(InitializeApplication)
{ {
app_state* State = (app_state*)Context.MemoryBase; app_state* State = (app_state*)Context.MemoryBase;
State->Permanent = {}; *State = {};
State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
State->Transient = {};
State->Transient.FindAddressRule = FindAddress_InLastBufferOnly;
State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
State->GlobalLog = PushStruct(&State->Transient, event_log); State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator);
State->Transient = Context.ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
State->GlobalLog = PushStruct(State->Transient, event_log);
*State->GlobalLog = {0}; *State->GlobalLog = {0};
s32 CommandQueueSize = 32; s32 CommandQueueSize = 32;
@ -87,13 +36,11 @@ INITIALIZE_APPLICATION(InitializeApplication)
CommandQueueSize); CommandQueueSize);
State->CommandQueue = InitializeCommandQueue(CommandQueueMemory, CommandQueueSize); State->CommandQueue = InitializeCommandQueue(CommandQueueMemory, CommandQueueSize);
State->ActiveTextEntry.Buffer = MakeString(PushArray(&State->Permanent, char, 256), 0, 256);
// TODO(Peter): put in InitializeInterface? // TODO(Peter): put in InitializeInterface?
r32 FontSize = 14; r32 FontSize = 14;
{ {
platform_memory_result FontFile = Context.PlatformReadEntireFile("Anonymous Pro.ttf"); gs_file FontFile = ReadEntireFile(Context.ThreadContext.FileHandler, ConstString("data/Anonymous Pro.ttf"));
if (!FontFile.Error) if (FileNoError(FontFile))
{ {
bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font); bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font);
@ -102,7 +49,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
Font->BitmapBytesPerPixel = 4; Font->BitmapBytesPerPixel = 4;
Font->BitmapMemory = PushArray(&State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel); Font->BitmapMemory = PushArray(&State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel);
Font->BitmapStride = Font->BitmapWidth * Font->BitmapBytesPerPixel; Font->BitmapStride = Font->BitmapWidth * Font->BitmapBytesPerPixel;
GSMemSet(Font->BitmapMemory, 0, Font->BitmapStride * Font->BitmapHeight); ZeroMemoryBlock(Font->BitmapMemory, Font->BitmapStride * Font->BitmapHeight);
platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false); platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false);
Font->PixelHeight = FontInfo.PixelHeight; Font->PixelHeight = FontInfo.PixelHeight;
@ -136,7 +83,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY);
} }
State->Interface.Font = Font; State->Interface.Style.Font = Font;
Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory, Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory,
Font->BitmapWidth, Font->BitmapHeight); Font->BitmapWidth, Font->BitmapHeight);
@ -147,37 +94,37 @@ INITIALIZE_APPLICATION(InitializeApplication)
} }
} }
State->Interface.FontSize = FontSize; State->Interface.Style.FontSize = FontSize;
State->Interface.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; State->Interface.Style.PanelBGColors[0] = v4{.3f, .3f, .3f, 1};
State->Interface.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; State->Interface.Style.PanelBGColors[1] = v4{.4f, .4f, .4f, 1};
State->Interface.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; State->Interface.Style.PanelBGColors[2] = v4{.5f, .5f, .5f, 1};
State->Interface.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1};
State->Interface.ButtonColor_Inactive = BlackV4; State->Interface.Style.ButtonColor_Inactive = BlackV4;
State->Interface.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1};
State->Interface.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; State->Interface.Style.ButtonColor_Selected = v4{.1f, .1f, .3f, 1};
State->Interface.TextColor = WhiteV4; State->Interface.Style.TextColor = WhiteV4;
State->Interface.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
State->Interface.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
State->Interface.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
State->Interface.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f };
State->Interface.Margin = v2{5, 5}; State->Interface.Style.Margin = v2{5, 5};
State->Interface.RowHeight = State->Interface.Font->PixelHeight + 2 * State->Interface.Margin.y; State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface);
State->Interface_.Style = State->Interface; State->SACN = SACN_Initialize(Context);
State->SACN = InitializeSACN(Context); State->Camera.FieldOfView = 45.0f;
State->NetworkProtocolHeaderSize = STREAM_HEADER_SIZE; State->Camera.AspectRatio = RectAspectRatio(State->WindowBounds);
State->Camera.Near = .1f;
State->Camera.Far = 800.0f;
State->Camera.Position = v3{0, 0, 400};
State->Camera.LookAt = v3{0, 0, 0
};
State->Camera.FieldOfView = DegreesToRadians(45.0f); State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128);
State->Camera.AspectRatio = gs_AspectRatio(State->WindowBounds);
State->Camera.Near = 1.0f;
State->Camera.Far = 100.0f;
State->Camera.Position = v3{0, 0, -250};
State->Camera.LookAt = v3{0, 0, 0};
#if 1 #if 1
char Path[] = "blumen_lumen.fold"; gs_const_string SculpturePath = ConstString("data/blumen_lumen_silver_spring.fold");
LoadAssembly(State, Context, Path); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
#endif #endif
State->PixelsToWorldScale = .01f; State->PixelsToWorldScale = .01f;
@ -186,33 +133,37 @@ INITIALIZE_APPLICATION(InitializeApplication)
ReloadStaticData(Context, GlobalDebugServices); ReloadStaticData(Context, GlobalDebugServices);
// Setup Operation Modes State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext);
State->Modes.ActiveModesCount = 0;
State->Modes.Arena = {};
State->Modes.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Modes.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
State->Modes.Arena.FindAddressRule = FindAddress_InLastBufferOnly;
{ // Animation PLAYGROUND { // Animation PLAYGROUND
State->AnimationSystem = {}; State->AnimationSystem = {};
State->AnimationSystem.Storage = &State->Permanent;
State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32);
State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; State->AnimationSystem.SecondsPerFrame = 1.f / 24.f;
State->AnimationSystem.PlayableRange.Min = 0;
State->AnimationSystem.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); animation Anim = {0};
State->AnimationSystem.LayersMax = 32; Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one");
State->AnimationSystem.Layers = PushArray(&State->Permanent, anim_layer, State->AnimationSystem.LayersMax); Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8);
AddLayer(MakeStringLiteral("Base Layer"), &State->AnimationSystem, BlendMode_Overwrite); Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8);
AddLayer(MakeStringLiteral("Color Layer"), &State->AnimationSystem, BlendMode_Multiply); Anim.PlayableRange.Min = 0;
AddLayer(MakeStringLiteral("Sparkles"), &State->AnimationSystem, BlendMode_Add); Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem);
Animation_AddBlock(&Anim, 22, 123, 2, 0);
AnimationArray_Push(&State->AnimationSystem.Animations, Anim);
} // End Animation Playground } // End Animation Playground
InitializePanelSystem(&State->PanelSystem); InitializePanelSystem(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount);
panel* Panel = TakeNewPanel(&State->PanelSystem); PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
SetPanelDefinition(Panel, PanelType_SculptureView, State);
} }
internal void internal void
HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_state Mouse) HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
@ -226,11 +177,12 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_
} }
else else
{ {
panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); panel_with_layout PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds);
if (!PanelWithMouseOverIt.Panel) { return; } if (!PanelWithMouseOverIt.Panel) { return; }
State->HotPanel = PanelWithMouseOverIt.Panel; State->HotPanel = PanelWithMouseOverIt.Panel;
panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; s32 PanelTypeIndex = PanelWithMouseOverIt.Panel->TypeIndex;
panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex];
if (!PanelDefinition.InputCommands) { return; } if (!PanelDefinition.InputCommands) { return; }
ActiveCommands.Commands = PanelDefinition.InputCommands; ActiveCommands.Commands = PanelDefinition.InputCommands;
@ -264,60 +216,12 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
{ {
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
Entry->Command.Proc(State, Entry->Event, Mouse); Entry->Command.Proc(State, Entry->Event, Mouse, Context);
} }
ClearCommandQueue(&State->CommandQueue); ClearCommandQueue(&State->CommandQueue);
} }
internal dmx_buffer_list*
CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena)
{
DEBUG_TRACK_FUNCTION;
dmx_buffer_list* Result = 0;
dmx_buffer_list* Head = 0;
s32 BufferSize = BufferHeaderSize + 512;
for (u32 Range = 0; Range < Assembly.LEDUniverseMapCount; Range++)
{
leds_in_universe_range LEDUniverseRange = Assembly.LEDUniverseMap[Range];
dmx_buffer_list* NewBuffer = PushStruct(Arena, dmx_buffer_list);
NewBuffer->Buffer.Universe = LEDUniverseRange.Universe;
NewBuffer->Buffer.Base = PushArray(Arena, u8, BufferSize);
NewBuffer->Buffer.TotalSize = BufferSize;
NewBuffer->Buffer.HeaderSize = BufferHeaderSize;
NewBuffer->Next = 0;
// Append
if (!Result) {
Result = NewBuffer;
Head = Result;
}
Head->Next = NewBuffer;
Head = NewBuffer;
u8* DestChannel = Head->Buffer.Base + BufferHeaderSize;
for (s32 LEDIdx = LEDUniverseRange.RangeStart;
LEDIdx < LEDUniverseRange.RangeOnePastLast;
LEDIdx++)
{
led LED = Assembly.LEDBuffer.LEDs[LEDIdx];
pixel Color = Assembly.LEDBuffer.Colors[LED.Index];
DestChannel[0] = Color.R;
DestChannel[1] = Color.G;
DestChannel[2] = Color.B;
DestChannel += 3;
}
}
return Result;
}
UPDATE_AND_RENDER(UpdateAndRender) UPDATE_AND_RENDER(UpdateAndRender)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
@ -327,19 +231,26 @@ UPDATE_AND_RENDER(UpdateAndRender)
// and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't // 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 // 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. // incorrect to clear the arena, and then access the memory later.
ClearArena(&State->Transient); ClearArena(State->Transient);
Context->Mouse.CursorType = CursorType_Arrow; Context->Mouse.CursorType = CursorType_Arrow;
HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse); PushRenderClearScreen(RenderBuffer);
State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds);
if (State->AnimationSystem.TimelineShouldAdvance) { HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
// TODO(Peter): Revisit this. This implies that the framerate of the animation system
// is tied to the framerate of the simulation. That seems correct to me, but I'm not sure {
State->AnimationSystem.CurrentFrame += 1; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
// Loop back to the beginning if (State->AnimationSystem.TimelineShouldAdvance) {
if (State->AnimationSystem.CurrentFrame > State->AnimationSystem.PlayableRange.Max) // TODO(Peter): Revisit this. This implies that the framerate of the animation system
{ // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
State->AnimationSystem.CurrentFrame = 0; State->AnimationSystem.CurrentFrame += 1;
// Loop back to the beginning
if (State->AnimationSystem.CurrentFrame > ActiveAnim->PlayableRange.Max)
{
State->AnimationSystem.CurrentFrame = 0;
}
} }
} }
@ -349,163 +260,102 @@ UPDATE_AND_RENDER(UpdateAndRender)
State->AnimationSystem.LastUpdatedFrame = CurrentFrame; State->AnimationSystem.LastUpdatedFrame = CurrentFrame;
r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame; r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame;
u32 CurrentBlocksMax = State->AnimationSystem.LayersCount; animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(&State->AnimationSystem, State->Transient);
b8* CurrentBlocksFilled = PushArray(&State->Transient, b8, CurrentBlocksMax);
GSZeroArray(CurrentBlocksFilled, b8, CurrentBlocksMax);
animation_block* CurrentBlocks = PushArray(&State->Transient, animation_block, CurrentBlocksMax);
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) led_buffer* LayerLEDBuffers = PushArray(State->Transient, led_buffer, CurrFrame.BlocksCountMax);
for (u32 AssemblyIndex = 0; AssemblyIndex < State->Assemblies.Count; AssemblyIndex++)
{ {
gs_list_entry<animation_block>* BlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
if (EntryIsFree(BlockEntry)) { continue; } led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly->LedBufferIndex);
animation_block Block = BlockEntry->Value;
if (CurrentFrame < Block.Range.Min || CurrentFrame > Block.Range.Max) { continue; }
CurrentBlocksFilled[Block.Layer] = true;
CurrentBlocks[Block.Layer] = Block;
}
assembly_led_buffer* LayerLEDBuffers = PushArray(&State->Transient, assembly_led_buffer, CurrentBlocksMax); for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
for (u32 AssemblyIndex = 0; AssemblyIndex < State->ActiveAssemblyIndecies.Used; AssemblyIndex++)
{
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(AssemblyIndex);
assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle);
arena_snapshot ResetAssemblyMemorySnapshot = TakeSnapshotOfArena(&State->Transient);
for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++)
{ {
if (!CurrentBlocksFilled[Layer]) { continue; } if (!CurrFrame.BlocksFilled[Layer]) { continue; }
animation_block Block = CurrentBlocks[Layer]; animation_block Block = CurrFrame.Blocks[Layer];
// Prep Temp Buffer // Prep Temp Buffer
LayerLEDBuffers[Layer] = Assembly->LEDBuffer; LayerLEDBuffers[Layer] = *AssemblyLedBuffer;
LayerLEDBuffers[Layer].Colors = PushArray(&State->Transient, pixel, Assembly->LEDBuffer.LEDCount); LayerLEDBuffers[Layer].Colors = PushArray(State->Transient, pixel, AssemblyLedBuffer->LedCount);
u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; u32 FramesIntoBlock = CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame; r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame;
// TODO(Peter): Temporary
switch(Block.AnimationProcHandle)
{
case 1:
{
TestPatternOne(&LayerLEDBuffers[Layer], SecondsIntoBlock);
}break;
case 2: // :AnimProcHandle
{ u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
TestPatternTwo(&LayerLEDBuffers[Layer], SecondsIntoBlock); animation_proc* AnimationProc = GlobalAnimationClips[AnimationProcIndex].Proc;
}break; AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, State->Transient);
case 3:
{
TestPatternThree(&LayerLEDBuffers[Layer], SecondsIntoBlock);
}break;
// NOTE(Peter): Zero is invalid
InvalidDefaultCase;
}
} }
// Consolidate Temp Buffers // Consolidate Temp Buffers
// We do this in reverse order so that they go from top to bottom // We do this in reverse order so that they go from top to bottom
for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++) animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
{ {
if (!CurrentBlocksFilled[Layer]) { continue; } if (!CurrFrame.BlocksFilled[Layer]) { continue; }
switch (State->AnimationSystem.Layers[Layer].BlendMode) switch (ActiveAnim->Layers.Values[Layer].BlendMode)
{ {
case BlendMode_Overwrite: case BlendMode_Overwrite:
{ {
for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
{ {
Assembly->LEDBuffer.Colors[LED] = LayerLEDBuffers[Layer].Colors[LED]; AssemblyLedBuffer->Colors[LED] = LayerLEDBuffers[Layer].Colors[LED];
} }
}break; }break;
case BlendMode_Add: case BlendMode_Add:
{ {
for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
{ {
u32 R = (u32)Assembly->LEDBuffer.Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R; u32 R = (u32)AssemblyLedBuffer->Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R;
u32 G = (u32)Assembly->LEDBuffer.Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G; u32 G = (u32)AssemblyLedBuffer->Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G;
u32 B = (u32)Assembly->LEDBuffer.Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B; u32 B = (u32)AssemblyLedBuffer->Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B;
Assembly->LEDBuffer.Colors[LED].R = (u8)GSMin(R, (u32)255); AssemblyLedBuffer->Colors[LED].R = (u8)Min(R, (u32)255);
Assembly->LEDBuffer.Colors[LED].G = (u8)GSMin(G, (u32)255); AssemblyLedBuffer->Colors[LED].G = (u8)Min(G, (u32)255);
Assembly->LEDBuffer.Colors[LED].B = (u8)GSMin(B, (u32)255); AssemblyLedBuffer->Colors[LED].B = (u8)Min(B, (u32)255);
} }
}break; }break;
case BlendMode_Multiply: case BlendMode_Multiply:
{ {
for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
{ {
r32 DR = (r32)Assembly->LEDBuffer.Colors[LED].R / 255.f; r32 DR = (r32)AssemblyLedBuffer->Colors[LED].R / 255.f;
r32 DG = (r32)Assembly->LEDBuffer.Colors[LED].G / 255.f; r32 DG = (r32)AssemblyLedBuffer->Colors[LED].G / 255.f;
r32 DB = (r32)Assembly->LEDBuffer.Colors[LED].B / 255.f; r32 DB = (r32)AssemblyLedBuffer->Colors[LED].B / 255.f;
r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f; r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f;
r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f; r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f;
r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f; r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f;
Assembly->LEDBuffer.Colors[LED].R = (u8)((DR * SR) * 255.f); AssemblyLedBuffer->Colors[LED].R = (u8)((DR * SR) * 255.f);
Assembly->LEDBuffer.Colors[LED].G = (u8)((DG * SG) * 255.f); AssemblyLedBuffer->Colors[LED].G = (u8)((DG * SG) * 255.f);
Assembly->LEDBuffer.Colors[LED].B = (u8)((DB * SB) * 255.f); AssemblyLedBuffer->Colors[LED].B = (u8)((DB * SB) * 255.f);
} }
}break; }break;
} }
} }
ClearArenaToSnapshot(&State->Transient, ResetAssemblyMemorySnapshot);
} }
} }
s32 HeaderSize = State->NetworkProtocolHeaderSize;
dmx_buffer_list* DMXBuffers = 0;
for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{ {
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); // NOTE(pjs): Building data buffers to be sent out to the sculpture
assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); // This array is used on the platform side to actually send the information
dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(*Assembly, HeaderSize, &State->Transient); assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers); 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);
} }
//DEBUG_IF(GlobalDebugServices->Interface.SendSACNData) PushRenderOrthographic(RenderBuffer, State->WindowBounds);
{
switch (State->NetworkProtocol)
{
case NetworkProtocol_SACN:
{
SACNUpdateSequence(&State->SACN);
dmx_buffer_list* CurrentDMXBuffer = DMXBuffers;
while (CurrentDMXBuffer)
{
dmx_buffer Buffer = CurrentDMXBuffer->Buffer;
SACNPrepareBufferHeader(Buffer.Universe, Buffer.Base, Buffer.TotalSize, Buffer.HeaderSize, State->SACN);
CurrentDMXBuffer = CurrentDMXBuffer->Next;
}
send_sacn_job_data* Job = PushStruct(&State->Transient, send_sacn_job_data);
Job->SendSocket = State->SACN.SendSocket;
Job->SendTo = Context->PlatformSendTo;
Job->DMXBuffers = DMXBuffers;
Context->GeneralWorkQueue->PushWorkOnQueue(Context->GeneralWorkQueue, SACNSendDMXBufferListJob, Job, "SACN Send Data Job");
}break;
InvalidDefaultCase;
}
}
PushRenderOrthographic(RenderBuffer, 0, 0, gs_Width(State->WindowBounds), gs_Height(State->WindowBounds));
PushRenderClearScreen(RenderBuffer); PushRenderClearScreen(RenderBuffer);
State->WindowBounds = Context->WindowBounds; State->WindowBounds = Context->WindowBounds;
State->Interface_.RenderBuffer = RenderBuffer; State->Interface.RenderBuffer = RenderBuffer;
State->Interface_.Mouse = Context->Mouse; State->Interface.Mouse = Context->Mouse;
panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, State->Transient);
DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context); DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
@ -513,30 +363,31 @@ UPDATE_AND_RENDER(UpdateAndRender)
operation_mode OperationMode = State->Modes.ActiveModes[m]; operation_mode OperationMode = State->Modes.ActiveModes[m];
if (OperationMode.Render != 0) if (OperationMode.Render != 0)
{ {
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse); OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
} }
} }
Context->GeneralWorkQueue->DoQueueWorkUntilDone(Context->GeneralWorkQueue, 0); Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);
// Checking for overflows // Checking for overflows
#if 0
{ {
DEBUG_TRACK_SCOPE(OverflowChecks); DEBUG_TRACK_SCOPE(OverflowChecks);
AssertAllocationsNoOverflow(State->Permanent); AssertAllocationsNoOverflow(State->Permanent);
for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) for (u32 i = 0; i < State->Assemblies.Count; i++)
{ {
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); assembly* Assembly = &State->Assemblies.Values[i];
assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle);
AssertAllocationsNoOverflow(Assembly->Arena); AssertAllocationsNoOverflow(Assembly->Arena);
} }
} }
#endif
} }
CLEANUP_APPLICATION(CleanupApplication) CLEANUP_APPLICATION(CleanupApplication)
{ {
app_state* State = (app_state*)Context.MemoryBase; app_state* State = (app_state*)Context.MemoryBase;
SACNCleanup(&State->SACN, Context); SACN_Cleanup(&State->SACN, Context);
} }
#define FOLDHAUS_APP_CPP #define FOLDHAUS_APP_CPP

View File

@ -8,128 +8,127 @@
#include "../meta/gs_meta_include.h" #include "../meta/gs_meta_include.h"
#include "../meta/gs_meta_lexer.h" #include "../meta/gs_meta_lexer.h"
#include "engine/foldhaus_serializer.h"
#include "../gs_libs/gs_font.h" #include "../gs_libs/gs_font.h"
#include "foldhaus_log.h" #include "foldhaus_log.h"
#include "interface.h" #include "interface.h"
#include "foldhaus_network_ordering.h" #include "engine/foldhaus_network_ordering.h"
#include "dmx/dmx.h"
#include "sacn/sacn.h"
#include "foldhaus_assembly.h" #include "engine/assembly/foldhaus_assembly.h"
#include "engine/assembly/foldhaus_assembly_parser.cpp"
#include "assembly_parser.h" #include "engine/sacn/foldhaus_sacn.h"
#include "engine/uart/foldhaus_uart.h"
#include "engine/uart/foldhaus_uart.cpp"
#include "foldhaus_node.h" typedef struct app_state app_state;
// TODO(Peter): TEMPORARY #include "editor/foldhaus_command_dispatch.h"
//u32 NodeSpecificationsCount = 0; #include "editor/foldhaus_operation_mode.h"
//node_specification* NodeSpecifications = 0;
#include "assembly_parser.cpp"
#include "test_patterns.h"
// TODO(Peter): something we can do later is to remove all reliance on app_state and context // 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 // 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. // perform operations on, like panel_draw_requests = { bounds, panel* } etc.
#include "foldhaus_panel.h" #include "editor/foldhaus_panel.h"
typedef struct app_state app_state; #include "engine/animation/foldhaus_animation.h"
#include "engine/animation/foldhaus_animation_serializer.cpp"
#include "foldhaus_command_dispatch.h"
#include "foldhaus_operation_mode.h"
#include "animation/foldhaus_animation.h"
#include "foldhaus_text_entry.h"
#include "foldhaus_search_lister.h"
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_Count,
};
struct app_state struct app_state
{ {
rect WindowBounds; gs_memory_arena Permanent;
gs_memory_arena* Transient;
memory_arena Permanent; // Engine
memory_arena Transient; //
s32 NetworkProtocolHeaderSize;
network_protocol NetworkProtocol; network_protocol NetworkProtocol;
streaming_acn SACN; streaming_acn SACN;
led_system LedSystem;
assembly_array Assemblies;
animation_system AnimationSystem;
event_log* GlobalLog;
s32 TotalLEDsCount; // Interface
gs_list<assembly> AssemblyList; //
gs_list<gs_list_handle> ActiveAssemblyIndecies; rect2 WindowBounds;
camera Camera;
r32 PixelsToWorldScale;
operation_mode_system Modes; operation_mode_system Modes;
input_command_queue CommandQueue; input_command_queue CommandQueue;
text_entry ActiveTextEntry;
ui_interface Interface_;
interface_config Interface;
animation_system AnimationSystem;
gs_list_handle SelectedAnimationBlockHandle;
u32 SelectedAnimationLayer;
ui_interface Interface;
panel_system PanelSystem; panel_system PanelSystem;
panel* HotPanel; panel* HotPanel;
pattern_node_workspace NodeWorkspace; camera Camera; // TODO(Peter): move into the sculpture view
r32 PixelsToWorldScale;
event_log* GlobalLog; handle SelectedAnimationBlockHandle; // TODO(Peter): move into animation panel
u32 SelectedAnimationLayer; // TODO(Peter): move into animation panel
}; };
internal void OpenColorPicker(app_state* State, v4* Address); internal void OpenColorPicker(app_state* State, v4* Address);
#include "engine/assembly/foldhaus_assembly.cpp"
// BEGIN TEMPORARY PATTERNS // BEGIN TEMPORARY PATTERNS
internal void internal void
TestPatternOne(assembly_led_buffer* Assembly, r32 Time) TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{ {
for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient);
led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient);
for (u32 i = 0; i < BlumenStrips.Count; i++)
{ {
led LED = Assembly->LEDs[LEDIdx]; u32 StripIndex = BlumenStrips.StripIndices[i];
if (LED.Position.x < 0) v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{ {
Assembly->Colors[LED.Index].R = 255; u32 LedIndex = StripAt.LedLUT[j];
Assembly->Colors[LED.Index].B = 255; Leds->Colors[LedIndex] = { 255, 0, 0 };
Assembly->Colors[LED.Index].G = 255;
}
else
{
Assembly->Colors[LED.Index].R = 0;
Assembly->Colors[LED.Index].B = 0;
Assembly->Colors[LED.Index].G = 0;
} }
} }
for (u32 i = 0; i < RadiaStrips.Count; i++)
{
u32 StripIndex = RadiaStrips.StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{
u32 LedIndex = StripAt.LedLUT[j];
Leds->Colors[LedIndex] = { 0, 255, 0 };
}
}
#if 0
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 LedPosition = Leds->Positions[LedIndex];
float PercentX = RemapClampedR32(LedPosition.x, -150.0f, 150.0f, 0.0f, 1.0f);
float PercentY = RemapClampedR32(LedPosition.y, -150.0f, 150.0f, 0.0f, 1.0f);
Leds->Colors[LedIndex].R = (u8)(PercentX * 255);
Leds->Colors[LedIndex].G = (u8)(PercentY * 255);
}
#endif
} }
internal void internal void
TestPatternTwo(assembly_led_buffer* Assembly, r32 Time) TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{ {
r32 PeriodicTime = (Time / PI) * 2; r32 PeriodicTime = (Time / PiR32) * 2;
r32 ZeroOneSin = (GSSin(PeriodicTime) * .5f) + .5f; r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f;
r32 ZeroOneCos = (GSCos(PeriodicTime) * .5f) + .5f; r32 ZeroOneCos = (CosR32(PeriodicTime) * .5f) + .5f;
pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) }; pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) };
v4 Center = v4{0, 0, 0, 1}; v4 Center = v4{0, 0, 0, 1};
r32 ThetaZ = Time / 2; r32 ThetaZ = Time / 2;
v4 Normal = v4{GSCos(ThetaZ), 0, GSSin(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 v4 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
v4 Right = Cross(Normal, v4{0, 1, 0, 0}); v4 Right = V4Cross(Normal, v4{0, 1, 0, 0});
v4 FrontCenter = Center + (Normal * 25); v4 FrontCenter = Center + (Normal * 25);
v4 BackCenter = Center - (Normal * 25); v4 BackCenter = Center - (Normal * 25);
@ -137,127 +136,100 @@ TestPatternTwo(assembly_led_buffer* Assembly, r32 Time)
r32 OuterRadiusSquared = 1000000; r32 OuterRadiusSquared = 1000000;
r32 InnerRadiusSquared = 0; r32 InnerRadiusSquared = 0;
for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{ {
led LED = Assembly->LEDs[LEDIdx]; v4 Position = Leds->Positions[LedIndex];
v4 Position = LED.Position;
v4 ToFront = Position + FrontCenter; v4 ToFront = Position + FrontCenter;
v4 ToBack = Position + BackCenter; v4 ToBack = Position + BackCenter;
r32 ToFrontDotNormal = Dot(ToFront, Normal); r32 ToFrontDotNormal = V4Dot(ToFront, Normal);
r32 ToBackDotNormal = Dot(ToBack, Normal); r32 ToBackDotNormal = V4Dot(ToBack, Normal);
ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000); ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000);
ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000); ToBackDotNormal = Clamp01(ToBackDotNormal * 1000);
r32 SqDistToCenter = MagSqr(Position); r32 SqDistToCenter = V4MagSquared(Position);
if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared)
{ {
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
{ {
Assembly->Colors[LED.Index] = Color; Leds->Colors[LedIndex] = Color;
} }
else else
{ {
//Assembly->Colors[LED.Index] = {}; //Leds->Colors[LedIndex] = {};
} }
} }
else else
{ {
//Assembly->Colors[LED.Index] = {}; //Leds->Colors[LedIndex] = {};
} }
} }
} }
internal void internal void
TestPatternThree(assembly_led_buffer* Assembly, r32 Time) TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{ {
v4 GreenCenter = v4{0, 0, 150, 1}; v4 GreenCenter = v4{0, 0, 150, 1};
r32 GreenRadius = GSAbs(GSSin(Time)) * 200; r32 GreenRadius = Abs(SinR32(Time)) * 200;
v4 TealCenter = v4{0, 0, 150, 1}; v4 TealCenter = v4{0, 0, 150, 1};
r32 TealRadius = GSAbs(GSSin(Time + 1.5)) * 200; r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200;
r32 FadeDist = 35; r32 FadeDist = 35;
for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{ {
led LED = Assembly->LEDs[LEDIdx]; v4 LedPosition = Leds->Positions[LedIndex];
u8 Red = 0; u8 Red = 0;
u8 Green = 0; u8 Green = 0;
u8 Blue = 0; u8 Blue = 0;
r32 GreenDist = GSAbs(Mag(LED.Position - GreenCenter) - GreenRadius); r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius);
r32 GreenBrightness = GSClamp(0.f, FadeDist - GSAbs(GreenDist), FadeDist); r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist);
Green = (u8)(GreenBrightness * 255); Green = (u8)(GreenBrightness * 255);
r32 TealDist = GSAbs(Mag(LED.Position - TealCenter) - TealRadius); r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius);
r32 TealBrightness = GSClamp(0.f, FadeDist - GSAbs(TealDist), FadeDist); r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist);
Red = (u8)(TealBrightness * 255); Red = (u8)(TealBrightness * 255);
Blue = (u8)(TealBrightness * 255); Blue = (u8)(TealBrightness * 255);
Assembly->Colors[LED.Index].R = Red; Leds->Colors[LedIndex].R = Red;
Assembly->Colors[LED.Index].B = Green; Leds->Colors[LedIndex].B = Green;
Assembly->Colors[LED.Index].G = Green; Leds->Colors[LedIndex].G = Green;
} }
} }
// END TEMPORARY PATTERNS // END TEMPORARY PATTERNS
#include "foldhaus_assembly.cpp"
#include "foldhaus_text_entry.cpp"
#include "foldhaus_search_lister.cpp"
#include "foldhaus_default_nodes.h"
#include "./generated/gs_meta_generated_typeinfo.h"
#include "generated/foldhaus_nodes_generated.h"
#include "foldhaus_node.cpp"
FOLDHAUS_INPUT_COMMAND_PROC(EndCurrentOperationMode) FOLDHAUS_INPUT_COMMAND_PROC(EndCurrentOperationMode)
{ {
DeactivateCurrentOperationMode(&State->Modes); DeactivateCurrentOperationMode(&State->Modes);
} }
#define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State) s32 GlobalAnimationClipsCount = 3;
typedef PANEL_INIT_PROC(panel_init_proc); animation_clip GlobalAnimationClips[] = {
{ "Test Pattern One", 16, TestPatternOne },
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel, app_state* State) { "Test Pattern Two", 16, TestPatternTwo },
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc); { "Test Pattern Three", 18, TestPatternThree },
// TODO(Peter): Should be able to take the mouse out of this
#define PANEL_RENDER_PROC(name) void name(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
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;
}; };
#include "panels/foldhaus_panel_sculpture_view.h" #include "editor/panels/foldhaus_panel_types.h"
#include "panels/foldhaus_panel_profiler.h"
#include "panels/foldhaus_panel_dmx_view.h"
#include "panels/foldhaus_panel_animation_timeline.h"
#include "panels/foldhaus_panel_hierarchy.h"
#include "panels/foldhaus_panel_node_graph.h"
#include "panels/foldhaus_panel_file_view.h"
#include "generated/foldhaus_panels_generated.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 "foldhaus_interface.cpp"
#include "editor/panels/foldhaus_panel_types.cpp"
//#include "generated/foldhaus_panels_generated.h"
#include "editor/foldhaus_interface.cpp"
#include "../meta/gs_meta_include.cpp" #include "../meta/gs_meta_include.cpp"

View File

@ -1,123 +0,0 @@
//
// File: foldhaus_assembly.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_CPP
internal assembly
ConstructAssemblyFromDefinition (assembly_definition Definition,
string AssemblyName,
v4 RootPosition,
r32 Scale,
memory_arena Arena)
{
assembly Assembly = {};
Assembly.Arena = Arena;
Assembly.Name = MakeString(PushArray(&Assembly.Arena, char, AssemblyName.Length), AssemblyName.Length);
CopyStringTo(AssemblyName, &Assembly.Name);
// NOTE(Peter): Setting this to zero so we can check at the end of the loop that creates leds
// and make sure we created to correct number. By the time this function returns it should be
// the case that: (Assembly.LEDCount == Definition.TotalLEDCount)
Assembly.LEDBuffer.LEDCount = 0;
Assembly.LEDBuffer.Colors = PushArray(&Assembly.Arena, pixel, Definition.TotalLEDCount);
Assembly.LEDBuffer.LEDs = PushArray(&Assembly.Arena, led, Definition.TotalLEDCount);
Assembly.LEDUniverseMapCount = Definition.LEDStripCount;
Assembly.LEDUniverseMap = PushArray(&Assembly.Arena, leds_in_universe_range, Definition.LEDStripCount);
// Add LEDs
for (u32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++)
{
led_strip_definition StripDef = Definition.LEDStrips[StripIdx];
leds_in_universe_range* LEDUniverseRange = Assembly.LEDUniverseMap + StripIdx;
LEDUniverseRange->Universe = StripDef.StartUniverse;
LEDUniverseRange->RangeStart = Assembly.LEDBuffer.LEDCount;
LEDUniverseRange->RangeOnePastLast = Assembly.LEDBuffer.LEDCount + StripDef.LEDsPerStrip;
// NOTE(Peter): this should be a switch on the type, but we only have one for
// now. The assert is to remind you to create more cases when necessary
Assert(StripDef.InterpolationType == StripInterpolate_Points);
v4 WS_StripStart = RootPosition + V4(StripDef.InterpolatePositionStart * Scale, 1);
v4 WS_StripEnd = RootPosition + V4(StripDef.InterpolatePositionEnd * Scale, 1);
s32 LEDsInStripCount = StripDef.LEDsPerStrip;
Assert(Assembly.LEDBuffer.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)LEDsInStripCount;
for (s32 Step = 0; Step < LEDsInStripCount; Step++)
{
s32 LEDIndex = Assembly.LEDBuffer.LEDCount++;
Assembly.LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step);
Assembly.LEDBuffer.LEDs[LEDIndex].Index = LEDIndex;
}
}
// NOTE(Peter): Did we create the correct number of LEDs?
Assert(Assembly.LEDBuffer.LEDCount == Definition.TotalLEDCount);
return Assembly;
}
// NOTE(Peter): These are here so that if we load 2+ sculptures, they don't all
// end up on top of one another. Purely aesthetic. Can remove once we implement
// scene editing tools
static v4 TempAssemblyOffsets[] = { v4{0, 0, 0, 0}, v4{250, 0, 75, 0}, v4{-250, 0, 75, 0} };
s32 TempAssemblyOffsetsCount = 3;
internal void
LoadAssembly (app_state* State, context Context, char* Path)
{
platform_memory_result AssemblyFile = Context.PlatformReadEntireFile(Path);
if (AssemblyFile.Error == PlatformMemory_NoError)
{
assembly_definition AssemblyDefinition = ParseAssemblyFile(AssemblyFile.Base, AssemblyFile.Size, &State->Transient, State->GlobalLog);
string PathString = MakeStringLiteral(Path);
s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\');
string FileName = Substring(PathString, IndexOfLastSlash + 1);
memory_arena AssemblyArena = {};
AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount];
r32 Scale = 100;
assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, Offset, Scale, AssemblyArena);
gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly);
State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle);
State->TotalLEDsCount += NewAssembly.LEDBuffer.LEDCount;
Context.PlatformFree(AssemblyFile.Base, AssemblyFile.Size);
}
else
{
LogError(State->GlobalLog, "Unable to load assembly file");
}
}
internal void
UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
{
assembly* Assembly = State->AssemblyList.GetElementAtIndex(AssemblyIndex);
State->TotalLEDsCount -= Assembly->LEDBuffer.LEDCount;
FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree);
State->AssemblyList.FreeElementAtIndex(AssemblyIndex);
for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{
gs_list_handle Handle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i);
if (Handle.Index == AssemblyIndex)
{
State->ActiveAssemblyIndecies.FreeElementAtIndex(i);
break;
}
}
}
#define FOLDHAUS_ASSEMBLY_CPP
#endif // FOLDHAUS_ASSEMBLY_CPP

View File

@ -1,64 +0,0 @@
//
// File: foldhaus_assembly.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_H
struct led
{
s32 Index;
v4 Position;
};
union pixel
{
struct
{
u8 R;
u8 G;
u8 B;
};
u8 Channels[3];
};
// NOTE(Peter): This structure is so we can keep track of
// what LEDs output to which DMX universe. You don't need
// to use it anywhere else, as all the data for patterns,
// colors, and groups is/will be stored elsewhere.
struct leds_in_universe_range
{
s32 RangeStart;
s32 RangeOnePastLast;
s32 Universe;
};
struct assembly_led_buffer
{
u32 LEDCount;
pixel* Colors;
led* LEDs;
};
struct assembly
{
memory_arena Arena;
string Name;
string FilePath;
assembly_led_buffer LEDBuffer;
#if 0
u32 LEDCount;
pixel* Colors;
led* LEDs;
#endif
u32 LEDUniverseMapCount;
leds_in_universe_range* LEDUniverseMap;
};
#define FOLDHAUS_ASSEMBLY_H
#endif // FOLDHAUS_ASSEMBLY_H

View File

@ -3,6 +3,9 @@
// Author: Peter Slattery // Author: Peter Slattery
// Creation Date: 2020-01-01 // Creation Date: 2020-01-01
// //
// DESCRIPTION:
// This file contains profiling capabilities for both the engine and app
//
#ifndef FOLDHAUS_DEBUG_H #ifndef FOLDHAUS_DEBUG_H
#define SCOPE_NAME_LENGTH 256 #define SCOPE_NAME_LENGTH 256
@ -30,7 +33,7 @@ struct collated_scope_record
struct scope_name struct scope_name
{ {
u32 Hash; u32 Hash;
string Name; gs_string Name;
char Buffer[SCOPE_NAME_BUFFER_LENGTH]; char Buffer[SCOPE_NAME_BUFFER_LENGTH];
}; };
@ -82,7 +85,7 @@ typedef u8* debug_realloc(u8* Memory, s32 OldSize, s32 NewSize);
struct debug_histogram_entry struct debug_histogram_entry
{ {
char ScopeName_[SCOPE_NAME_LENGTH]; char ScopeName_[SCOPE_NAME_LENGTH];
string ScopeName; gs_string ScopeName;
u32 PerFrame_Cycles[HISTOGRAM_DEPTH]; u32 PerFrame_Cycles[HISTOGRAM_DEPTH];
u32 PerFrame_CallCount[HISTOGRAM_DEPTH]; u32 PerFrame_CallCount[HISTOGRAM_DEPTH];
@ -359,9 +362,9 @@ BeginTrackingScopeAndGetNameHash (debug_services* Services, char* ScopeName)
if (Entry->Hash == 0) // If its new if (Entry->Hash == 0) // If its new
{ {
Entry->Hash = NameHash; Entry->Hash = NameHash;
// TODO(Peter): need to initialize all entry name strings to point at the buffer // 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 // This will break eventually. when it does, do this ^^^^ when on startup
CopyCharArrayToString(ScopeName, &Entry->Name); PrintF(&Entry->Name, "%s", ScopeName);
} }
return NameHash; return NameHash;

View File

@ -1,126 +0,0 @@
//
// File: foldhaus_debug_visuals.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_DEBUG_VISUALS_H
internal void
DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_config Interface, r32 WindowWidth, r32 WindowHeight, r32 DeltaTime, app_state* State, camera Camera, mouse_state Mouse, memory_arena* Transient)
{
DEBUG_TRACK_SCOPE(DrawDebugInterface);
v2 TopOfDebugView = v2{StartX, WindowHeight - (NewLineYOffset(*Interface.Font) + 5)};
v2 TopOfScreenLinePos = TopOfDebugView;
string DebugString = InitializeEmptyString(PushArray(Transient, char, 256), 256);
if (GlobalDebugServices->Interface.ShowCameraMouse)
{
PushRenderQuad2D(RenderBuffer,
v2{TopOfDebugView.x, TopOfDebugView.y - 500},
v2{TopOfDebugView.x + 700, TopOfDebugView.y},
v4{0, 0, 0, .8f});
}
r32 FramesPerSecond = 1.0f / DeltaTime;
PrintF(&DebugString, "Framerate: %.*f s %d fps | Modes: %d Memory Used: %d / %d | Commands: %d | HI SAM!!!! ",
5, DeltaTime,
(u32)FramesPerSecond,
State->Modes.ActiveModesCount,
State->Modes.Arena.TotalUsed,
State->Modes.Arena.TotalSize,
State->CommandQueue.Used);
DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, WhiteV4);
v2 ButtonDim = v2{200, (r32)NewLineYOffset(*Interface.Font) + 10};
TopOfScreenLinePos.y -= ButtonDim.y + 10;
v2 ButtonPos = TopOfScreenLinePos;
button_result CameraBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim,
MakeStringLiteral("Camera"), Interface, Mouse);
ButtonPos.x += ButtonDim.x + 10;
button_result ScopeTimeBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim,
MakeStringLiteral("Scope Time"), Interface, Mouse);
ButtonPos.x += ButtonDim.x + 10;
button_result RenderSculptureBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim,
MakeStringLiteral("Visualize"), Interface, Mouse);
ButtonPos.x += ButtonDim.x + 10;
string SACNButtonString;
if (GlobalDebugServices->Interface.SendSACNData)
{
SACNButtonString = MakeStringLiteral("Turn SACN Off");
}
else
{
SACNButtonString = MakeStringLiteral("Turn SACN On");
}
button_result SendSACNDataBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim,
SACNButtonString, Interface, Mouse);
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font) + 10;
if (CameraBtn.Pressed)
{
GlobalDebugServices->Interface.ShowCameraMouse = !GlobalDebugServices->Interface.ShowCameraMouse;
}
if (ScopeTimeBtn.Pressed)
{
GlobalDebugServices->Interface.ShowTrackedScopes = !GlobalDebugServices->Interface.ShowTrackedScopes;
}
if (RenderSculptureBtn.Pressed)
{
GlobalDebugServices->Interface.RenderSculpture =
!GlobalDebugServices->Interface.RenderSculpture;
}
if (SendSACNDataBtn.Pressed)
{
GlobalDebugServices->Interface.SendSACNData = !GlobalDebugServices->Interface.SendSACNData;
}
if (GlobalDebugServices->Interface.ShowCameraMouse)
{
PrintF(&DebugString, "Camera x=%.*f y=%.*f z=%.*f LookAt x=%.*f y=%.*f z=%.*f",
3, Camera.Position.x,
3, Camera.Position.y,
3, Camera.Position.z,
3, Camera.LookAt.x,
3, Camera.LookAt.y,
3, Camera.LookAt.z);
DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, v4{1.0f, 1.0f, 1.0f, 1.0f});
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
b32 LeftButtonIsDown = (Mouse.LeftButtonState & KeyState_IsDown) > 0;
b32 LeftButtonWasDown = (Mouse.LeftButtonState & KeyState_WasDown) > 0;
s32 MousePrecision = 0;
PrintF(&DebugString, "Mouse Pos: (%.*f, %.*f) Down: (%.*f, %.*f) State: %s %s",
MousePrecision, Mouse.Pos.x,
MousePrecision, Mouse.Pos.y,
MousePrecision, Mouse.DownPos.x,
MousePrecision, Mouse.DownPos.y,
(LeftButtonIsDown ? "Is Down" : "Is Not Down"),
(LeftButtonWasDown ? "Was Down" : "Was Not Down"));
DrawString(RenderBuffer, DebugString, Interface.Font,
TopOfScreenLinePos, WhiteV4);
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
PrintF(&DebugString, "Render Buffer: %d / %d (at this point)",
RenderBuffer->CommandMemoryUsed,
RenderBuffer->CommandMemorySize);
DrawString(RenderBuffer, DebugString, Interface.Font,
TopOfScreenLinePos, WhiteV4);
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
}
}
#define FOLDHAUS_DEBUG_VISUALS_H
#endif // FOLDHAUS_DEBUG_VISUALS_H

View File

@ -13,7 +13,7 @@ enum log_entry_type
struct log_entry struct log_entry
{ {
string Message; gs_string Message;
log_entry_type Type; log_entry_type Type;
}; };
@ -25,11 +25,11 @@ struct event_log
u32 NextEntry; u32 NextEntry;
}; };
#define LogMessage(_Log, _Message) PushLogEntry(_Log, MakeStringLiteral(_Message), LogEntry_Message) #define LogMessage(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Message)
#define LogError(_Log, _Message) PushLogEntry(_Log, MakeStringLiteral(_Message), LogEntry_Error) #define LogError(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Error)
internal void internal void
PushLogEntry(event_log* Log, string Message, log_entry_type Type) PushLogEntry(event_log* Log, gs_string Message, log_entry_type Type)
{ {
u32 NewLogIndex = Log->NextEntry++; u32 NewLogIndex = Log->NextEntry++;
if (Log->NextEntry >= LOG_ENTRIES_MAX) if (Log->NextEntry >= LOG_ENTRIES_MAX)
@ -44,5 +44,6 @@ PushLogEntry(event_log* Log, string Message, log_entry_type Type)
#define FOLDHAUS_LOG_H #define FOLDHAUS_LOG_H
#endif // FOLDHAUS_LOG_H #endif // FOLDHAUS_LOG_H

View File

@ -1,94 +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)
typedef OPERATION_RENDER_PROC(operation_render_proc);
struct operation_mode
{
input_command_registry Commands;
operation_render_proc* Render;
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];
// 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
memory_arena Arena;
};
internal operation_mode*
ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc)
{
operation_mode* Result = 0;
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
s32 ModeIndex = System->ActiveModesCount++;
System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
operation_mode NewMode = {};
System->ActiveModes[ModeIndex] = NewMode;
Result = &System->ActiveModes[ModeIndex];
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);
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);
}
return NewMode;
}
internal void
DeactivateCurrentOperationMode (operation_mode_system* System)
{
Assert(System->ActiveModesCount > 0);
s32 ModeIndex = --System->ActiveModesCount;
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)
{
Mode->OpStateMemory = PushSize(&System->Arena, StateSize);
return Mode->OpStateMemory;
}
#define FOLDHAUS_OPERATION_MODE_H
#endif // FOLDHAUS_OPERATION_MODE_H

View File

@ -1,356 +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
typedef struct panel panel;
enum panel_split_direction
{
PanelSplit_NoSplit,
PanelSplit_Horizontal,
PanelSplit_Vertical,
PanelSplit_Count,
};
typedef struct panel_entry panel_entry;
struct panel
{
s32 PanelDefinitionIndex;
panel_split_direction SplitDirection;
r32 SplitPercent;
// TODO(Peter): This REALLY doesn't want to live here
// Probably belongs in a more generalized PanelInterfaceState or something
b32 PanelSelectionMenuOpen;
u8* PanelStateMemory;
u32 PanelStateMemorySize;
union{
panel_entry* Left;
panel_entry* Top;
};
union{
panel_entry* Right;
panel_entry* Bottom;
};
};
struct free_panel
{
panel_entry* Next;
};
struct panel_entry
{
panel Panel;
free_panel Free;
};
#define PANELS_MAX 16
struct panel_system
{
panel_entry Panels[PANELS_MAX];
u32 PanelsUsed;
panel_entry FreeList;
};
// NOTE(Peter): This representation is used to let external code render and interact
// with panels. It shouldn't be stored across frame boundaries as the pointers to
// Panel's are liable to change.
struct panel_with_layout
{
panel* Panel;
rect Bounds;
};
struct panel_layout
{
panel_with_layout* Panels;
u32 PanelsCount;
u32 PanelsMax;
};
/////////////////////////////////
//
// Book-Keeping
//
/////////////////////////////////
internal void
InitializePanelSystem(panel_system* PanelSystem)
{
PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList;
}
internal panel_entry*
TakeNewPanelEntry(panel_system* PanelSystem)
{
panel_entry* FreeEntry = 0;
if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList)
{
FreeEntry = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next;
}
else
{
Assert(PanelSystem->PanelsUsed < PANELS_MAX);
FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++;
}
return FreeEntry;
}
internal panel*
TakeNewPanel(panel_system* PanelSystem)
{
panel* Result = 0;
panel_entry* FreeEntry = TakeNewPanelEntry(PanelSystem);
Result = &FreeEntry->Panel;
*Result = {0};
Result->PanelDefinitionIndex = -1;
return Result;
}
internal void
FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem)
{
Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX);
Entry->Panel = {0};
Entry->Free.Next = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = Entry;
}
internal void
FreePanelEntryRecursive(panel_entry* Entry, panel_system* PanelSystem)
{
if (Entry->Panel.SplitDirection != PanelSplit_NoSplit)
{
FreePanelEntryRecursive(Entry->Panel.Left, PanelSystem);
FreePanelEntryRecursive(Entry->Panel.Right, PanelSystem);
}
FreePanelEntry(Entry, PanelSystem);
}
internal void
FreePanelAtIndex(s32 Index, panel_system* PanelSystem)
{
Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed);
panel_entry* EntryToFree = PanelSystem->Panels + Index;
EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next;
PanelSystem->FreeList.Free.Next = EntryToFree;
}
internal void
SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem)
{
r32 SplitX = GSLerp(ParentBounds.Min.x, ParentBounds.Max.x, Percent);
if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x)
{
Parent->SplitDirection = PanelSplit_Vertical;
Parent->SplitPercent = Percent;
Parent->Left = TakeNewPanelEntry(PanelSystem);
Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
Parent->Right = TakeNewPanelEntry(PanelSystem);
Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
}
}
internal void
SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem)
{
r32 SplitY = GSLerp(ParentBounds.Min.y, ParentBounds.Max.y, Percent);
if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y)
{
Parent->SplitDirection = PanelSplit_Horizontal;
Parent->SplitPercent = Percent;
Parent->Bottom = TakeNewPanelEntry(PanelSystem);
Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
Parent->Top = TakeNewPanelEntry(PanelSystem);
Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex;
}
}
internal void
ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_system* PanelSystem)
{
panel_entry* LeftChild = Parent->Left;
panel_entry* RightChild = Parent->Right;
panel_entry* PanelEntryToDestroy = PanelEntryToKeep == LeftChild ? RightChild : LeftChild;
*Parent = PanelEntryToKeep->Panel;
FreePanelEntry(PanelEntryToKeep, PanelSystem);
FreePanelEntryRecursive(PanelEntryToDestroy, PanelSystem);
}
/////////////////////////////////
//
// Rendering And Interaction
//
/////////////////////////////////
internal rect
GetTopPanelBounds(panel* Panel, rect PanelBounds)
{
rect Result = {};
Result.Min = v2{
PanelBounds.Min.x,
GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent)
};
Result.Max = PanelBounds.Max;
return Result;
}
internal rect
GetBottomPanelBounds(panel* Panel, rect PanelBounds)
{
rect Result = {};
Result.Min = PanelBounds.Min;
Result.Max = v2{
PanelBounds.Max.x,
GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent)
};
return Result;
}
internal rect
GetRightPanelBounds(panel* Panel, rect PanelBounds)
{
rect Result = {};
Result.Min = v2{
GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent),
PanelBounds.Min.y
};
Result.Max = PanelBounds.Max;
return Result;
}
internal rect
GetLeftPanelBounds(panel* Panel, rect PanelBounds)
{
rect Result = {};
Result.Min = PanelBounds.Min;
Result.Max = v2{
GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent),
PanelBounds.Max.y
};
return Result;
}
internal void
LayoutPanel(panel* Panel, rect PanelBounds, panel_layout* Layout)
{
if (Panel->SplitDirection == PanelSplit_NoSplit)
{
panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++;
WithLayout->Panel = Panel;
WithLayout->Bounds = PanelBounds;
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout);
LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout);
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout);
LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout);
}
}
internal panel_layout
GetPanelLayout(panel_system* System, rect WindowBounds, memory_arena* Storage)
{
panel_layout Result = {};
Result.PanelsMax = System->PanelsUsed;
Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax);
LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result);
return Result;
}
struct panel_and_bounds
{
panel* Panel;
rect Bounds;
};
internal panel_and_bounds
GetPanelContainingPoint(v2 Point, panel* Panel, rect PanelBounds)
{
panel_and_bounds Result = {0};
if (Panel->SplitDirection == PanelSplit_NoSplit)
{
Result.Panel = Panel;
Result.Bounds = PanelBounds;
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds);
rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds);
if (PointIsInRange(Point, TopPanelBounds.Min, TopPanelBounds.Max))
{
Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds);
}
else if (PointIsInRange(Point, BottomPanelBounds.Min, BottomPanelBounds.Max))
{
Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds);
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds);
rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds);
if (PointIsInRange(Point, LeftPanelBounds.Min, LeftPanelBounds.Max))
{
Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds);
}
else if (PointIsInRange(Point, RightPanelBounds.Min, RightPanelBounds.Max))
{
Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds);
}
}
return Result;
}
internal panel_and_bounds
GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect WindowBounds)
{
panel_and_bounds Result = {0};
if (PanelSystem->PanelsUsed > 0)
{
Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds);
}
return Result;
}
#define FOLDHAUS_PANEL_H
#endif // FOLDHAUS_PANEL_H

View File

@ -7,25 +7,44 @@
#include <windows.h> #include <windows.h>
#define GS_LANGUAGE_NO_PROFILER_DEFINES #include <math.h> // TODO Remove
#include "..\gs_libs\gs_language.h"
#include "..\gs_libs\gs_radix_sort.h" #include "..\gs_libs\gs_types.h"
#include "..\gs_libs\gs_list.h" #include "..\gs_libs\gs_types.cpp"
#include "..\gs_libs\gs_bucket.h"
#define GS_MEMORY_TRACK_ALLOCATIONS struct handle
#include "..\gs_libs\gs_memory_arena.h" {
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_string.h"
#include "foldhaus_debug.h" #include "foldhaus_debug.h"
global_variable debug_services* GlobalDebugServices; global debug_services* GlobalDebugServices;
#include "..\gs_libs\gs_vector_matrix.h" //#include "..\gs_libs\gs_vector_matrix.h"
#include "..\gs_libs\gs_input.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 "foldhaus_renderer.h"
#include "engine/foldhaus_addressed_data.h"
typedef struct context context; typedef struct context context;
@ -34,7 +53,7 @@ typedef struct context context;
#define INITIALIZE_APPLICATION(name) void name(context Context) #define INITIALIZE_APPLICATION(name) void name(context Context)
typedef INITIALIZE_APPLICATION(initialize_application); typedef INITIALIZE_APPLICATION(initialize_application);
#define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer) #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); typedef UPDATE_AND_RENDER(update_and_render);
#define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices) #define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices)
@ -63,13 +82,25 @@ enum platform_memory_error
PlatformMemory_UnknownError, // You should implement handling this when you see it PlatformMemory_UnknownError, // You should implement handling this when you see it
}; };
struct platform_memory_result struct data
{ {
u8* Base; u8* Base;
s32 Size; u64 Size;
};
struct platform_memory_result
{
data Data;
platform_memory_error Error; platform_memory_error Error;
}; };
struct system_path
{
char* Path;
s32 PathLength;
s32 IndexOfLastSlash;
};
struct texture_buffer struct texture_buffer
{ {
u8* Memory; u8* Memory;
@ -79,68 +110,12 @@ struct texture_buffer
s32 BytesPerPixel; s32 BytesPerPixel;
}; };
struct system_path
{
char* Path;
s32 PathLength;
s32 IndexOfLastSlash;
};
#define PLATFORM_ALLOC(name) u8* name(s32 Size)
typedef PLATFORM_ALLOC(platform_alloc);
#define PLATFORM_FREE(name) b32 name(u8* Base, s32 Size)
typedef PLATFORM_FREE(platform_free);
#define PLATFORM_REALLOC(name) u8* name(u8* Base, u32 OldSize, u32 NewSize)
typedef PLATFORM_REALLOC(platform_realloc);
#define PLATFORM_READ_ENTIRE_FILE(name) platform_memory_result name(char* Path)
typedef PLATFORM_READ_ENTIRE_FILE(platform_read_entire_file);
#define PLATFORM_WRITE_ENTIRE_FILE(name) b32 name(char* Path, u8* Contents, s32 Size)
typedef PLATFORM_WRITE_ENTIRE_FILE(platform_write_entire_file);
#define PLATFORM_GET_FILE_PATH(name) b32 name(char* PathBuffer, s32 BufferLength, const char* FilterStrings)
typedef PLATFORM_GET_FILE_PATH(platform_get_file_path);
#define PLATFORM_GET_GPU_TEXTURE_HANDLE(name) s32 name(u8* Memory, s32 Width, s32 Height) #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); typedef PLATFORM_GET_GPU_TEXTURE_HANDLE(platform_get_gpu_texture_handle);
struct platform_network_address
{
s32 Family;
u16 Port;
u32 Address;
};
typedef s32 platform_socket_handle;
typedef s32 platform_network_address_handle;
#define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive) #define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive)
typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle); typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle);
#define PLATFORM_GET_SEND_ADDRESS_HANDLE(name) platform_network_address_handle name(s32 AddressFamily, u16 Port, u32 Address)
typedef PLATFORM_GET_SEND_ADDRESS_HANDLE(platform_get_send_address);
#define PLATFORM_SET_SOCKET_OPTION(name) s32 name(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
typedef PLATFORM_SET_SOCKET_OPTION(platform_set_socket_option);
#define PLATFORM_SEND_TO(name) s32 name(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags)
typedef PLATFORM_SEND_TO(platform_send_to);
#define PLATFORM_CLOSE_SOCKET(name) void name(platform_socket_handle SocketHandle)
typedef PLATFORM_CLOSE_SOCKET(platform_close_socket);
// File IO
// TODO(Peter):
struct directory_listing
{
string Path;
directory_listing* Next;
};
// Font // Font
struct platform_font_info struct platform_font_info
{ {
@ -175,50 +150,11 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint);
#define PLATFORM_THREAD_COUNT 4 #define PLATFORM_THREAD_COUNT 4
#define THREADED_WORK_PROC(name) void name(s32 ThreadID, void* Data)
typedef THREADED_WORK_PROC(threaded_work_proc);
typedef struct work_queue work_queue;
#define PUSH_WORK_ON_QUEUE(name) void name(work_queue* Queue, threaded_work_proc* WorkProc, void* Data, char* JobName)
typedef PUSH_WORK_ON_QUEUE(push_work_on_queue);
#define DO_QUEUE_WORK_UNTIL_DONE(name) void name(work_queue* Queue, s32 ThreadID)
typedef DO_QUEUE_WORK_UNTIL_DONE(do_queue_work_until_done);
#define RESET_WORK_QUEUE(name) void name(work_queue* Queue)
typedef RESET_WORK_QUEUE(reset_work_queue);
struct worker_thread_job
{
void* Data;
threaded_work_proc* WorkProc;
#ifdef DEBUG
char* JobName;
#endif
};
struct work_queue
{
void* SemaphoreHandle;
u32 JobsMax;
u32 volatile JobsCount;
u32 volatile NextJobIndex;
u32 volatile JobsCompleted;
worker_thread_job* Jobs;
// Work Queue
push_work_on_queue* PushWorkOnQueue;
do_queue_work_until_done* DoQueueWorkUntilDone;
reset_work_queue* ResetWorkQueue;
};
RESET_WORK_QUEUE(ResetWorkQueue) RESET_WORK_QUEUE(ResetWorkQueue)
{ {
for (u32 i = 0; i < Queue->JobsMax; i++) for (u32 i = 0; i < Queue->JobsMax; i++)
{ {
Queue->Jobs[i].Data = 0; Queue->Jobs[i].Data = {0};
Queue->Jobs[i].WorkProc = 0; Queue->Jobs[i].WorkProc = 0;
} }
@ -238,11 +174,13 @@ GetSecondsElapsed (s64 Start, s64 End, s64 PerformanceCountFrequency)
struct context struct context
{ {
gs_thread_context ThreadContext;
u8* MemoryBase; u8* MemoryBase;
u32 MemorySize; u32 MemorySize;
b32 WindowIsVisible; b32 WindowIsVisible;
rect WindowBounds; rect2 WindowBounds;
r32 DeltaTime; r32 DeltaTime;
mouse_state Mouse; mouse_state Mouse;
@ -253,21 +191,13 @@ struct context
cleanup_application* CleanupApplication; cleanup_application* CleanupApplication;
// Platform Services // Platform Services
work_queue* GeneralWorkQueue; gs_work_queue* GeneralWorkQueue;
platform_alloc* PlatformAlloc;
platform_free* PlatformFree;
platform_realloc* PlatformRealloc;
platform_read_entire_file* PlatformReadEntireFile;
platform_write_entire_file* PlatformWriteEntireFile;
platform_get_file_path* PlatformGetFilePath;
platform_get_gpu_texture_handle* PlatformGetGPUTextureHandle; platform_get_gpu_texture_handle* PlatformGetGPUTextureHandle;
platform_get_font_info* PlatformGetFontInfo; platform_get_font_info* PlatformGetFontInfo;
platform_draw_font_codepoint* PlatformDrawFontCodepoint; platform_draw_font_codepoint* PlatformDrawFontCodepoint;
platform_get_socket_handle* PlatformGetSocketHandle; platform_get_socket_handle* PlatformGetSocketHandle;
platform_set_socket_option* PlatformSetSocketOption;
platform_send_to* PlatformSendTo;
platform_close_socket* PlatformCloseSocket;
}; };

View File

@ -110,8 +110,8 @@ RenderCommandBuffer (render_command_buffer CommandBuffer)
glViewport(Command->ViewOffsetX, Command->ViewOffsetY, glViewport(Command->ViewOffsetX, Command->ViewOffsetY,
Command->ViewWidth, Command->ViewHeight); Command->ViewWidth, Command->ViewHeight);
LoadModelView(Command->ModelView.E); LoadModelView(Command->ModelView.Array);
LoadProjection(Command->Projection.E); LoadProjection(Command->Projection.Array);
if (Command->UseDepthBuffer) if (Command->UseDepthBuffer)
{ {

View File

@ -19,60 +19,71 @@ struct camera
inline m44 inline m44
GetCameraModelViewMatrix (camera Camera) GetCameraModelViewMatrix (camera Camera)
{ {
// Forward m44 RotationMatrix = M44LookAt(ToV4Point(Camera.Position), ToV4Point(Camera.LookAt));
v4 CamForward = V4(Normalize(Camera.Position - Camera.LookAt), 0); m44 PositionMatrix = M44Translation(ToV4Point(-Camera.Position));
// Right m44 ModelViewMatrix = RotationMatrix * PositionMatrix;
v4 CamRight = Normalize(Cross(v4{0, 1, 0, 0}, CamForward));
// Up
v4 CamUp = Normalize(Cross(CamForward, CamRight));
r32 X = Camera.Position.x;
r32 Y = Camera.Position.y;
r32 Z = Camera.Position.z;
m44 RotationMatrix = M44(
CamRight.x, CamUp.x, CamForward.x, 0,
CamRight.y, CamUp.y, CamForward.y, 0,
CamRight.z, CamUp.z, CamForward.z, 0,
0, 0, 0, 1);
m44 PositionMatrix = M44(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
-X, -Y, -Z, 1
);
m44 ModelViewMatrix = PositionMatrix * RotationMatrix;
return ModelViewMatrix; return ModelViewMatrix;
} }
inline m44 inline m44
GetCameraPerspectiveProjectionMatrix(camera Camera) GetCameraPerspectiveProjectionMatrix(camera Camera)
{ {
r32 Top = Camera.Near * GSTan((Camera.FieldOfView / 2.0f)); m44 Result = M44ProjectionPerspective(Camera.FieldOfView, Camera.AspectRatio, Camera.Near, Camera.Far);
r32 Bottom = -Top; return Result;
r32 Right = Top * Camera.AspectRatio; }
r32 Left = -Right;
r32 A = ((Right + Left) / (Right - Left)); internal m44
r32 B = ((Top + Bottom) / (Top - Bottom)); GetCameraMatrix(camera Camera)
r32 C = -((Camera.Far + Camera.Near) / (Camera.Far - Camera.Near)); {
r32 D = -((2 * Camera.Far * Camera.Near) / (Camera.Far - Camera.Near)); m44 ModelView = GetCameraModelViewMatrix(Camera);
m44 Projection = GetCameraPerspectiveProjectionMatrix(Camera);
m44 Result = Projection * ModelView;
return Result;
}
r32 E = ((2 * Camera.Near) / (Right - Left)); internal v2
r32 F = ((2 * Camera.Near) / (Top - Bottom)); 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);
m44 PerspectiveProjectionMatrix = return ScreenPosition;
{ }
E, 0, A, 0,
0, F, B, 0,
0, 0, C, D,
0, 0, -1, 0
};
return PerspectiveProjectionMatrix; 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 // Render Commands
@ -195,7 +206,7 @@ struct render_command_set_render_mode
typedef u8* renderer_realloc(u8* Base, s32 CurrentSize, s32 NewSize); typedef u8* renderer_realloc(u8* Base, s32 CurrentSize, s32 NewSize);
#define COMMAND_BUFFER_MIN_GROW_SIZE Megabytes(2) #define COMMAND_BUFFER_MIN_GROW_SIZE MB(2)
struct render_command_buffer struct render_command_buffer
{ {
@ -252,7 +263,7 @@ ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize)
// NewSize = Buffer->CommandMemorySize + (2 * DataSize); // NewSize = Buffer->CommandMemorySize + (2 * DataSize);
s32 SpaceAvailable = Buffer->CommandMemorySize - Buffer->CommandMemoryUsed; s32 SpaceAvailable = Buffer->CommandMemorySize - Buffer->CommandMemoryUsed;
s32 SpaceNeeded = DataSize - SpaceAvailable; // This is known to be positive at this point s32 SpaceNeeded = DataSize - SpaceAvailable; // This is known to be positive at this point
s32 AdditionSize = GSMax(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE); s32 AdditionSize = Max(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE);
s32 NewSize = Buffer->CommandMemorySize + AdditionSize; s32 NewSize = Buffer->CommandMemorySize + AdditionSize;
Buffer->CommandMemory = Buffer->Realloc(Buffer->CommandMemory, Buffer->CommandMemory = Buffer->Realloc(Buffer->CommandMemory,
Buffer->CommandMemorySize, Buffer->CommandMemorySize,
@ -280,7 +291,7 @@ PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* C
internal s32 internal s32
PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, s32 DataSize, u8* MemStart) PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, s32 DataSize, u8* MemStart)
{ {
GSZeroMemory(MemStart, DataSize); ZeroMemoryBlock(MemStart, DataSize);
Constructor->Max = QuadCount; Constructor->Max = QuadCount;
Constructor->Count = 0; Constructor->Count = 0;
@ -311,6 +322,16 @@ struct quad_batch_constructor_reserved_range
s32 OnePastLast; 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 internal quad_batch_constructor_reserved_range
ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded) ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded)
{ {
@ -326,6 +347,8 @@ SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex,
v2 UV0, v2 UV1, v2 UV2, v2 UV0, v2 UV1, v2 UV2,
v4 C0, v4 C1, v4 C2) 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 // Vertecies
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 0)] = P0; 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, 1)] = P1;
@ -342,6 +365,7 @@ SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex,
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 2)] = C2; Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 2)] = C2;
} }
inline void inline void
PushTri3DOnBatch (render_quad_batch_constructor* Constructor, PushTri3DOnBatch (render_quad_batch_constructor* Constructor,
v4 P0, v4 P1, v4 P2, v4 P0, v4 P1, v4 P2,
@ -349,6 +373,7 @@ PushTri3DOnBatch (render_quad_batch_constructor* Constructor,
v4 C0, v4 C1, v4 C2) v4 C0, v4 C1, v4 C2)
{ {
DEBUG_TRACK_FUNCTION; 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); s32 Tri = ThreadSafeIncrementQuadConstructorCount(Constructor);
SetTri3DInBatch(Constructor, Tri, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2); SetTri3DInBatch(Constructor, Tri, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}; };
@ -356,7 +381,7 @@ PushTri3DOnBatch (render_quad_batch_constructor* Constructor,
internal void internal void
PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 P2, v4 P3, v2 UVMin, v2 UVMax, v4 Color) 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); Assert(Constructor->Count + 2 <= Constructor->Max);
PushTri3DOnBatch(Constructor, P0, P1, P2, UVMin, v2{UVMax.x, UVMin.y}, UVMax, Color, Color, Color); 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); PushTri3DOnBatch(Constructor, P0, P2, P3, UVMin, UVMax, v2{UVMin.x, UVMax.y}, Color, Color, Color);
} }
@ -367,7 +392,7 @@ PushQuad3DOnBatch (render_quad_batch_constructor* Constructor,
v2 UV0, v2 UV1, v2 UV2, v2 UV3, v2 UV0, v2 UV1, v2 UV2, v2 UV3,
v4 C0, v4 C1, v4 C2, v4 C3) v4 C0, v4 C1, v4 C2, v4 C3)
{ {
Assert(Constructor->Count < Constructor->Max); Assert(Constructor->Count <= Constructor->Max);
PushTri3DOnBatch(Constructor, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2); PushTri3DOnBatch(Constructor, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
PushTri3DOnBatch(Constructor, P0, P2, P3, UV0, UV2, UV3, C0, C2, C3); PushTri3DOnBatch(Constructor, P0, P2, P3, UV0, UV2, UV3, C0, C2, C3);
} }
@ -466,7 +491,7 @@ internal void
PushLine2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, r32 Thickness, v4 Color) PushLine2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, r32 Thickness, v4 Color)
{ {
r32 HalfThickness = Thickness / 2.0f; r32 HalfThickness = Thickness / 2.0f;
v2 Perpendicular = Normalize(PerpendicularCCW(P1 - P0)) * HalfThickness; v2 Perpendicular = V2Normalize(V2PerpendicularCCW(P1 - P0)) * HalfThickness;
PushQuad2DOnBatch(Constructor, P0 - Perpendicular, P1 - Perpendicular, P1 + Perpendicular, P0 + Perpendicular, PushQuad2DOnBatch(Constructor, P0 - Perpendicular, P1 - Perpendicular, P1 + Perpendicular, P0 + Perpendicular,
v2{0, 0}, v2{1, 1}, Color); v2{0, 0}, v2{1, 1}, Color);
@ -495,8 +520,8 @@ PushRenderPerspective (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY,
{ {
render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode); render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode);
Command->ModelView = GetCameraModelViewMatrix(Camera); Command->ModelView = M44Transpose(GetCameraModelViewMatrix(Camera));
Command->Projection = GetCameraPerspectiveProjectionMatrix(Camera); Command->Projection = M44Transpose(GetCameraPerspectiveProjectionMatrix(Camera));
Command->ViewOffsetX = (r32)OffsetX; Command->ViewOffsetX = (r32)OffsetX;
Command->ViewOffsetY = (r32)OffsetY; Command->ViewOffsetY = (r32)OffsetY;
@ -508,25 +533,18 @@ PushRenderPerspective (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY,
return Command; 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 internal void
PushRenderOrthographic (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, s32 ViewWidth, s32 ViewHeight) 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); render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode);
Command->ModelView = m44{ Command->ModelView = M44Identity();
1, 0, 0, 0, Command->Projection = M44ProjectionOrtho((r32)ViewWidth, (r32)ViewHeight, 0, 100, ViewWidth, 0, ViewHeight, 0);
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
r32 a = 2.0f / ViewWidth;
r32 b = 2.0f / ViewHeight;
Command->Projection = m44{
a, 0, 0, 0,
0, b, 0, 0,
0, 0, 1, 0,
-1, -1, 0, 1
};
Command->ViewOffsetX = (r32)OffsetX; Command->ViewOffsetX = (r32)OffsetX;
Command->ViewOffsetY = (r32)OffsetY; Command->ViewOffsetY = (r32)OffsetY;
@ -536,6 +554,12 @@ PushRenderOrthographic (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY,
Command->UseDepthBuffer = false;; 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 internal void
PushRenderClearScreen (render_command_buffer* Buffer) PushRenderClearScreen (render_command_buffer* Buffer)
{ {
@ -565,6 +589,13 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color)
PushQuad2DOnBatch(&Batch, Min, Max, Color); PushQuad2DOnBatch(&Batch, Min, 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 internal void
PushRenderLine2D (render_command_buffer* Buffer, v2 P0, v2 P1, r32 Thickness, v4 Color) PushRenderLine2D (render_command_buffer* Buffer, v2 P0, v2 P1, r32 Thickness, v4 Color)
{ {

View File

@ -1,14 +1,32 @@
enum node_type enum node_type
{ {
NodeType_SolidColorProc,
NodeType_RevolvingDiscs,
NodeType_VerticalColorFadeProc,
NodeType_Count, NodeType_Count,
}; };
static node_specification_ NodeSpecifications[] = { 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) void CallNodeProc(node_type Type, u8* NodeData)
{ {
switch(Type) { 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,5 +0,0 @@
enum panel_type {
};
global_variable s32 GlobalPanelDefsCount = 0;
global_variable panel_definition GlobalPanelDefs[] = {
};

View File

@ -1,14 +1,110 @@
enum gsm_meta_tag_type 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 MetaTagStrings[] = { 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 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, 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[] = { 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 = 0; static gsm_u32 StructTypesCount = 12;

3239
src/app/handmade_math.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
// //
#ifndef INTERFACE_H #ifndef INTERFACE_H
enum string_alignment enum gs_string_alignment
{ {
Align_Left, Align_Left,
Align_Center, Align_Center,
@ -60,10 +60,10 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char
} }
internal v2 internal v2
DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color)
{ {
v2 RegisterPosition = InitialRegisterPosition; v2 RegisterPosition = InitialRegisterPosition;
char* C = String; char* C = gs_string;
for (s32 i = 0; i < Length; i++) for (s32 i = 0; i < Length; i++)
{ {
v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, Color);
@ -74,10 +74,10 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Leng
} }
internal v2 internal v2
DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color)
{ {
v2 RegisterPosition = InitialRegisterPosition; v2 RegisterPosition = InitialRegisterPosition;
char* C = String + Length - 1; char* C = gs_string + Length - 1;
for (s32 i = Length - 1; i >= 0; i--) for (s32 i = Length - 1; i >= 0; i--)
{ {
v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, Color);
@ -88,7 +88,7 @@ DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Len
} }
internal v2 internal v2
DrawString (render_command_buffer* RenderBuffer, string String, bitmap_font* Font, v2 Position, v4 Color, string_alignment Alignment = Align_Left) DrawString(render_command_buffer* RenderBuffer, gs_string String, bitmap_font* Font, v2 Position, v4 Color, gs_string_alignment Alignment = Align_Left)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
v2 LowerRight = Position; v2 LowerRight = Position;
@ -129,7 +129,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col
} }
internal v2 internal v2
DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, string_alignment Alignment = Align_Left) Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
v2 LowerRight = Position; v2 LowerRight = Position;
@ -153,21 +153,21 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 Cu
{ {
RegisterPosition = DrawStringLeftAligned(&BatchConstructor, RegisterPosition = DrawStringLeftAligned(&BatchConstructor,
String.Length - CursorPosition, String.Length - CursorPosition,
String.Memory + CursorPosition, String.Str + CursorPosition,
RegisterPosition, Font, Color); RegisterPosition, Font, Color);
} }
} }
else if (Alignment == Align_Right) else if (Alignment == Align_Right)
{ {
RegisterPosition = DrawStringRightAligned(&BatchConstructor, RegisterPosition = DrawStringRightAligned(&BatchConstructor,
CursorPosition, String.Memory, CursorPosition, String.Str,
RegisterPosition, Font, Color); RegisterPosition, Font, Color);
DrawCursor(&CursorBatch, RegisterPosition, GreenV4, *Font); DrawCursor(&CursorBatch, RegisterPosition, GreenV4, *Font);
if (String.Length - CursorPosition > 0) if (String.Length - CursorPosition > 0)
{ {
RegisterPosition = DrawStringRightAligned(&BatchConstructor, RegisterPosition = DrawStringRightAligned(&BatchConstructor,
String.Length - CursorPosition, String.Length - CursorPosition,
String.Memory + CursorPosition, String.Str + CursorPosition,
RegisterPosition, Font, Color); RegisterPosition, Font, Color);
} }
} }
@ -201,7 +201,7 @@ struct interface_config
struct ui_layout struct ui_layout
{ {
rect Bounds; rect2 Bounds;
v2 Margin; v2 Margin;
r32 RowHeight; r32 RowHeight;
r32 RowYAt; r32 RowYAt;
@ -220,7 +220,7 @@ struct ui_interface
}; };
static ui_layout static ui_layout
ui_CreateLayout(ui_interface Interface, rect Bounds) ui_CreateLayout(ui_interface Interface, rect2 Bounds)
{ {
ui_layout Result = {0}; ui_layout Result = {0};
Result.Bounds = Bounds; Result.Bounds = Bounds;
@ -263,7 +263,7 @@ ui_EndRow(ui_layout* Layout)
} }
static b32 static b32
ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds) ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
{ {
b32 Result = true; b32 Result = true;
if (!Layout->DrawHorizontal) if (!Layout->DrawHorizontal)
@ -289,7 +289,7 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds)
} }
else else
{ {
r32 ElementWidth = gs_Width(Layout->Bounds) / Layout->ColumnsMax; r32 ElementWidth = Rect2Width(Layout->Bounds) / Layout->ColumnsMax;
Bounds->Min = { Bounds->Min = {
Layout->Bounds.Min.x + (ElementWidth * Layout->ColumnsCount) + Layout->Margin.x, Layout->Bounds.Min.x + (ElementWidth * Layout->ColumnsCount) + Layout->Margin.x,
Layout->RowYAt Layout->RowYAt
@ -309,18 +309,18 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds)
return Result; return Result;
} }
static rect static rect2
ui_ReserveTextLineBounds(ui_interface Interface, string Text, ui_layout* Layout) ui_ReserveTextLineBounds(ui_interface Interface, gs_string Text, ui_layout* Layout)
{ {
rect Bounds = {0}; rect2 Bounds = {0};
return Bounds; return Bounds;
} }
static rect static rect2
ui_ReserveElementBounds(ui_layout* Layout) ui_ReserveElementBounds(ui_layout* Layout)
{ {
rect Bounds = {0}; rect2 Bounds = {0};
if (!ui_TryReserveElementBounds(Layout, &Bounds)) if (!ui_TryReserveElementBounds(Layout, &Bounds))
{ {
InvalidCodePath; InvalidCodePath;
@ -328,10 +328,10 @@ ui_ReserveElementBounds(ui_layout* Layout)
return Bounds; return Bounds;
} }
static rect static rect2
ui_LayoutRemaining(ui_layout Layout) ui_LayoutRemaining(ui_layout Layout)
{ {
rect Result = Layout.Bounds; rect2 Result = Layout.Bounds;
Result.Max.y = Layout.RowYAt; Result.Max.y = Layout.RowYAt;
if (Layout.DrawHorizontal) if (Layout.DrawHorizontal)
{ {
@ -339,24 +339,32 @@ ui_LayoutRemaining(ui_layout Layout)
} }
return Result; return Result;
} }
// //
// Drawing Functions // Drawing Functions
// //
static void static r32
ui_FillRect(ui_interface* Interface, rect Bounds, v4 Color) ui_GetTextLineHeight(ui_interface Interface)
{ {
PushRenderQuad2D(Interface->RenderBuffer, gs_RectExpand(Bounds), Color); r32 Result = Interface.Style.Font->PixelHeight + (2 * Interface.Style.Margin.y);
return Result;
} }
static void static void
ui_OutlineRect(ui_interface* Interface, rect Bounds, r32 Thickness, v4 Color) ui_FillRect(ui_interface* Interface, rect2 Bounds, v4 Color)
{
PushRenderQuad2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Color);
}
static void
ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color)
{ {
PushRenderBoundingBox2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Thickness, Color); PushRenderBoundingBox2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Thickness, Color);
} }
internal void internal void
ui_DrawString(ui_interface* Interface, string String, rect Bounds, v4 Color, string_alignment Alignment = Align_Left) ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, v4 Color, gs_string_alignment Alignment = Align_Left)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer, render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer,
@ -384,9 +392,9 @@ ui_DrawString(ui_interface* Interface, string String, rect Bounds, v4 Color, str
} }
static void static void
ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, string String, v4 Color, string_alignment Alignment = Align_Left) ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, gs_string String, v4 Color, gs_string_alignment Alignment = Align_Left)
{ {
rect Bounds = {0}; rect2 Bounds = {0};
if (!ui_TryReserveElementBounds(Layout, &Bounds)) if (!ui_TryReserveElementBounds(Layout, &Bounds))
{ {
// TODO(NAME): Not invalid, just haven't implemented yet. // TODO(NAME): Not invalid, just haven't implemented yet.
@ -397,18 +405,18 @@ ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, string String, v
} }
static void static void
ui_TextBox(ui_interface* Interface, rect Bounds, string Text, v4 BGColor, v4 TextColor) ui_TextBox(ui_interface* Interface, rect2 Bounds, gs_string Text, v4 BGColor, v4 TextColor)
{ {
ui_FillRect(Interface, Bounds, BGColor); ui_FillRect(Interface, Bounds, BGColor);
ui_DrawString(Interface, Text, Bounds, TextColor); ui_DrawString(Interface, Text, Bounds, TextColor);
} }
static b32 static b32
ui_Button(ui_interface* Interface, string Text, rect Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor)
{ {
b32 Pressed = false; b32 Pressed = false;
v4 ButtonBG = InactiveColor; v4 ButtonBG = InactiveColor;
if (gs_PointIsInRect(Interface->Mouse.Pos, Bounds)) if (PointIsInRect(Bounds, Interface->Mouse.Pos))
{ {
ButtonBG = HoverColor; ButtonBG = HoverColor;
if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState))
@ -422,7 +430,7 @@ ui_Button(ui_interface* Interface, string Text, rect Bounds, v4 InactiveColor, v
} }
static b32 static b32
ui_Button(ui_interface* Interface, string Text, rect Bounds) ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds)
{ {
v4 BGColor = Interface->Style.ButtonColor_Inactive; v4 BGColor = Interface->Style.ButtonColor_Inactive;
v4 HoverColor = Interface->Style.ButtonColor_Active; v4 HoverColor = Interface->Style.ButtonColor_Active;
@ -430,25 +438,12 @@ ui_Button(ui_interface* Interface, string Text, rect Bounds)
return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor);
} }
static b32 struct list_item_colors
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, string Text, v4 BGColor, v4 HoverColor, v4 SelectColor)
{ {
rect ButtonBounds = {0}; v4 Hover;
if (!ui_TryReserveElementBounds(Layout, &ButtonBounds)) v4 Selected;
{ v4 BGColor;
ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout); };
}
return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor);
}
static b32
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, string Text)
{
v4 BGColor = Interface->Style.ButtonColor_Inactive;
v4 HoverColor = Interface->Style.ButtonColor_Active;
v4 SelectedColor = Interface->Style.ButtonColor_Selected;
return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor);
}
inline v4 inline v4
ui_GetListItemBGColor(interface_config Style, u32 ElementIndex) ui_GetListItemBGColor(interface_config Style, u32 ElementIndex)
@ -457,10 +452,54 @@ ui_GetListItemBGColor(interface_config Style, u32 ElementIndex)
return Result; return Result;
} }
static b32 static list_item_colors
ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, string Text, u32 Index) ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex)
{ {
rect Bounds = {0}; list_item_colors Result = {};
Result.Hover = Interface->Style.ListBGHover;
Result.Selected = Interface->Style.ListBGSelected;
Result.BGColor = ui_GetListItemBGColor(Interface->Style, ListItemIndex);
return Result;
}
static b32
ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex)
{
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex);
return ui_Button(Interface, Text, Bounds, Colors.Hover, Colors.Selected, Colors.BGColor);
}
static b32
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, v4 BGColor, v4 HoverColor, v4 SelectColor)
{
rect2 ButtonBounds = {0};
if (!ui_TryReserveElementBounds(Layout, &ButtonBounds))
{
ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout);
}
return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor);
}
static b32
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text)
{
v4 BGColor = Interface->Style.ButtonColor_Inactive;
v4 HoverColor = Interface->Style.ButtonColor_Active;
v4 SelectedColor = Interface->Style.ButtonColor_Selected;
return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor);
}
static b32
ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex)
{
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex);
return ui_LayoutButton(Interface, Layout, Text, Colors.Hover, Colors.Selected, Colors.BGColor);
}
static b32
ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 Index)
{
rect2 Bounds = {0};
if (!ui_TryReserveElementBounds(Layout, &Bounds)) if (!ui_TryReserveElementBounds(Layout, &Bounds))
{ {
// TODO(Peter): this isn't really invalid, but I don't have a concrete use case // TODO(Peter): this isn't really invalid, but I don't have a concrete use case
@ -488,7 +527,7 @@ enum selection_state
struct interface_list struct interface_list
{ {
rect ListBounds; rect2 ListBounds;
v2 ListElementDimensions; v2 ListElementDimensions;
v2 ElementLabelIndent; v2 ElementLabelIndent;
@ -501,10 +540,10 @@ struct interface_list
s32 ListElementsCount; s32 ListElementsCount;
}; };
internal rect internal rect2
DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer) DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer)
{ {
rect LineBounds = {}; rect2 LineBounds = {};
LineBounds.Min = v2{ LineBounds.Min = v2{
List->ListBounds.Min.x, List->ListBounds.Min.x,
List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1)) List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1))
@ -512,7 +551,7 @@ DrawListElementBackground(interface_list* List, mouse_state Mouse, render_comman
LineBounds.Max = LineBounds.Min + List->ListElementDimensions; LineBounds.Max = LineBounds.Min + List->ListElementDimensions;
v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount]; v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount];
if (PointIsInRange(Mouse.Pos, LineBounds.Min, LineBounds.Max)) if (PointIsInRect(LineBounds, Mouse.Pos))
{ {
Color = List->LineBGHoverColor; Color = List->LineBGHoverColor;
} }
@ -521,10 +560,10 @@ DrawListElementBackground(interface_list* List, mouse_state Mouse, render_comman
return LineBounds; return LineBounds;
} }
internal rect internal rect2
DrawListElement(string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) DrawListElement(gs_string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface)
{ {
rect Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); rect2 Bounds = DrawListElementBackground(List, Mouse, RenderBuffer);
v2 LabelPosition = Bounds.Min + List->ElementLabelIndent; v2 LabelPosition = Bounds.Min + List->ElementLabelIndent;
DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor); DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor);
@ -539,27 +578,34 @@ EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask,
{ {
r32 Result = Current; r32 Result = Current;
// TODO(Peter): Can this come from outside the function? Would rather pass rect around than min/max
rect2 Rect = rect2{ Min, Max };
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(RenderBuffer, 2); render_quad_batch_constructor Batch = PushRenderQuad2DBatch(RenderBuffer, 2);
v4 LeftColor = ChannelMask * 0; v4 LeftColor = ChannelMask * 0;
LeftColor.a = 1.f; LeftColor.a = 1.f;
v4 RightColor = ChannelMask; v4 RightColor = ChannelMask;
PushQuad2DOnBatch(&Batch, PushQuad2DOnBatch(&Batch,
Min, v2{Max.x, Min.y}, Max, v2{Min.x, Max.y}, RectBottomLeft(Rect), RectBottomRight(Rect),
RectTopRight(Rect), RectTopLeft(Rect),
v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1}, v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1},
LeftColor, RightColor, RightColor, LeftColor); LeftColor, RightColor, RightColor, LeftColor);
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
{ {
if (PointIsInRange(Mouse.DownPos, Min, Max)) if (PointIsInRect(Rect, Mouse.DownPos))
{ {
Result = ((r32)Mouse.Pos.x - Min.x) / (Max.x - Min.x); Result = ((r32)Mouse.Pos.x - Min.x) / (Max.x - Min.x);
Result = GSClamp01(Result); Result = Clamp01(Result);
} }
} }
r32 DragBarWidth = 8; r32 DragBarWidth = 8;
v2 DragBarMin = v2{GSLerp(Min.x, Max.x, Result) - (DragBarWidth / 2), Min.y - 2}; v2 DragBarMin = v2{
LerpR32(Result, Min.x, Max.x) - (DragBarWidth / 2),
Min.y - 2
};
v2 DragBarMax = DragBarMin + v2{DragBarWidth, (Max.y - Min.y) + 4}; v2 DragBarMax = DragBarMin + v2{DragBarWidth, (Max.y - Min.y) + 4};
PushQuad2DOnBatch(&Batch, DragBarMin, DragBarMax, v4{.3f, .3f, .3f, 1.f}); PushQuad2DOnBatch(&Batch, DragBarMin, DragBarMax, v4{.3f, .3f, .3f, 1.f});
@ -573,16 +619,18 @@ EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin
b32 ShouldClose = false; b32 ShouldClose = false;
v2 PanelMax = v2{400, 500}; v2 PanelMax = v2{400, 500};
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRange(Mouse.Pos, PanelMin, PanelMax)) // TODO(Peter): Can this get passed from outside? rather pass rect2 than min/max pairs
rect2 PanelRect = rect2{PanelMin, PanelMax};
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRect(PanelRect, Mouse.Pos))
{ {
ShouldClose = true; ShouldClose = true;
} }
else else
{ {
PushRenderQuad2D(RenderBuffer, PanelMin, PanelMax, v4{.5f, .5f, .5f, 1.f}); PushRenderQuad2D(RenderBuffer, PanelRect.Min, PanelRect.Max, v4{.5f, .5f, .5f, 1.f});
v2 TitleMin = v2{PanelMin.x + 5, PanelMax.y - (Config.Font->PixelHeight + 5)}; v2 TitleMin = v2{PanelRect.Min.x + 5, PanelRect.Max.y - (Config.Font->PixelHeight + 5)};
DrawString(RenderBuffer, MakeStringLiteral("Color Picker"), Config.Font, DrawString(RenderBuffer, MakeString("Color Picker"), Config.Font,
TitleMin, WhiteV4); TitleMin, WhiteV4);
v2 SliderDim = v2{(PanelMax.x - PanelMin.x) - 20, 32}; v2 SliderDim = v2{(PanelMax.x - PanelMin.x) - 20, 32};
@ -611,13 +659,13 @@ struct search_lister_result
b32 ShouldRemainOpen; b32 ShouldRemainOpen;
}; };
typedef string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, string SearchString, s32 Offset); typedef gs_string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, gs_string Searchgs_string, s32 Offset);
internal search_lister_result internal search_lister_result
EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string Title, EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, gs_string Title,
string* ItemList, s32* ListLUT, s32 ListLength, gs_string* ItemList, s32* ListLUT, s32 ListLength,
s32 HotItem, s32 HotItem,
string* SearchString, s32 SearchStringCursorPosition) gs_string* Searchgs_string, s32 Searchgs_stringCursorPosition)
{ {
search_lister_result Result = {}; search_lister_result Result = {};
Result.ShouldRemainOpen = true; Result.ShouldRemainOpen = true;
@ -627,24 +675,24 @@ EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string
InvalidCodePath; InvalidCodePath;
#if 0 #if 0
// Title Bar // Title Bar
rect TitleBarBounds = rect{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; rect2 TitleBarBounds = rect2{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}};
ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f}); ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f});
ui_DrawString(Interface, Title, TitleBarBounds, Interface->Style.TextColor); ui_Drawgs_string(Interface, Title, TitleBarBounds, Interface->Style.TextColor);
MakeStringBuffer(DebugString, 256); MakeStringBuffer(Debuggs_string, 256);
PrintF(&DebugString, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); PrintF(&Debuggs_string, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength);
rect DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); rect2 DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight});
ui_DrawString(Interface, DebugString, DebugBounds, Interface->Style.TextColor); ui_Drawgs_string(Interface, Debuggs_string, DebugBounds, Interface->Style.TextColor);
// Search Bar // Search Bar
PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f});
DrawStringWithCursor(RenderBuffer, *SearchString, SearchStringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4); Drawgs_stringWithCursor(RenderBuffer, *Searchgs_string, Searchgs_stringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4);
TopLeft.y -= 30; TopLeft.y -= 30;
for (s32 i = 0; i < ListLength; i++) for (s32 i = 0; i < ListLength; i++)
{ {
s32 FilteredIndex = ListLUT[i]; s32 FilteredIndex = ListLUT[i];
string ListItemString = ItemList[FilteredIndex]; gs_string ListItemgs_string = ItemList[FilteredIndex];
v2 Min = v2{TopLeft.x, TopLeft.y - 30}; v2 Min = v2{TopLeft.x, TopLeft.y - 30};
v2 Max = Min + Dimension - v2{0, Config.Margin.y}; v2 Max = Min + Dimension - v2{0, Config.Margin.y};
@ -655,7 +703,7 @@ EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string
ButtonColor = Config.ButtonColor_Active; ButtonColor = Config.ButtonColor_Active;
} }
if (ui_Button(Interface, ListItemString, rect{Min, Max})) if (ui_Button(Interface, ListItemgs_string, rect2{Min, Max}))
{ {
Result.SelectedItem = i; Result.SelectedItem = i;
} }

View File

@ -1,616 +0,0 @@
//
// File: foldhaus_panel_animation_timeline.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
// Colors
global_variable v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f};
//
struct animation_timeline_state
{
frame_range VisibleRange;
};
inline u32
GetFrameFromPointInAnimationPanel(v2 Point, rect PanelBounds, frame_range VisibleRange)
{
r32 HorizontalPercentOfBounds = (Point.x - PanelBounds.Min.x) / (PanelBounds.Max.x - PanelBounds.Min.x);
u32 VisibleFramesCount = GetFrameCount(VisibleRange);
u32 TimeAtPoint = (u32)(HorizontalPercentOfBounds * VisibleFramesCount) + VisibleRange.Min;
return TimeAtPoint;
}
inline s32
GetXPositionFromFrameInAnimationPanel (u32 Frame, rect PanelBounds, frame_range VisibleRange)
{
r32 PercentOfTimeline = (r32)(Frame - VisibleRange.Min) / (r32)GetFrameCount(VisibleRange);
s32 XPositionAtFrame = (PercentOfTimeline * gs_Width(PanelBounds)) + PanelBounds.Min.x;
return XPositionAtFrame;
}
internal gs_list_handle
AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 Layer, animation_system* System)
{
u32 NewBlockStart = System->CurrentFrame;
u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System);
gs_list_handle Result = AddAnimationBlock(NewBlockStart, NewBlockEnd, AnimationProcHandle, Layer, System);
return Result;
}
internal void
SelectAnimationBlock(gs_list_handle BlockHandle, app_state* State)
{
State->SelectedAnimationBlockHandle = BlockHandle;
}
internal void
DeselectCurrentAnimationBlock(app_state* State)
{
State->SelectedAnimationBlockHandle = {};
}
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
{
if(ListHandleIsValid(State->SelectedAnimationBlockHandle))
{
RemoveAnimationBlock(State->SelectedAnimationBlockHandle, &State->AnimationSystem);
State->SelectedAnimationBlockHandle = {0};
}
}
//
// Drag Time Marker
//
OPERATION_STATE_DEF(drag_time_marker_operation_state)
{
rect TimelineBounds;
s32 StartFrame;
s32 EndFrame;
};
OPERATION_RENDER_PROC(UpdateDragTimeMarker)
{
drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory;
frame_range Range = { OpState->StartFrame, OpState->EndFrame };
u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, Range);
State->AnimationSystem.CurrentFrame = FrameAtMouseX;
}
FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command DragTimeMarkerCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragTimeMarker },
};
internal void
StartDragTimeMarker(rect TimelineBounds, frame_range VisibleFrames, app_state* State)
{
operation_mode* DragTimeMarkerMode = ActivateOperationModeWithCommands(&State->Modes, DragTimeMarkerCommands, UpdateDragTimeMarker);
drag_time_marker_operation_state* OpState = CreateOperationState(DragTimeMarkerMode,
&State->Modes,
drag_time_marker_operation_state);
OpState->StartFrame = VisibleFrames.Min;
OpState->EndFrame = VisibleFrames.Max;
OpState->TimelineBounds = TimelineBounds;
}
// --------------------
//
// Drag Animation Clip
//
#define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10
OPERATION_STATE_DEF(drag_animation_clip_state)
{
rect TimelineBounds;
frame_range VisibleRange;
frame_range ClipRange;
};
internal u32
AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame)
{
u32 Result = SnappingFrame;
s32 SnapDistance = 5;
if (GSAbs((s32)SnappingFrame - (s32)SnapToFrame) <= SnapDistance)
{
Result = SnapToFrame;
}
return Result;
}
OPERATION_RENDER_PROC(UpdateDragAnimationClip)
{
drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory;
r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange);
u32 ClipInitialStartFrameXPosition = GSLerp(OpState->TimelineBounds.Min.x,
OpState->TimelineBounds.Max.x,
ClipInitialStartFrameXPercent);
r32 ClipInitialEndFrameXPercent = FrameToPercentRange(OpState->ClipRange.Max, OpState->VisibleRange);
u32 ClipInitialEndFrameXPosition = GSLerp(OpState->TimelineBounds.Min.x,
OpState->TimelineBounds.Max.x,
ClipInitialEndFrameXPercent);
u32 FrameAtMouseDownX = GetFrameFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->VisibleRange);
u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange);
s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX;
animation_block* AnimationBlock = State->AnimationSystem.Blocks.GetElementWithHandle(State->SelectedAnimationBlockHandle);
if (!AnimationBlock)
{
EndCurrentOperationMode(State, {}, Mouse);
return;
}
if (GSAbs(Mouse.DownPos.x - ClipInitialStartFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{
s32 NewStartFrame = OpState->ClipRange.Min + FrameOffset;
if (FrameOffset < 0)
{
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (EntryIsFree(OtherBlockEntry)) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value;
NewStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max);
}
}
else
{
if (NewStartFrame >= AnimationBlock->Range.Max)
{
NewStartFrame = AnimationBlock->Range.Max - 1;
}
}
AnimationBlock->Range.Min = NewStartFrame;
}
else if (GSAbs(Mouse.DownPos.x - ClipInitialEndFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{
r32 NewEndFrame = OpState->ClipRange.Max + FrameOffset;
if (FrameOffset > 0)
{
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (EntryIsFree(OtherBlockEntry)) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value;
NewEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min);
}
}
else
{
if(NewEndFrame <= AnimationBlock->Range.Min)
{
NewEndFrame = AnimationBlock->Range.Min + 1;
}
}
AnimationBlock->Range.Max = NewEndFrame;
}
else
{
u32 NewStartFrame = OpState->ClipRange.Min + FrameOffset;
u32 NewEndFrame = OpState->ClipRange.Max + FrameOffset;
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (EntryIsFree(OtherBlockEntry)) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value;
u32 SnapFramesAmount = 0;
if (FrameOffset > 0)
{
u32 FinalEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min);
SnapFramesAmount = FinalEndFrame - NewEndFrame;
}
else if (FrameOffset < 0)
{
u32 FinalStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max);
SnapFramesAmount = FinalStartFrame - NewStartFrame;
}
NewEndFrame += SnapFramesAmount;
NewStartFrame += SnapFramesAmount;
}
AnimationBlock->Range.Min = NewStartFrame;
AnimationBlock->Range.Max = NewEndFrame;
}
s32 PlayableStartFrame = State->AnimationSystem.PlayableRange.Min;
s32 PlayableEndFrame = State->AnimationSystem.PlayableRange.Max;
AnimationBlock->Range.Min = (u32)GSClamp(PlayableStartFrame, (s32)AnimationBlock->Range.Min, PlayableEndFrame);
AnimationBlock->Range.Max = (u32)GSClamp(PlayableStartFrame, (s32)AnimationBlock->Range.Max, PlayableEndFrame);
}
input_command DragAnimationClipCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode },
};
internal void
SelectAndBeginDragAnimationBlock(gs_list_handle BlockHandle, frame_range VisibleRange, rect TimelineBounds, app_state* State)
{
SelectAnimationBlock(BlockHandle, State);
operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip);
drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode,
&State->Modes,
drag_animation_clip_state);
OpState->TimelineBounds = TimelineBounds;
OpState->VisibleRange = VisibleRange;
animation_block* SelectedBlock = State->AnimationSystem.Blocks.GetElementWithHandle(BlockHandle);
OpState->ClipRange = SelectedBlock->Range;
}
// -------------------
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
{
panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds);
frame_range Range = State->AnimationSystem.PlayableRange;
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range);
gs_list_handle NewBlockHandle = AddAnimationBlock(MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer, &State->AnimationSystem);
SelectAnimationBlock(NewBlockHandle, State);
}
input_command AnimationTimeline_Commands[] = {
{ KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand },
{ KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand },
};
s32 AnimationTimeline_CommandsCount = 2;
GSMetaTag(panel_init);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Init(panel* Panel, app_state* State)
{
// TODO: :FreePanelMemory
animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state);
TimelineState->VisibleRange = State->AnimationSystem.PlayableRange;
Panel->PanelStateMemory = (u8*)TimelineState;
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Cleanup(panel* Panel, app_state* State)
{
}
internal void
DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBuffer, frame_range VisibleFrames, rect BarBounds, mouse_state Mouse, app_state* State)
{
MakeStringBuffer(TempString, 256);
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
r32 BarHeight = gs_Height(BarBounds);
r32 BarWidth = gs_Width(BarBounds);
PushRenderQuad2D(RenderBuffer, gs_RectExpand(BarBounds), v4{.16f, .16f, .16f, 1.f});
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) &&
PointIsInRange(Mouse.DownPos, gs_RectExpand(BarBounds)))
{
StartDragTimeMarker(BarBounds, VisibleFrames, State);
}
// Frame Ticks
u32 TickCount = 10;
for (u32 Tick = 0; Tick < TickCount; Tick++)
{
r32 Percent = (r32)Tick / (r32)TickCount;
u32 Frame = PercentToFrameInRange(Percent, VisibleFrames);
PrintF(&TempString, "%d", Frame);
r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames);
r32 FrameX = GSLerp(BarBounds.Min.x, BarBounds.Max.x, FramePercent);
v2 FrameTextPos = v2{FrameX, BarBounds.Min.y + 2};
DrawString(RenderBuffer, TempString, State->Interface.Font, FrameTextPos, WhiteV4);
}
// Time Slider
if (FrameIsInRange(AnimationSystem->CurrentFrame, VisibleFrames))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, VisibleFrames);
r32 SliderX = GSLerp(BarBounds.Min.x, BarBounds.Max.x, FrameAtPercentVisibleRange);
u32 FrameNumberCharCount = GetU32NumberOfCharactersNeeded(AnimationSystem->CurrentFrame);
// space for each character + a margin on either side
r32 SliderWidth = (8 * FrameNumberCharCount) + 8;
r32 SliderHalfWidth = SliderWidth / 2.f;
v2 HeadMin = v2{SliderX - SliderHalfWidth, BarBounds.Min.y};
v2 HeadMax = v2{SliderX + SliderHalfWidth, BarBounds.Max.y};
PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
PrintF(&TempString, "%d", AnimationSystem->CurrentFrame);
DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{6, 4}, WhiteV4);
}
}
internal frame_range
DrawTimelineRangeBar (animation_system* AnimationSystem, animation_timeline_state* TimelineState, render_command_buffer* RenderBuffer, rect BarBounds, mouse_state Mouse)
{
frame_range Result = {0};
r32 BarHeight = gs_Height(BarBounds);
r32 BarWidth = gs_Width(BarBounds);
PushRenderQuad2D(RenderBuffer, gs_RectExpand(BarBounds), v4{.16f, .16f, .16f, 1.f});
r32 PlayableFrames = (r32)GetFrameCount(AnimationSystem->PlayableRange);
v2 SliderBarDim = v2{25, BarHeight};
// Convert Frames To Pixels
r32 VisibleMinPercentPlayable = FrameToPercentRange(TimelineState->VisibleRange.Min, AnimationSystem->PlayableRange);
r32 VisibleMaxPercentPlayable = FrameToPercentRange(TimelineState->VisibleRange.Max, AnimationSystem->PlayableRange);
v2 RangeMinSliderMin = v2{BarBounds.Min.x + (VisibleMinPercentPlayable * gs_Width(BarBounds)), BarBounds.Min.y};
v2 RangeMaxSliderMin = v2{BarBounds.Min.x + (VisibleMaxPercentPlayable * gs_Width(BarBounds)) - 25, BarBounds.Min.y};
if (MouseButtonHeldDown(Mouse.LeftButtonState) ||
MouseButtonTransitionedUp(Mouse.LeftButtonState))
{
v2 MouseDragOffset = Mouse.Pos - Mouse.DownPos;
if (PointIsInRange(Mouse.DownPos, RangeMinSliderMin, RangeMinSliderMin + SliderBarDim))
{
r32 NewSliderX = RangeMinSliderMin.x + MouseDragOffset.x;
RangeMinSliderMin.x = GSClamp(BarBounds.Min.x, NewSliderX, RangeMaxSliderMin.x - SliderBarDim.x);
}
if (PointIsInRange(Mouse.DownPos, RangeMaxSliderMin, RangeMaxSliderMin + SliderBarDim))
{
r32 NewSliderX = RangeMaxSliderMin.x + MouseDragOffset.x;
RangeMaxSliderMin.x = GSClamp(RangeMinSliderMin.x + SliderBarDim.x, NewSliderX, BarBounds.Max.x - SliderBarDim.x);
}
}
v2 RangeMinSliderMax = v2{RangeMinSliderMin.x + 25, BarBounds.Max.y};
v2 RangeMaxSliderMax = v2{RangeMaxSliderMin.x + 25, BarBounds.Max.y};
PushRenderQuad2D(RenderBuffer, RangeMinSliderMin, RangeMinSliderMax, v4{.8f, .8f, .8f, 1.f});
PushRenderQuad2D(RenderBuffer, RangeMaxSliderMin, RangeMaxSliderMax, v4{.8f, .8f, .8f, 1.f});
// Convert Pixels Back To Frames and store
VisibleMinPercentPlayable = (RangeMinSliderMin.x - BarBounds.Min.x) / BarWidth;
VisibleMaxPercentPlayable = (RangeMaxSliderMax.x - BarBounds.Min.x) / BarWidth;
u32 VisibleFrameCount = GetFrameCount(AnimationSystem->PlayableRange);
Result.Min = VisibleMinPercentPlayable * VisibleFrameCount;
Result.Max = VisibleMaxPercentPlayable * VisibleFrameCount;
if (MouseButtonTransitionedUp(Mouse.LeftButtonState))
{
TimelineState->VisibleRange = Result;
}
return Result;
}
#define LAYER_HEIGHT 52
internal void
DrawLayerMenu(animation_system* AnimationSystem, rect PanelDim, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse)
{
v2 LayerDim = { gs_Width(PanelDim), LAYER_HEIGHT };
v2 LayerListMin = PanelDim.Min + v2{0, 24};
for (u32 LayerIndex = 0; LayerIndex < AnimationSystem->LayersCount; LayerIndex++)
{
anim_layer* Layer = AnimationSystem->Layers + LayerIndex;
rect LayerBounds = {0};
LayerBounds.Min = { LayerListMin.x, LayerListMin.y + (LayerDim.y * LayerIndex) };
LayerBounds.Max = LayerBounds.Min + LayerDim;
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) &&
gs_PointIsInRect(Mouse.Pos, LayerBounds))
{
State->SelectedAnimationLayer = LayerIndex;
}
v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16};
if (State->SelectedAnimationLayer == LayerIndex)
{
PushRenderBoundingBox2D(RenderBuffer, gs_RectExpand(LayerBounds), 1, WhiteV4);
}
DrawString(RenderBuffer, Layer->Name, State->Interface.Font, LayerTextPos, WhiteV4);
}
}
internal rect
DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range VisibleFrames, rect TimelineBounds, render_command_buffer* RenderBuffer)
{
rect BlockBounds = {};
r32 TimelineWidth = gs_Width(TimelineBounds);
u32 ClampedBlockStartFrame = ClampFrameToRange(AnimationBlock.Range.Min, VisibleFrames);
r32 StartFramePercent = FrameToPercentRange(ClampedBlockStartFrame, VisibleFrames);
r32 StartPosition = TimelineWidth * StartFramePercent;
u32 ClampedBlockEndFrame = ClampFrameToRange(AnimationBlock.Range.Max, VisibleFrames);
r32 EndFramePercent = FrameToPercentRange(ClampedBlockEndFrame, VisibleFrames);
r32 EndPosition = TimelineWidth * EndFramePercent;
r32 LayerYOffset = LAYER_HEIGHT * AnimationBlock.Layer;
BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, LayerYOffset};
BlockBounds.Max = TimelineBounds.Min + v2{EndPosition, LayerYOffset + LAYER_HEIGHT};
PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor);
PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4);
return BlockBounds;
}
internal gs_list_handle
DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect PanelBounds, gs_list_handle SelectedBlockHandle, ui_interface* Interface, app_state* State)
{
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
gs_list_handle Result = SelectedBlockHandle;
rect LayerMenuBounds, TimelineBounds;
gs_VSplitRectAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds);
// In Top To Bottom Order
rect TimelineFrameBarBounds, TimelineBlockDisplayBounds, TimelineRangeBarBounds;
gs_HSplitRectAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds);
gs_HSplitRectAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds);
// TODO(Peter): Clean Up
DrawLayerMenu(AnimationSystem, LayerMenuBounds, Interface->RenderBuffer, State, Interface->Mouse);
frame_range AdjustedViewRange = {0};
// TODO(Peter): Clean Up
AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, TimelineState, Interface->RenderBuffer, TimelineRangeBarBounds, Interface->Mouse);
s32 VisibleFrameCount = AdjustedViewRange.Max - AdjustedViewRange.Min;
// TODO(Peter): Clean Up
DrawFrameBar(AnimationSystem, Interface->RenderBuffer, AdjustedViewRange, TimelineFrameBarBounds, Interface->Mouse, State);
ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f});
// Animation Blocks
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
gs_list_handle DragBlockHandle = {0};
for (u32 i = 0; i < AnimationSystem->Blocks.Used; i++)
{
gs_list_entry<animation_block>* AnimationBlockEntry = AnimationSystem->Blocks.GetEntryAtIndex(i);
if (EntryIsFree(AnimationBlockEntry)) { continue; }
gs_list_handle CurrentBlockHandle = AnimationBlockEntry->Handle;
animation_block AnimationBlockAt = AnimationBlockEntry->Value;
// If either end is in the range, we should draw it
b32 RangeIsVisible = (FrameIsInRange(AnimationBlockAt.Range.Min, AdjustedViewRange) ||
FrameIsInRange(AnimationBlockAt.Range.Max, AdjustedViewRange));
// If neither end is in the range, but the ends surround the visible range,
// we should still draw it.
RangeIsVisible |= (AnimationBlockAt.Range.Min <= AdjustedViewRange.Min &&
AnimationBlockAt.Range.Max>= AdjustedViewRange.Max);
if (RangeIsVisible)
{
v4 BlockColor = BlackV4;
if (GSListHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
{
BlockColor = PinkV4;
}
// TODO(Peter): Clean Up
rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer);
if (gs_PointIsInRect(Interface->Mouse.Pos, BlockBounds))
{
DragBlockHandle = CurrentBlockHandle;
}
}
}
if (MouseDownAndNotHandled && ListHandleIsValid(DragBlockHandle))
{
MouseDownAndNotHandled = false;
// TODO(Peter): Why are we passing state around?
SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State);
}
// Time Slider
if (FrameIsInRange(AnimationSystem->CurrentFrame, AdjustedViewRange))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange);
r32 SliderX = GSLerp(TimelineBounds.Min.x, TimelineBounds.Max.x, FrameAtPercentVisibleRange);
rect SliderBounds = {
v2{ SliderX, TimelineBounds.Min.y },
v2{ SliderX + 1, TimelineBounds.Max.y }
};
ui_FillRect(Interface, SliderBounds, TimeSliderColor);
}
ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4);
ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4);
ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4);
if (MouseDownAndNotHandled && gs_PointIsInRect(Interface->Mouse.Pos, TimelineBounds))
{
DeselectCurrentAnimationBlock(State);
}
return Result;
}
struct animation_clip
{
char* Name;
s32 NameLength;
animation_proc* Proc;
};
s32 GlobalAnimationClipsCount = 3;
animation_clip GlobalAnimationClips[] = {
{ "Test Pattern One", 16, TestPatternOne },
{ "Test Pattern Two", 16, TestPatternTwo },
{ "Test Pattern Three", 18, TestPatternThree },
};
internal void
DrawAnimationClipsList(rect PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayer, animation_system* AnimationSystem)
{
ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds);
for (s32 i = 0; i < GlobalAnimationClipsCount; i++)
{
animation_clip Clip = GlobalAnimationClips[i];
string ClipName = MakeString(Clip.Name, Clip.NameLength);
if (ui_LayoutListEntry(Interface, &Layout, ClipName, i))
{
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayer, AnimationSystem);
}
}
// TODO(Peter): Fill up the rest of the area with empty list entries
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
animation_timeline_state* TimelineState = (animation_timeline_state*)Panel.PanelStateMemory;
gs_list_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
ui_interface* Interface = &State->Interface_;
animation_system* AnimationSystem = &State->AnimationSystem;
rect TitleBarBounds, PanelContentsBounds;
gs_HSplitRectAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds);
rect AnimationListBounds, TimelineBounds;
gs_VSplitRectAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds);
ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]);
ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds);
ui_StartRow(&TitleBarLayout, 3);
{
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Pause")))
{
State->AnimationSystem.TimelineShouldAdvance = true;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Play")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Stop")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
State->AnimationSystem.CurrentFrame = 0;
}
}
ui_EndRow(&TitleBarLayout);
if (gs_Height(TimelineBounds) > 0)
{
SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State);
DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem);
}
}
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
#endif // FOLDHAUS_PANEL_ANIMATION_TIMELINE_H

View File

@ -1,56 +0,0 @@
//
// File: foldhaus_panel_file_view.h
// Author: Peter Slattery
// Creation Date: 2020-03-08
//
#ifndef FOLDHAUS_PANEL_FILE_VIEW_H
struct file_view_state
{
string WorkingDirectory;
};
input_command* FileView_Commands = 0;
s32 FileView_CommandsCount = 0;
GSMetaTag(panel_init);
GSMetaTag(panel_type_file_view);
internal void
FileView_Init(panel* Panel, app_state* State)
{
// TODO: :FreePanelMemory
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
FileViewState->WorkingDirectory = MakeString(PushArray(&State->Permanent, char, 256), 256);
PrintF(&FileViewState->WorkingDirectory, "C:\\");
Panel->PanelStateMemory = (u8*)FileViewState;
}
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, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
rect HeaderBounds = {0};
HeaderBounds.Min = {PanelBounds.Min.x, PanelBounds.Max.y - 32};
HeaderBounds.Max = PanelBounds.Max;
rect ListBounds = {0};
ListBounds.Min = PanelBounds.Min;
ListBounds.Max = gs_BottomRight(HeaderBounds);
PushRenderQuad2D(RenderBuffer, gs_RectExpand(HeaderBounds), PinkV4);
PushRenderQuad2D(RenderBuffer, gs_RectExpand(ListBounds), RedV4);
}
#define FOLDHAUS_PANEL_FILE_VIEW_H
#endif // FOLDHAUS_PANEL_FILE_VIEW_H

View File

@ -1,87 +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)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Cleanup(panel* Panel, app_state* State)
{
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
ui_layout Layout = ui_CreateLayout(State->Interface_, PanelBounds);
v4 ListItemHover = State->Interface_.Style.ListBGHover;
v4 ListItemSelected = State->Interface_.Style.ListBGSelected;
string TempString = MakeString(PushArray(&State->Transient, char, 256), 0, 256);
u32 LineCount = (u32)(gs_Height(PanelBounds) / Layout.RowHeight) + 1;
u32 LinesDrawn = 0;
u32 AssembliesToDraw = GSMin(LineCount, State->ActiveAssemblyIndecies.Used);
for (; LinesDrawn < AssembliesToDraw; LinesDrawn++)
{
rect Bounds = ui_ReserveElementBounds(&Layout);
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn);
ui_FillRect(&State->Interface_, Bounds, ListItemBGColor);
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(LinesDrawn);
assembly Assembly = *State->AssemblyList.GetElementWithHandle(AssemblyHandle);
PrintF(&TempString, "%S", Assembly.Name);
ui_layout ItemLayout = ui_CreateLayout(State->Interface_, Bounds);
ui_StartRow(&ItemLayout, 2);
{
ui_LayoutDrawString(&State->Interface_, &ItemLayout, TempString, State->Interface_.Style.TextColor);
if (ui_LayoutButton(&State->Interface_, &ItemLayout, MakeStringLiteral("X"), ListItemBGColor, ListItemHover, ListItemSelected))
{
UnloadAssembly(AssemblyHandle.Index, State, Context);
}
}
ui_EndRow(&ItemLayout);
}
if (LinesDrawn < LineCount)
{
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn++);
PrintF(&TempString, "+ Add Assembly");
if (ui_LayoutButton(&State->Interface_, &Layout, TempString, ListItemBGColor, ListItemHover, ListItemSelected))
{
char FilePath[256];
b32 Success = Context.PlatformGetFilePath(FilePath, 256, "Foldhaus Files\0*.fold\0\0");
if (Success)
{
LoadAssembly(State, Context, FilePath);
}
}
for (; LinesDrawn < LineCount; LinesDrawn++)
{
rect Bounds = ui_ReserveElementBounds(&Layout);
ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn);
ui_FillRect(&State->Interface_, Bounds, ListItemBGColor);
}
}
}
#define FOLDHAUS_PANEL_HIERARCHY_H
#endif // FOLDHAUS_PANEL_HIERARCHY_H

View File

@ -1,184 +0,0 @@
//
// File: foldhaus_panel_sculpture_view.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H
// 3D Mouse View
OPERATION_STATE_DEF(mouse_rotate_view_operation_state)
{
v4 CameraStartPos;
};
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 = GetXRotation(-TotalDeltaPos.y * State->PixelsToWorldScale);
m44 YRotation = GetYRotation(TotalDeltaPos.x * State->PixelsToWorldScale);
m44 Combined = XRotation * YRotation;
State->Camera.Position = V3(Combined * OpState->CameraStartPos);
}
FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate)
{
DeactivateCurrentOperationMode(&State->Modes);
}
input_command MouseRotateViewCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate},
};
FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
{
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 = V4(State->Camera.Position, 1);
}
// ----------------
GSMetaTag(panel_commands);
GSMetaTag(panel_type_sculpture_view);
global_variable input_command SculptureView_Commands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate },
};
global_variable s32 SculptureView_CommandsCount = 1;
GSMetaTag(panel_init);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Init(panel* Panel, app_state* State)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Cleanup(panel* Panel, app_state* State)
{
}
struct draw_leds_job_data
{
led* LEDs;
pixel* Colors;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
m44 FaceCameraMatrix;
m44 ModelViewMatrix;
r32 LEDHalfWidth;
};
internal void
DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
{
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData;
s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex;
quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2);
s32 TrisUsed = 0;
r32 HalfWidth = Data->LEDHalfWidth;
v4 P0_In = v4{-HalfWidth, -HalfWidth, 0, 1};
v4 P1_In = v4{HalfWidth, -HalfWidth, 0, 1};
v4 P2_In = v4{HalfWidth, HalfWidth, 0, 1};
v4 P3_In = v4{-HalfWidth, HalfWidth, 0, 1};
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
led* LED = Data->LEDs + Data->StartIndex;
for (s32 LEDIdx = 0;
LEDIdx < LEDCount;
LEDIdx++)
{
pixel PixelColor = Data->Colors[LED->Index];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 V4Position = LED->Position;
V4Position.w = 0;
v4 P0 = P0_In + V4Position;
v4 P1 = P1_In + V4Position;
v4 P2 = P2_In + V4Position;
v4 P3 = P3_In + V4Position;
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
LED++;
}
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
DEBUG_TRACK_SCOPE(RenderSculpture);
r32 PanelWidth = PanelBounds.Max.x - PanelBounds.Min.x;
r32 PanelHeight = PanelBounds.Max.y - PanelBounds.Min.y;
State->Camera.AspectRatio = PanelWidth / PanelHeight;
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
m44 ProjectionMatrix = GetCameraPerspectiveProjectionMatrix(State->Camera);
r32 LEDHalfWidth = .5f;
PushRenderPerspective(RenderBuffer, PanelBounds.Min.x, PanelBounds.Min.y, PanelWidth, PanelHeight, State->Camera);
// TODO(Peter): Pretty sure this isn't working right now
m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1));
FaceCameraMatrix = FaceCameraMatrix;
u32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount);
for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i);
assembly Assembly = *State->AssemblyList.GetElementWithHandle(AssemblyHandle);
u32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDBuffer.LEDCount, MaxLEDsPerJob);
for (u32 Job = 0; Job < JobsNeeded; Job++)
{
draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data);
JobData->LEDs = Assembly.LEDBuffer.LEDs;
JobData->Colors = Assembly.LEDBuffer.Colors;
JobData->StartIndex = Job * MaxLEDsPerJob;
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDBuffer.LEDCount);
JobData->Batch = &RenderLEDsBatch;
JobData->FaceCameraMatrix;
JobData->ModelViewMatrix = ModelViewMatrix;
JobData->LEDHalfWidth = LEDHalfWidth;
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, DrawLEDsInBufferRangeJob, JobData, "Sculpture Draw LEDS");
}
}
Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0);
}
#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H
#endif // FOLDHAUS_PANEL_SCULPTURE_VIEW_H

View File

@ -67,7 +67,7 @@ gsosx_CreateWindow(NSApplication* App, int Width, int Height, id Title)
[App setMainMenu: MenuBar]; [App setMainMenu: MenuBar];
NSMenu* AppMenu = [NSMenu alloc]; NSMenu* AppMenu = [NSMenu alloc];
id QuitTitle = [@"Quit " stringByAppendingString: Title]; id QuitTitle = [@"Quit " gs_stringByAppendinggs_string: Title];
id QuitMenuItem = [[NSMenuItem alloc] initWithTitle: QuitTitle action: @selector(terminate:) keyEquivalent: @"q"]; id QuitMenuItem = [[NSMenuItem alloc] initWithTitle: QuitTitle action: @selector(terminate:) keyEquivalent: @"q"];
[AppMenu addItem: QuitMenuItem]; [AppMenu addItem: QuitMenuItem];
[AppMenuItem setSubmenu: AppMenu]; [AppMenuItem setSubmenu: AppMenu];

View File

@ -11,19 +11,23 @@
#include <windowsx.h> #include <windowsx.h>
#include <gl/gl.h> #include <gl/gl.h>
#include "../meta/gs_meta_include.h" #include "../../meta/gs_meta_include.h"
#include "foldhaus_platform.h" #include "../foldhaus_platform.h"
#include "../gs_libs/gs_win32.cpp" #include "../../gs_libs/gs_win32.cpp"
#include "win32_foldhaus_utils.h"
#include "win32_foldhaus_memory.h" #include "win32_foldhaus_memory.h"
#include "win32_foldhaus_fileio.h" #include "win32_foldhaus_fileio.h"
#include "win32_foldhaus_dll.h" #include "win32_foldhaus_dll.h"
#include "win32_foldhaus_timing.h" #include "win32_foldhaus_timing.h"
#include "win32_foldhaus_work_queue.h"
#include "win32_foldhaus_serial.h"
#include "win32_foldhaus_socket.h"
#include "foldhaus_renderer.cpp" #include "../foldhaus_renderer.cpp"
global_variable b32 Running = false; global b32 Running = false;
global_variable b32 WindowIsActive = false; global b32 WindowIsActive = false;
char DLLName[] = "foldhaus.dll"; char DLLName[] = "foldhaus.dll";
char WorkingDLLName[] = "foldhaus_temp.dll"; char WorkingDLLName[] = "foldhaus_temp.dll";
@ -31,224 +35,12 @@ char DLLLockFileName[] = "lock.tmp";
window MainWindow; window MainWindow;
struct worker_thread_entry
{
b32 IsValid;
u32 Index;
};
struct worker_thread_info
{
s32 ID;
HANDLE Handle;
work_queue* Queue;
};
PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue)
{
#ifdef 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)
{
string DebugString = MakeString((char*)malloc(256), 256);
for (u32 i = 0; i < Queue->JobsCount; i++)
{
PrintF(&DebugString, "%d %s\n", i, Queue->Jobs[i].JobName);
NullTerminate(&DebugString);
OutputDebugStringA(DebugString.Memory);
}
}
#endif
Assert(Queue->JobsCount < Queue->JobsMax);
worker_thread_job* Job = Queue->Jobs + Queue->JobsCount;
Job->WorkProc = WorkProc;
Job->Data = Data;
#ifdef 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(work_queue* Queue, worker_thread_entry Completed)
{
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;
}
DO_QUEUE_WORK_UNTIL_DONE(Win32DoQueueWorkUntilDone)
{
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (Queue->JobsCompleted < Queue->JobsCount)
{
Entry = CompleteAndTakeNextJob(Queue, Entry);
if (Entry.IsValid)
{
Queue->Jobs[Entry.Index].WorkProc(ThreadID, Queue->Jobs[Entry.Index].Data);
}
}
}
DWORD WINAPI
WorkerThreadProc (LPVOID InputThreadInfo)
{
worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo;
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (true)
{
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry);
if (Entry.IsValid)
{
ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ID,
ThreadInfo->Queue->Jobs[Entry.Index].Data);
}
else
{
WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0);
}
}
return 0;
}
PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle) PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle)
{ {
s32 Handle = SubmitTexture(Memory, Width, Height); s32 Handle = SubmitTexture(Memory, Width, Height);
return Handle; return Handle;
} }
struct win32_socket
{
SOCKET Socket;
};
#define SOCKET_DICTIONARY_GROW_SIZE 32
s32 Win32SocketHandleMax;
s32 Win32SocketHandleCount;
win32_socket* SocketValues;
PLATFORM_SET_SOCKET_OPTION(Win32SetSocketOption)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
int Error = setsockopt(SocketValues[SocketIndex].Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
// NOTE(Peter): These used to be passed in as paramters, but we only use this function
// with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values
// so I was having to include windows.h in the platform agnostic code to accomodate that
// function signature.
s32 AddressFamily = AF_INET;
s32 Type = SOCK_DGRAM;
s32 Protocol = 0;
if (Win32SocketHandleCount >= Win32SocketHandleMax)
{
s32 NewDictionaryMax = Win32SocketHandleMax + SOCKET_DICTIONARY_GROW_SIZE;
s32 NewDictionaryDataSize = NewDictionaryMax * sizeof(win32_socket);
u8* DictionaryMemory = Win32Alloc(NewDictionaryDataSize);
Assert(DictionaryMemory);
win32_socket* NewValues = (win32_socket*)(DictionaryMemory);
if (SocketValues)
{
GSMemCopy(SocketValues, NewValues, sizeof(win32_socket) * NewDictionaryMax);
Win32Free((u8*)SocketValues, sizeof(win32_socket) * Win32SocketHandleCount);
}
SocketValues = NewValues;
Win32SocketHandleMax = NewDictionaryMax;
}
Assert(Win32SocketHandleCount < Win32SocketHandleMax);
s32 NewSocketIndex = Win32SocketHandleCount++;
SocketValues[NewSocketIndex].Socket = socket(AddressFamily, Type, Protocol);
int Error = Win32SetSocketOption(NewSocketIndex, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
return (platform_socket_handle)NewSocketIndex;
}
PLATFORM_SEND_TO(Win32SendTo)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(SocketValues[SocketIndex].Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
if (Error == 10051)
{
}
else
{
// TODO(Peter): :ErrorLogging
InvalidCodePath;
}
}
return LengthSent;
}
PLATFORM_CLOSE_SOCKET(Win32CloseSocket)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
closesocket(SocketValues[SocketIndex].Socket);
}
HDC FontDrawingDC; HDC FontDrawingDC;
HBITMAP FontBitmap; HBITMAP FontBitmap;
HFONT CurrentFont; HFONT CurrentFont;
@ -512,7 +304,7 @@ internal void
DebugPrint (char* Format, ...) DebugPrint (char* Format, ...)
{ {
char Buffer[256]; char Buffer[256];
string StringBuffer = MakeString(Buffer, 256); gs_string StringBuffer = MakeString(Buffer, 256);
va_list Args; va_list Args;
va_start(Args, Format); va_start(Args, Format);
PrintF(&StringBuffer, Format, Args); PrintF(&StringBuffer, Format, Args);
@ -521,7 +313,7 @@ DebugPrint (char* Format, ...)
} }
internal void internal void
SetApplicationLinks (context* Context, win32_dll_refresh DLL, work_queue* WorkQueue) SetApplicationLinks (context* Context, win32_dll_refresh DLL, gs_work_queue* WorkQueue)
{ {
if (DLL.IsValid) if (DLL.IsValid)
{ {
@ -539,27 +331,22 @@ SetApplicationLinks (context* Context, win32_dll_refresh DLL, work_queue* WorkQu
} }
} }
// TODO(Peter): :Redundant remove
internal u8* internal u8*
DEBUGAlloc(s32 ElementSize, s32 ElementCount) DEBUGAlloc(s32 ElementSize, s32 ElementCount)
{ {
return Win32Alloc(ElementSize * ElementCount); return (u8*)Win32Alloc(ElementSize * ElementCount, 0);
} }
// TODO(Peter): :Redundant remove
internal u8* internal u8*
Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize) Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize)
{ {
u8* NewMemory = Win32Alloc(NewSize); u8* NewMemory = (u8*)Win32Alloc(NewSize, 0);
GSMemCopy(Buf, NewMemory, OldSize); CopyMemoryTo(Buf, NewMemory, OldSize);
return NewMemory; return NewMemory;
} }
internal s32
Win32GetThreadId()
{
s32 Result = GetCurrentThreadId();
return Result;
}
// NOTE(Peter): Only meant to take one of the values specified below: // 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_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_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE,
@ -577,6 +364,65 @@ Win32LoadSystemCursor(char* CursorIdentifier)
return Result; return Result;
} }
internal void
Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData)
{
DEBUG_TRACK_FUNCTION;
u32 BuffersSent = 0;
for (addressed_data_buffer* BufferAt = OutputData.Root;
BufferAt != 0;
BufferAt = BufferAt->Next)
{
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);
if (SerialPort != INVALID_HANDLE_VALUE)
{
if (Win32SerialPort_Write(SerialPort, BufferAt->Data))
{
BuffersSent += 1;
}
}
}
else
{
OutputDebugStringA("Skipping data buffer because its COM Port isn't set");
}
}break;
InvalidDefaultCase;
}
}
gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256);
PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent);
NullTerminate(&OutputStr);
OutputDebugStringA(OutputStr.Str);
}
internal void
Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg)
{
addressed_data_buffer_list* OutputData = (addressed_data_buffer_list*)Arg.Memory;
Win32_SendAddressedDataBuffers(Context, *OutputData);
}
int WINAPI int WINAPI
WinMain ( WinMain (
HINSTANCE HInstance, HINSTANCE HInstance,
@ -585,6 +431,36 @@ WinMain (
INT NCmdShow INT NCmdShow
) )
{ {
gs_thread_context ThreadContext = Win32CreateThreadContext();
#if 0
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
MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents);
Win32UpdateWindowDimension(&MainWindow); Win32UpdateWindowDimension(&MainWindow);
@ -594,12 +470,23 @@ WinMain (
OpenGLWindowInfo.DepthBits = 0; OpenGLWindowInfo.DepthBits = 0;
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow); CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
s32 InitialMemorySize = MB(64);
u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0);
context Context = {};
Context.ThreadContext = ThreadContext;
Context.MemorySize = InitialMemorySize;
Context.MemoryBase = InitialMemory;
Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
Context.Mouse = {0};
gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator);
s64 PerformanceCountFrequency = GetPerformanceFrequency(); s64 PerformanceCountFrequency = GetPerformanceFrequency();
s64 LastFrameEnd = GetWallClock(); s64 LastFrameEnd = GetWallClock();
r32 TargetSecondsPerFrame = 1 / 60.0f; r32 TargetSecondsPerFrame = 1 / 60.0f;
r32 LastFrameSecondsElapsed = 0.0f; r32 LastFrameSecondsElapsed = 0.0f;
GlobalDebugServices = (debug_services*)malloc(sizeof(debug_services)); GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services);
s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1; s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1;
InitDebugServices(GlobalDebugServices, InitDebugServices(GlobalDebugServices,
PerformanceCountFrequency, PerformanceCountFrequency,
@ -612,7 +499,7 @@ WinMain (
input_queue InputQueue; input_queue InputQueue;
{ {
s32 InputQueueMemorySize = sizeof(input_entry) * 32; s32 InputQueueMemorySize = sizeof(input_entry) * 32;
u8* InputQueueMemory = Win32Alloc(InputQueueMemorySize); u8* InputQueueMemory = (u8*)Win32Alloc(InputQueueMemorySize, 0);
InputQueue = InitializeInputQueue(InputQueueMemory, InputQueueMemorySize); InputQueue = InitializeInputQueue(InputQueueMemory, InputQueueMemorySize);
} }
@ -622,36 +509,27 @@ WinMain (
worker_thread_info* WorkerThreads = 0; worker_thread_info* WorkerThreads = 0;
if (PLATFORM_THREAD_COUNT > 0) if (PLATFORM_THREAD_COUNT > 0)
{ {
WorkerThreads = (worker_thread_info*)malloc(sizeof(worker_thread_info) * PLATFORM_THREAD_COUNT); WorkerThreads = PushArray(&PlatformPermanent, worker_thread_info, PLATFORM_THREAD_COUNT);
} }
work_queue WorkQueue = {}; HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
WorkQueue.SemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
gs_work_queue WorkQueue = {};
WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle;
WorkQueue.JobsMax = 512; WorkQueue.JobsMax = 512;
WorkQueue.Jobs = (worker_thread_job*)Win32Alloc(sizeof(worker_thread_job) * WorkQueue.JobsMax); WorkQueue.Jobs = PushArray(&PlatformPermanent, gs_threaded_job, WorkQueue.JobsMax);
WorkQueue.NextJobIndex = 0; WorkQueue.NextJobIndex = 0;
WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue; WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue;
WorkQueue.DoQueueWorkUntilDone = Win32DoQueueWorkUntilDone; WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone;
WorkQueue.ResetWorkQueue = ResetWorkQueue; WorkQueue.ResetWorkQueue = ResetWorkQueue;
OutputDebugStringA("Hellooooo\n");
for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++) for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++)
{ {
// ID = 0 is reserved for this thread // ID = 0 is reserved for this thread
WorkerThreads[i].ID = i + 1;
WorkerThreads[i].Queue = &WorkQueue; WorkerThreads[i].Queue = &WorkQueue;
WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0); WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0);
} }
s32 InitialMemorySize = Megabytes(64);
u8* InitialMemory = Win32Alloc(InitialMemorySize);
context Context = {};
Context.MemorySize = InitialMemorySize;
Context.MemoryBase = InitialMemory;
Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
Context.Mouse = {0};
// Cursors // Cursors
HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW); HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND); HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND);
@ -663,17 +541,8 @@ WinMain (
// Platform functions // Platform functions
Context.GeneralWorkQueue = &WorkQueue; Context.GeneralWorkQueue = &WorkQueue;
Context.PlatformAlloc = Win32Alloc;
Context.PlatformFree = Win32Free;
Context.PlatformRealloc = Win32Realloc;
Context.PlatformReadEntireFile = Win32ReadEntireFile;
Context.PlatformWriteEntireFile = Win32WriteEntireFile;
Context.PlatformGetFilePath = Win32SystemDialogueOpenFile;
Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle; Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle;
Context.PlatformGetSocketHandle = Win32GetSocketHandle; Context.PlatformGetSocketHandle = Win32GetSocketHandle;
Context.PlatformSetSocketOption = Win32SetSocketOption;
Context.PlatformSendTo = Win32SendTo;
Context.PlatformCloseSocket = Win32CloseSocket;
Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformGetFontInfo = Win32GetFontInfo;
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
@ -691,11 +560,18 @@ WinMain (
WSADATA WSAData; WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData); WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
s32 RenderMemorySize = Megabytes(12); Win32SerialArray_Create(ThreadContext);
u8* RenderMemory = Win32Alloc(RenderMemorySize);
s32 RenderMemorySize = MB(12);
u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize);
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc); render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc);
addressed_data_buffer_list OutputData = {};
OutputData.Arena = AllocatorAllocStruct(Context.ThreadContext.Allocator, gs_memory_arena);
*OutputData.Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
Context.InitializeApplication(Context); Context.InitializeApplication(Context);
Running = true; Running = true;
@ -715,6 +591,8 @@ WinMain (
Context.ReloadStaticData(Context, GlobalDebugServices); Context.ReloadStaticData(Context, GlobalDebugServices);
} }
AddressedDataBufferList_Clear(&OutputData);
{ // Mouse Position { // Mouse Position
POINT MousePos; POINT MousePos;
GetCursorPos (&MousePos); GetCursorPos (&MousePos);
@ -733,16 +611,24 @@ WinMain (
HandleWindowMessage(Message, &MainWindow, &InputQueue, &Context.Mouse); HandleWindowMessage(Message, &MainWindow, &InputQueue, &Context.Mouse);
} }
Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
RenderBuffer.ViewWidth = MainWindow.Width; RenderBuffer.ViewWidth = MainWindow.Width;
RenderBuffer.ViewHeight = MainWindow.Height; RenderBuffer.ViewHeight = MainWindow.Height;
Context.DeltaTime = LastFrameSecondsElapsed; Context.DeltaTime = LastFrameSecondsElapsed;
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer); Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData);
RenderCommandBuffer(RenderBuffer); RenderCommandBuffer(RenderBuffer);
ClearRenderBuffer(&RenderBuffer); ClearRenderBuffer(&RenderBuffer);
if (true)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)&OutputData;
ProcArg.Size = sizeof(OutputData);
Win32PushWorkOnQueue(&WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data"));
}
Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState); Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState);
Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState); Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState);
Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState); Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState);
@ -784,6 +670,8 @@ WinMain (
SwapBuffers(DeviceContext); SwapBuffers(DeviceContext);
ReleaseDC(MainWindow.Handle, DeviceContext); ReleaseDC(MainWindow.Handle, DeviceContext);
//Win32DoQueueWorkUntilDone(&WorkQueue, Context.ThreadContext);
s64 FinishedWorkTime = GetWallClock(); s64 FinishedWorkTime = GetWallClock();
r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency); r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency);
@ -801,6 +689,11 @@ WinMain (
Context.CleanupApplication(Context); Context.CleanupApplication(Context);
for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++)
{
Win32Socket_Close(Win32Sockets.Values + SocketIdx);
}
s32 CleanupResult = 0; s32 CleanupResult = 0;
do { do {
CleanupResult = WSACleanup(); CleanupResult = WSACleanup();

View File

@ -22,15 +22,15 @@ struct win32_dll_refresh
}; };
internal int internal int
Win32DLLStringLength(char* String) Win32DLLgs_stringLength(char* gs_string)
{ {
char* At = String; char* At = gs_string;
while (*At) { At++; }; while (*At) { At++; };
return At - String; return At - gs_string;
} }
internal int internal int
Win32DLLConcatStrings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest) Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest)
{ {
char* Dst = Dest; char* Dst = Dest;
char* AAt = A; char* AAt = A;
@ -112,14 +112,14 @@ InitializeDLLHotReloading(char* SourceDLLName,
ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
GetApplicationPath(&ExePath); GetApplicationPath(&ExePath);
Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLStringLength(SourceDLLName), SourceDLLName, Win32DLLgs_stringLength(SourceDLLName), SourceDLLName,
MAX_PATH, Result.SourceDLLPath); MAX_PATH, Result.SourceDLLPath);
Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLStringLength(WorkingDLLFileName), WorkingDLLFileName, Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName,
MAX_PATH, Result.WorkingDLLPath); MAX_PATH, Result.WorkingDLLPath);
Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLStringLength(LockFileName), LockFileName, Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath); MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength); Win32Free((u8*)ExePath.Path, ExePath.PathLength);

View File

@ -0,0 +1,254 @@
//
// 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);
}
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);
// 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 + 1);
PrintF(&FileName, "%S%.*s", SearchPath, FileName.Size, FindFileData.cFileName);
NullTerminate(&FileName);
Info->FileSize = Win32HighLowToU64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh);
Info->CreationTime = Win32FileTimeToU64(FindFileData.ftCreationTime);
Info->LastWriteTime = Win32FileTimeToU64(FindFileData.ftLastWriteTime);
Info->Path = FileName.ConstString;
Info->IsDirectory = HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
}
internal u32
Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list* TempList, gs_const_string Path, gs_memory_arena* Storage, b32 Flags)
{
u32 FilesCount = 0;
u32 IndexOfLastSlash = FindLastFromSet(Path, "\\/");
gs_const_string SearchPath = Substring(Path, 0, IndexOfLastSlash + 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))
{
if (HasFlag(Flags, EnumerateDirectory_Recurse))
{
gs_const_string SubDirName = ConstString(FindFileData.cFileName);
if (!StringsEqual(SubDirName, ConstString(".")) &&
!StringsEqual(SubDirName, ConstString("..")))
{
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, SearchPath, 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

@ -8,36 +8,28 @@
// //
#ifndef WIN32_FOLDHAUS_MEMORY_H #ifndef WIN32_FOLDHAUS_MEMORY_H
PLATFORM_ALLOC(Win32Alloc) ALLOCATOR_ALLOC(Win32Alloc)
{ {
u8* Result = (u8*)VirtualAlloc(NULL, Size, u8* Result = (u8*)VirtualAlloc(NULL, Size,
MEM_COMMIT | MEM_RESERVE, MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE); PAGE_EXECUTE_READWRITE);
if (ResultSize != 0)
{
*ResultSize = Size;
}
return Result; return Result;
} }
PLATFORM_FREE(Win32Free) ALLOCATOR_FREE(Win32Free)
{ {
b32 Result = VirtualFree(Base, 0, MEM_RELEASE); b32 Result = VirtualFree(Ptr, 0, MEM_RELEASE);
if (!Result) if (!Result)
{ {
s32 Error = WSAGetLastError(); s32 Error = GetLastError();
// TODO(Peter): I'm waiting to see an error actually occur here // TODO(Peter): I'm waiting to see an error actually occur here
// to know what it could possibly be. // to know what it could possibly be.
InvalidCodePath; InvalidCodePath;
} }
return Result;
}
PLATFORM_REALLOC(Win32Realloc)
{
u8* NewMemory = Win32Alloc(NewSize);
if (Base)
{
GSMemCopy(Base, NewMemory, OldSize);
Win32Free(Base, OldSize);
}
return NewMemory;
} }
#define WIN32_FOLDHAUS_MEMORY_H #define WIN32_FOLDHAUS_MEMORY_H

View File

@ -0,0 +1,243 @@
//
// File: win32_serial.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef WIN32_SERIAL_H
global u32 Win32SerialHandlesCountMax;
global u32 Win32SerialHandlesCount;
global HANDLE* Win32SerialHandles;
global gs_string* Win32SerialPortNames;
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);
}
HANDLE
Win32SerialPort_Open(char* PortName)
{
DEBUG_TRACK_FUNCTION;
HANDLE 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);
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
if (SetCommTimeouts(ComPortHandle, &Timeouts))
{
}
else
{
s32 Error = GetLastError();
// TODO(pjs): Error logging
}
}
else
{
// Error
s32 Error = GetLastError();
// TODO(pjs): Error logging
}
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)
{
OutputDebugString("Error: Entire buffer not written.\n");
}
}
else
{
OutputDebugStringA("Error: Unable to write to port\n");
s32 Error = GetLastError();
//InvalidCodePath;
}
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_thread_context Context)
{
DEBUG_TRACK_FUNCTION;
Win32SerialHandlesCountMax = 32;
Win32SerialHandlesCount = 0;
Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
Win32SerialPortNames[i] = AllocatorAllocString(Context.Allocator, 256);
}
}
void
Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax);
u32 Index = Win32SerialHandlesCount++;
Win32SerialHandles[Index] = SerialHandle;
PrintF(&Win32SerialPortNames[Index], "%S", PortName);
}
HANDLE
Win32SerialArray_Get(gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCount; i++)
{
if (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)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = Win32SerialArray_Get(PortName);
if (PortHandle == INVALID_HANDLE_VALUE)
{
Assert(IsNullTerminated(PortName));
PortHandle = Win32SerialPort_Open(PortName.Str);
if (PortHandle != INVALID_HANDLE_VALUE)
{
Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits);
Win32SerialArray_Push(PortHandle, PortName);
}
}
return PortHandle;
}
#define WIN32_SERIAL_H
#endif // WIN32_SERIAL_H

View File

@ -0,0 +1,140 @@
//
// 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;
};
//////////////////////
//
// 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 Socket System
global win32_socket_array Win32Sockets;
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);
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
// NOTE(Peter): These used to be passed in as paramters, but we only use this function
// with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values
// so I was having to include windows.h in the platform agnostic code to accomodate that
// function signature.
s32 AddressFamily = AF_INET;
s32 Type = SOCK_DGRAM;
s32 Protocol = 0;
s32 Result = Win32SocketArray_Take(&Win32Sockets);
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result);
Socket->Socket = socket(AddressFamily, Type, Protocol);
if (Socket->Socket != INVALID_SOCKET)
{
int Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
}
else
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
return (platform_socket_handle)Result;
}
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();
if (Error == 10051)
{
}
else
{
// TODO(Peter): :ErrorLogging
InvalidCodePath;
}
}
return LengthSent;
}
internal void
Win32Socket_Close(win32_socket* Socket)
{
closesocket(Socket->Socket);
Socket->Socket = INVALID_SOCKET;
}
#define WIN32_FOLDHAUS_SOCKET_H
#endif // WIN32_FOLDHAUS_SOCKET_H

View File

@ -0,0 +1,75 @@
//
// 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)
{
Assert(IsNullTerminated(Message));
OutputDebugStringA(Message.Str);
}
#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();
PrintF(&DebugString, "%s Line %d: Win32 Error %d\n\0", File, Line, Error);
OutputDebugStringA(DebugString.Str);
}
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

@ -0,0 +1,155 @@
//
// 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;
};
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 = CreateAllocator(Win32Alloc, Win32Free);
if (Transient != 0)
{
Result.Transient = Transient;
}
else
{
Result.Transient = (gs_memory_arena*)AllocatorAlloc(Result.Allocator, sizeof(gs_memory_arena)).Memory;
*Result.Transient = CreateMemoryArena(Result.Allocator);
}
Result.FileHandler = CreateFileHandler(Win32GetFileInfo,
Win32ReadEntireFile,
Win32WriteEntireFile,
Win32EnumerateDirectory,
Result.Transient);
return Result;
}
PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue)
{
#ifdef 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++)
{
PrintF(&DebugString, "%d %s\n", i, Queue->Jobs[i].JobName);
NullTerminate(&DebugString);
OutputDebugStringA(DebugString.Str);
}
}
#endif
Assert(Queue->JobsCount < Queue->JobsMax);
gs_threaded_job* Job = Queue->Jobs + Queue->JobsCount;
Job->WorkProc = WorkProc;
Job->Data = Data;
#ifdef 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)
{
ClearArena(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;
}
#define WIN32_FOLDHAUS_WORK_QUEUE_H
#endif // WIN32_FOLDHAUS_WORK_QUEUE_H

View File

@ -18,19 +18,17 @@ struct solid_color_data
GSMetaTag(node_proc); // :TagParamsForNodeParamStructs GSMetaTag(node_proc); // :TagParamsForNodeParamStructs
void SolidColorProc(solid_color_data* Data) void SolidColorProc(solid_color_data* Data)
{ {
u8 R = (u8)GSClamp(0.f, (Data->Color.r * 255), 255.f); u8 R = (u8)Clamp(0.f, (Data->Color.r * 255), 255.f);
u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f); u8 G = (u8)Clamp(0.f, (Data->Color.g * 255), 255.f);
u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f); u8 B = (u8)Clamp(0.f, (Data->Color.b * 255), 255.f);
led* LED = Data->Result.LEDs; for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++)
for (s32 l = 0; l < Data->Result.LEDCount; l++)
{ {
Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount);
Data->Result.Colors[LED->Index].R = R; Data->Result.Colors[LedIndex].R = R;
Data->Result.Colors[LED->Index].G = G; Data->Result.Colors[LedIndex].G = G;
Data->Result.Colors[LED->Index].B = B; Data->Result.Colors[LedIndex].B = B;
LED++;
} }
} }
@ -59,18 +57,18 @@ void VerticalColorFadeProc(vertical_color_fade_data* Data)
r32 Range = Data->Max - Data->Min; r32 Range = Data->Max - Data->Min;
led* LED = Data->Result.LEDs;
for (s32 l = 0; l < Data->Result.LEDCount; l++) for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++)
{ {
Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount);
v4 LedPosition = Data->Result.LedPositions[LedIndex];
r32 Amount = (LED->Position.y - Data->Min) / Range; r32 Amount = (LedPosition.y - Data->Min) / Range;
Amount = GSClamp01(1.0f - Amount); Amount = Clamp01(1.0f - Amount);
Data->Result.Colors[LED->Index].R = (u8)(R * Amount); Data->Result.Colors[LedIndex].R = (u8)(R * Amount);
Data->Result.Colors[LED->Index].G = (u8)(G * Amount); Data->Result.Colors[LedIndex].G = (u8)(G * Amount);
Data->Result.Colors[LED->Index].B = (u8)(B * Amount); Data->Result.Colors[LedIndex].B = (u8)(B * Amount);
LED++;
} }
} }
@ -109,14 +107,14 @@ void RevolvingDiscs(revolving_discs_data* Data)
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
pixel Color = { pixel Color = {
(u8)(GSClamp01(Data->Color.r) * 255), (u8)(Clamp01(Data->Color.r) * 255),
(u8)(GSClamp01(Data->Color.g) * 255), (u8)(Clamp01(Data->Color.g) * 255),
(u8)(GSClamp01(Data->Color.b) * 255), (u8)(Clamp01(Data->Color.b) * 255),
}; };
v4 Center = v4{0, 0, 0, 1}; v4 Center = v4{0, 0, 0, 1};
v4 Normal = v4{GSCos(Data->ThetaZ), 0, GSSin(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 v4 Normal = v4{CosR32(Data->ThetaZ), 0, SinR32(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
v4 Right = Cross(Normal, v4{0, 1, 0, 0}); v4 Right = V4Cross(Normal, v4{0, 1, 0, 0});
v4 FrontCenter = Center + (Normal * Data->DiscWidth); v4 FrontCenter = Center + (Normal * Data->DiscWidth);
v4 BackCenter = Center - (Normal * Data->DiscWidth); v4 BackCenter = Center - (Normal * Data->DiscWidth);
@ -124,29 +122,27 @@ void RevolvingDiscs(revolving_discs_data* Data)
r32 OuterRadiusSquared = Data->OuterRadius * Data->OuterRadius; r32 OuterRadiusSquared = Data->OuterRadius * Data->OuterRadius;
r32 InnerRadiusSquared = Data->InnerRadius * Data->InnerRadius; r32 InnerRadiusSquared = Data->InnerRadius * Data->InnerRadius;
led* LED = Data->Result.LEDs; for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++)
for (s32 l = 0; l < Data->Result.LEDCount; l++)
{ {
v4 Position = LED->Position; v4 Position = Data->Result.LedPositions[LedIndex];
v4 ToFront = Position + FrontCenter; v4 ToFront = Position + FrontCenter;
v4 ToBack = Position + BackCenter; v4 ToBack = Position + BackCenter;
r32 ToFrontDotNormal = Dot(ToFront, Normal); r32 ToFrontDotNormal = V4Dot(ToFront, Normal);
r32 ToBackDotNormal = Dot(ToBack, Normal); r32 ToBackDotNormal = V4Dot(ToBack, Normal);
ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000); ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000);
ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000); ToBackDotNormal = Clamp01(ToBackDotNormal * 1000);
r32 SqDistToCenter = MagSqr(Position); r32 SqDistToCenter = V4MagSquared(Position);
if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared)
{ {
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
{ {
Data->Result.Colors[LED->Index] = Color; Data->Result.Colors[LedIndex] = Color;
} }
} }
LED++;
} }
} }

View File

@ -1,146 +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
PLATFORM_READ_ENTIRE_FILE(Win32ReadEntireFile)
{
platform_memory_result Result = {};
Result.Error = PlatformMemory_NoError;
HANDLE FileHandle = CreateFileA (Path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD FileSize = GetFileSize(FileHandle, NULL);
Result.Base = (u8*)VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (Result.Base)
{
Result.Size = FileSize;
s32 BytesRead = 0;
if (ReadFile(FileHandle, (LPVOID)Result.Base, FileSize, (LPDWORD)(&BytesRead), NULL))
{
}
else
{
u32 Error = GetLastError();
// TODO(Peter): :ErrorLogging
Result.Size = 0;
Result.Error = PlatformMemory_UnknownError;
}
}
CloseHandle(FileHandle);
}
else
{
Result.Error = PlatformMemory_FileNotFound;
// TODO(Peter): :ErrorLogging
}
return Result;
}
PLATFORM_WRITE_ENTIRE_FILE(Win32WriteEntireFile)
{
b32 Result = false;
HANDLE FileHandle = CreateFileA (
Path,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten = 0;
b32 WriteSuccess = WriteFile(FileHandle,
Contents, Size,
&BytesWritten,
NULL);
if (WriteSuccess && BytesWritten == (u32)Size)
{
CloseHandle(FileHandle);
Result = true;
}
else
{
Result = false;
}
}
else
{
Result = false;
}
return Result;
}
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;
}
PLATFORM_GET_FILE_PATH(Win32SystemDialogueOpenFile)
{
b32 Result = false;
PathBuffer[0] = 0;
OPENFILENAMEA OpenFileName = {};
OpenFileName.lStructSize = sizeof(OpenFileName);
OpenFileName.hwndOwner = NULL;
OpenFileName.lpstrFilter = FilterStrings;
OpenFileName.lpstrCustomFilter = NULL; // NOTE(Peter): for preserving last filter string chosen
OpenFileName.nMaxCustFilter = 0; // NOTE(Peter): ignored since we left CustomFilter null
OpenFileName.nFilterIndex = 1;
OpenFileName.lpstrFile = PathBuffer;
OpenFileName.nMaxFile = BufferLength;
OpenFileName.lpstrFileTitle = NULL;
OpenFileName.nMaxFileTitle = 0; // NOTE(Peter): Ignored since fileTitle is null
OpenFileName.lpstrInitialDir = NULL;
OpenFileName.lpstrTitle = NULL;
OpenFileName.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST;
OpenFileName.lpstrDefExt = NULL;
Result = GetOpenFileNameA (&OpenFileName);
return Result;
}
internal directory_listing
EnumerateDirectory(char* Path, memory_arena* Storage)
{
directory_listing Result = {};
// TODO(Peter):
return Result;
}
#define WIN32_FOLDHAUS_FILEIO_H
#endif // WIN32_FOLDHAUS_FILEIO_H

View File

@ -1,5 +1,6 @@
#ifndef GS_LANGUAGE_H #ifndef GS_LANGUAGE_H
#if 0
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__)
#include <intrin.h> #include <intrin.h>
@ -42,6 +43,8 @@ typedef long long int s64;
typedef float r32; typedef float r32;
typedef double r64; typedef double r64;
#endif
#ifndef _STDINT #ifndef _STDINT
#define INT8_MIN (-128) #define INT8_MIN (-128)
@ -124,7 +127,7 @@ Test(b32 Result, char* Description, s32* Count)
#define DEBUG_TRACK_SCOPE(a) #define DEBUG_TRACK_SCOPE(a)
#endif // DEBUG_TRACK_SCOPE #endif // DEBUG_TRACK_SCOPE
#ifndef DEBUG_TRACK_FUNCTION #ifndef DEBUG_TRACK_FUNCTION
// #define DEBUG_TRACK_FUNCTION #define DEBUG_TRACK_FUNCTION
#endif // DEBUG_TRACK_FUNCTION #endif // DEBUG_TRACK_FUNCTION
#endif // GS_LANGUAGE_NO_PROFILER_DEFINES #endif // GS_LANGUAGE_NO_PROFILER_DEFINES

View File

@ -167,21 +167,6 @@ if((expression)) { \
#define GSMem_Assert(expression) #define GSMem_Assert(expression)
#endif #endif
struct data
{
u8* Memory;
u64 Size;
};
typedef data allocator_alloc(u64 Size);
typedef void allocator_free(u8* Base, u64 Size);
struct base_allocator
{
allocator_alloc* Alloc;
allocator_free* Free;
};
enum gs_memory_expansion_rule enum gs_memory_expansion_rule
{ {
MemoryExpansion_Allowed, // Zero is initialization lets the memory grow on its own MemoryExpansion_Allowed, // Zero is initialization lets the memory grow on its own
@ -207,9 +192,21 @@ enum gs_memory_find_address_rule
FindAddress_Count, FindAddress_Count,
}; };
typedef void* gs_memory_alloc(gs_mem_u32 Size); #define PLATFORM_ALLOC(name) u8* name(s32 Size)
typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize); typedef PLATFORM_ALLOC(platform_alloc);
typedef void gs_memory_free(void* Address, gs_mem_u32 Size);
#define PLATFORM_FREE(name) b32 name(u8* Base, s32 Size)
typedef PLATFORM_FREE(platform_free);
#define PLATFORM_REALLOC(name) u8* name(u8* Base, u32 OldSize, u32 NewSize)
typedef PLATFORM_REALLOC(platform_realloc);
struct platform_memory_handler
{
platform_alloc* Alloc;
platform_free* Free;
platform_realloc* Realloc;
};
#ifndef GS_MEMORY_BUFFER_SIZE #ifndef GS_MEMORY_BUFFER_SIZE
#define GS_MEMORY_BUFFER_SIZE 1024 #define GS_MEMORY_BUFFER_SIZE 1024
@ -244,8 +241,6 @@ struct memory_buffer
struct memory_arena struct memory_arena
{ {
base_allocator Allocator;
memory_buffer* Buffers; memory_buffer* Buffers;
gs_mem_u32 BuffersCount; gs_mem_u32 BuffersCount;
@ -254,8 +249,8 @@ struct memory_arena
gs_memory_find_address_rule FindAddressRule; gs_memory_find_address_rule FindAddressRule;
gs_memory_expansion_rule ExpansionRule; gs_memory_expansion_rule ExpansionRule;
gs_memory_alloc* Alloc;
gs_memory_realloc* Realloc; platform_memory_handler PlatformMemory;
#ifdef GS_MEMORY_TRACK_ALLOCATIONS #ifdef GS_MEMORY_TRACK_ALLOCATIONS
tracked_allocation_buffer** AllocationBuffers; tracked_allocation_buffer** AllocationBuffers;
@ -283,59 +278,64 @@ struct arena_snapshot
#endif #endif
}; };
#define AllocatorAllocArray(alloc,type,count) (type*)(AllocatorAlloc((alloc), sizeof(type) * (count)).Memory) #define PlatformFreeArray(platform, base, type, count) PlatformFree((platform), (gs_mem_u8*)(base), sizeof(type) * (count))
#define AllocatorAllocStruct(alloc,type) (type*)(AllocatorAlloc((alloc), sizeof(type)).Memory) #define ArenaFree(arena, base, size) PlatformFree((arena).PlatformMemory, (gs_mem_u8*)(base), (gs_mem_u32)(size))
static data
AllocatorAlloc(base_allocator Allocator, gs_mem_u64 Size)
{
return Allocator.Alloc(Size);
}
static void static void
AllocatorFree(base_allocator Allocator, gs_mem_u8* Base, gs_mem_u64 Size) PlatformFree(platform_memory_handler Platform, gs_mem_u8* Base, gs_mem_u32 Size)
{ {
Allocator.Free(Base, Size); Assert(Platform.Free != 0);
Platform.Free(Base, Size);
} }
static memory_arena #define PlatformAllocArray(platform, type, size) (type*)PlatformAlloc((platform), sizeof(type) * (size))
CreateMemoryArena(base_allocator Allocator) #define ArenaAlloc(arena, size) PlatformAlloc((arena).PlatformMemory, (gs_mem_u32)(size))
#define ArenaAllocStruct(arena, type) (type*)PlatformAlloc((arena).PlatformMemory, sizeof(type))
#define ArenaAllocArray(arena, type, size) (type*)PlatformAlloc((arena).PlatformMemory, sizeof(type) * (size))
static gs_mem_u8*
PlatformAlloc(platform_memory_handler Platform, gs_mem_u32 Size)
{ {
memory_arena Result = {0}; Assert(Platform.Alloc != 0);
Result.Allocator = Allocator; gs_mem_u8* Result = Platform.Alloc(Size);
Result.ExpansionRule = MemoryExpansion_Allowed; return Result;
Result.FindAddressRule = FindAddress_InLastBufferOnly; }
#define ArenaRealloc(arena, base, oldSize, newSize) PlatformRealloc((arena).PlatformMemory, (gs_mem_u8*)(base), (gs_mem_u32)(oldSize), (gs_mem_u32)(newSize))
#define ArenaReallocArray(arena, base, type, oldCount, newCount) (type*)PlatformRealloc((arena).PlatformMemory, (gs_mem_u8*)(base), sizeof(type) * oldCount, sizeof(type) * newCount)
static gs_mem_u8*
PlatformRealloc(platform_memory_handler Platform, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize)
{
gs_mem_u8* Result = 0;
if (Platform.Realloc != 0)
{
Result = Platform.Realloc(Head, OldSize, NewSize);
}
else if (Platform.Alloc != 0 && Platform.Free != 0)
{
Result = PlatformAlloc(Platform, NewSize);
if (Head != 0 && OldSize != 0)
{
CopyMemoryTo(Head, Result, OldSize);
PlatformFree(Platform, Head, OldSize);
}
}
else
{
InvalidCodePath;
}
return Result; return Result;
} }
static void static void
FreeMemoryArena(memory_arena* Arena, gs_memory_free* Free = 0) FreeMemoryArena(memory_arena* Arena)
{ {
if (Free) for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{ {
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++) memory_buffer* Buffer = Arena->Buffers + i;
{ PlatformFree(Arena->PlatformMemory, Buffer->Buffer, Buffer->Size);
memory_buffer* Buffer = Arena->Buffers + i;
Free(Buffer->Buffer, Buffer->Size);
}
Free(Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount);
}
else
{
#ifdef GS_MEMORY_NO_STD_LIBS
GSMem_Assert(0);
#else
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{
memory_buffer* Buffer = Arena->Buffers + i;
free(Buffer->Buffer);
}
free(Arena->Buffers);
#endif
} }
PlatformFree(Arena->PlatformMemory, (u8*)Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount);
} }
#define IsPowerOfTwo(v) ((v != 0) && ((v & (v - 1)) == 0))
inline gs_mem_u32 inline gs_mem_u32
GetAlignmentOffset (gs_mem_u64 Address, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask) GetAlignmentOffset (gs_mem_u64 Address, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
{ {
@ -385,51 +385,17 @@ FindAlignedAddressInBufferWithRoom(memory_arena* Arena, gs_mem_u32 Size, gs_mem_
return Result; return Result;
} }
static gs_mem_u8*
ArenaAlloc(memory_arena* Arena, gs_mem_u32 Size)
{
gs_mem_u8* Result = 0;
data Data = AllocatorAlloc(Arena->Allocator, Size);
Result = Data.Memory;
return Result;
}
static gs_mem_u8*
ArenaRealloc(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize)
{
gs_mem_u8* Result = 0;
GSMem_Assert(Arena->Allocator.Alloc);
GSMem_Assert(Arena->Allocator.Free);
data Data = AllocatorAlloc(Arena->Allocator, NewSize);
for (gs_mem_u64 i = 0; i < (gs_mem_u64)OldSize; i++)
{
Data.Memory[i] = Head[i];
}
if (Head != 0)
{
AllocatorFree(Arena->Allocator, Head, OldSize);
}
Result = Data.Memory;
return Result;
}
static memory_buffer* static memory_buffer*
GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded) GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded)
{ {
GSMem_Assert(Arena->ExpansionRule != MemoryExpansion_Disallowed); GSMem_Assert(Arena->ExpansionRule != MemoryExpansion_Disallowed);
if (Arena->ExpansionRule == MemoryExpansion_OnlyIfFunctionsProvided)
{
GSMem_Assert((Arena->Allocator.Alloc != 0) && (Arena->Allocator.Free != 0));
}
gs_mem_u32 NewBuffersCount = (Arena->BuffersCount + 1); gs_mem_u32 NewBuffersCount = (Arena->BuffersCount + 1);
#if 0
gs_mem_u32 OldBuffersSize = sizeof(memory_buffer) * Arena->BuffersCount; gs_mem_u32 OldBuffersSize = sizeof(memory_buffer) * Arena->BuffersCount;
gs_mem_u32 NewBuffersSize = sizeof(memory_buffer) * NewBuffersCount; gs_mem_u32 NewBuffersSize = sizeof(memory_buffer) * NewBuffersCount;
Arena->Buffers = (memory_buffer*)ArenaRealloc(Arena, (gs_mem_u8*)Arena->Buffers, OldBuffersSize, NewBuffersSize); #endif
Arena->Buffers = ArenaReallocArray(*Arena, Arena->Buffers, memory_buffer, Arena->BuffersCount, NewBuffersCount);
Arena->BuffersCount = NewBuffersCount; Arena->BuffersCount = NewBuffersCount;
memory_buffer* NewBuffer = Arena->Buffers + (Arena->BuffersCount - 1); memory_buffer* NewBuffer = Arena->Buffers + (Arena->BuffersCount - 1);
@ -439,7 +405,7 @@ GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded)
NewBuffer->Size = SizeNeeded; NewBuffer->Size = SizeNeeded;
} }
NewBuffer->Buffer = ArenaAlloc(Arena, sizeof(gs_mem_u8) * NewBuffer->Size); NewBuffer->Buffer = ArenaAllocArray(*Arena, gs_mem_u8, NewBuffer->Size);
NewBuffer->Used = 0; NewBuffer->Used = 0;
Arena->TotalSize += NewBuffer->Size; Arena->TotalSize += NewBuffer->Size;
@ -460,14 +426,20 @@ TrackAllocation(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 Size, char* Fil
if (Arena->AllocationsUsed >= AllocationsMax) if (Arena->AllocationsUsed >= AllocationsMax)
{ {
gs_mem_u32 NewAllocationBuffersCount = Arena->AllocationBuffersCount + 1; gs_mem_u32 NewAllocationBuffersCount = Arena->AllocationBuffersCount + 1;
Arena->AllocationBuffers = (tracked_allocation_buffer**)ArenaRealloc(Arena, #if 0
(gs_mem_u8*)Arena->AllocationBuffers, gs_mem_u32 OldSize = Arena->AllocationBuffersCount * sizeof(void*);
Arena->AllocationBuffersCount * sizeof(void*), gs_mem_u32 NewSize = NewAllocationBuffersCount * sizeof(void*);
NewAllocationBuffersCount * sizeof(void*)); Arena->AllocationBuffers = (tracked_allocation_buffer**)PlatformRealloc(Arena->PlatformMemory,
(gs_mem_u8*)Arena->AllocationBuffers,
OldSize, NewSize);
#else
Arena->AllocationBuffers = ArenaReallocArray(*Arena, Arena->AllocationBuffers, tracked_allocation_buffer*, Arena->AllocationBuffersCount, NewAllocationBuffersCount);
#endif
Arena->AllocationBuffersCount = NewAllocationBuffersCount; Arena->AllocationBuffersCount = NewAllocationBuffersCount;
gs_mem_u32 NewBufferIndex = Arena->AllocationBuffersCount - 1; gs_mem_u32 NewBufferIndex = Arena->AllocationBuffersCount - 1;
Arena->AllocationBuffers[NewBufferIndex] = (tracked_allocation_buffer*)ArenaAlloc(Arena, sizeof(tracked_allocation_buffer)); Arena->AllocationBuffers[NewBufferIndex] = ArenaAllocStruct(*Arena, tracked_allocation_buffer);
} }
gs_mem_u32 AllocationIndex = Arena->AllocationsUsed++; gs_mem_u32 AllocationIndex = Arena->AllocationsUsed++;

View File

@ -10,31 +10,31 @@ TODO
#if !defined(GSRad_Assert) #if !defined(GSRad_Assert)
#define GSRad_Assert(expression) \ #define GSRad_Assert(expression) \
if(!(expression)) { \ if(!(expression)) { \
*((int *)0) = 5; \ *((int *)0) = 5; \
} }
#endif // !defined(GSRad_Assert) #endif // !defined(GSRad_Assert)
#endif // DEBUG #endif // DEBUG
typedef unsigned long long int gs_rad_u64; typedef unsigned int gs_rad_u32;
typedef unsigned int gs_rad_b32; typedef unsigned int gs_rad_b32;
struct gs_radix_entry struct gs_radix_entry
{ {
gs_rad_u64 Radix; gs_rad_u32 Radix;
gs_rad_u64 ID; gs_rad_u32 ID;
}; };
static void static void
RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u64 Start, gs_rad_u64 End, gs_rad_u64 Iteration) RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u32 Start, gs_rad_u32 End, gs_rad_u32 Iteration)
{ {
gs_rad_u64 Shift = Iteration; gs_rad_u32 Shift = Iteration;
gs_rad_u64 ZerosBoundary = Start; gs_rad_u32 ZerosBoundary = Start;
gs_rad_u64 OnesBoundary = End - 1; gs_rad_u32 OnesBoundary = End - 1;
for (gs_rad_u64 d = Start; d < End; d++) for (gs_rad_u32 d = Start; d < End; d++)
{ {
gs_radix_entry Entry = Data[ZerosBoundary]; gs_radix_entry Entry = Data[ZerosBoundary];
gs_rad_u64 Place = (Entry.Radix >> Shift) & 0x1; gs_rad_u32 Place = (Entry.Radix >> Shift) & 0x1;
if (Place) if (Place)
{ {
gs_radix_entry Evicted = Data[OnesBoundary]; gs_radix_entry Evicted = Data[OnesBoundary];
@ -56,10 +56,10 @@ RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u64 Start, gs_rad_u64 End, gs_ra
} }
static void static void
RadixSortInPlace (gs_radix_entry* Data, gs_rad_u64 Count) RadixSortInPlace (gs_radix_entry* Data, gs_rad_u32 Count)
{ {
gs_rad_u64 Highest = 0; gs_rad_u32 Highest = 0;
for (gs_rad_u64 i = 0; i < Count; i++) for (gs_rad_u32 i = 0; i < Count; i++)
{ {
if (Data[i].Radix > Highest) if (Data[i].Radix > Highest)
{ {
@ -67,7 +67,7 @@ RadixSortInPlace (gs_radix_entry* Data, gs_rad_u64 Count)
} }
} }
gs_rad_u64 Iterations = 0; gs_rad_u32 Iterations = 0;
while (Highest > 1) while (Highest > 1)
{ {
++Iterations; ++Iterations;

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,7 @@ Write(string Text, string_builder* StringBuilder)
// Copy what there is room for // Copy what there is room for
s32 SpaceAvailable = StringBuilder->Head->String.Max - StringBuilder->Head->String.Length; s32 SpaceAvailable = StringBuilder->Head->String.Max - StringBuilder->Head->String.Length;
ConcatString(TextLeft, GSMin(SpaceAvailable, TextLeft.Length), &StringBuilder->Head->String); ConcatString(TextLeft, Min(SpaceAvailable, TextLeft.Length), &StringBuilder->Head->String);
TextLeft.Memory += SpaceAvailable; TextLeft.Memory += SpaceAvailable;
TextLeft.Length -= SpaceAvailable; TextLeft.Length -= SpaceAvailable;
@ -93,7 +93,7 @@ WriteStringBuilderToFile(string_builder StringBuilder, FILE* WriteFile)
while (BufferAt) while (BufferAt)
{ {
string String = BufferAt->String; string String = BufferAt->String;
fwrite(String.Memory, 1, String.Length, WriteFile); fwrite(String.Str, 1, String.Length, WriteFile);
BufferAt = BufferAt->Next; BufferAt = BufferAt->Next;
} }
} }

3403
src/gs_libs/gs_types.cpp Normal file

File diff suppressed because it is too large Load Diff

1054
src/gs_libs/gs_types.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -75,6 +75,18 @@ union v4
float a; float a;
}; };
struct
{
v2 xy;
v2 yz;
};
struct
{
v3 xyz;
float z;
};
float E[4]; float E[4];
}; };
@ -93,25 +105,12 @@ union v4
union m33 union m33
{ {
struct float E[3][3];
{
float a; float b; float c;
float d; float e; float f;
float g; float h; float i;
};
float E[9];
}; };
union m44 union m44
{ {
struct float E[4][4];
{
float a; float b; float c; float d;
float e; float f; float g; float h;
float i; float j; float k; float l;
float m; float n; float o; float p;
};
float E[16];
}; };
////////////////////////////////////// //////////////////////////////////////
@ -636,10 +635,10 @@ PointIsInRange (v2 _P, v2 _Min, v2 _Max)
static bool static bool
PointIsInRangeSafe (v2 _P, v2 _Min, v2 _Max) PointIsInRangeSafe (v2 _P, v2 _Min, v2 _Max)
{ {
s32 MinX = GSMin(_Min.x, _Max.x); s32 MinX = Min(_Min.x, _Max.x);
s32 MinY = GSMin(_Min.y, _Max.y); s32 MinY = Min(_Min.y, _Max.y);
s32 MaxX = GSMax(_Min.x, _Max.x); s32 MaxX = Max(_Min.x, _Max.x);
s32 MaxY = GSMax(_Min.y, _Max.y); s32 MaxY = Max(_Min.y, _Max.y);
return (_P.x >= MinX && _P.x <= MaxX && return (_P.x >= MinX && _P.x <= MaxX &&
_P.y >= MinY && _P.y <= MaxY); _P.y >= MinY && _P.y <= MaxY);
@ -1271,11 +1270,10 @@ GetLookAtMatrix (v4 Position, v4 Target)
v4 Up = Normalize(Cross(Forward, Right)); v4 Up = Normalize(Cross(Forward, Right));
m44 RotationMatrix = M44( m44 RotationMatrix = M44(
Right.x, Up.x, Forward.x, 0, Right.x, Right.y, Right.z, 0,
Right.y, Up.y, Forward.y, 0, Up.x, Up.y, Up.z, 0,
Right.z, Up.z, Forward.z, 0, Forward.x, Forward.y, Forward.z, 0,
0, 0, 0, 1); 0, 0, 0, 1);
return RotationMatrix; return RotationMatrix;
} }
@ -1427,11 +1425,11 @@ void TestVectorMatrixMultiplication ()
// Utility Functions // Utility Functions
TestClean((GSSqrt(4.f) == 2.f), "Vector Square Root"); TestClean((GSSqrt(4.f) == 2.f), "Vector Square Root");
TestClean((GSLerp(0.f, 1.f, .5f) == .5f), "Vector Lerp"); TestClean((Lerp(0.f, 1.f, .5f) == .5f), "Vector Lerp");
TestClean((GSMin(-.25f, 5.f) == -.25f), "Vector Min"); TestClean((Min(-.25f, 5.f) == -.25f), "Vector Min");
TestClean((GSMax(-.25f, 5.f) == 5.f), "Vector Max"); TestClean((Max(-.25f, 5.f) == 5.f), "Vector Max");
TestClean((GSClamp(-2.f, -3.f, 5.f) == -2.f), "Vector Clamp, Lower Than Range"); TestClean((Clamp(-2.f, -3.f, 5.f) == -2.f), "Vector Clamp, Lower Than Range");
TestClean((GSClamp(-2.f, 6.f, 5.f) == 5.f), "Vector Clamp, Higher Than Range"); TestClean((Clamp(-2.f, 6.f, 5.f) == 5.f), "Vector Clamp, Higher Than Range");
////////////////////////////// //////////////////////////////
// Vector Functions // Vector Functions

View File

@ -45,7 +45,7 @@ struct handle_window_msg_result
#endif #endif
}; };
global_variable win32_state GlobalWin32State; global win32_state GlobalWin32State;
// Utility // Utility
internal s32 Win32StringLength(char* String); internal s32 Win32StringLength(char* String);
@ -66,9 +66,8 @@ internal void Win32DisplayBufferInWindow(win32_offscreen_buffer* Buffer
// Memory // Memory
internal PLATFORM_ALLOC(Win32Alloc); internal ALLOCATOR_ALLOC(Win32Alloc);
internal PLATFORM_FREE(Win32Free); internal ALLOCATOR_FREE(Win32Free);
internal PLATFORM_REALLOC(Win32Realloc);
/// ///
// Utils // Utils

View File

@ -218,14 +218,14 @@ GeneratePanelMetaInfo(gs_meta_preprocessor Meta, string_builder* PanelEnumGen, s
} }
WriteF(PanelEnumGen, "enum panel_type {\n"); WriteF(PanelEnumGen, "enum panel_type {\n");
WriteF(PanelCodeGen, "global_variable s32 GlobalPanelDefsCount = %d;\n", Panels.Used); WriteF(PanelCodeGen, "global s32 GlobalPanelDefsCount = %d;\n", Panels.Used);
WriteF(PanelCodeGen, "global_variable panel_definition GlobalPanelDefs[] = {\n"); WriteF(PanelCodeGen, "global panel_definition GlobalPanelDefs[] = {\n");
for (u32 i = 0; i < Panels.Used; i++) for (u32 i = 0; i < Panels.Used; i++)
{ {
panel_elements* Panel = Panels.GetElementAtIndex(i); panel_elements* Panel = Panels.GetElementAtIndex(i);
string PanelIdentifier = {0}; string PanelIdentifier = {0};
PanelIdentifier.Max = Panel->PanelIdentifier.Length; PanelIdentifier.Max = Panel->PanelIdentifier.Length;
PanelIdentifier.Memory = PushArray(&Meta.Permanent, char, PanelIdentifier.Max); PanelIdentifier.Memory = (char*)malloc(sizeof(char) * PanelIdentifier.Max);
CopyStringTo(Substring(Panel->PanelIdentifier, 11), &PanelIdentifier); CopyStringTo(Substring(Panel->PanelIdentifier, 11), &PanelIdentifier);
MakeReadableIdentifier(&PanelIdentifier); MakeReadableIdentifier(&PanelIdentifier);
@ -259,11 +259,11 @@ GeneratePanelMetaInfo(gs_meta_preprocessor Meta, string_builder* PanelEnumGen, s
} }
internal string internal string
AllocAndConcatStrings(base_allocator Allocator, string First, string Second) AllocAndConcatStrings(string First, string Second)
{ {
string Result = {0}; string Result = {0};
Result.Max = First.Length + Second.Length + 1; Result.Max = First.Length + Second.Length + 1;
Result.Memory = AllocatorAllocArray(Allocator, char, Result.Max); Result.Memory = (char*)malloc(sizeof(char) * Result.Max);
ConcatString(First, &Result); ConcatString(First, &Result);
ConcatString(Second, &Result); ConcatString(Second, &Result);
NullTerminate(&Result); NullTerminate(&Result);
@ -271,26 +271,6 @@ AllocAndConcatStrings(base_allocator Allocator, string First, string Second)
return Result; return Result;
} }
u64 TotalAllocatedSpace = 0;
internal data
PlatformAlloc(u64 Size)
{
data Result = {0};
Result.Memory = (u8*)malloc(Size);
Result.Size = Size;
TotalAllocatedSpace += Size;
return Result;
}
internal void
PlatformFree(u8* Base, u64 Size)
{
free((void*)Base);
}
int main(int ArgCount, char* Args[]) int main(int ArgCount, char* Args[])
{ {
if (ArgCount <= 1) if (ArgCount <= 1)
@ -299,30 +279,22 @@ int main(int ArgCount, char* Args[])
return 0; return 0;
} }
base_allocator Allocator = {0};
Allocator.Alloc = (allocator_alloc*)PlatformAlloc;
Allocator.Free = (allocator_free*)PlatformFree;
GlobalDebugServices.Arena = CreateMemoryArena(Allocator);
GlobalDebugServices.Transient = CreateMemoryArena(Allocator);
GlobalDebugServices.ShouldProfile = true;
string RootFile = MakeString(Args[1]); string RootFile = MakeString(Args[1]);
s32 IndexOfLastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); s32 IndexOfLastSlash = ReverseSearchForCharInSet(RootFile, "\\/");
string WorkingDirectory = Substring(RootFile, 0, IndexOfLastSlash + 1); string WorkingDirectory = Substring(RootFile, 0, IndexOfLastSlash + 1);
string GeneratedDirectoryName = MakeStringLiteral("generated\\"); string GeneratedDirectoryName = MakeStringLiteral("generated\\");
string GeneratedFilesDirectory = AllocAndConcatStrings(Allocator, WorkingDirectory, GeneratedDirectoryName); string GeneratedFilesDirectory = AllocAndConcatStrings(WorkingDirectory, GeneratedDirectoryName);
printf("Putting Generated Files In %s\n", GeneratedFilesDirectory.Memory); printf("Putting Generated Files In %s\n", GeneratedFilesDirectory.Memory);
gs_meta_preprocessor Meta = PreprocessProgram(Allocator, Args[1]); gs_meta_preprocessor Meta = PreprocessProgram(Args[1]);
typeinfo_generator TypeGenerator = InitTypeInfoGenerator(&Meta.TypeTable); typeinfo_generator TypeGenerator = InitTypeInfoGenerator(Meta.TypeTable);
GenerateMetaTagList(Meta.TypeTable, &TypeGenerator); GenerateMetaTagList(Meta.TypeTable, &TypeGenerator);
GenerateFilteredTypeInfo(MakeStringLiteral("node_struct"), Meta.TypeTable, &TypeGenerator); GenerateFilteredTypeInfo(MakeStringLiteral("node_struct"), Meta.TypeTable, &TypeGenerator);
GenerateFilteredTypeInfo(MakeStringLiteral("gen_type_info"), Meta.TypeTable, &TypeGenerator); GenerateFilteredTypeInfo(MakeStringLiteral("gen_type_info"), Meta.TypeTable, &TypeGenerator);
FinishGeneratingTypes(&TypeGenerator); FinishGeneratingTypes(&TypeGenerator);
gsm_code_generator NodeTypeGen = BeginEnumGeneration(&Meta.TypeTable.Arena, "node_type", "NodeType", false, true); gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true);
string_builder NodeSpecificationGen = {0}; string_builder NodeSpecificationGen = {0};
string_builder CallNodeProcGen = {0}; string_builder CallNodeProcGen = {0};
GenerateNodeMetaInfo(&NodeTypeGen, &NodeSpecificationGen, &CallNodeProcGen, Meta); GenerateNodeMetaInfo(&NodeTypeGen, &NodeSpecificationGen, &CallNodeProcGen, Meta);
@ -331,7 +303,7 @@ int main(int ArgCount, char* Args[])
string_builder PanelCodeGen = {0}; string_builder PanelCodeGen = {0};
GeneratePanelMetaInfo(Meta, &PanelEnumGen, &PanelCodeGen); GeneratePanelMetaInfo(Meta, &PanelEnumGen, &PanelCodeGen);
string TypeInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("gs_meta_generated_typeinfo.h")); string TypeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("gs_meta_generated_typeinfo.h"));
FILE* TypeInfoH = fopen(TypeInfoHFilePath.Memory, "w"); FILE* TypeInfoH = fopen(TypeInfoHFilePath.Memory, "w");
if (TypeInfoH) if (TypeInfoH)
{ {
@ -347,7 +319,7 @@ int main(int ArgCount, char* Args[])
printf("Error: Unable to open file at %.*s\n", StringExpand(TypeInfoHFilePath)); printf("Error: Unable to open file at %.*s\n", StringExpand(TypeInfoHFilePath));
} }
string NodeInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("foldhaus_nodes_generated.h")); string NodeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_nodes_generated.h"));
FILE* NodeInfoH = fopen(NodeInfoHFilePath.Memory, "w"); FILE* NodeInfoH = fopen(NodeInfoHFilePath.Memory, "w");
if (NodeInfoH) if (NodeInfoH)
{ {
@ -361,7 +333,7 @@ int main(int ArgCount, char* Args[])
printf("Error: Unable to open file at %.*s\n", StringExpand(NodeInfoHFilePath)); printf("Error: Unable to open file at %.*s\n", StringExpand(NodeInfoHFilePath));
} }
string PanelInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("foldhaus_panels_generated.h")); string PanelInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_panels_generated.h"));
FILE* PanelInfoH = fopen(PanelInfoHFilePath.Memory, "w"); FILE* PanelInfoH = fopen(PanelInfoHFilePath.Memory, "w");
if (PanelInfoH) if (PanelInfoH)
{ {
@ -376,10 +348,6 @@ int main(int ArgCount, char* Args[])
FinishMetaprogram(&Meta); FinishMetaprogram(&Meta);
r64 AllocatedMegabytes = (r64)TotalAllocatedSpace / (1024 * 1024);
printf("Total Allocated Space: %lld bytes, or %f MB\n", TotalAllocatedSpace, AllocatedMegabytes);
//__debugbreak();
return 0; return 0;
} }

View File

@ -21,40 +21,40 @@
#include <stdio.h> #include <stdio.h>
#include "..\gs_libs\gs_language.h" #include "..\gs_libs\gs_language.h"
#include "..\gs_libs\gs_radix_sort.h"
#include "..\gs_libs\gs_bucket.h" #include "..\gs_libs\gs_bucket.h"
#include "..\gs_libs\gs_memory_arena.h" #include "..\gs_libs\gs_memory_arena.h"
#include "..\gs_libs\gs_profiler.h"
#include "..\gs_libs\gs_string.h" #include "..\gs_libs\gs_string.h"
global_variable u64 TokenHash_GSMetaTag = HashDJB2ToU64("GSMetaTag"); #include "gs_meta_lexer.h"
global_variable u64 TokenHash_OpenParen = HashDJB2ToU64("("); #include "gs_meta_error.h"
global_variable u64 TokenHash_CloseParen = HashDJB2ToU64(")");
global_variable u64 TokenHash_Semicolon = HashDJB2ToU64(";"); #include "gs_meta_type_table.h"
global_variable u64 TokenHash_Unsigned = HashDJB2ToU64("unsigned");
global_variable u64 TokenHash_Signed = HashDJB2ToU64("signed"); struct source_code_file
global_variable u64 TokenHash_Short = HashDJB2ToU64("short"); {
global_variable u64 TokenHash_Int = HashDJB2ToU64("int"); string Path;
global_variable u64 TokenHash_Long = HashDJB2ToU64("long"); s32 FileSize;
global_variable u64 TokenHash_Char = HashDJB2ToU64("char"); string Contents;
global_variable u64 TokenHash_WCharT = HashDJB2ToU64("wchar_t");
global_variable u64 TokenHash_Bool = HashDJB2ToU64("bool"); s32 FirstTokenIndex;
global_variable u64 TokenHash_Float = HashDJB2ToU64("float"); s32 LastTokenIndex;
global_variable u64 TokenHash_Double = HashDJB2ToU64("double"); };
global_variable u64 TokenHash_Star = HashDJB2ToU64("*");
global_variable u64 TokenHash_Volatile = HashDJB2ToU64("volatile"); struct token_iter
global_variable u64 TokenHash_Const = HashDJB2ToU64("const"); {
global_variable u64 TokenHash_OpenSquareBracket = HashDJB2ToU64("["); gs_bucket<token>* Tokens;
global_variable u64 TokenHash_CloseSquareBracket = HashDJB2ToU64("]"); token* TokenAt;
global_variable u64 TokenHash_Comma = HashDJB2ToU64(","); s32 TokenAtIndex;
global_variable u64 TokenHash_Struct = HashDJB2ToU64("struct"); s32 FirstToken;
global_variable u64 TokenHash_Union = HashDJB2ToU64("union"); s32 LastToken;
global_variable u64 TokenHash_OpenCurlyBracket = HashDJB2ToU64("{");
global_variable u64 TokenHash_CloseCurlyBracket = HashDJB2ToU64("}"); #define TOKEN_ITER_SNAPSHOTS_MAX 64
global_variable u64 TokenHash_Typedef = HashDJB2ToU64("typedef"); u32 SnapshotsUsed;
global_variable u64 TokenHash_Enum = HashDJB2ToU64("enum"); u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX];
global_variable u64 TokenHash_Equals = HashDJB2ToU64("=");
errors* Errors;
};
struct gsm_profiler_scope struct gsm_profiler_scope
{ {
@ -81,10 +81,31 @@ struct gsm_profiler
gs_bucket<gsm_profiler_category> Categories; gs_bucket<gsm_profiler_category> Categories;
}; };
struct gs_meta_preprocessor
{
errors Errors;
gs_bucket<source_code_file> SourceFiles;
gs_bucket<token> Tokens;
gs_bucket<type_table_handle> TagList;
type_table TypeTable;
// Performance
s64 PreprocessorStartTime;
s64 TokenizeTime;
s64 PreprocTime;
s64 FixupTime;
s64 PreprocessorEndTime;
gsm_profiler Profiler;
};
// ------------------------ // ------------------------
// Timing / Performance // Timing / Performance
// ------------------------ // ------------------------
#if 0
internal s64 internal s64
GetWallClock () GetWallClock ()
{ {
@ -98,7 +119,7 @@ GetWallClock ()
} }
return (s64)Time.QuadPart; return (s64)Time.QuadPart;
} }
#endif
internal s64 internal s64
GetPerformanceFrequency () GetPerformanceFrequency ()
{ {
@ -253,63 +274,6 @@ PrintAllCategories(gsm_profiler* Profiler)
} }
} }
#include "gs_meta_lexer.h"
#include "gs_meta_error.h"
#include "gs_meta_type_table.h"
struct token_array
{
token* List;
u32 Count;
};
struct source_code_file
{
string Path;
s32 FileSize;
string Contents;
token_array Tokens;
};
struct token_iter
{
token_array Tokens;
token* TokenAt;
u32 TokenAtIndex;
#define TOKEN_ITER_SNAPSHOTS_MAX 64
u32 SnapshotsUsed;
u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX];
errors* Errors;
};
struct gs_meta_preprocessor
{
memory_arena Permanent;
memory_arena Transient;
errors Errors;
gs_bucket<source_code_file> SourceFiles;
//gs_bucket<token> Tokens;
gs_bucket<type_table_handle> TagList;
type_table TypeTable;
// Performance
s64 PreprocessorStartTime;
s64 TokenizeTime;
s64 PreprocTime;
s64 FixupTime;
s64 PreprocessorEndTime;
gsm_profiler Profiler;
};
// ------------------------ // ------------------------
// Token Iterator // Token Iterator
// ------------------------ // ------------------------
@ -317,10 +281,10 @@ struct gs_meta_preprocessor
internal token* internal token*
NextToken (token_iter* Iter) NextToken (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION; if (Iter->TokenAtIndex < Iter->LastToken)
if (Iter->TokenAtIndex < Iter->Tokens.Count)
{ {
Iter->TokenAt = Iter->Tokens.List + Iter->TokenAtIndex++; Iter->TokenAtIndex++;
Iter->TokenAt = Iter->Tokens->GetElementAtIndex(Iter->TokenAtIndex);
} }
return Iter->TokenAt; return Iter->TokenAt;
@ -329,7 +293,6 @@ NextToken (token_iter* Iter)
internal b32 internal b32
TokenAtEquals(token_iter* Iter, char* String) TokenAtEquals(token_iter* Iter, char* String)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (StringEqualsCharArray(Iter->TokenAt->Text, String)) if (StringEqualsCharArray(Iter->TokenAt->Text, String))
{ {
@ -339,23 +302,9 @@ TokenAtEquals(token_iter* Iter, char* String)
return Result; return Result;
} }
internal b32
TokenAtHashEquals(token_iter* Iter, u64 Hash)
{
DEBUG_TRACK_FUNCTION;
b32 Result = false;
if (Hash == Iter->TokenAt->TextHash)
{
Result = true;
NextToken(Iter);
}
return Result;
}
internal b32 internal b32
TokenAtEquals(token_iter* Iter, token_type Type) TokenAtEquals(token_iter* Iter, token_type Type)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (Iter->TokenAt->Type == Type) if (Iter->TokenAt->Type == Type)
{ {
@ -368,7 +317,6 @@ TokenAtEquals(token_iter* Iter, token_type Type)
internal b32 internal b32
TokenAtEquals(token_iter* Iter, token_type Type, token* Token) TokenAtEquals(token_iter* Iter, token_type Type, token* Token)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (Iter->TokenAt->Type == Type) if (Iter->TokenAt->Type == Type)
{ {
@ -382,14 +330,12 @@ TokenAtEquals(token_iter* Iter, token_type Type, token* Token)
internal void internal void
PushSnapshot (token_iter* Iter) PushSnapshot (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
Iter->Snapshots[Iter->SnapshotsUsed++] = Iter->TokenAtIndex; Iter->Snapshots[Iter->SnapshotsUsed++] = Iter->TokenAtIndex;
} }
internal void internal void
PopSnapshot (token_iter* Iter) PopSnapshot (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
if (Iter->SnapshotsUsed > 0) if (Iter->SnapshotsUsed > 0)
{ {
Iter->SnapshotsUsed -= 1; Iter->SnapshotsUsed -= 1;
@ -399,17 +345,15 @@ PopSnapshot (token_iter* Iter)
internal void internal void
ApplySnapshot (token_iter* Iter) ApplySnapshot (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
u32 SnapshotIndex = Iter->SnapshotsUsed; u32 SnapshotIndex = Iter->SnapshotsUsed;
u32 SnapshotPoint = Iter->Snapshots[SnapshotIndex]; u32 SnapshotPoint = Iter->Snapshots[SnapshotIndex];
Iter->TokenAtIndex = SnapshotPoint; Iter->TokenAtIndex = SnapshotPoint;
Iter->TokenAt = Iter->Tokens.List + Iter->TokenAtIndex; Iter->TokenAt = Iter->Tokens->GetElementAtIndex(SnapshotPoint);
} }
internal void internal void
ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter) ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
PopSnapshot(Iter); PopSnapshot(Iter);
if (!ParseSuccess) if (!ParseSuccess)
{ {
@ -421,7 +365,6 @@ ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter)
internal s32 internal s32
GetFileSize (char* FileName) GetFileSize (char* FileName)
{ {
DEBUG_TRACK_FUNCTION;
s32 Result = 0; s32 Result = 0;
FILE* ReadFile = fopen(FileName, "r"); FILE* ReadFile = fopen(FileName, "r");
@ -443,9 +386,8 @@ GetFileSize (char* FileName)
// ------------------------- // -------------------------
internal s32 internal s32
ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, errors* Errors) ReadEntireFileAndNullTerminate (source_code_file* File, errors* Errors)
{ {
DEBUG_TRACK_FUNCTION;
s32 LengthRead = 0; s32 LengthRead = 0;
FILE* ReadFile = fopen(File->Path.Memory, "r"); FILE* ReadFile = fopen(File->Path.Memory, "r");
@ -457,7 +399,7 @@ ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, e
Assert(File->Contents.Memory == 0); Assert(File->Contents.Memory == 0);
File->Contents.Max = (s32)FileSize + 1; File->Contents.Max = (s32)FileSize + 1;
File->Contents.Memory = (char*)PushSize(Storage, File->Contents.Max); File->Contents.Memory = (char*)malloc(File->Contents.Max);
size_t ReadSize = fread(File->Contents.Memory, 1, FileSize, ReadFile); size_t ReadSize = fread(File->Contents.Memory, 1, FileSize, ReadFile);
File->Contents.Memory[FileSize] = 0; File->Contents.Memory[FileSize] = 0;
@ -473,7 +415,6 @@ ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, e
internal b32 internal b32
FileAlreadyInSource(string Path, gs_bucket<source_code_file> SourceFiles) FileAlreadyInSource(string Path, gs_bucket<source_code_file> SourceFiles)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
for (u32 i = 0; i < SourceFiles.Used; i++) for (u32 i = 0; i < SourceFiles.Used; i++)
@ -490,18 +431,19 @@ FileAlreadyInSource(string Path, gs_bucket<source_code_file> SourceFiles)
} }
internal void internal void
AddFileToSource(memory_arena* Storage, string RelativePath, source_code_file CurrentFile, gs_bucket<source_code_file>* SourceFiles, errors* Errors) AddFileToSource(string RelativePath, source_code_file CurrentFile, gs_bucket<source_code_file>* SourceFiles, errors* Errors)
{ {
DEBUG_TRACK_FUNCTION;
source_code_file File = {0}; source_code_file File = {0};
File.FirstTokenIndex = -1;
File.LastTokenIndex = -1;
u32 PathLength = RelativePath.Length + 1; u32 PathLength = RelativePath.Length + 1;
char* PathData = PushArray(Storage, char, PathLength); File.Path = MakeString((char*)malloc(sizeof(char) * PathLength), 0, PathLength);
File.Path = MakeString(PathData, 0, PathLength);
CopyStringTo(RelativePath, &File.Path); CopyStringTo(RelativePath, &File.Path);
NullTerminate(&File.Path); NullTerminate(&File.Path);
File.FileSize = ReadEntireFileAndNullTerminate(Storage, &File, Errors); File.FileSize = ReadEntireFileAndNullTerminate(&File, Errors);
if (File.FileSize > 0) if (File.FileSize > 0)
{ {
@ -518,21 +460,8 @@ AddFileToSource(memory_arena* Storage, string RelativePath, source_code_file Cur
} }
internal void internal void
TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File) TokenizeFile (source_code_file* File, gs_bucket<token>* Tokens)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* Scope = BeginScope(&Meta->Profiler, MakeStringLiteral("tokenize"), File->Path);
struct token_list
{
token Token;
token_list* Next;
};
u32 TokensCount = 0;
token_list* TokensHead = 0;
token_list* TokensTail = 0;
tokenizer Tokenizer = {}; tokenizer Tokenizer = {};
Tokenizer.At = File->Contents.Memory; Tokenizer.At = File->Contents.Memory;
Tokenizer.Memory = File->Contents.Memory; Tokenizer.Memory = File->Contents.Memory;
@ -541,35 +470,15 @@ TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File)
token* LastToken = 0; token* LastToken = 0;
while(AtValidPosition(Tokenizer)) while(AtValidPosition(Tokenizer))
{ {
token_list* NewToken = PushStruct(&Meta->Transient, token_list); token NewToken = GetNextToken(&Tokenizer);
NewToken->Token = GetNextToken(&Tokenizer); u32 TokenIndex = Tokens->PushElementOnBucket(NewToken);
NewToken->Next = 0; if (File->FirstTokenIndex < 0)
TokensCount++;
if (TokensHead != 0)
{ {
TokensTail->Next = NewToken; File->FirstTokenIndex = (s32)TokenIndex;
TokensTail = NewToken;
}
else
{
TokensHead = NewToken;
TokensTail = NewToken;
} }
} }
File->Tokens = {0}; File->LastTokenIndex = Tokens->Used - 1;
File->Tokens.Count = TokensCount;
File->Tokens.List = PushArray(&Meta->Permanent, token, File->Tokens.Count);
token_list* At = TokensHead;
for (u32 i = 0; i < TokensCount; i++)
{
Assert(At != 0);
File->Tokens.List[i] = At->Token;
At = At->Next;
}
EndScope(Scope);
} }
// ------------------------ // ------------------------
@ -579,21 +488,20 @@ TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File)
internal b32 internal b32
ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta) ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseMetaTag")); MakeStringLiteral("ParseMetaTag"));
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_GSMetaTag) && if (TokenAtEquals(Iter, "GSMetaTag") &&
TokenAtHashEquals(Iter, TokenHash_OpenParen)) TokenAtEquals(Iter, "("))
{ {
token MetaIdentifier = {0}; token MetaIdentifier = {0};
if (TokenAtEquals(Iter, Token_Identifier, &MetaIdentifier)) if (TokenAtEquals(Iter, Token_Identifier, &MetaIdentifier))
{ {
if (TokenAtHashEquals(Iter, TokenHash_OpenParen) && if (TokenAtEquals(Iter, ")") &&
TokenAtHashEquals(Iter, TokenHash_Semicolon)) TokenAtEquals(Iter, ";"))
{ {
Result = true; Result = true;
type_table_handle MetaTagHandle = GetMetaTagHandle(MetaIdentifier.Text, Meta->TypeTable); type_table_handle MetaTagHandle = GetMetaTagHandle(MetaIdentifier.Text, Meta->TypeTable);
@ -626,15 +534,14 @@ ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta)
internal b32 internal b32
ParseSignedness (token_iter* Iter) ParseSignedness (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
// NOTE(Peter): This doesn't really do much at the moment, but // NOTE(Peter): This doesn't really do much at the moment, but
// I want all signedness parsing to happen in one place in case // I want all signedness parsing to happen in one place in case
// we ever need to do anything with it. // we ever need to do anything with it.
b32 Result = false; b32 Result = false;
if (TokenAtHashEquals(Iter, TokenHash_Unsigned) || if (TokenAtEquals(Iter, "unsigned") ||
TokenAtHashEquals(Iter, TokenHash_Signed)) TokenAtEquals(Iter, "signed"))
{ {
Result = true; Result = true;
} }
@ -645,15 +552,14 @@ ParseSignedness (token_iter* Iter)
internal b32 internal b32
ShortInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) ShortInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
ParseSignedness(Iter); ParseSignedness(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Short)) if (TokenAtEquals(Iter, "short"))
{ {
Result = true; Result = true;
if (TokenAtHashEquals(Iter, TokenHash_Int)) if (TokenAtEquals(Iter, "int"))
{ {
Result = true; Result = true;
} }
@ -670,12 +576,11 @@ ShortInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab
internal b32 internal b32
Int (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) Int (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
ParseSignedness(Iter); ParseSignedness(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Int)) if (TokenAtEquals(Iter, "int"))
{ {
Result = true; Result = true;
} }
@ -691,15 +596,14 @@ Int (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
internal b32 internal b32
LongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) LongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
ParseSignedness(Iter); ParseSignedness(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Long)) if (TokenAtEquals(Iter, "long"))
{ {
Result = true; Result = true;
if (TokenAtHashEquals(Iter, TokenHash_Int)) if (TokenAtEquals(Iter, "int"))
{ {
Result = true; Result = true;
} }
@ -716,17 +620,16 @@ LongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTabl
internal b32 internal b32
LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
ParseSignedness(Iter); ParseSignedness(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Long)) if (TokenAtEquals(Iter, "long"))
{ {
if (TokenAtHashEquals(Iter, TokenHash_Long)) if (TokenAtEquals(Iter, "long"))
{ {
Result = true; Result = true;
if (TokenAtHashEquals(Iter, TokenHash_Int)) if (TokenAtEquals(Iter, "int"))
{ {
Result = true; Result = true;
} }
@ -744,17 +647,16 @@ LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table Type
internal b32 internal b32
ParseChar(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) ParseChar(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
ParseSignedness(Iter); ParseSignedness(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Char)) if (TokenAtEquals(Iter, "char"))
{ {
Result = true; Result = true;
*TypeHandleOut = GetTypeHandle(MakeStringLiteral("char"), TypeTable); *TypeHandleOut = GetTypeHandle(MakeStringLiteral("char"), TypeTable);
} }
else if (TokenAtHashEquals(Iter, TokenHash_WCharT)) else if (TokenAtEquals(Iter, "wchar_t"))
{ {
Result = true; Result = true;
*TypeHandleOut = GetTypeHandle(MakeStringLiteral("wchar_t"), TypeTable); *TypeHandleOut = GetTypeHandle(MakeStringLiteral("wchar_t"), TypeTable);
@ -767,11 +669,10 @@ ParseChar(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab
internal b32 internal b32
ParseBool(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) ParseBool(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Bool)) if (TokenAtEquals(Iter, "bool"))
{ {
Result = true; Result = true;
*TypeHandleOut = GetTypeHandle(MakeStringLiteral("bool"), TypeTable); *TypeHandleOut = GetTypeHandle(MakeStringLiteral("bool"), TypeTable);
@ -784,11 +685,10 @@ ParseBool(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab
internal b32 internal b32
ParseFloat(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) ParseFloat(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Float)) if (TokenAtEquals(Iter, "float"))
{ {
Result = true; Result = true;
*TypeHandleOut = GetTypeHandle(MakeStringLiteral("float"), TypeTable); *TypeHandleOut = GetTypeHandle(MakeStringLiteral("float"), TypeTable);
@ -801,11 +701,10 @@ ParseFloat(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTa
internal b32 internal b32
ParseDouble(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) ParseDouble(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Double)) if (TokenAtEquals(Iter, "double"))
{ {
Result = true; Result = true;
*TypeHandleOut = GetTypeHandle(MakeStringLiteral("double"), TypeTable); *TypeHandleOut = GetTypeHandle(MakeStringLiteral("double"), TypeTable);
@ -821,7 +720,6 @@ ParseDouble(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeT
internal b32 internal b32
ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeHandleOut) ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeHandleOut)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseType")); MakeStringLiteral("ParseType"));
@ -882,9 +780,8 @@ ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeH
internal b32 internal b32
ParsePointer (token_iter* Iter) ParsePointer (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (TokenAtHashEquals(Iter, TokenHash_Star)) if (TokenAtEquals(Iter, "*"))
{ {
Result = true; Result = true;
} }
@ -894,12 +791,11 @@ ParsePointer (token_iter* Iter)
internal b32 internal b32
ParseConstVolatile (token_iter* Iter) ParseConstVolatile (token_iter* Iter)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Volatile) || if (TokenAtEquals(Iter, "volatile") ||
TokenAtHashEquals(Iter, TokenHash_Const)) TokenAtEquals(Iter, "const"))
{ {
Result = true; Result = true;
} }
@ -911,7 +807,6 @@ ParseConstVolatile (token_iter* Iter)
internal b32 internal b32
ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_meta_preprocessor* Meta) ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseVariableDecl")); MakeStringLiteral("ParseVariableDecl"));
@ -951,7 +846,7 @@ ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_m
// are still ok to proceed // are still ok to proceed
b32 ArrayParseSuccess = true; b32 ArrayParseSuccess = true;
u32 ArrayCount = 0; u32 ArrayCount = 0;
if (TokenAtHashEquals(Iter, TokenHash_OpenSquareBracket)) if (TokenAtEquals(Iter, "["))
{ {
// NOTE(Peter): Once we get to this point, we have to complete the entire // NOTE(Peter): Once we get to this point, we have to complete the entire
// array notation before we have successfully parsed, hence setting // array notation before we have successfully parsed, hence setting
@ -972,7 +867,7 @@ ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_m
} }
} }
if (TokenAtHashEquals(Iter, TokenHash_CloseSquareBracket)) if (TokenAtEquals(Iter, "]"))
{ {
ArrayParseSuccess = true; ArrayParseSuccess = true;
} }
@ -1010,7 +905,7 @@ ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_m
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtEquals(Iter, Token_Identifier) && if (TokenAtEquals(Iter, Token_Identifier) &&
(TokenAtHashEquals(Iter, TokenHash_Comma) || TokenAtHashEquals(Iter, TokenHash_Semicolon))) (TokenAtEquals(Iter, ",") || TokenAtEquals(Iter, ";")))
{ {
// We are in a declaration list (case 1) // We are in a declaration list (case 1)
ApplySnapshotIfNotParsedAndPop(false, Iter); ApplySnapshotIfNotParsedAndPop(false, Iter);
@ -1039,14 +934,13 @@ ParseVariableDecl(token_iter* Iter, gs_bucket<variable_decl>* VariableList, gs_m
internal b32 internal b32
StructOrUnion(token_iter* Iter, type_definition_type* Type) StructOrUnion(token_iter* Iter, type_definition_type* Type)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (TokenAtHashEquals(Iter, TokenHash_Struct)) if (TokenAtEquals(Iter, "struct"))
{ {
Result = true; Result = true;
*Type = TypeDef_Struct; *Type = TypeDef_Struct;
} }
else if (TokenAtHashEquals(Iter, TokenHash_Union)) else if (TokenAtEquals(Iter, "union"))
{ {
Result = true; Result = true;
*Type = TypeDef_Union; *Type = TypeDef_Union;
@ -1060,7 +954,6 @@ StructOrUnion(token_iter* Iter, type_definition_type* Type)
internal b32 internal b32
ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_preprocessor* Meta, type_definition* ContainingStruct = 0) ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_preprocessor* Meta, type_definition* ContainingStruct = 0)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseStruct")); MakeStringLiteral("ParseStruct"));
@ -1076,7 +969,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) {} if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) {}
// TODO(Peter): Handle name coming after the struct // TODO(Peter): Handle name coming after the struct
if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket)) if (TokenAtEquals(Iter, "{"))
{ {
type_definition StructDecl = {}; type_definition StructDecl = {};
if (IdentifierToken.Text.Length > 0) if (IdentifierToken.Text.Length > 0)
@ -1095,7 +988,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
string AnonStructIdentifier = {}; string AnonStructIdentifier = {};
AnonStructIdentifier.Max = 256; AnonStructIdentifier.Max = 256;
AnonStructIdentifier.Memory = PushArray(&Meta->Permanent, char, AnonStructIdentifier.Max); AnonStructIdentifier.Memory = (char*)malloc(sizeof(char) * AnonStructIdentifier.Max);
PrintF(&AnonStructIdentifier, "%S_%d", ContainingStruct->Identifier, ContainingStruct->Struct.MemberDecls.Used); PrintF(&AnonStructIdentifier, "%S_%d", ContainingStruct->Identifier, ContainingStruct->Struct.MemberDecls.Used);
@ -1106,7 +999,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
StructDecl.Type = DeclType; StructDecl.Type = DeclType;
CopyMetaTagsAndClear(&Meta->TagList, &StructDecl.MetaTags); CopyMetaTagsAndClear(&Meta->TagList, &StructDecl.MetaTags);
while (!TokenAtHashEquals(Iter, TokenHash_CloseCurlyBracket)) while (!TokenAtEquals(Iter, "}"))
{ {
type_table_handle MemberStructTypeHandle = InvalidTypeTableHandle; type_table_handle MemberStructTypeHandle = InvalidTypeTableHandle;
variable_decl MemberDecl = {}; variable_decl MemberDecl = {};
@ -1116,7 +1009,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
} }
else if (ParseVariableDecl(Iter, &StructDecl.Struct.MemberDecls, Meta)) else if (ParseVariableDecl(Iter, &StructDecl.Struct.MemberDecls, Meta))
{ {
if (!TokenAtHashEquals(Iter, TokenHash_Semicolon)) if (!TokenAtEquals(Iter, ";"))
{ {
PushFError(Iter->Errors, "No semicolon after struct member variable declaration. %S", StructDecl.Identifier); PushFError(Iter->Errors, "No semicolon after struct member variable declaration. %S", StructDecl.Identifier);
} }
@ -1143,7 +1036,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
} }
} }
if (TokenAtHashEquals(Iter, TokenHash_Semicolon)) if (TokenAtEquals(Iter, ";"))
{ {
Result = true; Result = true;
*StructTypeHandleOut = PushTypeDefOnTypeTable(StructDecl, &Meta->TypeTable); *StructTypeHandleOut = PushTypeDefOnTypeTable(StructDecl, &Meta->TypeTable);
@ -1160,11 +1053,10 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr
internal b32 internal b32
ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, gs_meta_preprocessor* Meta) ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_OpenParen)) if (TokenAtEquals(Iter, "("))
{ {
Result = true; Result = true;
@ -1183,7 +1075,7 @@ ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl,
} }
} }
if (TokenAtHashEquals(Iter, TokenHash_CloseParen)) if (TokenAtEquals(Iter, ")"))
{ {
Result = true; Result = true;
} }
@ -1196,7 +1088,6 @@ ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl,
internal b32 internal b32
ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preprocessor* Meta) ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
@ -1224,7 +1115,7 @@ ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preproces
if (ParseFunctionParameterList(Iter, &FunctionPtr, Meta)) if (ParseFunctionParameterList(Iter, &FunctionPtr, Meta))
{ {
if (TokenAtHashEquals(Iter, TokenHash_Semicolon)) if (TokenAtEquals(Iter, ";"))
{ {
Result = true; Result = true;
PushTypeDefOnTypeTable(FunctionPtr, &Meta->TypeTable); PushTypeDefOnTypeTable(FunctionPtr, &Meta->TypeTable);
@ -1244,7 +1135,6 @@ ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preproces
internal b32 internal b32
ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseTypedef")); MakeStringLiteral("ParseTypedef"));
@ -1255,7 +1145,7 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
token TypeToken = {0}; token TypeToken = {0};
type_table_handle TypeHandle = InvalidTypeTableHandle; type_table_handle TypeHandle = InvalidTypeTableHandle;
if (TokenAtHashEquals(Iter, TokenHash_Struct) && if (TokenAtEquals(Iter, "struct") &&
ParseStruct(Iter, &TypeHandle, Meta)) ParseStruct(Iter, &TypeHandle, Meta))
{ {
Result = true; Result = true;
@ -1299,7 +1189,7 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
string* Error = TakeError(Iter->Errors); string* Error = TakeError(Iter->Errors);
PrintF(Error, "unhandled typedef "); PrintF(Error, "unhandled typedef ");
while (!TokenAtHashEquals(Iter, TokenHash_Semicolon)) while (!TokenAtEquals(Iter, ";"))
{ {
PrintF(Error, "%S ", Iter->TokenAt->Text); PrintF(Error, "%S ", Iter->TokenAt->Text);
NextToken(Iter); NextToken(Iter);
@ -1317,14 +1207,13 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta)
internal b32 internal b32
ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION;
gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"), MakeStringLiteral("parse"),
MakeStringLiteral("ParseEnum")); MakeStringLiteral("ParseEnum"));
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
if (TokenAtHashEquals(Iter, TokenHash_Enum)) if (TokenAtEquals(Iter, "enum"))
{ {
token IdentifierToken = {}; token IdentifierToken = {};
if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken))
@ -1335,7 +1224,7 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
CopyMetaTagsAndClear(&Meta->TagList, &EnumDecl.MetaTags); CopyMetaTagsAndClear(&Meta->TagList, &EnumDecl.MetaTags);
EnumDecl.Type = TypeDef_Enum; EnumDecl.Type = TypeDef_Enum;
if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket)) if (TokenAtEquals(Iter, "{"))
{ {
u32 EnumAcc = 0; u32 EnumAcc = 0;
@ -1344,7 +1233,7 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
token EnumIdentifierToken = {}; token EnumIdentifierToken = {};
if (TokenAtEquals(Iter, Token_Identifier, &EnumIdentifierToken)) if (TokenAtEquals(Iter, Token_Identifier, &EnumIdentifierToken))
{ {
if (TokenAtHashEquals(Iter, TokenHash_Equals)) if (TokenAtEquals(Iter, "="))
{ {
// TODO(Peter): TempValue is just here until we handle all // TODO(Peter): TempValue is just here until we handle all
// const expr that could define an enum value. Its there so // const expr that could define an enum value. Its there so
@ -1372,7 +1261,7 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
} }
s32 EnumValue = EnumAcc++; s32 EnumValue = EnumAcc++;
if (TokenAtHashEquals(Iter, TokenHash_Comma) || if (TokenAtEquals(Iter, ",") ||
StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}")))
{ {
EnumDecl.Enum.Identifiers.PushElementOnBucket(EnumIdentifierToken.Text); EnumDecl.Enum.Identifiers.PushElementOnBucket(EnumIdentifierToken.Text);
@ -1386,8 +1275,8 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
} }
} }
if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket) && if (TokenAtEquals(Iter, "}") &&
TokenAtHashEquals(Iter, TokenHash_Semicolon)) TokenAtEquals(Iter, ";"))
{ {
PushTypeDefOnTypeTable(EnumDecl, &Meta->TypeTable); PushTypeDefOnTypeTable(EnumDecl, &Meta->TypeTable);
Result = true; Result = true;
@ -1404,8 +1293,9 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta)
internal b32 internal b32
ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta) ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
DEBUG_TRACK_FUNCTION; gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"),
MakeStringLiteral("ParseFunction"));
b32 Result = false; b32 Result = false;
PushSnapshot(Iter); PushSnapshot(Iter);
@ -1414,8 +1304,11 @@ ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta)
{ {
token IdentifierToken = {}; token IdentifierToken = {};
if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken) && if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken) &&
TokenAtHashEquals(Iter, TokenHash_OpenParen)) TokenAtEquals(Iter, "("))
{ {
gsm_profiler_scope* ProfilerInnerScope = BeginScope(&Meta->Profiler,
MakeStringLiteral("parse"),
MakeStringLiteral("ParseFunctionInner"));
type_definition FunctionDecl = {}; type_definition FunctionDecl = {};
FunctionDecl.Identifier = IdentifierToken.Text; FunctionDecl.Identifier = IdentifierToken.Text;
FunctionDecl.Function.ReturnTypeHandle = ReturnTypeHandle; FunctionDecl.Function.ReturnTypeHandle = ReturnTypeHandle;
@ -1430,29 +1323,29 @@ ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta)
} }
if(!TokenAtHashEquals(Iter, TokenHash_Comma)) if(!TokenAtEquals(Iter, ","))
{ {
break; break;
} }
} }
if (TokenAtHashEquals(Iter, TokenHash_OpenParen)) if (TokenAtEquals(Iter, ")"))
{ {
Result = true; Result = true;
PushTypeDefOnTypeTable(FunctionDecl, &Meta->TypeTable); PushTypeDefOnTypeTable(FunctionDecl, &Meta->TypeTable);
} }
EndScope(ProfilerInnerScope);
} }
} }
ApplySnapshotIfNotParsedAndPop(Result, Iter); ApplySnapshotIfNotParsedAndPop(Result, Iter);
EndScope(ProfilerScope);
return Result; return Result;
} }
internal void internal void
PrintIndent (u32 Indent) PrintIndent (u32 Indent)
{ {
DEBUG_TRACK_FUNCTION;
for (u32 i = 0; i < Indent; i++) for (u32 i = 0; i < Indent; i++)
{ {
printf(" "); printf(" ");
@ -1464,8 +1357,6 @@ internal void PrintStructDecl (type_definition* StructDecl, type_table TypeTable
internal void internal void
PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0) PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* MemberTypeDef = GetTypeDefinition(Member.TypeHandle, TypeTable); type_definition* MemberTypeDef = GetTypeDefinition(Member.TypeHandle, TypeTable);
if ((MemberTypeDef->Type == TypeDef_Struct || MemberTypeDef->Type == TypeDef_Union) if ((MemberTypeDef->Type == TypeDef_Struct || MemberTypeDef->Type == TypeDef_Union)
&& MemberTypeDef->Identifier.Length == 0) && MemberTypeDef->Identifier.Length == 0)
@ -1498,8 +1389,6 @@ PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0)
internal void internal void
PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = 0) PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = 0)
{ {
DEBUG_TRACK_FUNCTION;
Assert(StructDecl->Type == TypeDef_Struct || Assert(StructDecl->Type == TypeDef_Struct ||
StructDecl->Type == TypeDef_Union); StructDecl->Type == TypeDef_Union);
@ -1533,8 +1422,6 @@ PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent =
internal void internal void
PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable) PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* ReturnType = GetTypeDefinition(FnPtrDecl->FunctionPtr.ReturnTypeHandle, TypeTable); type_definition* ReturnType = GetTypeDefinition(FnPtrDecl->FunctionPtr.ReturnTypeHandle, TypeTable);
printf("%.*s ", StringExpand(ReturnType->Identifier)); printf("%.*s ", StringExpand(ReturnType->Identifier));
@ -1555,16 +1442,9 @@ PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable)
} }
internal gs_meta_preprocessor internal gs_meta_preprocessor
PreprocessProgram (base_allocator Allocator, char* SourceFile) PreprocessProgram (char* SourceFile)
{ {
DEBUG_TRACK_FUNCTION;
gs_meta_preprocessor Meta = {}; gs_meta_preprocessor Meta = {};
Meta.Permanent = CreateMemoryArena(Allocator);
Meta.Transient = CreateMemoryArena(Allocator);
Meta.Errors.Arena = CreateMemoryArena(Allocator);
Meta.TypeTable.Arena = CreateMemoryArena(Allocator);
gsm_profiler_scope* TotalScope = BeginScope(&Meta.Profiler, "total", "total"); gsm_profiler_scope* TotalScope = BeginScope(&Meta.Profiler, "total", "total");
@ -1572,10 +1452,10 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile)
PopulateTableWithDefaultCPPTypes(&Meta.TypeTable); PopulateTableWithDefaultCPPTypes(&Meta.TypeTable);
string CurrentWorkingDirectory = MakeString(PushArray(&Meta.Permanent, char, 1024), 0, 1024); string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024);
string RootFile = MakeString(SourceFile); string RootFile = MakeString(SourceFile);
AddFileToSource(&Meta.Permanent, RootFile, {}, &Meta.SourceFiles, &Meta.Errors); AddFileToSource(RootFile, {}, &Meta.SourceFiles, &Meta.Errors);
s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/");
if (LastSlash <= 0) if (LastSlash <= 0)
@ -1595,18 +1475,24 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile)
MakeStringLiteral("file"), MakeStringLiteral("file"),
File->Path); File->Path);
TokenizeFile(&Meta, File); gsm_profiler_scope* TokenizeScope = BeginScope(&Meta.Profiler,
MakeStringLiteral("tokenize"),
File->Path);
TokenizeFile(File, &Meta.Tokens);
EndScope(TokenizeScope);
gsm_profiler_scope* PreprocScope = BeginScope(&Meta.Profiler, gsm_profiler_scope* PreprocScope = BeginScope(&Meta.Profiler,
MakeStringLiteral("preproc"), MakeStringLiteral("preproc"),
File->Path); File->Path);
token_iter Iter = {}; token_iter Iter = {};
Iter.Tokens = File->Tokens; Iter.Tokens = &Meta.Tokens;
Iter.TokenAtIndex = 0; Iter.FirstToken = File->FirstTokenIndex;
Iter.TokenAt = File->Tokens.List + Iter.TokenAtIndex; Iter.LastToken = File->LastTokenIndex;
Iter.TokenAtIndex = Iter.FirstToken;
Iter.TokenAt = Meta.Tokens.GetElementAtIndex(Iter.TokenAtIndex);
Iter.Errors = &Meta.Errors; Iter.Errors = &Meta.Errors;
while (Iter.TokenAtIndex < Iter.Tokens.Count) while (Iter.TokenAtIndex < Iter.LastToken)
{ {
b32 ParseSuccess = false; b32 ParseSuccess = false;
@ -1641,7 +1527,7 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile)
ParseSuccess = true; ParseSuccess = true;
if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles)) if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles))
{ {
AddFileToSource(&Meta.Permanent, TempFilePath, *File, &Meta.SourceFiles, &Meta.Errors); AddFileToSource(TempFilePath, *File, &Meta.SourceFiles, &Meta.Errors);
} }
EndScope(IncludeScope); EndScope(IncludeScope);
} }
@ -1714,8 +1600,6 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile)
internal void internal void
FinishMetaprogram(gs_meta_preprocessor* Meta) FinishMetaprogram(gs_meta_preprocessor* Meta)
{ {
CollateFrame(&GlobalDebugServices);
FinishProfiler(&Meta->Profiler); FinishProfiler(&Meta->Profiler);
PrintAllErrors(Meta->Errors); PrintAllErrors(Meta->Errors);

View File

@ -37,12 +37,12 @@ struct gsm_code_generator
// --------------- // ---------------
internal gsm_code_generator internal gsm_code_generator
BeginEnumGeneration(memory_arena* Storage, string EnumIdentifier, string ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) BeginEnumGeneration(string EnumIdentifier, string ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount)
{ {
gsm_code_generator Gen = {}; gsm_code_generator Gen = {};
// TODO(Peter): TEMP!! // TODO(Peter): TEMP!!
Gen.Builder = PushStruct(Storage, string_builder); Gen.Builder = (string_builder*)malloc(sizeof(string_builder));
*Gen.Builder = {}; *Gen.Builder = {};
Gen.Type = gsm_CodeGen_Enum; Gen.Type = gsm_CodeGen_Enum;
@ -60,9 +60,9 @@ BeginEnumGeneration(memory_arena* Storage, string EnumIdentifier, string ValuePr
} }
internal gsm_code_generator internal gsm_code_generator
BeginEnumGeneration(memory_arena* Storage, char* EnumIdentifier, char* ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) BeginEnumGeneration(char* EnumIdentifier, char* ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount)
{ {
return BeginEnumGeneration(Storage, MakeStringLiteral(EnumIdentifier), return BeginEnumGeneration(MakeStringLiteral(EnumIdentifier),
MakeStringLiteral(ValuePrefix), MakeStringLiteral(ValuePrefix),
StartsWithInvalid, StartsWithInvalid,
EndsWithCount); EndsWithCount);

View File

@ -9,28 +9,46 @@ struct error_buffer
#define ERROR_BUFFER_SIZE 256 #define ERROR_BUFFER_SIZE 256
struct errors struct errors
{ {
memory_arena Arena;
error_buffer* Buffers; error_buffer* Buffers;
u32 BuffersCount; u32 BuffersCount;
u32 Used; u32 Used;
}; };
#define ErrorReallocArray(base, type, oldcount, newcount) (type*)ErrorRealloc_((u8*)(base), (u64)(sizeof(type) * oldcount), (u64)(sizeof(type) * newcount))
internal u8*
ErrorRealloc_(u8* Base, u64 OldSize, u64 NewSize)
{
Assert(NewSize > 0);
u8* Result = (u8*)malloc(NewSize);
if (Base != 0 && OldSize > 0)
{
GSMemCopy(Base, Result, OldSize);
free(Base);
}
return Result;
}
internal void internal void
PushFError (errors* Errors, char* Format, ...) PushFError (errors* Errors, char* Format, ...)
{ {
if (Errors->Used >= (Errors->BuffersCount * ERROR_BUFFER_SIZE)) if (Errors->Used >= (Errors->BuffersCount * ERROR_BUFFER_SIZE))
{ {
#if 0
Errors->BuffersCount += 1; Errors->BuffersCount += 1;
Errors->Buffers = (error_buffer*)realloc(Errors->Buffers, sizeof(error_buffer*) * Errors->BuffersCount); Errors->Buffers = (error_buffer*)realloc(Errors->Buffers, sizeof(error_buffer*) * Errors->BuffersCount);
#else
Errors->Buffers = ErrorReallocArray(Errors->Buffers, error_buffer, Errors->BuffersCount, Errors->BuffersCount + 1);
Errors->BuffersCount += 1;
#endif
error_buffer* NewBuffer = Errors->Buffers + (Errors->BuffersCount - 1); error_buffer* NewBuffer = Errors->Buffers + (Errors->BuffersCount - 1);
NewBuffer->Backbuffer = PushArray(&Errors->Arena, char, ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE); NewBuffer->Backbuffer = (char*)malloc(sizeof(char) * ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE);
NewBuffer->Contents = PushArray(&Errors->Arena, string, ERROR_BUFFER_SIZE); NewBuffer->Contents = (string*)malloc(sizeof(string) * ERROR_BUFFER_SIZE);
for (u32 i = 0; i < ERROR_BUFFER_SIZE; i++) for (u32 i = 0; i < ERROR_BUFFER_SIZE; i++)
{ {
NewBuffer->Contents[i].Memory = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH); NewBuffer->Contents[i].Str = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH);
NewBuffer->Contents[i].Max = ERROR_MAX_LENGTH; NewBuffer->Contents[i].Size = ERROR_MAX_LENGTH;
NewBuffer->Contents[i].Length = 0; NewBuffer->Contents[i].Length = 0;
} }
} }

View File

@ -1,7 +1,7 @@
struct token_selection_spec struct token_selection_spec
{ {
b32 MatchText; b32 MatchText;
string Text; gs_string Text;
}; };
internal s32 internal s32
@ -160,69 +160,69 @@ GetNextToken (tokenizer* Tokenizer)
{ {
Result.Type = Token_PoundDefine; Result.Type = Token_PoundDefine;
EatPreprocessor(Tokenizer); EatPreprocessor(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "undef")) else if (TokenAtEquals(Tokenizer, "undef"))
{ {
Result.Type = Token_PoundUndef; Result.Type = Token_PoundUndef;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "include")) else if (TokenAtEquals(Tokenizer, "include"))
{ {
Result.Type = Token_PoundInclude; Result.Type = Token_PoundInclude;
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "ifdef")) else if (TokenAtEquals(Tokenizer, "ifdef"))
{ {
Result.Type = Token_PoundIfDef; Result.Type = Token_PoundIfDef;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "ifndef")) else if (TokenAtEquals(Tokenizer, "ifndef"))
{ {
Result.Type = Token_PoundIfNDef; Result.Type = Token_PoundIfNDef;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "if")) else if (TokenAtEquals(Tokenizer, "if"))
{ {
Result.Type = Token_PoundIf; Result.Type = Token_PoundIf;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "elif")) else if (TokenAtEquals(Tokenizer, "elif"))
{ {
Result.Type = Token_PoundElif; Result.Type = Token_PoundElif;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "else")) else if (TokenAtEquals(Tokenizer, "else"))
{ {
Result.Type = Token_PoundElse; Result.Type = Token_PoundElse;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "endif")) else if (TokenAtEquals(Tokenizer, "endif"))
{ {
Result.Type = Token_PoundEndif; Result.Type = Token_PoundEndif;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "error")) else if (TokenAtEquals(Tokenizer, "error"))
{ {
Result.Type = Token_PoundError; Result.Type = Token_PoundError;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
else if (TokenAtEquals(Tokenizer, "pragma")) else if (TokenAtEquals(Tokenizer, "pragma"))
{ {
Result.Type = Token_PoundPragma; Result.Type = Token_PoundPragma;
EatToNewLine(Tokenizer); EatToNewLine(Tokenizer);
Result.Text.Length = Tokenizer->At - Result.Text.Memory; Result.Text.Length = Tokenizer->At - Result.Text.Str;
} }
} }
else if (IsNumeric(C)) else if (IsNumericExtended(C))
{ {
Result.Type = Token_Number; Result.Type = Token_Number;
@ -233,7 +233,7 @@ GetNextToken (tokenizer* Tokenizer)
else if (C == '\'') else if (C == '\'')
{ {
Result.Type = Token_Char; Result.Type = Token_Char;
Result.Text.Memory = Tokenizer->At; Result.Text.Str = Tokenizer->At;
if (Tokenizer->At[0] && Tokenizer->At[0] == '\\') if (Tokenizer->At[0] && Tokenizer->At[0] == '\\')
{ {
++Tokenizer->At; ++Tokenizer->At;
@ -245,7 +245,7 @@ GetNextToken (tokenizer* Tokenizer)
{ {
Result.Type = Token_String; Result.Type = Token_String;
// replace the length added by the quote // replace the length added by the quote
Result.Text.Memory = Tokenizer->At; Result.Text.Str = Tokenizer->At;
Result.Text.Length = EatString(Tokenizer); Result.Text.Length = EatString(Tokenizer);
} }
// NOTE(Peter): This is after comment parsing so that the division operator // NOTE(Peter): This is after comment parsing so that the division operator
@ -257,6 +257,5 @@ GetNextToken (tokenizer* Tokenizer)
Result.Text.Length += EatIdentifier(Tokenizer); Result.Text.Length += EatIdentifier(Tokenizer);
} }
Result.TextHash = HashDJB2ToU64(Result.Text.Memory);
return Result; return Result;
} }

View File

@ -44,7 +44,6 @@ struct type_table_handle
// #define TypeHandleIsValid(handle) (!((handle).BucketIndex == 0) && ((handle).IndexInBucket == 0)) // #define TypeHandleIsValid(handle) (!((handle).BucketIndex == 0) && ((handle).IndexInBucket == 0))
inline b32 TypeHandleIsValid(type_table_handle A) inline b32 TypeHandleIsValid(type_table_handle A)
{ {
DEBUG_TRACK_FUNCTION;
b32 FirstBucket = (A.BucketIndex == 0); b32 FirstBucket = (A.BucketIndex == 0);
b32 FirstIndex = (A.IndexInBucket == 0); b32 FirstIndex = (A.IndexInBucket == 0);
b32 Both = FirstBucket && FirstIndex; b32 Both = FirstBucket && FirstIndex;
@ -142,8 +141,6 @@ struct meta_tag_hash_bucket
struct type_table struct type_table
{ {
memory_arena Arena;
type_table_hash_bucket* Types; type_table_hash_bucket* Types;
u32 TypeBucketsCount; u32 TypeBucketsCount;
@ -154,7 +151,6 @@ struct type_table
internal b32 internal b32
HandlesAreEqual(type_table_handle A, type_table_handle B) HandlesAreEqual(type_table_handle A, type_table_handle B)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = ((A.BucketIndex == B.BucketIndex) && (A.IndexInBucket == B.IndexInBucket)); b32 Result = ((A.BucketIndex == B.BucketIndex) && (A.IndexInBucket == B.IndexInBucket));
return Result; return Result;
} }
@ -162,7 +158,6 @@ HandlesAreEqual(type_table_handle A, type_table_handle B)
internal u32 internal u32
HashIdentifier(string Identifier) HashIdentifier(string Identifier)
{ {
DEBUG_TRACK_FUNCTION;
u32 IdentHash = HashString(Identifier); u32 IdentHash = HashString(Identifier);
if (IdentHash == 0) if (IdentHash == 0)
{ {
@ -177,7 +172,6 @@ HashIdentifier(string Identifier)
internal type_table_handle internal type_table_handle
GetTypeHandle (string Identifier, type_table TypeTable) GetTypeHandle (string Identifier, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
u32 IdentHash = HashIdentifier(Identifier); u32 IdentHash = HashIdentifier(Identifier);
@ -200,7 +194,6 @@ GetTypeHandle (string Identifier, type_table TypeTable)
internal type_table_handle internal type_table_handle
GetMetaTagHandle(string Identifier, type_table TypeTable) GetMetaTagHandle(string Identifier, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
u32 IdentHash = HashIdentifier(Identifier); u32 IdentHash = HashIdentifier(Identifier);
@ -223,7 +216,6 @@ GetMetaTagHandle(string Identifier, type_table TypeTable)
internal type_table_handle internal type_table_handle
GetMetaTagHandleWithIdentifier(string Identifier, type_table TypeTable) GetMetaTagHandleWithIdentifier(string Identifier, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
u32 IdentHash = HashIdentifier(Identifier); u32 IdentHash = HashIdentifier(Identifier);
@ -245,7 +237,6 @@ GetMetaTagHandleWithIdentifier(string Identifier, type_table TypeTable)
internal b32 internal b32
HasTag(string Needle, gs_bucket<type_table_handle> Tags, type_table TypeTable) HasTag(string Needle, gs_bucket<type_table_handle> Tags, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
type_table_handle NeedleTagHandle = GetMetaTagHandleWithIdentifier(Needle, TypeTable); type_table_handle NeedleTagHandle = GetMetaTagHandleWithIdentifier(Needle, TypeTable);
@ -268,7 +259,6 @@ HasTag(string Needle, gs_bucket<type_table_handle> Tags, type_table TypeTable)
internal void internal void
CopyMetaTagsAndClear(gs_bucket<type_table_handle>* Source, gs_bucket<type_table_handle>* Dest) CopyMetaTagsAndClear(gs_bucket<type_table_handle>* Source, gs_bucket<type_table_handle>* Dest)
{ {
DEBUG_TRACK_FUNCTION;
for (u32 i = 0; i < Source->Used; i++) for (u32 i = 0; i < Source->Used; i++)
{ {
type_table_handle* TagToken = Source->GetElementAtIndex(i); type_table_handle* TagToken = Source->GetElementAtIndex(i);
@ -280,7 +270,6 @@ CopyMetaTagsAndClear(gs_bucket<type_table_handle>* Source, gs_bucket<type_table_
internal type_table_handle internal type_table_handle
FindSlotForTypeIdentifier(u32 IdentHash, type_table* TypeTable) FindSlotForTypeIdentifier(u32 IdentHash, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX; u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
@ -303,8 +292,8 @@ FindSlotForTypeIdentifier(u32 IdentHash, type_table* TypeTable)
TypeTable->Types = (type_table_hash_bucket*)realloc(TypeTable->Types, NewTypesSize); TypeTable->Types = (type_table_hash_bucket*)realloc(TypeTable->Types, NewTypesSize);
type_table_hash_bucket* NewBucket = TypeTable->Types + NewTypeBucketIndex; type_table_hash_bucket* NewBucket = TypeTable->Types + NewTypeBucketIndex;
NewBucket->Keys = PushArray(&TypeTable->Arena, u32, TYPE_TABLE_BUCKET_MAX); NewBucket->Keys = (u32*)malloc(sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
NewBucket->Values = PushArray(&TypeTable->Arena, type_definition, TYPE_TABLE_BUCKET_MAX); NewBucket->Values = (type_definition*)malloc(sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX);
GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
GSZeroMemory((u8*)NewBucket->Values, sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Values, sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX);
@ -321,7 +310,6 @@ FindSlotForTypeIdentifier(u32 IdentHash, type_table* TypeTable)
internal type_table_handle internal type_table_handle
FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable) FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX; u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
@ -343,8 +331,8 @@ FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable)
TypeTable->MetaTags = (meta_tag_hash_bucket*)realloc(TypeTable->MetaTags, NewMetaBucketListSize); TypeTable->MetaTags = (meta_tag_hash_bucket*)realloc(TypeTable->MetaTags, NewMetaBucketListSize);
meta_tag_hash_bucket* NewBucket = TypeTable->MetaTags + NewMetaBucketIndex; meta_tag_hash_bucket* NewBucket = TypeTable->MetaTags + NewMetaBucketIndex;
NewBucket->Keys = PushArray(&TypeTable->Arena, u32, TYPE_TABLE_BUCKET_MAX); NewBucket->Keys = (u32*)malloc(sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
NewBucket->Values = PushArray(&TypeTable->Arena, meta_tag, TYPE_TABLE_BUCKET_MAX); NewBucket->Values = (meta_tag*)malloc(sizeof(meta_tag) * TYPE_TABLE_BUCKET_MAX);
GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX);
GSZeroMemory((u8*)NewBucket->Values, sizeof(meta_tag) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Values, sizeof(meta_tag) * TYPE_TABLE_BUCKET_MAX);
@ -358,7 +346,6 @@ FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable)
internal type_table_handle internal type_table_handle
PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable) PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
u32 IdentHash = HashIdentifier(TypeDef.Identifier); u32 IdentHash = HashIdentifier(TypeDef.Identifier);
type_table_handle Result = FindSlotForTypeIdentifier(IdentHash, TypeTable); type_table_handle Result = FindSlotForTypeIdentifier(IdentHash, TypeTable);
@ -378,7 +365,6 @@ PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable)
internal type_table_handle internal type_table_handle
PushUndeclaredType (string Identifier, type_table* TypeTable) PushUndeclaredType (string Identifier, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_definition UndeclaredTypeDef = {}; type_definition UndeclaredTypeDef = {};
UndeclaredTypeDef.Identifier = Identifier; UndeclaredTypeDef.Identifier = Identifier;
UndeclaredTypeDef.Type = TypeDef_Unknown; UndeclaredTypeDef.Type = TypeDef_Unknown;
@ -389,7 +375,6 @@ PushUndeclaredType (string Identifier, type_table* TypeTable)
internal type_table_handle internal type_table_handle
PushMetaTagOnTable(meta_tag Tag, type_table* TypeTable) PushMetaTagOnTable(meta_tag Tag, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
u32 TagIdentifierHash = HashIdentifier(Tag.Identifier); u32 TagIdentifierHash = HashIdentifier(Tag.Identifier);
type_table_handle Result = FindSlotForMetaTag(TagIdentifierHash, TypeTable); type_table_handle Result = FindSlotForMetaTag(TagIdentifierHash, TypeTable);
@ -409,7 +394,6 @@ PushMetaTagOnTable(meta_tag Tag, type_table* TypeTable)
internal type_definition* internal type_definition*
GetTypeDefinition(type_table_handle Handle, type_table TypeTable) GetTypeDefinition(type_table_handle Handle, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
Assert(TypeHandleIsValid(Handle)); Assert(TypeHandleIsValid(Handle));
type_definition* Result = 0; type_definition* Result = 0;
if (TypeTable.Types[Handle.BucketIndex].Keys != 0) if (TypeTable.Types[Handle.BucketIndex].Keys != 0)
@ -423,7 +407,6 @@ GetTypeDefinition(type_table_handle Handle, type_table TypeTable)
internal type_definition* internal type_definition*
GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable) GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* Result = 0; type_definition* Result = 0;
if (TypeTable.Types[Handle.BucketIndex].Keys != 0) if (TypeTable.Types[Handle.BucketIndex].Keys != 0)
{ {
@ -435,7 +418,6 @@ GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable)
internal meta_tag* internal meta_tag*
GetMetaTag(type_table_handle Handle, type_table TypeTable) GetMetaTag(type_table_handle Handle, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
meta_tag* Result = 0; meta_tag* Result = 0;
if (TypeTable.MetaTags[Handle.BucketIndex].Keys != 0) if (TypeTable.MetaTags[Handle.BucketIndex].Keys != 0)
{ {
@ -447,7 +429,6 @@ GetMetaTag(type_table_handle Handle, type_table TypeTable)
internal type_definition* internal type_definition*
GetTypeDefinition(string Identifier, type_table TypeTable) GetTypeDefinition(string Identifier, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* Result = 0; type_definition* Result = 0;
u32 IdentHash = HashIdentifier(Identifier); u32 IdentHash = HashIdentifier(Identifier);
u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX; u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX;
@ -466,7 +447,6 @@ GetTypeDefinition(string Identifier, type_table TypeTable)
internal type_table_handle internal type_table_handle
PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable) PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
// NOTE(Peter): We don't accept type definitions with empty identifiers. // NOTE(Peter): We don't accept type definitions with empty identifiers.
// If a struct or union is anonymous, it should be assigned a name of the form // If a struct or union is anonymous, it should be assigned a name of the form
// parent_struct_name_# where # is the member index // parent_struct_name_# where # is the member index
@ -496,7 +476,6 @@ PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable)
internal s32 internal s32
GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable) GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
s32 Result = -1; s32 Result = -1;
type_definition* TypeDef = GetTypeDefinition(TypeHandle, TypeTable); type_definition* TypeDef = GetTypeDefinition(TypeHandle, TypeTable);
if (TypeDef) if (TypeDef)
@ -509,7 +488,6 @@ GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable)
internal s32 internal s32
GetSizeOfType (string Identifier, type_table TypeTable) GetSizeOfType (string Identifier, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
s32 Result = -1; s32 Result = -1;
type_definition* TypeDef = GetTypeDefinition(Identifier, TypeTable); type_definition* TypeDef = GetTypeDefinition(Identifier, TypeTable);
if (TypeDef) if (TypeDef)
@ -522,7 +500,6 @@ GetSizeOfType (string Identifier, type_table TypeTable)
internal b32 internal b32
VariableDeclsEqual (variable_decl A, variable_decl B) VariableDeclsEqual (variable_decl A, variable_decl B)
{ {
DEBUG_TRACK_FUNCTION;
b32 Result = false; b32 Result = false;
if (TypeHandlesEqual(A.TypeHandle, B.TypeHandle) && if (TypeHandlesEqual(A.TypeHandle, B.TypeHandle) &&
A.ArrayCount == B.ArrayCount && A.ArrayCount == B.ArrayCount &&
@ -536,7 +513,6 @@ VariableDeclsEqual (variable_decl A, variable_decl B)
internal b32 internal b32
StructOrUnionsEqual (type_definition A, type_definition B) StructOrUnionsEqual (type_definition A, type_definition B)
{ {
DEBUG_TRACK_FUNCTION;
// NOTE(Peter): Fairly certain the only places this is used are when we // NOTE(Peter): Fairly certain the only places this is used are when we
// already know the identifiers match // already know the identifiers match
Assert(StringsEqual(A.Identifier, B.Identifier)); Assert(StringsEqual(A.Identifier, B.Identifier));
@ -565,7 +541,6 @@ StructOrUnionsEqual (type_definition A, type_definition B)
internal type_table_handle internal type_table_handle
FindHandleOfMatchingType (type_definition Match, type_table TypeTable) FindHandleOfMatchingType (type_definition Match, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
type_table_handle Result = InvalidTypeTableHandle; type_table_handle Result = InvalidTypeTableHandle;
type_table_handle Handle = GetTypeHandle(Match.Identifier, TypeTable); type_table_handle Handle = GetTypeHandle(Match.Identifier, TypeTable);
if (TypeHandleIsValid(Handle)) if (TypeHandleIsValid(Handle))
@ -581,7 +556,6 @@ internal void FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable
internal void internal void
FixupMemberType (variable_decl* Member, type_table TypeTable) FixupMemberType (variable_decl* Member, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
if (!TypeHandleIsValid(Member->TypeHandle)) if (!TypeHandleIsValid(Member->TypeHandle))
{ {
Member->TypeHandle = GetTypeHandle(Member->Identifier, TypeTable); Member->TypeHandle = GetTypeHandle(Member->Identifier, TypeTable);
@ -592,7 +566,6 @@ FixupMemberType (variable_decl* Member, type_table TypeTable)
internal s32 internal s32
CalculateStructMemberSize (variable_decl Member, type_definition MemberType) CalculateStructMemberSize (variable_decl Member, type_definition MemberType)
{ {
DEBUG_TRACK_FUNCTION;
Assert(TypeHandleIsValid(Member.TypeHandle)); Assert(TypeHandleIsValid(Member.TypeHandle));
// NOTE(Peter): At one point we were Asserting on struct sizes of zero, but // NOTE(Peter): At one point we were Asserting on struct sizes of zero, but
// that's actually incorrect. It is valid to have an empty struct. // that's actually incorrect. It is valid to have an empty struct.
@ -614,7 +587,6 @@ CalculateStructMemberSize (variable_decl Member, type_definition MemberType)
internal void internal void
FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_table TypeTable, errors* Errors) FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_table TypeTable, errors* Errors)
{ {
DEBUG_TRACK_FUNCTION;
// NOTE(Peter): There are a lot of cases where struct members which are pointers // NOTE(Peter): There are a lot of cases where struct members which are pointers
// to other structs cause interesting behavior here. // to other structs cause interesting behavior here.
// For example: // For example:
@ -669,7 +641,6 @@ FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_t
internal void internal void
FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors) FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* Struct = GetTypeDefinition(TypeHandle, TypeTable); type_definition* Struct = GetTypeDefinition(TypeHandle, TypeTable);
Assert(Struct->Type == TypeDef_Struct); Assert(Struct->Type == TypeDef_Struct);
@ -715,7 +686,6 @@ FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Err
internal void internal void
FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors) FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors)
{ {
DEBUG_TRACK_FUNCTION;
type_definition* Union = GetTypeDefinition(TypeHandle, TypeTable); type_definition* Union = GetTypeDefinition(TypeHandle, TypeTable);
Assert(Union->Type == TypeDef_Union); Assert(Union->Type == TypeDef_Union);
@ -773,7 +743,6 @@ type_definition CPPBasicTypes[] = {
internal void internal void
PopulateTableWithDefaultCPPTypes(type_table* TypeTable) PopulateTableWithDefaultCPPTypes(type_table* TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
for (u32 i = 0; i < GSArrayLength(CPPBasicTypes); i++) for (u32 i = 0; i < GSArrayLength(CPPBasicTypes); i++)
{ {
PushTypeDefOnTypeTable(CPPBasicTypes[i], TypeTable); PushTypeDefOnTypeTable(CPPBasicTypes[i], TypeTable);
@ -783,7 +752,6 @@ PopulateTableWithDefaultCPPTypes(type_table* TypeTable)
internal void internal void
PrintTypeDefinition(type_definition TypeDef, type_table TypeTable) PrintTypeDefinition(type_definition TypeDef, type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
printf("Type: %.*s\n", StringExpand(TypeDef.Identifier)); printf("Type: %.*s\n", StringExpand(TypeDef.Identifier));
printf(" Size: %d\n", TypeDef.Size); printf(" Size: %d\n", TypeDef.Size);
@ -849,7 +817,6 @@ PrintTypeDefinition(type_definition TypeDef, type_table TypeTable)
internal void internal void
PrintTypeTable(type_table TypeTable) PrintTypeTable(type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++) for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++)
{ {
type_table_hash_bucket Bucket = TypeTable.Types[b]; type_table_hash_bucket Bucket = TypeTable.Types[b];
@ -866,7 +833,6 @@ PrintTypeTable(type_table TypeTable)
internal void internal void
DEBUGPrintTypeTableMembership(type_table TypeTable) DEBUGPrintTypeTableMembership(type_table TypeTable)
{ {
DEBUG_TRACK_FUNCTION;
printf("\n--- Type Table Membership --\n"); printf("\n--- Type Table Membership --\n");
u32 SlotsAvailable = 0; u32 SlotsAvailable = 0;
u32 SlotsFilled = 0; u32 SlotsFilled = 0;

View File

@ -31,15 +31,15 @@ struct typeinfo_generator
#define TypeHandleToIndex(handle) ((handle.BucketIndex * TYPE_TABLE_BUCKET_MAX) + handle.IndexInBucket) #define TypeHandleToIndex(handle) ((handle.BucketIndex * TYPE_TABLE_BUCKET_MAX) + handle.IndexInBucket)
internal typeinfo_generator internal typeinfo_generator
InitTypeInfoGenerator(type_table* TypeTable) InitTypeInfoGenerator(type_table TypeTable)
{ {
typeinfo_generator Result = {}; typeinfo_generator Result = {};
Result.TypesMax = TypeTable->TypeBucketsCount * TYPE_TABLE_BUCKET_MAX; Result.TypesMax = TypeTable.TypeBucketsCount * TYPE_TABLE_BUCKET_MAX;
Result.TypesGeneratedMask = PushArray(&TypeTable->Arena, b8, Result.TypesMax); Result.TypesGeneratedMask = (b8*)malloc(sizeof(b8) * Result.TypesMax);
GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax); GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax);
Result.TypeList = BeginEnumGeneration(&TypeTable->Arena, "gsm_struct_type", "gsm_StructType", false, true); Result.TypeList = BeginEnumGeneration("gsm_struct_type", "gsm_StructType", false, true);
WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n"); WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n");
return Result; return Result;

View File

@ -0,0 +1,221 @@
//
// File: first.cpp
// Author: Peter Slattery
// Creation Date: 2020-10-10
//
#ifndef FIRST_CPP
#include "../gs_libs/gs_types.h"
#include "../gs_libs/gs_types.cpp"
#define DEBUG_TRACK_FUNCTION
#include <windows.h>
#include <stdio.h>
//#include "../app/foldhaus_platform.h"
//#include "../gs_libs/gs_win32.cpp"
#include "../app/platform_win32/win32_foldhaus_utils.h"
#include "../app/platform_win32/win32_foldhaus_memory.h"
#include "../app/platform_win32/win32_foldhaus_fileio.h"
#include "../app/platform_win32/win32_foldhaus_serial.h"
#include "../app/platform_win32/win32_foldhaus_work_queue.h"
#include "../app/engine/uart/foldhaus_uart.h"
u8*
FindNextHeader(gs_data Data, u8* StartAt)
{
u8* At = StartAt;
while (!(At[0] == 'U' &&
At[1] == 'P' &&
At[2] == 'X' &&
At[3] == 'L') &&
(u32)(At - Data.Memory) < Data.Size)
{
At++;
}
return At;
}
void
CreateMessage(gs_data* Data, u8 Count)
{
gs_memory_cursor WriteCursor = CreateMemoryCursor(*Data);
u32 Channels[] = {
0, 1, 2, 3, 4, 5, 6, 7,
16, 17, 18, 19, 20, 21, 22, 23,
//40, 41, 42, 43, 44, 45, 46, 47,
};
u8* FirstHeaderAddr = 0;
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++)
{
u32 ChannelIndex = Channels[j];
uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header);
UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812);
if (FirstHeaderAddr == 0)
{
FirstHeaderAddr = (u8*)Header;
}
uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel);
Channel->ElementsCount = 3;
Channel->ColorPackingOrder = 36; // 10010000
Channel->PixelsCount = 300;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u8* Pixel = PushArrayOnCursor(&WriteCursor, u8, 3);
Pixel[0] = Count;
Pixel[1] = 0;
Pixel[2] = 255 - Count;
}
uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer);
Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer));
}
uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header);
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL);
uart_footer* DrawAllFooter =
PushStructOnCursor(&WriteCursor, uart_footer);
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer);
}
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9");
Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1);
gs_const_string OutFileName = ConstString("./serial_dump.data");
if (false)
{
Win32SerialPort_SetRead(SerialHandle);
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
Win32SerialPort_SetRead(SerialHandle);
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data);
u8* SetChannelHeaderAddr = 0;
uart_header* SetChannelHeader = 0;
uart_header* DrawAllHeader = 0;
u8* ScanAt = Data.Memory;
do
{
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_SET_CHANNEL_WS2812)
{
printf("Set Channel:\n");
printf(" Channel: %d\n", Header->Channel);
printf(" Pixels: %d\n", ((uart_channel*)(Header + 1))->PixelsCount);
if (!SetChannelHeader)
{
SetChannelHeaderAddr = (u8*)Header;
SetChannelHeader = Header;
}
}
if (Header->RecordType == UART_DRAW_ALL)
{
printf("Draw All:\n");
printf(" Channel: %d\n", Header->Channel);
if (!DrawAllHeader)
{
DrawAllHeader= Header;
}
}
ScanAt += sizeof(uart_header);
}while(((u32)(ScanAt - Data.Memory + sizeof(uart_header)) < Data.Size));
uart_channel* Channel = (uart_channel*)(SetChannelHeader + 1);
u8* DataStart = (u8*)(Channel + 1);
uart_footer* Footer = (uart_footer*)(DataStart + (Channel->ElementsCount * Channel->PixelsCount));
u32 TestCRC = UART_CalculateCRC((u8*)SetChannelHeader, (u8*)(Footer));
uart_footer* DrawAllFooter = (uart_footer*)(DrawAllHeader + 1);
u32 DrawwAllCRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
HANDLE FileHandle = CreateFileA(OutFileName.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))
{
InvalidCodePath;
}
}
CloseHandle(FileHandle);
Win32SerialPort_Close(SerialHandle);
}
else if (true)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
u8 Count = 0;
while(true)
{
CreateMessage(&Data, ++Count);
Win32SerialPort_Write(SerialHandle, Data);
Sleep(100);
}
}
else if (false)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
gs_data Messages = {0};
u8* ScanAt = Data.Memory;
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* FirstHeader = (uart_header*)ScanAt;
ScanAt += sizeof(uart_header);
uart_header* LastHeader = 0;
do
{
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_DRAW_ALL)
{
LastHeader = Header;
}
ScanAt += sizeof(uart_header);
}while((u32)(ScanAt - Data.Memory) < Data.Size);
u8* OnePastLastByte = ((u8*)(LastHeader + 1)) + sizeof(uart_footer);
Messages.Memory = (u8*)FirstHeader;
Messages.Size = OnePastLastByte - Messages.Memory;
while (true)
{
Win32SerialPort_Write(SerialHandle, Messages);
Sleep(100);
}
}
return 0;
}
#define FIRST_CPP
#endif // FIRST_CPP

View File

@ -1,45 +1,5 @@
TODO FOLDHAUS TODO FOLDHAUS
STREAM #0: Metaprogramming
- Metaprogramming
- fix memory layout (remeber to profile before and after)
- use a base_allocator struct to track allocations to begin with
- introduce memory_arenas
- get rid of gs_bucket and gs_list or whatever, just use custom bucket lists
Profile 0:
Total Allocated Space: 1186150 bytes, or 1.131201 MB
Total Time: 0.062665 seconds
Profile 1:
Total Allocated Space: 1217890 bytes, or 1.161470 MB
Total Time: 0.061852 seconds
Profile 2:
Profile 3:
Converted many of the TokenAtEquals to TokenAtHashEquals
Total Allocated Space: 912143773 bytes, or 869.888089 MB
Total Time: 4.915469
- convert gs_memory_arena to using 64 bit integers
- investigate centralizing type table type creation in a similar place, rather than scattered all over
- Make everything truly platform agnostic
- Application DLL
- math.h: present for trig functions (though this is part of the c-std lib, so it should be everywhere)
- windows.h: only thing left is InterlockedIncrement and InterlockedAdd
- Meta Layer
- ???
STREAM #1: 3D Overhaul STREAM #1: 3D Overhaul
- Rendering (Working on this elsewhere) - Rendering (Working on this elsewhere)
- OpenGL 3 - OpenGL 3
@ -54,22 +14,15 @@ STREAM #1: 3D Overhaul
- leds always face camera - leds always face camera
- Sculptures - Sculptures
- store scale in the assembly definition file
- cache led vertex buffers - cache led vertex buffers
- custom sculpture update functions (for motion) - custom sculpture update functions (for motion)
- placing sculptures
- editing sculpture files (change universe output) - editing sculpture files (change universe output)
- led groups & subgroups - defined in file
- motion - motion
- Sculpture View - Sculpture View
- mouse spatial interaction - handles, and hover for info - mouse spatial interaction - handles, and hover for info
- debug capabilities (toggle strip/led/universe colors) - debug capabilities (toggle strip/led/universe colors)
STREAM #2: Memory
- Buckets & Lists
- On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place
- Internal Log File - Internal Log File
NOTE: This should not be a part of the debug system NOTE: This should not be a part of the debug system
- Save output log to a file continuously - Save output log to a file continuously
@ -77,11 +30,11 @@ STREAM #2: Memory
- Create a bar that displays the most recent error message - Create a bar that displays the most recent error message
- :ErrorLogging - :ErrorLogging
STREAM #3: Nodes
- Animation System - Animation System
- blending between animation - blending between animation
- layers - layers
- layer masks by sculpture - layer masks by sculpture
- layer masks by tag / value
- interface for animation system - interface for animation system
- add/remove layers - add/remove layers
- select blend modes - select blend modes
@ -90,23 +43,11 @@ STREAM #3: Nodes
- clips can have parameters that drive them? - clips can have parameters that drive them?
- clips cannot overlap eachother on the same layer - clips cannot overlap eachother on the same layer
- Node System
- automatic node layout
- blending node layouts
- workspace -> animation block
- generating node workspace as code
- compiling node workspace
- hotload compiled pattern sets
- Serialization - Serialization
- saving scenes - saving scenes
- saving node graphs
- saving animation timelines
- saving projects - saving projects
STRAM #4: Completeness STRAM #4: Completeness
- Win32 Platform Layer
- Enumerate Directory Contents (you started this in win32_foldhaus_fileio.h)
- Platform Layer - Platform Layer
- Mac Platform Layer - Mac Platform Layer
@ -137,27 +78,6 @@ Assembly -> SACN interface
BUGS BUGS
- Typing a period into a float value doesn't register. Problem here is that we arent' translating key presses into characters at the win32 layer. Need to do that. - Typing a period into a float value doesn't register. Problem here is that we arent' translating key presses into characters at the win32 layer. Need to do that.
Switch To Nodes
- BUG: Connect a solid color node to output then try and pick a color. I think temporary node buffers are
- overwriting other data when they get evaluated. Bigger solution is to create a system of working
- led buffers that get assigned to nodes as needed.
- gonna need to remove output node from the node lister
- delete nodes
- - Simplify node storage
- - investigate if node connections can be operated on separately from the node headers
- - UpdatedThisFrame can probably go into each connection
- - Allow insertion/deletion within connection table
- - Allow inerstion/deletion within header table
- - maintain free list of connections and headers
- separate node functionality from drawing the nodes
- - pull node position, size, etc out into a parallel data structure. after split names: node_header, interface_node
- - create separate files: foldhaus_node_engine, foldhaus_node_gui
- - store interface_nodes in binary tree
- - allow panning and zooming around the node canvas
- - Investigate why we're giving nodes bounds :NodesDontNeedToKnowTheirBounds
- selector node (has a list of connections that it can switch between)
- evaluation step (one node at a time)
Hardening Hardening
- Then we want to think about separating out mode render functions from mode update functions. Not sure its necessary but having something that operates like an update funciton but is called render is weird. Might want some sort of coroutine functionality in place, where modes can add and remove optional, parallel - Then we want to think about separating out mode render functions from mode update functions. Not sure its necessary but having something that operates like an update funciton but is called render is weird. Might want some sort of coroutine functionality in place, where modes can add and remove optional, parallel
update functions update functions
@ -190,3 +110,13 @@ Name
- Splash screen (like blender) (thisll be fun) - Splash screen (like blender) (thisll be fun)
- - Image importer (stb image? or find a png > bmp converter for the image you have) - - Image importer (stb image? or find a png > bmp converter for the image you have)
- - Display on startup - - Display on startup
STREAM #0: Metaprogramming
- Metaprogramming
- fix memory layout (remeber to profile before and after)
- Make everything truly platform agnostic
- Application DLL
- math.h: present for trig functions (though this is part of the c-std lib, so it should be everywhere)
- windows.h: only thing left is InterlockedIncrement and InterlockedAdd
- Meta Layer
- ???

View File

@ -1,3 +1,8 @@
x saving animation timelines
x Buckets & Lists
x On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place
BUGS BUGS
x if there is nothing in the filtered list when searching for a node, hitting enter still selects one x if there is nothing in the filtered list when searching for a node, hitting enter still selects one
x Search lister - returning from a filtered list that has zero elements to one that has a few, hotItem = -1 x Search lister - returning from a filtered list that has zero elements to one that has a few, hotItem = -1