Finished config implementation.
parent
aefb393dcc
commit
cab0dac728
114
code/vn.cpp
114
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);
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
474
code/vn_string.h
474
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
28
code/vn_ui.h
28
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -68,6 +68,7 @@ struct workspace_drag_payload
|
|||
|
||||
struct workspace
|
||||
{
|
||||
vn_input *Input;
|
||||
platform_event_list *EventList;
|
||||
|
||||
// sixten: Command Allocation
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
Platform
|
||||
{
|
||||
RefreshRate = 60;
|
||||
}
|
||||
|
||||
Dev
|
||||
{
|
||||
RenderUIDebugRects = false;
|
||||
RenderFPSCounter = false;
|
||||
}
|
Loading…
Reference in New Issue