Added basic text editing.

main
sixtenhugosson 2023-07-19 17:09:41 +02:00
parent 4dd7703810
commit a9f257ca7c
98 changed files with 12534 additions and 1868 deletions

View File

@ -5,9 +5,8 @@ set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /Oi /W4 /W
if not exist "../build" mkdir "../build"
pushd "../build/"
rem cl %CommonCompilerOptions% ../code/gen.cpp
rem gen.exe
rem cl /Zi /nologo /FC ../code/third_party/codegen/codegen.c
codegen ../code/
cl %CommonCompilerOptions% ../code/vn.cpp /LD /link /export:VN_UpdateAndRender /incremental:no
cl %CommonCompilerOptions% ../code/win32_main.cpp /link user32.lib gdi32.lib winmm.lib opengl32.lib

View File

@ -90,6 +90,12 @@ Index = ___; break;\
}\
}\
#define Bytes(n) (n)
#define Kilobytes(n) (n << 10)
#define Megabytes(n) (n << 20)
#define Gigabytes(n) (((u64)n) << 30)
#define Terabytes(n) (((u64)n) << 40)
//- sixten: Min, max & clamp
#define Minimum(A, B) (((A)<(B))?(A):(B))
@ -103,6 +109,23 @@ Index = ___; break;\
#define IsNull(x) ((x) == 0)
#define SetNull(x) ((x) = 0)
#define QueuePush_N(f,l,n,next) (IsNull(f)?\
(((f)=(l)=(n)), SetNull((n)->next)):\
((l)->next=(n),(l)=(n),SetNull((n)->next)))
#define QueuePushFront_N(f,l,n,next) (IsNull(f) ? (((f) = (l) = (n)), SetNull((n)->next)) :\
((n)->next = (f)), ((f) = (n)))
#define QueuePop_N(f,l,next) ((f)==(l)?\
(SetNull(f),SetNull(l)):\
((f)=(f)->next))
#define StackPush_N(f,n,next) ((n)->next=(f),(f)=(n))
#define StackPop_N(f,next) (IsNull(f)?0:((f)=(f)->next))
#define QueuePush(f,l,n) QueuePush_N(f,l,n,Next)
#define QueuePushFront(f,l,n) QueuePushFront_N(f,l,n,Next)
#define QueuePop(f,l) QueuePop_N(f,l,Next)
#define StackPush(f,n) StackPush_N(f,n,Next)
#define StackPop(f) StackPop_N(f,Next)
#define DLLInsert_NP(f,l,p,n,next,prev) \
(IsNull(f) ? (((f) = (l) = (n)), SetNull((n)->next), SetNull((n)->prev)) :\
IsNull(p) ? (SetNull((n)->prev), (n)->next = (f), (IsNull(f) ? (0) : ((f)->prev = (n))), (f) = (n)) :\
@ -168,7 +191,6 @@ inline void EndTicketMutex(ticket_mutex *Mutex)
}
//- sixten: Axes
enum axis2
{
Axis2_X,
@ -178,4 +200,15 @@ enum axis2
inline axis2 Opposite(axis2 Axis) { axis2 Result = (axis2)(!(u32)Axis); return(Result); }
////////////////////////////////
//- sixten: Corners
enum corner
{
Corner_00 = 0,
Corner_10 = (1 << Axis2_X),
Corner_01 = (1 << Axis2_Y),
Corner_11 = (1 << Axis2_X)|(1 << Axis2_Y),
Corner_Count,
};
#endif //CORE_H

View File

@ -489,9 +489,9 @@ inline v4_s64 Max(v4_s64 A, v4_s64 B)
//- sixten: Range functions
inline range1_r32 Range1R32(r32 Min, r32 Max)
inline range1_r32 Range1R32(r32 A, r32 B)
{
range1_r32 Result = {Min, Max};
range1_r32 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -501,6 +501,12 @@ inline b32 InRange(range1_r32 Range, r32 Value)
return(Result);
}
inline b32 Contains(range1_r32 Range, r32 Value)
{
b32 Result = (Value >= Range.Min) && (Value <= Range.Max);
return(Result);
}
inline r32 DimOfRange(range1_r32 Range)
{
r32 Result = Range.Max - Range.Min;
@ -513,9 +519,9 @@ inline range1_r32 Intersection(range1_r32 A, range1_r32 B)
return(Result);
}
inline range1_s32 Range1S32(s32 Min, s32 Max)
inline range1_s32 Range1S32(s32 A, s32 B)
{
range1_s32 Result = {Min, Max};
range1_s32 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -525,6 +531,12 @@ inline b32 InRange(range1_s32 Range, s32 Value)
return(Result);
}
inline b32 Contains(range1_s32 Range, s32 Value)
{
b32 Result = (Value >= Range.Min) && (Value <= Range.Max);
return(Result);
}
inline s32 DimOfRange(range1_s32 Range)
{
s32 Result = Range.Max - Range.Min;
@ -537,9 +549,9 @@ inline range1_s32 Intersection(range1_s32 A, range1_s32 B)
return(Result);
}
inline range1_s64 Range1S64(s64 Min, s64 Max)
inline range1_s64 Range1S64(s64 A, s64 B)
{
range1_s64 Result = {Min, Max};
range1_s64 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -549,6 +561,12 @@ inline b32 InRange(range1_s64 Range, s64 Value)
return(Result);
}
inline b32 Contains(range1_s64 Range, s64 Value)
{
b32 Result = (Value >= Range.Min) && (Value <= Range.Max);
return(Result);
}
inline s64 DimOfRange(range1_s64 Range)
{
s64 Result = Range.Max - Range.Min;
@ -561,9 +579,9 @@ inline range1_s64 Intersection(range1_s64 A, range1_s64 B)
return(Result);
}
inline range2_r32 Range2R32(v2_r32 Min, v2_r32 Max)
inline range2_r32 Range2R32(v2_r32 A, v2_r32 B)
{
range2_r32 Result = {Min, Max};
range2_r32 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -574,6 +592,13 @@ inline b32 InRange(range2_r32 Range, v2_r32 Value)
return(Result);
}
inline b32 Contains(range2_r32 Range, v2_r32 Value)
{
b32 Result = ((Value.x >= Range.Min.x) && (Value.y >= Range.Min.y) &&
(Value.x <= Range.Max.x) && (Value.y <= Range.Max.y));
return(Result);
}
inline v2_r32 DimOfRange(range2_r32 Range)
{
v2_r32 Result = Range.Max - Range.Min;
@ -586,9 +611,16 @@ inline range2_r32 Intersection(range2_r32 A, range2_r32 B)
return(Result);
}
inline range2_s32 Range2S32(v2_s32 Min, v2_s32 Max)
inline v2_r32 CornerFromRange(range2_r32 Range, corner Corner)
{
range2_s32 Result = {Min, Max};
v2_r32 Result = V2R32((Corner & (1 << Axis2_X))?Range.Min.x:Range.Max.x,
(Corner & (1 << Axis2_Y))?Range.Min.y:Range.Max.y);
return(Result);
}
inline range2_s32 Range2S32(v2_s32 A, v2_s32 B)
{
range2_s32 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -599,6 +631,13 @@ inline b32 InRange(range2_s32 Range, v2_s32 Value)
return(Result);
}
inline b32 Contains(range2_s32 Range, v2_s32 Value)
{
b32 Result = ((Value.x >= Range.Min.x) && (Value.y >= Range.Min.y) &&
(Value.x <= Range.Max.x) && (Value.y <= Range.Max.y));
return(Result);
}
inline v2_s32 DimOfRange(range2_s32 Range)
{
v2_s32 Result = Range.Max - Range.Min;
@ -611,9 +650,16 @@ inline range2_s32 Intersection(range2_s32 A, range2_s32 B)
return(Result);
}
inline range2_s64 Range2S64(v2_s64 Min, v2_s64 Max)
inline v2_s32 CornerFromRange(range2_s32 Range, corner Corner)
{
range2_s64 Result = {Min, Max};
v2_s32 Result = V2S32((Corner & (1 << Axis2_X))?Range.Min.x:Range.Max.x,
(Corner & (1 << Axis2_Y))?Range.Min.y:Range.Max.y);
return(Result);
}
inline range2_s64 Range2S64(v2_s64 A, v2_s64 B)
{
range2_s64 Result = {Min(A, B), Max(A, B)};
return(Result);
}
@ -624,6 +670,13 @@ inline b32 InRange(range2_s64 Range, v2_s64 Value)
return(Result);
}
inline b32 Contains(range2_s64 Range, v2_s64 Value)
{
b32 Result = ((Value.x >= Range.Min.x) && (Value.y >= Range.Min.y) &&
(Value.x <= Range.Max.x) && (Value.y <= Range.Max.y));
return(Result);
}
inline v2_s64 DimOfRange(range2_s64 Range)
{
v2_s64 Result = Range.Max - Range.Min;
@ -635,3 +688,10 @@ inline range2_s64 Intersection(range2_s64 A, range2_s64 B)
range2_s64 Result = {Max(A.Min, B.Min), Min(A.Max, B.Max)};
return(Result);
}
inline v2_s64 CornerFromRange(range2_s64 Range, corner Corner)
{
v2_s64 Result = V2S64((Corner & (1 << Axis2_X))?Range.Min.x:Range.Max.x,
(Corner & (1 << Axis2_Y))?Range.Min.y:Range.Max.y);
return(Result);
}

View File

@ -325,35 +325,47 @@ inline v4_s64 Max(v4_s64 A, v4_s64 B);
//- sixten: Range functions
inline range1_r32 Range1R32(r32 Min, r32 Max);
// sixten(NOTE): InRange means that the value is in [Min, Max) and
// Contains means that the value is in [Min, Max]
inline range1_r32 Range1R32(r32 A, r32 B);
inline b32 InRange(range1_r32 Range, r32 Value);
inline b32 Contains(range1_r32 Range, r32 Value);
inline r32 DimOfRange(range1_r32 Range);
inline range1_r32 Intersection(range1_r32 A, range1_r32 B);
inline range1_s32 Range1S32(s32 Min, s32 Max);
inline range1_s32 Range1S32(s32 A, s32 B);
inline b32 InRange(range1_s32 Range, s32 Value);
inline b32 Contains(range1_s32 Range, s32 Value);
inline s32 DimOfRange(range1_s32 Range);
inline range1_s32 Intersection(range1_s32 A, range1_s32 B);
inline range1_s64 Range1S64(s64 Min, s64 Max);
inline range1_s64 Range1S64(s64 A, s64 B);
inline b32 InRange(range1_s64 Range, s64 Value);
inline b32 Contains(range1_s64 Range, s64 Value);
inline s64 DimOfRange(range1_s64 Range);
inline range1_s64 Intersection(range1_s64 A, range1_s64 B);
inline range2_r32 Range2R32(v2_r32 Min, v2_r32 Max);
inline range2_r32 Range2R32(v2_r32 A, v2_r32 B);
inline b32 InRange(range2_r32 Range, v2_r32 Value);
inline b32 Contains(range2_r32 Range, v2_r32 Value);
inline v2_r32 DimOfRange(range2_r32 Range);
inline range2_r32 Intersection(range2_r32 A, range2_r32 B);
inline v2_r32 CornerFromRange(range2_r32 Range, corner Corner);
inline range2_s32 Range2S32(v2_s32 Min, v2_s32 Max);
inline range2_s32 Range2S32(v2_s32 A, v2_s32 B);
inline b32 InRange(range2_s32 Range, v2_s32 Value);
inline b32 Contains(range2_s32 Range, v2_s32 Value);
inline v2_s32 DimOfRange(range2_s32 Range);
inline range2_s32 Intersection(range2_s32 A, range2_s32 B);
inline v2_s32 CornerFromRange(range2_s32 Range, corner Corner);
inline range2_s64 Range2S64(v2_s64 Min, v2_s64 Max);
inline range2_s64 Range2S64(v2_s64 A, v2_s64 B);
inline b32 InRange(range2_s64 Range, v2_s64 Value);
inline b32 Contains(range2_s64 Range, v2_s64 Value);
inline v2_s64 DimOfRange(range2_s64 Range);
inline range2_s64 Intersection(range2_s64 A, range2_s64 B);
inline v2_s64 CornerFromRange(range2_s64 Range, corner Corner);
//- sixten: Shorthand base types

View File

@ -1,6 +1,9 @@
//- sixten: Common memory functions
////////////////////////////////
//- sixten: Common Memory Functions
static void Copy(void *Dest, void *Source, umm Count)
{
if(Count <= S64_Max)
{
u8 *Dest8 = (u8 *)Dest;
u8 *Source8 = (u8 *)Source;
@ -10,8 +13,25 @@ static void Copy(void *Dest, void *Source, umm Count)
*Dest8++ = *Source8++;
}
}
}
static void CopyReverse(void *Dest, void *Source, umm Count)
{
if(Count <= S64_Max)
{
u8 *Dest8 = (u8 *)Dest + Count;
u8 *Source8 = (u8 *)Source + Count;
while(Count--)
{
*--Dest8 = *--Source8;
}
}
}
static void Fill(void *Dest, u8 Value, umm Count)
{
if(Count <= S64_Max)
{
u8 *Dest8 = (u8 *)Dest;
@ -20,134 +40,103 @@ static void Fill(void *Dest, u8 Value, umm Count)
*Dest8++ = Value;
}
}
//- sixten: Memory arena functions
static void Release(memory_arena *Arena)
{
while(Arena->CurrentBlock != 0)
{
platform_memory_block *MemoryBlock = Arena->CurrentBlock;
b32 IsLastBlock = (MemoryBlock->ArenaPrev == 0);
Arena->CurrentBlock = MemoryBlock->ArenaPrev;
Platform.DeallocateMemory(MemoryBlock);
if(IsLastBlock)
{
break;
}
}
}
inline umm GetAlignmentOffset(memory_arena *Arena, umm Alignment)
{
umm AlignmentOffset = 0;
////////////////////////////////
//- sixten: Memory Arena Functions
umm ResultPointer = (umm)Arena->CurrentBlock + Arena->CurrentBlock->Used;
umm AlignmentMask = Alignment - 1;
if(ResultPointer & AlignmentMask)
static memory_arena *ArenaAllocate(u64 Size)
{
AlignmentOffset = Alignment - (ResultPointer & AlignmentMask);
u64 RoundedSize = Size+Megabytes(64)-1;
RoundedSize -= RoundedSize&Megabytes(64);
void *Memory = Platform.Reserve(RoundedSize);
u64 InitialCommitSize = MEMORY_ARENA_COMMIT_SIZE;
Platform.Commit(Memory, InitialCommitSize);
memory_arena *Arena = (memory_arena *)Memory;
Arena->Position = sizeof(memory_arena);
Arena->CommitPosition = InitialCommitSize;
Arena->Size = Size;
Arena->Align = 8;
return(Arena);
}
return(AlignmentOffset);
}
inline umm GetEffectiveSizeFor(memory_arena *Arena, umm InitialSize, arena_push_params Params)
static void ArenaRelease(memory_arena *Arena)
{
umm Size = InitialSize;
umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment);
Size += AlignmentOffset;
return(Size);
Platform.Release(Arena);
}
static void *PushSize_(memory_arena *Arena, umm InitialSize, arena_push_params Params)
static void *ArenaPushNoClear(memory_arena *Arena, u64 Size)
{
void *Result = 0;
umm Size = 0;
if(Arena->CurrentBlock)
if(Arena->Position + Size <= Arena->Size)
{
Size = GetEffectiveSizeFor(Arena, InitialSize, Params);
}
if(!Arena->CurrentBlock || ((Arena->CurrentBlock->Used + Size) > Arena->CurrentBlock->Size))
u8 *Base = (u8 *)Arena;
u64 PostAlignPos = (Arena->Position+Arena->Align-1);
PostAlignPos -= PostAlignPos%Arena->Align;
u64 Align = PostAlignPos - Arena->Position;
Result = Base + Arena->Position + Align;
Arena->Position += Size + Align;
if(Arena->CommitPosition < Arena->Position)
{
Size = InitialSize;
if(!Arena->MinimumBlockSize)
u64 ToCommit = Arena->Position - Arena->CommitPosition;
ToCommit += MEMORY_ARENA_COMMIT_SIZE - 1;
ToCommit -= ToCommit%MEMORY_ARENA_COMMIT_SIZE;
Platform.Commit(Base + Arena->CommitPosition, ToCommit);
Arena->CommitPosition += ToCommit;
}
}
else
{
Arena->MinimumBlockSize = 1024*1024;
InvalidCodepath;
}
umm BlockSize = Maximum(Size, Arena->MinimumBlockSize);
platform_memory_block *NewBlock = Platform.AllocateMemory(BlockSize);
NewBlock->ArenaPrev = Arena->CurrentBlock;
Arena->CurrentBlock = NewBlock;
}
Assert((Arena->CurrentBlock->Used + Size) <= Arena->CurrentBlock->Size);
umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment);
umm OffsetInBlock = Arena->CurrentBlock->Used + AlignmentOffset;
Result = Arena->CurrentBlock->Base + OffsetInBlock;
Arena->CurrentBlock->Used += Size;
Assert(Size >= InitialSize);
Assert(Arena->CurrentBlock->Used <= Arena->CurrentBlock->Size);
if(Params.Flags & ArenaFlag_ClearToZero)
{
Fill(Result, 0, InitialSize);
}
return(Result);
}
//- sixten: Bootsrapping helpers
static void *BootstrapPushSize(umm Size, umm OffsetToArena)
static void *ArenaPush(memory_arena *Arena, u64 Size)
{
memory_arena Arena = {};
void *Result = PushSize(&Arena, Size);
*(memory_arena *)((u8 *)Result + OffsetToArena) = Arena;
void *Result = ArenaPushNoClear(Arena, Size);
Fill(Result, 0, Size);
return(Result);
}
//- sixten: Temporary memory functions
static void ArenaPopTo(memory_arena *Arena, u64 Position)
{
u64 MinPosition = sizeof(*Arena);
u64 NewPosition = Maximum(MinPosition, Position);
Arena->Position = NewPosition;
u64 CommitAlignedPosition = Arena->Position+MEMORY_ARENA_COMMIT_SIZE-1;
CommitAlignedPosition -= CommitAlignedPosition%MEMORY_ARENA_COMMIT_SIZE;
if(CommitAlignedPosition + MEMORY_ARENA_DECOMMIT_THRESHOLD <= Arena->CommitPosition)
{
u8 *Base = (u8 *)Arena;
u64 ToDecommit = Arena->CommitPosition-CommitAlignedPosition;
Platform.Decommit(Base+CommitAlignedPosition, ToDecommit);
Arena->CommitPosition -= ToDecommit;
}
}
static void ArenaClear(memory_arena *Arena)
{
ArenaPopTo(Arena, sizeof(*Arena));
}
static void ArenaSetAlign(memory_arena *Arena, u64 Align)
{
Arena->Align = Align;
}
////////////////////////////////
//- sixten: Temporary Memory Functions
static temporary_memory BeginTemporaryMemory(memory_arena *Arena)
{
temporary_memory Result;
Result.Arena = Arena;
Result.Block = Arena->CurrentBlock;
Result.Used = Arena->CurrentBlock ? Arena->CurrentBlock->Used : 0;
++Arena->TemporaryMemoryCount;
return(Result);
temporary_memory Temp;
Temp.Arena = Arena;
Temp.Position = Arena->Position;
return(Temp);
}
static void EndTemporaryMemory(temporary_memory Temp)
{
memory_arena *Arena = Temp.Arena;
while(Arena->CurrentBlock != Temp.Block)
{
platform_memory_block *MemoryBlock = Arena->CurrentBlock;
Arena->CurrentBlock = MemoryBlock->ArenaPrev;
Platform.DeallocateMemory(MemoryBlock);
}
if(Arena->CurrentBlock)
{
Assert(Arena->CurrentBlock->Used >= Temp.Used);
Arena->CurrentBlock->Used = Temp.Used;
}
Assert(Arena->TemporaryMemoryCount > 0);
--Arena->TemporaryMemoryCount;
ArenaPopTo(Temp.Arena, Temp.Position);
}

View File

@ -3,72 +3,54 @@
#ifndef CORE_MEMORY_H
#define CORE_MEMORY_H
//- sixten: Common memory functions
////////////////////////////////
//- sixten: Common Memory Functions
static void Copy(void *Dest, void *Source, umm Count);
static void CopyReverse(void *Dest, void *Source, umm Count);
static void Fill(void *Dest, u8 Value, umm Count);
#define Move(Dest, Source, Count) memmove(Dest, Source, Count)
//- sixten: Memory arena types
struct platform_memory_block;
////////////////////////////////
//- sixten: Memory Arena Types
struct memory_arena
{
platform_memory_block *CurrentBlock;
umm MinimumBlockSize;
s32 TemporaryMemoryCount;
u64 Position;
u64 CommitPosition;
u64 Size;
u64 Align;
u64 Unused[4];
};
struct temporary_memory
{
memory_arena *Arena;
platform_memory_block *Block;
umm Used;
u64 Position;
};
//- sixten: Arena push flags
////////////////////////////////
//~ sixten: Memory Arena Settings
#define MEMORY_ARENA_COMMIT_SIZE Kilobytes(4)
#define MEMORY_ARENA_DECOMMIT_THRESHOLD Megabytes(64)
enum arena_push_flag
{
ArenaFlag_ClearToZero = 0x1,
};
////////////////////////////////
//- sixten: Memory Arena Functions
struct arena_push_params
{
u32 Flags;
u32 Alignment;
};
static memory_arena *ArenaAllocate(u64 Size);
static void ArenaRelease(memory_arena *Arena);
static void *ArenaPushNoClear(memory_arena *Arena, u64 Size);
static void *ArenaPush(memory_arena *Arena, u64 Size);
static void ArenaPopTo(memory_arena *Arena, u64 Position);
static void ArenaClear(memory_arena *Arena);
static void ArenaSetAlign(memory_arena *Arena, u64 Align);
#define PushArray(Arena, type, Count) (type *)ArenaPush((Arena), sizeof(type)*(Count))
#define PushArrayNoClear(Arena, type, Count) (type *)ArenaPushNoClear((Arena), sizeof(type)*(Count))
#define PushStruct(Arena, type) (type *)ArenaPush((Arena), sizeof(type))
#define PushStructNoClear(Arena, type) (type *)ArenaPushNoClear((Arena), sizeof(type))
inline arena_push_params DefaultArenaParams(void)
{
arena_push_params Params = {};
Params.Flags = ArenaFlag_ClearToZero;
Params.Alignment = 4;
return(Params);
}
inline arena_push_params NoClear(void)
{
arena_push_params Params = DefaultArenaParams();
Params.Flags &= ~ArenaFlag_ClearToZero;
return(Params);
}
//- sixten: Memory arena functions
static void Release(memory_arena *Arena);
#define PushSize(Arena, InitialSize, ...) PushSize_(Arena, InitialSize, __VA_ARGS__)
#define PushStruct(Arena, type, ...) (type *)PushSize_(Arena, sizeof(type), __VA_ARGS__)
#define PushArray(Arena, type, Count, ...) (type *)PushSize_(Arena, sizeof(type)*Count, __VA_ARGS__)
static void *PushSize_(memory_arena *Arena, umm InitialSize, arena_push_params Params = DefaultArenaParams());
//- sixten: Bootstrapping helpers
#define BootstrapPushStruct(type, Member) (type *)BootstrapPushSize(sizeof(type), OffsetOf(type, Member))
static void *BootstrapPushSize(umm Size, umm OffsetToArena);
//- sixten: Temporary memory functions
////////////////////////////////
//- sixten: Temporary Memory Functions
static temporary_memory BeginTemporaryMemory(memory_arena *Arena);
static void EndTemporaryMemory(temporary_memory Temp);

View File

@ -186,7 +186,7 @@ static s64 LastIndexOf(string String, string Sub)
static string PushString(memory_arena *Arena, string String)
{
string Result;
Result.Data = PushArray(Arena, u8, String.Count, NoClear());
Result.Data = PushArrayNoClear(Arena, u8, String.Count);
Result.Count = String.Count;
Copy(Result.Data, String.Data, String.Count);
@ -200,7 +200,7 @@ static string PushFormatVariadic(memory_arena *Arena, char *Format, va_list Argu
string Result;
Result.Count = stbsp_vsnprintf(0, 0, Format, ArgumentsCopy);
Result.Data = PushArray(Arena, u8, Result.Count + 1, NoClear());
Result.Data = PushArrayNoClear(Arena, u8, Result.Count + 1);
Result.Data[Result.Count] = 0;
stbsp_vsnprintf((char *)Result.Data, (s32)Result.Count + 1, Format, Arguments);
@ -294,6 +294,41 @@ static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint)
return(Result);
}
//- sixten: Replacing
static string RemoveAll(memory_arena *Arena, string Text, char ToRemove)
{
//- sixten: get new count
s64 Occurrences = 0;
u8 *TextBegin = Text.Data;
u8 *TextEnd = TextBegin+Text.Count;
for(u8 *Char = TextBegin; Char != TextEnd; Char += 1)
{
if(*Char == ToRemove)
{
Occurrences += 1;
}
}
//- sixten: copy over all other bytes
s64 Count = Text.Count - Occurrences;
u8 *Data = PushArrayNoClear(Arena, u8, Count + 1);
Data[Count] = 0;
s64 Index = 0;
for(u8 *Char = TextBegin; Char != TextEnd; Char += 1)
{
if(*Char != ToRemove)
{
Data[Index] = *Char;
Index += 1;
}
}
string Result = MakeString(Data, Count);
return(Result);
}
//- sixten: "C Style" strings
static s64 StringLength(char *String)
@ -344,9 +379,136 @@ static string JoinStringList(string_list *List, memory_arena *Arena)
return(Result);
}
/////////////////////////////////////
//~ sixten: String Chunk Functions
static string_chunk_list MakeStringChunkList(s64 ChunkSize)
{
string_chunk_list Result = {};
Result.ChunkSize = ChunkSize;
return(Result);
}
static string JoinStringChunkList(memory_arena *Arena, string_chunk_list *List)
{
string Result = {};
Result.Count = List->TotalCount;
Result.Data = PushArrayNoClear(Arena, u8, List->TotalCount + 1);
s64 Index = 0;
s64 CountRemaining = List->TotalCount;
for(string_node *Node = List->First; Node != 0; Node = Node->Next)
{
string String = Node->String;
Copy(Result.Data + Index, String.Data, Min(CountRemaining, List->ChunkSize));
CountRemaining -= List->ChunkSize;
Index += String.Count;
}
return(Result);
}
// sixten(TODO): Incomplete, remove maybe?
static void ReplaceRange(memory_arena *Arena, string_chunk_list *List, string Text, range1_s64 Range)
{
s64 NewTotalCount = Max(0ULL, List->TotalCount - DimOfRange(Range)) + Text.Count;
//- sixten: do we need to allocate more chunks?
if(List->ChunkSize*List->ChunkCount < NewTotalCount)
{
s64 ChunksToAlloc = (NewTotalCount - List->ChunkSize*List->ChunkCount)/List->ChunkSize + 1;
for(s64 Index = 0; Index < ChunksToAlloc; Index += 1)
{
if(DLLIsEmpty(List->FirstFree))
{
string_node *Node = PushStructNoClear(Arena, string_node);
Node->String.Count = 0;
Node->String.Data = PushArrayNoClear(Arena, u8, List->ChunkSize);
DLLInsertLast(List->First, List->Last, Node);
}
else
{
string_node *Node = List->FirstFree;
Node->String.Count = 0;
DLLRemove(List->FirstFree, List->LastFree, Node);
DLLInsertLast(List->First, List->Last, Node);
}
}
List->ChunkCount += ChunksToAlloc;
}
s64 CountDelta = NewTotalCount - List->TotalCount;
// sixten: I cannot be bothered enough to figure out the correct implementation for this. However, if I do this - remember that you can rearrange
// the ordering of the linked list, instead of actually copying over the bytes for the majority of this.
Assert(AbsoluteValue(CountDelta) < List->ChunkSize);
//- sixten: find the first and last affected nodes
s64 FirstAffectedNodeIndex = Range.Min/List->ChunkSize;
s64 LastAffectedNodeIndex = Range.Max/List->ChunkSize;
string_node *FirstAffectedNode = List->First;
for(s64 WalkIndex = 0; WalkIndex < FirstAffectedNodeIndex; WalkIndex += 1)
{
FirstAffectedNode = FirstAffectedNode->Next;
}
string_node *LastAffectedNode = FirstAffectedNode;
for(s64 WalkIndex = 0; WalkIndex < LastAffectedNodeIndex-FirstAffectedNodeIndex; WalkIndex += 1)
{
LastAffectedNode = LastAffectedNode->Next;
}
if(CountDelta >= 0)
{
//- sixten: insertion - make room and the copy the data
s64 WriteOffset = Range.Min%List->ChunkSize;
for(string_node *Node = List->Last; Node != 0; Node = Node->Prev)
{
CopyReverse(Node->String.Data+CountDelta+WriteOffset, Node->String.Data+WriteOffset, List->ChunkSize-CountDelta-WriteOffset);
if(Node == LastAffectedNode)
{
break;
}
else
{
Copy(Node->String.Data, Node->Prev->String.Data+List->ChunkSize-CountDelta, CountDelta);
}
}
s64 SourceOffset = 0;
for(string_node *Node = FirstAffectedNode; Node != 0; Node = Node->Next)
{
Copy(Node->String.Data+WriteOffset, Text.Data+SourceOffset, Min(List->ChunkSize-WriteOffset, Text.Count-SourceOffset));
SourceOffset += List->ChunkSize;
if(Node == LastAffectedNode)
{
break;
}
}
}
else if(CountDelta < 0)
{
//- sixten: deletion
}
List->TotalCount = NewTotalCount;
}
//~ sixten: Unicode
read_only u8 UTF8Lengths[] =
{
1, 1, 1, 1, // 000xx
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
0, 0, 0, 0, // 100xx
0, 0, 0, 0,
2, 2, 2, 2, // 110xx
3, 3, // 1110x
4, // 11110
0, // 11111
};
static utf8_iterator IterateUTF8String(string String)
{
utf8_iterator Iter = {};
@ -432,3 +594,114 @@ static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
return(Length);
}
//~ sixten: Text point
static text_point TextPointFromOffset(string String, s64 Offset)
{
text_point Point = {1, 1};
for(s64 Index = 0;
Index < String.Count && Index < Offset;
++Index)
{
if(String.Data[Index] == '\n')
{
++Point.Line;
Point.Column = 1;
}
else
{
if(String.Data[Index] != '\r')
{
++Point.Column;
}
}
}
return(Point);
}
static s64 OffsetFromTextPoint(string String, text_point Point)
{
s64 Offset = 0;
Point.Line -= 1;
Point.Column -= 1;
u8 *StringBegin = String.Data;
u8 *StringEnd = StringBegin+String.Count;
u8 *Char = StringBegin;
//- sixten: find the start of the correct line
for(;Char < StringEnd && Point.Line > 0; Char += 1, Offset += 1)
{
if(*Char == '\n')
{
Point.Line -= 1;
}
}
for(;Char < StringEnd && Point.Column > 0; Char += 1, Offset += 1)
{
//- sixten: if a newline has been reached, the initial column was out of bounds
if(*Char == '\n')
{
break;
}
//- sixten: tabs are two-spaces, so we must take that into account
#if 0
if(*Char == '\t')
{
Point.Column -= 1;
}
#endif
Point.Column -= 1;
}
return(Offset);
}
static text_range TextRange(text_point A, text_point B)
{
text_range Result;
if(A.Line > B.Line || (A.Line == B.Line && A.Column > B.Column))
{
Result = {B, A};
}
else
{
Result = {A, B};
}
return(Result);
}
////////////////////////////////
//~ sixten: 1D Interval List & Array Functions
static void Range1S64ListPush(memory_arena *Arena, range1_s64_list *List, range1_s64 Range)
{
range1_s64_node *Node = PushStructNoClear(Arena, range1_s64_node);
Node->Range = Range;
QueuePush(List->First, List->Last, Node);
List->Count += 1;
}
static range1_s64_array Range1S64ArrayFromList(memory_arena *Arena, range1_s64_list *List)
{
range1_s64_array Result = {};
Result.Count = List->Count;
Result.Ranges = PushArray(Arena, range1_s64, List->Count);
s64 Index = 0;
for(range1_s64_node *Node = List->First; Node != 0; Node = Node->Next, Index += 1)
{
Result.Ranges[Index] = Node->Range;
}
return(Result);
}
static s64 OffsetFromTextPoint(string String, range1_s64_array Lines, text_point Point)
{
s64 LineIndex = Clamp(Point.Line, 1, Lines.Count) - 1;
range1_s64 Range = Lines.Ranges[LineIndex];
s64 ColumnIndex = Clamp(Point.Column, 1, DimOfRange(Range)) - 1;
s64 Offset = Range.Min+ColumnIndex;
return(Offset);
}

View File

@ -29,7 +29,22 @@ struct string_list
s64 TotalCount;
};
/////////////////////////////////////
//~ sixten: String Chunk Types
struct string_chunk_list
{
s64 ChunkSize;
s64 ChunkCount;
s64 TotalCount;
string_node *First;
string_node *Last;
string_node *FirstFree;
string_node *LastFree;
};
/////////////////////////////////////
//~ sixten: Char funcitons
inline b32 IsWhitespace(char C);
@ -37,6 +52,7 @@ inline b32 IsDigit(char C);
inline b32 IsLetter(char C);
/////////////////////////////////////
//~ sixten: String functions
//- sixten: Basic constructors
@ -79,11 +95,21 @@ static s64 ConvertStringToS64(string String);
static string ConvertS64ToString(memory_arena *Arena, s64 Value);
static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint);
//- sixten: Replacing
static string RemoveAll(memory_arena *Arena, string Text, char ToRemove);
//- sixten: "C Style" strings
static s64 StringLength(char *String);
/////////////////////////////////////
//~ sixten: String Chunk Functions
static string_chunk_list MakeStringChunkList(s64 ChunkSize);
static string JoinStringChunkList(memory_arena *Arena, string_chunk_list *List);
static void ReplaceRange(memory_arena *Arena, string_chunk_list *List, string Text, range1_s64 Range);
//~ sixten: String list
static void AppendString(string_list *List, string String, memory_arena *Arena);
@ -108,4 +134,50 @@ static b32 IsValid(utf8_iterator *Iter);
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint);
//~ sixten: Text point
struct text_point
{
s64 Line;
s64 Column;
};
struct text_range
{
text_point Min;
text_point Max;
};
static text_point TextPointFromOffset(string String, s64 Offset);
static s64 OffsetFromTextPoint(string String, text_point Point);
static text_range TextRange(text_point A, text_point B);
////////////////////////////////
//~ sixten: 1D Interval List & Array Types
struct range1_s64_node
{
range1_s64 Range;
range1_s64_node *Next;
};
struct range1_s64_list
{
s64 Count;
range1_s64_node *First;
range1_s64_node *Last;
};
struct range1_s64_array
{
s64 Count;
range1_s64 *Ranges;
};
////////////////////////////////
//~ sixten: 1D Interval List & Array Functions
static void Range1S64ListPush(memory_arena *Arena, range1_s64_list *List, range1_s64 Range);
static range1_s64_array Range1S64ArrayFromList(memory_arena *Arena, range1_s64_list *List);
static s64 OffsetFromTextPoint(string Text, range1_s64_array Lines, text_point Point);
#endif //CORE_STRING_H

View File

@ -1,5 +1,15 @@
per_thread thread_context *ThreadLocal_ThreadContext = 0;
static thread_context AllocateThreadContext(void)
{
thread_context Context = {};
for(s64 ArenaIndex = 0; ArenaIndex < ArrayCount(Context.Arenas); ArenaIndex += 1)
{
Context.Arenas[ArenaIndex] = ArenaAllocate(Gigabytes(1));
}
return(Context);
}
static void SetThreadContext(thread_context *Context)
{
ThreadLocal_ThreadContext = Context;
@ -25,7 +35,7 @@ static temporary_memory GetScratch(memory_arena **Conflicts, u64 ConflictCount)
++ConflictIndex)
{
memory_arena *Conflict = Conflicts[ConflictIndex];
if(Conflict == Context->Arenas + ArenaIndex)
if(Conflict == Context->Arenas[ArenaIndex])
{
FoundConflict = true;
break;
@ -34,7 +44,7 @@ static temporary_memory GetScratch(memory_arena **Conflicts, u64 ConflictCount)
if(!FoundConflict)
{
Scratch = BeginTemporaryMemory(Context->Arenas + ArenaIndex);
Scratch = BeginTemporaryMemory(Context->Arenas[ArenaIndex]);
break;
}
}

View File

@ -5,7 +5,7 @@
struct thread_context
{
memory_arena Arenas[2];
memory_arena *Arenas[2];
};
//- sixten: Thread state management

View File

@ -1,15 +0,0 @@
#include "core/core.h"
#include <stdio.h>
#define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0]))
#include "gen_opengl.cpp"
#include "gen_ui.cpp"
int main(int ArgumentCount, char **Arguments)
{
GenOpenGL();
GenUI();
return(0);
}

View File

@ -1,140 +0,0 @@
struct opengl_function
{
char *Name;
char *Type;
char *Arguments;
};
struct opengl_function OpenGLFunctionEntries[] =
{
{"BindTexture", "void", "GLenum target, GLuint texture"},
{"BlendFunc", "void", "GLenum sfactor, GLenum dfactor"},
{"Clear", "void", "GLbitfield mask"},
{"ClearAccum", "void", "GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha"},
{"ClearColor", "void", "GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha"},
{"ClearDepth", "void", "GLclampd depth"},
{"ClearIndex", "void", "GLfloat c"},
{"ClearStencil", "void", "GLint s"},
{"ClipPlane", "void", "GLenum plane, const GLdouble *equation"},
{"CullFace", "void", "GLenum mode"},
{"DeleteTextures", "void", "GLsizei n, const GLuint *textures"},
{"Disable", "void", "GLenum cap"},
{"DrawArrays", "void", "GLenum mode, GLint first, GLsizei count"},
{"DrawBuffer", "void", "GLenum mode"},
{"DrawElements", "void", "GLenum mode, GLsizei count, GLenum type, const GLvoid *indices"},
{"DrawArraysInstanced", "void", "GLenum mode, GLint first, GLsizei count, GLsizei instancecount"},
{"Enable", "void", "GLenum cap"},
{"GenTextures", "void", "GLsizei n, GLuint *textures"},
{"GetClipPlane", "void", "GLenum plane, GLdouble *equation"},
{"GetDoublev", "void", "GLenum pname, GLdouble *params"},
{"GetError", "GLenum", "void"},
{"GetFloatv", "void", "GLenum pname, GLfloat *params"},
{"GetIntegerv", "void", "GLenum pname, GLint *params"},
{"GetPointerv", "void", "GLenum pname, GLvoid* *params"},
{"GetString", "const GLubyte *", "GLenum name"},
{"GetTexEnvfv", "void", "GLenum target, GLenum pname, GLfloat *params"},
{"GetTexEnviv", "void", "GLenum target, GLenum pname, GLint *params"},
{"GetTexGendv", "void", "GLenum coord, GLenum pname, GLdouble *params"},
{"GetTexGenfv", "void", "GLenum coord, GLenum pname, GLfloat *params"},
{"GetTexGeniv", "void", "GLenum coord, GLenum pname, GLint *params"},
{"GetTexImage", "void", "GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels"},
{"GetTexLevelParameterfv", "void", "GLenum target, GLint level, GLenum pname, GLfloat *params"},
{"GetTexLevelParameteriv", "void", "GLenum target, GLint level, GLenum pname, GLint *params"},
{"GetTexParameterfv", "void", "GLenum target, GLenum pname, GLfloat *params"},
{"GetTexParameteriv", "void", "GLenum target, GLenum pname, GLint *params"},
{"Hint", "void", "GLenum target, GLenum mode"},
{"IsTexture", "GLboolean", "GLuint texture"},
{"LineWidth", "void", "GLfloat width"},
{"ListBase", "void", "GLuint base"},
{"LoadName", "void", "GLuint name"},
{"LogicOp", "void", "GLenum opcode"},
{"PointSize", "void", "GLfloat size"},
{"PolygonMode", "void", "GLenum face, GLenum mode"},
{"Scissor", "void", "GLint x, GLint y, GLsizei width, GLsizei height"},
{"TexImage1D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels"},
{"TexImage2D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels"},
{"TexParameterf", "void", "GLenum target, GLenum pname, GLfloat param"},
{"TexParameterfv", "void", "GLenum target, GLenum pname, const GLfloat *params"},
{"TexParameteri", "void", "GLenum target, GLenum pname, GLint param"},
{"TexParameteriv", "void", "GLenum target, GLenum pname, const GLint *params"},
{"TexSubImage1D", "void", "GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels"},
{"TexSubImage2D", "void", "GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels"},
{"CompressedTexImage2D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels"},
{"ActiveTexture", "void", "GLenum texture"},
{"Viewport", "void", "GLint x, GLint y, GLsizei width, GLsizei height"},
{"GenBuffers", "void", "GLsizei n, GLuint *buffers"},
{"BindBuffer", "void", "GLenum target, GLuint buffer"},
{"BufferData", "void", "GLenum target, GLsizeiptr size, const void *data, GLenum usage"},
{"BufferSubData", "void", "GLenum target, GLintptr offset, GLsizeiptr size, const void *data"},
{"GenVertexArrays", "void", "GLsizei n, GLuint *arrays"},
{"BindVertexArray", "void", "GLenum array"},
{"GetAttribLocation", "GLint", "GLuint program, const GLchar *name"},
{"EnableVertexAttribArray", "void", "GLuint index"},
{"DisableVertexAttribArray", "void", "GLuint index"},
{"VertexAttribPointer", "void", "GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer"},
{"VertexAttribIPointer", "void", "GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer"},
{"VertexAttribLPointer", "void", "GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer"},
{"VertexAttribDivisor", "void", "GLuint index, GLuint divisor"},
{"CreateShader", "GLuint", "GLenum type"},
{"ShaderSource", "void", "GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length"},
{"CompileShader", "void", "GLuint shader"},
{"DeleteShader", "void", "GLuint shader"},
{"GetShaderiv", "void", "GLuint shader, GLenum pname, GLint *params"},
{"GetShaderInfoLog", "void", "GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog"},
{"CreateProgram", "GLuint", "void"},
{"UseProgram", "void", "GLuint program"},
{"AttachShader", "void", "GLuint program, GLuint shader"},
{"DeleteProgram", "void", "GLuint program"},
{"LinkProgram", "void", "GLuint program"},
{"GetProgramiv", "void", "GLuint program, GLenum pname, GLint *params"},
{"GetProgramInfoLog", "void", "GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog"},
{"GetUniformLocation", "GLint", "GLuint program, const GLchar *name"},
{"Uniform1i", "void", "GLint location, GLint v0"},
{"Uniform2f", "void", "GLint location, GLfloat v0, GLfloat v1"},
{"Uniform3f", "void", "GLint location, GLfloat v0, GLfloat v1, GLfloat v2"},
{"UniformMatrix4fv", "void", "GLint location, GLsizei count, GLboolean transpose, const GLfloat *value"},
{"DebugMessageCallback", "void", "void (*)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar *, const void *), const void *userParam"},
};
static void GenOpenGL(void)
{
FILE *Out = fopen("../code/generated/vn_opengl_functions.h", "wb");
if(Out)
{
for(s32 Index = 0;
Index < ArrayCount(OpenGLFunctionEntries);
++Index)
{
struct opengl_function *Function = OpenGLFunctionEntries + Index;
fprintf(Out, "typedef %s opengl_%s(%s);\n", Function->Type, Function->Name, Function->Arguments);
}
fprintf(Out, "\n");
for(s32 Index = 0;
Index < ArrayCount(OpenGLFunctionEntries);
++Index)
{
struct opengl_function *Function = OpenGLFunctionEntries + Index;
fprintf(Out, "global opengl_%s *gl%s = 0;\n", Function->Name, Function->Name);
}
fprintf(Out, "\n");
fprintf(Out, "extern void *OpenGL_LoadFunction(char *);\n");
fprintf(Out, "\n");
fprintf(Out, "static void OpenGL_LoadAllFunctions(void)\n");
fprintf(Out, "{\n");
for(s32 Index = 0;
Index < ArrayCount(OpenGLFunctionEntries);
++Index)
{
struct opengl_function *Function = OpenGLFunctionEntries + Index;
fprintf(Out, "\tgl%s = (opengl_%s *)OpenGL_LoadFunction(\"gl%s\");\n", Function->Name, Function->Name, Function->Name);
}
fprintf(Out, "}\n");
fclose(Out);
}
}

View File

@ -1,129 +0,0 @@
struct ui_style_stack
{
char *Name;
char *Type;
char *MemberName;
};
ui_style_stack UIStyleStacks[] =
{
{ "Parent", "ui_box *", "Parent" },
{ "Width", "ui_size", "SemanticSize[Axis2_X]" },
{ "Height", "ui_size", "SemanticSize[Axis2_Y]" },
{ "FixedX", "r32", "FixedP.E[Axis2_X]" },
{ "FixedY", "r32", "FixedP.E[Axis2_Y]" },
{ "TextColor", "v4", "TextColor" },
{ "BackgroundColor", "v4", "BackgroundColor" },
{ "BorderColor", "v4", "BorderColor" },
{ "BorderThickness", "r32", "BorderThickness" },
{ "LayoutAxis", "axis2", "LayoutAxis" },
{ "CornerRadius", "r32", "CornerRadius" },
{ "Font", "font_id", "Font" },
{ "FontSize", "r32", "FontSize" },
{ "OffsetX", "r32", "Offset.x" },
{ "OffsetY", "r32", "Offset.y" },
};
static void GenUI(void)
{
FILE *Out = fopen("../code/generated/vn_generated_ui.h", "wb");
if(Out)
{
fprintf(Out, "struct ui_style_stacks\n");
fprintf(Out, "{\n");
for(s32 Index = 0;
Index < ArrayCount(UIStyleStacks);
++Index)
{
ui_style_stack Stack = UIStyleStacks[Index];
fprintf(Out, "\t%s %sStack[64];\n", Stack.Type, Stack.Name);
fprintf(Out, "\ts32 %sStackUsed;\n", Stack.Name);
fprintf(Out, "\tb32 AutoPop%s;\n", Stack.Name);
}
fprintf(Out, "};\n");
fclose(Out);
}
Out = fopen("../code/generated/vn_generated_ui.cpp", "wb");
if(Out)
{
for(s32 Index = 0;
Index < ArrayCount(UIStyleStacks);
++Index)
{
ui_style_stack Stack = UIStyleStacks[Index];
fprintf(Out, "inline void UI_Push%s(%s Element)\n", Stack.Name, Stack.Type);
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed + 1 < ArrayCount(UI->Stacks.%sStack));\n", Stack.Name, Stack.Name);
fprintf(Out, "\tUI->Stacks.%sStack[UI->Stacks.%sStackUsed++] = Element;\n", Stack.Name, Stack.Name);
fprintf(Out, "}\n");
fprintf(Out, "\n");
fprintf(Out, "inline void UI_Pop%s(void)\n", Stack.Name);
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed > 0);\n", Stack.Name);
fprintf(Out, "\t--UI->Stacks.%sStackUsed;\n", Stack.Name);
fprintf(Out, "}\n");
fprintf(Out, "\n");
fprintf(Out, "inline void UI_SetNext%s(%s Element)\n", Stack.Name, Stack.Type);
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
fprintf(Out, "\tUI_Push%s(Element);\n", Stack.Name);
fprintf(Out, "\tUI->Stacks.AutoPop%s = true;\n", Stack.Name);
fprintf(Out, "}\n");
fprintf(Out, "\n");
fprintf(Out, "inline %s UI_First%s(void)\n", Stack.Type, Stack.Name);
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
fprintf(Out, "\treturn(UI->Stacks.%sStack[0]);\n", Stack.Name);
fprintf(Out, "}\n");
fprintf(Out, "\n");
fprintf(Out, "inline %s UI_Top%s(void)\n", Stack.Type, Stack.Name);
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
fprintf(Out, "\treturn(UI->Stacks.%sStack[UI->Stacks.%sStackUsed - 1]);\n", Stack.Name, Stack.Name);
fprintf(Out, "}\n");
fprintf(Out, "\n");
fprintf(Out, "#define UI_%s(Element) DeferLoop(UI_Push%s(Element), UI_Pop%s())\n",
Stack.Name, Stack.Name, Stack.Name);
fprintf(Out, "\n");
}
fprintf(Out, "\n");
fprintf(Out, "inline void UI_ApplyStyles(ui_box *Box)\n");
fprintf(Out, "{\n");
fprintf(Out, "\tui *UI = UI_GetState();\n");
for(s32 Index = 0;
Index < ArrayCount(UIStyleStacks);
++Index)
{
ui_style_stack Stack = UIStyleStacks[Index];
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed > 0);\n", Stack.Name);
fprintf(Out, "\tBox->%s = UI->Stacks.%sStack[UI->Stacks.%sStackUsed - 1];\n",
Stack.MemberName, Stack.Name, Stack.Name);
fprintf(Out, "\tif(UI->Stacks.AutoPop%s)\n", Stack.Name);
fprintf(Out, "\t{\n");
fprintf(Out, "\t\tUI_Pop%s();\n", Stack.Name);
fprintf(Out, "\t\tUI->Stacks.AutoPop%s = false;\n", Stack.Name);
fprintf(Out, "\t}\n\n");
}
fprintf(Out, "}\n");
fclose(Out);
}
}

View File

@ -1,650 +0,0 @@
inline void UI_PushParent(ui_box * Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.ParentStackUsed + 1 < ArrayCount(UI->Stacks.ParentStack));
UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed++] = Element;
}
inline void UI_PopParent(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.ParentStackUsed > 0);
--UI->Stacks.ParentStackUsed;
}
inline void UI_SetNextParent(ui_box * Element)
{
ui *UI = UI_GetState();
UI_PushParent(Element);
UI->Stacks.AutoPopParent = true;
}
inline ui_box * UI_FirstParent(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.ParentStack[0]);
}
inline ui_box * UI_TopParent(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1]);
}
#define UI_Parent(Element) DeferLoop(UI_PushParent(Element), UI_PopParent())
inline void UI_PushWidth(ui_size Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.WidthStackUsed + 1 < ArrayCount(UI->Stacks.WidthStack));
UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed++] = Element;
}
inline void UI_PopWidth(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.WidthStackUsed > 0);
--UI->Stacks.WidthStackUsed;
}
inline void UI_SetNextWidth(ui_size Element)
{
ui *UI = UI_GetState();
UI_PushWidth(Element);
UI->Stacks.AutoPopWidth = true;
}
inline ui_size UI_FirstWidth(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.WidthStack[0]);
}
inline ui_size UI_TopWidth(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1]);
}
#define UI_Width(Element) DeferLoop(UI_PushWidth(Element), UI_PopWidth())
inline void UI_PushHeight(ui_size Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.HeightStackUsed + 1 < ArrayCount(UI->Stacks.HeightStack));
UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed++] = Element;
}
inline void UI_PopHeight(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.HeightStackUsed > 0);
--UI->Stacks.HeightStackUsed;
}
inline void UI_SetNextHeight(ui_size Element)
{
ui *UI = UI_GetState();
UI_PushHeight(Element);
UI->Stacks.AutoPopHeight = true;
}
inline ui_size UI_FirstHeight(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.HeightStack[0]);
}
inline ui_size UI_TopHeight(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1]);
}
#define UI_Height(Element) DeferLoop(UI_PushHeight(Element), UI_PopHeight())
inline void UI_PushFixedX(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FixedXStackUsed + 1 < ArrayCount(UI->Stacks.FixedXStack));
UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed++] = Element;
}
inline void UI_PopFixedX(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FixedXStackUsed > 0);
--UI->Stacks.FixedXStackUsed;
}
inline void UI_SetNextFixedX(r32 Element)
{
ui *UI = UI_GetState();
UI_PushFixedX(Element);
UI->Stacks.AutoPopFixedX = true;
}
inline r32 UI_FirstFixedX(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FixedXStack[0]);
}
inline r32 UI_TopFixedX(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1]);
}
#define UI_FixedX(Element) DeferLoop(UI_PushFixedX(Element), UI_PopFixedX())
inline void UI_PushFixedY(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FixedYStackUsed + 1 < ArrayCount(UI->Stacks.FixedYStack));
UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed++] = Element;
}
inline void UI_PopFixedY(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FixedYStackUsed > 0);
--UI->Stacks.FixedYStackUsed;
}
inline void UI_SetNextFixedY(r32 Element)
{
ui *UI = UI_GetState();
UI_PushFixedY(Element);
UI->Stacks.AutoPopFixedY = true;
}
inline r32 UI_FirstFixedY(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FixedYStack[0]);
}
inline r32 UI_TopFixedY(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1]);
}
#define UI_FixedY(Element) DeferLoop(UI_PushFixedY(Element), UI_PopFixedY())
inline void UI_PushTextColor(v4 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.TextColorStackUsed + 1 < ArrayCount(UI->Stacks.TextColorStack));
UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed++] = Element;
}
inline void UI_PopTextColor(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.TextColorStackUsed > 0);
--UI->Stacks.TextColorStackUsed;
}
inline void UI_SetNextTextColor(v4 Element)
{
ui *UI = UI_GetState();
UI_PushTextColor(Element);
UI->Stacks.AutoPopTextColor = true;
}
inline v4 UI_FirstTextColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.TextColorStack[0]);
}
inline v4 UI_TopTextColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1]);
}
#define UI_TextColor(Element) DeferLoop(UI_PushTextColor(Element), UI_PopTextColor())
inline void UI_PushBackgroundColor(v4 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BackgroundColorStackUsed + 1 < ArrayCount(UI->Stacks.BackgroundColorStack));
UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed++] = Element;
}
inline void UI_PopBackgroundColor(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BackgroundColorStackUsed > 0);
--UI->Stacks.BackgroundColorStackUsed;
}
inline void UI_SetNextBackgroundColor(v4 Element)
{
ui *UI = UI_GetState();
UI_PushBackgroundColor(Element);
UI->Stacks.AutoPopBackgroundColor = true;
}
inline v4 UI_FirstBackgroundColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BackgroundColorStack[0]);
}
inline v4 UI_TopBackgroundColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1]);
}
#define UI_BackgroundColor(Element) DeferLoop(UI_PushBackgroundColor(Element), UI_PopBackgroundColor())
inline void UI_PushBorderColor(v4 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BorderColorStackUsed + 1 < ArrayCount(UI->Stacks.BorderColorStack));
UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed++] = Element;
}
inline void UI_PopBorderColor(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BorderColorStackUsed > 0);
--UI->Stacks.BorderColorStackUsed;
}
inline void UI_SetNextBorderColor(v4 Element)
{
ui *UI = UI_GetState();
UI_PushBorderColor(Element);
UI->Stacks.AutoPopBorderColor = true;
}
inline v4 UI_FirstBorderColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BorderColorStack[0]);
}
inline v4 UI_TopBorderColor(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1]);
}
#define UI_BorderColor(Element) DeferLoop(UI_PushBorderColor(Element), UI_PopBorderColor())
inline void UI_PushBorderThickness(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BorderThicknessStackUsed + 1 < ArrayCount(UI->Stacks.BorderThicknessStack));
UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed++] = Element;
}
inline void UI_PopBorderThickness(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.BorderThicknessStackUsed > 0);
--UI->Stacks.BorderThicknessStackUsed;
}
inline void UI_SetNextBorderThickness(r32 Element)
{
ui *UI = UI_GetState();
UI_PushBorderThickness(Element);
UI->Stacks.AutoPopBorderThickness = true;
}
inline r32 UI_FirstBorderThickness(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BorderThicknessStack[0]);
}
inline r32 UI_TopBorderThickness(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1]);
}
#define UI_BorderThickness(Element) DeferLoop(UI_PushBorderThickness(Element), UI_PopBorderThickness())
inline void UI_PushLayoutAxis(axis2 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.LayoutAxisStackUsed + 1 < ArrayCount(UI->Stacks.LayoutAxisStack));
UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed++] = Element;
}
inline void UI_PopLayoutAxis(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.LayoutAxisStackUsed > 0);
--UI->Stacks.LayoutAxisStackUsed;
}
inline void UI_SetNextLayoutAxis(axis2 Element)
{
ui *UI = UI_GetState();
UI_PushLayoutAxis(Element);
UI->Stacks.AutoPopLayoutAxis = true;
}
inline axis2 UI_FirstLayoutAxis(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.LayoutAxisStack[0]);
}
inline axis2 UI_TopLayoutAxis(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1]);
}
#define UI_LayoutAxis(Element) DeferLoop(UI_PushLayoutAxis(Element), UI_PopLayoutAxis())
inline void UI_PushCornerRadius(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.CornerRadiusStackUsed + 1 < ArrayCount(UI->Stacks.CornerRadiusStack));
UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed++] = Element;
}
inline void UI_PopCornerRadius(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.CornerRadiusStackUsed > 0);
--UI->Stacks.CornerRadiusStackUsed;
}
inline void UI_SetNextCornerRadius(r32 Element)
{
ui *UI = UI_GetState();
UI_PushCornerRadius(Element);
UI->Stacks.AutoPopCornerRadius = true;
}
inline r32 UI_FirstCornerRadius(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.CornerRadiusStack[0]);
}
inline r32 UI_TopCornerRadius(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1]);
}
#define UI_CornerRadius(Element) DeferLoop(UI_PushCornerRadius(Element), UI_PopCornerRadius())
inline void UI_PushFont(font_id Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FontStackUsed + 1 < ArrayCount(UI->Stacks.FontStack));
UI->Stacks.FontStack[UI->Stacks.FontStackUsed++] = Element;
}
inline void UI_PopFont(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FontStackUsed > 0);
--UI->Stacks.FontStackUsed;
}
inline void UI_SetNextFont(font_id Element)
{
ui *UI = UI_GetState();
UI_PushFont(Element);
UI->Stacks.AutoPopFont = true;
}
inline font_id UI_FirstFont(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FontStack[0]);
}
inline font_id UI_TopFont(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1]);
}
#define UI_Font(Element) DeferLoop(UI_PushFont(Element), UI_PopFont())
inline void UI_PushFontSize(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FontSizeStackUsed + 1 < ArrayCount(UI->Stacks.FontSizeStack));
UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed++] = Element;
}
inline void UI_PopFontSize(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.FontSizeStackUsed > 0);
--UI->Stacks.FontSizeStackUsed;
}
inline void UI_SetNextFontSize(r32 Element)
{
ui *UI = UI_GetState();
UI_PushFontSize(Element);
UI->Stacks.AutoPopFontSize = true;
}
inline r32 UI_FirstFontSize(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FontSizeStack[0]);
}
inline r32 UI_TopFontSize(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]);
}
#define UI_FontSize(Element) DeferLoop(UI_PushFontSize(Element), UI_PopFontSize())
inline void UI_PushOffsetX(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.OffsetXStackUsed + 1 < ArrayCount(UI->Stacks.OffsetXStack));
UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed++] = Element;
}
inline void UI_PopOffsetX(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.OffsetXStackUsed > 0);
--UI->Stacks.OffsetXStackUsed;
}
inline void UI_SetNextOffsetX(r32 Element)
{
ui *UI = UI_GetState();
UI_PushOffsetX(Element);
UI->Stacks.AutoPopOffsetX = true;
}
inline r32 UI_FirstOffsetX(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.OffsetXStack[0]);
}
inline r32 UI_TopOffsetX(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1]);
}
#define UI_OffsetX(Element) DeferLoop(UI_PushOffsetX(Element), UI_PopOffsetX())
inline void UI_PushOffsetY(r32 Element)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.OffsetYStackUsed + 1 < ArrayCount(UI->Stacks.OffsetYStack));
UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed++] = Element;
}
inline void UI_PopOffsetY(void)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.OffsetYStackUsed > 0);
--UI->Stacks.OffsetYStackUsed;
}
inline void UI_SetNextOffsetY(r32 Element)
{
ui *UI = UI_GetState();
UI_PushOffsetY(Element);
UI->Stacks.AutoPopOffsetY = true;
}
inline r32 UI_FirstOffsetY(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.OffsetYStack[0]);
}
inline r32 UI_TopOffsetY(void)
{
ui *UI = UI_GetState();
return(UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1]);
}
#define UI_OffsetY(Element) DeferLoop(UI_PushOffsetY(Element), UI_PopOffsetY())
inline void UI_ApplyStyles(ui_box *Box)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.ParentStackUsed > 0);
Box->Parent = UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1];
if(UI->Stacks.AutoPopParent)
{
UI_PopParent();
UI->Stacks.AutoPopParent = false;
}
Assert(UI->Stacks.WidthStackUsed > 0);
Box->SemanticSize[Axis2_X] = UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1];
if(UI->Stacks.AutoPopWidth)
{
UI_PopWidth();
UI->Stacks.AutoPopWidth = false;
}
Assert(UI->Stacks.HeightStackUsed > 0);
Box->SemanticSize[Axis2_Y] = UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1];
if(UI->Stacks.AutoPopHeight)
{
UI_PopHeight();
UI->Stacks.AutoPopHeight = false;
}
Assert(UI->Stacks.FixedXStackUsed > 0);
Box->FixedP.E[Axis2_X] = UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1];
if(UI->Stacks.AutoPopFixedX)
{
UI_PopFixedX();
UI->Stacks.AutoPopFixedX = false;
}
Assert(UI->Stacks.FixedYStackUsed > 0);
Box->FixedP.E[Axis2_Y] = UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1];
if(UI->Stacks.AutoPopFixedY)
{
UI_PopFixedY();
UI->Stacks.AutoPopFixedY = false;
}
Assert(UI->Stacks.TextColorStackUsed > 0);
Box->TextColor = UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1];
if(UI->Stacks.AutoPopTextColor)
{
UI_PopTextColor();
UI->Stacks.AutoPopTextColor = false;
}
Assert(UI->Stacks.BackgroundColorStackUsed > 0);
Box->BackgroundColor = UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1];
if(UI->Stacks.AutoPopBackgroundColor)
{
UI_PopBackgroundColor();
UI->Stacks.AutoPopBackgroundColor = false;
}
Assert(UI->Stacks.BorderColorStackUsed > 0);
Box->BorderColor = UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1];
if(UI->Stacks.AutoPopBorderColor)
{
UI_PopBorderColor();
UI->Stacks.AutoPopBorderColor = false;
}
Assert(UI->Stacks.BorderThicknessStackUsed > 0);
Box->BorderThickness = UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1];
if(UI->Stacks.AutoPopBorderThickness)
{
UI_PopBorderThickness();
UI->Stacks.AutoPopBorderThickness = false;
}
Assert(UI->Stacks.LayoutAxisStackUsed > 0);
Box->LayoutAxis = UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1];
if(UI->Stacks.AutoPopLayoutAxis)
{
UI_PopLayoutAxis();
UI->Stacks.AutoPopLayoutAxis = false;
}
Assert(UI->Stacks.CornerRadiusStackUsed > 0);
Box->CornerRadius = UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1];
if(UI->Stacks.AutoPopCornerRadius)
{
UI_PopCornerRadius();
UI->Stacks.AutoPopCornerRadius = false;
}
Assert(UI->Stacks.FontStackUsed > 0);
Box->Font = UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1];
if(UI->Stacks.AutoPopFont)
{
UI_PopFont();
UI->Stacks.AutoPopFont = false;
}
Assert(UI->Stacks.FontSizeStackUsed > 0);
Box->FontSize = UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1];
if(UI->Stacks.AutoPopFontSize)
{
UI_PopFontSize();
UI->Stacks.AutoPopFontSize = false;
}
Assert(UI->Stacks.OffsetXStackUsed > 0);
Box->Offset.x = UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1];
if(UI->Stacks.AutoPopOffsetX)
{
UI_PopOffsetX();
UI->Stacks.AutoPopOffsetX = false;
}
Assert(UI->Stacks.OffsetYStackUsed > 0);
Box->Offset.y = UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1];
if(UI->Stacks.AutoPopOffsetY)
{
UI_PopOffsetY();
UI->Stacks.AutoPopOffsetY = false;
}
}

View File

@ -1,48 +0,0 @@
struct ui_style_stacks
{
ui_box * ParentStack[64];
s32 ParentStackUsed;
b32 AutoPopParent;
ui_size WidthStack[64];
s32 WidthStackUsed;
b32 AutoPopWidth;
ui_size HeightStack[64];
s32 HeightStackUsed;
b32 AutoPopHeight;
r32 FixedXStack[64];
s32 FixedXStackUsed;
b32 AutoPopFixedX;
r32 FixedYStack[64];
s32 FixedYStackUsed;
b32 AutoPopFixedY;
v4 TextColorStack[64];
s32 TextColorStackUsed;
b32 AutoPopTextColor;
v4 BackgroundColorStack[64];
s32 BackgroundColorStackUsed;
b32 AutoPopBackgroundColor;
v4 BorderColorStack[64];
s32 BorderColorStackUsed;
b32 AutoPopBorderColor;
r32 BorderThicknessStack[64];
s32 BorderThicknessStackUsed;
b32 AutoPopBorderThickness;
axis2 LayoutAxisStack[64];
s32 LayoutAxisStackUsed;
b32 AutoPopLayoutAxis;
r32 CornerRadiusStack[64];
s32 CornerRadiusStackUsed;
b32 AutoPopCornerRadius;
font_id FontStack[64];
s32 FontStackUsed;
b32 AutoPopFont;
r32 FontSizeStack[64];
s32 FontSizeStackUsed;
b32 AutoPopFontSize;
r32 OffsetXStack[64];
s32 OffsetXStackUsed;
b32 AutoPopOffsetX;
r32 OffsetYStack[64];
s32 OffsetYStackUsed;
b32 AutoPopOffsetY;
};

View File

@ -175,7 +175,6 @@ global opengl_UniformMatrix4fv *glUniformMatrix4fv = 0;
global opengl_DebugMessageCallback *glDebugMessageCallback = 0;
extern void *OpenGL_LoadFunction(char *);
static void OpenGL_LoadAllFunctions(void)
{
glBindTexture = (opengl_BindTexture *)OpenGL_LoadFunction("glBindTexture");
@ -266,3 +265,4 @@ static void OpenGL_LoadAllFunctions(void)
glUniformMatrix4fv = (opengl_UniformMatrix4fv *)OpenGL_LoadFunction("glUniformMatrix4fv");
glDebugMessageCallback = (opengl_DebugMessageCallback *)OpenGL_LoadFunction("glDebugMessageCallback");
}

View File

View File

@ -0,0 +1,56 @@
#define PLATFORM_RESERVE(name) void * name(u64 Size)
#define PLATFORM_RELEASE(name) void name(void *Pointer)
#define PLATFORM_COMMIT(name) void name(void *Pointer, u64 Size)
#define PLATFORM_DECOMMIT(name) void name(void *Pointer, u64 Size)
#define PLATFORM_OPEN_FILE(name) platform_file_handle name(string Path, platform_access_flags FileAccess)
#define PLATFORM_CLOSE_FILE(name) void name(platform_file_handle Handle)
#define PLATFORM_READ_FILE(name) void name(platform_file_handle Handle, void *Dest, u64 Offset, u64 Size)
#define PLATFORM_WRITE_FILE(name) void name(platform_file_handle Handle, void *Source, u64 Offset, u64 Size)
#define PLATFORM_GET_FILE_SIZE(name) u64 name(platform_file_handle Handle)
#define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor)
#define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void)
#define PLATFORM_SHOW_MESSAGE(name) void name(string Message, platform_message_type Type)
typedef PLATFORM_RESERVE(platform_reserve);
typedef PLATFORM_RELEASE(platform_release);
typedef PLATFORM_COMMIT(platform_commit);
typedef PLATFORM_DECOMMIT(platform_decommit);
typedef PLATFORM_OPEN_FILE(platform_open_file);
typedef PLATFORM_CLOSE_FILE(platform_close_file);
typedef PLATFORM_READ_FILE(platform_read_file);
typedef PLATFORM_WRITE_FILE(platform_write_file);
typedef PLATFORM_GET_FILE_SIZE(platform_get_file_size);
typedef PLATFORM_SET_CURSOR(platform_set_cursor);
typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen);
typedef PLATFORM_SHOW_MESSAGE(platform_show_message);
struct platform_api
{
platform_reserve *Reserve;
platform_release *Release;
platform_commit *Commit;
platform_decommit *Decommit;
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;
};
#define RegisterPlatformFunctions(PlatformName)\
Platform.Reserve = PlatformName##_Reserve;\
Platform.Release = PlatformName##_Release;\
Platform.Commit = PlatformName##_Commit;\
Platform.Decommit = PlatformName##_Decommit;\
Platform.OpenFile = PlatformName##_OpenFile;\
Platform.CloseFile = PlatformName##_CloseFile;\
Platform.ReadFile = PlatformName##_ReadFile;\
Platform.WriteFile = PlatformName##_WriteFile;\
Platform.GetFileSize = PlatformName##_GetFileSize;\
Platform.SetCursor = PlatformName##_SetCursor;\
Platform.ToggleFullscreen = PlatformName##_ToggleFullscreen;\
Platform.ShowMessage = PlatformName##_ShowMessage;\

View File

View File

@ -0,0 +1,25 @@
enum scene_ast_node_type
{
S_AstNode_Invalid,
S_AstNode_BlockStatement,
S_AstNode_SceneDecl,
S_AstNode_Count,
};
struct scene_ast_node;
struct scene_ast_node_invalid {};
struct scene_ast_node_block_statement {scene_ast_node *First; scene_ast_node *Last;};
struct scene_ast_node_scene_declaration {};
struct scene_ast_node
{
scene_ast_node_type Type;
union
{
scene_ast_node_invalid InvalidData;
scene_ast_node_block_statement BlockStatementData;
scene_ast_node_scene_declaration SceneDeclData;
};
};

View File

@ -0,0 +1,111 @@
inline void UI_PushParent(ui_box * Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.ParentStackUsed + 1 < ArrayCount(UI->Stacks.ParentStack)); UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed++] = Element; }
inline void UI_PushWidth(ui_size Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.WidthStackUsed + 1 < ArrayCount(UI->Stacks.WidthStack)); UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed++] = Element; }
inline void UI_PushHeight(ui_size Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.HeightStackUsed + 1 < ArrayCount(UI->Stacks.HeightStack)); UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed++] = Element; }
inline void UI_PushFixedX(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.FixedXStackUsed + 1 < ArrayCount(UI->Stacks.FixedXStack)); UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed++] = Element; }
inline void UI_PushFixedY(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.FixedYStackUsed + 1 < ArrayCount(UI->Stacks.FixedYStack)); UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed++] = Element; }
inline void UI_PushTextColor(v4 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.TextColorStackUsed + 1 < ArrayCount(UI->Stacks.TextColorStack)); UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed++] = Element; }
inline void UI_PushBackgroundColor(v4 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.BackgroundColorStackUsed + 1 < ArrayCount(UI->Stacks.BackgroundColorStack)); UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed++] = Element; }
inline void UI_PushBorderColor(v4 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.BorderColorStackUsed + 1 < ArrayCount(UI->Stacks.BorderColorStack)); UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed++] = Element; }
inline void UI_PushBorderThickness(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.BorderThicknessStackUsed + 1 < ArrayCount(UI->Stacks.BorderThicknessStack)); UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed++] = Element; }
inline void UI_PushLayoutAxis(axis2 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.LayoutAxisStackUsed + 1 < ArrayCount(UI->Stacks.LayoutAxisStack)); UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed++] = Element; }
inline void UI_PushCornerRadius(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.CornerRadiusStackUsed + 1 < ArrayCount(UI->Stacks.CornerRadiusStack)); UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed++] = Element; }
inline void UI_PushFont(font_id Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontStackUsed + 1 < ArrayCount(UI->Stacks.FontStack)); UI->Stacks.FontStack[UI->Stacks.FontStackUsed++] = Element; }
inline void UI_PushFontSize(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontSizeStackUsed + 1 < ArrayCount(UI->Stacks.FontSizeStack)); UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed++] = Element; }
inline void UI_PushOffsetX(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetXStackUsed + 1 < ArrayCount(UI->Stacks.OffsetXStack)); UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed++] = Element; }
inline void UI_PushOffsetY(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetYStackUsed + 1 < ArrayCount(UI->Stacks.OffsetYStack)); UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed++] = Element; }
inline void UI_PopParent(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.ParentStackUsed > 0); --UI->Stacks.ParentStackUsed; }
inline void UI_PopWidth(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.WidthStackUsed > 0); --UI->Stacks.WidthStackUsed; }
inline void UI_PopHeight(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.HeightStackUsed > 0); --UI->Stacks.HeightStackUsed; }
inline void UI_PopFixedX(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.FixedXStackUsed > 0); --UI->Stacks.FixedXStackUsed; }
inline void UI_PopFixedY(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.FixedYStackUsed > 0); --UI->Stacks.FixedYStackUsed; }
inline void UI_PopTextColor(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.TextColorStackUsed > 0); --UI->Stacks.TextColorStackUsed; }
inline void UI_PopBackgroundColor(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.BackgroundColorStackUsed > 0); --UI->Stacks.BackgroundColorStackUsed; }
inline void UI_PopBorderColor(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.BorderColorStackUsed > 0); --UI->Stacks.BorderColorStackUsed; }
inline void UI_PopBorderThickness(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.BorderThicknessStackUsed > 0); --UI->Stacks.BorderThicknessStackUsed; }
inline void UI_PopLayoutAxis(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.LayoutAxisStackUsed > 0); --UI->Stacks.LayoutAxisStackUsed; }
inline void UI_PopCornerRadius(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.CornerRadiusStackUsed > 0); --UI->Stacks.CornerRadiusStackUsed; }
inline void UI_PopFont(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontStackUsed > 0); --UI->Stacks.FontStackUsed; }
inline void UI_PopFontSize(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontSizeStackUsed > 0); --UI->Stacks.FontSizeStackUsed; }
inline void UI_PopOffsetX(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetXStackUsed > 0); --UI->Stacks.OffsetXStackUsed; }
inline void UI_PopOffsetY(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetYStackUsed > 0); --UI->Stacks.OffsetYStackUsed; }
inline void UI_SetNextParent(ui_box * Element) { ui *UI = UI_GetState(); UI_PushParent(Element); UI->Stacks.AutoPopParent = true; }
inline void UI_SetNextWidth(ui_size Element) { ui *UI = UI_GetState(); UI_PushWidth(Element); UI->Stacks.AutoPopWidth = true; }
inline void UI_SetNextHeight(ui_size Element) { ui *UI = UI_GetState(); UI_PushHeight(Element); UI->Stacks.AutoPopHeight = true; }
inline void UI_SetNextFixedX(r32 Element) { ui *UI = UI_GetState(); UI_PushFixedX(Element); UI->Stacks.AutoPopFixedX = true; }
inline void UI_SetNextFixedY(r32 Element) { ui *UI = UI_GetState(); UI_PushFixedY(Element); UI->Stacks.AutoPopFixedY = true; }
inline void UI_SetNextTextColor(v4 Element) { ui *UI = UI_GetState(); UI_PushTextColor(Element); UI->Stacks.AutoPopTextColor = true; }
inline void UI_SetNextBackgroundColor(v4 Element) { ui *UI = UI_GetState(); UI_PushBackgroundColor(Element); UI->Stacks.AutoPopBackgroundColor = true; }
inline void UI_SetNextBorderColor(v4 Element) { ui *UI = UI_GetState(); UI_PushBorderColor(Element); UI->Stacks.AutoPopBorderColor = true; }
inline void UI_SetNextBorderThickness(r32 Element) { ui *UI = UI_GetState(); UI_PushBorderThickness(Element); UI->Stacks.AutoPopBorderThickness = true; }
inline void UI_SetNextLayoutAxis(axis2 Element) { ui *UI = UI_GetState(); UI_PushLayoutAxis(Element); UI->Stacks.AutoPopLayoutAxis = true; }
inline void UI_SetNextCornerRadius(r32 Element) { ui *UI = UI_GetState(); UI_PushCornerRadius(Element); UI->Stacks.AutoPopCornerRadius = true; }
inline void UI_SetNextFont(font_id Element) { ui *UI = UI_GetState(); UI_PushFont(Element); UI->Stacks.AutoPopFont = true; }
inline void UI_SetNextFontSize(r32 Element) { ui *UI = UI_GetState(); UI_PushFontSize(Element); UI->Stacks.AutoPopFontSize = true; }
inline void UI_SetNextOffsetX(r32 Element) { ui *UI = UI_GetState(); UI_PushOffsetX(Element); UI->Stacks.AutoPopOffsetX = true; }
inline void UI_SetNextOffsetY(r32 Element) { ui *UI = UI_GetState(); UI_PushOffsetY(Element); UI->Stacks.AutoPopOffsetY = true; }
inline ui_box * UI_FirstParent(void) { ui *UI = UI_GetState(); return(UI->Stacks.ParentStack[0]); }
inline ui_size UI_FirstWidth(void) { ui *UI = UI_GetState(); return(UI->Stacks.WidthStack[0]); }
inline ui_size UI_FirstHeight(void) { ui *UI = UI_GetState(); return(UI->Stacks.HeightStack[0]); }
inline r32 UI_FirstFixedX(void) { ui *UI = UI_GetState(); return(UI->Stacks.FixedXStack[0]); }
inline r32 UI_FirstFixedY(void) { ui *UI = UI_GetState(); return(UI->Stacks.FixedYStack[0]); }
inline v4 UI_FirstTextColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.TextColorStack[0]); }
inline v4 UI_FirstBackgroundColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.BackgroundColorStack[0]); }
inline v4 UI_FirstBorderColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.BorderColorStack[0]); }
inline r32 UI_FirstBorderThickness(void) { ui *UI = UI_GetState(); return(UI->Stacks.BorderThicknessStack[0]); }
inline axis2 UI_FirstLayoutAxis(void) { ui *UI = UI_GetState(); return(UI->Stacks.LayoutAxisStack[0]); }
inline r32 UI_FirstCornerRadius(void) { ui *UI = UI_GetState(); return(UI->Stacks.CornerRadiusStack[0]); }
inline font_id UI_FirstFont(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontStack[0]); }
inline r32 UI_FirstFontSize(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontSizeStack[0]); }
inline r32 UI_FirstOffsetX(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetXStack[0]); }
inline r32 UI_FirstOffsetY(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetYStack[0]); }
inline ui_box * UI_TopParent(void) { ui *UI = UI_GetState(); return(UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1]); }
inline ui_size UI_TopWidth(void) { ui *UI = UI_GetState(); return(UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1]); }
inline ui_size UI_TopHeight(void) { ui *UI = UI_GetState(); return(UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1]); }
inline r32 UI_TopFixedX(void) { ui *UI = UI_GetState(); return(UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1]); }
inline r32 UI_TopFixedY(void) { ui *UI = UI_GetState(); return(UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1]); }
inline v4 UI_TopTextColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1]); }
inline v4 UI_TopBackgroundColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1]); }
inline v4 UI_TopBorderColor(void) { ui *UI = UI_GetState(); return(UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1]); }
inline r32 UI_TopBorderThickness(void) { ui *UI = UI_GetState(); return(UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1]); }
inline axis2 UI_TopLayoutAxis(void) { ui *UI = UI_GetState(); return(UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1]); }
inline r32 UI_TopCornerRadius(void) { ui *UI = UI_GetState(); return(UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1]); }
inline font_id UI_TopFont(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1]); }
inline r32 UI_TopFontSize(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]); }
inline r32 UI_TopOffsetX(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1]); }
inline r32 UI_TopOffsetY(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1]); }
#define UI_Parent(Element) DeferLoop(UI_PushParent(Element), UI_PopParent())
#define UI_Width(Element) DeferLoop(UI_PushWidth(Element), UI_PopWidth())
#define UI_Height(Element) DeferLoop(UI_PushHeight(Element), UI_PopHeight())
#define UI_FixedX(Element) DeferLoop(UI_PushFixedX(Element), UI_PopFixedX())
#define UI_FixedY(Element) DeferLoop(UI_PushFixedY(Element), UI_PopFixedY())
#define UI_TextColor(Element) DeferLoop(UI_PushTextColor(Element), UI_PopTextColor())
#define UI_BackgroundColor(Element) DeferLoop(UI_PushBackgroundColor(Element), UI_PopBackgroundColor())
#define UI_BorderColor(Element) DeferLoop(UI_PushBorderColor(Element), UI_PopBorderColor())
#define UI_BorderThickness(Element) DeferLoop(UI_PushBorderThickness(Element), UI_PopBorderThickness())
#define UI_LayoutAxis(Element) DeferLoop(UI_PushLayoutAxis(Element), UI_PopLayoutAxis())
#define UI_CornerRadius(Element) DeferLoop(UI_PushCornerRadius(Element), UI_PopCornerRadius())
#define UI_Font(Element) DeferLoop(UI_PushFont(Element), UI_PopFont())
#define UI_FontSize(Element) DeferLoop(UI_PushFontSize(Element), UI_PopFontSize())
#define UI_OffsetX(Element) DeferLoop(UI_PushOffsetX(Element), UI_PopOffsetX())
#define UI_OffsetY(Element) DeferLoop(UI_PushOffsetY(Element), UI_PopOffsetY())
static void UI_ApplyStyles(ui_box *Box)
{
ui *UI = UI_GetState();
Assert(UI->Stacks.ParentStackUsed > 0); Box->Parent = UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1]; if(UI->Stacks.AutoPopParent) { UI_PopParent(); UI->Stacks.AutoPopParent = false; }
Assert(UI->Stacks.WidthStackUsed > 0); Box->SemanticSize[Axis2_X] = UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1]; if(UI->Stacks.AutoPopWidth) { UI_PopWidth(); UI->Stacks.AutoPopWidth = false; }
Assert(UI->Stacks.HeightStackUsed > 0); Box->SemanticSize[Axis2_Y] = UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1]; if(UI->Stacks.AutoPopHeight) { UI_PopHeight(); UI->Stacks.AutoPopHeight = false; }
Assert(UI->Stacks.FixedXStackUsed > 0); Box->FixedP.E[Axis2_X] = UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1]; if(UI->Stacks.AutoPopFixedX) { UI_PopFixedX(); UI->Stacks.AutoPopFixedX = false; }
Assert(UI->Stacks.FixedYStackUsed > 0); Box->FixedP.E[Axis2_Y] = UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1]; if(UI->Stacks.AutoPopFixedY) { UI_PopFixedY(); UI->Stacks.AutoPopFixedY = false; }
Assert(UI->Stacks.TextColorStackUsed > 0); Box->TextColor = UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1]; if(UI->Stacks.AutoPopTextColor) { UI_PopTextColor(); UI->Stacks.AutoPopTextColor = false; }
Assert(UI->Stacks.BackgroundColorStackUsed > 0); Box->BackgroundColor = UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1]; if(UI->Stacks.AutoPopBackgroundColor) { UI_PopBackgroundColor(); UI->Stacks.AutoPopBackgroundColor = false; }
Assert(UI->Stacks.BorderColorStackUsed > 0); Box->BorderColor = UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1]; if(UI->Stacks.AutoPopBorderColor) { UI_PopBorderColor(); UI->Stacks.AutoPopBorderColor = false; }
Assert(UI->Stacks.BorderThicknessStackUsed > 0); Box->BorderThickness = UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1]; if(UI->Stacks.AutoPopBorderThickness) { UI_PopBorderThickness(); UI->Stacks.AutoPopBorderThickness = false; }
Assert(UI->Stacks.LayoutAxisStackUsed > 0); Box->LayoutAxis = UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1]; if(UI->Stacks.AutoPopLayoutAxis) { UI_PopLayoutAxis(); UI->Stacks.AutoPopLayoutAxis = false; }
Assert(UI->Stacks.CornerRadiusStackUsed > 0); Box->CornerRadius = UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1]; if(UI->Stacks.AutoPopCornerRadius) { UI_PopCornerRadius(); UI->Stacks.AutoPopCornerRadius = false; }
Assert(UI->Stacks.FontStackUsed > 0); Box->Font = UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1]; if(UI->Stacks.AutoPopFont) { UI_PopFont(); UI->Stacks.AutoPopFont = false; }
Assert(UI->Stacks.FontSizeStackUsed > 0); Box->FontSize = UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]; if(UI->Stacks.AutoPopFontSize) { UI_PopFontSize(); UI->Stacks.AutoPopFontSize = false; }
Assert(UI->Stacks.OffsetXStackUsed > 0); Box->Offset.x = UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1]; if(UI->Stacks.AutoPopOffsetX) { UI_PopOffsetX(); UI->Stacks.AutoPopOffsetX = false; }
Assert(UI->Stacks.OffsetYStackUsed > 0); Box->Offset.y = UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1]; if(UI->Stacks.AutoPopOffsetY) { UI_PopOffsetY(); UI->Stacks.AutoPopOffsetY = false; }
}

View File

@ -0,0 +1,19 @@
struct ui_style_stacks
{
ui_box * ParentStack[64]; s32 ParentStackUsed; b32 AutoPopParent;
ui_size WidthStack[64]; s32 WidthStackUsed; b32 AutoPopWidth;
ui_size HeightStack[64]; s32 HeightStackUsed; b32 AutoPopHeight;
r32 FixedXStack[64]; s32 FixedXStackUsed; b32 AutoPopFixedX;
r32 FixedYStack[64]; s32 FixedYStackUsed; b32 AutoPopFixedY;
v4 TextColorStack[64]; s32 TextColorStackUsed; b32 AutoPopTextColor;
v4 BackgroundColorStack[64]; s32 BackgroundColorStackUsed; b32 AutoPopBackgroundColor;
v4 BorderColorStack[64]; s32 BorderColorStackUsed; b32 AutoPopBorderColor;
r32 BorderThicknessStack[64]; s32 BorderThicknessStackUsed; b32 AutoPopBorderThickness;
axis2 LayoutAxisStack[64]; s32 LayoutAxisStackUsed; b32 AutoPopLayoutAxis;
r32 CornerRadiusStack[64]; s32 CornerRadiusStackUsed; b32 AutoPopCornerRadius;
font_id FontStack[64]; s32 FontStackUsed; b32 AutoPopFont;
r32 FontSizeStack[64]; s32 FontSizeStackUsed; b32 AutoPopFontSize;
r32 OffsetXStack[64]; s32 OffsetXStackUsed; b32 AutoPopOffsetX;
r32 OffsetYStack[64]; s32 OffsetYStackUsed; b32 AutoPopOffsetY;
};

View File

@ -255,7 +255,7 @@ flat out s32 TextureIndex;
SourceP = In_SourceP;
v2 ScreenP = V2(DestP.x / Uniform_Resolution.x, DestP.y / Uniform_Resolution.y);
v2 ScreenP = DestP / Uniform_Resolution;;
ScreenP = ScreenP*2 - 1;
ScreenP.y = -ScreenP.y;
@ -416,6 +416,11 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
RenderCommands->MaxQuadIndexCount = MAX_QUAD_COUNT*6;
RenderCommands->QuadIndexBase = (s32 *)OpenGL_AllocateMemory(RenderCommands->MaxQuadIndexCount*sizeof(s32));
#if 0
RenderCommands->MaxInstancedQuadCount = MAX_QUAD_COUNT;
RenderCommands->InstancedQuadBase = (instanced_quad *)OpenGL_AllocateMemory(RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad));
#endif
Context.QuadProgram = OpenGL_CompileQuadProgram();
glGenBuffers(1, &Context.VertexBuffer);
@ -453,6 +458,9 @@ static void OpenGL_BeginFrame(vn_render_commands *RenderCommands, v2 RenderDim)
RenderCommands->PushBufferAt = RenderCommands->PushBufferBase;
RenderCommands->QuadVertexCount = 0;
RenderCommands->QuadIndexCount = 0;
#if 0
RenderCommands->InstancedQuadCount = 0;
#endif
RenderCommands->RenderDim = RenderDim;
}
@ -518,6 +526,27 @@ static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderC
glBindTexture(GL_TEXTURE_2D, 0);
} break;
#if 0
case Render_Command_render_command_instanced_quads:
{
render_command_quads *Command = (render_command_quads *)PushBufferAt;
PushBufferAt += sizeof(*Command);
for(s32 TextureIndex = 0;
TextureIndex < Command->TexturesUsed;
++TextureIndex)
{
opengl_texture Texture = OpenGL_GetTextureFromHandle(Command->Textures[TextureIndex]);
glActiveTexture(GL_TEXTURE0 + TextureIndex);
glBindTexture(GL_TEXTURE_2D, Texture.ID);
}
glDrawElements(GL_TRIANGLES, Command->QuadCount*6, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
} break;
#endif
case Render_Command_render_command_clip:
{
render_command_clip *Command = (render_command_clip *)PushBufferAt;

View File

@ -4,7 +4,7 @@
#define OPENGL_RENDER_H
#include "vn_opengl_defines.h"
#include "generated/vn_opengl_functions.h"
#include "generated/vn_opengl_functions.meta.h"
struct opengl_texture
{

View File

@ -0,0 +1,188 @@
#define _CRT_SECURE_NO_WARNINGS 1
#include <inttypes.h>
#include "../metadesk/md.h"
#include "../metadesk/md.c"
#include "../meow_hash_x64_aesni.h"
#include "codegen_embed.h"
#include "codegen_table.h"
#include "codegen.h"
#include "codegen_embed.c"
#include "codegen_table.c"
////////////////////////////////
//~ rjf: Helpers
static CG_FilePair
CG_FilePairFromNode(MD_Node *node)
{
CG_FilePair result = {0};
MD_CodeLoc loc = MD_CodeLocFromNode(node);
MD_String8 filename = loc.filename;
MD_b32 found = 0;
for(int i = 0; i < cg_file_pair_count; i += 1)
{
if(MD_S8Match(filename, cg_file_pairs[i].src_filename, 0))
{
result = cg_file_pairs[i];
found = 1;
break;
}
}
if(found == 0)
{
MD_String8 folder = MD_PathChopLastSlash(filename);
MD_String8 layer_name = MD_PathChopLastPeriod(MD_PathSkipLastSlash(loc.filename));
MD_String8 gen_folder = MD_S8Fmt(cg_arena, "%.*s/generated", MD_S8VArg(folder));
MD_String8 h_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.h", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
MD_String8 c_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.c", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
result.src_filename = filename;
result.h = fopen((char *)h_filename.str, "w");
result.c = fopen((char *)c_filename.str, "w");
cg_file_pairs[cg_file_pair_count] = result;
cg_file_pair_count += 1;
}
return result;
}
static FILE *
CG_FileFromNodePair(MD_Node *node, CG_FilePair *pair)
{
FILE *result = pair->h;
if(MD_NodeHasTag(node, MD_S8Lit("c"), MD_StringMatchFlag_CaseInsensitive))
{
result = pair->c;
}
return result;
}
static void
CG_CloseAllFiles(void)
{
for(int i = 0; i < cg_file_pair_count; i += 1)
{
fclose(cg_file_pairs[i].h);
fclose(cg_file_pairs[i].c);
}
}
static void
CG_GenerateMultilineStringAsCLiteral(FILE *file, MD_String8 string)
{
fprintf(file, "\"\"\n\"");
for(MD_u64 i = 0; i < string.size; i += 1)
{
if(string.str[i] == '\n')
{
fprintf(file, "\\n\"\n\"");
}
else if(string.str[i] == '\r')
{
continue;
}
else
{
fprintf(file, "%c", string.str[i]);
}
}
fprintf(file, "\"\n");
}
static MD_String8
CG_EscapedFromString(MD_Arena *arena, MD_String8 string)
{
MD_ArenaTemp scratch = MD_GetScratch(&arena, 1);
MD_String8List strs = {0};
MD_b32 escaped = 0;
MD_u64 start = 0;
for(MD_u64 idx = 0; idx <= string.size; idx += 1)
{
if(idx < string.size && escaped)
{
escaped = 0;
start = idx+1;
MD_u8 replace_char = 0;
switch(string.str[idx])
{
default: break;
case 'a': replace_char = 0x07; break;
case 'b': replace_char = 0x08; break;
case 'e': replace_char = 0x1b; break;
case 'f': replace_char = 0x0c; break;
case 'n': replace_char = 0x0a; break;
case 'r': replace_char = 0x0d; break;
case 't': replace_char = 0x09; break;
case 'v': replace_char = 0x0b; break;
case '\\': replace_char = 0x5c; break;
case '\'': replace_char = 0x27; break;
case '\"': replace_char = 0x22; break;
case '\?': replace_char = 0x3f; break;
}
if(replace_char)
{
MD_String8 string = MD_S8Copy(scratch.arena, MD_S8(&replace_char, 1));
MD_S8ListPush(scratch.arena, &strs, string);
}
}
else if(idx == string.size || string.str[idx] == '\\')
{
escaped = (string.str[idx] == '\\');
MD_String8 part = MD_S8Substring(string, start, idx);
MD_S8ListPush(scratch.arena, &strs, part);
start = idx;
}
}
MD_String8 result = MD_S8ListJoin(arena, strs, 0);
MD_ReleaseScratch(scratch);
return result;
}
////////////////////////////////
//~ rjf: Entry Point
int main(int argument_count, char **arguments)
{
cg_arena = MD_ArenaAlloc();
//- rjf: parse command line
MD_String8List options = MD_StringListFromArgCV(cg_arena, argument_count, arguments);
MD_CmdLine cmdln = MD_MakeCmdLineFromOptions(cg_arena, options);
//- rjf: parse all files
MD_Node *file_list = MD_MakeList(cg_arena);
for(MD_String8Node *n = cmdln.inputs.first; n != 0; n = n->next)
{
MD_String8 code_dir = n->string;
printf("searching %.*s for metacode...\n", MD_S8VArg(code_dir));
MD_FileIter it = {0};
MD_FileIterBegin(&it, code_dir);
for(MD_FileInfo info = {0};;)
{
info = MD_FileIterNext(cg_arena, &it);
if(info.filename.size == 0)
{
break;
}
if(!(info.flags & MD_FileFlag_Directory) &&
MD_S8Match(MD_PathSkipLastPeriod(info.filename), MD_S8Lit("md"), MD_StringMatchFlag_CaseInsensitive))
{
printf("parsing %.*s...\n", MD_S8VArg(info.filename));
MD_String8 path = MD_S8Fmt(cg_arena, "%.*s/%.*s", MD_S8VArg(code_dir), MD_S8VArg(info.filename));
MD_ParseResult parse = MD_ParseWholeFile(cg_arena, path);
MD_PushNewReference(cg_arena, file_list, parse.node);
}
}
MD_FileIterEnd(&it);
}
//- rjf: send all parses to backends
CG_EMBED_Generate(file_list);
CG_TBL_Generate(file_list);
CG_CloseAllFiles();
return 0;
}

View File

@ -0,0 +1,28 @@
#ifndef METAPROGRAM_H
#define METAPROGRAM_H
typedef struct CG_FilePair CG_FilePair;
struct CG_FilePair
{
MD_String8 src_filename;
FILE *h;
FILE *c;
};
////////////////////////////////
//~ rjf: Helpers
static CG_FilePair CG_FilePairFromNode(MD_Node *node);
static FILE *CG_FileFromNodePair(MD_Node *node, CG_FilePair *pair);
static void CG_CloseAllFiles(void);
static void CG_GenerateMultilineStringAsCLiteral(FILE *file, MD_String8 string);
static MD_String8 CG_EscapedFromString(MD_Arena *arena, MD_String8 string);
////////////////////////////////
//~ rjf: Globals
static MD_Arena *cg_arena = 0;
static int cg_file_pair_count = 0;
static CG_FilePair cg_file_pairs[4096] = {0};
#endif // METAPROGRAM_H

View File

@ -0,0 +1,40 @@
static void
CG_EMBED_Generate(MD_Node *file_list)
{
for(MD_EachNode(file_ref, file_list->first_child))
{
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
for(MD_EachNode(node, file->first_child))
{
CG_FilePair f = CG_FilePairFromNode(node);
if(MD_NodeHasTag(node, MD_S8Lit("embed_string"), MD_StringMatchFlag_CaseInsensitive))
{
FILE *file = CG_FileFromNodePair(node, &f);
fprintf(file, "read_only global String8 %.*s =\nStr8LitComp(", MD_S8VArg(node->string));
CG_GenerateMultilineStringAsCLiteral(file, node->first_child->string);
fprintf(file, ");\n\n");
}
if(MD_NodeHasTag(node, MD_S8Lit("embed_file"), MD_StringMatchFlag_CaseInsensitive))
{
MD_String8 path = node->first_child->string;
MD_String8 file_data = MD_LoadEntireFile(cg_arena, path);
meow_u128 file_data_hash = MeowHash(MeowDefaultSeed, file_data.size, file_data.str);
FILE *file = CG_FileFromNodePair(node, &f);
fprintf(file, "read_only global U8 %.*s_data[] =\n{\n", MD_S8VArg(node->string));
MD_u64 col = 0;
for(MD_u64 idx = 0; idx < file_data.size; idx += 1, col += 1)
{
fprintf(file, "%i,", (int)file_data.str[idx]);
if(col == 32)
{
fprintf(file,"\n");
col = 0;
}
}
fprintf(file, "};\n\n");
fprintf(file, "read_only global String8 %.*s = {%.*s_data, sizeof(%.*s_data)};\n\n", MD_S8VArg(node->string), MD_S8VArg(node->string), MD_S8VArg(node->string));
fprintf(file, "read_only global U64 %.*s_hash[2] = {0x%" PRIx64 ", 0x%" PRIx64 "};\n\n", MD_S8VArg(node->string), MeowU64From(file_data_hash, 0), MeowU64From(file_data_hash, 1));
}
}
}
}

View File

@ -0,0 +1,6 @@
/* date = May 5th 2023 11:04 am */
#ifndef CODEGEN_EMBED_H
#define CODEGEN_EMBED_H
#endif // CODEGEN_EMBED_H

View File

@ -0,0 +1,581 @@
static MD_Map cg_tbl_top_level_node_grid_map = {0};
static MD_Map cg_tbl_top_level_table_header_map = {0};
static MD_Map cg_tbl_layer_map_gen = {0};
static MD_Map cg_tbl_layer_map_gen_enum = {0};
static MD_Map cg_tbl_layer_map_gen_data = {0};
static MD_String8 cg_tbl_tag__table = MD_S8LitComp("table");
static MD_String8 cg_tbl_tag__table_gen = MD_S8LitComp("table_gen");
static MD_String8 cg_tbl_tag__table_gen_enum = MD_S8LitComp("table_gen_enum");
static MD_String8 cg_tbl_tag__table_gen_data = MD_S8LitComp("table_gen_data");
static CG_NodeArray
CG_NodeArrayMake(MD_u64 count)
{
CG_NodeArray result = {0};
result.count = count;
result.v = MD_PushArrayZero(cg_arena, MD_Node *, result.count);
for(MD_u64 idx = 0; idx < result.count; idx += 1)
{
result.v[idx] = MD_NilNode();
}
return result;
}
static CG_NodeGrid
CG_GridFromNode(MD_Node *node)
{
CG_NodeGrid grid = {0};
//- rjf: determine dimensions
MD_u64 row_count = 0;
MD_u64 column_count = 0;
{
for(MD_EachNode(row, node->first_child))
{
row_count += 1;
MD_u64 cell_count_this_row = MD_ChildCountFromNode(row);
column_count = MD_Max(cell_count_this_row, column_count);
}
}
//- rjf: allocate cells / row parents
{
grid.cells = CG_NodeArrayMake(row_count * column_count);
grid.row_parents = CG_NodeArrayMake(row_count);
}
//- rjf: fill cells
{
MD_u64 row_idx = 0;
for(MD_EachNode(row, node->first_child))
{
MD_u64 col_idx = 0;
grid.row_parents.v[row_idx] = row;
for(MD_EachNode(cell, row->first_child))
{
grid.cells.v[row_idx * column_count + col_idx] = cell;
col_idx += 1;
}
row_idx += 1;
}
}
return grid;
}
static CG_TableHeader
CG_TableHeaderFromTag(MD_Node *tag)
{
CG_TableHeader result = {0};
result.column_count = MD_ChildCountFromNode(tag);
result.column_descs = MD_PushArrayZero(cg_arena, CG_ColumnDesc, result.column_count);
MD_u64 idx = 0;
for(MD_EachNode(column_node, tag->first_child))
{
result.column_descs[idx].kind = CG_ColumnKind_Default;
result.column_descs[idx].name = column_node->string;
MD_Node *check_for_tag = MD_TagFromString(column_node, MD_S8Lit("check_for_tag"), 0);
if(!MD_NodeIsNil(check_for_tag))
{
result.column_descs[idx].kind = CG_ColumnKind_CheckForTag;
result.column_descs[idx].tag_string = check_for_tag->first_child->string;
}
MD_Node *default_value = MD_TagFromString(column_node, MD_S8Lit("default"), 0);
if(!MD_NodeIsNil(default_value))
{
result.column_descs[idx].default_value = default_value->first_child->string;
}
idx += 1;
}
return result;
}
static MD_u64
CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name)
{
MD_u64 result = 0;
for(MD_u64 idx = 0; idx < header->column_count; idx += 1)
{
if(MD_S8Match(header->column_descs[idx].name, column_name, 0))
{
break;
}
if(header->column_descs[idx].kind == CG_ColumnKind_Default)
{
result += 1;
}
}
return result;
}
static MD_i64
CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr)
{
MD_i64 result = 0;
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
switch(op)
{
case CG_TableOp_Equal:
case CG_TableOp_IsNotEqual:
{
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
MD_String8List left_strs = {0};
MD_String8List right_strs = {0};
CG_TableExprEvaluate_String(info, expr->left, &left_strs);
CG_TableExprEvaluate_String(info, expr->right, &right_strs);
MD_String8 left_str = MD_S8ListJoin(scratch.arena, left_strs, 0);
MD_String8 right_str = MD_S8ListJoin(scratch.arena, right_strs, 0);
result = MD_S8Match(left_str, right_str, 0);
if(op == CG_TableOp_IsNotEqual)
{
result = !result;
}
MD_ReleaseScratch(scratch);
}break;
case CG_TableOp_BooleanAnd:
case CG_TableOp_BooleanOr:
{
MD_i64 left = CG_TableExprEvaluate_Numeric(info, expr->left);
MD_i64 right = CG_TableExprEvaluate_Numeric(info, expr->right);
switch(op)
{
case CG_TableOp_BooleanAnd: result = left && right; break;
case CG_TableOp_BooleanOr: result = left || right; break;
}
}break;
}
return result;
}
static void
CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out)
{
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
switch(op)
{
default:
case CG_TableOp_Null:
{
MD_S8ListPush(cg_arena, out, expr->md_node->string);
}break;
case CG_TableOp_Dot:
{
MD_Expr *label_expr = expr->left;
MD_Expr *column_query_expr = expr->right;
MD_Node *label_node = label_expr->md_node;
MD_Node *column_query_node = column_query_expr->md_node;
MD_String8 label = label_node->string;
MD_String8 column_query = column_query_node->string;
MD_b32 column_query_is_by_expand_idx = MD_S8Match(column_query_node->string, MD_S8Lit("_it"), 0);
MD_b32 column_query_is_by_name = !column_query_is_by_expand_idx && column_query_node->flags & MD_NodeFlag_Identifier;
MD_b32 column_query_is_by_index = column_query_node->flags & MD_NodeFlag_Numeric;
// rjf: find which expansion this label refers to, grab its iterator
CG_ExpandIter *iter = 0;
for(CG_ExpandIter *it = info->first_expand_iter; it != 0; it = it->next)
{
if(MD_S8Match(it->label, label, 0))
{
iter = it;
break;
}
}
// rjf: error on invalid label
if(iter == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(label_node), MD_MessageKind_Error, "Expansion label \"%S\" was not found as referring to a valid @expand tag.", label);
}
// rjf: generate strings from iterator's table
if(iter != 0)
{
CG_NodeGrid *grid = iter->grid;
CG_TableHeader *header = iter->header;
MD_Node *row = grid->row_parents.v[iter->idx];
// rjf: grab the cell string given the row & column_query
MD_String8 cell_string = {0};
{
// NOTE(rjf): expansion index counter
if(column_query_is_by_expand_idx)
{
MD_i64 index = iter->idx;
cell_string = MD_S8Fmt(cg_arena, "%" PRIu64 "", index);
}
// NOTE(rjf): by-name index (look into table header)
else if(column_query_is_by_name && header != 0)
{
MD_u64 column_idx = 0;
CG_ColumnDesc *column = 0;
for(MD_u64 col_idx = 0; col_idx < header->column_count; col_idx += 1)
{
if(MD_S8Match(header->column_descs[col_idx].name, column_query, 0))
{
column = &header->column_descs[col_idx];
column_idx = col_idx;
break;
}
}
MD_u64 row_child_idx = CG_RowChildIndexFromColumnName(header, column_query);
// rjf: error on invalid column
if(column == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(column_query_node), MD_MessageKind_Error, "Column query \"%S\" did not map to a valid column for expansion label \"%S\".", column_query, label);
}
if(column != 0)
{
switch(column->kind)
{
default:
case CG_ColumnKind_Default:
{
MD_Node *cell_node = MD_ChildFromIndex(row, row_child_idx);
cell_string = cell_node->string;
if(MD_S8Match(cell_node->raw_string, MD_S8Lit("."), 0))
{
cell_string = column->default_value;
}
}break;
case CG_ColumnKind_CheckForTag:
{
MD_b32 has_tag = MD_NodeHasTag(row, column->tag_string, 0);
cell_string = has_tag ? MD_S8Lit("1") : MD_S8Lit("0");
}break;
}
}
}
// NOTE(rjf): by-index (grab nth child of row)
else if(column_query_is_by_index)
{
MD_i64 index = MD_CStyleIntFromString(column_query);
cell_string = MD_ChildFromIndex(row, index)->string;
}
}
MD_S8ListPush(cg_arena, out, cell_string);
}
}break;
case CG_TableOp_Bump:
{
MD_u64 dst = MD_CStyleIntFromString(expr->unary_operand->md_node->string);
MD_u64 src = out->total_size;
MD_u64 spaces_to_print = dst - src;
if(dst > src)
{
for(MD_u64 space_idx = 0; space_idx < spaces_to_print; space_idx += 1)
{
MD_S8ListPush(cg_arena, out, MD_S8Lit(" "));
}
}
}break;
case CG_TableOp_CheckIfTrue:
{
MD_i64 check_val = CG_TableExprEvaluate_Numeric(info, expr->left);
if(check_val)
{
CG_TableExprEvaluate_String(info, expr->right, out);
}
}break;
case CG_TableOp_Concat:
{
CG_TableExprEvaluate_String(info, expr->left, out);
CG_TableExprEvaluate_String(info, expr->right, out);
}break;
}
}
static void
CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out)
{
if(it->next)
{
for(MD_u64 idx = 0; idx < it->count; idx += 1)
{
it->idx = idx;
CG_LoopExpansionDimension(it->next, info, out);
}
}
else
{
for(MD_u64 idx = 0; idx < it->count; idx += 1)
{
it->idx = idx;
MD_String8List expansion_strs = {0};
MD_u64 start_idx = 0;
for(MD_u64 char_idx = 0; char_idx <= info->strexpr.size; char_idx += 1)
{
MD_b32 is_expr_marker = info->strexpr.str[char_idx] == '$';
// rjf: push regular string contents
if(char_idx == info->strexpr.size || is_expr_marker)
{
MD_String8 normal_string_chunk = MD_S8Substring(info->strexpr, start_idx, char_idx);
MD_String8 escaped = CG_EscapedFromString(cg_arena, normal_string_chunk);
MD_S8ListPush(cg_arena, &expansion_strs, escaped);
}
// rjf: handle expansion
if(is_expr_marker)
{
MD_String8 expr_string = MD_S8Skip(info->strexpr, char_idx+1);
{
MD_i64 paren_nest = 0;
for(MD_u64 expr_str_char_idx = 0; expr_str_char_idx < expr_string.size; expr_str_char_idx += 1)
{
if(expr_string.str[expr_str_char_idx] == '(')
{
paren_nest += 1;
}
else if(expr_string.str[expr_str_char_idx] == ')')
{
paren_nest -= 1;
if(paren_nest == 0)
{
expr_string.size = expr_str_char_idx+1;
break;
}
}
}
}
MD_ParseResult parse = MD_ParseOneNode(cg_arena, expr_string, 0);
MD_Node *node = parse.node;
MD_ExprParseResult expr_parse = MD_ExprParse(cg_arena, &info->expr_op_table, node->first_child, MD_NilNode());
MD_Expr *expr = expr_parse.expr;
CG_TableExprEvaluate_String(info, expr, &expansion_strs);
MD_String8 parsed_string = MD_S8Substring(info->strexpr, char_idx+1, char_idx+1+parse.string_advance);
parsed_string = MD_S8ChopWhitespace(parsed_string);
start_idx = char_idx+1+parsed_string.size;
}
}
// rjf: push expansion string to output list
MD_String8 expansion_str = MD_S8ListJoin(cg_arena, expansion_strs, 0);
MD_S8ListPush(cg_arena, out, expansion_str);
}
}
}
static MD_String8List
CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen)
{
MD_String8List result = {0};
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
for(MD_EachNode(strexpr, gen->first_child))
{
//- rjf: build expansion iterator list
CG_ExpandIter *first_iter = 0;
CG_ExpandIter *last_iter = 0;
{
for(MD_EachNode(tag, strexpr->first_tag))
{
if(MD_S8Match(tag->string, MD_S8Lit("expand"), 0))
{
MD_Node *table_name_node = MD_ChildFromIndex(tag, 0);
MD_Node *label_node = MD_ChildFromIndex(tag, 1);
MD_String8 table_name = table_name_node->string;
MD_String8 label = label_node->string;
// rjf: grab the table associated with table_name
CG_NodeGrid *grid = 0;
{
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_node_grid_map, MD_MapKeyStr(table_name));
if(slot != 0)
{
grid = slot->val;
}
}
// rjf: grab the table header associated with table_name
CG_TableHeader *header = 0;
{
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_table_header_map, MD_MapKeyStr(table_name));
if(slot != 0)
{
header = slot->val;
}
}
// rjf: make iterator node if we got a grid
if(grid != 0)
{
CG_ExpandIter *iter = MD_PushArrayZero(scratch.arena, CG_ExpandIter, 1);
MD_QueuePush(first_iter, last_iter, iter);
iter->grid = grid;
iter->header = header;
iter->label = label;
iter->count = grid->row_parents.count;
}
// rjf: print out an error if grid is 0
if(grid == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(tag), MD_MessageKind_Error, "Table \"%S\" was not found.", table_name);
}
}
}
}
//- rjf: generate string list for this strexpr & push to result
if(first_iter != 0)
{
CG_ExpandInfo info = {0};
{
info.strexpr = strexpr->string;
info.first_expand_iter = first_iter;
info.expr_op_table = expr_op_table;
}
CG_LoopExpansionDimension(first_iter, &info, &result);
}
//- rjf: generate non-expansion strings
else
{
MD_String8 escaped = CG_EscapedFromString(cg_arena, strexpr->string);
MD_S8ListPush(cg_arena, &result, escaped);
}
}
MD_ReleaseScratch(scratch);
return result;
}
static void
CG_TBL_Generate(MD_Node *file_list)
{
//- rjf: initialize all maps
cg_tbl_top_level_node_grid_map = MD_MapMake(cg_arena);
cg_tbl_top_level_table_header_map = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen_enum = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen_data = MD_MapMake(cg_arena);
//- rjf: build table expression operator table
MD_ExprOprTable table_expr_op_table = {0};
{
MD_ExprOprList ops_list = {0};
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 10, MD_S8Lit("."), CG_TableOp_Dot, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Prefix, 9, MD_S8Lit("=>"), CG_TableOp_Bump, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 6, MD_S8Lit("??"), CG_TableOp_CheckIfTrue, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 7, MD_S8Lit(".."), CG_TableOp_Concat, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("=="), CG_TableOp_Equal, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("!="), CG_TableOp_IsNotEqual, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 5, MD_S8Lit("&&"), CG_TableOp_BooleanAnd, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 4, MD_S8Lit("||"), CG_TableOp_BooleanOr, 0);
table_expr_op_table = MD_ExprBakeOprTableFromList(cg_arena, &ops_list);
}
//- rjf: gather phase
for(MD_EachNode(file_ref, file_list->first_child))
{
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
MD_String8 layer_name = file->string;
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
for(MD_EachNode(node, file->first_child))
{
MD_Node *table_tag = MD_TagFromString(node, cg_tbl_tag__table, 0);
if(!MD_NodeIsNil(table_tag))
{
CG_NodeGrid *grid = MD_PushArrayZero(cg_arena, CG_NodeGrid, 1);
*grid = CG_GridFromNode(node);
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_node_grid_map, MD_MapKeyStr(node->string), grid);
CG_TableHeader *header = MD_PushArrayZero(cg_arena, CG_TableHeader, 1);
*header = CG_TableHeaderFromTag(table_tag);
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_table_header_map, MD_MapKeyStr(node->string), header);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen, layer_key, node);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_enum, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_enum, layer_key, node);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_data, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_data, layer_key, node);
}
}
}
//- rjf: generation phase
for(MD_EachNode(file_ref, file_list->first_child))
{
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
MD_String8 layer_name = file->string;
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
//- rjf: generate all table enums
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_enum, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
CG_FilePair f = CG_FilePairFromNode(gen);
FILE *file = CG_FileFromNodePair(gen, &f);
fprintf(file, "enum %.*s\n{\n", MD_S8VArg(gen->string));
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(file, "%.*s", MD_S8VArg(gen_string));
fprintf(file, "\n};\n\n");
}
//- rjf: generate all data tables
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_data, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
MD_Node *tag = MD_TagFromString(gen, cg_tbl_tag__table_gen_data, 0);
MD_Node *data_table_type_node = tag->first_child;
MD_String8 data_table_type = data_table_type_node->string;
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_String8 h_decl_specifier = MD_S8Lit("extern");
CG_FilePair f = CG_FilePairFromNode(gen);
fprintf(f.h, "%.*s %.*s %.*s[%" PRIu64 "];\n\n", MD_S8VArg(h_decl_specifier), MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
fprintf(f.c, "%.*s %.*s[%" PRIu64 "] =\n{\n", MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(f.c, "%.*s", MD_S8VArg(gen_string));
fprintf(f.c, "\n};\n");
fprintf(f.c, "\n");
}
//- rjf: generate all general generations
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
CG_FilePair f = CG_FilePairFromNode(gen);
FILE *file = CG_FileFromNodePair(gen, &f);
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(file, "%.*s", MD_S8VArg(gen_string));
fprintf(file, "\n\n");
}
}
}

View File

@ -0,0 +1,93 @@
#ifndef METAPROGRAM_TABLE_H
#define METAPROGRAM_TABLE_H
typedef enum CG_TableOp
{
CG_TableOp_Null,
CG_TableOp_BeginStringOps,
CG_TableOp_Dot,
CG_TableOp_Bump,
CG_TableOp_CheckIfTrue,
CG_TableOp_Concat,
CG_TableOp_EndStringOps,
CG_TableOp_BeginNumericOps,
CG_TableOp_Equal,
CG_TableOp_IsNotEqual,
CG_TableOp_BooleanAnd,
CG_TableOp_BooleanOr,
CG_TableOp_EndNumericOps,
CG_TableOp_COUNT
}
CG_TableOp;
typedef struct CG_NodeArray CG_NodeArray;
struct CG_NodeArray
{
MD_u64 count;
MD_Node **v;
};
typedef struct CG_NodeGrid CG_NodeGrid;
struct CG_NodeGrid
{
CG_NodeArray cells;
CG_NodeArray row_parents;
};
typedef enum CG_ColumnKind
{
CG_ColumnKind_Default,
CG_ColumnKind_CheckForTag,
CG_ColumnKind_COUNT
}
CG_ColumnKind;
typedef struct CG_ColumnDesc CG_ColumnDesc;
struct CG_ColumnDesc
{
CG_ColumnKind kind;
MD_String8 name;
MD_String8 tag_string;
MD_String8 default_value;
};
typedef struct CG_TableHeader CG_TableHeader;
struct CG_TableHeader
{
MD_u64 column_count;
CG_ColumnDesc *column_descs;
};
typedef struct CG_ExpandIter CG_ExpandIter;
struct CG_ExpandIter
{
CG_ExpandIter *next;
CG_NodeGrid *grid;
CG_TableHeader *header;
MD_String8 label;
MD_u64 idx;
MD_u64 count;
};
typedef struct CG_ExpandInfo CG_ExpandInfo;
struct CG_ExpandInfo
{
MD_String8 strexpr;
CG_ExpandIter *first_expand_iter;
MD_ExprOprTable expr_op_table;
};
static CG_NodeArray CG_NodeArrayMake(MD_u64 count);
static CG_NodeGrid CG_GridFromNode(MD_Node *node);
static CG_TableHeader CG_TableHeaderFromTag(MD_Node *tag);
static MD_u64 CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name);
static MD_i64 CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr);
static void CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out);
static void CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out);
static MD_String8List CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen);
static void CG_TBL_Generate(MD_Node *file_list);
#endif // METAPROGRAM_TABLE_H

View File

@ -0,0 +1,744 @@
/* ========================================================================
Meow - A Fast Non-cryptographic Hash
(C) Copyright 2018-2019 by Molly Rocket, Inc. (https://mollyrocket.com)
See https://mollyrocket.com/meowhash for details.
========================================================================
zlib License
(C) Copyright 2018-2019 Molly Rocket, Inc.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
========================================================================
FAQ
Q: What is it?
A: Meow is a 128-bit Level 3 hash taking 128 bytes of seed. It operates
at very high speeds on x64 processors, and potentially other processors
that provide accelerated AES instructions.
Q: What is it GOOD for?
A: Quickly hashing any amount of data for comparison purposes such as
block deduplication or change detection. It is fast on all buffer
sizes, and can generally be used anywhere you need fast Level 3
hashing without worrying about how big or small the inputs tend to be.
However, substantial speed improvements could be made over Meow
if you either a) know you are always hashing an exact, small number of bytes,
or b) can always supply a small number of bytes in a buffer padded to some
fixed multiple of 16.
Q: What is it BAD for?
A: Anything requiring Level 4 or Level 5 security guarantees (see
http://nohatcoder.dk/2019-05-19-1.html#level3). Also, note that
Meow is a new hash and has not had the extensive community
cryptanalysis necessary to ensure that it is not breakable down to
a lower level of hash, so you must do your due diligence in
deciding when and where to use Meow instead of a slower but
more extensively studied existing hash. We have tried to design
it to provide Level 3 security, but the possibility of the hash
being broken in the future always exists.
Q: Why is it called the "Meow hash"?
A: It is named after a character in Meow the Infinite
(https://meowtheinfinite.com)
Q: Who wrote it?
A: The final Meow Hash was created as a collaboration between
JACOB CHRISTIAN MUNCH-ANDERSEN (https://twitter.com/nohatcoder) and
CASEY MURATORI (https://caseymuratori.com). Casey wrote the original
implementation for use in processing large-footprint assets for the
game 1935 (https://molly1935.com). Jacob was the first to analyze
that implementation and determine the adversarial bit strength, which
was weaker than they would have liked.
Following that, the two collaborated to figure out how the hash
could be strengthened without reducing Meow's 16 bytes/cycle
maximum theoretical throughput. Jacob created the hash candidates
and Casey did the performance validation. After a long and
exhaustive effort, Jacob found the unaligned aes/add/xor formulation
that forms the current Meow hash core.
A number of valuable additions to Meow Hash were also contributed
by other great folks along the way:
JEFF ROBERTS (https://radgametools.com) provided a super slick
way to handle the residual end-of-buffer bytes that dramatically
improved Meow's small hash performance.
MARTINS MOZEIKO (https://matrins.ninja) ported Meow to ARM and
ANSI-C, and added the proper preprocessor dressing for clean
compilation on a variety of compiler configurations.
FABIAN GIESEN (https://fgiesen.wordpress.com) analyzed many
performance oddities that came up during development, and
helped get the benchmarking working properly across a number
of platforms.
ARAS PRANCKEVICIUS (https://aras-p.info) provided the allocation
shim for compilation on Mac OS X.
======================================================================== */
//
// IMPORTANT(casey): We are currently evaluating this hash construction as
// the final one for Meow Hash. If you find a way to produce collisions
// that should not be possible with a Level 3 hash, find significant performance
// problems, or see any bugs in this version, please be sure to report them
// to the Meow Hash GitHub as soon as possible. We would like to know as
// much as we can about the robustness and performance before committing to
// it as the final construction.
//
#if !defined(MEOW_HASH_X64_AESNI_H)
#define MEOW_HASH_VERSION 5
#define MEOW_HASH_VERSION_NAME "0.5/calico"
#if !defined(meow_u8)
#if _MSC_VER
#if !defined(__clang__)
#define INSTRUCTION_REORDER_BARRIER _ReadWriteBarrier()
#else
#endif
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
#define meow_u8 char unsigned
#define meow_u64 long long unsigned
#define meow_u128 __m128i
#if __x86_64__ || _M_AMD64
#define meow_umm long long unsigned
#define MeowU64From(A, I) (_mm_extract_epi64((A), (I)))
#elif __i386__ || _M_IX86
#define meow_umm int unsigned
#define MeowU64From(A, I) (*(meow_u64 *)&(A))
#else
#error Cannot determine architecture to use!
#endif
#define MeowU32From(A, I) (_mm_extract_epi32((A), (I)))
#define MeowHashesAreEqual(A, B) (_mm_movemask_epi8(_mm_cmpeq_epi8((A), (B))) == 0xFFFF)
#if !defined INSTRUCTION_REORDER_BARRIER
#define INSTRUCTION_REORDER_BARRIER
#endif
#if !defined MEOW_PAGESIZE
#define MEOW_PAGESIZE 4096
#endif
#if !defined MEOW_PREFETCH
#define MEOW_PREFETCH 4096
#endif
#if !defined MEOW_PREFETCH_LIMIT
#define MEOW_PREFETCH_LIMIT 0x3ff
#endif
#endif
#define prefetcht0(A) _mm_prefetch((char *)(A), _MM_HINT_T0)
#define movdqu(A, B) A = _mm_loadu_si128((__m128i *)(B))
#define movdqu_mem(A, B) _mm_storeu_si128((__m128i *)(A), B)
#define movq(A, B) A = _mm_set_epi64x(0, B);
#define aesdec(A, B) A = _mm_aesdec_si128(A, B)
#define pshufb(A, B) A = _mm_shuffle_epi8(A, B)
#define pxor(A, B) A = _mm_xor_si128(A, B)
#define paddq(A, B) A = _mm_add_epi64(A, B)
#define pand(A, B) A = _mm_and_si128(A, B)
#define palignr(A, B, i) A = _mm_alignr_epi8(A, B, i)
#define pxor_clear(A, B) A = _mm_setzero_si128(); // NOTE(casey): pxor_clear is a nonsense thing that is only here because compilers don't detect xor(a, a) is clearing a :(
#define MEOW_MIX_REG(r1, r2, r3, r4, r5, i1, i2, i3, i4) \
aesdec(r1, r2); \
INSTRUCTION_REORDER_BARRIER; \
paddq(r3, i1); \
pxor(r2, i2); \
aesdec(r2, r4); \
INSTRUCTION_REORDER_BARRIER; \
paddq(r5, i3); \
pxor(r4, i4);
#define MEOW_MIX(r1, r2, r3, r4, r5, ptr) \
MEOW_MIX_REG(r1, r2, r3, r4, r5, _mm_loadu_si128( (__m128i *) ((ptr) + 15) ), _mm_loadu_si128( (__m128i *) ((ptr) + 0) ), _mm_loadu_si128( (__m128i *) ((ptr) + 1) ), _mm_loadu_si128( (__m128i *) ((ptr) + 16) ))
#define MEOW_SHUFFLE(r1, r2, r3, r4, r5, r6) \
aesdec(r1, r4); \
paddq(r2, r5); \
pxor(r4, r6); \
aesdec(r4, r2); \
paddq(r5, r6); \
pxor(r2, r3)
#if MEOW_DUMP
struct meow_dump
{
meow_u128 xmm[8];
void *Ptr;
char const *Title;
};
extern "C" meow_dump *MeowDumpTo;
meow_dump *MeowDumpTo;
#define MEOW_DUMP_STATE(T, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, ptr) \
if(MeowDumpTo) \
{ \
MeowDumpTo->xmm[0] = xmm0; \
MeowDumpTo->xmm[1] = xmm1; \
MeowDumpTo->xmm[2] = xmm2; \
MeowDumpTo->xmm[3] = xmm3; \
MeowDumpTo->xmm[4] = xmm4; \
MeowDumpTo->xmm[5] = xmm5; \
MeowDumpTo->xmm[6] = xmm6; \
MeowDumpTo->xmm[7] = xmm7; \
MeowDumpTo->Ptr = ptr; \
MeowDumpTo->Title = T; \
++MeowDumpTo; \
}
#else
#define MEOW_DUMP_STATE(...)
#endif
static meow_u8 MeowShiftAdjust[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
static meow_u8 MeowMaskLen[32] = {255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
// NOTE(casey): The default seed is now a "nothing-up-our-sleeves" number for good measure. You may verify that it is just an encoding of Pi.
static meow_u8 MeowDefaultSeed[128] =
{
0x32, 0x43, 0xF6, 0xA8, 0x88, 0x5A, 0x30, 0x8D,
0x31, 0x31, 0x98, 0xA2, 0xE0, 0x37, 0x07, 0x34,
0x4A, 0x40, 0x93, 0x82, 0x22, 0x99, 0xF3, 0x1D,
0x00, 0x82, 0xEF, 0xA9, 0x8E, 0xC4, 0xE6, 0xC8,
0x94, 0x52, 0x82, 0x1E, 0x63, 0x8D, 0x01, 0x37,
0x7B, 0xE5, 0x46, 0x6C, 0xF3, 0x4E, 0x90, 0xC6,
0xCC, 0x0A, 0xC2, 0x9B, 0x7C, 0x97, 0xC5, 0x0D,
0xD3, 0xF8, 0x4D, 0x5B, 0x5B, 0x54, 0x70, 0x91,
0x79, 0x21, 0x6D, 0x5D, 0x98, 0x97, 0x9F, 0xB1,
0xBD, 0x13, 0x10, 0xBA, 0x69, 0x8D, 0xFB, 0x5A,
0xC2, 0xFF, 0xD7, 0x2D, 0xBD, 0x01, 0xAD, 0xFB,
0x7B, 0x8E, 0x1A, 0xFE, 0xD6, 0xA2, 0x67, 0xE9,
0x6B, 0xA7, 0xC9, 0x04, 0x5F, 0x12, 0xC7, 0xF9,
0x92, 0x4A, 0x19, 0x94, 0x7B, 0x39, 0x16, 0xCF,
0x70, 0x80, 0x1F, 0x2E, 0x28, 0x58, 0xEF, 0xC1,
0x66, 0x36, 0x92, 0x0D, 0x87, 0x15, 0x74, 0xE6
};
//
// NOTE(casey): Single block version
//
static meow_u128
MeowHash(void *Seed128Init, meow_umm Len, void *SourceInit)
{
meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // NOTE(casey): xmm0-xmm7 are the hash accumulation lanes
meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15; // NOTE(casey): xmm8-xmm15 hold values to be appended (residual, length)
meow_u8 *rax = (meow_u8 *)SourceInit;
meow_u8 *rcx = (meow_u8 *)Seed128Init;
//
// NOTE(casey): Seed the eight hash registers
//
movdqu(xmm0, rcx + 0x00);
movdqu(xmm1, rcx + 0x10);
movdqu(xmm2, rcx + 0x20);
movdqu(xmm3, rcx + 0x30);
movdqu(xmm4, rcx + 0x40);
movdqu(xmm5, rcx + 0x50);
movdqu(xmm6, rcx + 0x60);
movdqu(xmm7, rcx + 0x70);
MEOW_DUMP_STATE("Seed", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
//
// NOTE(casey): Hash all full 256-byte blocks
//
meow_umm BlockCount = (Len >> 8);
if(BlockCount > MEOW_PREFETCH_LIMIT)
{
// NOTE(casey): For large input, modern Intel x64's can't hit full speed without prefetching, so we use this loop
while(BlockCount--)
{
prefetcht0(rax + MEOW_PREFETCH + 0x00);
prefetcht0(rax + MEOW_PREFETCH + 0x40);
prefetcht0(rax + MEOW_PREFETCH + 0x80);
prefetcht0(rax + MEOW_PREFETCH + 0xc0);
MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00);
MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20);
MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40);
MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60);
MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80);
MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0);
MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0);
MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0);
rax += 0x100;
}
}
else
{
// NOTE(casey): For small input, modern Intel x64's can't hit full speed _with_ prefetching (because of port pressure), so we use this loop.
while(BlockCount--)
{
MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00);
MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20);
MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40);
MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60);
MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80);
MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0);
MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0);
MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0);
rax += 0x100;
}
}
MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
//
// NOTE(casey): Load any less-than-32-byte residual
//
pxor_clear(xmm9, xmm9);
pxor_clear(xmm11, xmm11);
//
// TODO(casey): I need to put more thought into how the end-of-buffer stuff is actually working out here,
// because I _think_ it may be possible to remove the first branch (on Len8) and let the mask zero out the
// result, but it would take a little thought to make sure it couldn't read off the end of the buffer due
// to the & 0xf on the align computation.
//
// NOTE(casey): First, we have to load the part that is _not_ 16-byte aligned
meow_u8 *Last = (meow_u8 *)SourceInit + (Len & ~0xf);
int unsigned Len8 = (Len & 0xf);
if(Len8)
{
// NOTE(casey): Load the mask early
movdqu(xmm8, &MeowMaskLen[0x10 - Len8]);
meow_u8 *LastOk = (meow_u8*)((((meow_umm)(((meow_u8 *)SourceInit)+Len - 1)) | (MEOW_PAGESIZE - 1)) - 16);
int Align = (Last > LastOk) ? ((int)(meow_umm)Last) & 0xf : 0;
movdqu(xmm10, &MeowShiftAdjust[Align]);
movdqu(xmm9, Last - Align);
pshufb(xmm9, xmm10);
// NOTE(jeffr): and off the extra bytes
pand(xmm9, xmm8);
}
// NOTE(casey): Next, we have to load the part that _is_ 16-byte aligned
if(Len & 0x10)
{
xmm11 = xmm9;
movdqu(xmm9, Last - 0x10);
}
//
// NOTE(casey): Construct the residual and length injests
//
xmm8 = xmm9;
xmm10 = xmm9;
palignr(xmm8, xmm11, 15);
palignr(xmm10, xmm11, 1);
// NOTE(casey): We have room for a 128-bit nonce and a 64-bit none here, but
// the decision was made to leave them zero'd so as not to confuse people
// about hwo to use them or what security implications they had.
pxor_clear(xmm12, xmm12);
pxor_clear(xmm13, xmm13);
pxor_clear(xmm14, xmm14);
movq(xmm15, Len);
palignr(xmm12, xmm15, 15);
palignr(xmm14, xmm15, 1);
MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0);
// NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty
MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11);
// NOTE(casey): Append the length, to avoid problems with our 32-byte padding
MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15);
MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
//
// NOTE(casey): Hash all full 32-byte blocks
//
int unsigned LaneCount = (Len >> 5) & 0x7;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount;
//
// NOTE(casey): Mix the eight lanes down to one 128-bit hash
//
MixDown:
MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6);
MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7);
MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0);
MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1);
MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2);
MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3);
MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4);
MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5);
MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6);
MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7);
MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0);
MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1);
MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
paddq(xmm0, xmm2);
paddq(xmm1, xmm3);
paddq(xmm4, xmm6);
paddq(xmm5, xmm7);
pxor(xmm0, xmm1);
pxor(xmm4, xmm5);
paddq(xmm0, xmm4);
MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
return(xmm0);
}
//
// NOTE(casey): Streaming construction
//
typedef struct meow_state
{
meow_u128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
meow_u64 TotalLengthInBytes;
int unsigned BufferLen;
meow_u8 Buffer[256];
meow_u128 Pad[2]; // NOTE(casey): So we know we can over-read Buffer as necessary
} meow_state;
static void
MeowBegin(meow_state *State, void *Seed128)
{
meow_u8 *rcx = (meow_u8 *)Seed128;
movdqu(State->xmm0, rcx + 0x00);
movdqu(State->xmm1, rcx + 0x10);
movdqu(State->xmm2, rcx + 0x20);
movdqu(State->xmm3, rcx + 0x30);
movdqu(State->xmm4, rcx + 0x40);
movdqu(State->xmm5, rcx + 0x50);
movdqu(State->xmm6, rcx + 0x60);
movdqu(State->xmm7, rcx + 0x70);
MEOW_DUMP_STATE("Seed", State->xmm0, State->xmm1, State->xmm2, State->xmm3, State->xmm4, State->xmm5, State->xmm6, State->xmm7, 0);
State->BufferLen = 0;
State->TotalLengthInBytes = 0;
}
static void
MeowAbsorbBlocks(meow_state *State, meow_umm BlockCount, meow_u8 *rax)
{
meow_u128 xmm0 = State->xmm0;
meow_u128 xmm1 = State->xmm1;
meow_u128 xmm2 = State->xmm2;
meow_u128 xmm3 = State->xmm3;
meow_u128 xmm4 = State->xmm4;
meow_u128 xmm5 = State->xmm5;
meow_u128 xmm6 = State->xmm6;
meow_u128 xmm7 = State->xmm7;
if(BlockCount > MEOW_PREFETCH_LIMIT)
{
while(BlockCount--)
{
prefetcht0(rax + MEOW_PREFETCH + 0x00);
prefetcht0(rax + MEOW_PREFETCH + 0x40);
prefetcht0(rax + MEOW_PREFETCH + 0x80);
prefetcht0(rax + MEOW_PREFETCH + 0xc0);
MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00);
MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20);
MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40);
MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60);
MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80);
MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0);
MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0);
MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0);
rax += 0x100;
}
}
else
{
while(BlockCount--)
{
MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0x00);
MEOW_MIX(xmm1,xmm5,xmm7,xmm2,xmm3, rax + 0x20);
MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x40);
MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x60);
MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x80);
MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0xa0);
MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0xc0);
MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xe0);
rax += 0x100;
}
}
State->xmm0 = xmm0;
State->xmm1 = xmm1;
State->xmm2 = xmm2;
State->xmm3 = xmm3;
State->xmm4 = xmm4;
State->xmm5 = xmm5;
State->xmm6 = xmm6;
State->xmm7 = xmm7;
}
static void
MeowAbsorb(meow_state *State, meow_umm Len, void *SourceInit)
{
State->TotalLengthInBytes += Len;
meow_u8 *Source = (meow_u8 *)SourceInit;
// NOTE(casey): Handle any buffered residual
if(State->BufferLen)
{
int unsigned Fill = (sizeof(State->Buffer) - State->BufferLen);
if(Fill > Len)
{
Fill = (int unsigned)Len;
}
Len -= Fill;
while(Fill--)
{
State->Buffer[State->BufferLen++] = *Source++;
}
if(State->BufferLen == sizeof(State->Buffer))
{
MeowAbsorbBlocks(State, 1, State->Buffer);
State->BufferLen = 0;
}
}
// NOTE(casey): Handle any full blocks
meow_u64 BlockCount = (Len >> 8);
meow_u64 Advance = (BlockCount << 8);
MeowAbsorbBlocks(State, BlockCount, Source);
Len -= Advance;
Source += Advance;
// NOTE(casey): Store residual
while(Len--)
{
State->Buffer[State->BufferLen++] = *Source++;
}
}
static meow_u128
MeowEnd(meow_state *State, meow_u8 *Store128)
{
meow_umm Len = State->TotalLengthInBytes;
meow_u128 xmm0 = State->xmm0;
meow_u128 xmm1 = State->xmm1;
meow_u128 xmm2 = State->xmm2;
meow_u128 xmm3 = State->xmm3;
meow_u128 xmm4 = State->xmm4;
meow_u128 xmm5 = State->xmm5;
meow_u128 xmm6 = State->xmm6;
meow_u128 xmm7 = State->xmm7;
meow_u128 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15;
meow_u8 *rax = State->Buffer;
pxor_clear(xmm9, xmm9);
pxor_clear(xmm11, xmm11);
meow_u8 *Last = (meow_u8 *)rax + (Len & 0xf0);
int unsigned Len8 = (Len & 0xf);
if(Len8)
{
movdqu(xmm8, &MeowMaskLen[0x10 - Len8]);
movdqu(xmm9, Last);
pand(xmm9, xmm8);
}
if(Len & 0x10)
{
xmm11 = xmm9;
movdqu(xmm9, Last - 0x10);
}
xmm8 = xmm9;
xmm10 = xmm9;
palignr(xmm8, xmm11, 15);
palignr(xmm10, xmm11, 1);
pxor_clear(xmm12, xmm12);
pxor_clear(xmm13, xmm13);
pxor_clear(xmm14, xmm14);
movq(xmm15, Len);
palignr(xmm12, xmm15, 15);
palignr(xmm14, xmm15, 1);
MEOW_DUMP_STATE("PostBlocks", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
MEOW_DUMP_STATE("Residuals", xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 0);
// NOTE(casey): To maintain the mix-down pattern, we always Meow Mix the less-than-32-byte residual, even if it was empty
MEOW_MIX_REG(xmm0, xmm4, xmm6, xmm1, xmm2, xmm8, xmm9, xmm10, xmm11);
// NOTE(casey): Append the length, to avoid problems with our 32-byte padding
MEOW_MIX_REG(xmm1, xmm5, xmm7, xmm2, xmm3, xmm12, xmm13, xmm14, xmm15);
MEOW_DUMP_STATE("PostAppend", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
//
// NOTE(casey): Hash all full 32-byte blocks
//
int unsigned LaneCount = (Len >> 5) & 0x7;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm2,xmm6,xmm0,xmm3,xmm4, rax + 0x00); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm3,xmm7,xmm1,xmm4,xmm5, rax + 0x20); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm4,xmm0,xmm2,xmm5,xmm6, rax + 0x40); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm5,xmm1,xmm3,xmm6,xmm7, rax + 0x60); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm6,xmm2,xmm4,xmm7,xmm0, rax + 0x80); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm7,xmm3,xmm5,xmm0,xmm1, rax + 0xa0); --LaneCount;
if(LaneCount == 0) goto MixDown; MEOW_MIX(xmm0,xmm4,xmm6,xmm1,xmm2, rax + 0xc0); --LaneCount;
//
// NOTE(casey): Mix the eight lanes down to one 128-bit hash
//
MixDown:
MEOW_DUMP_STATE("PostLanes", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6);
MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7);
MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0);
MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1);
MEOW_SHUFFLE(xmm4, xmm5, xmm6, xmm0, xmm1, xmm2);
MEOW_SHUFFLE(xmm5, xmm6, xmm7, xmm1, xmm2, xmm3);
MEOW_SHUFFLE(xmm6, xmm7, xmm0, xmm2, xmm3, xmm4);
MEOW_SHUFFLE(xmm7, xmm0, xmm1, xmm3, xmm4, xmm5);
MEOW_SHUFFLE(xmm0, xmm1, xmm2, xmm4, xmm5, xmm6);
MEOW_SHUFFLE(xmm1, xmm2, xmm3, xmm5, xmm6, xmm7);
MEOW_SHUFFLE(xmm2, xmm3, xmm4, xmm6, xmm7, xmm0);
MEOW_SHUFFLE(xmm3, xmm4, xmm5, xmm7, xmm0, xmm1);
MEOW_DUMP_STATE("PostMix", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
if(Store128)
{
movdqu_mem(Store128 + 0x00, xmm0);
movdqu_mem(Store128 + 0x10, xmm1);
movdqu_mem(Store128 + 0x20, xmm2);
movdqu_mem(Store128 + 0x30, xmm3);
movdqu_mem(Store128 + 0x40, xmm4);
movdqu_mem(Store128 + 0x50, xmm5);
movdqu_mem(Store128 + 0x60, xmm6);
movdqu_mem(Store128 + 0x70, xmm7);
}
paddq(xmm0, xmm2);
paddq(xmm1, xmm3);
paddq(xmm4, xmm6);
paddq(xmm5, xmm7);
pxor(xmm0, xmm1);
pxor(xmm4, xmm5);
paddq(xmm0, xmm4);
MEOW_DUMP_STATE("PostFold", xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 0);
return(xmm0);
}
#undef INSTRUCTION_REORDER_BARRIER
#undef prefetcht0
#undef movdqu
#undef movdqu_mem
#undef movq
#undef aesdec
#undef pshufb
#undef pxor
#undef paddq
#undef pand
#undef palignr
#undef pxor_clear
#undef MEOW_MIX
#undef MEOW_MIX_REG
#undef MEOW_SHUFFLE
#undef MEOW_DUMP_STATE
//
// NOTE(casey): If you need to create your own seed from non-random data, you can use MeowExpandSeed
// to create a seed which you then store for repeated use. It is _expensive_ to generate the seed,
// so you do not want to do this every time you hash. You _only_ want to do it when you actually
// need to create a new seed.
//
static void
MeowExpandSeed(meow_umm InputLen, void *Input, meow_u8 *SeedResult)
{
meow_state State;
meow_u64 LengthTab = (meow_u64)InputLen; // NOTE(casey): We need to always injest 8-byte lengths exactly, even on 32-bit builds, to ensure identical results
meow_umm InjestCount = (256 / InputLen) + 2;
MeowBegin(&State, MeowDefaultSeed);
MeowAbsorb(&State, sizeof(LengthTab), &LengthTab);
while(InjestCount--)
{
MeowAbsorb(&State, InputLen, Input);
}
MeowEnd(&State, SeedResult);
}
#define MEOW_HASH_X64_AESNI_H
#endif

4410
code/third_party/metadesk/md.c vendored 100644

File diff suppressed because it is too large Load Diff

1248
code/third_party/metadesk/md.h vendored 100644

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,23 @@
#include "vn_platform.h"
#include "vn_platform.cpp"
#if VN_INTERNAL
#define STB_IMAGE_IMPLEMENTATION
#include "third_party/stb_image.h"
#if VN_INTERNAL
struct debug_settings
{
b32 RenderUIDebugRects;
b32 RenderFPSCounter;
b32 ListHotAndActive;
b32 ShowWelcomeMessage;
};
per_thread debug_settings *DEBUG_DebugSettings = 0;
#endif
#include "vn_config.h"
#include "vn_tokenizer.h"
#include "vn_config.h"
#include "vn_font.h"
#include "vn_text_op.h"
#include "vn_ui.h"
@ -23,7 +25,9 @@ per_thread debug_settings *DEBUG_DebugSettings = 0;
#include "vn_workspace.h"
#include "vn_theme_dark.h"
#include "vn_animation_curve.h"
#include "vn_scene.h"
#include "vn_tokenizer.cpp"
#include "vn_config.cpp"
#include "vn_render.cpp"
#include "vn_font.cpp"
@ -31,10 +35,11 @@ per_thread debug_settings *DEBUG_DebugSettings = 0;
#include "vn_ui_utils.cpp"
#include "vn_animation_curve.cpp"
#include "vn_workspace.cpp"
#include "vn_scene.cpp"
struct vn_state
{
memory_arena Arena;
memory_arena *Arena;
glyph_atlas *GlyphAtlas;
config *Config;
@ -43,11 +48,47 @@ struct vn_state
workspace Workspace;
animation_curve_state AnimationCurveState;
render_handle BackgroundTexture;
#if VN_INTERNAL
debug_settings DebugSettings;
#endif
};
static render_handle CreateTextureFromPath(vn_render_commands *Commands, string Path)
{
render_handle Result = {};
temporary_memory Scratch = GetScratch();
platform_file_handle File = Platform.OpenFile(Path, PlatformAccess_Read);
if(File.IsValid)
{
u64 DataCount = Platform.GetFileSize(File);
u8 *Data = PushArray(Scratch.Arena, u8, DataCount);
Platform.ReadFile(File, Data, 0, DataCount);
s32 Width, Height, BPP;
u8 *TextureData = stbi_load_from_memory(Data, DataCount, &Width, &Height, &BPP, 0);
render_texture_format TextureFormat = Render_TextureFormat_Invalid;
switch(BPP)
{
InvalidDefaultCase;
case 1: { TextureFormat = Render_TextureFormat_R8; } break;
case 3: { TextureFormat = Render_TextureFormat_RGB8; } break;
case 4: { TextureFormat = Render_TextureFormat_RGBA8; } break;
}
Result = Commands->AllocateTexture(V2S32(Width, Height), TextureFormat, TextureData);
stbi_image_free(TextureData);
Platform.CloseFile(File);
}
ReleaseScratch(Scratch);
return(Result);
}
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
{
SetThreadContext(ThreadContext);
@ -55,35 +96,47 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
vn_state *State = Memory->State;
//- sixten: initialize application state
if(!Memory->State)
{
State = Memory->State = BootstrapPushStruct(vn_state, Arena);
memory_arena *Arena = ArenaAllocate(Gigabytes(1));
State = Memory->State = PushStruct(Arena, vn_state);
State->Arena = Arena;
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
State->Config = BootstrapPushStruct(config, Arena);
State->Config = CreateConfig();
// sixten: Setup config binds and load current config.
//- sixten: load assets
State->BackgroundTexture = CreateTextureFromPath(RenderCommands, StrLit("data/backgrounds/Futon_Room.png"));
//- 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);
Config_BindB32(State->Config, StrLit("Dev/ListHotAndActive"), &State->DebugSettings.ListHotAndActive, 0);
DEBUG_DebugSettings = &State->DebugSettings;
Config_BindB32(State->Config, StrLit("Dev/RenderUIDebugRects"), &DEBUG_DebugSettings->RenderUIDebugRects, 0);
Config_BindB32(State->Config, StrLit("Dev/RenderFPSCounter"), &DEBUG_DebugSettings->RenderFPSCounter, 0);
Config_BindB32(State->Config, StrLit("Dev/ListHotAndActive"), &DEBUG_DebugSettings->ListHotAndActive, 0);
Config_BindB32(State->Config, StrLit("Dev/ShowWelcomeMessage"), &DEBUG_DebugSettings->ShowWelcomeMessage, 1);
#endif
Config_ReadFile(State->Config, StrLit("config.vn"));
}
UI_Init(&State->UI);
Workspace_Init(&State->Workspace);
AnimationCurve_Init(&State->AnimationCurveState);
}
#if VN_INTERNAL
DEBUG_DebugSettings = &State->DebugSettings;
#endif
//- sixten: begin new frame
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP, State->GlyphAtlas);
//- sixten: build the ui
UI_BeginBuild(RenderCommands->RenderDim);
{
Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
@ -91,6 +144,7 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
UI_EndBuild();
//- sixten: consume all remaining evetns
for(platform_event *Event = Input->EventList->First;
Event != 0;
Event = Event->Next)
@ -104,16 +158,24 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
Platform_ConsumeEvent(Input->EventList, Event);
}
//- sixten: render the frame
{
render_group Group = BeginRenderGroup(RenderCommands);
PushClear(&Group, V3(0.1, 0.1, 0.1));
PushTexturedQuad(&Group,
Range2R32(V2R32(0, 0), RenderCommands->RenderDim),
Range2R32(V2R32(0, 0), ConvertV2ToR32(DimFromTexture(State->BackgroundTexture))),
Color_White, Color_White, Color_White, Color_White, 0, 0, 0, State->BackgroundTexture);
UI_RenderFrame(&Group, State->GlyphAtlas);
if(DEBUG_DebugSettings->ListHotAndActive)
{
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 20), 15, Color_Grey,
PushFormat(&State->UI.FrameArena, "Hot: %S:%llu", UI_GetBoxNameByKey(UI_GetHot()), UI_GetHot()));
PushFormat(State->UI.FrameArena, "Hot: %S:%llu", UI_GetBoxNameByKey(UI_GetHot()), UI_GetHot()));
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 40), 15, Color_Grey,
PushFormat(&State->UI.FrameArena, "Active: %S:%llu", UI_GetBoxNameByKey(UI_GetActive()), UI_GetActive()));
PushFormat(State->UI.FrameArena, "Active: %S:%llu", UI_GetBoxNameByKey(UI_GetActive()), UI_GetActive()));
}
}
}

View File

@ -10,6 +10,11 @@ inline void AnimationCurve_SetState(animation_curve_state *State)
Global_AnimationCurveState = State;
}
static void AnimationCurve_Init(animation_curve_state *State)
{
State->Arena = ArenaAllocate(Gigabytes(1));
}
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String)
{
animation_curve_key Key;
@ -43,7 +48,7 @@ static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key K
{
if(DLLIsEmpty(State->FirstFreeEntry))
{
Result = PushStruct(&State->Arena, animation_curve_entry);
Result = PushStruct(State->Arena, animation_curve_entry);
}
else
{

View File

@ -33,7 +33,7 @@ struct animation_curve_bucket
struct animation_curve_state
{
memory_arena Arena;
memory_arena *Arena;
u32 CurrentFrame;
r32 dtForFrame;
@ -48,6 +48,7 @@ struct animation_curve_state
inline void AnimationCurve_SetState(animation_curve_state *State);
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String);
static void AnimationCurve_Init(animation_curve_state *State);
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);

View File

@ -1,3 +1,11 @@
static config *CreateConfig(void)
{
memory_arena *Arena = ArenaAllocate(Gigabytes(1));
config *Config = PushStruct(Arena, config);
Config->Arena = Arena;
return(Config);
}
static config_entry *Config_FindEntryByName(config *Config, string Name)
{
config_entry *Result = 0;
@ -24,8 +32,8 @@ static void Config_BindEntry(config *Config, string Name, config_entry_type Type
config_entry *Entry = Config_FindEntryByName(Config, Name);
if(!Entry)
{
Entry = PushStruct(&Config->Arena, config_entry);
Entry->Name = PushString(&Config->Arena, Name);
Entry = PushStruct(Config->Arena, config_entry);
Entry->Name = PushString(Config->Arena, Name);
Entry->Type = Type;
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
@ -66,9 +74,10 @@ inline void Config_BindB32(config *Config, string Name, b32 *Target, b32 Default
Config_BindEntry(Config, Name, Config_Entry_B32, Target);
}
static void Config_ParseError(char *Message, memory_arena *Arena)
static void Config_ParseError(string Message, string FileText, s64 Offset, memory_arena *Arena)
{
string String = PushFormat(Arena, "An error occured during config parsing:\n\"%s\"", Message);
text_point Point = TextPointFromOffset(FileText, Offset);
string String = PushFormat(Arena, "Config: At %i:%i - %S", Point.Line, Point.Column, Message);
Platform.ShowMessage(String, Platform_Message_Warning);
}
@ -76,43 +85,92 @@ 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);
//- sixten: read & tokenize input file
string Text = Platform_ReadEntireFile(Scratch.Arena, Path);
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Path, Text, TokenGroup_Whitespace|TokenGroup_Comment);
token_array Tokens = TokenizeResult.Tokens;
if(Token.Type == Token_Identifier)
{
string Dir = Token.String;
// sixten: parse context
config_parse_list FullPath = {};
config_parse_mode ParseMode = ConfigParseMode_Main;
if(Tokenizer_RequireToken(&Tokenizer, Token_CurlyOpen))
//- sixten: parse tokens
token *TokensStart = Tokens.Tokens;
token *TokensEnd = Tokens.Tokens + Tokens.Count;
token *Token = TokensStart;
for(;Token < TokensEnd;)
{
for(;;)
{
Token = Tokenizer_GetNextToken(&Tokenizer);
string TokenString = Substring(Text, Token->Range);
if(Token.Type == Token_Identifier)
//- sixten: get next name
if(ParseMode == ConfigParseMode_Main && Token->Flags & TokenFlag_Identifier)
{
string Name = Token.String;
Config_ParseListPush(Scratch.Arena, &FullPath, TokenString);
ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals;
Token += 1;
goto TokenConsumed;
}
if(Tokenizer_RequireToken(&Tokenizer, Token_Equals))
//- sixten: scan for curly close
if(ParseMode == ConfigParseMode_Main && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit("}")))
{
Token = Tokenizer_GetNextToken(&Tokenizer);
Config_ParseListPop(&FullPath);
Token += 1;
goto TokenConsumed;
}
if(Token.Type == Token_IntegerValue)
//- sixten: scan for curly open
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit("{")))
{
s64 Value = ConvertStringToS64(Token.String);
ParseMode = ConfigParseMode_Main;
Token += 1;
goto TokenConsumed;
}
string FullName = PushFormat(Scratch.Arena, "%S/%S", Dir, Name);
//- sixten: scan for equals
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Flags & TokenFlag_Symbol && AreEqual(TokenString, StrLit("=")))
{
ParseMode = ConfigParseMode_ScanForValue;
Token += 1;
goto TokenConsumed;
}
//- sixten: scan for semicolon
if(ParseMode == ConfigParseMode_ScanForSemicolon && Token->Flags & TokenFlag_Reserved && AreEqual(TokenString, StrLit(";")))
{
ParseMode = ConfigParseMode_Main;
Token += 1;
goto TokenConsumed;
}
//- sixten: scan for boolean value
if(ParseMode == ConfigParseMode_ScanForValue && Token->Flags & TokenFlag_Identifier && (AreEqual(TokenString, StrLit("true")) || AreEqual(TokenString, StrLit("false"))))
{
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
config_entry *Entry = Config_FindEntryByName(Config, FullName);
if(Entry)
{
b32 Value = AreEqual(TokenString, StrLit("true"));
Assert(Entry->Type == Config_Entry_B32);
*(b32 *)Entry->Target = Value;
}
Config_ParseListPop(&FullPath);
ParseMode = ConfigParseMode_ScanForSemicolon;
Token += 1;
goto TokenConsumed;
}
//- sixten: scan for integer value
if(ParseMode == ConfigParseMode_ScanForValue && Token->Flags & TokenFlag_Numeric)
{
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
config_entry *Entry = Config_FindEntryByName(Config, FullName);
if(Entry)
{
s64 Value = ConvertStringToS64(TokenString);
if(Entry->Type == Config_Entry_S32)
{
*(s32 *)Entry->Target = (s32)Value;
*(s32 *)Entry->Target = Value;
}
else if(Entry->Type == Config_Entry_S64)
{
@ -120,93 +178,75 @@ static void Config_ReadFile(config *Config, string Path)
}
else
{
Config_ParseError("Entry has wrong data type.", Scratch.Arena);
goto End;
InvalidCodepath;
}
}
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;
Config_ParseListPop(&FullPath);
ParseMode = ConfigParseMode_ScanForSemicolon;
Token += 1;
goto TokenConsumed;
}
if(!Tokenizer_RequireToken(&Tokenizer, Token_Semicolon))
//- sixten: if the token has not been consumed, something's gone wrong
{
Config_ParseError("Expected a ';'.", Scratch.Arena);
goto End;
}
}
else
string ErrorMessage = StrLit("Unknown parse error");
//- sixten: determine error message
switch(ParseMode)
{
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;
}
}
case ConfigParseMode_Main: { ErrorMessage = StrLit("Expected identifier or '}'"); } break;
case ConfigParseMode_ScanForCurlyOpenOrEquals: { ErrorMessage = StrLit("Expected '{' or '='") ; } break;
case ConfigParseMode_ScanForValue: { ErrorMessage = StrLit("Expected value"); } break;
case ConfigParseMode_ScanForSemicolon: { ErrorMessage = StrLit("Expected ';'"); } break;
}
Config_ParseError(ErrorMessage, Text, Token->Range.Min, Scratch.Arena);
Token += 1;
}
TokenConsumed:;
}
End:
ReleaseScratch(Scratch);
}
////////////////////////////////
//~ sixten: Config Parse Type Functions
static void Config_ParseListPush(memory_arena *Arena, config_parse_list *List, string Name)
{
config_parse_node *Node = PushStruct(Arena, config_parse_node);
Node->Name = Name;
List->TotalCountPlusOne += Name.Count + 1;
DLLInsertLast(List->First, List->Last, Node);
}
static void Config_ParseListPop(config_parse_list *List)
{
config_parse_node *Node = List->Last;
if(Node)
{
List->TotalCountPlusOne -= Node->Name.Count + 1;
DLLRemove(List->First, List->Last, Node);
}
}
static string Config_ParseListJoin(memory_arena *Arena, config_parse_list *List)
{
s64 TotalCount = List->TotalCountPlusOne - 1;
string Result = MakeString(PushArray(Arena, u8, List->TotalCountPlusOne), TotalCount);
s64 Index = 0;
for(config_parse_node *Node = List->First; Node != 0; Node = Node->Next)
{
Copy(Result.Data + Index, Node->Name.Data, Node->Name.Count);
Index += Node->Name.Count;
if(Node->Next)
{
Result.Data[Index] = '/';
Index += 1;
}
}
return(Result);
}
static void Config_WriteFile(config *Config, string Path)
{
string_list Out = {};

View File

@ -3,6 +3,8 @@
#ifndef VN_CONFIG_H
#define VN_CONFIG_H
////////////////////////////////
//~ sixten: Config Types
enum config_entry_type
{
Config_Entry_S32,
@ -30,7 +32,7 @@ struct config_entry_bucket
struct config
{
memory_arena Arena;
memory_arena *Arena;
config_entry_bucket EntryBuckets[32];
// sixten(NOTE): Keeps track of the order in which the entries were declared. (Used during saving)
@ -38,6 +40,35 @@ struct config
config_entry *LastInternal;
};
////////////////////////////////
//~ sixten: Config Parse Types
enum config_parse_mode
{
ConfigParseMode_Main,
ConfigParseMode_ScanForCurlyOpenOrEquals,
ConfigParseMode_ScanForValue,
ConfigParseMode_ScanForSemicolon,
};
struct config_parse_node
{
config_parse_node *Next;
config_parse_node *Prev;
string Name;
};
struct config_parse_list
{
config_parse_node *First;
config_parse_node *Last;
s64 TotalCountPlusOne;
};
////////////////////////////////
//~ sixten: Config Type Functions
static config *CreateConfig(void);
static config_entry *Config_FindEntryByName(config *Config, string Name);
static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target);
@ -48,4 +79,10 @@ 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);
////////////////////////////////
//~ sixten: Config Parse Type Functions
static void Config_ParseListPush(memory_arena *Arena, config_parse_list *List, string Name);
static void Config_ParseListPop(config_parse_list *List);
static string Config_ParseListJoin(memory_arena *Arena, config_parse_list *List);
#endif //VN_CONFIG_H

View File

@ -1,5 +1,7 @@
#define GLYPH_SUBPIXEL_SEGMENTS 3
global read_only s32 Font_Oversample = 2;
inline s32 GetSubpixelSegmentAtP(r32 Value)
{
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
@ -102,22 +104,24 @@ static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
s32 GlyphSize = MAX_GLYPH_SIZE)
{
glyph_atlas *Atlas = BootstrapPushStruct(glyph_atlas, Arena);
memory_arena *Arena = ArenaAllocate(Megabytes(128));
glyph_atlas *Atlas = PushStruct(Arena, glyph_atlas);
Atlas->Arena = Arena;
Atlas->BitmapSize = BitmapSize;
Atlas->GlyphSize = GlyphSize;
Atlas->MaxGlyphCount = (DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE)*(DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE);
Atlas->Glyphs = PushArray(&Atlas->Arena, glyph, Atlas->MaxGlyphCount);
Atlas->Glyphs = PushArray(Atlas->Arena, glyph, Atlas->MaxGlyphCount);
Atlas->RenderCommands = RenderCommands;
Atlas->Texture = RenderCommands->AllocateTexture(V2S32(BitmapSize, BitmapSize), Render_TextureFormat_R8, 0);
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Roboto-Regular.ttf"));
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Roboto-Bold.ttf"));
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/Liberation-Mono.ttf"));
Atlas->Fonts[Font_Hand].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/PatrickHand-Regular.ttf"));
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("fonts/icons.ttf"));
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/Roboto-Regular.ttf"));
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/Roboto-Bold.ttf"));
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/DejaVuSansMono.ttf"));
Atlas->Fonts[Font_Hand].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/PatrickHand-Regular.ttf"));
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/icons.ttf"));
for(s32 FontIndex = 0;
FontIndex < Font_Count;
@ -131,40 +135,38 @@ static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap);
}
Atlas->BitmapBuffer = PushArray(&Atlas->Arena, u8, GlyphSize*GlyphSize);
Atlas->BitmapBuffer = PushArray(Atlas->Arena, u8, GlyphSize*GlyphSize);
return(Atlas);
}
static void PushText(render_group *Group, glyph_atlas *Atlas, font_id Font,
static r32 PushText(render_group *Group, glyph_atlas *Atlas, font_id Font,
v2 P, r32 Size, v4 Color,
string Text)
{
r32 Oversample = 2;
r32 OffsetX = 0;
for(utf8_iterator Iter = IterateUTF8String(Text);
IsValid(&Iter);
Advance(&Iter))
{
u32 Codepoint = Iter.Codepoint;
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample));
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(P.x*Font_Oversample));
Assert(Glyph);
v2 GlyphP = P;
GlyphP.x += Glyph->Offset.x/Oversample;
GlyphP.y += Glyph->Offset.y/Oversample;
v2 GlyphP = P + Glyph->Offset*(1.0 / Font_Oversample) + V2(OffsetX, 1);
v2 RenderDim = ConvertV2ToR32(Glyph->P1 - Glyph->P0);
v2 Dim = RenderDim;
Dim.x /= Oversample;
Dim.y /= Oversample;
v2 Dim = RenderDim*(1.0 / Font_Oversample);
PushTexturedQuad(Group, GlyphP, Dim, ConvertV2ToR32(Glyph->P0), RenderDim,
PushTexturedQuad(Group,
Range2R32(GlyphP, GlyphP+Dim),
Range2R32(ConvertV2ToR32(Glyph->P0), ConvertV2ToR32(Glyph->P1)),
Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
P.x += Glyph->Advance/Oversample;
OffsetX += Glyph->Advance/Font_Oversample;
}
return(OffsetX);
}
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
@ -185,8 +187,6 @@ static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
{
r32 Oversample = 2;
r32 X = 0;
for(utf8_iterator Iter = IterateUTF8String(Text);
@ -195,10 +195,10 @@ inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Si
{
u32 Codepoint = Iter.Codepoint;
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(X*Oversample));
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(X*Font_Oversample));
Assert(Glyph);
X += Glyph->Advance/Oversample;
X += Glyph->Advance/Font_Oversample;
}
return(X);

View File

@ -89,7 +89,7 @@ struct loaded_font
struct glyph_atlas
{
memory_arena Arena;
memory_arena *Arena;
s32 MaxGlyphCount;
s32 GlyphsUsed;

View File

@ -0,0 +1,113 @@
@table(Name, Type, Arguments)
OpenGLFunctions:
{
{BindTexture `void` `GLenum target, GLuint texture`}
{BlendFunc `void` `GLenum sfactor, GLenum dfactor`}
{Clear `void` `GLbitfield mask`}
{ClearAccum `void` `GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha`}
{ClearColor `void` `GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha`}
{ClearDepth `void` `GLclampd depth`}
{ClearIndex `void` `GLfloat c`}
{ClearStencil `void` `GLint s`}
{ClipPlane `void` `GLenum plane, const GLdouble *equation`}
{CullFace `void` `GLenum mode`}
{DeleteTextures `void` `GLsizei n, const GLuint *textures`}
{Disable `void` `GLenum cap`}
{DrawArrays `void` `GLenum mode, GLint first, GLsizei count`}
{DrawBuffer `void` `GLenum mode`}
{DrawElements `void` `GLenum mode, GLsizei count, GLenum type, const GLvoid *indices`}
{DrawArraysInstanced `void` `GLenum mode, GLint first, GLsizei count, GLsizei instancecount`}
{Enable `void` `GLenum cap`}
{GenTextures `void` `GLsizei n, GLuint *textures`}
{GetClipPlane `void` `GLenum plane, GLdouble *equation`}
{GetDoublev `void` `GLenum pname, GLdouble *params`}
{GetError `GLenum` `void`}
{GetFloatv `void` `GLenum pname, GLfloat *params`}
{GetIntegerv `void` `GLenum pname, GLint *params`}
{GetPointerv `void` `GLenum pname, GLvoid* *params`}
{GetString `const GLubyte *` `GLenum name`}
{GetTexEnvfv `void` `GLenum target, GLenum pname, GLfloat *params`}
{GetTexEnviv `void` `GLenum target, GLenum pname, GLint *params`}
{GetTexGendv `void` `GLenum coord, GLenum pname, GLdouble *params`}
{GetTexGenfv `void` `GLenum coord, GLenum pname, GLfloat *params`}
{GetTexGeniv `void` `GLenum coord, GLenum pname, GLint *params`}
{GetTexImage `void` `GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels`}
{GetTexLevelParameterfv `void` `GLenum target, GLint level, GLenum pname, GLfloat *params`}
{GetTexLevelParameteriv `void` `GLenum target, GLint level, GLenum pname, GLint *params`}
{GetTexParameterfv `void` `GLenum target, GLenum pname, GLfloat *params`}
{GetTexParameteriv `void` `GLenum target, GLenum pname, GLint *params`}
{Hint `void` `GLenum target, GLenum mode`}
{IsTexture `GLboolean` `GLuint texture`}
{LineWidth `void` `GLfloat width`}
{ListBase `void` `GLuint base`}
{LoadName `void` `GLuint name`}
{LogicOp `void` `GLenum opcode`}
{PointSize `void` `GLfloat size`}
{PolygonMode `void` `GLenum face, GLenum mode`}
{Scissor `void` `GLint x, GLint y, GLsizei width, GLsizei height`}
{TexImage1D `void` `GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels`}
{TexImage2D `void` `GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels`}
{TexParameterf `void` `GLenum target, GLenum pname, GLfloat param`}
{TexParameterfv `void` `GLenum target, GLenum pname, const GLfloat *params`}
{TexParameteri `void` `GLenum target, GLenum pname, GLint param`}
{TexParameteriv `void` `GLenum target, GLenum pname, const GLint *params`}
{TexSubImage1D `void` `GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels`}
{TexSubImage2D `void` `GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels`}
{CompressedTexImage2D `void` `GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels`}
{ActiveTexture `void` `GLenum texture`}
{Viewport `void` `GLint x, GLint y, GLsizei width, GLsizei height`}
{GenBuffers `void` `GLsizei n, GLuint *buffers`}
{BindBuffer `void` `GLenum target, GLuint buffer`}
{BufferData `void` `GLenum target, GLsizeiptr size, const void *data, GLenum usage`}
{BufferSubData `void` `GLenum target, GLintptr offset, GLsizeiptr size, const void *data`}
{GenVertexArrays `void` `GLsizei n, GLuint *arrays`}
{BindVertexArray `void` `GLenum array`}
{GetAttribLocation `GLint` `GLuint program, const GLchar *name`}
{EnableVertexAttribArray `void` `GLuint index`}
{DisableVertexAttribArray `void` `GLuint index`}
{VertexAttribPointer `void` `GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer`}
{VertexAttribIPointer `void` `GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer`}
{VertexAttribLPointer `void` `GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer`}
{VertexAttribDivisor `void` `GLuint index, GLuint divisor`}
{CreateShader `GLuint` `GLenum type`}
{ShaderSource `void` `GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length`}
{CompileShader `void` `GLuint shader`}
{DeleteShader `void` `GLuint shader`}
{GetShaderiv `void` `GLuint shader, GLenum pname, GLint *params`}
{GetShaderInfoLog `void` `GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog`}
{CreateProgram `GLuint` `void`}
{UseProgram `void` `GLuint program`}
{AttachShader `void` `GLuint program, GLuint shader`}
{DeleteProgram `void` `GLuint program`}
{LinkProgram `void` `GLuint program`}
{GetProgramiv `void` `GLuint program, GLenum pname, GLint *params`}
{GetProgramInfoLog `void` `GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog`}
{GetUniformLocation `GLint` `GLuint program, const GLchar *name`}
{Uniform1i `void` `GLint location, GLint v0`}
{Uniform2f `void` `GLint location, GLfloat v0, GLfloat v1`}
{Uniform3f `void` `GLint location, GLfloat v0, GLfloat v1, GLfloat v2`}
{UniformMatrix4fv `void` `GLint location, GLsizei count, GLboolean transpose, const GLfloat *value`}
{DebugMessageCallback `void` `void (*)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar *, const void *), const void *userParam`}
}
// sixten: Generate the typedefs.
@table_gen
{
@expand(OpenGLFunctions s) `typedef $(s.Type) opengl_$(s.Name)($(s.Arguments));`;
}
// sixten: Generate the global pointers.
@table_gen
{
@expand(OpenGLFunctions s) `global opengl_$(s.Name) *gl$(s.Name) = 0;`;
}
// sixten: Generate OpenGL_LoadAllFunctions
@table_gen
{
`extern void *OpenGL_LoadFunction(char *);`;
`static void OpenGL_LoadAllFunctions(void)`;
`{`;
@expand(OpenGLFunctions s) `gl$(s.Name) = (opengl_$(s.Name) *)OpenGL_LoadFunction("gl$(s.Name)");`;
`}`;
}

View File

@ -11,21 +11,6 @@
// sixten: Services the platform provides to the application
struct platform_memory_block
{
u8 *Base;
u64 Size;
u64 Used;
platform_memory_block *ArenaPrev;
};
#define PLATFORM_ALLOCATE_MEMORY(name) platform_memory_block *name(u64 Size)
typedef PLATFORM_ALLOCATE_MEMORY(platform_allocate_memory);
#define PLATFORM_DEALLOCATE_MEMORY(name) b32 name(platform_memory_block *Block)
typedef PLATFORM_DEALLOCATE_MEMORY(platform_deallocate_memory);
enum
{
PlatformAccess_Read = 0x1,
@ -39,21 +24,6 @@ struct platform_file_handle
b32 IsValid;
};
#define PLATFORM_OPEN_FILE(name) platform_file_handle name(string Path, platform_access_flags FileAccess)
typedef PLATFORM_OPEN_FILE(platform_open_file);
#define PLATFORM_CLOSE_FILE(name) void name(platform_file_handle Handle)
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);
enum platform_cursor
{
PlatformCursor_Arrow,
@ -72,12 +42,6 @@ enum platform_cursor
PlatformCursor_Count
};
#define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor)
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,
@ -86,25 +50,6 @@ enum platform_message_type
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;
platform_deallocate_memory *DeallocateMemory;
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
{
PlatformEvent_Press,
@ -170,6 +115,8 @@ struct platform_event_list
platform_event *Last;
};
#include "generated/vn_platform.meta.h"
static platform_api Platform;
// sixten: Services that the render backend provides to the application

View File

@ -0,0 +1,39 @@
@table(Name, NameLower, NameCaps, Type, Arguments) platform_functions:
{
{ Reserve reserve RESERVE `void *` `u64 Size` }
{ Release release RELEASE `void` `void *Pointer` }
{ Commit commit COMMIT `void` `void *Pointer, u64 Size` }
{ Decommit decommit DECOMMIT `void` `void *Pointer, u64 Size` }
{ OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` }
{ CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` }
{ ReadFile read_file READ_FILE `void` `platform_file_handle Handle, void *Dest, u64 Offset, u64 Size` }
{ WriteFile write_file WRITE_FILE `void` `platform_file_handle Handle, void *Source, u64 Offset, u64 Size` }
{ GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` }
{ SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` }
{ ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` }
{ ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` }
}
@table_gen
{
@expand(platform_functions s) `#define PLATFORM_$(s.NameCaps)(name) $(s.Type) name($(s.Arguments))`
}
@table_gen
{
@expand(platform_functions s) `typedef PLATFORM_$(s.NameCaps)(platform_$(s.NameLower));`
}
@table_gen
{
`struct platform_api`
`{`
@expand(platform_functions s) `platform_$(s.NameLower) *$(s.Name); `
`};`
}
@table_gen
{
`#define RegisterPlatformFunctions(PlatformName)\\`
@expand(platform_functions s) `Platform.$(s.Name) = PlatformName##_$(s.Name);\\`
}

View File

@ -9,7 +9,7 @@ inline b32 AreEqual(render_handle A, render_handle B)
return(Result);
}
inline v2_s32 GetTextureDim(render_handle Handle)
inline v2_s32 DimFromTexture(render_handle Handle)
{
v2_s32 Result = V2S32(Handle.U32[2], Handle.U32[3]);
return(Result);
@ -102,9 +102,49 @@ inline u32 PackV4ToU32(v4 V)
return(Result);
}
inline void PushTexturedQuad(render_group *Group,
v2 P, v2 Dim,
v2 SourceP, v2 SourceDim,
#if 0
static void PushTexturedQuadAsInstances(render_group *Group,
range2_r32 Dest,
range2_r32 Source,
v4 Color00, v4 Color10, v4 Color01, v4 Color11,
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness,
render_handle Texture)
{
vn_render_commands *Commands = Group->Commands;
render_command_instanced_quads *Command = (render_command_instanced_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_instanced_quads &&
(TextureIndex = GetTextureIndexForCommand((render_command_quads *)Command, Texture)) != -1))
{
Command = PushCommand(Group, render_command_instanced_quads);
TextureIndex = GetTextureIndexForCommand((render_command_quads *)Command, Texture);
Command->QuadBufferIndex = Commands->QuadIndexCount;
}
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
range2_r32 FinalDest = Intersection(Dest, Clip);
if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
instanced_quad *Quad = Commands->InstancedQuadBase + Commands->InstancedQuadCount++;
Quad->Dest = Dest;
Quad->Source = Source;
Quad->TextureIndex = TextureIndex;
Quad->Colors[0] = PackV4ToU32(Color00);
Quad->Colors[1] = PackV4ToU32(Color10);
Quad->Colors[2] = PackV4ToU32(Color01);
Quad->Colors[3] = PackV4ToU32(Color11);
Quad->CornerRadius = CornerRadius;
Quad->EdgeSoftness = EdgeSoftness;
Quad->BorderThickness = BorderThickness;
}
}
#endif
static void PushTexturedQuad(render_group *Group,
range2_r32 Dest,
range2_r32 Source,
v4 Color00, v4 Color10, v4 Color01, v4 Color11,
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness,
render_handle Texture)
@ -122,33 +162,30 @@ inline void PushTexturedQuad(render_group *Group,
}
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
range2_r32 Dest = Range2R32(P, P + Dim);
v2 DestMin = Max(Dest.Min, Clip.Min);
v2 DestMax = Min(Dest.Max, Clip.Max);
if(InRange(Clip, P) || InRange(Clip, P + Dim))
// sixten(TODO): Proper aabb overlap testing here!
if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2 HalfSize = Dim*0.5;
v2 HalfSize = DimOfRange(Dest)*0.5;
v2 P00 = V2(DestMin.x, DestMin.y);
v2 P01 = V2(DestMin.x, DestMax.y);
v2 P10 = V2(DestMax.x, DestMin.y);
v2 P11 = V2(DestMax.x, DestMax.y);
v2 Center = P + HalfSize;
v2 Center = (DestMin + DestMax)*0.5;
u32 Width = Texture.U32[2];
u32 Height = Texture.U32[3];
v2 TextureSize = V2(Texture.U32[2], Texture.U32[3]);
SourceP.x /= Width;
SourceP.y /= Height;
SourceDim.x /= Width;
SourceDim.y /= Height;
Source.Min /= TextureSize;
Source.Max /= TextureSize;
v2 Source00 = SourceP;
v2 Source01 = SourceP + V2(0, SourceDim.y);
v2 Source10 = SourceP + V2(SourceDim.x, 0);
v2 Source11 = SourceP + SourceDim;
v2 Source00 = Source.Min;
v2 Source01 = V2(Source.Min.x, Source.Max.y);
v2 Source10 = V2(Source.Max.x, Source.Min.y);
v2 Source11 = Source.Max;;
s32 BaseVertex = Commands->QuadVertexCount;
@ -213,19 +250,19 @@ inline void PushTexturedQuad(render_group *Group,
#endif
}
inline void PushQuad(render_group *Group, v2 P, v2 Dim,
inline void PushQuad(render_group *Group, range2_r32 Dest,
v4 Color00, v4 Color01, v4 Color10, v4 Color11,
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness)
{
PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color00, Color01, Color10, Color11,
PushTexturedQuad(Group, Dest, Range2R32(V2(0, 0), V2(0, 0)), Color00, Color01, Color10, Color11,
CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture);
}
inline void PushQuad(render_group *Group, v2 P, v2 Dim,
inline void PushQuad(render_group *Group, range2_r32 Dest,
v4 Color,
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness)
{
PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color, Color, Color, Color,
PushTexturedQuad(Group, Dest, Range2R32(V2(0, 0), V2(0, 0)), Color, Color, Color, Color,
CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture);
}

View File

@ -4,7 +4,7 @@
#define VN_RENDER_H
#define MAX_BOUND_TEXTURES 16
#define MAX_QUAD_COUNT 16*1024
#define MAX_QUAD_COUNT 128*1024
#define ColorFromHex(Value) V4((((Value) >> 24) & 0xFF) / 255.0, (((Value) >> 16) & 0xFF) / 255.0, (((Value) >> 8) & 0xFF) / 255.0, (((Value) >> 0) & 0xFF) / 255.0)
@ -21,8 +21,11 @@ read_only v4 Color_Yellow = V4(1, 1, 0, 1);
read_only v4 Color_Magenta = V4(1, 0, 1, 1);
read_only v4 Color_Cyan = V4(0, 1, 1, 1);
#define SetAlpha(Color, Value) V4(Color.x, Color.y, Color.z, Value)
enum render_texture_format
{
Render_TextureFormat_Invalid,
Render_TextureFormat_R8,
Render_TextureFormat_RGB8,
Render_TextureFormat_RGBA8,
@ -41,6 +44,7 @@ enum render_command_type
{
Render_Command_render_command_clear,
Render_Command_render_command_quads,
//Render_Command_render_command_instanced_quads,
Render_Command_render_command_clip,
};
@ -78,6 +82,19 @@ struct render_group
s32 ClipStackUsed;
};
#if 0
struct instanced_quad
{
range2_r32 Dest;
range2_r32 Source;
u32 TextureIndex;
u32 Colors[4];
r32 CornerRadius;
r32 EdgeSoftness;
r32 BorderThickness;
};
#endif
struct quad_vertex
{
v2 P;

63
code/vn_scene.cpp 100644
View File

@ -0,0 +1,63 @@
////////////////////////////////
//~ sixten: Scene Message Functions
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String)
{
scene_message *Message = PushStruct(Arena, scene_message);
Message->Type = Type;
Message->Node = Node;
Message->String = String;
QueuePush(Messages->First, Messages->Last, Message);
Messages->Count += 1;
}
////////////////////////////////
//~ sixten: Scene Node Functions
static scene_node *S_SceneFromText(memory_arena *Arena, string Filename, string Text)
{
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Filename, Text, TokenGroup_Comment|TokenGroup_Whitespace);
scene_parse_result ParseResult = S_ParseFromTokens(Arena, Filename, Text, TokenizeResult.Tokens);
scene_node *Result = ParseResult.Root;
return(Result);
}
////////////////////////////////
//~ sixten: Tokens -> Syntax Tree
static scene_parse_result S_ParseFromTokens(memory_arena *Arena, string Filename, string Text, token_array Tokens)
{
temporary_memory Scratch = GetScratch(&Arena, 1);
//scene_node *Root = {};
//- sixten: setup parse context
scene_parse_context Context = {};
{
Context.TokensStart = Tokens.Tokens;
Context.TokensEnd = Context.TokensStart + Tokens.Count;
Context.Token = Context.TokensStart;
}
//- sixten: parse top-level
for(;Context.Token < Context.TokensEnd;)
{
string TokenString = PushString(Scratch.Arena, T_StringFromToken(Text, *Context.Token));
if(T_TokenMatches(*Context.Token, TokenFlag_Identifier, Text, StrLit("proc")))
{
Context.Token += 1;
goto TokenConsumed;
}
//- sixten: token was not consumed, something has gone wrong
{
Context.Token += 1;
}
TokenConsumed:;
}
ReleaseScratch(Scratch);
scene_parse_result Result =
{
0
};
return(Result);
}

97
code/vn_scene.h 100644
View File

@ -0,0 +1,97 @@
/* date = July 9th 2023 11:08 am */
#ifndef VN_SCENE_H
#define VN_SCENE_H
////////////////////////////////
//~ sixten: Scene Node Types
enum scene_node_kind
{
S_NodeKind_Invalid,
S_NodeKind_File,
S_NodeKind_Proc,
S_NodeKind_Text,
S_NodeKind_Branch,
S_NodeKind_Count,
};
struct scene_node
{
scene_node *Next;
scene_node *Prev;
scene_node *First;
scene_node *Last;
scene_node *Parent;
scene_node *FirstTag;
scene_node *LastTag;
scene_node_kind Kind;
string String;
u64 SourceOffset;
};
////////////////////////////////
//~ sixten: Scene Messages
enum scene_message_type
{
S_MessageType_Invalid,
S_MessageType_Note,
S_MessageType_Warning,
S_MessageType_Error,
};
struct scene_message
{
scene_message_type Type;
scene_message *Next;
scene_node *Node;
string String;
};
struct scene_message_list
{
scene_message *First;
scene_message *Last;
s64 Count;
};
////////////////////////////////
//~ sixten: Text -> Tokens
struct scene_tokenize_result
{
token_array Tokens;
scene_message_list Messages;
};
struct scene_parse_context
{
token *TokensStart;
token *TokensEnd;
token *Token;
};
////////////////////////////////
//~ sixten: Tokens -> Syntax Tree
struct scene_parse_result
{
scene_node *Root;
scene_message_list Messages;
};
////////////////////////////////
//~ sixten: Scene Message Functions
static void S_PushMessage(memory_arena *Arena, scene_message_list *Messages, scene_node *Node, scene_message_type Type, string String);;
////////////////////////////////
//~ sixten: Scene Node Functions
static scene_node *S_PushNode(memory_arena *Arena, scene_node_kind Kind, string String);
static scene_node *S_SceneFromText(memory_arena *Arena, string Text);
////////////////////////////////
//~ sixten: Tokens -> Syntax Tree
static scene_node *S_ParseProc(scene_parse_context *Context, string ProcName);
static scene_parse_result S_ParseFromTokens(memory_arena *Arena, string Filename, string Text, token_array Tokens);
#endif //VN_SCENE_H

34
code/vn_scene.md 100644
View File

@ -0,0 +1,34 @@
@table(Name, NameLower, Contents) scene_ast_node_types:
{
{ Invalid invalid `` }
{ BlockStatement block_statement `scene_ast_node *First; scene_ast_node *Last;` }
{ SceneDecl scene_declaration `` }
}
@table_gen_enum scene_ast_node_type:
{
@expand(scene_ast_node_types s) `S_AstNode_$(s.Name),`;
`S_AstNode_Count,`:
}
@table_gen
{
`struct scene_ast_node;`
}
@table_gen
{
@expand(scene_ast_node_types s) `struct scene_ast_node_$(s.NameLower) {$(s.Contents)};`
}
@table_gen
{
`struct scene_ast_node`;
`{`;
`scene_ast_node_type Type;`;
`union`;
`{`;
@expand(scene_ast_node_types s) `scene_ast_node_$(s.NameLower) $(s.Name)Data;`;
`};`;
`};`;
}

View File

@ -26,6 +26,10 @@ enum
TextActionFlag_Delete = (1<<2),
TextActionFlag_ZeroDeltaWithSelection = (1<<3),
TextActionFlag_DeltaPicksSelectionSide = (1<<4),
TextActionFlag_OperateOnLine = (1<<5),
TextActionFlag_StopOnNewline = (1<<6),
TextActionFlag_EmptyLineScan = TextActionFlag_WordScan,
};
struct text_action
@ -98,7 +102,82 @@ static text_action SingleLineTextActionFromEvent(platform_event *Event)
return(Action);
}
inline s64 CodepointScan(string String, s64 Index, s64 Delta)
static text_action MultiLineTextActionFromEvent(platform_event *Event)
{
text_action Action = {};
if(Event->Type == PlatformEvent_Text)
{
Action.Codepoint = Event->Codepoint;
}
else if(Event->Type == PlatformEvent_Press)
{
if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_WordScan;
}
if(Event->Modifiers & PlatformModifier_Shift)
{
Action.Flags |= TextActionFlag_KeepMark;
}
switch(Event->Key)
{
case Key_Right:
{
Action.Delta = +1;
Action.Flags |= TextActionFlag_DeltaPicksSelectionSide;
} break;
case Key_Left:
{
Action.Delta = -1;
Action.Flags |= TextActionFlag_DeltaPicksSelectionSide;
} break;
case Key_Down:
{
Action.Delta = +1;
Action.Flags |= TextActionFlag_OperateOnLine;
} break;
case Key_Up:
{
Action.Delta = -1;
Action.Flags |= TextActionFlag_OperateOnLine;
} break;
case Key_Home:
{
Action.Delta = S64_Min;
Action.Flags |= TextActionFlag_StopOnNewline;
} break;
case Key_End:
{
Action.Delta = S64_Max;
Action.Flags |= TextActionFlag_StopOnNewline;
} break;
case Key_Backspace:
{
Action.Delta = -1;
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
} break;
case Key_Delete:
{
Action.Delta = +1;
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
} break;
default: {} break;
}
}
return(Action);
}
inline s64 CodepointScan(string String, s64 Index, s64 Delta, b32 StopOnNewline)
{
s64 Result = 0;
if(Delta > 0)
@ -108,6 +187,11 @@ inline s64 CodepointScan(string String, s64 Index, s64 Delta)
u8 Base = String.Data[Index];
s64 ToMove = 0;
if(StopOnNewline && Base == '\n')
{
break;
}
if((Base & 0x80) == 0x00)
{
ToMove = 1;
@ -138,6 +222,13 @@ inline s64 CodepointScan(string String, s64 Index, s64 Delta)
while(Index >= 0 && (Delta != 0))
{
u8 Base = String.Data[Index];
if(StopOnNewline && Base == '\n')
{
break;
}
if(((Base & 0x80) == 0) || !((Base & 0xC0) == 0x80))
{
++Delta;
@ -218,7 +309,8 @@ static s64 WordScan(string String, s64 Index, s64 Delta)
}
static text_op TextOpFromAction(memory_arena *Arena, string String,
text_edit_state *State, text_action *Action)
text_edit_state *State, text_action *Action,
range1_s64_array *Lines = 0, s64 LastColumnIndex = 0)
{
text_op Op = {};
@ -228,15 +320,57 @@ static text_op TextOpFromAction(memory_arena *Arena, string String,
Op.ReplaceString = StrLit("");
s64 Delta = 0;
if(Action->Flags & TextActionFlag_OperateOnLine)
{
if(Action->Flags & TextActionFlag_EmptyLineScan)
{
}
else
{
//- sixten: determine what line we are on.
s64 LineIndex = 0;
s64 ColumnIndex = 0;
u8 *TextBegin = String.Data;
u8 *TextEnd = TextBegin + State->Cursor;
u8 *Char = TextBegin;
for(;Char < TextEnd; Char += 1)
{
ColumnIndex += 1;
if(*Char == '\n')
{
LineIndex += 1;
ColumnIndex = 0;
}
}
u64 ColumnOffset = Max(LastColumnIndex - ColumnIndex, 0LLU);
//- sixten: check that the line we are trying to access is inbouse, else just go to the start or end of the text.
if(InRange(Range1S64(0, Lines->Count), LineIndex + Action->Delta))
{
Delta = Lines->Ranges[LineIndex+Action->Delta].Min - Lines->Ranges[LineIndex].Min + ColumnOffset;
if(!InRange(Lines->Ranges[LineIndex+Action->Delta], State->Cursor + Delta))
{
Delta = Lines->Ranges[LineIndex+Action->Delta].Max - State->Cursor - 1;
}
}
else
{
s64 TempDelta = (Action->Delta > 0)?S64_Max:S64_Min;
Delta = CodepointScan(String, State->Cursor, TempDelta, Action->Flags & TextActionFlag_StopOnNewline);
}
}
}
else
{
if(Action->Flags & TextActionFlag_WordScan)
{
Delta = WordScan(String, State->Cursor, Action->Delta);
}
else
{
Delta = CodepointScan(String, State->Cursor, Action->Delta);
Delta = CodepointScan(String, State->Cursor, Action->Delta, Action->Flags & TextActionFlag_StopOnNewline);
}
}
if(State->Cursor != State->Mark &&
Action->Flags & TextActionFlag_ZeroDeltaWithSelection)
{

View File

@ -0,0 +1,288 @@
////////////////////////////////
//~ sixten: Token Type Functions
static string T_StringFromToken(string Text, token Token)
{
string Result = Substring(Text, Token.Range);
return(Result);
}
static b32 T_TokenMatches(token Token, token_flags Flags, string Text, string String)
{
b32 Result = (Token.Flags & Flags && AreEqual(T_StringFromToken(Text, Token), String));
return(Result);
}
static void T_TokenChunkListPush(memory_arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode)
{
token_chunk_node *Node = List->Last;
if(!Node || Node->Count >= Node->MaxCount)
{
Node = PushStruct(Arena, token_chunk_node);
Node->Count = 0;
Node->MaxCount = MaxTokenCountPerNode;
Node->Tokens = PushArrayNoClear(Arena, token, Node->MaxCount);
QueuePush(List->First, List->Last, Node);
}
Node->Tokens[Node->Count] = Token;
Node->Count += 1;
List->Count += 1;
}
static token_array T_TokenArrayFromList(memory_arena *Arena, token_chunk_list *List)
{
token_array Result = {};
Result.Tokens = PushArrayNoClear(Arena, token, List->Count);
Result.Count = List->Count;
s64 Index = 0;
for(token_chunk_node *Node = List->First; Node != 0; Node = Node->Next)
{
Copy(Result.Tokens + Index, Node->Tokens, sizeof(token)*Node->Count);
Index += Node->Count;
}
return(Result);
}
////////////////////////////////
//~ sixten: Tokenizer Message Functions
static void T_MessageListPush(memory_arena *Arena, tokenizer_message_list *List, tokenizer_message_kind Kind, s64 Offset, string String)
{
tokenizer_message *Message = PushStructNoClear(Arena, tokenizer_message);
Message->Kind = Kind;
Message->Offset = Offset;
Message->String = String;
QueuePush(List->First, List->Last, Message);
}
////////////////////////////////
//~ sixten: Text -> Token Functions
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename, string Text, token_flags ExcludeFilter)
{
temporary_memory Scratch = GetScratch(&Arena, 1);
token_chunk_list Tokens = {};
tokenizer_message_list Messages = {};
u8 *TextStart = Text.Data;
u8 *TextEnd = TextStart + Text.Count;
u8 *Byte = TextStart;
//- sixten: scan string & produce tokens
for(;Byte < TextEnd;)
{
token_flags TokenFlags = 0;
u8 *TokenStart = 0;
u8 *TokenEnd = 0;
//- sixten: whitespace
if(TokenFlags == 0 && (*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
{
TokenFlags = TokenFlag_Whitespace;
TokenStart = Byte;
TokenEnd = Byte;
Byte += 1;
for(;Byte <= TextEnd; Byte += 1)
{
TokenEnd += 1;
if(Byte == TextEnd || !(*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
{
break;
}
}
}
//- sixten: newlines
if(TokenFlags == 0 && *Byte == '\n')
{
TokenFlags = TokenFlag_Newline;
TokenStart = Byte;
TokenEnd = Byte + 1;
Byte += 1;
}
//- sixten: single-line comments
if(TokenFlags == 0 && (Byte[0] == '/' && Byte[1] == '/'))
{
TokenFlags = TokenFlag_Comment;
TokenStart = Byte;
TokenEnd = Byte + 2;
Byte += 2;
for(;Byte <= TextEnd; Byte += 1)
{
if(Byte == TextEnd || *Byte == '\n' || *Byte == '\r')
{
break;
}
TokenEnd += 1;
}
}
//- sixten: multi-line comments
if(TokenFlags == 0 && (Byte+1 < TextEnd && Byte[0] == '/' && Byte[1] == '*'))
{
TokenFlags = TokenFlag_Comment;
TokenStart = Byte;
TokenEnd = Byte + 2;
Byte += 2;
for(;Byte <= TextEnd; Byte += 1)
{
// sixten(NOTE): This could potentially be wrong. The TokenEnd += 1 statement could currently make the token include the EOF.
if(Byte == TextEnd)
{
TokenFlags |= TokenFlag_BrokenComment;
break;
}
TokenEnd += 1;
if(Byte+1 < TextEnd && Byte[0] == '*' && Byte[1] == '/')
{
TokenEnd += 1;
Byte += 2;
break;
}
}
}
//- sixten: identifiers
if(TokenFlags == 0 && (('A' <= *Byte && *Byte <= 'Z') ||
('a' <= *Byte && *Byte <= 'z') ||
(UTF8Lengths[*Byte>>3] > 1) ||
*Byte == '_'))
{
TokenFlags = TokenFlag_Identifier;
TokenStart = Byte;
TokenEnd = Byte;
Byte += 1;
for(;Byte <= TextEnd; Byte += 1)
{
TokenEnd += 1;
if(Byte == TextEnd || !(('A' <= *Byte && *Byte <= 'Z') ||
('a' <= *Byte && *Byte <= 'z') ||
('0' <= *Byte && *Byte <= '9') ||
(UTF8Lengths[*Byte>>3] > 1) ||
*Byte == '_'))
{
break;
}
}
}
//- sixten: numerics
if(TokenFlags == 0 && (('0' <= *Byte && *Byte <= '9') ||
*Byte == '.' ||
((*Byte == '+' || *Byte == '-') && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
{
TokenFlags = TokenFlag_Numeric;
TokenStart = Byte;
TokenEnd = Byte;
Byte += 1;
for(;Byte <= TextEnd; Byte += 1)
{
TokenEnd += 1;
if(Byte == TextEnd ||
!(('A' <= *Byte && *Byte <= 'Z') ||
('a' <= *Byte && *Byte <= 'z') ||
('0' <= *Byte && *Byte <= '9') ||
*Byte == '_' || *Byte == '.'))
{
break;
}
}
}
//- sixten: string literals
if(TokenFlags == 0 && *Byte == '"')
{
TokenFlags = TokenFlag_StringLiteral;
TokenStart = Byte;
TokenEnd = Byte;
Byte += 1;
for(;Byte <= TextEnd; Byte += 1)
{
TokenEnd += 1;
if(Byte == TextEnd || *Byte == '\n')
{
TokenFlags |= TokenFlag_BrokenStringLiteral;
break;
}
if(*Byte == '"')
{
Byte += 1;
TokenEnd += 1;
break;
}
}
}
//- sixten: multi-char symbols
if(TokenFlags == 0 && (*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' ||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' ||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' ||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\''))
{
TokenFlags = TokenFlag_Symbol;
TokenStart = Byte;
TokenEnd = Byte;
Byte += 1;
for(;Byte <= TextEnd; Byte += 1)
{
TokenEnd += 1;
if(Byte == TextEnd ||
!(*Byte == '!' || *Byte == '%' || *Byte == '&' || *Byte == '|' ||
*Byte == '/' || *Byte == '=' || *Byte == '?' || *Byte == '^' ||
*Byte == '*' || *Byte == '+' || *Byte == '-' || *Byte == '$' ||
*Byte == '<' || *Byte == '>' || *Byte == '~' || *Byte == '\''))
{
break;
}
}
}
//- sixten: single-char symbols
if(TokenFlags == 0 && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
*Byte == '[' || *Byte == ']' || *Byte == ',' || *Byte == ';' ||
*Byte == ':' || *Byte == '@' || *Byte == '#'))
{
TokenFlags = TokenFlag_Reserved;
TokenStart = Byte;
TokenEnd = Byte + 1;
Byte += 1;
}
//- sixten: bad character
if(TokenFlags == 0)
{
TokenFlags = TokenFlag_BadCharacter;
TokenStart = Byte;
TokenStart = Byte + 1;
Byte += 1;
}
//- sixten: push token
if(TokenFlags != 0 && !(TokenFlags & ExcludeFilter) && TokenStart != 0 && TokenEnd > TokenStart)
{
token Token = {TokenFlags, {TokenStart - TextStart, TokenEnd - TextStart}};
T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
}
if(TokenFlags & TokenFlag_BrokenComment)
{
string Message = StrLit("broken comment");
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
}
if(TokenFlags & TokenFlag_BrokenStringLiteral)
{
string Message = StrLit("broken string literal");
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
}
}
tokenize_result Result =
{
T_TokenArrayFromList(Arena, &Tokens),
Messages
};
ReleaseScratch(Scratch);
return(Result);
}

View File

@ -1,122 +1,118 @@
/* date = June 18th 2023 5:12 pm */
/* date = July 9th 2023 8:04 pm */
#ifndef VN_TOKENIZER_H
#define VN_TOKENIZER_H
enum token_type
////////////////////////////////
//~ sixten: Token Types
typedef u32 token_flags;
enum
{
Token_EndOfFile,
Token_Identifier,
Token_IntegerValue,
//Token_RealValue,
Token_CurlyOpen,
Token_CurlyClose,
Token_Semicolon,
Token_Equals,
TokenFlag_Identifier = (1<<0),
TokenFlag_Numeric = (1<<1),
TokenFlag_StringLiteral = (1<<2),
TokenFlag_Symbol = (1<<3),
TokenFlag_Reserved = (1<<4),
TokenFlag_Comment = (1<<5),
TokenFlag_Whitespace = (1<<6),
TokenFlag_Newline = (1<<7),
TokenFlag_BrokenComment = (1<<8),
TokenFlag_BrokenStringLiteral = (1<<9),
TokenFlag_BadCharacter = (1<<10),
};
struct tokenizer
typedef u32 token_group;
enum
{
string Input;
s64 At;
s64 Index;
TokenGroup_Comment = TokenFlag_Comment,
TokenGroup_Whitespace = (TokenFlag_Whitespace |
TokenFlag_Newline),
TokenGroup_Irregular = (TokenGroup_Comment |
TokenGroup_Whitespace),
TokenGroup_Regular = ~TokenGroup_Irregular,
TokenGroup_Label = (TokenFlag_Identifier |
TokenFlag_Numeric |
TokenFlag_StringLiteral |
TokenFlag_Symbol),
TokenGroup_Error = (TokenFlag_BrokenComment |
TokenFlag_BrokenStringLiteral |
TokenFlag_BadCharacter),
};
struct token
{
token_type Type;
token_flags Flags;
range1_s64 Range;
};
struct token_chunk_node
{
token *Tokens;
s64 MaxCount;
s64 Count;
token_chunk_node *Next;
};
struct token_chunk_list
{
token_chunk_node *First;
token_chunk_node *Last;
s64 Count;
};
struct token_array
{
token *Tokens;
s64 Count;
};
////////////////////////////////
//~ sixten: Tokenizer Message Types
enum tokenizer_message_kind
{
T_MessageKind_Invalid,
T_MessageKind_Note,
T_MessageKind_Warning,
T_MessageKind_Error,
};
struct tokenizer_message
{
tokenizer_message *Next;
tokenizer_message_kind Kind;
s64 Offset;
string String;
};
inline tokenizer Tokenizer_BeginTokenization(string Input)
struct tokenizer_message_list
{
tokenizer Result = {};
Result.Input = Input;
tokenizer_message *First;
tokenizer_message *Last;
s64 Count;
};
return(Result);
}
static token Tokenizer_GetNextToken(tokenizer *Tokenizer)
////////////////////////////////
//~ sixten: Text -> Token Types
struct tokenize_result
{
token Token = {};
token_array Tokens;
tokenizer_message_list Messages;
};
string Input = Tokenizer->Input;
u8 *Base = Input.Data;
////////////////////////////////
//~ sixten: Token Type Functions
static string T_StringFromToken(string Text, token Token);
static b32 T_TokenMatches(token Token, token_flags Flags, string Text, string String);
static void T_TokenChunkListPush(memory_arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode);
static token_array T_TokenArrayFromChunkList(memory_arena *Arena, token_chunk_list *List);
// sixten: Consume whitespace
while(IsWhitespace(Base[Tokenizer->Index]))
{
++Tokenizer->Index;
}
////////////////////////////////
//~ sixten: Tokenizer Message Functions
static void T_MessageListPush(memory_arena *Arena, tokenizer_message_list *List, tokenizer_message_kind Kind, s64 Offset, string String);
// 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);
}
////////////////////////////////
//~ sixten: Text -> Token Functions
static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Filename, string Text, token_flags ExcludeFilter = 0);
#endif //VN_TOKENIZER_H

View File

@ -1,4 +1,4 @@
#include "generated/vn_generated_ui.cpp"
#include "generated/vn_ui.meta.c"
inline ui_size UI_Pixels(r32 Value, r32 Strictness)
{
@ -54,6 +54,25 @@ inline ui_key UI_GetActive(void)
return(UI->Active);
}
inline platform_event_list *UI_EventList(void)
{
ui *UI = UI_GetState();
return(UI->EventList);
}
inline v2 UI_MouseP(void)
{
ui *UI = UI_GetState();
return(UI->MouseP);
}
inline glyph_atlas *UI_GlyphAtlas(void)
{
ui *UI = UI_GetState();
return(UI->GlyphAtlas);
}
inline void UI_SetDragStartP(v2 P)
{
ui *UI = UI_GetState();
@ -207,7 +226,7 @@ inline ui_box *UI_GetBoxByKey(ui *UI, ui_key Key)
if(DLLIsEmpty(UI->FirstFreeBox))
{
// sixten: If not, simply allocate one
Result = PushStruct(&UI->Arena, ui_box);
Result = PushStruct(UI->Arena, ui_box);
}
else
{
@ -259,7 +278,7 @@ inline ui_box *UI_MakeBox(ui_box_flags Flags, string String)
Box->LastFrameTouched = UI->CurrentFrame;
Box->Flags = Flags;
Box->String = PushString(&UI->FrameArena, String);
Box->String = PushString(UI->FrameArena, String);
s64 HashIndex = LastIndexOf(Box->String, '#');
if(HashIndex != -1)
@ -286,7 +305,7 @@ inline ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...)
va_list Arguments;
va_start(Arguments, Format);
string String = PushFormatVariadic(&UI->FrameArena, Format, Arguments);
string String = PushFormatVariadic(UI->FrameArena, Format, Arguments);
va_end(Arguments);
ui_box *Box = UI_MakeBox(Flags, String);
@ -335,6 +354,11 @@ static b32 UI_ChildrenContainsP(ui_box *Parent, v2 P, range2_r32 Clip)
break;
}
}
if(Child == Parent->Last)
{
break;
}
}
return(Result);
@ -358,7 +382,21 @@ static ui_signal UI_SignalFromBox(ui_box *Box)
}
}
Signal.Hovering = InRange(ClippedRect, UI->MouseP) && !UI_ChildrenContainsP(Box, UI->MouseP, ClippedRect);
Signal.Hovering = InRange(ClippedRect, UI->MouseP);
// sixten: Make sure no children boxes overlap.
Signal.Hovering &= !UI_ChildrenContainsP(Box, UI->MouseP, ClippedRect);
// sixten: Make sure no previous boxes overlap.
if(Box->Prev)
{
ui_box PrevBoxParent = {};
PrevBoxParent.Rect = Box->Rect;
PrevBoxParent.First = Box->Parent->First;
PrevBoxParent.Last = Box->Prev;
Signal.Hovering &= !UI_ChildrenContainsP(&PrevBoxParent, UI->MouseP, ClippedRect);
}
// sixten: Make sure the tooltip is not overlapping.
{
@ -557,23 +595,23 @@ static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas
if(Box->Flags & UI_BoxFlag_DrawBackground)
{
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Box->BackgroundColor, Box->CornerRadius, 0, 0);
PushQuad(Group, Box->Rect, Box->BackgroundColor, Box->CornerRadius, 0, 0);
}
if(Box->Flags & UI_BoxFlag_HotAnimation)
{
v4 Top = V4(1, 1, 1, 0.06F*Box->HotTransition);
v4 Top = V4(1, 1, 1, 0.08F*Box->HotTransition);
v4 Bottom = V4(1, 1, 1, 0.0);
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
PushQuad(Group, Box->Rect, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
}
if(Box->Flags & UI_BoxFlag_ActiveAnimation)
{
v4 Top = V4(0, 0, 0, 0.5F*Box->ActiveTransition);
v4 Top = V4(0, 0, 0, 0.7F*Box->ActiveTransition);
v4 Bottom = V4(0, 0, 0, 0.1F*Box->ActiveTransition);
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
PushQuad(Group, Box->Rect, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
}
if(Box->Flags & UI_BoxFlag_DrawText)
@ -599,7 +637,7 @@ static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas
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 = V4R32(R, G, B, 1);
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8);
PushQuad(Group, Box->Rect, Red, Red, Red, Red, 0, 1.8, 1.8);
}
#endif
@ -619,9 +657,12 @@ static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas
v2 P = Child->Rect.Min - V2(ShadowRadius, ShadowRadius);
v2 Dim = Child->ComputedDim + V2(ShadowRadius, ShadowRadius)*2;
range2_r32 Rect = Range2R32(Box->Rect.Min - V2R32(ShadowRadius, ShadowRadius),
Box->Rect.Min + V2R32(ShadowRadius, ShadowRadius));
v4 ShadowColor = V4(0, 0, 0, 0.7);
PushQuad(Group, P, Dim, ShadowColor, 0, ShadowRadius, 0);
PushQuad(Group, Rect, ShadowColor, 0, ShadowRadius, 0);
}
}
@ -639,7 +680,7 @@ static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas
if(Box->Flags & UI_BoxFlag_DrawBorder)
{
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Box->BorderColor, Box->CornerRadius, 0.8, Box->BorderThickness);
PushQuad(Group, Box->Rect, Box->BorderColor, Box->CornerRadius, 0.8, Box->BorderThickness);
}
}
@ -673,7 +714,13 @@ static r32 UI_CalculateBoxSize(ui_box *Box, axis2 Axis)
{
if(Parent && Parent->SemanticSize[Axis].Type != UI_SizeType_ChildrenSum)
{
Result = Parent->ComputedDim.E[Axis]*Box->SemanticSize[Axis].Value;
r32 Size = Parent->ComputedDim.E[Axis];
// sixten: if the size is zero, try to find it.
if(Size == 0.0)
{
Size = DimOfRange(Parent->Rect).E[Axis];
}
Result = Size*Box->SemanticSize[Axis].Value;
}
else
{
@ -743,6 +790,12 @@ static void UI_LayoutBox(ui_box *Box)
}
}
static void UI_Init(ui *UI)
{
UI->Arena = ArenaAllocate(Gigabytes(1));
UI->FrameArena = ArenaAllocate(Gigabytes(1));
}
static void UI_BeginBuild(v2 ScreenDim)
{
ui *UI = UI_GetState();
@ -837,12 +890,7 @@ static void UI_NewFrame(ui *UI, platform_event_list *EventList, v2 MouseP, glyph
{
UI_SetState(UI);
if(UI->FrameMemory.Arena)
{
EndTemporaryMemory(UI->FrameMemory);
}
UI->FrameMemory = BeginTemporaryMemory(&UI->FrameArena);
ArenaClear(UI->FrameArena);
UI->EventList = EventList;
UI->MouseP = MouseP;

View File

@ -52,10 +52,12 @@ enum
UI_BoxFlag_OverflowY = (1 << 9),
UI_BoxFlag_FloatingX = (1 << 10),
UI_BoxFlag_FloatingY = (1 << 11),
UI_BoxFlag_Scrollable = (1 << 12),
};
typedef u32 ui_box_flags;
typedef void ui_draw_callback(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data);
#define UI_CUSTOM_DRAW_CALLBACK(name) void name(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data)
typedef UI_CUSTOM_DRAW_CALLBACK(ui_custom_draw_callback);
struct ui_box
{
@ -86,7 +88,7 @@ struct ui_box
r32 FontSize;
v2 Offset;
ui_draw_callback *DrawCallback;
ui_custom_draw_callback *DrawCallback;
void *DrawCallbackData;
v2 ComputedRelativeP;
@ -109,6 +111,7 @@ struct ui_signal
ui_box *Box;
v2 MouseP;
v2 DragDelta;
v2 Scroll;
b8 Clicked;
b8 Pressed;
b8 PressedRight;
@ -117,13 +120,12 @@ struct ui_signal
b8 Dragging;
};
#include "generated/vn_generated_ui.h"
#include "generated/vn_ui.meta.h"
struct ui
{
memory_arena Arena;
memory_arena FrameArena;
temporary_memory FrameMemory;
memory_arena *Arena;
memory_arena *FrameArena;
ui_box *FirstFreeBox;
ui_box *LastFreeBox;
@ -158,6 +160,10 @@ inline ui *UI_GetState(void);
inline ui_key UI_GetHot(void);
inline ui_key UI_GetActive(void);
inline platform_event_list *UI_EventList(void);
inline v2 UI_MouseP(void);
inline glyph_atlas *UI_GlyphAtlas(void);
//- sixten: Drag helpers
inline void UI_SetDragStartP(v2 P);
inline void UI_UpdateDragStartP(void);
@ -186,6 +192,7 @@ static ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...);
static ui_signal UI_SignalFromBox(ui_box *Box);
//- sixten: Building and rendering
static void UI_Init(ui *UI);
static void UI_BeginBuild(ui *UI, v2 ScreenDim);
static void UI_EndBuild(void);
static void UI_RenderFrame(render_group *RenderGroup);

46
code/vn_ui.md 100644
View File

@ -0,0 +1,46 @@
@table(Name, Type, BoxName)
UIStyleStacks:
{
{ Parent `ui_box *` `Parent` }
{ Width `ui_size` `SemanticSize[Axis2_X]` }
{ Height `ui_size` `SemanticSize[Axis2_Y]` }
{ FixedX `r32` `FixedP.E[Axis2_X]` }
{ FixedY `r32` `FixedP.E[Axis2_Y]` }
{ TextColor `v4` `TextColor` }
{ BackgroundColor `v4` `BackgroundColor` }
{ BorderColor `v4` `BorderColor` }
{ BorderThickness `r32` `BorderThickness` }
{ LayoutAxis `axis2` `LayoutAxis` }
{ CornerRadius `r32` `CornerRadius` }
{ Font `font_id` `Font` }
{ FontSize `r32` `FontSize` }
{ OffsetX `r32` `Offset.x` }
{ OffsetY `r32` `Offset.y` }
}
@table_gen
{
`struct ui_style_stacks`;
`{`;
@expand(UIStyleStacks s) `$(s.Type) $(s.Name)Stack[64]; s32 $(s.Name)StackUsed; b32 AutoPop$(s.Name);`;
`};`;
}
@c @table_gen
{
@expand(UIStyleStacks s) `inline void UI_Push$(s.Name)($(s.Type) Element) $(=>50) { ui *UI = UI_GetState(); Assert(UI->Stacks.$(s.Name)StackUsed $(=>125) + 1 < ArrayCount(UI->Stacks.$(s.Name)Stack)); $(=>180) UI->Stacks.$(s.Name)Stack[UI->Stacks.$(s.Name)StackUsed++] $(=>260) = Element; }`;
@expand(UIStyleStacks s) `inline void UI_Pop$(s.Name)(void) $(=>50) { ui *UI = UI_GetState(); Assert(UI->Stacks.$(s.Name)StackUsed $(=>125) > 0); $(=>180) --UI->Stacks.$(s.Name)StackUsed; $(=>271) }`;
@expand(UIStyleStacks s) `inline void UI_SetNext$(s.Name)($(s.Type) Element) { ui *UI = UI_GetState(); UI_Push$(s.Name)(Element); UI->Stacks.AutoPop$(s.Name) = true; }`;
@expand(UIStyleStacks s) `inline $(s.Type) UI_First$(s.Name)(void) { ui *UI = UI_GetState(); return(UI->Stacks.$(s.Name)Stack[0]); }`;
@expand(UIStyleStacks s) `inline $(s.Type) UI_Top$(s.Name)(void) { ui *UI = UI_GetState(); return(UI->Stacks.$(s.Name)Stack[UI->Stacks.$(s.Name)StackUsed - 1]); }`;
@expand(UIStyleStacks s) `#define UI_$(s.Name)(Element) DeferLoop(UI_Push$(s.Name)(Element), UI_Pop$(s.Name)())`
}
@c @table_gen
{
`static void UI_ApplyStyles(ui_box *Box)`;
`{`;
`ui *UI = UI_GetState();`;
@expand(UIStyleStacks s) `Assert(UI->Stacks.$(s.Name)StackUsed > 0); $(=>50) Box->$(s.BoxName) $(=>75) = UI->Stacks.$(s.Name)Stack[UI->Stacks.$(s.Name)StackUsed - 1]; $(=>160) if(UI->Stacks.AutoPop$(s.Name)) $(=>200) { UI_Pop$(s.Name)(); $(=>230) UI->Stacks.AutoPop$(s.Name) = false; $(=>260) }`
`}`;
}

View File

@ -223,13 +223,6 @@ static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
return(Signal);
}
/*
Goal for next week: Be able to make basic dialog trees.
Goal for tomorrow: Scrollable regions and basic text editing (with line wrapping).
*/
static void UI_ScrollBegin(r32 *X, r32 *Y, string Name)
{
u32 Flags = 0;
@ -270,6 +263,7 @@ static void UI_ScrollEnd(r32 *X, r32 *Y)
b32 AllowOnY = (Y != 0);
ui_box *ScrollableBox = UI_TopParent();
ui_signal ScrollableBoxSignal = UI_SignalFromBox(ScrollableBox);
{
{
UI_PopParent();

View File

@ -1,12 +1,28 @@
#include "vn_workspace_view.cpp"
#include "vn_workspace_editor.cpp"
#include "vn_workspace_text_editor.cpp"
#include "vn_workspace_commands.cpp"
//- sixten: State management
per_thread workspace *ThreadLocal_Workspace;
static void Workspace_SetState(workspace *Workspace)
{
ThreadLocal_Workspace = Workspace;
}
static workspace *Workspace_GetState(void)
{
return(ThreadLocal_Workspace);
}
//- sixten: Commands
static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *Sig, u64 Argument = 0)
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
{
workspace_command *Result = 0;
workspace *Workspace = Workspace_GetState();
if(Workspace->FirstFreeCommand)
{
Result = Workspace->FirstFreeCommand;
@ -15,7 +31,7 @@ static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *
if(!Result)
{
Result = PushStruct(&Workspace->CommandArena, workspace_command);
Result = PushStruct(Workspace->CommandArena, workspace_command);
}
Result->Command = Sig;
@ -23,12 +39,14 @@ static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *
DLLInsertLast(Workspace->FirstCommand, Workspace->LastCommand, Result);
}
static void Workspace_ProcessCommands(workspace *Workspace)
static void Workspace_ProcessCommands(void)
{
workspace *Workspace = Workspace_GetState();
workspace_command *Command = Workspace->FirstCommand;
while(Command != 0)
{
Command->Command(Workspace, Command->Argument);
Command->Command(Command->Argument);
workspace_command *ToRemove = Command;
Command = Command->Next;
@ -39,8 +57,10 @@ static void Workspace_ProcessCommands(workspace *Workspace)
}
}
static void Workspace_ProcessKeyBinds(workspace *Workspace)
static void Workspace_ProcessKeyBinds()
{
workspace *Workspace = Workspace_GetState();
platform_event_list *EventList = Workspace->EventList;
for(platform_event *Event = EventList->First;
@ -56,7 +76,7 @@ static void Workspace_ProcessKeyBinds(workspace *Workspace)
workspace_keybind *Keybind = Workspace->Keybinds + KeybindIndex;
if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers))
{
Workspace_IssueCommand(Workspace, Keybind->Command, Keybind->Argument);
Workspace_IssueCommand(Keybind->Command, Keybind->Argument);
}
}
}
@ -65,8 +85,10 @@ static void Workspace_ProcessKeyBinds(workspace *Workspace)
//- sixten: Builder code
static ui_signal Workspace_BuildToolbarButton(workspace *Workspace, char *Text, toolbar_menu Menu)
static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu)
{
workspace *Workspace = Workspace_GetState();
UI_SetNextWidth(UI_TextContent(20, 1));
UI_SetNextHeight(UI_Pixels(30, 1));
UI_SetNextCornerRadius(4);
@ -136,8 +158,10 @@ static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
return(Signal);
}
static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
static void Workspace_BuildToolbar()
{
workspace *Workspace = Workspace_GetState();
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHeight(UI_Pixels(30, 1));
UI_SetNextBackgroundColor(Theme_BackgroundColor);
@ -147,9 +171,9 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
UI_Parent(ToolbarBox)
{
Workspace_BuildToolbarButton(Workspace, "Panel", ToolbarMenu_Panel);
Workspace_BuildToolbarButton(Workspace, "View", ToolbarMenu_View);
Workspace_BuildToolbarButton(Workspace, "Window", ToolbarMenu_Window);
Workspace_BuildToolbarButton("Panel", ToolbarMenu_Panel);
Workspace_BuildToolbarButton("View", ToolbarMenu_View);
Workspace_BuildToolbarButton("Window", ToolbarMenu_Window);
}
if(Workspace->Menu != ToolbarMenu_None)
@ -179,13 +203,12 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
{
if(Workspace_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
{
Workspace_IssueCommand(Workspace, Workspace_Command_SplitPanelHorizontal);
Workspace_IssueCommand(Workspace_Command_SplitPanelHorizontal);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
{
Workspace_IssueCommand(Workspace, Workspace_Command_SplitPanelVertical);
Workspace_IssueCommand(Workspace_Command_SplitPanelVertical);
Workspace->Menu = ToolbarMenu_None;
}
}
@ -193,28 +216,28 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
{
workspace_panel *CurrentPanel = Workspace->CurrentPanel;
// sixten(TODO): The views should be created at the end of the frame i.e. this should be done via
// commmands instead. (since we want all things that deals with major state changes to occur at a fixed
// point in our programs execution)
if(Workspace_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_Startup, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_None, "Editor", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_Editor, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_None, "Command Palette", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_CommandPalette, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_Settings, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
}
@ -239,13 +262,15 @@ static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
}
//- sixten: Panels
static workspace_panel *Workspace_CreateNewPanel(workspace *Workspace, workspace_panel *Parent)
static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent)
{
workspace_panel *Result = 0;
workspace *Workspace = Workspace_GetState();
if(DLLIsEmpty(Workspace->FirstFreePanel))
{
Result = PushStruct(&Workspace->PanelArena, workspace_panel);
Result = PushStruct(Workspace->PanelArena, workspace_panel);
}
else
{
@ -260,8 +285,10 @@ static workspace_panel *Workspace_CreateNewPanel(workspace *Workspace, workspace
return(Result);
}
static void Workspace_DeletePanel(workspace *Workspace, workspace_panel *Panel)
static void Workspace_DeletePanel(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
if(Workspace->CurrentPanel == Panel)
{
Workspace->CurrentPanel = 0;
@ -271,22 +298,24 @@ static void Workspace_DeletePanel(workspace *Workspace, workspace_panel *Panel)
DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel);
}
static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, axis2 Axis)
static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
{
workspace *Workspace = Workspace_GetState();
if(Panel)
{
workspace_panel *Parent = Panel->Parent;
if(Parent && (Parent->SplitAxis == Axis))
{
workspace_panel *NewPanel = Workspace_CreateNewPanel(Workspace, Parent);
workspace_panel *NewPanel = Workspace_CreateNewPanel(Parent);
NewPanel->PercentOfParent = Panel->PercentOfParent = Panel->PercentOfParent * 0.5;
DLLInsert_NP(Parent->First, Parent->Last, Panel, NewPanel, Next, Prev);
}
else
{
workspace_panel *NewPanel = Workspace_CreateNewPanel(Workspace, Panel);
workspace_panel *NewPanel = Workspace_CreateNewPanel(Panel);
NewPanel->FirstView = Panel->FirstView;
NewPanel->LastView = Panel->LastView;
@ -302,7 +331,7 @@ static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, a
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
NewPanel = Workspace_CreateNewPanel(Workspace, Panel);
NewPanel = Workspace_CreateNewPanel(Panel);
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
@ -319,8 +348,10 @@ static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, a
}
}
inline void Workspace_BeginDrag(workspace *Workspace, workspace_drag_payload *Payload)
inline void Workspace_BeginDrag(workspace_drag_payload *Payload)
{
workspace *Workspace = Workspace_GetState();
// sixten(TODO): Right now, if you spam-click a draggable item, you can trigger this
// assertion. I don't know what I want to do about this at the moment, but I'm sure
// future me will have a soulution at hand. ^.^
@ -330,15 +361,19 @@ inline void Workspace_BeginDrag(workspace *Workspace, workspace_drag_payload *Pa
Workspace->DragPayloadState = Workspace_DragPayload_Active;
}
inline b32 Workspace_GetDragPayload(workspace *Workspace, workspace_drag_payload *Dest)
inline b32 Workspace_GetDragPayload(workspace_drag_payload *Dest)
{
workspace *Workspace = Workspace_GetState();
b32 Result = (Workspace->DragPayloadState != Workspace_DragPayload_Inactive);
*Dest = Workspace->DragPayload;
return(Result);
}
static void Workspace_BuildTabItem(workspace *Workspace, workspace_panel *Panel, workspace_view *View)
static void Workspace_BuildTabItem(workspace_panel *Panel, workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
b32 ViewIsCurrent = (Panel->CurrentView == View);
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
@ -396,6 +431,7 @@ static void Workspace_BuildTabItem(workspace *Workspace, workspace_panel *Panel,
Panel->CurrentView = View;
}
// sixten: Handle dragging the view.
if(Signal.Dragging)
{
if(Signal.Pressed)
@ -404,13 +440,15 @@ static void Workspace_BuildTabItem(workspace *Workspace, workspace_panel *Panel,
Payload.View = View;
Payload.Key = TabBox->Key;
Workspace_BeginDrag(Workspace, &Payload);
Workspace_BeginDrag(&Payload);
}
}
}
static void Workspace_BuildPanelHeader(workspace *Workspace, workspace_panel *Panel)
static void Workspace_BuildPanelHeader(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
UI_SetNextCornerRadius(0);
@ -422,14 +460,14 @@ static void Workspace_BuildPanelHeader(workspace *Workspace, workspace_panel *Pa
View != 0;
View = View->Next)
{
Workspace_BuildTabItem(Workspace, Panel, View);
Workspace_BuildTabItem(Panel, View);
}
UI_Spacer(UI_Percent(1, 0));
// sixten: Panel Close Button
if(Panel != Workspace->RootPanel)
{
UI_Spacer(UI_Percent(1, 0));
UI_SetNextSize(UI_Pixels(30, 1), UI_Pixels(30, 1));
UI_SetNextFont(Font_Icons);
UI_SetNextBorderColor(ColorFromHex(0xA6514288));
@ -447,7 +485,7 @@ static void Workspace_BuildPanelHeader(workspace *Workspace, workspace_panel *Pa
ui_signal Signal = UI_SignalFromBox(CloseBox);
if(Signal.Clicked)
{
Workspace_IssueCommand(Workspace, Workspace_Command_ClosePanel, PointerToU64(Panel));
Workspace_IssueCommand(Workspace_Command_ClosePanel, PointerToU64(Panel));
}
}
@ -455,8 +493,10 @@ static void Workspace_BuildPanelHeader(workspace *Workspace, workspace_panel *Pa
}
}
static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
static void Workspace_BuildPanel(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
// sixten: Fill remaining percent of parent.
workspace_panel *Parent = Panel->Parent;
if(Parent && Panel != Parent->First)
@ -480,7 +520,7 @@ static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
{
if(DLLIsEmpty(Panel->First))
{
Workspace_BuildPanelHeader(Workspace, Panel);
Workspace_BuildPanelHeader(Panel);
// sixten: Main body
{
@ -522,7 +562,7 @@ static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
{
ui_key CurrentActive = UI_GetActive();
Workspace_BuildView(Workspace, Panel->CurrentView);
Workspace_BuildView(Panel->CurrentView);
if(!AreEqual(CurrentActive, UI_GetActive()))
{
@ -533,7 +573,7 @@ static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
// sixten: Draw dragged view overlay.
{
workspace_drag_payload Payload;
b32 DragActive = Workspace_GetDragPayload(Workspace, &Payload);
b32 DragActive = Workspace_GetDragPayload(&Payload);
b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) &&
InRange(BodyBox->Rect, UI_GetState()->MouseP));
@ -630,8 +670,9 @@ static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
{
UI_SetNextAxisSize(Panel->SplitAxis, UI_Percent(Child->PercentOfParent*SizeScalar, 0));
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
Workspace_BuildPanel(Workspace, Child);
Workspace_BuildPanel(Child);
// sixten: Create drag area
if(Child->Next)
{
UI_SetNextAxisSize(Panel->SplitAxis, UI_Pixels(PaddingSize, 1));
@ -667,10 +708,13 @@ static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
}
}
static void Workspace_BuildDragPayload(workspace *Workspace, vn_input *Input)
static void Workspace_BuildDragPayload()
{
workspace *Workspace = Workspace_GetState();
vn_input *Input = Workspace->Input;
workspace_drag_payload Payload;
if(Workspace_GetDragPayload(Workspace, &Payload))
if(Workspace_GetDragPayload(&Payload))
{
if(Workspace->DragPayloadState == Workspace_DragPayload_Released)
{
@ -709,15 +753,28 @@ static void Workspace_BuildDragPayload(workspace *Workspace, vn_input *Input)
//- sixten: Workspace
static void Workspace_Init(workspace *Workspace)
{
Workspace->RootPanel = Workspace->CurrentPanel = Workspace_CreateNewPanel(Workspace, 0);
Workspace_SetState(Workspace);
Workspace->CommandArena = ArenaAllocate(Gigabytes(1));
Workspace->PanelArena = ArenaAllocate(Gigabytes(1));
Workspace->RootPanel = Workspace->CurrentPanel = Workspace_CreateNewPanel(0);
if(DEBUG_DebugSettings->ShowWelcomeMessage)
{
Workspace_CreateNewView(Workspace_View_Startup, Workspace->RootPanel);
}
Workspace_CreateNewView(Workspace_View_TextEditor, Workspace->RootPanel);
// sixten: Setup keybinds
{
#define BIND_COMMAND(...) Workspace->Keybinds[Workspace->KeybindCount++] = {__VA_ARGS__}
BIND_COMMAND(Key_P, PlatformModifier_Ctrl, Workspace_Command_SplitPanelHorizontal);
BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical);
#if VN_INTERNAL
BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects);
#endif
#undef BIND_COMMAND
}
}
@ -725,13 +782,12 @@ static void Workspace_Init(workspace *Workspace)
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
vn_input *Input, glyph_atlas *GlyphAtlas)
{
Workspace_SetState(Workspace);
Workspace->Input = Input;
Workspace->EventList = Input->EventList;
// sixten: Process last frame's commands.
Workspace_ProcessKeyBinds(Workspace);
Workspace_ProcessCommands(Workspace);
// sixten: Make sure that a view/panel is always selected.
if(!Workspace->CurrentPanel)
{
Workspace->CurrentPanel = Workspace->RootPanel;
@ -743,12 +799,16 @@ static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCom
// sixten: Build the UI.
{
Workspace_BuildToolbar(Workspace, Input->dtForFrame);
Workspace_BuildToolbar();
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
Workspace_BuildPanel(Workspace, Workspace->RootPanel);
Workspace_BuildPanel(Workspace->RootPanel);
Workspace_BuildDragPayload(Workspace, Input);
Workspace_BuildDragPayload();
}
// sixten: Process the keybinds and commands.
Workspace_ProcessKeyBinds();
Workspace_ProcessCommands();
}

View File

@ -4,6 +4,7 @@
#define VN_WORKSPACE_H
#include "vn_workspace_editor.h"
#include "vn_workspace_text_editor.h"
// sixten(TODO): Remove this type entirely.
enum toolbar_menu
@ -33,7 +34,7 @@ struct workspace_panel
#include "vn_workspace_view.h"
#define WORKSPACE_COMMAND(name, ...) void name(workspace *Workspace, u64 Argument)
#define WORKSPACE_COMMAND(name, ...) void name(u64 Argument)
typedef WORKSPACE_COMMAND(workspace_command_sig);
struct workspace_command
@ -72,7 +73,7 @@ struct workspace
platform_event_list *EventList;
// sixten: Command Allocation
memory_arena CommandArena;
memory_arena *CommandArena;
workspace_command *FirstFreeCommand;
workspace_command *LastFreeCommand;
@ -85,7 +86,7 @@ struct workspace
s32 KeybindCount;
// sixten: Panels
memory_arena PanelArena;
memory_arena *PanelArena;
workspace_panel *FirstFreePanel;
workspace_panel *LastFreePanel;
@ -100,19 +101,23 @@ struct workspace
workspace_panel *CurrentPanel;
};
//- sixten: State management
static void Workspace_SetState(workspace *Workspace);
static workspace *Workspace_GetState(void);
//- sixten: Commands
static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *Sig, u64 Argument);
static void Workspace_ProcessCommands(workspace *Workspace);
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument);
static void Workspace_ProcessCommands(void);
//- sixten: Panels
static workspace_panel *Workspace_CreateNewPanel(workspace *Workspace, workspace_panel *Parent);
static void Workspace_DeletePanel(workspace *Workspace, workspace_panel *Panel);
static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, axis2 Axis);
static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent);
static void Workspace_DeletePanel(workspace_panel *Panel);
static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis);
//- sixten: Builder code
static ui_signal Workspace_BuildToolbarButton(workspace *Workspace, char *Text, toolbar_menu Menu);
static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu);
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut);
static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame);
static void Workspace_BuildToolbar(r32 dtForFrame);
//- sixten: Workspace
static void Workspace_Init(workspace *Workspace);

View File

@ -1,15 +1,19 @@
WORKSPACE_COMMAND(Workspace_Command_SplitPanelHorizontal)
{
Workspace_SplitPanel(Workspace, Workspace->CurrentPanel, Axis2_X);
workspace *Workspace = Workspace_GetState();
Workspace_SplitPanel(Workspace->CurrentPanel, Axis2_X);
}
WORKSPACE_COMMAND(Workspace_Command_SplitPanelVertical)
{
Workspace_SplitPanel(Workspace, Workspace->CurrentPanel, Axis2_Y);
workspace *Workspace = Workspace_GetState();
Workspace_SplitPanel(Workspace->CurrentPanel, Axis2_Y);
}
WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
{
workspace *Workspace = Workspace_GetState();
workspace_panel *Panel = (workspace_panel *)Argument;
if(!Panel)
{
@ -50,7 +54,7 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
}
DLLRemove(Parent->First, Parent->Last, Child);
Workspace_DeletePanel(Workspace, Child);
Workspace_DeletePanel(Child);
}
else
{
@ -79,5 +83,12 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
//Workspace_DeleteView(Child);
}
Workspace_DeletePanel(Workspace, Panel);
Workspace_DeletePanel(Panel);
}
#if VN_INTERNAL
WORKSPACE_COMMAND(Workspace_Command_ToggleRenderUIDebugRects)
{
DEBUG_DebugSettings->RenderUIDebugRects = !DEBUG_DebugSettings->RenderUIDebugRects;
}
#endif

View File

@ -9,7 +9,7 @@ static workspace_editor_node *Workspace_GetNewEditorNode(workspace_view *View)
if(DLLIsEmpty(Editor->FirstFreeNode))
{
Result = PushStruct(&View->Arena, workspace_editor_node);
Result = PushStruct(View->Arena, workspace_editor_node);
}
else
{
@ -63,6 +63,126 @@ inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel)
//- sixten: Builder code
static void Workspace_BuildEditorListerDropdown(workspace_editor_lister_dropdown *ListerDropdown)
{
b32 ActiveInDropdown = false;
UI_PushBackgroundColor(SetAlpha(Color_Black, 0.3));
UI_PushBorderColor(SetAlpha(Color_Black, 0.7));
r32 HeightTransition = AnimationCurve_AnimateValueF(1, 0, 0.3, "Editor Lister Dropdown %p", ListerDropdown);
UI_SetNextSize(UI_Em(15, 1), UI_Em(25*HeightTransition, 1));
UI_SetNextCornerRadius(4.0);
UI_SetNextFixedP(ListerDropdown->P);
UI_SetNextLayoutAxis(Axis2_Y);
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawBackground |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY |
UI_BoxFlag_Clickable |
UI_BoxFlag_Clip,
StrLit("Editor Lister Dropdown"));
UI_Parent(Box)
{
UI_BorderColor(SetAlpha(Color_Grey, 0.7))
UI_Row() UI_Column()
{
UI_Size(UI_TextContent(15, 1), UI_TextContent(12, 1)) UI_LabelF("Create new node");
// sixten: Build search bar
UI_SetNextWidth(UI_Percent(1, 1));
UI_SetNextHeight(UI_Em(2, 1));
UI_SetNextCornerRadius(4.0);
UI_SetNextLayoutAxis(Axis2_X);
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, StrLit("Editor Lister Field")))
{
UI_Spacer(UI_Em(0.8, 1));
UI_Width(UI_TextContent(1, 1)) UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Filter);
UI_Width(UI_Percent(1, 0))
{
UI_MakeBox(0, StrLit(""));
}
}
struct lister_option
{
char *Text;
u32 Icons;
};
lister_option Options[] =
{
{"Text", FontIcon_Pencil},
{"Branch", FontIcon_Menu},
};
for(s32 OptionIndex = 0;
OptionIndex < ArrayCount(Options);
++OptionIndex)
{
lister_option *Option = Options + OptionIndex;
UI_SetNextSize(UI_Percent(1, 1), UI_Em(2, 1));
UI_SetNextLayoutAxis(Axis2_X);
ui_box *ClickableBox = UI_MakeBoxF(UI_BoxFlag_Clickable, "Editor Lister %s", Option->Text);
ui_signal Signal = UI_SignalFromBox(ClickableBox);
if(AreEqual(UI_GetActive(), ClickableBox->Key))
{
ActiveInDropdown = true;
}
UI_Parent(ClickableBox)
UI_Height(UI_Percent(1, 1))
{
b32 IsHot = AreEqual(UI_GetHot(), ClickableBox->Key);
r32 TargetHot = IsHot*0.8;
UI_SetNextCornerRadius(3.0);
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
UI_SetNextBackgroundColor(SetAlpha(Theme_HighlightBorderColor,
AnimationCurve_AnimateValueF(TargetHot, TargetHot, 0.1, "Editor Lister %s%p",
Option->Text, ListerDropdown)));
UI_SetNextLayoutAxis(Axis2_X);
ui_box *HighlightBox = UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit(""));
UI_Parent(HighlightBox)
UI_Padding(UI_Em(0.8, 1))
{
UI_Width(UI_TextContent(0, 1))
UI_Font(Font_Icons) UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Option->Icons);
UI_Spacer(UI_Em(0.6, 1));
UI_Width(UI_TextContent(0, 1)) UI_MakeBoxF(UI_BoxFlag_DrawText, "%s", Option->Text);
if(Signal.Clicked)
{
// sixten(TODO): Issue the requested command.
ListerDropdown->Open = false;
}
}
}
}
}
ui_signal Signal = UI_SignalFromBox(Box);
if(AreEqual(UI_GetActive(), Box->Key))
{
ActiveInDropdown = true;
}
}
UI_PopBackgroundColor();
UI_PopBorderColor();
if(!ActiveInDropdown && !AreEqual(UI_GetActive(), UI_EmptyKey()))
{
ListerDropdown->Open = false;
}
}
static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data)
{
workspace_view_editor *Editor = (workspace_view_editor *)Data;
@ -79,7 +199,9 @@ static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas
++LineIndex)
{
r32 OffsetX = Workspace_WorldToView(Editor->Offset.x, Scale, Dim.x, LineIndex - (s32)Editor->Offset.x);
PushQuad(Group, Box->Rect.Min + V2(OffsetX, 0), V2(1.5, Dim.y), LineColor, 0, 1.2, 0);
v2 Min = Box->Rect.Min + V2(OffsetX, 0);
v2 Max = Min + V2(1.5, Dim.y);
PushQuad(Group, Range2R32(Min, Max), LineColor, 0, 1.2, 0);
}
s32 HorizontalLineCount = Dim.y / Scale + 4;
@ -88,18 +210,21 @@ static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas
++LineIndex)
{
r32 OffsetY = Workspace_WorldToView(Editor->Offset.y, Scale, Dim.y, LineIndex - (s32)Editor->Offset.y);
v2 Min = Box->Rect.Min + V2(0, OffsetY);
v2 Max = Min + V2(Dim.x, 1.5);
PushQuad(Group, Box->Rect.Min + V2(0, OffsetY), V2(Dim.x, 1.5), LineColor, 0, 1.2, 0);
PushQuad(Group, Range2R32(Min, Max), LineColor, 0, 1.2, 0);
}
}
static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
static void Workspace_BuildEditor(workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
// sixten(TODO): These should be able to have a strictness of 1, but they can't. Fix that.
UI_SetNextWidth(UI_Percent(1, 0));
UI_SetNextHeight(UI_Percent(1, 0));
UI_SetNextWidth(UI_Percent(1, 1));
UI_SetNextHeight(UI_Percent(1, 1));
ui_box *EditorBox = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "Workspace Editor %p", View);
EditorBox->DrawCallback = Workspace_EditorDrawCallback;
@ -110,6 +235,8 @@ static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
v2 EditorDim = DimOfRange(EditorBox->Rect);
UI_Parent(EditorBox)
{
// sixten: Build the node boxes.
for(workspace_editor_node *Node = Editor->FirstNode;
Node != 0;
@ -132,8 +259,8 @@ static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
UI_Parent(Node->Box)
{
UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Color_Black, 0.3));
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(20, 1));
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextSize(UI_Percent(1, 1), UI_Em(1.8, 1));
Node->TitleBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawBorder |
UI_BoxFlag_Clickable,
@ -141,11 +268,24 @@ static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
UI_Parent(Node->TitleBox)
{
UI_Width(UI_TextContent(7, 0)) UI_Font(Font_Bold) UI_LabelF("Node");
UI_Spacer(UI_Em(0.5, 1));
UI_Width(UI_TextContent(0, 1)) UI_Font(Font_Bold) UI_LabelF("Node");
UI_Spacer(UI_Percent(1, 0));
UI_SetNextSize(UI_Em(1.8, 1), UI_Percent(1, 1));
UI_SetNextFont(Font_Icons);
Node->CloseBox = UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
}
}
}
if(Editor->ListerDropdown.Open)
{
Workspace_BuildEditorListerDropdown(&Editor->ListerDropdown);
}
}
// sixten: Get input from boxes.
{
workspace_editor_node *Next = 0;
@ -176,10 +316,6 @@ static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
}
}
// sixten: Process the movement of the node.
{
}
// sixten: Process panning and zooming of the editor.
ui_signal Signal = UI_SignalFromBox(EditorBox);
{
@ -227,6 +363,16 @@ static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
// sixten: Process shortcuts.
if(Platform_KeyPress(Workspace->EventList, Key_Space, PlatformModifier_Ctrl))
{
Workspace_GetNewEditorNode(View);
workspace_editor_lister_dropdown *ListerDropdown = &Editor->ListerDropdown;
if(ListerDropdown->Open)
{
ListerDropdown->Open = false;
}
else if(InRange(EditorBox->Rect, UI_GetState()->MouseP))
{
ListerDropdown->Open = true;
ListerDropdown->P = UI_GetState()->MouseP - EditorBox->Rect.Min;
}
}
}

