From cab0dac728b0802182d26ac7108347151c8c9bf4 Mon Sep 17 00:00:00 2001 From: sixtenhugosson Date: Mon, 19 Jun 2023 19:12:26 +0200 Subject: [PATCH] Finished config implementation. --- code/vn.cpp | 114 ++++++--- code/vn_animation_curve.cpp | 2 +- code/vn_animation_curve.h | 10 + code/vn_config.cpp | 259 +++++++++++++++++++- code/vn_config.h | 13 +- code/vn_core.h | 15 +- code/vn_math.h | 18 ++ code/vn_memory.h | 3 + code/vn_platform.h | 18 ++ code/vn_string.h | 474 +++++++++++++++++++++++------------- code/vn_thread_context.h | 2 +- code/vn_tokenizer.h | 122 ++++++++++ code/vn_types.h | 15 ++ code/vn_ui.cpp | 57 ++++- code/vn_ui.h | 28 +-- code/vn_ui_utils.cpp | 31 +++ code/vn_workspace.cpp | 7 +- code/vn_workspace.h | 1 + code/vn_workspace_view.cpp | 33 ++- code/win32_main.cpp | 55 ++++- config.vn | 10 + config/config.vn | 0 22 files changed, 1009 insertions(+), 278 deletions(-) create mode 100644 code/vn_tokenizer.h create mode 100644 config.vn delete mode 100644 config/config.vn diff --git a/code/vn.cpp b/code/vn.cpp index 0445e71..4899866 100644 --- a/code/vn.cpp +++ b/code/vn.cpp @@ -1,7 +1,20 @@ #include "vn_platform.h" #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_tokenizer.h" #include "vn_font.h" #include "vn_text_op.h" #include "vn_ui.h" @@ -19,50 +32,73 @@ struct vn_state { - memory_arena Arena; - glyph_atlas *GlyphAtlas; - - config *Config; - - ui UI; - workspace Workspace; - animation_curve_state AnimationCurveState; + memory_arena Arena; + glyph_atlas *GlyphAtlas; + + config *Config; + + ui UI; + workspace Workspace; + animation_curve_state AnimationCurveState; + +#if VN_INTERNAL + debug_settings DebugSettings; +#endif }; VN_UPDATE_AND_RENDER(VN_UpdateAndRender) { - SetThreadContext(ThreadContext); - Platform = Memory->PlatformAPI; - - vn_state *State = Memory->State; - - if(!Memory->State) - { - State = Memory->State = BootstrapPushStruct(vn_state, Arena); + SetThreadContext(ThreadContext); + Platform = Memory->PlatformAPI; - State->GlyphAtlas = CreateGlyphAtlas(RenderCommands); - State->Config = BootstrapPushStruct(config, Arena); + vn_state *State = Memory->State; - Config_BindEntry(State->Config, StrLit("Platform/RefreshRate"), Config_Entry_S32, &Input->RefreshRate); + if(!Memory->State) + { + State = Memory->State = BootstrapPushStruct(vn_state, Arena); + + State->GlyphAtlas = CreateGlyphAtlas(RenderCommands); + State->Config = BootstrapPushStruct(config, Arena); + + // 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); - } - - AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame); - UI_NewFrame(&State->UI, Input->EventList, Input->MouseP); - - Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas); - UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere. - - for(platform_event *Event = Input->EventList->First; - Event != 0; - Event = Event->Next) - { - Platform_ConsumeEvent(Input->EventList, Event); - } - - render_group Group = BeginRenderGroup(RenderCommands); - PushClear(&Group, V3(0.1, 0.1, 0.1)); - - UI_RenderFrame(&Group, State->GlyphAtlas); +#if VN_INTERNAL + DEBUG_DebugSettings = &State->DebugSettings; +#endif + + AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame); + UI_NewFrame(&State->UI, Input->EventList, Input->MouseP); + + Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas); + UI_SignalFromBox(UI_GetState()->ContainerNode); // sixten(TODO): Move elsewhere. + + for(platform_event *Event = Input->EventList->First; + Event != 0; + Event = Event->Next) + { + if(Event->Type == PlatformEvent_WindowClose) + { + Config_WriteFile(State->Config); + Input->ExitRequested = true; + } + + Platform_ConsumeEvent(Input->EventList, Event); + } + + render_group Group = BeginRenderGroup(RenderCommands); + PushClear(&Group, V3(0.1, 0.1, 0.1)); + + UI_RenderFrame(&Group, State->GlyphAtlas); } \ No newline at end of file diff --git a/code/vn_animation_curve.cpp b/code/vn_animation_curve.cpp index 883779f..53a9fbf 100644 --- a/code/vn_animation_curve.cpp +++ b/code/vn_animation_curve.cpp @@ -18,7 +18,7 @@ inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String) 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(); diff --git a/code/vn_animation_curve.h b/code/vn_animation_curve.h index f3031e6..794f066 100644 --- a/code/vn_animation_curve.h +++ b/code/vn_animation_curve.h @@ -46,4 +46,14 @@ struct animation_curve_state 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 diff --git a/code/vn_config.cpp b/code/vn_config.cpp index 9f86a17..abc9dee 100644 --- a/code/vn_config.cpp +++ b/code/vn_config.cpp @@ -19,30 +19,269 @@ static config_entry *Config_FindEntryByName(config *Config, string Name) 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) { config_entry *Entry = Config_FindEntryByName(Config, Name); if(!Entry) { Entry = PushStruct(&Config->Arena, config_entry); - Entry->Name = Name; + Entry->Name = PushString(&Config->Arena, Name); Entry->Type = Type; u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets); config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot; 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); 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); } \ No newline at end of file diff --git a/code/vn_config.h b/code/vn_config.h index 9c1dc73..2c972f4 100644 --- a/code/vn_config.h +++ b/code/vn_config.h @@ -18,6 +18,8 @@ struct config_entry config_entry *Next; config_entry *Prev; + + config_entry *NextInternal; }; struct config_entry_bucket @@ -30,13 +32,20 @@ struct config { memory_arena Arena; 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 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_WriteFile(config *Config); -static void Config_BindEntry(config *Config, string Name, config_entry_type, void *Target); - #endif //VN_CONFIG_H diff --git a/code/vn_core.h b/code/vn_core.h index d4a4544..ec63624 100644 --- a/code/vn_core.h +++ b/code/vn_core.h @@ -66,8 +66,9 @@ IsNull(p) ? (SetNull((n)->prev), (n)->next = (f), (IsNull(f) ? (0) : ((f)->prev #include "vn_types.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 #include "third_party/stb_sprintf.h" @@ -126,6 +127,12 @@ inline void EndTicketMutex(ticket_mutex *Mutex) 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) { b32 Result = ((P.x >= Range.Min.x) && @@ -153,6 +160,12 @@ inline range2_r32 Range2R32(v2 A, v2 B) return(Result); } +inline s64 DimOfRange(range_s64 Range) +{ + s64 Dim = Range.Max - Range.Min; + return(Dim); +} + inline v2 DimOfRange(range2_r32 Range) { v2 Dim = Range.Max - Range.Min; diff --git a/code/vn_math.h b/code/vn_math.h index 1d596e5..9ee3a8b 100644 --- a/code/vn_math.h +++ b/code/vn_math.h @@ -23,6 +23,12 @@ inline r32 Ceil(r32 Value) return(Result); } +inline r32 Log(r32 Value) +{ + r32 Result = logf(Value); + return(Result); +} + inline r32 Pow(r32 Base, r32 Exponent) { r32 Result = powf(Base, Exponent); @@ -48,6 +54,18 @@ inline b32 AreAlmostEqual(r32 A, r32 B) 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) { v2s Result = {A.x + B.x, A.y + B.y}; diff --git a/code/vn_memory.h b/code/vn_memory.h index a27dd25..c32be0c 100644 --- a/code/vn_memory.h +++ b/code/vn_memory.h @@ -209,6 +209,9 @@ inline string PushFormat(memory_arena *Arena, char *Format, ...) 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) { string Result; diff --git a/code/vn_platform.h b/code/vn_platform.h index af6722f..929ae55 100644 --- a/code/vn_platform.h +++ b/code/vn_platform.h @@ -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) 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) 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) 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 { platform_allocate_memory *AllocateMemory; @@ -79,10 +93,12 @@ struct platform_api platform_open_file *OpenFile; platform_close_file *CloseFile; platform_read_file *ReadFile; + platform_write_file *WriteFile; platform_get_file_size *GetFileSize; platform_set_cursor *SetCursor; platform_toggle_fullscreen *ToggleFullscreen; + platform_show_message *ShowMessage; }; enum platform_event_type @@ -91,6 +107,7 @@ enum platform_event_type PlatformEvent_Release, PlatformEvent_Text, PlatformEvent_MouseScroll, + PlatformEvent_WindowClose, }; enum platform_key @@ -201,6 +218,7 @@ struct vn_input // sixten: Application to platform s32 RefreshRate; + b32 ExitRequested; }; struct vn_memory diff --git a/code/vn_string.h b/code/vn_string.h index 1e326ab..3ae38bc 100644 --- a/code/vn_string.h +++ b/code/vn_string.h @@ -5,181 +5,273 @@ inline b32 IsWhitespace(char C) { - b32 Result = ((C == ' ') || - (C == '\n') || - (C == '\t') || - (C == '\r')); - return(Result); + b32 Result = ((C == ' ') || + (C == '\n') || + (C == '\t') || + (C == '\r')); + 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) { - s64 Result = 0; - while(*String++) - { - ++Result; - } - return(Result); -} - -inline u64 HashString(string String) -{ - u64 Result = 5731; - for(s64 Index = 0; - Index < String.Count; - ++Index) - { - Result += String.Data[Index]; - Result ^= Result << 13; - Result ^= Result >> 7; - Result ^= Result << 17; - } - - return(Result); + s64 Result = 0; + while(*String++) + { + ++Result; + } + return(Result); } inline string MakeStringFromCString(char *Data) { - string Result = {StringLength(Data), (u8 *)Data}; - return(Result); + string Result = {StringLength(Data), (u8 *)Data}; + return(Result); +} + +inline u64 HashString(string String) +{ + u64 Result = 5731; + for(s64 Index = 0; + Index < String.Count; + ++Index) + { + Result += String.Data[Index]; + Result ^= Result << 13; + Result ^= Result >> 7; + Result ^= Result << 17; + } + + return(Result); } inline b32 AreEqual(string A, string B) { - b32 Result = false; - if(A.Count == B.Count) - { - Result = true; - - for(s64 Index = 0; - Index < A.Count; - ++Index) + b32 Result = false; + if(A.Count == B.Count) { - if(A.Data[Index] != B.Data[Index]) - { - Result = false; - break; - } + Result = true; + + for(s64 Index = 0; + Index < A.Count; + ++Index) + { + if(A.Data[Index] != B.Data[Index]) + { + Result = false; + break; + } + } } - } - - return(Result); + + return(Result); } inline s64 FirstIndexOf(string String, char Char) { - s64 Result = -1; - for(s64 Index = 0; - Index < String.Count; - ++Index) - { - if(String.Data[Index] == Char) + s64 Result = -1; + for(s64 Index = 0; + Index < String.Count; + ++Index) { - Result = Index; - break; + if(String.Data[Index] == Char) + { + Result = Index; + break; + } } - } - return(Result); + return(Result); } inline s64 LastIndexOf(string String, char Char) { - s64 Result = -1; - for(s64 Index = String.Count-1; - Index >= 0; - --Index) - { - if(String.Data[Index] == Char) + s64 Result = -1; + for(s64 Index = String.Count-1; + Index >= 0; + --Index) { - Result = Index; - break; + if(String.Data[Index] == Char) + { + Result = Index; + break; + } } - } - return(Result); + return(Result); } inline s64 LastIndexOf(string String, string Substring) { - s64 Result = -1; - if(String.Count >= Substring.Count) - { - for(s64 Index = String.Count-Substring.Count; - Index >= 0; - --Index) + s64 Result = -1; + if(String.Count >= Substring.Count) { - string ToCheck = MakeString((char *)String.Data + Index, Substring.Count); - if(AreEqual(ToCheck, Substring)) - { - Result = Index; - break; - } + for(s64 Index = String.Count-Substring.Count; + Index >= 0; + --Index) + { + string ToCheck = MakeString((char *)String.Data + Index, Substring.Count); + if(AreEqual(ToCheck, Substring)) + { + Result = Index; + break; + } + } } - } - 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) { - s64 Length = 0; - if(Codepoint <= 0x7F) - { - Out[0] = (u8)Codepoint; - Length = 1; - } - else if(Codepoint <= 0x7FF) - { - Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F); - Out[1] = 0x80 | ( Codepoint & 0x3F); - Length = 2; - } - else if(Codepoint <= 0xFFFF) - { - Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F); - Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F); - Out[2] = 0x80 | ( Codepoint & 0x3F); - Length = 3; - } - else if(Codepoint <= 0x10FFFF) - { - Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07); - Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F); - Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F); - Out[3] = 0x80 | ( Codepoint & 0x3F); - Length = 4; - } - else - { - Out[0] = '?'; - Length = 1; - } - - return(Length); + s64 Length = 0; + if(Codepoint <= 0x7F) + { + Out[0] = (u8)Codepoint; + Length = 1; + } + else if(Codepoint <= 0x7FF) + { + Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F); + Out[1] = 0x80 | ( Codepoint & 0x3F); + Length = 2; + } + else if(Codepoint <= 0xFFFF) + { + Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F); + Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F); + Out[2] = 0x80 | ( Codepoint & 0x3F); + Length = 3; + } + else if(Codepoint <= 0x10FFFF) + { + Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07); + Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F); + Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F); + Out[3] = 0x80 | ( Codepoint & 0x3F); + Length = 4; + } + else + { + Out[0] = '?'; + Length = 1; + } + + return(Length); } inline s64 GetCodepointSize(u32 Codepoint) { - s64 Result = 0; - if(Codepoint <= 0x7F) - { - Result = 1; - } - else if(Codepoint <= 0x7FF) - { - Result = 2; - } - else if(Codepoint <= 0xFFFF) - { - Result = 3; - } - else if(Codepoint <= 0x10FFFF) - { - Result = 4; - } - else - { - Result = 1; - } - return(Result); + s64 Result = 0; + if(Codepoint <= 0x7F) + { + Result = 1; + } + else if(Codepoint <= 0x7FF) + { + Result = 2; + } + else if(Codepoint <= 0xFFFF) + { + Result = 3; + } + else if(Codepoint <= 0x10FFFF) + { + Result = 4; + } + else + { + Result = 1; + } + return(Result); } // sixten(TODO): Remove this forward decl. @@ -187,61 +279,95 @@ inline string PushCString(struct memory_arena *Arena, char *CString); inline string StringFromCodepoint(struct memory_arena *Arena, u32 Codepoint) { - char Buffer[5] = {}; - UTF8FromCodepoint((u8 *)Buffer, Codepoint); - - string Result = PushCString(Arena, Buffer); - return(Result); + char Buffer[5] = {}; + UTF8FromCodepoint((u8 *)Buffer, Codepoint); + + string Result = PushCString(Arena, Buffer); + return(Result); } struct utf8_iterator { - string Data; - s64 Index; - - u32 Codepoint; + string Data; + s64 Index; + + u32 Codepoint; }; inline void Advance(utf8_iterator *Iter) { - u8 *At = Iter->Data.Data + Iter->Index; - - if(Iter->Index < Iter->Data.Count) - { - if((At[0] & 0x80) == 0x00) + u8 *At = Iter->Data.Data + Iter->Index; + + if(Iter->Index < Iter->Data.Count) { - Iter->Codepoint = (At[0] & 0x7F); - Iter->Index += 1; + if((At[0] & 0x80) == 0x00) + { + Iter->Codepoint = (At[0] & 0x7F); + Iter->Index += 1; + } + else if((At[0] & 0xE0) == 0xC0) + { + Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F); + Iter->Index += 2; + } + else if((At[0] & 0xF0) == 0xE0) + { + Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F); + Iter->Index += 3; + } + else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0) + { + Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F); + Iter->Index += 4; + } } - else if((At[0] & 0xE0) == 0xC0) + else { - Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F); - Iter->Index += 2; + Iter->Codepoint = 0; } - else if((At[0] & 0xF0) == 0xE0) - { - Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F); - Iter->Index += 3; - } - else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0) - { - Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F); - Iter->Index += 4; - } - } - else - { - Iter->Codepoint = 0; - } } inline utf8_iterator IterateUTF8String(string String) { - utf8_iterator Iter = {}; - Iter.Data = String; - Advance(&Iter); - - return(Iter); + utf8_iterator Iter = {}; + Iter.Data = String; + Advance(&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 diff --git a/code/vn_thread_context.h b/code/vn_thread_context.h index 8896b7f..c968672 100644 --- a/code/vn_thread_context.h +++ b/code/vn_thread_context.h @@ -22,7 +22,7 @@ inline thread_context *GetThreadContext(void) 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 = {}; thread_context *Context = GetThreadContext(); diff --git a/code/vn_tokenizer.h b/code/vn_tokenizer.h new file mode 100644 index 0000000..37a9e3c --- /dev/null +++ b/code/vn_tokenizer.h @@ -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 diff --git a/code/vn_types.h b/code/vn_types.h index 0d26acc..d8ab3dc 100644 --- a/code/vn_types.h +++ b/code/vn_types.h @@ -70,6 +70,21 @@ inline string MakeString16(wchar_t *Data, s64 Count) 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 { s32 x, y; diff --git a/code/vn_ui.cpp b/code/vn_ui.cpp index 996cdef..16649a0 100644 --- a/code/vn_ui.cpp +++ b/code/vn_ui.cpp @@ -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; inline void UI_SetState(ui *UI) @@ -193,8 +226,6 @@ inline ui_box *UI_GetBoxByKey(ui *UI, ui_key Key) return(Result); } -#include "generated/vn_generated_ui.cpp" - inline ui_box *UI_MakeBox(ui_box_flags Flags, string String) { ui *UI = UI_GetState(); @@ -231,6 +262,12 @@ inline ui_box *UI_MakeBox(ui_box_flags Flags, string String) Box->Flags = Flags; Box->String = PushString(&UI->FrameArena, String); + s64 HashIndex = LastIndexOf(Box->String, '#'); + if(HashIndex != -1) + { + Box->String = Prefix(Box->String, HashIndex); + } + UI_ApplyStyles(Box); 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); } -#if 0 // sixten: Render debug rects around boxes. - 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 B = (((Box->Key.Value >> 42) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1)); - v4 Red = V4(R, G, B, 1); - PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8); +#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 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)); + v4 Red = V4(R, G, B, 1); + PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8); + } #endif if(Box->Flags & UI_BoxFlag_Clip) diff --git a/code/vn_ui.h b/code/vn_ui.h index 62775e5..0684e91 100644 --- a/code/vn_ui.h +++ b/code/vn_ui.h @@ -46,29 +46,11 @@ struct ui_size r32 Strictness; }; -inline ui_size UI_Pixels(r32 Value, r32 Strictness) -{ - ui_size Result = {UI_SizeType_Pixels, Value, 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); -} +inline ui_size UI_Pixels(r32 Value, r32 Strictness); +inline ui_size UI_Em(r32 Value, r32 Strictness); +inline ui_size UI_TextContent(r32 Value, r32 Strictness); +inline ui_size UI_Percent(r32 Value, r32 Strictness); +inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness); typedef void ui_draw_callback(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data); diff --git a/code/vn_ui_utils.cpp b/code/vn_ui_utils.cpp index 5cb9e54..b5f1290 100644 --- a/code/vn_ui_utils.cpp +++ b/code/vn_ui_utils.cpp @@ -162,5 +162,36 @@ static ui_signal UI_ButtonF(char *Format, ...) ReleaseScratch(Scratch); + 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); } \ No newline at end of file diff --git a/code/vn_workspace.cpp b/code/vn_workspace.cpp index 6dabdda..62c01d7 100644 --- a/code/vn_workspace.cpp +++ b/code/vn_workspace.cpp @@ -150,8 +150,6 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame) Workspace_BuildToolbarButton(Workspace, "Panel", ToolbarMenu_Panel); Workspace_BuildToolbarButton(Workspace, "View", ToolbarMenu_View); Workspace_BuildToolbarButton(Workspace, "Window", ToolbarMenu_Window); - - UI_Spacer(UI_Percent(1, 0)); } 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, - glyph_atlas *GlyphAtlas) +static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands, + vn_input *Input, glyph_atlas *GlyphAtlas) { + Workspace->Input = Input; Workspace->EventList = Input->EventList; // sixten: Process last frame's commands. diff --git a/code/vn_workspace.h b/code/vn_workspace.h index db2d598..ed39f47 100644 --- a/code/vn_workspace.h +++ b/code/vn_workspace.h @@ -68,6 +68,7 @@ struct workspace_drag_payload struct workspace { + vn_input *Input; platform_event_list *EventList; // sixten: Command Allocation diff --git a/code/vn_workspace_view.cpp b/code/vn_workspace_view.cpp index 73732af..48cd8d6 100644 --- a/code/vn_workspace_view.cpp +++ b/code/vn_workspace_view.cpp @@ -225,7 +225,7 @@ static void Workspace_BuildSettingsTabButton(workspace_view_settings *Settings, { 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_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"}; 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)) { + 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; } @@ -399,12 +419,9 @@ static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View) if(!Category || (Category == Workspace_Settings_Developer)) { UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer"); - UI_LabelF("Render UI Debug Rects:"); - UI_LabelF("Render FPS Counter:"); - - UI_CornerRadius(4) - UI_Size(UI_TextContent(20, 1), UI_TextContent(10, 1)) - UI_ButtonF("Hello Line Paint Color Design Address Brightness"); + UI_Checkbox(StrLit("Render UI Debug Rects"), &DEBUG_DebugSettings->RenderUIDebugRects); + UI_Spacer(UI_Pixels(5, 1)); + UI_Checkbox(StrLit("Render FPS Counter"), &DEBUG_DebugSettings->RenderFPSCounter); UI_Spacer(UI_Pixels(50, 1)); } diff --git a/code/win32_main.cpp b/code/win32_main.cpp index 7dc943d..6169443 100644 --- a/code/win32_main.cpp +++ b/code/win32_main.cpp @@ -8,13 +8,12 @@ #include "win32_main.h" #include "win32_opengl.cpp" -global b32 Global_Running; global win32_state Global_Win32State; global WINDOWPLACEMENT Global_WindowPosition = {sizeof(Global_WindowPosition)};; 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) { @@ -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) { win32_state *State = &Global_Win32State; @@ -83,6 +106,10 @@ static PLATFORM_OPEN_FILE(Win32_OpenFile) { CreationAttributes = OPEN_EXISTING; } + if(FileAccess & PlatformAccess_Write) + { + CreationAttributes = CREATE_ALWAYS; + } 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) { u64 Result = 0; @@ -307,7 +346,8 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP { case WM_CLOSE: { - Global_Running = false; + Event = PushStruct(&State->EventArena, platform_event); + Event->Type = PlatformEvent_WindowClose; } break; case WM_WINDOWPOSCHANGED: @@ -604,7 +644,7 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i State->MemorySentinel.Next = &State->MemorySentinel; State->MemorySentinel.Prev = &State->MemorySentinel; - State->SleepIsGranular = (timeBeginPeriod(1) != TIMERR_NOERROR); + State->SleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR); } // sixten: Setup platform layer @@ -614,9 +654,11 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i Platform.OpenFile = Win32_OpenFile; Platform.CloseFile = Win32_CloseFile; Platform.ReadFile = Win32_ReadFile; + Platform.WriteFile = Win32_WriteFile; Platform.GetFileSize = Win32_GetFileSize; Platform.SetCursor = Win32_SetCursor; Platform.ToggleFullscreen = Win32_ToggleFullscreen; + Platform.ShowMessage = Win32_ShowMessage; } WNDCLASS WindowClass = {}; @@ -639,9 +681,9 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i Global_Win32State.Window = Window; vn_input Input = {}; + vn_render_commands RenderCommands = {}; // sixten: Setup OpenGL - vn_render_commands RenderCommands = {}; HDC DeviceContext = GetDC(Window); Win32_CreateOpenGLContext(DeviceContext); 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(); - Global_Running = true; - while(Global_Running) + while(!Input.ExitRequested) { u64 NewTime = Win32_GetWallClock(); r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime); diff --git a/config.vn b/config.vn new file mode 100644 index 0000000..f749c5c --- /dev/null +++ b/config.vn @@ -0,0 +1,10 @@ +Platform +{ + RefreshRate = 60; +} + +Dev +{ + RenderUIDebugRects = false; + RenderFPSCounter = false; +} \ No newline at end of file diff --git a/config/config.vn b/config/config.vn deleted file mode 100644 index e69de29..0000000