merging in dev. Latest Stable Build: October 24, 2020
This commit is contained in:
commit
9847c991d9
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 }, \
|
|
@ -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;
|
|
@ -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);
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
enum panel_type {
|
|
||||||
};
|
|
||||||
global_variable s32 GlobalPanelDefsCount = 0;
|
|
||||||
global_variable panel_definition GlobalPanelDefs[] = {
|
|
||||||
};
|
|
|
@ -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;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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];
|
|
@ -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();
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
92
src/todo.txt
92
src/todo.txt
|
@ -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
|
||||||
|
- ???
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue