Finished config implementation.

main
sixtenhugosson 2023-06-19 19:12:26 +02:00
parent aefb393dcc
commit cab0dac728
22 changed files with 1009 additions and 278 deletions

View File

@ -1,7 +1,20 @@
#include "vn_platform.h" #include "vn_platform.h"
#include "vn_platform.cpp" #include "vn_platform.cpp"
#if VN_INTERNAL
struct debug_settings
{
b32 RenderUIDebugRects;
b32 RenderFPSCounter;
};
per_thread debug_settings *DEBUG_DebugSettings = 0;
#endif
#include "vn_config.h" #include "vn_config.h"
#include "vn_tokenizer.h"
#include "vn_font.h" #include "vn_font.h"
#include "vn_text_op.h" #include "vn_text_op.h"
#include "vn_ui.h" #include "vn_ui.h"
@ -27,6 +40,10 @@ struct vn_state
ui UI; ui UI;
workspace Workspace; workspace Workspace;
animation_curve_state AnimationCurveState; animation_curve_state AnimationCurveState;
#if VN_INTERNAL
debug_settings DebugSettings;
#endif
}; };
VN_UPDATE_AND_RENDER(VN_UpdateAndRender) VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
@ -43,11 +60,24 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands); State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
State->Config = BootstrapPushStruct(config, Arena); State->Config = BootstrapPushStruct(config, Arena);
Config_BindEntry(State->Config, StrLit("Platform/RefreshRate"), Config_Entry_S32, &Input->RefreshRate); // sixten: Setup config binds and load current config.
{
Config_BindS32(State->Config, StrLit("Platform/RefreshRate"), &Input->RefreshRate, 60);
#if VN_INTERNAL
Config_BindB32(State->Config, StrLit("Dev/RenderUIDebugRects"), &State->DebugSettings.RenderUIDebugRects, 0);
Config_BindB32(State->Config, StrLit("Dev/RenderFPSCounter"), &State->DebugSettings.RenderFPSCounter, 0);
#endif
Config_ReadFile(State->Config, StrLit("config.vn"));
}
Workspace_Init(&State->Workspace); Workspace_Init(&State->Workspace);
} }
#if VN_INTERNAL
DEBUG_DebugSettings = &State->DebugSettings;
#endif
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame); AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP); UI_NewFrame(&State->UI, Input->EventList, Input->MouseP);
@ -58,6 +88,12 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
Event != 0; Event != 0;
Event = Event->Next) Event = Event->Next)
{ {
if(Event->Type == PlatformEvent_WindowClose)
{
Config_WriteFile(State->Config);
Input->ExitRequested = true;
}
Platform_ConsumeEvent(Input->EventList, Event); Platform_ConsumeEvent(Input->EventList, Event);
} }

View File

@ -18,7 +18,7 @@ inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String)
return(Key); return(Key);
} }
static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial = 0) static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial)
{ {
animation_curve_state *State = AnimationCurve_GetState(); animation_curve_state *State = AnimationCurve_GetState();

View File

@ -46,4 +46,14 @@ struct animation_curve_state
animation_curve_entry *LastFreeEntry; animation_curve_entry *LastFreeEntry;
}; };
inline void AnimationCurve_SetState(animation_curve_state *State);
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String);
static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial = 0);
inline r32 AnimationCurve_GetValue(string Name, r32 Initial);
inline void AnimationCurve_SetValue(string Name, r32 Value);
inline r32 AnimationCurve_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value);
inline r32 AnimationCurve_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name);
inline r32 AnimationCurve_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...);
static void AnimationCurve_NewFrame(animation_curve_state *State, r32 dtForFrame);
#endif //VN_ANIMATION_CURVE_H #endif //VN_ANIMATION_CURVE_H

View File

@ -19,30 +19,269 @@ static config_entry *Config_FindEntryByName(config *Config, string Name)
return(Result); return(Result);
} }
static void Config_ReadFile(config *Config, string Path)
{
}
static void Config_WriteFile(config *Config)
{
}
static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target) static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target)
{ {
config_entry *Entry = Config_FindEntryByName(Config, Name); config_entry *Entry = Config_FindEntryByName(Config, Name);
if(!Entry) if(!Entry)
{ {
Entry = PushStruct(&Config->Arena, config_entry); Entry = PushStruct(&Config->Arena, config_entry);
Entry->Name = Name; Entry->Name = PushString(&Config->Arena, Name);
Entry->Type = Type; Entry->Type = Type;
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets); u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot; config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot;
DLLInsertLast(Bucket->First, Bucket->Last, Entry); DLLInsertLast(Bucket->First, Bucket->Last, Entry);
if(Config->LastInternal)
{
Config->LastInternal->NextInternal = Entry;
Config->LastInternal = Entry;
}
else
{
Config->FirstInternal = Config->LastInternal = Entry;
}
} }
Assert(Entry->Type == Type); Assert(Entry->Type == Type);
Entry->Target = Target; Entry->Target = Target;
} }
inline void Config_BindS32(config *Config, string Name, s32 *Target, s32 Default)
{
*Target = Default;
Config_BindEntry(Config, Name, Config_Entry_S32, Target);
}
inline void Config_BindS64(config *Config, string Name, s64 *Target, s64 Default)
{
*Target = Default;
Config_BindEntry(Config, Name, Config_Entry_S64, Target);
}
inline void Config_BindB32(config *Config, string Name, b32 *Target, b32 Default)
{
*Target = Default;
Config_BindEntry(Config, Name, Config_Entry_B32, Target);
}
static void Config_ParseError(char *Message, memory_arena *Arena)
{
string String = PushFormat(Arena, "An error occured during config parsing:\n\"%s\"", Message);
Platform.ShowMessage(String, Platform_Message_Warning);
}
static void Config_ReadFile(config *Config, string Path)
{
temporary_memory Scratch = GetScratch();
tokenizer Tokenizer = Tokenizer_BeginTokenization(Platform_ReadEntireFile(Scratch.Arena, Path));
if(Tokenizer.Input.Data)
{
token Token;
for(;;)
{
Token = Tokenizer_GetNextToken(&Tokenizer);
if(Token.Type == Token_Identifier)
{
string Dir = Token.String;
if(Tokenizer_RequireToken(&Tokenizer, Token_CurlyOpen))
{
for(;;)
{
Token = Tokenizer_GetNextToken(&Tokenizer);
if(Token.Type == Token_Identifier)
{
string Name = Token.String;
if(Tokenizer_RequireToken(&Tokenizer, Token_Equals))
{
Token = Tokenizer_GetNextToken(&Tokenizer);
if(Token.Type == Token_IntegerValue)
{
s64 Value = ConvertStringToS64(Token.String);
string FullName = PushFormat(Scratch.Arena, "%S/%S", Dir, Name);
config_entry *Entry = Config_FindEntryByName(Config, FullName);
if(Entry)
{
if(Entry->Type == Config_Entry_S32)
{
*(s32 *)Entry->Target = (s32)Value;
}
else if(Entry->Type == Config_Entry_S64)
{
*(s64 *)Entry->Target = Value;
}
else
{
Config_ParseError("Entry has wrong data type.", Scratch.Arena);
goto End;
}
}
else
{
Config_ParseError("Cannot find entry.", Scratch.Arena);
goto End;
}
}
else if(Token.Type == Token_Identifier)
{
string FullName = PushFormat(Scratch.Arena, "%S/%S", Dir, Name);
config_entry *Entry = Config_FindEntryByName(Config, FullName);
if(Entry)
{
if(AreEqual(Token.String, StrLit("true")))
{
*(b32 *)Entry->Target = true;
}
else if(AreEqual(Token.String, StrLit("false")))
{
*(b32 *)Entry->Target = false;
}
else
{
Config_ParseError("Entry has wrong data type.", Scratch.Arena);
goto End;
}
}
else
{
Config_ParseError("Cannot find entry.", Scratch.Arena);
goto End;
}
}
else
{
Config_ParseError("Expected a value.", Scratch.Arena);
goto End;
}
if(!Tokenizer_RequireToken(&Tokenizer, Token_Semicolon))
{
Config_ParseError("Expected a ';'.", Scratch.Arena);
goto End;
}
}
else
{
Config_ParseError("Expected '='.", Scratch.Arena);
goto End;
}
}
else if(Token.Type == Token_CurlyClose)
{
break;
}
else
{
Config_ParseError("Expected '}' or identifier.", Scratch.Arena);
goto End;
}
}
}
else
{
Config_ParseError("Expected '{'.", Scratch.Arena);
goto End;
}
}
else if(Token.Type == Token_EndOfFile)
{
goto End;
}
else
{
Config_ParseError("Unexpected token.", Scratch.Arena);
goto End;
}
}
}
End:
ReleaseScratch(Scratch);
}
static void Config_WriteFile(config *Config)
{
string_list Out = {};
temporary_memory Scratch = GetScratch();
string LastDir = MakeString(0, 0);
for(config_entry *Entry = Config->FirstInternal;
Entry != 0;
Entry = Entry->NextInternal)
{
s64 LastSlash = LastIndexOf(Entry->Name, '/');
Assert(LastSlash != -1);
string Dir = Prefix(Entry->Name, LastSlash);
string Name = Suffix(Entry->Name, Entry->Name.Count - LastSlash - 1);
if(!AreEqual(Dir, LastDir))
{
if(!AreEqual(LastDir, MakeString(0, 0)))
{
AppendString(&Out, StrLit("}\n\n"), Scratch.Arena);
}
AppendString(&Out, Dir, Scratch.Arena);
AppendString(&Out, StrLit("\n{\n"), Scratch.Arena);
LastDir = Dir;
}
AppendString(&Out, StrLit("\t"), Scratch.Arena);
AppendString(&Out, Name, Scratch.Arena);
AppendString(&Out, StrLit(" = "), Scratch.Arena);
// sixten: Output the value of the entry
if(Entry->Type == Config_Entry_S32 || Entry->Type == Config_Entry_S64)
{
s64 IntegerValue;
if(Entry->Type == Config_Entry_S32)
{
IntegerValue = *(s32 *)Entry->Target;
}
else
{
IntegerValue = *(s64 *)Entry->Target;
}
string Value = ConvertS64ToString(IntegerValue, Scratch.Arena);
AppendString(&Out, Value, Scratch.Arena);
}
else if(Entry->Type == Config_Entry_B32)
{
string Value = (*(b32 *)Entry->Target)?StrLit("true"):StrLit("false");
AppendString(&Out, Value, Scratch.Arena);
}
else
{
UnimplementedCodepath;
}
AppendString(&Out, StrLit(";\n"), Scratch.Arena);
}
if(!AreEqual(LastDir, MakeString(0, 0)))
{
AppendString(&Out, StrLit("}"), Scratch.Arena);
}
string FinalOut = JoinStringList(&Out, Scratch.Arena);
platform_file_handle Handle = Platform.OpenFile(StrLit("config.vn"), PlatformAccess_Write);
if(Handle.IsValid)
{
Platform.WriteFile(Handle, FinalOut.Data, 0, FinalOut.Count);
Platform.CloseFile(Handle);
}
ReleaseScratch(Scratch);
}

View File

@ -18,6 +18,8 @@ struct config_entry
config_entry *Next; config_entry *Next;
config_entry *Prev; config_entry *Prev;
config_entry *NextInternal;
}; };
struct config_entry_bucket struct config_entry_bucket
@ -30,13 +32,20 @@ struct config
{ {
memory_arena Arena; memory_arena Arena;
config_entry_bucket EntryBuckets[32]; config_entry_bucket EntryBuckets[32];
// sixten(NOTE): Keeps track of the order in which the entries were declared. (Used during saving)
config_entry *FirstInternal;
config_entry *LastInternal;
}; };
static config_entry *Config_FindEntryByName(config *Config, string Name); static config_entry *Config_FindEntryByName(config *Config, string Name);
static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target);
inline void Config_BindS32(config *Config, string Name, s32 *Target, s32 Default);
inline void Config_BindS64(config *Config, string Name, s64 *Target, s64 Default);
inline void Config_BindB32(config *Config, string Name, b32 *Target, b32 Default);
static void Config_ReadFile(config *Config, string Path); static void Config_ReadFile(config *Config, string Path);
static void Config_WriteFile(config *Config); static void Config_WriteFile(config *Config);
static void Config_BindEntry(config *Config, string Name, config_entry_type, void *Target);
#endif //VN_CONFIG_H #endif //VN_CONFIG_H

View File

@ -66,8 +66,9 @@ IsNull(p) ? (SetNull((n)->prev), (n)->next = (f), (IsNull(f) ? (0) : ((f)->prev
#include "vn_types.h" #include "vn_types.h"
#include "vn_math.h" #include "vn_math.h"
#include "vn_string.h"
// sixten(TODO): Scuffed AF. Need to make a proper "core" of the codebase.
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint);
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "third_party/stb_sprintf.h" #include "third_party/stb_sprintf.h"
@ -126,6 +127,12 @@ inline void EndTicketMutex(ticket_mutex *Mutex)
AtomicAddU64(&Mutex->Serving, 1); AtomicAddU64(&Mutex->Serving, 1);
} }
inline b32 InRange(range_s64 Range, s64 P)
{
b32 Result = ((P >= Range.Min) && (P < Range.Max));
return(Result);
}
inline b32 InRange(range2_r32 Range, v2 P) inline b32 InRange(range2_r32 Range, v2 P)
{ {
b32 Result = ((P.x >= Range.Min.x) && b32 Result = ((P.x >= Range.Min.x) &&
@ -153,6 +160,12 @@ inline range2_r32 Range2R32(v2 A, v2 B)
return(Result); return(Result);
} }
inline s64 DimOfRange(range_s64 Range)
{
s64 Dim = Range.Max - Range.Min;
return(Dim);
}
inline v2 DimOfRange(range2_r32 Range) inline v2 DimOfRange(range2_r32 Range)
{ {
v2 Dim = Range.Max - Range.Min; v2 Dim = Range.Max - Range.Min;

View File

@ -23,6 +23,12 @@ inline r32 Ceil(r32 Value)
return(Result); return(Result);
} }
inline r32 Log(r32 Value)
{
r32 Result = logf(Value);
return(Result);
}
inline r32 Pow(r32 Base, r32 Exponent) inline r32 Pow(r32 Base, r32 Exponent)
{ {
r32 Result = powf(Base, Exponent); r32 Result = powf(Base, Exponent);
@ -48,6 +54,18 @@ inline b32 AreAlmostEqual(r32 A, r32 B)
return(Result); return(Result);
} }
inline s64 Min(s64 A, s64 B)
{
s64 Result = Minimum(A, B);
return(Result);
}
inline s64 Max(s64 A, s64 B)
{
s64 Result = Maximum(A, B);
return(Result);
}
inline v2s operator+(v2s A, v2s B) inline v2s operator+(v2s A, v2s B)
{ {
v2s Result = {A.x + B.x, A.y + B.y}; v2s Result = {A.x + B.x, A.y + B.y};

View File

@ -209,6 +209,9 @@ inline string PushFormat(memory_arena *Arena, char *Format, ...)
return(Result); return(Result);
} }
// sixten(TODO): Scuffed AF. Need to make a proper "core" of the codebase.
inline s64 StringLength(char *String);
inline string PushCString(memory_arena *Arena, char *CString) inline string PushCString(memory_arena *Arena, char *CString)
{ {
string Result; string Result;

View File

@ -44,6 +44,9 @@ typedef PLATFORM_CLOSE_FILE(platform_close_file);
#define PLATFORM_READ_FILE(name) void name(platform_file_handle Handle, void *Dest, u64 Offset, u64 Size) #define PLATFORM_READ_FILE(name) void name(platform_file_handle Handle, void *Dest, u64 Offset, u64 Size)
typedef PLATFORM_READ_FILE(platform_read_file); typedef PLATFORM_READ_FILE(platform_read_file);
#define PLATFORM_WRITE_FILE(name) void name(platform_file_handle Handle, void *Source, u64 Offset, u64 Size)
typedef PLATFORM_WRITE_FILE(platform_write_file);
#define PLATFORM_GET_FILE_SIZE(name) u64 name(platform_file_handle Handle) #define PLATFORM_GET_FILE_SIZE(name) u64 name(platform_file_handle Handle)
typedef PLATFORM_GET_FILE_SIZE(platform_get_file_size); typedef PLATFORM_GET_FILE_SIZE(platform_get_file_size);
@ -71,6 +74,17 @@ typedef PLATFORM_SET_CURSOR(platform_set_cursor);
#define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void) #define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void)
typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen); typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen);
enum platform_message_type
{
Platform_Message_Info,
Platform_Message_Warning,
Platform_Message_Error,
Platform_Message_Fatal,
};
#define PLATFORM_SHOW_MESSAGE(name) void name(string Message, platform_message_type Type)
typedef PLATFORM_SHOW_MESSAGE(platform_show_message);
struct platform_api struct platform_api
{ {
platform_allocate_memory *AllocateMemory; platform_allocate_memory *AllocateMemory;
@ -79,10 +93,12 @@ struct platform_api
platform_open_file *OpenFile; platform_open_file *OpenFile;
platform_close_file *CloseFile; platform_close_file *CloseFile;
platform_read_file *ReadFile; platform_read_file *ReadFile;
platform_write_file *WriteFile;
platform_get_file_size *GetFileSize; platform_get_file_size *GetFileSize;
platform_set_cursor *SetCursor; platform_set_cursor *SetCursor;
platform_toggle_fullscreen *ToggleFullscreen; platform_toggle_fullscreen *ToggleFullscreen;
platform_show_message *ShowMessage;
}; };
enum platform_event_type enum platform_event_type
@ -91,6 +107,7 @@ enum platform_event_type
PlatformEvent_Release, PlatformEvent_Release,
PlatformEvent_Text, PlatformEvent_Text,
PlatformEvent_MouseScroll, PlatformEvent_MouseScroll,
PlatformEvent_WindowClose,
}; };
enum platform_key enum platform_key
@ -201,6 +218,7 @@ struct vn_input
// sixten: Application to platform // sixten: Application to platform
s32 RefreshRate; s32 RefreshRate;
b32 ExitRequested;
}; };
struct vn_memory struct vn_memory

View File

@ -12,6 +12,18 @@ inline b32 IsWhitespace(char C)
return(Result); return(Result);
} }
inline b32 IsDigit(char C)
{
b32 Result = ((C >= '0') && (C <= '9'));
return(Result);
}
inline b32 IsLetter(char C)
{
b32 Result = ((C >= 'A') && (C <= 'Z')) || ((C >= 'a') && (C <= 'z'));
return(Result);
}
inline s64 StringLength(char *String) inline s64 StringLength(char *String)
{ {
s64 Result = 0; s64 Result = 0;
@ -22,6 +34,12 @@ inline s64 StringLength(char *String)
return(Result); return(Result);
} }
inline string MakeStringFromCString(char *Data)
{
string Result = {StringLength(Data), (u8 *)Data};
return(Result);
}
inline u64 HashString(string String) inline u64 HashString(string String)
{ {
u64 Result = 5731; u64 Result = 5731;
@ -38,12 +56,6 @@ inline u64 HashString(string String)
return(Result); return(Result);
} }
inline string MakeStringFromCString(char *Data)
{
string Result = {StringLength(Data), (u8 *)Data};
return(Result);
}
inline b32 AreEqual(string A, string B) inline b32 AreEqual(string A, string B)
{ {
b32 Result = false; b32 Result = false;
@ -118,6 +130,86 @@ inline s64 LastIndexOf(string String, string Substring)
return(Result); return(Result);
} }
static s64 ConvertStringToS64(string String)
{
s64 Result = 0;
b32 IsNegative = false;
s64 Index = 0;
if(String.Data[Index] == '-')
{
IsNegative = true;
++Index;
}
for(;Index < String.Count; ++Index)
{
u8 Char = String.Data[Index];
Assert(IsDigit(Char));
Result = Result*10 + (Char-'0');
}
if(IsNegative)
{
Result = -Result;
}
return(Result);
}
static string ConvertS64ToString(s64 Value, memory_arena *Arena)
{
b32 IsNegative = (Value < 0);
if(IsNegative)
{
Value = -Value;
}
s64 DigitCount = (s64)Floor(Log(Max(Value, 1)) / Log(10)) + 1;
s64 TotalBufferCount = DigitCount + IsNegative;
string String = {TotalBufferCount, PushArray(Arena, u8, TotalBufferCount + 1)};
String.Data[TotalBufferCount] = 0;
if(IsNegative)
{
String.Data[0] = '-';
}
for(s64 Index = 0;
Index < DigitCount;
++Index)
{
String.Data[TotalBufferCount - 1 - Index] = '0' + (Value % 10);
Value /= 10;
}
return(String);
}
static string Substring(string String, range_s64 Range)
{
string Result = MakeString((char *)String.Data + Range.Min, DimOfRange(Range));
return(Result);
}
static string Prefix(string String, s64 Count)
{
range_s64 Range = RangeS64(0, Count);
string Result = Substring(String, Range);
return(Result);
}
static string Suffix(string String, s64 Count)
{
range_s64 Range = RangeS64(String.Count - Count, String.Count);
string Result = Substring(String, Range);
return(Result);
}
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint) static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
{ {
s64 Length = 0; s64 Length = 0;
@ -244,4 +336,38 @@ inline utf8_iterator IterateUTF8String(string String)
return(Iter); return(Iter);
} }
static void AppendString(string_list *List, string String, memory_arena *Arena)
{
string_node *Node = PushStruct(Arena, string_node);
Node->String = String;
List->TotalCount += String.Count;
DLLInsertLast(List->First, List->Last, Node);
}
static string JoinStringList(string_list *List, memory_arena *Arena)
{
u8 *Buffer = PushArray(Arena, u8, List->TotalCount + 1);
Buffer[List->TotalCount] = 0;
s64 GlobalIndex = 0;
for(string_node *Node = List->First;
Node != 0;
Node = Node->Next)
{
string String = Node->String;
for(s64 Index = 0;
Index < String.Count;
++Index)
{
Buffer[GlobalIndex++] = String.Data[Index];
}
}
string Result = MakeString((char *)Buffer, List->TotalCount);
return(Result);
}
#endif //VN_STRING_H #endif //VN_STRING_H