View File

@ -6,15 +6,16 @@
/* sixten(NOTE): Node types
*
* Text(String, opt. Character) -> Node
* Menu(Strings[0..n]) -> Nodes[0..n]
* Branch(Strings[0..n]) -> Nodes[0..n]
*
*/
enum workspace_editor_node_type
{
Workspace_EditorNode_None,
Workspace_EditorNode_Start,
Workspace_EditorNode_Text,
Workspace_EditorNode_Menu,
Workspace_EditorNode_Branch,
};
struct workspace_editor_node
@ -26,10 +27,23 @@ struct workspace_editor_node
ui_box *Box;
ui_box *TitleBox;
ui_box *CloseBox;
v2 P;
};
struct workspace_editor_lister_dropdown
{
// sixten: Input field
char InputField[128];
s32 InputFieldUsed;
b32 InputFieldSelected;
// sixten: Properties
b32 Open;
v2 P;
};
//- sixten: Managing nodes
static workspace_editor_node *Workspace_GetNewEditorNode(struct workspace_view *View);
@ -38,8 +52,12 @@ inline v2 Workspace_ViewToWorld(v2 Offset, r32 Scale, v2 Dim, v2 P);
inline v2 Workspace_WorldToView(v2 Offset, r32 Scale, v2 Dim, v2 P);
inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel);
//- sixten: Lister dropdown
static void Workspace_OpenListerDropdown(v2 MouseP);
//- sixten: Builder code
static void Workspace_BuildEditorListerDropdown(workspace_editor_lister_dropdown *ListerDropdown);
static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
static void Workspace_BuildEditor(struct workspace *Workspace, struct workspace_view *View);
static void Workspace_BuildEditor(struct workspace_view *View);
#endif //VN_WORKSPACE_EDITOR_H

View File

@ -0,0 +1,362 @@
////////////////////////////////
//~ sixten: Mutable String Functions
static mutable_string MutableStringAllocate(u64 Size)
{
mutable_string Result = {};
Result.Arena = ArenaAllocate(Size);
ArenaSetAlign(Result.Arena, 1);
Result.String = MakeString(PushArray(Result.Arena, u8, 1), 0);
return(Result);
}
static void MutableStringRelease(mutable_string *String)
{
ArenaRelease(String->Arena);
}
static void MutableStringReplaceRange(mutable_string *MutString, string ReplaceString, range1_s64 Range)
{
Range = Intersection(Range, Range1S64(0, MutString->String.Count));
s64 NewCount = MutString->String.Count+ReplaceString.Count-DimOfRange(Range);
if(NewCount > MutString->String.Count)
{
s64 ToAllocate = NewCount-MutString->String.Count;
PushArray(MutString->Arena, u8, ToAllocate);
}
Move(MutString->String.Data+Range.Min+ReplaceString.Count, MutString->String.Data+Range.Max, MutString->String.Count-DimOfRange(Range));
Copy(MutString->String.Data+Range.Min, ReplaceString.Data, ReplaceString.Count);
MutString->String.Count = NewCount;
}
////////////////////////////////
//~ sixten: Workspace Text Editor Functions
static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *Arena, string Text)
{
temporary_memory Scratch = GetScratch(&Arena, 1);
//- sixten: tokenize the text
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, StrLit("*scratch*"), Text);
token_array Tokens = TokenizeResult.Tokens;
//- sixten: gather all line ranges
range1_s64_list Lines = {};
{
u8 *TextBegin = Text.Data;
u8 *TextEnd = TextBegin + Text.Count;
range1_s64 Range = Range1S64(0, 0);
for(u8 *Char = TextBegin; Char <= TextEnd; Char += 1)
{
Range.Max += 1;
//- sixten: push line range on newline and EOF
if(Char == TextEnd || *Char == '\n')
{
Range1S64ListPush(Scratch.Arena, &Lines, Range);
Range = Range1S64(Range.Max, Range.Max);
}
}
}
//- sixten: fill & return
workspace_text_data Result = {};
{
Result.Tokens = Tokens;
Result.Lines = Range1S64ArrayFromList(Arena, &Lines);;
}
ReleaseScratch(Scratch);
return(Result);
}
static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
{
temporary_memory Scratch = GetScratch();
workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data;
//- sixten: get dimensions & scroll offset from container
ui_box *ContainerBox = Editor->ContainerBox;
range2_r32 ParentRect = ContainerBox->Rect;
v2 ParentDim = DimOfRange(ParentRect);
v2 Offset = Box->Parent->Offset;
//- sixten: rendering properties
r32 FontSize = 16.0f;
r32 LineHeight = FontSize + 4.0f;
//- sixten: calculate the dimensions of the glyphs
glyph *Glyph = GetGlyph(Atlas, Font_Monospace, 'A', FontSize, 0);
r32 GlyphAdvance = Glyph->Advance;
//- sixten: find the text point
text_point CursorTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor);
text_point MarkTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Mark);
//- sixten: get the line count
range1_s64_array *Lines = &Editor->Lines;
s64 LineCount = Lines->Count;
//- sixten: calculate the text dim
Editor->TextDim = V2(1900, LineCount*LineHeight);
//- sixten: calculate the line margin dim
s32 LineMarginDigitsRequired = 6;
v2_r32 LineMarginDim = V2((LineMarginDigitsRequired)*GlyphAdvance, ParentRect.Max.y - ParentRect.Min.y);
//- sixten: tokenize text
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, StrLit("nobody cares"), Editor->Text.String);
token_array Tokens = TokenizeResult.Tokens;
token *TokensBegin = Tokens.Tokens;
token *TokensEnd = TokensBegin + Tokens.Count;
//- sixten: find the first visible token
token *VisibleTokensBegin = TokensBegin;
s64 TopMostLine = Min((s64)Floor(-Offset.y / LineHeight), LineCount);
for(s64 LinesFound = 0; LinesFound < TopMostLine && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1)
{
if(VisibleTokensBegin->Flags & TokenFlag_Newline)
{
LinesFound += 1;
}
}
//- sixten: find the last visible token
token *VisibleTokensEnd = VisibleTokensBegin;
s64 LinesOnScreen = Min((s64)Floor(ParentDim.y / LineHeight)+1, LineCount-TopMostLine);
for(s64 LinesFound = 0; LinesFound < LinesOnScreen && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1)
{
if(VisibleTokensEnd->Flags & TokenFlag_Newline)
{
LinesFound += 1;
}
}
//- sixten: draw line numbers & line highlights
{
//- sixten: draw the background
v4 LineMarginColor = ColorFromHex(0x10203080);
range2_r32 LineMarginBox = Range2R32(ParentRect.Min, ParentRect.Min+LineMarginDim);
PushQuad(Group, LineMarginBox, LineMarginColor, LineMarginColor, LineMarginColor, LineMarginColor, 0, 0, 0);
//- sixten: draw the numbers
v2_r32 LineOffset = Box->Rect.Min;
for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1)
{
r32 LineY = LineOffset.y + LineIndex*LineHeight;
PushTextF(Group, Atlas, Font_Monospace, V2(0, LineY), FontSize, Color_Grey, "%*.i", LineMarginDigitsRequired, LineIndex+1);
if(LineIndex + 1 == CursorTextP.Line)
{
v4_r32 LineHighlightColor = ColorFromHex(0x10204080);
range2_r32 LineHighlightBox = Range2R32(V2(LineMarginBox.Max.x, LineY), V2(Box->Rect.Max.x, LineY+LineHeight));
PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 0, 0, 0);
}
}
}
//- sixten: render tokens
v2 BaseTokenP = Box->Rect.Min+V2(LineMarginDim.x, TopMostLine*LineHeight);
v2 TokenP = BaseTokenP;
for(token *Token = VisibleTokensBegin; Token < VisibleTokensEnd; Token += 1)
{
string TokenString = T_StringFromToken(Editor->Text.String, *Token);
//- sixten: get color from token
v4 Color = Color_Magenta;
if(Token->Flags & TokenGroup_Comment) { Color = Color_Grey; }
else if(Token->Flags & TokenFlag_Reserved) { Color = Color_Grey; }
else if(Token->Flags & TokenFlag_Symbol) { Color = ColorFromHex(0xbd2d2dff); }
else if(Token->Flags & TokenFlag_StringLiteral) { Color = ColorFromHex(0xffa900ff); }
else if(Token->Flags & TokenFlag_Numeric) { Color = ColorFromHex(0xffa900ff); }
else if(Token->Flags & TokenFlag_Identifier)
{
//- sixten: check for keywords
if(AreEqual(TokenString, StrLit("var")) ||
AreEqual(TokenString, StrLit("proc")) ||
AreEqual(TokenString, StrLit("branch")) ||
AreEqual(TokenString, StrLit("jump")) ||
AreEqual(TokenString, StrLit("if")) ||
AreEqual(TokenString, StrLit("true")) ||
AreEqual(TokenString, StrLit("false")))
{
Color = ColorFromHex(0xf0c674ff);
}
else
{
Color = Theme_TextColor;
}
}
//- sixten: render & advance by token
if(!(Token->Flags & TokenGroup_Whitespace))
{
TokenP.x += PushText(Group, Atlas, Font_Monospace, TokenP, FontSize, Color, TokenString);
}
else
{
if(Token->Flags & TokenFlag_Newline)
{
TokenP.x = BaseTokenP.x;
TokenP.y += LineHeight;
}
else
{
u8 *StringBegin = TokenString.Data;
u8 *StringEnd = StringBegin + TokenString.Count;
for(u8 *Char = StringBegin; Char < StringEnd; Char += 1)
{
if(*Char == ' ' || *Char == '\t')
{
TokenP.x += GlyphAdvance;
}
}
}
}
}
//- sixten: render cursor
{
v2 TargetCursorP = Box->Rect.Min+V2(LineMarginDim.x+(CursorTextP.Column-1)*GlyphAdvance,(CursorTextP.Line-1)*LineHeight);
v2 CursorP = V2(AnimationCurve_AnimateValueF(TargetCursorP.x, TargetCursorP.x, 0.1, "Workspace Text Editor Cursor X %p", Editor),
AnimationCurve_AnimateValueF(TargetCursorP.y, TargetCursorP.y, 0.1, "Workspace Text Editor Cursor Y %p", Editor));
v2 CursorDim = V2(2, LineHeight);
range2_r32 CursorRect = Range2R32(CursorP, CursorP+CursorDim);
v4 CursorColor = ColorFromHex(0x10FF20FF);
PushQuad(Group, CursorRect, CursorColor, CursorColor, CursorColor, CursorColor, 2, 0.4, 0);
}
//- sixten: render the selection
{
text_range Selection = TextRange(CursorTextP, MarkTextP);
range1_s64 LineRange = Range1S64(Selection.Min.Line, Selection.Max.Line);
for(s64 Line = TopMostLine; Line < TopMostLine + LinesOnScreen; Line += 1)
{
r32 LineY = Box->Rect.Min.y + Line*LineHeight;
if(Contains(LineRange, Line + 1))
{
range1_s64 ColumnRange = Lines->Ranges[Line];
range1_s64 NormalizedColumnRange = Range1S64(0, DimOfRange(ColumnRange));
if(Line + 1 == LineRange.Min && Line + 1 == LineRange.Max)
{
NormalizedColumnRange = Range1S64(Editor->EditState.Cursor - ColumnRange.Min, Editor->EditState.Mark - ColumnRange.Min);
}
else if(Line + 1 == LineRange.Min)
{
NormalizedColumnRange = Range1S64(Min(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min, DimOfRange(ColumnRange));
}
else if(Line + 1 == LineRange.Max)
{
NormalizedColumnRange = Range1S64(0, Max(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min);
}
v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C);
range2_r32 LineHighlightBox = Range2R32(V2(LineMarginDim.x+NormalizedColumnRange.Min*GlyphAdvance, LineY),
V2(LineMarginDim.x+NormalizedColumnRange.Max*GlyphAdvance, LineY+LineHeight));
PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0);
}
}
}
ReleaseScratch(Scratch);
}
static void Workspace_BuildTextEditor(workspace_view *View)
{
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
temporary_memory Scratch = GetScratch();
//- sixten: rendering properties
r32 FontSize = 16.0f;
r32 LineHeight = FontSize + 4.0f;
//- sixten: calculate the dimensions of the glyphs
glyph *Glyph = GetGlyph(UI_GlyphAtlas(), Font_Monospace, 'A', FontSize, 0);
r32 GlyphAdvance = Glyph->Advance;
//- sixten: calculate the line margin dim
s32 LineMarginDigitsRequired = 6;
r32 LineMarginWidth = (LineMarginDigitsRequired)*GlyphAdvance;
ui_box *EditorBox = 0;
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
UI_Scroll(0, &Editor->Offset.y)
{
//- sixten: find the container box for the scrollable region
Editor->ContainerBox = UI_TopParent()->Parent->Parent;
UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1));
EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View);
EditorBox->DrawCallback = Workspace_TextEditorDrawCallback;
EditorBox->DrawCallbackData = Editor;
}
b32 CursorHasBeenModified = false;
//- sixten: keyboard input -> text op plus handling
if(Workspace_ViewIsCurrent(View))
{
for(platform_event *Event = UI_EventList()->First;
Event != 0;
Event = Event->Next)
{
if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text)
{
text_action Action = MultiLineTextActionFromEvent(Event);
if(IsValid(&Action))
{
text_op Op = TextOpFromAction(Scratch.Arena, Editor->Text.String, &Editor->EditState, &Action, &Editor->Lines, Editor->LastTextPoint.Column - 1);
CursorHasBeenModified = true;
{
MutableStringReplaceRange(&Editor->Text, Op.ReplaceString, Op.Range);
ArenaClear(Editor->ProcessingArena);
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
Editor->Tokens = TextData.Tokens;
Editor->Lines = TextData.Lines;
}
Editor->EditState.Cursor = Op.NewCursor;
Editor->EditState.Mark = Op.NewMark;
}
}
}
}
ui_signal Signal = UI_SignalFromBox(EditorBox);
if(Signal.Dragging)
{
if(Signal.Pressed)
{
//- sixten: translate mouse position to text point
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0);
text_point Point = {(s64)(MouseOffset.y / LineHeight) + 1, (s64)(MouseOffset.x / GlyphAdvance) + 1};
Editor->EditState.Cursor = Editor->EditState.Mark = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
}
//- sixten: translate mouse position to text point
v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0);
text_point Point = {(s64)(MouseOffset.y / LineHeight) + 1, (s64)(MouseOffset.x / GlyphAdvance) + 1};
Editor->EditState.Cursor = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point);
CursorHasBeenModified = true;
}
//- sixten: update eventual text point extents
if(CursorHasBeenModified)
{
text_point Point = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor);
if(Editor->LastTextPoint.Line == Point.Line)
{
Editor->LastTextPoint = Point;
}
else
{
Editor->LastTextPoint.Line = Point.Line;
Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column);
}
}
ReleaseScratch(Scratch);
}

View File

@ -0,0 +1,73 @@
/* date = July 11th 2023 0:34 pm */
#ifndef VN_WORKSPACE_TEXT_EDITOR_H
#define VN_WORKSPACE_TEXT_EDITOR_H
////////////////////////////////
//~ sixten: Mutable String Types
struct mutable_string
{
memory_arena *Arena;
string String;
};
struct history_node
{
range1_s64 Range;
string ReplaceString;
history_node *Next;
};
struct history_list
{
memory_arena *HistoryArena;
history_node *First;
history_node *Last;
};
////////////////////////////////
//~ sixten: Workspace Text Editor Types
struct workspace_text_data
{
token_array Tokens;
range1_s64_array Lines;
};
struct workspace_view_text_editor
{
//- sixten: processed text
memory_arena *ProcessingArena;
token_array Tokens;
range1_s64_array Lines;
//- sixten: text being edited
mutable_string Text;
//- sixten: text editing
text_edit_state EditState;
text_point LastTextPoint;
//- sixten: ui building & rendering
ui_box *ContainerBox;
v2 TextDim;
v2 Offset;
};
////////////////////////////////
//~ sixten: Mutable String Functions
static mutable_string MutableStringAllocate(u64 Size);
static void MutableStringRelease(mutable_string *String);
static void MutableStringReplaceRange(mutable_string *String, string ReplaceString, range1_s64 Range);
////////////////////////////////
//~ sixten: Workspace Text Editor Functions
static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *Arena, string Text);
static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback);
static void Workspace_BuildTextEditor(workspace_view *View);
#endif //VN_WORKSPACE_TEXT_EDITOR_H

View File

@ -1,18 +1,27 @@
//- sixten: Views
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent)
{
workspace_view *View = BootstrapPushStruct(workspace_view, Arena);
memory_arena *Arena = ArenaAllocate(Gigabytes(1));
workspace_view *View = PushStruct(Arena, workspace_view);
View->Arena = Arena;
View->Type = Type;
View->Parent = Parent;
switch(View->Type)
{
case Workspace_View_Editor:
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_editor)); } break;
{ View->Data = PushStruct(View->Arena, workspace_view_editor); } break;
case Workspace_View_CommandPalette:
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_command_palette)); } break;
{ View->Data = PushStruct(View->Arena, workspace_view_command_palette); } break;
case Workspace_View_Settings:
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_settings)); } break;
{ View->Data = PushStruct(View->Arena, workspace_view_settings); } break;
case Workspace_View_TextEditor:
{
View->Data = PushStruct(View->Arena, workspace_view_text_editor);
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
Editor->ProcessingArena = ArenaAllocate(Gigabytes(1));
Editor->Text = MutableStringAllocate(Gigabytes(2));
} break;
}
DLLInsertLast(Parent->FirstView, Parent->LastView, View);
@ -28,11 +37,13 @@ inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspa
inline void Workspace_DestroyView(workspace_view *View)
{
// sixten(NOTE): This function does not ensure that the view is not being used anywhere else.
Release(&View->Arena);
ArenaRelease(View->Arena);
}
inline b32 Workspace_ViewIsCurrent(workspace *Workspace, workspace_view *View)
inline b32 Workspace_ViewIsCurrent(workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
b32 Result = (Workspace->CurrentPanel && Workspace->CurrentPanel->CurrentView == View);
return(Result);
}
@ -82,7 +93,7 @@ static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *
v2 P = Box->Rect.Min + Offset;
v4 Color = V4(0.4, 0.7, 0.8, 0.3);
PushQuad(Group, P, Dim, Color, 0, 0, 0);
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
}
// sixten: Draw cursor
@ -95,14 +106,16 @@ static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *
v2 P = Box->Rect.Min + Offset;
v4 Color = V4(0.3, 1, 0.3, 0.7);
PushQuad(Group, P, Dim, Color, 0, 0, 0);
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
}
}
static void Workspace_BuildViewTypeLister(workspace *Workspace, workspace_view *View)
static void Workspace_BuildViewTypeLister(workspace_view *View)
{
workspace_view_command_palette *CommandPalette = (workspace_view_command_palette *)View->Data;
workspace *Workspace = Workspace_GetState();
temporary_memory Scratch = GetScratch(0, 0);
UI_Size(UI_Percent(1, 1), UI_Percent(1, 1))
@ -333,10 +346,12 @@ static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *
return(Result);
}
static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View)
static void Workspace_BuildSettings(workspace_view *View)
{
workspace_view_settings *Settings = (workspace_view_settings *)View->Data;
workspace *Workspace = Workspace_GetState();
UI_Height(UI_ChildrenSum(1, 1))
UI_Column() UI_Padding(UI_Pixels(50, 0))
UI_Row() UI_Padding(UI_Pixels(50, 0))
@ -447,10 +462,10 @@ static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View)
UI_Spacer(UI_Pixels(50, 1));
}
static void Workspace_BuildView(workspace *Workspace, workspace_view *View)
static void Workspace_BuildView(workspace_view *View)
{
r32 ViewHighlightTransition =
AnimationCurve_AnimateValueF(Workspace_ViewIsCurrent(Workspace, View), 0, 0.25, "Workspace View Highlight %p", View);
AnimationCurve_AnimateValueF(Workspace_ViewIsCurrent(View), 0, 0.25, "Workspace View Highlight %p", View);
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, ViewHighlightTransition));
UI_PushBackgroundColor(Theme_BackgroundColor);
UI_SetNextCornerRadius(3);
@ -474,20 +489,28 @@ static void Workspace_BuildView(workspace *Workspace, workspace_view *View)
UI_Font(Font_Bold) UI_FontSize(36)
UI_LabelF("Welcome to VN");
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
UI_Spacer(UI_Percent(1, 0));
UI_Checkbox(&DEBUG_DebugSettings->ShowWelcomeMessage, StrLit("Show this message on startup"));
}
}
}
else if(View->Type == Workspace_View_CommandPalette)
{
Workspace_BuildViewTypeLister(Workspace, View);
Workspace_BuildViewTypeLister(View);
}
else if(View->Type == Workspace_View_Editor)
{
Workspace_BuildEditor(Workspace, View);
Workspace_BuildEditor(View);
}
else if(View->Type == Workspace_View_Settings)
{
Workspace_BuildSettings(Workspace, View);
Workspace_BuildSettings(View);
}
else if(View->Type == Workspace_View_TextEditor)
{
Workspace_BuildTextEditor(View);
}
}

View File

@ -5,7 +5,7 @@
struct workspace_view
{
memory_arena Arena;
memory_arena *Arena;
enum workspace_view_type Type;
workspace_panel *Parent;
@ -21,6 +21,7 @@ enum workspace_view_type
Workspace_View_Editor,
Workspace_View_CommandPalette,
Workspace_View_Settings,
Workspace_View_TextEditor,
};
struct workspace_view_editor
@ -32,6 +33,8 @@ struct workspace_view_editor
workspace_editor_node *LastNode;
workspace_editor_node *FirstFreeNode;
workspace_editor_node *LastFreeNode;
workspace_editor_lister_dropdown ListerDropdown;
};
struct workspace_view_command_palette
@ -64,12 +67,12 @@ struct workspace_view_settings
//- sixten: Views
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent);
inline void Workspace_DestroyView(workspace_view *View);
inline b32 Workspace_ViewIsCurrent(workspace *Workspace, workspace_view *View);
inline b32 Workspace_ViewIsCurrent(workspace_view *View);
inline string Workspace_GetViewName(workspace_view *View);
//- sixten: Builder code
static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
static void Workspace_BuildViewTypeLister(workspace *Workspace, workspace_view *View);
static void Workspace_BuildView(workspace *Workspace, workspace_view *View);
static void Workspace_BuildViewTypeLister(workspace_view *View);
static void Workspace_BuildView(workspace_view *View);
#endif //VN_WORKSPACE_VIEW_H

Binary file not shown.

View File

@ -45,48 +45,36 @@ static PLATFORM_SHOW_MESSAGE(Win32_ShowMessage)
}
}
static PLATFORM_ALLOCATE_MEMORY(Win32_AllocateMemory)
static u64 Win32_GetPageSize(void)
{
win32_state *State = &Global_Win32State;
SYSTEM_INFO Info;
GetSystemInfo(&Info);
return(Info.dwPageSize);
}
umm TotalSize = Size + sizeof(win32_memory_block);
win32_memory_block *Block =
(win32_memory_block *)VirtualAlloc(0, TotalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
Assert(Block);
Block->Block.Base = (u8 *)Block + sizeof(win32_memory_block);
Block->Block.Size = Size;
win32_memory_block *Sentinel = &State->MemorySentinel;
Block->Next = Sentinel;
BeginTicketMutex(&State->MemoryMutex);
Block->Prev = Sentinel->Prev;
Block->Prev->Next = Block;
Block->Next->Prev = Block;
EndTicketMutex(&State->MemoryMutex);
platform_memory_block *Result = &Block->Block;
static PLATFORM_RESERVE(Win32_Reserve)
{
u64 GigabyteAlignedSize = Size+Gigabytes(1)-1;
GigabyteAlignedSize -= GigabyteAlignedSize%Gigabytes(1);
void *Result = VirtualAlloc(0, GigabyteAlignedSize, MEM_RESERVE, PAGE_NOACCESS);
return(Result);
}
static PLATFORM_DEALLOCATE_MEMORY(Win32_DeallocateMemory)
static PLATFORM_RELEASE(Win32_Release)
{
win32_state *State = &Global_Win32State;
win32_memory_block *Win32Block = (win32_memory_block *)Block;
if(Block)
{
BeginTicketMutex(&State->MemoryMutex);
Win32Block->Prev->Next = Win32Block->Next;
Win32Block->Next->Prev = Win32Block->Prev;
EndTicketMutex(&State->MemoryMutex);
VirtualFree(Pointer, 0, MEM_RELEASE);
}
BOOL Result = VirtualFree(Block, 0, MEM_RELEASE);
return(Result);
static PLATFORM_COMMIT(Win32_Commit)
{
u64 PageAlignedSize = Size+Win32_GetPageSize()-1;
PageAlignedSize -= PageAlignedSize%Win32_GetPageSize();
VirtualAlloc(Pointer, PageAlignedSize, MEM_COMMIT, PAGE_READWRITE);
}
static PLATFORM_DECOMMIT(Win32_Decommit)
{
VirtualFree(Pointer, Size, MEM_DECOMMIT);
}
static PLATFORM_OPEN_FILE(Win32_OpenFile)
@ -257,6 +245,9 @@ static void Win32_UpdateCode(win32_loaded_code *Code)
{
Win32_UnloadCode(Code);
*Code = Win32_LoadCode();
// sixten(NOTE): Sometimes the program decides to crash upon reloads, so we just wait for those to be over...
Sleep(200);
}
}
@ -271,7 +262,7 @@ static PLATFORM_TOGGLE_FULLSCREEN(Win32_ToggleFullscreen)
if(GetWindowPlacement(Window, &Global_WindowPosition) &&
GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo))
{
// sixten: This doesn't work when the window is maximized. One wordaround would be to set the
// sixten(NOTE): This doesn't work when the window is maximized. One wordaround would be to set the
// window to "normal" size using ShowWindow(Window, SW_SHOWNORMAL) but it looks *very* scuffed.
SetWindowLong(Window, GWL_STYLE, Style & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(Window, HWND_TOP,
@ -346,7 +337,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
{
case WM_CLOSE:
{
Event = PushStruct(&State->EventArena, platform_event);
Event = PushStruct(State->EventArena, platform_event);
Event->Type = PlatformEvent_WindowClose;
} break;
@ -391,7 +382,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
} fallthrough;
case WM_MOUSEWHEEL:
{
Event = PushStruct(&State->EventArena, platform_event);
Event = PushStruct(State->EventArena, platform_event);
Event->Type = PlatformEvent_MouseScroll;
Event->Scroll.E[ScrollAxis] = GET_WHEEL_DELTA_WPARAM(WParam) / 120.0;
} break;
@ -417,7 +408,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
case WM_RBUTTONUP: case WM_RBUTTONDOWN: { Key = Key_MouseRight; } break;
}
Event = PushStruct(&State->EventArena, platform_event);
Event = PushStruct(State->EventArena, platform_event);
Event->Type = Type;
Event->Key = Key;
Event->P = Win32_GetMouseP(Window);
@ -458,7 +449,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
if(Key != Key_Invalid)
{
Event = PushStruct(&State->EventArena, platform_event);
Event = PushStruct(State->EventArena, platform_event);
Event->Type = Type;
Event->Key = Key;
}
@ -484,7 +475,7 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP
if((Codepoint >= 32 && Codepoint != 127) || Codepoint == '\t' || Codepoint == '\n')
{
Event = PushStruct(&State->EventArena, platform_event);
Event = PushStruct(State->EventArena, platform_event);
Event->Type = PlatformEvent_Text;
Event->Codepoint = Codepoint;
}
@ -551,7 +542,7 @@ static void Win32_ProcessInput(vn_input *Input, HWND Window, r32 dtForFrame)
EndTemporaryMemory(State->EventArenaTemp);
}
State->EventArenaTemp = BeginTemporaryMemory(&State->EventArena);
State->EventArenaTemp = BeginTemporaryMemory(State->EventArena);
}
MSG Message;
@ -634,7 +625,9 @@ inline void Win32_GetRelevantPaths(win32_state *State)
int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, int ShowCommand)
{
thread_context ThreadContext = {};
RegisterPlatformFunctions(Win32);
thread_context ThreadContext = AllocateThreadContext();
SetThreadContext(&ThreadContext);
// sixten: Setup Win32 platform state.
@ -646,26 +639,11 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
QueryPerformanceFrequency(&FrequencyQuery);
State->PerformanceFrequency = FrequencyQuery.QuadPart;
State->MemorySentinel.Next = &State->MemorySentinel;
State->MemorySentinel.Prev = &State->MemorySentinel;
State->EventArena = ArenaAllocate(Gigabytes(1));
State->SleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR);
}
// sixten: Setup platform layer
{
Platform.AllocateMemory = Win32_AllocateMemory;
Platform.DeallocateMemory = Win32_DeallocateMemory;
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 = {};
WindowClass.lpszClassName = "vn-window-class";
WindowClass.lpfnWndProc = Win32_WindowCallback;
@ -676,7 +654,7 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
{
HWND Window = CreateWindowEx(0,
WindowClass.lpszClassName,
"vn - June 2023 Build",
"vn - July 2023 Build",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,

View File

@ -3,27 +3,14 @@
#ifndef WIN32_MAIN_H
#define WIN32_MAIN_H
struct win32_memory_block
{
platform_memory_block Block;
win32_memory_block *Next;
win32_memory_block *Prev;
u64 Padding[2];
};
CTAssert(sizeof(win32_memory_block) == 64);
struct win32_state
{
win32_memory_block MemorySentinel;
ticket_mutex MemoryMutex;
u64 PerformanceFrequency;
b32 SleepIsGranular;
HWND Window;
memory_arena EventArena;
memory_arena *EventArena;
temporary_memory EventArenaTemp;
platform_event_list EventList;

View File

@ -7,5 +7,6 @@ Dev
{
RenderUIDebugRects = false;
RenderFPSCounter = false;
ListHotAndActive = true;
ListHotAndActive = false;
ShowWelcomeMessage = false;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,22 @@
RULES
-Credit "Noraneko Games"
-For games: credit can be given in the in-game credits, in a note accompanying the game, or on a website where the project is downloaded. Any one of those is fine. It doesn't have to be all of them.
-For Art: Credit must accompany the picture where it is posted or on the image itself.
-For Vtubing/video: Credit can be given in the description or in a panel of your streaming platform or on the video itself. Any of those are fine.
-If this pack is re-uploaded to another site for download as is, do not remove this text file or any part of it.
-These assets cannot be sold as is. For merchandising options, contact me and we can discuss options.
-Modifications are allowed. (Change colors, add blood splatters, draw characters in the image, etc)
-Using for 18+ is fine as long as it doesn't contain illegal themes/content (such as homophobia, racism, threats to real people, or pedophilia) that could reflect poorly on the Noraneko Games name and reputation.
-Commercial use in a game is ok if you can provide proof of credit if I contact you for it and it follows all other rules. Contact me for commercial use outside of games.
-If you aren't making money from your project, you can use without contacting me if you'd prefer.
-Using this asset for Game Jams and Contests is okay!
-If you want to use this media for anything other than a game, make sure it follows the rules above.
Find more of my work at:
@NoranekoGames on Twitter
Noranekokgames.itch.io
Not required, but I would love for you to link me to your project!
Good luck with your project!

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

41
data/test.vns 100644
View File

@ -0,0 +1,41 @@
// This just experiments with the scripting language
var times = 0
proc "Start"
{
"so, I actually changed my mind."
"the editor will not be node based"
"I realised that it would just be slower to write dialog that way soooo..."
"instead, I present to you the.........."
"vn scene - scripting language"
"btw something happens if you go through this dialog 10 times"
times += 1
branch
{
"Return to start"
{
jump "Start"
}
if(times >= 10)
{
"SUPER EPIC SECRET"
{
jump "Epic Scene"
}
}
}
}
proc "Epic Scene"
{
"woah... so epic"
@s "oh, right. almost forgot to mention that you can talk as different characters."
@s "you know... "
wait
@s #noclear "the usual"
}

Binary file not shown.