View File

@ -22,7 +22,7 @@ inline thread_context *GetThreadContext(void)
return(ThreadLocal_ThreadContext); return(ThreadLocal_ThreadContext);
} }
static temporary_memory GetScratch(memory_arena **Conflicts, u64 ConflictCount) static temporary_memory GetScratch(memory_arena **Conflicts = 0, u64 ConflictCount = 0)
{ {
temporary_memory Scratch = {}; temporary_memory Scratch = {};
thread_context *Context = GetThreadContext(); thread_context *Context = GetThreadContext();

122
code/vn_tokenizer.h 100644
View File

@ -0,0 +1,122 @@
/* date = June 18th 2023 5:12 pm */
#ifndef VN_TOKENIZER_H
#define VN_TOKENIZER_H
enum token_type
{
Token_EndOfFile,
Token_Identifier,
Token_IntegerValue,
//Token_RealValue,
Token_CurlyOpen,
Token_CurlyClose,
Token_Semicolon,
Token_Equals,
};
struct tokenizer
{
string Input;
s64 At;
s64 Index;
};
struct token
{
token_type Type;
string String;
};
inline tokenizer Tokenizer_BeginTokenization(string Input)
{
tokenizer Result = {};
Result.Input = Input;
return(Result);
}
static token Tokenizer_GetNextToken(tokenizer *Tokenizer)
{
token Token = {};
string Input = Tokenizer->Input;
u8 *Base = Input.Data;
// sixten: Consume whitespace
while(IsWhitespace(Base[Tokenizer->Index]))
{
++Tokenizer->Index;
}
// sixten(NOTE): Assume single char token.
Token.String.Data = Base + Tokenizer->Index;
Token.String.Count = 1;
if(Tokenizer->Index < Input.Count)
{
switch(Base[Tokenizer->Index])
{
case '{': { Token.Type = Token_CurlyOpen; } break;
case '}': { Token.Type = Token_CurlyClose; } break;
case ';': { Token.Type = Token_Semicolon; } break;
case '=': { Token.Type = Token_Equals; } break;
default:
{
if(IsDigit(Base[Tokenizer->Index]) || Base[Tokenizer->Index] == '-')
{
// sixten: Parse integer number
Token.Type = Token_IntegerValue;
Token.String.Data = Base + Tokenizer->Index;
Token.String.Count = 0;
while(IsDigit(Token.String.Data[Token.String.Count]) || Token.String.Data[Token.String.Count] == '-')
{
++Token.String.Count;
}
}
else
{
// sixten: Parse tokenizer
Token.Type = Token_Identifier;
Token.String.Data = Base + Tokenizer->Index;
Token.String.Count = 0;
while(IsDigit(Token.String.Data[Token.String.Count]) ||
IsLetter(Token.String.Data[Token.String.Count]))
{
++Token.String.Count;
}
}
} break;
}
}
else
{
Token.Type = Token_EndOfFile;
}
Tokenizer->Index += Token.String.Count;
return(Token);
}
inline token Tokenizer_PeekNextToken(tokenizer Tokenizer)
{
// sixten(NOTE): Yup, we just make a copy of the tokenizer and read the next token.
token Result = Tokenizer_GetNextToken(&Tokenizer);
return(Result);
}
inline b32 Tokenizer_RequireToken(tokenizer *Tokenizer, token_type Type)
{
token Token = Tokenizer_GetNextToken(Tokenizer);
b32 Result = (Token.Type == Type);
return(Result);
}
#endif //VN_TOKENIZER_H

View File

@ -70,6 +70,21 @@ inline string MakeString16(wchar_t *Data, s64 Count)
return(Result); return(Result);
} }
struct string_node
{
string String;
string_node *Next;
string_node *Prev;
};
struct string_list
{
string_node *First;
string_node *Last;
s64 TotalCount;
};
struct v2s struct v2s
{ {
s32 x, y; s32 x, y;

View File

@ -1,3 +1,36 @@
#include "generated/vn_generated_ui.cpp"
inline ui_size UI_Pixels(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_Pixels, Value, Strictness};
return(Result);
}
inline ui_size UI_Em(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_Pixels, Value*UI_TopFontSize(), Strictness};
return(Result);
}
inline ui_size UI_TextContent(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_TextContent, Value, Strictness};
return(Result);
}
inline ui_size UI_Percent(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_PercentOfParent, Value, Strictness};
return(Result);
}
inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_ChildrenSum, Value, Strictness};
return(Result);
}
per_thread ui *ThreadLocal_UI; per_thread ui *ThreadLocal_UI;
inline void UI_SetState(ui *UI) inline void UI_SetState(ui *UI)
@ -193,8 +226,6 @@ inline ui_box *UI_GetBoxByKey(ui *UI, ui_key Key)
return(Result); return(Result);
} }
#include "generated/vn_generated_ui.cpp"
inline ui_box *UI_MakeBox(ui_box_flags Flags, string String) inline ui_box *UI_MakeBox(ui_box_flags Flags, string String)
{ {
ui *UI = UI_GetState(); ui *UI = UI_GetState();
@ -231,6 +262,12 @@ inline ui_box *UI_MakeBox(ui_box_flags Flags, string String)
Box->Flags = Flags; Box->Flags = Flags;
Box->String = PushString(&UI->FrameArena, String); Box->String = PushString(&UI->FrameArena, String);
s64 HashIndex = LastIndexOf(Box->String, '#');
if(HashIndex != -1)
{
Box->String = Prefix(Box->String, HashIndex);
}
UI_ApplyStyles(Box); UI_ApplyStyles(Box);
if(Parent) if(Parent)
@ -620,12 +657,16 @@ static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas
Box->DrawCallback(Group, GlyphAtlas, Box, Box->DrawCallbackData); Box->DrawCallback(Group, GlyphAtlas, Box, Box->DrawCallbackData);
} }
#if 0 // sixten: Render debug rects around boxes. #if VN_INTERNAL
if(DEBUG_DebugSettings->RenderUIDebugRects)
{
// sixten: Render debug rects around boxes.
r32 R = (((Box->Key.Value >> 0) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1)); r32 R = (((Box->Key.Value >> 0) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
r32 G = (((Box->Key.Value >> 21) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1)); r32 G = (((Box->Key.Value >> 21) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
r32 B = (((Box->Key.Value >> 42) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1)); r32 B = (((Box->Key.Value >> 42) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
v4 Red = V4(R, G, B, 1); v4 Red = V4(R, G, B, 1);
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8); PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8);
}
#endif #endif
if(Box->Flags & UI_BoxFlag_Clip) if(Box->Flags & UI_BoxFlag_Clip)

View File

@ -46,29 +46,11 @@ struct ui_size
r32 Strictness; r32 Strictness;
}; };
inline ui_size UI_Pixels(r32 Value, r32 Strictness) inline ui_size UI_Pixels(r32 Value, r32 Strictness);
{ inline ui_size UI_Em(r32 Value, r32 Strictness);
ui_size Result = {UI_SizeType_Pixels, Value, Strictness}; inline ui_size UI_TextContent(r32 Value, r32 Strictness);
return(Result); inline ui_size UI_Percent(r32 Value, r32 Strictness);
} inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness);
inline ui_size UI_TextContent(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_TextContent, Value, Strictness};
return(Result);
}
inline ui_size UI_Percent(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_PercentOfParent, Value, Strictness};
return(Result);
}
inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness)
{
ui_size Result = {UI_SizeType_ChildrenSum, Value, Strictness};
return(Result);
}
typedef void ui_draw_callback(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data); typedef void ui_draw_callback(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data);

View File

@ -164,3 +164,34 @@ static ui_signal UI_ButtonF(char *Format, ...)
return(Signal); return(Signal);
} }
static ui_signal UI_Checkbox(string String, b32 *Checked)
{
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
UI_SetNextLayoutAxis(Axis2_X);
ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
UI_Parent(ContainerBox)
{
r32 OpacityTransition = AnimationCurve_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
v4 TextColor = UI_TopTextColor();
TextColor.a = OpacityTransition;
UI_Size(UI_Em(1, 1), UI_Em(1, 1)) UI_Font(Font_Icons) UI_TextColor(TextColor)
UI_MakeBoxF(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
UI_Size(UI_TextContent(15, 1), UI_Em(1, 1)) UI_Label(String);
}
ui_signal Signal = UI_SignalFromBox(ContainerBox);
if(Signal.Hovering)
{
Platform.SetCursor(PlatformCursor_Hand);
}
if(Signal.Pressed)
{
*Checked = !*Checked;
}
return(Signal);
}

View File

@ -150,8 +150,6 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
Workspace_BuildToolbarButton(Workspace, "Panel", ToolbarMenu_Panel); Workspace_BuildToolbarButton(Workspace, "Panel", ToolbarMenu_Panel);
Workspace_BuildToolbarButton(Workspace, "View", ToolbarMenu_View); Workspace_BuildToolbarButton(Workspace, "View", ToolbarMenu_View);
Workspace_BuildToolbarButton(Workspace, "Window", ToolbarMenu_Window); Workspace_BuildToolbarButton(Workspace, "Window", ToolbarMenu_Window);
UI_Spacer(UI_Percent(1, 0));
} }
if(Workspace->Menu != ToolbarMenu_None) if(Workspace->Menu != ToolbarMenu_None)
@ -721,9 +719,10 @@ static void Workspace_Init(workspace *Workspace)
} }
} }
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands, vn_input *Input, static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
glyph_atlas *GlyphAtlas) vn_input *Input, glyph_atlas *GlyphAtlas)
{ {
Workspace->Input = Input;
Workspace->EventList = Input->EventList; Workspace->EventList = Input->EventList;
// sixten: Process last frame's commands. // sixten: Process last frame's commands.

View File

@ -68,6 +68,7 @@ struct workspace_drag_payload
struct workspace struct workspace
{ {
vn_input *Input;
platform_event_list *EventList; platform_event_list *EventList;
// sixten: Command Allocation // sixten: Command Allocation

View File

@ -225,7 +225,7 @@ static void Workspace_BuildSettingsTabButton(workspace_view_settings *Settings,
{ {
b32 IsSelected = (Settings->Category == Category); b32 IsSelected = (Settings->Category == Category);
v4 Color = LinearBlend(Theme_TextColor, Theme_HighlightBorderColor, AnimationCurve_AnimateValueF(IsSelected, 0, 0.3, "Workspace Settings %s %p", Name, Settings)); v4 Color = LinearBlend(Theme_TextColor, Theme_HighlightBorderColor, AnimationCurve_AnimateValueF(IsSelected, IsSelected, 0.3, "Workspace Settings %s %p", Name, Settings));
UI_SetNextFont(Font_Bold); UI_SetNextFont(Font_Bold);
UI_SetNextHeight(UI_TextContent(0, 1)); UI_SetNextHeight(UI_TextContent(0, 1));
@ -386,10 +386,30 @@ static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View)
char *Alternatives[] = {"60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"}; char *Alternatives[] = {"60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
persist b32 DropdownOpen = false; persist b32 DropdownOpen = false;
persist s32 DropdownSelected = 0;
s32 DropdownSelected;
switch(Workspace->Input->RefreshRate)
{
case 60: { DropdownSelected = 0; } break;
case 120:{ DropdownSelected = 1; } break;
case 144:{ DropdownSelected = 2; } break;
case -1: { DropdownSelected = 3; } break;
case 0: { DropdownSelected = 4; } break;
default: { DropdownSelected = 0; } break;
}
if(UI_DropdownSelection(Alternatives, ArrayCount(Alternatives), &DropdownOpen, &DropdownSelected)) if(UI_DropdownSelection(Alternatives, ArrayCount(Alternatives), &DropdownOpen, &DropdownSelected))
{ {
switch(DropdownSelected)
{
case 0: { Workspace->Input->RefreshRate = 60; } break;
case 1: { Workspace->Input->RefreshRate = 120; } break;
case 2: { Workspace->Input->RefreshRate = 144; } break;
case 3: { Workspace->Input->RefreshRate = -1; } break;
case 4: { Workspace->Input->RefreshRate = 0; } break;
InvalidDefaultCase;
}
DropdownOpen = false; DropdownOpen = false;
} }
@ -399,12 +419,9 @@ static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View)
if(!Category || (Category == Workspace_Settings_Developer)) if(!Category || (Category == Workspace_Settings_Developer))
{ {
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer"); UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer");
UI_LabelF("Render UI Debug Rects:"); UI_Checkbox(StrLit("Render UI Debug Rects"), &DEBUG_DebugSettings->RenderUIDebugRects);
UI_LabelF("Render FPS Counter:"); UI_Spacer(UI_Pixels(5, 1));
UI_Checkbox(StrLit("Render FPS Counter"), &DEBUG_DebugSettings->RenderFPSCounter);
UI_CornerRadius(4)
UI_Size(UI_TextContent(20, 1), UI_TextContent(10, 1))
UI_ButtonF("Hello Line Paint Color Design Address Brightness");
UI_Spacer(UI_Pixels(50, 1)); UI_Spacer(UI_Pixels(50, 1));
} }

View File

@ -8,13 +8,12 @@
#include "win32_main.h" #include "win32_main.h"
#include "win32_opengl.cpp" #include "win32_opengl.cpp"
global b32 Global_Running;
global win32_state Global_Win32State; global win32_state Global_Win32State;
global WINDOWPLACEMENT Global_WindowPosition = {sizeof(Global_WindowPosition)};; global WINDOWPLACEMENT Global_WindowPosition = {sizeof(Global_WindowPosition)};;
static void Win32_PlatformError(char *Message, bool IsFatal) static void Win32_PlatformError(char *Message, bool IsFatal)
{ {
MessageBoxA(0, Message, "nv - Platform Error", MB_OK|(IsFatal?MB_ICONSTOP:MB_ICONEXCLAMATION)); MessageBoxA(0, Message, "vn - Platform Error", MB_OK|(IsFatal?MB_ICONSTOP:MB_ICONEXCLAMATION));
if(IsFatal) if(IsFatal)
{ {
@ -22,6 +21,30 @@ static void Win32_PlatformError(char *Message, bool IsFatal)
} }
} }
static PLATFORM_SHOW_MESSAGE(Win32_ShowMessage)
{
DWORD Flags = MB_OK;
switch(Type)
{
case Platform_Message_Info: { Flags |= MB_ICONINFORMATION; } break;
case Platform_Message_Warning: { Flags |= MB_ICONWARNING; } break;
case Platform_Message_Error: { Flags |= MB_ICONEXCLAMATION; } break;
case Platform_Message_Fatal: { Flags |= MB_ICONSTOP; } break;
InvalidDefaultCase;
}
// sixten(NOTE): Check for null-termination.
Assert(Message.Data[Message.Count] == 0);
MessageBoxA(0, (char *)Message.Data, "vn - A message from the developer", Flags);
if(Type == Platform_Message_Fatal)
{
ExitProcess((UINT)-1);
}
}
static PLATFORM_ALLOCATE_MEMORY(Win32_AllocateMemory) static PLATFORM_ALLOCATE_MEMORY(Win32_AllocateMemory)
{ {
win32_state *State = &Global_Win32State; win32_state *State = &Global_Win32State;
@ -83,6 +106,10 @@ static PLATFORM_OPEN_FILE(Win32_OpenFile)
{ {
CreationAttributes = OPEN_EXISTING; CreationAttributes = OPEN_EXISTING;
} }
if(FileAccess & PlatformAccess_Write)
{
CreationAttributes = CREATE_ALWAYS;
}
temporary_memory Scratch = GetScratch(0, 0); temporary_memory Scratch = GetScratch(0, 0);
@ -119,6 +146,18 @@ static PLATFORM_READ_FILE(Win32_ReadFile)
} }
} }
static PLATFORM_WRITE_FILE(Win32_WriteFile)
{
HANDLE File = (HANDLE)Handle.Platform;
if(File != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten;
WriteFile(File, Source, Size, &BytesWritten, 0);
Assert(BytesWritten == Size);
}
}
static PLATFORM_GET_FILE_SIZE(Win32_GetFileSize) static PLATFORM_GET_FILE_SIZE(Win32_GetFileSize)
{ {
u64 Result = 0; u64 Result = 0;
@ -307,7 +346,8 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
{ {
case WM_CLOSE: case WM_CLOSE:
{ {
Global_Running = false; Event = PushStruct(&State->EventArena, platform_event);
Event->Type = PlatformEvent_WindowClose;
} break; } break;
case WM_WINDOWPOSCHANGED: case WM_WINDOWPOSCHANGED:
@ -604,7 +644,7 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
State->MemorySentinel.Next = &State->MemorySentinel; State->MemorySentinel.Next = &State->MemorySentinel;
State->MemorySentinel.Prev = &State->MemorySentinel; State->MemorySentinel.Prev = &State->MemorySentinel;
State->SleepIsGranular = (timeBeginPeriod(1) != TIMERR_NOERROR); State->SleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR);
} }
// sixten: Setup platform layer // sixten: Setup platform layer
@ -614,9 +654,11 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
Platform.OpenFile = Win32_OpenFile; Platform.OpenFile = Win32_OpenFile;
Platform.CloseFile = Win32_CloseFile; Platform.CloseFile = Win32_CloseFile;
Platform.ReadFile = Win32_ReadFile; Platform.ReadFile = Win32_ReadFile;
Platform.WriteFile = Win32_WriteFile;
Platform.GetFileSize = Win32_GetFileSize; Platform.GetFileSize = Win32_GetFileSize;
Platform.SetCursor = Win32_SetCursor; Platform.SetCursor = Win32_SetCursor;
Platform.ToggleFullscreen = Win32_ToggleFullscreen; Platform.ToggleFullscreen = Win32_ToggleFullscreen;
Platform.ShowMessage = Win32_ShowMessage;
} }
WNDCLASS WindowClass = {}; WNDCLASS WindowClass = {};
@ -639,9 +681,9 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
Global_Win32State.Window = Window; Global_Win32State.Window = Window;
vn_input Input = {}; vn_input Input = {};
vn_render_commands RenderCommands = {};
// sixten: Setup OpenGL // sixten: Setup OpenGL
vn_render_commands RenderCommands = {};
HDC DeviceContext = GetDC(Window); HDC DeviceContext = GetDC(Window);
Win32_CreateOpenGLContext(DeviceContext); Win32_CreateOpenGLContext(DeviceContext);
opengl_context OpenGLContext = OpenGL_SetupContext(&RenderCommands, 16*1024); opengl_context OpenGLContext = OpenGL_SetupContext(&RenderCommands, 16*1024);
@ -655,8 +697,7 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
u64 CurrentTime = Win32_GetWallClock(); u64 CurrentTime = Win32_GetWallClock();
Global_Running = true; while(!Input.ExitRequested)
while(Global_Running)
{ {
u64 NewTime = Win32_GetWallClock(); u64 NewTime = Win32_GetWallClock();
r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime); r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime);

10
config.vn 100644
View File

@ -0,0 +1,10 @@
Platform
{
RefreshRate = 60;
}
Dev
{
RenderUIDebugRects = false;
RenderFPSCounter = false;
}

View File