Completed Nav Editor.
|
@ -1,45 +0,0 @@
|
||||||
UI_Column()
|
|
||||||
{
|
|
||||||
UI_Spacer(UI_Em(1, 1));
|
|
||||||
UI_Height(UI_Em(1, 1)) UI_Row()
|
|
||||||
{
|
|
||||||
UI_Width(UI_TextContent(15, 1)) UI_LabelF("Scrollbar T:");
|
|
||||||
|
|
||||||
UI_SetNextWidth(UI_Em(20, 1));
|
|
||||||
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
|
||||||
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Scrollable");
|
|
||||||
UI_Parent(Container)
|
|
||||||
{
|
|
||||||
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
|
||||||
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
|
||||||
UI_SetNextFixedX((DimOfRange(Container->Rect).x-UI_TopFontSize())*ScrollbarT);
|
|
||||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground|
|
|
||||||
UI_BoxFlag_DrawBorder|
|
|
||||||
UI_BoxFlag_HotAnimation|
|
|
||||||
UI_BoxFlag_ActiveAnimation|
|
|
||||||
UI_BoxFlag_Clickable|
|
|
||||||
UI_BoxFlag_FloatingX|
|
|
||||||
0, "Dragable");
|
|
||||||
ui_signal Signal = UI_SignalFromBox(Box);
|
|
||||||
if(Signal.Dragging)
|
|
||||||
{
|
|
||||||
if(Signal.Pressed)
|
|
||||||
{
|
|
||||||
UI_StoreDragR32(ScrollbarT);
|
|
||||||
}
|
|
||||||
|
|
||||||
r32 StartT = UI_GetDragR32();
|
|
||||||
r32 EndT = StartT + Signal.DragDelta.x/(DimOfRange(Container->Rect).x-UI_TopFontSize());
|
|
||||||
ScrollbarT = Clamp01(EndT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UI_Width(UI_TextContent(30, 1)) UI_Height(UI_Em(2, 1))
|
|
||||||
{
|
|
||||||
if(UI_ButtonF("Reset Dialog").Pressed)
|
|
||||||
{
|
|
||||||
Time = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -162,8 +162,7 @@ IsNull(p) ? (SetNull((n)->prev), (n)->next = (f), (IsNull(f) ? (0) : ((f)->prev
|
||||||
#define DLLIsEmpty(First) ((First) == 0)
|
#define DLLIsEmpty(First) ((First) == 0)
|
||||||
|
|
||||||
#define SenDLLInit(Sentinel)\
|
#define SenDLLInit(Sentinel)\
|
||||||
(Sentinel)->Next = (Sentinel);\
|
do { (Sentinel)->Next = (Sentinel); (Sentinel)->Prev = (Sentinel); } while(0)
|
||||||
(Sentinel)->Prev = (Sentinel);
|
|
||||||
|
|
||||||
#define SenDLLInsertFirst(Sentinel, Element)\
|
#define SenDLLInsertFirst(Sentinel, Element)\
|
||||||
(Element)->Next = (Sentinel)->Next;\
|
(Element)->Next = (Sentinel)->Next;\
|
||||||
|
@ -199,42 +198,42 @@ auto __Temp = (Element)->Next->Prev;\
|
||||||
|
|
||||||
inline u64 AtomicExchangeU64(u64 volatile *Value, u64 New)
|
inline u64 AtomicExchangeU64(u64 volatile *Value, u64 New)
|
||||||
{
|
{
|
||||||
u64 Result = _InterlockedExchange64((__int64 volatile *)Value, New);
|
u64 Result = _InterlockedExchange64((__int64 volatile *)Value, New);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u64 AtomicAddU64(u64 volatile *Value, u64 Addend)
|
inline u64 AtomicAddU64(u64 volatile *Value, u64 Addend)
|
||||||
{
|
{
|
||||||
u64 Result = _InterlockedExchangeAdd64((__int64 volatile *)Value, Addend);
|
u64 Result = _InterlockedExchangeAdd64((__int64 volatile *)Value, Addend);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sixten: Memory mutexes
|
// sixten: Memory mutexes
|
||||||
|
|
||||||
struct ticket_mutex
|
struct ticket_mutex
|
||||||
{
|
{
|
||||||
u64 volatile Ticket;
|
u64 volatile Ticket;
|
||||||
u64 volatile Serving;
|
u64 volatile Serving;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void BeginTicketMutex(ticket_mutex *Mutex)
|
inline void BeginTicketMutex(ticket_mutex *Mutex)
|
||||||
{
|
{
|
||||||
u64 Ticket = AtomicAddU64(&Mutex->Ticket, 1);
|
u64 Ticket = AtomicAddU64(&Mutex->Ticket, 1);
|
||||||
while(Ticket != Mutex->Serving) { _mm_pause(); }
|
while(Ticket != Mutex->Serving) { _mm_pause(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void EndTicketMutex(ticket_mutex *Mutex)
|
inline void EndTicketMutex(ticket_mutex *Mutex)
|
||||||
{
|
{
|
||||||
AtomicAddU64(&Mutex->Serving, 1);
|
AtomicAddU64(&Mutex->Serving, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//- sixten: Axes
|
//- sixten: Axes
|
||||||
enum axis2
|
enum axis2
|
||||||
{
|
{
|
||||||
Axis2_X = 0,
|
Axis2_X = 0,
|
||||||
Axis2_Y = 1,
|
Axis2_Y = 1,
|
||||||
Axis2_Count
|
Axis2_Count
|
||||||
};
|
};
|
||||||
|
|
||||||
inline axis2 Opposite(axis2 Axis) { axis2 Result = (axis2)(!(u32)Axis); return(Result); }
|
inline axis2 Opposite(axis2 Axis) { axis2 Result = (axis2)(!(u32)Axis); return(Result); }
|
||||||
|
@ -243,11 +242,11 @@ inline axis2 Opposite(axis2 Axis) { axis2 Result = (axis2)(!(u32)Axis); return(R
|
||||||
//- sixten: Corners
|
//- sixten: Corners
|
||||||
enum corner
|
enum corner
|
||||||
{
|
{
|
||||||
Corner_00 = 0,
|
Corner_00 = 0,
|
||||||
Corner_10 = (1 << Axis2_X),
|
Corner_10 = (1 << Axis2_X),
|
||||||
Corner_01 = (1 << Axis2_Y),
|
Corner_01 = (1 << Axis2_Y),
|
||||||
Corner_11 = (1 << Axis2_X)|(1 << Axis2_Y),
|
Corner_11 = (1 << Axis2_X)|(1 << Axis2_Y),
|
||||||
Corner_Count,
|
Corner_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CORE_H
|
#endif //CORE_H
|
||||||
|
|
|
@ -3,43 +3,43 @@
|
||||||
|
|
||||||
static void Copy(void *Dest, void *Source, umm Count)
|
static void Copy(void *Dest, void *Source, umm Count)
|
||||||
{
|
{
|
||||||
if(Count <= S32_Max)
|
if(Count <= S32_Max)
|
||||||
{
|
{
|
||||||
u8 *Dest8 = (u8 *)Dest;
|
u8 *Dest8 = (u8 *)Dest;
|
||||||
u8 *Source8 = (u8 *)Source;
|
u8 *Source8 = (u8 *)Source;
|
||||||
|
|
||||||
while(Count--)
|
while(Count--)
|
||||||
{
|
{
|
||||||
*Dest8++ = *Source8++;
|
*Dest8++ = *Source8++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyReverse(void *Dest, void *Source, umm Count)
|
static void CopyReverse(void *Dest, void *Source, umm Count)
|
||||||
{
|
{
|
||||||
if(Count <= S32_Max)
|
if(Count <= S32_Max)
|
||||||
{
|
{
|
||||||
u8 *Dest8 = (u8 *)Dest + Count;
|
u8 *Dest8 = (u8 *)Dest + Count;
|
||||||
u8 *Source8 = (u8 *)Source + Count;
|
u8 *Source8 = (u8 *)Source + Count;
|
||||||
|
|
||||||
while(Count--)
|
while(Count--)
|
||||||
{
|
{
|
||||||
*--Dest8 = *--Source8;
|
*--Dest8 = *--Source8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Fill(void *Dest, u8 Value, umm Count)
|
static void Fill(void *Dest, u8 Value, umm Count)
|
||||||
{
|
{
|
||||||
if(Count <= S32_Max)
|
if(Count <= S32_Max)
|
||||||
{
|
{
|
||||||
u8 *Dest8 = (u8 *)Dest;
|
u8 *Dest8 = (u8 *)Dest;
|
||||||
|
|
||||||
while(Count--)
|
while(Count--)
|
||||||
{
|
{
|
||||||
*Dest8++ = Value;
|
*Dest8++ = Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
|
@ -51,199 +51,199 @@ static void Fill(void *Dest, u8 Value, umm Count)
|
||||||
|
|
||||||
static arena *ArenaAlloc(u64 Size, b32 Chaining)
|
static arena *ArenaAlloc(u64 Size, b32 Chaining)
|
||||||
{
|
{
|
||||||
arena *Arena = 0;
|
arena *Arena = 0;
|
||||||
if(Chaining)
|
if(Chaining)
|
||||||
{
|
{
|
||||||
void *Memory = Platform.Allocate(Size);
|
void *Memory = Platform.Allocate(Size);
|
||||||
Arena = (arena *)Memory;
|
Arena = (arena *)Memory;
|
||||||
|
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
ASAN_POISON_MEMORY_REGION(Arena, Size);
|
ASAN_POISON_MEMORY_REGION(Arena, Size);
|
||||||
ASAN_UNPOISON_MEMORY_REGION(Arena, sizeof(arena));
|
ASAN_UNPOISON_MEMORY_REGION(Arena, sizeof(arena));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Arena->Chaining = true;
|
Arena->Chaining = true;
|
||||||
SenDLLInit(Arena);
|
SenDLLInit(Arena);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u64 RoundedSize = Size+Megabytes(64)-1;
|
u64 RoundedSize = Size+Megabytes(64)-1;
|
||||||
RoundedSize -= RoundedSize&Megabytes(64);
|
RoundedSize -= RoundedSize&Megabytes(64);
|
||||||
void *Memory = Platform.Reserve(RoundedSize);
|
void *Memory = Platform.Reserve(RoundedSize);
|
||||||
u64 InitialCommitSize = MEMORY_ARENA_COMMIT_SIZE;
|
u64 InitialCommitSize = MEMORY_ARENA_COMMIT_SIZE;
|
||||||
Platform.Commit(Memory, InitialCommitSize);
|
Platform.Commit(Memory, InitialCommitSize);
|
||||||
Arena = (arena *)Memory;
|
Arena = (arena *)Memory;
|
||||||
}
|
}
|
||||||
Arena->Position = sizeof(arena);
|
Arena->Position = sizeof(arena);
|
||||||
Arena->Size = Size;
|
Arena->Size = Size;
|
||||||
Arena->Align = 8;
|
Arena->Align = 8;
|
||||||
return(Arena);
|
return(Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArenaRelease(arena *Arena)
|
static void ArenaRelease(arena *Arena)
|
||||||
{
|
{
|
||||||
if(Arena->Chaining)
|
if(Arena->Chaining)
|
||||||
{
|
{
|
||||||
arena *Node = Arena->Prev;
|
arena *Node = Arena->Prev;
|
||||||
for(;Node != Arena;)
|
for(;Node != Arena;)
|
||||||
{
|
{
|
||||||
arena *Next = Node->Prev;
|
arena *Next = Node->Prev;
|
||||||
Platform.Deallocate(Node);
|
Platform.Deallocate(Node);
|
||||||
Node = Next;
|
Node = Next;
|
||||||
}
|
}
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
ASAN_POISON_MEMORY_REGION(Arena, Arena->Size);
|
ASAN_POISON_MEMORY_REGION(Arena, Arena->Size);
|
||||||
#endif
|
#endif
|
||||||
Platform.Deallocate(Arena);
|
Platform.Deallocate(Arena);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Platform.Release(Arena);
|
Platform.Release(Arena);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *ArenaPushNoClear(arena *Arena, u64 Size)
|
static void *ArenaPushNoClear(arena *Arena, u64 Size)
|
||||||
{
|
{
|
||||||
void *Result = 0;
|
void *Result = 0;
|
||||||
if(Arena->Chaining)
|
if(Arena->Chaining)
|
||||||
{
|
{
|
||||||
if(Size <= Arena->Size)
|
if(Size <= Arena->Size)
|
||||||
{
|
{
|
||||||
arena *Target = Arena->Prev; // sixten: We always append to the end of the list.
|
arena *Target = Arena->Prev; // sixten: We always append to the end of the list.
|
||||||
if(Target->Position + Size > Target->Size)
|
if(Target->Position + Size + Arena->Align > Target->Size)
|
||||||
{
|
{
|
||||||
arena *New = ArenaAlloc(Arena->Size, true);
|
arena *New = ArenaAlloc(Arena->Size, true);
|
||||||
New->NotFirst = true;
|
New->NotFirst = true;
|
||||||
SenDLLInsertLast(Arena, New);
|
SenDLLInsertLast(Arena, New);
|
||||||
Target = New;
|
Target = New;
|
||||||
}
|
}
|
||||||
u8 *Base = (u8 *)Target;
|
u8 *Base = (u8 *)Target;
|
||||||
u64 PostAlignPos = (Target->Position+Target->Align-1);
|
u64 PostAlignPos = (Target->Position+Target->Align-1);
|
||||||
PostAlignPos -= PostAlignPos%Target->Align;
|
PostAlignPos -= PostAlignPos%Target->Align;
|
||||||
Result = Base + PostAlignPos;
|
Result = Base + PostAlignPos;
|
||||||
Target->Position = PostAlignPos+Size;
|
Target->Position = PostAlignPos+Size;
|
||||||
|
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
ASAN_UNPOISON_MEMORY_REGION(Result, Size);
|
ASAN_UNPOISON_MEMORY_REGION(Result, Size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// sixten(NOTE): We can't really do anything in this situation.
|
// sixten(NOTE): We can't really do anything in this situation.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(Arena->Position + Size <= Arena->Size)
|
if(Arena->Position + Size <= Arena->Size)
|
||||||
{
|
{
|
||||||
u8 *Base = (u8 *)Arena;
|
u8 *Base = (u8 *)Arena;
|
||||||
u64 PostAlignPos = (Arena->Position+Arena->Align-1);
|
u64 PostAlignPos = (Arena->Position+Arena->Align-1);
|
||||||
PostAlignPos -= PostAlignPos%Arena->Align;
|
PostAlignPos -= PostAlignPos%Arena->Align;
|
||||||
u64 Align = PostAlignPos - Arena->Position;
|
u64 Align = PostAlignPos - Arena->Position;
|
||||||
Result = Base + Arena->Position + Align;
|
Result = Base + Arena->Position + Align;
|
||||||
Arena->Position += Size + Align;
|
Arena->Position += Size + Align;
|
||||||
if(Arena->CommitPosition < Arena->Position)
|
if(Arena->CommitPosition < Arena->Position)
|
||||||
{
|
{
|
||||||
u64 ToCommit = Arena->Position - Arena->CommitPosition;
|
u64 ToCommit = Arena->Position - Arena->CommitPosition;
|
||||||
ToCommit += MEMORY_ARENA_COMMIT_SIZE - 1;
|
ToCommit += MEMORY_ARENA_COMMIT_SIZE - 1;
|
||||||
ToCommit -= ToCommit%MEMORY_ARENA_COMMIT_SIZE;
|
ToCommit -= ToCommit%MEMORY_ARENA_COMMIT_SIZE;
|
||||||
Platform.Commit(Base + Arena->CommitPosition, ToCommit);
|
Platform.Commit(Base + Arena->CommitPosition, ToCommit);
|
||||||
Arena->CommitPosition += ToCommit;
|
Arena->CommitPosition += ToCommit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InvalidCodepath;
|
InvalidCodepath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *ArenaPush(arena *Arena, u64 Size)
|
static void *ArenaPush(arena *Arena, u64 Size)
|
||||||
{
|
{
|
||||||
void *Result = ArenaPushNoClear(Arena, Size);
|
void *Result = ArenaPushNoClear(Arena, Size);
|
||||||
Fill(Result, 0, Size);
|
Fill(Result, 0, Size);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArenaPopTo(arena *Arena, u64 Position)
|
static void ArenaPopTo(arena *Arena, u64 Position)
|
||||||
{
|
{
|
||||||
if(Arena->Chaining)
|
if(Arena->Chaining)
|
||||||
{
|
{
|
||||||
// sixten: find the relevant arena
|
// sixten: find the relevant arena
|
||||||
arena *Target = Arena;
|
arena *Target = Arena;
|
||||||
for(int ArenaIndex = 0; ArenaIndex < Position/Arena->Size; ++ArenaIndex)
|
for(int ArenaIndex = 0; ArenaIndex < Position/Arena->Size; ++ArenaIndex)
|
||||||
{
|
{
|
||||||
Target = Arena->Next;
|
Target = Arena->Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sixten: deallocate all arenas that are no longer needed
|
// sixten: deallocate all arenas that are no longer needed
|
||||||
{
|
{
|
||||||
arena *Node = Arena->Prev;
|
arena *Node = Arena->Prev;
|
||||||
while(Node != Target)
|
while(Node != Target)
|
||||||
{
|
{
|
||||||
arena *Prev = Node->Prev;
|
arena *Prev = Node->Prev;
|
||||||
SenDLLRemove(Node);
|
SenDLLRemove(Node);
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
ASAN_POISON_MEMORY_REGION(Node, Node->Size);
|
ASAN_POISON_MEMORY_REGION(Node, Node->Size);
|
||||||
#endif
|
#endif
|
||||||
Platform.Deallocate(Node);
|
Platform.Deallocate(Node);
|
||||||
Node = Prev;
|
Node = Prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Target->Position = Position%Arena->Size;
|
Target->Position = Position%Arena->Size;
|
||||||
#if VN_ASAN_ENABLED
|
#if VN_ASAN_ENABLED
|
||||||
u64 UnpoisonPosition = Target->Position;
|
u64 UnpoisonPosition = Target->Position;
|
||||||
ASAN_POISON_MEMORY_REGION(Target, Target->Size);
|
ASAN_POISON_MEMORY_REGION(Target, Target->Size);
|
||||||
ASAN_UNPOISON_MEMORY_REGION(Target, UnpoisonPosition);
|
ASAN_UNPOISON_MEMORY_REGION(Target, UnpoisonPosition);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u64 MinPosition = sizeof(*Arena);
|
u64 MinPosition = sizeof(*Arena);
|
||||||
u64 NewPosition = Maximum(MinPosition, Position);
|
u64 NewPosition = Maximum(MinPosition, Position);
|
||||||
Arena->Position = NewPosition;
|
Arena->Position = NewPosition;
|
||||||
u64 CommitAlignedPosition = Arena->Position+MEMORY_ARENA_COMMIT_SIZE-1;
|
u64 CommitAlignedPosition = Arena->Position+MEMORY_ARENA_COMMIT_SIZE-1;
|
||||||
CommitAlignedPosition -= CommitAlignedPosition%MEMORY_ARENA_COMMIT_SIZE;
|
CommitAlignedPosition -= CommitAlignedPosition%MEMORY_ARENA_COMMIT_SIZE;
|
||||||
if(CommitAlignedPosition + MEMORY_ARENA_DECOMMIT_THRESHOLD <= Arena->CommitPosition)
|
if(CommitAlignedPosition + MEMORY_ARENA_DECOMMIT_THRESHOLD <= Arena->CommitPosition)
|
||||||
{
|
{
|
||||||
u8 *Base = (u8 *)Arena;
|
u8 *Base = (u8 *)Arena;
|
||||||
u64 ToDecommit = Arena->CommitPosition-CommitAlignedPosition;
|
u64 ToDecommit = Arena->CommitPosition-CommitAlignedPosition;
|
||||||
Platform.Decommit(Base+CommitAlignedPosition, ToDecommit);
|
Platform.Decommit(Base+CommitAlignedPosition, ToDecommit);
|
||||||
Arena->CommitPosition -= ToDecommit;
|
Arena->CommitPosition -= ToDecommit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArenaPop(arena *Arena, u64 Amount)
|
static void ArenaPop(arena *Arena, u64 Amount)
|
||||||
{
|
{
|
||||||
ArenaPopTo(Arena, Max(Arena->Position-Amount, (s64)sizeof(arena)));
|
ArenaPopTo(Arena, Max(Arena->Position-Amount, (s64)sizeof(arena)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArenaClear(arena *Arena)
|
static void ArenaClear(arena *Arena)
|
||||||
{
|
{
|
||||||
ArenaPopTo(Arena, sizeof(*Arena));
|
ArenaPopTo(Arena, sizeof(*Arena));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArenaSetAlign(arena *Arena, u64 Align)
|
static void ArenaSetAlign(arena *Arena, u64 Align)
|
||||||
{
|
{
|
||||||
Arena->Align = Align;
|
Arena->Align = Align;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//- sixten: Temporary Memory Functions
|
//- sixten: Temporary Memory Functions
|
||||||
|
|
||||||
static temporary_memory BeginTemporaryMemory(arena *Arena)
|
static temp BeginTemp(arena *Arena)
|
||||||
{
|
{
|
||||||
temporary_memory Temp;
|
temp Temp;
|
||||||
Temp.Arena = Arena;
|
Temp.Arena = Arena;
|
||||||
Temp.Position = Arena->Position;
|
Temp.Position = Arena->Position;
|
||||||
return(Temp);
|
return(Temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EndTemporaryMemory(temporary_memory Temp)
|
static void EndTemp(temp Temp)
|
||||||
{
|
{
|
||||||
ArenaPopTo(Temp.Arena, Temp.Position);
|
ArenaPopTo(Temp.Arena, Temp.Position);
|
||||||
}
|
}
|
|
@ -34,21 +34,20 @@ static void Fill(void *Dest, u8 Value, umm Count);
|
||||||
|
|
||||||
struct arena
|
struct arena
|
||||||
{
|
{
|
||||||
u64 Position;
|
u64 Position;
|
||||||
u64 CommitPosition;
|
u64 CommitPosition;
|
||||||
u64 Size;
|
u64 Size;
|
||||||
u64 Align;
|
u64 Align;
|
||||||
b32 Chaining;
|
b32 Chaining;
|
||||||
b32 NotFirst;
|
b32 NotFirst;
|
||||||
arena *Next;
|
arena *Next;
|
||||||
arena *Prev;
|
arena *Prev;
|
||||||
u64 Unused[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct temporary_memory
|
struct temp
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
u64 Position;
|
u64 Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -75,7 +74,7 @@ static void ArenaSetAlign(arena *Arena, u64 Align);
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//- sixten: Temporary Memory Functions
|
//- sixten: Temporary Memory Functions
|
||||||
|
|
||||||
static temporary_memory BeginTemporaryMemory(arena *Arena);
|
static temp BeginTemp(arena *Arena);
|
||||||
static void EndTemporaryMemory(temporary_memory Temp);
|
static void EndTemp(temp Temp);
|
||||||
|
|
||||||
#endif //CORE_MEMORY_H
|
#endif //CORE_MEMORY_H
|
||||||
|
|
|
@ -2,54 +2,54 @@ per_thread thread_context *ThreadLocal_ThreadContext = 0;
|
||||||
|
|
||||||
static thread_context AllocateThreadContext(void)
|
static thread_context AllocateThreadContext(void)
|
||||||
{
|
{
|
||||||
thread_context Context = {};
|
thread_context Context = {};
|
||||||
for(s64 ArenaIndex = 0; ArenaIndex < ArrayCount(Context.Arenas); ArenaIndex += 1)
|
for(s64 ArenaIndex = 0; ArenaIndex < ArrayCount(Context.Arenas); ArenaIndex += 1)
|
||||||
{
|
{
|
||||||
Context.Arenas[ArenaIndex] = ArenaAlloc(Megabytes(2), true);
|
Context.Arenas[ArenaIndex] = ArenaAlloc(Megabytes(2), true);
|
||||||
}
|
}
|
||||||
return(Context);
|
return(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetThreadContext(thread_context *Context)
|
static void SetThreadContext(thread_context *Context)
|
||||||
{
|
{
|
||||||
ThreadLocal_ThreadContext = Context;
|
ThreadLocal_ThreadContext = Context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static thread_context *GetThreadContext(void)
|
static thread_context *GetThreadContext(void)
|
||||||
{
|
{
|
||||||
return(ThreadLocal_ThreadContext);
|
return(ThreadLocal_ThreadContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
static temporary_memory GetScratch(arena **Conflicts, u64 ConflictCount)
|
static temp GetScratch(arena **Conflicts, u64 ConflictCount)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = {};
|
temp Scratch = {};
|
||||||
thread_context *Context = GetThreadContext();
|
thread_context *Context = GetThreadContext();
|
||||||
|
|
||||||
for(u64 ArenaIndex = 0;
|
for(u64 ArenaIndex = 0;
|
||||||
ArenaIndex < ArrayCount(Context->Arenas);
|
ArenaIndex < ArrayCount(Context->Arenas);
|
||||||
++ArenaIndex)
|
++ArenaIndex)
|
||||||
{
|
{
|
||||||
b32 FoundConflict = false;
|
b32 FoundConflict = false;
|
||||||
for(u64 ConflictIndex = 0;
|
for(u64 ConflictIndex = 0;
|
||||||
ConflictIndex < ConflictCount;
|
ConflictIndex < ConflictCount;
|
||||||
++ConflictIndex)
|
++ConflictIndex)
|
||||||
{
|
{
|
||||||
arena *Conflict = Conflicts[ConflictIndex];
|
arena *Conflict = Conflicts[ConflictIndex];
|
||||||
if(Conflict == Context->Arenas[ArenaIndex])
|
if(Conflict == Context->Arenas[ArenaIndex])
|
||||||
{
|
{
|
||||||
FoundConflict = true;
|
FoundConflict = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!FoundConflict)
|
if(!FoundConflict)
|
||||||
{
|
{
|
||||||
Scratch = BeginTemporaryMemory(Context->Arenas[ArenaIndex]);
|
Scratch = BeginTemp(Context->Arenas[ArenaIndex]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(Scratch.Arena);
|
Assert(Scratch.Arena);
|
||||||
|
|
||||||
return(Scratch);
|
return(Scratch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
struct thread_context
|
struct thread_context
|
||||||
{
|
{
|
||||||
arena *Arenas[2];
|
arena *Arenas[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
//- sixten: Thread state management
|
//- sixten: Thread state management
|
||||||
|
@ -13,7 +13,7 @@ static void SetThreadContext(thread_context *Context);
|
||||||
static thread_context *GetThreadContext(void);
|
static thread_context *GetThreadContext(void);
|
||||||
|
|
||||||
//- sixten: Scratch
|
//- sixten: Scratch
|
||||||
static temporary_memory GetScratch(arena **Conflicts = 0, u64 ConflictCount = 0);
|
static temp GetScratch(arena **Conflicts = 0, u64 ConflictCount = 0);
|
||||||
#define ReleaseScratch(Scratch) EndTemporaryMemory(Scratch)
|
#define ReleaseScratch(Scratch) EndTemp(Scratch)
|
||||||
|
|
||||||
#endif //CORE_THREAD_CONTEXT_H
|
#endif //CORE_THREAD_CONTEXT_H
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
char * AssetPathLUT[5] =
|
char * AssetPathLUT[7] =
|
||||||
{
|
{
|
||||||
"",
|
"",
|
||||||
|
"backgrounds/unknown.png",
|
||||||
"backgrounds/test.jpg",
|
"backgrounds/test.jpg",
|
||||||
|
"backgrounds/ddlc.png",
|
||||||
"characters/test_normal.png",
|
"characters/test_normal.png",
|
||||||
"characters/test_happy.png",
|
"characters/test_happy.png",
|
||||||
"characters/monika_leaning.png",
|
"characters/monika_leaning.png",
|
||||||
};
|
};
|
||||||
|
|
||||||
bool AssetIsPermanentLUT[5] =
|
bool AssetIsPermanentLUT[7] =
|
||||||
{
|
{
|
||||||
|
true,
|
||||||
|
true,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
@ -16,10 +20,12 @@ false,
|
||||||
false,
|
false,
|
||||||
};
|
};
|
||||||
|
|
||||||
char * AssetNameLUT[5] =
|
char * AssetNameLUT[7] =
|
||||||
{
|
{
|
||||||
"None",
|
"None",
|
||||||
|
"Error",
|
||||||
"DemoBackground",
|
"DemoBackground",
|
||||||
|
"DDLCBackground",
|
||||||
"ArthurNormal",
|
"ArthurNormal",
|
||||||
"ArthurHappy",
|
"ArthurHappy",
|
||||||
"MonikaLeaning",
|
"MonikaLeaning",
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
enum asset_id
|
extern char * AssetPathLUT[7];
|
||||||
|
|
||||||
|
extern bool AssetIsPermanentLUT[7];
|
||||||
|
|
||||||
|
extern char * AssetNameLUT[7];
|
||||||
|
|
||||||
|
typedef s32 asset_id;
|
||||||
|
enum
|
||||||
{
|
{
|
||||||
AssetID_None,
|
AssetID_None,
|
||||||
|
AssetID_Error,
|
||||||
AssetID_DemoBackground,
|
AssetID_DemoBackground,
|
||||||
|
AssetID_DDLCBackground,
|
||||||
AssetID_ArthurNormal,
|
AssetID_ArthurNormal,
|
||||||
AssetID_ArthurHappy,
|
AssetID_ArthurHappy,
|
||||||
AssetID_MonikaLeaning,
|
AssetID_MonikaLeaning,
|
||||||
AssetID_COUNT,
|
AssetID_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern char * AssetPathLUT[5];
|
|
||||||
|
|
||||||
extern bool AssetIsPermanentLUT[5];
|
|
||||||
|
|
||||||
extern char * AssetNameLUT[5];
|
|
||||||
|
|
||||||
|
|
337
code/vn.cpp
|
@ -7,10 +7,10 @@
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
struct debug_settings
|
struct debug_settings
|
||||||
{
|
{
|
||||||
b32 RenderUIDebugRects;
|
b32 RenderUIDebugRects;
|
||||||
b32 RenderFPSCounter;
|
b32 RenderFPSCounter;
|
||||||
b32 ListHotAndActive;
|
b32 ListHotAndActive;
|
||||||
b32 ShowWelcomeMessage;
|
b32 ShowWelcomeMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
global debug_settings *DEBUG_DebugSettings = 0;
|
global debug_settings *DEBUG_DebugSettings = 0;
|
||||||
|
@ -32,6 +32,9 @@ global debug_settings *DEBUG_DebugSettings = 0;
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
#include "vn_workspace.h"
|
#include "vn_workspace.h"
|
||||||
|
#include "vn_debug_info.h"
|
||||||
|
|
||||||
|
global vn_render_commands *GlobalRenderCommands = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "generated/vn_character.meta.c"
|
#include "generated/vn_character.meta.c"
|
||||||
|
@ -49,199 +52,179 @@ global debug_settings *DEBUG_DebugSettings = 0;
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
#include "vn_workspace.cpp"
|
#include "vn_workspace.cpp"
|
||||||
|
#include "vn_debug_info.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct vn_state
|
struct vn_state
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
arena *FrameArena;
|
arena *FrameArena;
|
||||||
|
|
||||||
assets Assets;
|
assets Assets;
|
||||||
|
|
||||||
glyph_atlas *GlyphAtlas;
|
glyph_atlas *GlyphAtlas;
|
||||||
|
|
||||||
config *Config;
|
config *Config;
|
||||||
|
|
||||||
ui UI;
|
ui UI;
|
||||||
animation_curve_state AnimationCurveState;
|
animation_curve_state AnimationCurveState;
|
||||||
b32 EditorMode;
|
b32 EditorMode;
|
||||||
|
|
||||||
render_handle BackgroundTexture;
|
render_handle BackgroundTexture;
|
||||||
|
|
||||||
scene_view SceneView;
|
scene_view SceneView;
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
workspace Workspace;
|
debug_info *DebugInfo;
|
||||||
debug_settings DebugSettings;
|
workspace Workspace;
|
||||||
|
debug_settings DebugSettings;
|
||||||
#endif
|
#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, true, TextureData);
|
|
||||||
|
|
||||||
stbi_image_free(TextureData);
|
|
||||||
|
|
||||||
Platform.CloseFile(File);
|
|
||||||
}
|
|
||||||
ReleaseScratch(Scratch);
|
|
||||||
return(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
||||||
{
|
{
|
||||||
SetThreadContext(ThreadContext);
|
SetThreadContext(ThreadContext);
|
||||||
Platform = Memory->PlatformAPI;
|
Platform = Memory->PlatformAPI;
|
||||||
|
|
||||||
vn_state *State = Memory->State;
|
|
||||||
|
|
||||||
//- sixten: initialize application state
|
|
||||||
if(!Memory->State)
|
|
||||||
{
|
|
||||||
arena *Arena = ArenaAlloc(Kilobytes(24), true);
|
|
||||||
State = Memory->State = PushStruct(Arena, vn_state);
|
|
||||||
State->Arena = Arena;
|
|
||||||
State->FrameArena = ArenaAlloc(Megabytes(1), true);
|
|
||||||
|
|
||||||
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
|
|
||||||
State->Config = CreateConfig();
|
|
||||||
|
|
||||||
//- sixten: load assets
|
|
||||||
State->Assets.AllocateTexture = RenderCommands->AllocateTexture;
|
|
||||||
LoadPermanentAssets(&State->Assets);
|
|
||||||
|
|
||||||
State->BackgroundTexture = TextureFromAssetID(AssetID_DemoBackground);
|
|
||||||
|
|
||||||
//- sixten: setup config binds and load current config
|
|
||||||
{
|
|
||||||
Config_BindS32(State->Config, StrLit("Platform/RefreshRate"), &Input->RefreshRate, 60);
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
DEBUG_DebugSettings = &State->DebugSettings;
|
GlobalRenderCommands = RenderCommands;
|
||||||
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
|
#endif
|
||||||
|
|
||||||
Config_ReadFile(State->Config, StrLit("config.vn"));
|
vn_state *State = Memory->State;
|
||||||
}
|
|
||||||
|
//- sixten: initialize application state
|
||||||
scene_view *SceneView = &State->SceneView;
|
if(!Memory->State)
|
||||||
SV_Init(SceneView, State->Arena);
|
{
|
||||||
|
arena *Arena = ArenaAlloc(Kilobytes(24), true);
|
||||||
//- sixten: load startup scene
|
State = Memory->State = PushStruct(Arena, vn_state);
|
||||||
temporary_memory Scratch = GetScratch();
|
State->Arena = Arena;
|
||||||
string SceneInput = Platform_ReadEntireFile(Scratch.Arena, StrLit("data/scene.vns"));
|
State->FrameArena = ArenaAlloc(Megabytes(1), true);
|
||||||
compiled_scene Scene = S_ScriptFromText(Scratch.Arena, SceneInput);
|
|
||||||
SV_SetCurrentSource(&Scene);
|
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
|
||||||
ReleaseScratch(Scratch);
|
State->Config = CreateConfig();
|
||||||
|
|
||||||
SceneView->TestHappy = TextureFromAssetID(AssetID_ArthurHappy);
|
//- sixten: load assets
|
||||||
SceneView->TestNormal = TextureFromAssetID(AssetID_ArthurNormal);
|
State->Assets.AllocateTexture = RenderCommands->AllocateTexture;
|
||||||
SceneView->MonikaLeaning = TextureFromAssetID(AssetID_MonikaLeaning);
|
LoadPermanentAssets(&State->Assets);
|
||||||
|
|
||||||
SceneView->BackgroundTexture = State->BackgroundTexture;
|
State->BackgroundTexture = TextureFromAssetID(AssetID_DemoBackground);
|
||||||
|
|
||||||
UI_Init(&State->UI);
|
//- sixten: setup config binds and load current config
|
||||||
AC_Init(&State->AnimationCurveState);
|
{
|
||||||
|
Config_BindS32(State->Config, StrLit("Platform/RefreshRate"), &Input->RefreshRate, 60);
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
W_Init(&State->Workspace);
|
State->DebugInfo = DI_DebugInfoAlloc();
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
return;
|
|
||||||
}
|
Config_ReadFile(State->Config, StrLit("config.vn"));
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_view *SceneView = &State->SceneView;
|
||||||
|
SV_Init(SceneView, State->Arena);
|
||||||
|
|
||||||
|
//- sixten: load startup scene
|
||||||
|
temp Scratch = GetScratch();
|
||||||
|
string SceneInput = Platform_ReadEntireFile(Scratch.Arena, StrLit("data/scene.vns"));
|
||||||
|
compiled_scene Scene = S_ScriptFromText(Scratch.Arena, SceneInput);
|
||||||
|
SV_SetCurrentSource(&Scene);
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
|
SceneView->TestHappy = TextureFromAssetID(AssetID_ArthurHappy);
|
||||||
|
SceneView->TestNormal = TextureFromAssetID(AssetID_ArthurNormal);
|
||||||
|
SceneView->MonikaLeaning = TextureFromAssetID(AssetID_MonikaLeaning);
|
||||||
|
|
||||||
|
SceneView->BackgroundTexture = State->BackgroundTexture;
|
||||||
|
|
||||||
|
UI_Init(&State->UI);
|
||||||
|
AC_Init(&State->AnimationCurveState);
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
DEBUG_DebugSettings = &State->DebugSettings;
|
W_Init(&State->Workspace);
|
||||||
#endif
|
#endif
|
||||||
|
return;
|
||||||
//- sixten: begin new frame
|
}
|
||||||
ArenaClear(State->FrameArena);
|
|
||||||
SetAssets(&State->Assets);
|
|
||||||
AC_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
|
|
||||||
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP, Input->dtForFrame, State->GlyphAtlas);
|
|
||||||
SV_NewFrame(&State->SceneView, Input->EventList, Input->dtForFrame);
|
|
||||||
|
|
||||||
//- sixten: check for toggle between modes
|
|
||||||
if(Platform_KeyPress(Input->EventList, Key_Return, PlatformModifier_Ctrl))
|
|
||||||
{
|
|
||||||
State->EditorMode = !State->EditorMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- sixten: build the ui
|
|
||||||
UI_BeginBuild(RenderCommands->RenderDim);
|
|
||||||
{
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
if(State->EditorMode)
|
DI_BeginFrame(State->DebugInfo);
|
||||||
{
|
DEBUG_DebugSettings = &State->DebugSettings;
|
||||||
W_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
SV_BuildSceneView(Input);
|
|
||||||
|
//- sixten: begin new frame
|
||||||
|
ArenaClear(State->FrameArena);
|
||||||
|
SetAssets(&State->Assets);
|
||||||
|
AC_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
|
||||||
|
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP, Input->dtForFrame, State->GlyphAtlas);
|
||||||
|
SV_NewFrame(&State->SceneView, Input->EventList, Input->dtForFrame);
|
||||||
|
|
||||||
|
//- sixten: check for toggle between modes
|
||||||
|
if(Platform_KeyPress(Input->EventList, Key_Return, PlatformModifier_Ctrl))
|
||||||
|
{
|
||||||
|
State->EditorMode = !State->EditorMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: update the scene
|
||||||
|
SV_Update(State->FrameArena);
|
||||||
|
|
||||||
|
//- sixten: build the ui
|
||||||
|
UI_BeginBuild(RenderCommands->RenderDim);
|
||||||
|
{
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
}
|
DI_BuildInfo();
|
||||||
|
if(State->EditorMode)
|
||||||
|
{
|
||||||
|
W_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
}
|
SV_BuildSceneView(Input);
|
||||||
UI_EndBuild();
|
#if VN_INTERNAL
|
||||||
|
}
|
||||||
|
#endif
|
||||||
//- sixten: update the scene
|
}
|
||||||
SV_Update(State->FrameArena);
|
UI_EndBuild();
|
||||||
|
|
||||||
//- sixten: consume all remaining evetns
|
|
||||||
for(platform_event *Event = Input->EventList->First;
|
//- sixten: consume all remaining evetns
|
||||||
Event != 0;
|
for(platform_event *Event = Input->EventList->First;
|
||||||
Event = Event->Next)
|
Event != 0;
|
||||||
{
|
Event = Event->Next)
|
||||||
if(Event->Type == PlatformEvent_WindowClose)
|
{
|
||||||
{
|
if(Event->Type == PlatformEvent_WindowClose)
|
||||||
Config_WriteFile(State->Config, StrLit("config.vn"));
|
{
|
||||||
Input->ExitRequested = true;
|
Config_WriteFile(State->Config, StrLit("config.vn"));
|
||||||
}
|
Input->ExitRequested = true;
|
||||||
|
}
|
||||||
Platform_ConsumeEvent(Input->EventList, Event);
|
|
||||||
}
|
Platform_ConsumeEvent(Input->EventList, Event);
|
||||||
|
}
|
||||||
//- sixten: render the frame
|
|
||||||
{
|
//- sixten: render the frame
|
||||||
render_group Group = BeginRenderGroup(RenderCommands);
|
{
|
||||||
PushClear(&Group, V3(0.1, 0.1, 0.1));
|
render_group Group = BeginRenderGroup(RenderCommands);
|
||||||
|
PushClear(&Group, V3(0.1, 0.1, 0.1));
|
||||||
UI_RenderFrame(&Group, State->GlyphAtlas);
|
|
||||||
|
UI_RenderFrame(&Group, State->GlyphAtlas);
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
if(DEBUG_DebugSettings->ListHotAndActive)
|
if(DEBUG_DebugSettings->ListHotAndActive)
|
||||||
{
|
{
|
||||||
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 20), 15, Color_Grey,
|
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 20), 15, Color_Grey,
|
||||||
PushFormat(State->UI.FrameArena, "Hot: %S:%llu", UI_BoxStringFromKey(UI_HotKey()), UI_HotKey()));
|
PushFormat(State->UI.FrameArena, "Hot: %S:%llu", UI_BoxStringFromKey(UI_HotKey()), UI_HotKey()));
|
||||||
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 40), 15, Color_Grey,
|
PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 40), 15, Color_Grey,
|
||||||
PushFormat(State->UI.FrameArena, "Active: %S:%llu", UI_BoxStringFromKey(UI_ActiveKey()), UI_ActiveKey()));
|
PushFormat(State->UI.FrameArena, "Active: %S:%llu", UI_BoxStringFromKey(UI_ActiveKey()), UI_ActiveKey()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
#if VN_INTERNAL
|
||||||
|
DI_EndFrame();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,154 +5,154 @@ global animation_curve_state *Global_AnimationCurveState = 0;
|
||||||
|
|
||||||
inline animation_curve_state *AC_GetState(void)
|
inline animation_curve_state *AC_GetState(void)
|
||||||
{
|
{
|
||||||
return(Global_AnimationCurveState);
|
return(Global_AnimationCurveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AC_SetState(animation_curve_state *State)
|
inline void AC_SetState(animation_curve_state *State)
|
||||||
{
|
{
|
||||||
Global_AnimationCurveState = State;
|
Global_AnimationCurveState = State;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AC_Init(animation_curve_state *State)
|
static void AC_Init(animation_curve_state *State)
|
||||||
{
|
{
|
||||||
State->Arena = ArenaAlloc(Kilobytes(32), true);
|
State->Arena = ArenaAlloc(Kilobytes(32), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline animation_curve_key AC_GenerateKeyFromString(string String)
|
inline animation_curve_key AC_GenerateKeyFromString(string String)
|
||||||
{
|
{
|
||||||
animation_curve_key Key;
|
animation_curve_key Key;
|
||||||
Key.Value = HashString(String);
|
Key.Value = HashString(String);
|
||||||
|
|
||||||
return(Key);
|
return(Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static animation_curve_entry *AC_GetEntryByKey(animation_curve_key Key, r32 Initial)
|
static animation_curve_entry *AC_GetEntryByKey(animation_curve_key Key, r32 Initial)
|
||||||
{
|
{
|
||||||
animation_curve_state *State = AC_GetState();
|
animation_curve_state *State = AC_GetState();
|
||||||
|
|
||||||
u64 Hash = Key.Value;
|
u64 Hash = Key.Value;
|
||||||
u64 Slot = Hash % ArrayCount(State->Buckets);
|
u64 Slot = Hash % ArrayCount(State->Buckets);
|
||||||
|
|
||||||
animation_curve_bucket *Bucket = State->Buckets + Slot;
|
animation_curve_bucket *Bucket = State->Buckets + Slot;
|
||||||
|
|
||||||
animation_curve_entry *Result = 0;
|
animation_curve_entry *Result = 0;
|
||||||
for(animation_curve_entry *Entry = Bucket->First;
|
for(animation_curve_entry *Entry = Bucket->First;
|
||||||
Entry != 0;
|
Entry != 0;
|
||||||
Entry = Entry->Next)
|
Entry = Entry->Next)
|
||||||
{
|
{
|
||||||
if(AreEqual(Entry->Key, Key))
|
if(AreEqual(Entry->Key, Key))
|
||||||
{
|
{
|
||||||
Result = Entry;
|
Result = Entry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Result)
|
if(!Result)
|
||||||
{
|
{
|
||||||
if(DLLIsEmpty(State->FirstFreeEntry))
|
if(DLLIsEmpty(State->FirstFreeEntry))
|
||||||
{
|
{
|
||||||
Result = PushStruct(State->Arena, animation_curve_entry);
|
Result = PushStruct(State->Arena, animation_curve_entry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Result = State->FirstFreeEntry;
|
Result = State->FirstFreeEntry;
|
||||||
DLLRemove(State->FirstFreeEntry, State->LastFreeEntry, Result);
|
DLLRemove(State->FirstFreeEntry, State->LastFreeEntry, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLInsertLast(Bucket->First, Bucket->Last, Result);
|
DLLInsertLast(Bucket->First, Bucket->Last, Result);
|
||||||
|
|
||||||
Result->Value = Initial;
|
Result->Value = Initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->Key = Key;
|
Result->Key = Key;
|
||||||
Result->LastFrameTouched = State->CurrentFrame;
|
Result->LastFrameTouched = State->CurrentFrame;
|
||||||
|
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 AC_GetValue(string Name, r32 Initial)
|
inline r32 AC_GetValue(string Name, r32 Initial)
|
||||||
{
|
{
|
||||||
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
||||||
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
|
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
|
||||||
|
|
||||||
r32 Result = Entry->Value;
|
r32 Result = Entry->Value;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AC_SetValue(string Name, r32 Value)
|
inline void AC_SetValue(string Name, r32 Value)
|
||||||
{
|
{
|
||||||
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
||||||
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Value);
|
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Value);
|
||||||
|
|
||||||
Entry->Value = Value;
|
Entry->Value = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 AC_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
|
inline r32 AC_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
|
||||||
{
|
{
|
||||||
animation_curve_state *State = AC_GetState();
|
animation_curve_state *State = AC_GetState();
|
||||||
|
|
||||||
r32 Result = *Value;
|
r32 Result = *Value;
|
||||||
|
|
||||||
r32 Rate = 1.0 - Pow(2, -(10.0 / Duration * State->dtForFrame));
|
r32 Rate = 1.0 - Pow(2, -(10.0 / Duration * State->dtForFrame));
|
||||||
*Value += (Target - *Value) * Rate;
|
*Value += (Target - *Value) * Rate;
|
||||||
|
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 AC_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name)
|
inline r32 AC_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name)
|
||||||
{
|
{
|
||||||
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
animation_curve_key Key = AC_GenerateKeyFromString(Name);
|
||||||
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
|
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
|
||||||
|
|
||||||
r32 Result = AC_AnimateValueDirect(Target, Duration, &Entry->Value);
|
r32 Result = AC_AnimateValueDirect(Target, Duration, &Entry->Value);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 AC_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...)
|
inline r32 AC_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temp Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
r32 Result = AC_AnimateValue(Target, Initial, Duration, String);
|
r32 Result = AC_AnimateValue(Target, Initial, Duration, String);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AC_NewFrame(animation_curve_state *State, r32 dtForFrame)
|
static void AC_NewFrame(animation_curve_state *State, r32 dtForFrame)
|
||||||
{
|
{
|
||||||
AC_SetState(State);
|
AC_SetState(State);
|
||||||
State->dtForFrame = dtForFrame;
|
State->dtForFrame = dtForFrame;
|
||||||
|
|
||||||
// sixten: Prune untouched entries.
|
// sixten: Prune untouched entries.
|
||||||
for(s32 BucketIndex = 0;
|
for(s32 BucketIndex = 0;
|
||||||
BucketIndex < ArrayCount(State->Buckets);
|
BucketIndex < ArrayCount(State->Buckets);
|
||||||
++BucketIndex)
|
++BucketIndex)
|
||||||
{
|
{
|
||||||
animation_curve_bucket *Bucket = State->Buckets + BucketIndex;
|
animation_curve_bucket *Bucket = State->Buckets + BucketIndex;
|
||||||
|
|
||||||
animation_curve_entry *Entry = Bucket->First;
|
animation_curve_entry *Entry = Bucket->First;
|
||||||
while(Entry != 0)
|
while(Entry != 0)
|
||||||
{
|
{
|
||||||
if(Entry->LastFrameTouched != State->CurrentFrame)
|
if(Entry->LastFrameTouched != State->CurrentFrame)
|
||||||
{
|
{
|
||||||
animation_curve_entry *ToRemove = Entry;
|
animation_curve_entry *ToRemove = Entry;
|
||||||
Entry = Entry->Next;
|
Entry = Entry->Next;
|
||||||
|
|
||||||
DLLRemove(Bucket->First, Bucket->Last, ToRemove);
|
DLLRemove(Bucket->First, Bucket->Last, ToRemove);
|
||||||
DLLInsertLast(State->FirstFreeEntry, State->LastFreeEntry, ToRemove);
|
DLLInsertLast(State->FirstFreeEntry, State->LastFreeEntry, ToRemove);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Entry = Entry->Next;
|
Entry = Entry->Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++State->CurrentFrame;
|
++State->CurrentFrame;
|
||||||
}
|
}
|
|
@ -2,77 +2,77 @@ global assets *Global_Assets;
|
||||||
|
|
||||||
static assets *GetAssets()
|
static assets *GetAssets()
|
||||||
{
|
{
|
||||||
return(Global_Assets);
|
return(Global_Assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetAssets(assets *Assets)
|
static void SetAssets(assets *Assets)
|
||||||
{
|
{
|
||||||
Global_Assets = Assets;
|
Global_Assets = Assets;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadAsset(asset_id ID)
|
static void LoadAsset(asset_id ID)
|
||||||
{
|
{
|
||||||
assets *Assets = GetAssets();
|
assets *Assets = GetAssets();
|
||||||
Assert(ID >= AssetID_None && ID < AssetID_COUNT);
|
Assert(ID >= AssetID_None && ID < AssetID_COUNT);
|
||||||
|
|
||||||
asset *Asset = Assets->Assets + ID;
|
asset *Asset = Assets->Assets + ID;
|
||||||
|
|
||||||
if(!Asset->IsLoaded)
|
if(!Asset->IsLoaded)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch();
|
temp Scratch = GetScratch();
|
||||||
|
|
||||||
string Filepath = PushFormat(Scratch.Arena, "data/%s", AssetPathLUT[ID]);
|
string Filepath = PushFormat(Scratch.Arena, "data/%s", AssetPathLUT[ID]);
|
||||||
platform_file_handle File = Platform.OpenFile(Filepath, PlatformAccess_Read);
|
platform_file_handle File = Platform.OpenFile(Filepath, PlatformAccess_Read);
|
||||||
if(File.IsValid)
|
if(File.IsValid)
|
||||||
{
|
{
|
||||||
u64 DataCount = Platform.GetFileSize(File);
|
u64 DataCount = Platform.GetFileSize(File);
|
||||||
u8 *Data = PushArray(Scratch.Arena, u8, DataCount);
|
u8 *Data = PushArray(Scratch.Arena, u8, DataCount);
|
||||||
Platform.ReadFile(File, Data, 0, DataCount);
|
Platform.ReadFile(File, Data, 0, DataCount);
|
||||||
|
|
||||||
s32 Width, Height, BPP;
|
s32 Width, Height, BPP;
|
||||||
u8 *TextureData = stbi_load_from_memory(Data, DataCount, &Width, &Height, &BPP, 0);
|
u8 *TextureData = stbi_load_from_memory(Data, DataCount, &Width, &Height, &BPP, 0);
|
||||||
|
|
||||||
render_texture_format TextureFormat = Render_TextureFormat_Invalid;
|
render_texture_format TextureFormat = Render_TextureFormat_Invalid;
|
||||||
switch(BPP)
|
switch(BPP)
|
||||||
{
|
{
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
case 1: { TextureFormat = Render_TextureFormat_R8; } break;
|
case 1: { TextureFormat = Render_TextureFormat_R8; } break;
|
||||||
case 3: { TextureFormat = Render_TextureFormat_RGB8; } break;
|
case 3: { TextureFormat = Render_TextureFormat_RGB8; } break;
|
||||||
case 4: { TextureFormat = Render_TextureFormat_RGBA8; } break;
|
case 4: { TextureFormat = Render_TextureFormat_RGBA8; } break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Asset->Handle = Assets->AllocateTexture(V2S32(Width, Height), TextureFormat, true, TextureData);
|
Asset->Handle = Assets->AllocateTexture(V2S32(Width, Height), TextureFormat, true, TextureData);
|
||||||
|
|
||||||
stbi_image_free(TextureData);
|
stbi_image_free(TextureData);
|
||||||
|
|
||||||
Platform.CloseFile(File);
|
Platform.CloseFile(File);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void LoadPermanentAssets(assets *Assets)
|
static void LoadPermanentAssets(assets *Assets)
|
||||||
{
|
{
|
||||||
SetAssets(Assets);
|
SetAssets(Assets);
|
||||||
|
|
||||||
//- sixten: assign ID to all assets & load all permanent ones
|
//- sixten: assign ID to all assets & load all permanent ones
|
||||||
for(int Index = 0; Index < AssetID_COUNT; ++Index)
|
for(int Index = 0; Index < AssetID_COUNT; ++Index)
|
||||||
{
|
{
|
||||||
asset_id ID = (asset_id)Index;
|
asset_id ID = (asset_id)Index;
|
||||||
asset *Asset = Assets->Assets + Index;
|
asset *Asset = Assets->Assets + Index;
|
||||||
Asset->ID = ID;
|
Asset->ID = ID;
|
||||||
|
|
||||||
if(ID != AssetID_None)
|
if(ID != AssetID_None)
|
||||||
{
|
{
|
||||||
LoadAsset(ID);
|
LoadAsset(ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static render_handle TextureFromAssetID(asset_id ID)
|
static render_handle TextureFromAssetID(asset_id ID)
|
||||||
{
|
{
|
||||||
Assert(ID >= AssetID_None && ID < AssetID_COUNT);
|
Assert(ID >= AssetID_None && ID < AssetID_COUNT);
|
||||||
|
|
||||||
asset *Asset = GetAssets()->Assets + ID;
|
asset *Asset = GetAssets()->Assets + ID;
|
||||||
return(Asset->Handle);
|
return(Asset->Handle);
|
||||||
}
|
}
|
|
@ -1,44 +1,50 @@
|
||||||
@table(Name, Path, IsPermanent) assets_desc:
|
@table(Name, Path, IsPermanent) assets_desc:
|
||||||
{
|
{
|
||||||
{ None, "", false }
|
{ None, "", true }
|
||||||
|
{ Error, "backgrounds/unknown.png", true }
|
||||||
////////////////////////////////
|
|
||||||
//~ sixten: backgrounds
|
////////////////////////////////
|
||||||
{ DemoBackground, "backgrounds/test.jpg", false }
|
//~ sixten: backgrounds
|
||||||
|
{ DemoBackground, "backgrounds/test.jpg", false }
|
||||||
////////////////////////////////
|
{ DDLCBackground, "backgrounds/ddlc.png", false }
|
||||||
//~ sixten: characters
|
|
||||||
|
////////////////////////////////
|
||||||
//- sixten: arthur
|
//~ sixten: characters
|
||||||
{ ArthurNormal, "characters/test_normal.png", false }
|
|
||||||
{ ArthurHappy, "characters/test_happy.png", false }
|
//- sixten: arthur
|
||||||
|
{ ArthurNormal, "characters/test_normal.png", false }
|
||||||
//- sixten: monika
|
{ ArthurHappy, "characters/test_happy.png", false }
|
||||||
{ MonikaLeaning, "characters/monika_leaning.png", false }
|
|
||||||
|
//- sixten: monika
|
||||||
|
{ MonikaLeaning, "characters/monika_leaning.png", false }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@table_gen_enum asset_id:
|
@table_gen
|
||||||
{
|
{
|
||||||
@expand(assets_desc s) `AssetID_$(s.Name),`;
|
`typedef s32 asset_id;`
|
||||||
`AssetID_COUNT,`;
|
`enum`
|
||||||
|
`{`
|
||||||
|
@expand(assets_desc s) `AssetID_$(s.Name),`;
|
||||||
|
`AssetID_COUNT,`;
|
||||||
|
`};`
|
||||||
}
|
}
|
||||||
|
|
||||||
@table_gen_data(`char *`) AssetPathLUT:
|
@table_gen_data(`char *`) AssetPathLUT:
|
||||||
{
|
{
|
||||||
@expand(assets_desc s)
|
@expand(assets_desc s)
|
||||||
`"$(s.Path)",`;
|
`"$(s.Path)",`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@table_gen_data(`bool`) AssetIsPermanentLUT:
|
@table_gen_data(`bool`) AssetIsPermanentLUT:
|
||||||
{
|
{
|
||||||
@expand(assets_desc s)
|
@expand(assets_desc s)
|
||||||
`$(s.IsPermanent),`;
|
`$(s.IsPermanent),`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@table_gen_data(`char *`) AssetNameLUT:
|
@table_gen_data(`char *`) AssetNameLUT:
|
||||||
{
|
{
|
||||||
@expand(assets_desc s)
|
@expand(assets_desc s)
|
||||||
`"$(s.Name)",`;
|
`"$(s.Name)",`;
|
||||||
}
|
}
|
|
@ -1,327 +1,327 @@
|
||||||
static config *CreateConfig(void)
|
static config *CreateConfig(void)
|
||||||
{
|
{
|
||||||
arena *Arena = ArenaAlloc(Kilobytes(4), true);
|
arena *Arena = ArenaAlloc(Kilobytes(4), true);
|
||||||
config *Config = PushStruct(Arena, config);
|
config *Config = PushStruct(Arena, config);
|
||||||
Config->Arena = Arena;
|
Config->Arena = Arena;
|
||||||
return(Config);
|
return(Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static config_entry *Config_FindEntryByName(config *Config, string Name)
|
static config_entry *Config_FindEntryByName(config *Config, string Name)
|
||||||
{
|
{
|
||||||
config_entry *Result = 0;
|
config_entry *Result = 0;
|
||||||
|
|
||||||
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
|
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
|
||||||
config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot;
|
config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot;
|
||||||
|
|
||||||
for(config_entry *Entry = Bucket->First;
|
for(config_entry *Entry = Bucket->First;
|
||||||
Entry != 0;
|
Entry != 0;
|
||||||
Entry = Entry->Next)
|
Entry = Entry->Next)
|
||||||
{
|
{
|
||||||
if(AreEqual(Entry->Name, Name))
|
if(AreEqual(Entry->Name, Name))
|
||||||
{
|
{
|
||||||
Result = Entry;
|
Result = Entry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target)
|
static void Config_BindEntry(config *Config, string Name, config_entry_type Type, void *Target)
|
||||||
{
|
{
|
||||||
config_entry *Entry = Config_FindEntryByName(Config, Name);
|
config_entry *Entry = Config_FindEntryByName(Config, Name);
|
||||||
if(!Entry)
|
if(!Entry)
|
||||||
{
|
{
|
||||||
Entry = PushStruct(Config->Arena, config_entry);
|
Entry = PushStruct(Config->Arena, config_entry);
|
||||||
Entry->Name = PushString(Config->Arena, Name);
|
Entry->Name = PushString(Config->Arena, Name);
|
||||||
Entry->Type = Type;
|
Entry->Type = Type;
|
||||||
|
|
||||||
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
|
u32 BucketSlot = HashString(Name) % ArrayCount(Config->EntryBuckets);
|
||||||
config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot;
|
config_entry_bucket *Bucket = Config->EntryBuckets + BucketSlot;
|
||||||
|
|
||||||
DLLInsertLast(Bucket->First, Bucket->Last, Entry);
|
DLLInsertLast(Bucket->First, Bucket->Last, Entry);
|
||||||
|
|
||||||
if(Config->LastInternal)
|
if(Config->LastInternal)
|
||||||
{
|
{
|
||||||
Config->LastInternal->NextInternal = Entry;
|
Config->LastInternal->NextInternal = Entry;
|
||||||
Config->LastInternal = Entry;
|
Config->LastInternal = Entry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Config->FirstInternal = Config->LastInternal = Entry;
|
Config->FirstInternal = Config->LastInternal = Entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(Entry->Type == Type);
|
Assert(Entry->Type == Type);
|
||||||
Entry->Target = Target;
|
Entry->Target = Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Config_BindS32(config *Config, string Name, s32 *Target, s32 Default)
|
inline void Config_BindS32(config *Config, string Name, s32 *Target, s32 Default)
|
||||||
{
|
{
|
||||||
*Target = Default;
|
*Target = Default;
|
||||||
Config_BindEntry(Config, Name, Config_Entry_S32, Target);
|
Config_BindEntry(Config, Name, Config_Entry_S32, Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Config_BindS64(config *Config, string Name, s64 *Target, s64 Default)
|
inline void Config_BindS64(config *Config, string Name, s64 *Target, s64 Default)
|
||||||
{
|
{
|
||||||
*Target = Default;
|
*Target = Default;
|
||||||
Config_BindEntry(Config, Name, Config_Entry_S64, Target);
|
Config_BindEntry(Config, Name, Config_Entry_S64, Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Config_BindB32(config *Config, string Name, b32 *Target, b32 Default)
|
inline void Config_BindB32(config *Config, string Name, b32 *Target, b32 Default)
|
||||||
{
|
{
|
||||||
*Target = Default;
|
*Target = Default;
|
||||||
Config_BindEntry(Config, Name, Config_Entry_B32, Target);
|
Config_BindEntry(Config, Name, Config_Entry_B32, Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Config_ParseError(string Message, string FileText, s64 Offset, arena *Arena)
|
static void Config_ParseError(string Message, string FileText, s64 Offset, arena *Arena)
|
||||||
{
|
{
|
||||||
text_point Point = TextPointFromOffset(FileText, Offset);
|
text_point Point = TextPointFromOffset(FileText, Offset);
|
||||||
string String = PushFormat(Arena, "Config: At %i:%i - %S", Point.Line, Point.Column, Message);
|
string String = PushFormat(Arena, "Config: At %i:%i - %S", Point.Line, Point.Column, Message);
|
||||||
Platform.ShowMessage(String, Platform_Message_Warning);
|
Platform.ShowMessage(String, Platform_Message_Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Config_ReadFile(config *Config, string Path)
|
static void Config_ReadFile(config *Config, string Path)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch();
|
temp Scratch = GetScratch();
|
||||||
|
|
||||||
//- sixten: read & tokenize input file
|
//- sixten: read & tokenize input file
|
||||||
string Text = Platform_ReadEntireFile(Scratch.Arena, Path);
|
string Text = Platform_ReadEntireFile(Scratch.Arena, Path);
|
||||||
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Text, T_IsIrregular);
|
tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Text, T_IsIrregular);
|
||||||
token_array Tokens = TokenizeResult.Tokens;
|
token_array Tokens = TokenizeResult.Tokens;
|
||||||
|
|
||||||
// sixten: parse context
|
// sixten: parse context
|
||||||
config_parse_list FullPath = {};
|
config_parse_list FullPath = {};
|
||||||
config_parse_mode ParseMode = ConfigParseMode_Main;
|
config_parse_mode ParseMode = ConfigParseMode_Main;
|
||||||
|
|
||||||
//- sixten: parse tokens
|
//- sixten: parse tokens
|
||||||
token *TokensStart = Tokens.Tokens;
|
token *TokensStart = Tokens.Tokens;
|
||||||
token *TokensEnd = Tokens.Tokens + Tokens.Count;
|
token *TokensEnd = Tokens.Tokens + Tokens.Count;
|
||||||
token *Token = TokensStart;
|
token *Token = TokensStart;
|
||||||
for(;Token < TokensEnd;)
|
for(;Token < TokensEnd;)
|
||||||
{
|
{
|
||||||
string TokenString = Substring(Text, Token->Range);
|
string TokenString = Substring(Text, Token->Range);
|
||||||
|
|
||||||
//- sixten: get next name
|
//- sixten: get next name
|
||||||
if(ParseMode == ConfigParseMode_Main && Token->Kind & TokenKind_Identifier)
|
if(ParseMode == ConfigParseMode_Main && Token->Kind & TokenKind_Identifier)
|
||||||
{
|
{
|
||||||
Config_ParseListPush(Scratch.Arena, &FullPath, TokenString);
|
Config_ParseListPush(Scratch.Arena, &FullPath, TokenString);
|
||||||
ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals;
|
ParseMode = ConfigParseMode_ScanForCurlyOpenOrEquals;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for curly close
|
//- sixten: scan for curly close
|
||||||
if(ParseMode == ConfigParseMode_Main && Token->Kind == TokenKind_CurlyClose)
|
if(ParseMode == ConfigParseMode_Main && Token->Kind == TokenKind_CurlyClose)
|
||||||
{
|
{
|
||||||
Config_ParseListPop(&FullPath);
|
Config_ParseListPop(&FullPath);
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for curly open
|
//- sixten: scan for curly open
|
||||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind == TokenKind_CurlyOpen)
|
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind == TokenKind_CurlyOpen)
|
||||||
{
|
{
|
||||||
ParseMode = ConfigParseMode_Main;
|
ParseMode = ConfigParseMode_Main;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for equals
|
//- sixten: scan for equals
|
||||||
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind & TokenKind_Equal)
|
if(ParseMode == ConfigParseMode_ScanForCurlyOpenOrEquals && Token->Kind & TokenKind_Equal)
|
||||||
{
|
{
|
||||||
ParseMode = ConfigParseMode_ScanForValue;
|
ParseMode = ConfigParseMode_ScanForValue;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for semicolon
|
//- sixten: scan for semicolon
|
||||||
if(ParseMode == ConfigParseMode_ScanForSemicolon && Token->Kind == TokenKind_Semicolon)
|
if(ParseMode == ConfigParseMode_ScanForSemicolon && Token->Kind == TokenKind_Semicolon)
|
||||||
{
|
{
|
||||||
ParseMode = ConfigParseMode_Main;
|
ParseMode = ConfigParseMode_Main;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for boolean value
|
//- sixten: scan for boolean value
|
||||||
if(ParseMode == ConfigParseMode_ScanForValue && (Token->Kind == TokenKind_True || Token->Kind == TokenKind_False))
|
if(ParseMode == ConfigParseMode_ScanForValue && (Token->Kind == TokenKind_True || Token->Kind == TokenKind_False))
|
||||||
{
|
{
|
||||||
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
||||||
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
||||||
if(Entry)
|
if(Entry)
|
||||||
{
|
{
|
||||||
b32 Value = AreEqual(TokenString, StrLit("true"));
|
b32 Value = AreEqual(TokenString, StrLit("true"));
|
||||||
Assert(Entry->Type == Config_Entry_B32);
|
Assert(Entry->Type == Config_Entry_B32);
|
||||||
*(b32 *)Entry->Target = Value;
|
*(b32 *)Entry->Target = Value;
|
||||||
}
|
}
|
||||||
Config_ParseListPop(&FullPath);
|
Config_ParseListPop(&FullPath);
|
||||||
ParseMode = ConfigParseMode_ScanForSemicolon;
|
ParseMode = ConfigParseMode_ScanForSemicolon;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: scan for integer value
|
//- sixten: scan for integer value
|
||||||
if(ParseMode == ConfigParseMode_ScanForValue && Token->Kind & TokenKind_Numeric)
|
if(ParseMode == ConfigParseMode_ScanForValue && Token->Kind & TokenKind_Numeric)
|
||||||
{
|
{
|
||||||
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
string FullName = Config_ParseListJoin(Scratch.Arena, &FullPath);
|
||||||
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
config_entry *Entry = Config_FindEntryByName(Config, FullName);
|
||||||
if(Entry)
|
if(Entry)
|
||||||
{
|
{
|
||||||
s64 Value = ConvertStringToS64(TokenString);
|
s64 Value = ConvertStringToS64(TokenString);
|
||||||
if(Entry->Type == Config_Entry_S32)
|
if(Entry->Type == Config_Entry_S32)
|
||||||
{
|
{
|
||||||
*(s32 *)Entry->Target = Value;
|
*(s32 *)Entry->Target = Value;
|
||||||
}
|
}
|
||||||
else if(Entry->Type == Config_Entry_S64)
|
else if(Entry->Type == Config_Entry_S64)
|
||||||
{
|
{
|
||||||
*(s64 *)Entry->Target = Value;
|
*(s64 *)Entry->Target = Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InvalidCodepath;
|
InvalidCodepath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Config_ParseListPop(&FullPath);
|
Config_ParseListPop(&FullPath);
|
||||||
ParseMode = ConfigParseMode_ScanForSemicolon;
|
ParseMode = ConfigParseMode_ScanForSemicolon;
|
||||||
Token += 1;
|
Token += 1;
|
||||||
goto TokenConsumed;
|
goto TokenConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: if the token has not been consumed, something's gone wrong
|
//- sixten: if the token has not been consumed, something's gone wrong
|
||||||
{
|
{
|
||||||
string ErrorMessage = StrLit("Unknown parse error");
|
string ErrorMessage = StrLit("Unknown parse error");
|
||||||
//- sixten: determine error message
|
//- sixten: determine error message
|
||||||
switch(ParseMode)
|
switch(ParseMode)
|
||||||
{
|
{
|
||||||
case ConfigParseMode_Main: { ErrorMessage = StrLit("Expected identifier or '}'"); } break;
|
case ConfigParseMode_Main: { ErrorMessage = StrLit("Expected identifier or '}'"); } break;
|
||||||
case ConfigParseMode_ScanForCurlyOpenOrEquals: { ErrorMessage = StrLit("Expected '{' or '='") ; } break;
|
case ConfigParseMode_ScanForCurlyOpenOrEquals: { ErrorMessage = StrLit("Expected '{' or '='") ; } break;
|
||||||
case ConfigParseMode_ScanForValue: { ErrorMessage = StrLit("Expected value"); } break;
|
case ConfigParseMode_ScanForValue: { ErrorMessage = StrLit("Expected value"); } break;
|
||||||
case ConfigParseMode_ScanForSemicolon: { ErrorMessage = StrLit("Expected ';'"); } break;
|
case ConfigParseMode_ScanForSemicolon: { ErrorMessage = StrLit("Expected ';'"); } break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config_ParseError(ErrorMessage, Text, Token->Range.Min, Scratch.Arena);
|
Config_ParseError(ErrorMessage, Text, Token->Range.Min, Scratch.Arena);
|
||||||
Token += 1;
|
Token += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenConsumed:;
|
TokenConsumed:;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ sixten: Config Parse Type Functions
|
//~ sixten: Config Parse Type Functions
|
||||||
static void Config_ParseListPush(arena *Arena, config_parse_list *List, string Name)
|
static void Config_ParseListPush(arena *Arena, config_parse_list *List, string Name)
|
||||||
{
|
{
|
||||||
config_parse_node *Node = PushStruct(Arena, config_parse_node);
|
config_parse_node *Node = PushStruct(Arena, config_parse_node);
|
||||||
Node->Name = Name;
|
Node->Name = Name;
|
||||||
List->TotalCountPlusOne += Name.Count + 1;
|
List->TotalCountPlusOne += Name.Count + 1;
|
||||||
DLLInsertLast(List->First, List->Last, Node);
|
DLLInsertLast(List->First, List->Last, Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Config_ParseListPop(config_parse_list *List)
|
static void Config_ParseListPop(config_parse_list *List)
|
||||||
{
|
{
|
||||||
config_parse_node *Node = List->Last;
|
config_parse_node *Node = List->Last;
|
||||||
if(Node)
|
if(Node)
|
||||||
{
|
{
|
||||||
List->TotalCountPlusOne -= Node->Name.Count + 1;
|
List->TotalCountPlusOne -= Node->Name.Count + 1;
|
||||||
DLLRemove(List->First, List->Last, Node);
|
DLLRemove(List->First, List->Last, Node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static string Config_ParseListJoin(arena *Arena, config_parse_list *List)
|
static string Config_ParseListJoin(arena *Arena, config_parse_list *List)
|
||||||
{
|
{
|
||||||
s64 TotalCount = List->TotalCountPlusOne - 1;
|
s64 TotalCount = List->TotalCountPlusOne - 1;
|
||||||
string Result = MakeString(PushArray(Arena, u8, List->TotalCountPlusOne), TotalCount);
|
string Result = MakeString(PushArray(Arena, u8, List->TotalCountPlusOne), TotalCount);
|
||||||
s64 Index = 0;
|
s64 Index = 0;
|
||||||
for(config_parse_node *Node = List->First; Node != 0; Node = Node->Next)
|
for(config_parse_node *Node = List->First; Node != 0; Node = Node->Next)
|
||||||
{
|
{
|
||||||
Copy(Result.Data + Index, Node->Name.Data, Node->Name.Count);
|
Copy(Result.Data + Index, Node->Name.Data, Node->Name.Count);
|
||||||
Index += Node->Name.Count;
|
Index += Node->Name.Count;
|
||||||
if(Node->Next)
|
if(Node->Next)
|
||||||
{
|
{
|
||||||
Result.Data[Index] = '/';
|
Result.Data[Index] = '/';
|
||||||
Index += 1;
|
Index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Config_WriteFile(config *Config, string Path)
|
static void Config_WriteFile(config *Config, string Path)
|
||||||
{
|
{
|
||||||
string_list Out = {};
|
string_list Out = {};
|
||||||
temporary_memory Scratch = GetScratch();
|
temp Scratch = GetScratch();
|
||||||
|
|
||||||
string LastDir = MakeString(0, 0LL);
|
string LastDir = MakeString(0, 0LL);
|
||||||
for(config_entry *Entry = Config->FirstInternal;
|
for(config_entry *Entry = Config->FirstInternal;
|
||||||
Entry != 0;
|
Entry != 0;
|
||||||
Entry = Entry->NextInternal)
|
Entry = Entry->NextInternal)
|
||||||
{
|
{
|
||||||
s64 LastSlash = LastIndexOf(Entry->Name, '/');
|
s64 LastSlash = LastIndexOf(Entry->Name, '/');
|
||||||
Assert(LastSlash != -1);
|
Assert(LastSlash != -1);
|
||||||
|
|
||||||
string Dir = Prefix(Entry->Name, LastSlash);
|
string Dir = Prefix(Entry->Name, LastSlash);
|
||||||
string Name = Suffix(Entry->Name, Entry->Name.Count - LastSlash - 1);
|
string Name = Suffix(Entry->Name, Entry->Name.Count - LastSlash - 1);
|
||||||
|
|
||||||
if(!AreEqual(Dir, LastDir))
|
if(!AreEqual(Dir, LastDir))
|
||||||
{
|
{
|
||||||
if(!AreEqual(LastDir, MakeString(0, 0LL)))
|
if(!AreEqual(LastDir, MakeString(0, 0LL)))
|
||||||
{
|
{
|
||||||
AppendString(&Out, StrLit("}\n\n"), Scratch.Arena);
|
AppendString(&Out, StrLit("}\n\n"), Scratch.Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendString(&Out, Dir, Scratch.Arena);
|
AppendString(&Out, Dir, Scratch.Arena);
|
||||||
AppendString(&Out, StrLit("\n{\n"), Scratch.Arena);
|
AppendString(&Out, StrLit("\n{\n"), Scratch.Arena);
|
||||||
|
|
||||||
LastDir = Dir;
|
LastDir = Dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendString(&Out, StrLit("\t"), Scratch.Arena);
|
AppendString(&Out, StrLit("\t"), Scratch.Arena);
|
||||||
AppendString(&Out, Name, Scratch.Arena);
|
AppendString(&Out, Name, Scratch.Arena);
|
||||||
AppendString(&Out, StrLit(" = "), Scratch.Arena);
|
AppendString(&Out, StrLit(" = "), Scratch.Arena);
|
||||||
|
|
||||||
// sixten: Output the value of the entry
|
// sixten: Output the value of the entry
|
||||||
if(Entry->Type == Config_Entry_S32 || Entry->Type == Config_Entry_S64)
|
if(Entry->Type == Config_Entry_S32 || Entry->Type == Config_Entry_S64)
|
||||||
{
|
{
|
||||||
s64 IntegerValue;
|
s64 IntegerValue;
|
||||||
if(Entry->Type == Config_Entry_S32)
|
if(Entry->Type == Config_Entry_S32)
|
||||||
{
|
{
|
||||||
IntegerValue = *(s32 *)Entry->Target;
|
IntegerValue = *(s32 *)Entry->Target;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntegerValue = *(s64 *)Entry->Target;
|
IntegerValue = *(s64 *)Entry->Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Value = ConvertS64ToString(Scratch.Arena, IntegerValue);
|
string Value = ConvertS64ToString(Scratch.Arena, IntegerValue);
|
||||||
AppendString(&Out, Value, Scratch.Arena);
|
AppendString(&Out, Value, Scratch.Arena);
|
||||||
}
|
}
|
||||||
else if(Entry->Type == Config_Entry_B32)
|
else if(Entry->Type == Config_Entry_B32)
|
||||||
{
|
{
|
||||||
string Value = (*(b32 *)Entry->Target)?StrLit("true"):StrLit("false");
|
string Value = (*(b32 *)Entry->Target)?StrLit("true"):StrLit("false");
|
||||||
AppendString(&Out, Value, Scratch.Arena);
|
AppendString(&Out, Value, Scratch.Arena);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UnimplementedCodepath;
|
UnimplementedCodepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendString(&Out, StrLit(";\n"), Scratch.Arena);
|
AppendString(&Out, StrLit(";\n"), Scratch.Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!AreEqual(LastDir, MakeString(0, 0LL)))
|
if(!AreEqual(LastDir, MakeString(0, 0LL)))
|
||||||
{
|
{
|
||||||
AppendString(&Out, StrLit("}"), Scratch.Arena);
|
AppendString(&Out, StrLit("}"), Scratch.Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
string FinalOut = JoinStringList(&Out, Scratch.Arena);
|
string FinalOut = JoinStringList(&Out, Scratch.Arena);
|
||||||
|
|
||||||
platform_file_handle Handle = Platform.OpenFile(Path, PlatformAccess_Write);
|
platform_file_handle Handle = Platform.OpenFile(Path, PlatformAccess_Write);
|
||||||
if(Handle.IsValid)
|
if(Handle.IsValid)
|
||||||
{
|
{
|
||||||
Platform.WriteFile(Handle, FinalOut.Data, 0, FinalOut.Count);
|
Platform.WriteFile(Handle, FinalOut.Data, 0, FinalOut.Count);
|
||||||
Platform.CloseFile(Handle);
|
Platform.CloseFile(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
////////////////////////////////
|
||||||
|
//~ sixten: Debug Info Functions
|
||||||
|
|
||||||
|
per_thread debug_info *ThreadLocal_DebugInfo = 0;
|
||||||
|
|
||||||
|
//- sixten: manage state
|
||||||
|
static debug_info *DI_DebugInfoAlloc(void)
|
||||||
|
{
|
||||||
|
arena *Arena = ArenaAlloc(Kilobytes(1), true);
|
||||||
|
debug_info *Result = PushStruct(Arena, debug_info);
|
||||||
|
Result->Arena = Arena;
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DI_BeginFrame(debug_info *DebugInfo)
|
||||||
|
{
|
||||||
|
ThreadLocal_DebugInfo = DebugInfo;
|
||||||
|
DebugInfo->FrameTemp = BeginTemp(DebugInfo->Arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DI_EndFrame()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: user interface
|
||||||
|
static void DI_Info(string Message)
|
||||||
|
{
|
||||||
|
debug_info *DebugInfo = ThreadLocal_DebugInfo;
|
||||||
|
debug_info_node *Node = PushStruct(DebugInfo->Arena, debug_info_node);
|
||||||
|
Node->Message = PushString(DebugInfo->Arena, Message);
|
||||||
|
DLLInsertLast(DebugInfo->First, DebugInfo->Last, Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DI_InfoF(char *Format, ...)
|
||||||
|
{
|
||||||
|
debug_info *DebugInfo = ThreadLocal_DebugInfo;
|
||||||
|
va_list Arguments;
|
||||||
|
va_start(Arguments, Format);
|
||||||
|
temp Scratch = GetScratch();
|
||||||
|
string Message = PushFormatVariadic(DebugInfo->Arena, Format, Arguments);
|
||||||
|
DI_Info(Message);
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
|
va_end(Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DI_BuildInfo(void)
|
||||||
|
{
|
||||||
|
debug_info *DebugInfo = ThreadLocal_DebugInfo;
|
||||||
|
AC_AnimateValueDirect(DebugInfo->Open, 0.3f, &DebugInfo->OpenT);
|
||||||
|
if(!DLLIsEmpty(DebugInfo->First))
|
||||||
|
{
|
||||||
|
UI_Tooltip
|
||||||
|
{
|
||||||
|
UI_SetNextBackgroundColor(SetAlpha(Theme_BackgroundColor, 0.5f));
|
||||||
|
UI_SetNextSize(UI_Em(15, 1), UI_ChildrenSum(1, 1));
|
||||||
|
UI_SetNextCornerRadius(4.0f);
|
||||||
|
UI_SetNextHoverCursor(PlatformCursor_ArrowAll);
|
||||||
|
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder|UI_BoxFlag_Clickable|
|
||||||
|
UI_BoxFlag_HotAnimation|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_Clip,
|
||||||
|
StrLit("DI Container"));
|
||||||
|
UI_Parent(Box)
|
||||||
|
{
|
||||||
|
UI_Size(UI_Percent(1, 1), UI_ChildrenSum(1, 1)) UI_Row() UI_Width(UI_TextContent(15, 1)) UI_Height(UI_TextContent(15, 1))
|
||||||
|
{
|
||||||
|
UI_Font(Font_Bold) UI_LabelF("Debug Info");
|
||||||
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
|
UI_Font(Font_Icons)
|
||||||
|
{
|
||||||
|
ui_box *ExpandBox = UI_MakeBoxF(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable|UI_BoxFlag_HotAnimation, "%U", DebugInfo->Open?FontIcon_DownDir:FontIcon_RightDir);
|
||||||
|
ui_signal ExpandBoxSignal = UI_SignalFromBox(ExpandBox);
|
||||||
|
if(ExpandBoxSignal.Pressed)
|
||||||
|
{
|
||||||
|
DebugInfo->Open = !DebugInfo->Open;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_Height(UI_ChildrenSum(DebugInfo->OpenT, 1)) UI_Column()
|
||||||
|
{
|
||||||
|
UI_Width(UI_TextContent(15, 1)) UI_Height(UI_TextContent(15, 1))
|
||||||
|
for(debug_info_node *Node = DebugInfo->First; Node != 0; Node = Node->Next)
|
||||||
|
{
|
||||||
|
ui_box *MessageBox = UI_MakeBoxF(UI_BoxFlag_DrawText, "%p", Node);
|
||||||
|
UI_EquipBoxText(MessageBox, Node->Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_signal Signal = UI_SignalFromBox(Box);
|
||||||
|
if(Signal.Dragging)
|
||||||
|
{
|
||||||
|
if(Signal.Pressed)
|
||||||
|
{
|
||||||
|
UI_StoreDragV2(DebugInfo->RelativeP);
|
||||||
|
}
|
||||||
|
|
||||||
|
v2 StartP = UI_GetDragV2();
|
||||||
|
v2 EndP = StartP + Signal.DragDelta;
|
||||||
|
DebugInfo->RelativeP = EndP;
|
||||||
|
}
|
||||||
|
Box->FixedP = DebugInfo->RelativeP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sixten: after building we assume that the data should be released
|
||||||
|
EndTemp(DebugInfo->FrameTemp);
|
||||||
|
DebugInfo->First = DebugInfo->Last = 0;
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* date = December 9th 2023 0:37 pm */
|
||||||
|
|
||||||
|
#ifndef VN_DEBUG_INFO_H
|
||||||
|
#define VN_DEBUG_INFO_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ sixten: Debug Info Types
|
||||||
|
|
||||||
|
struct debug_info_node
|
||||||
|
{
|
||||||
|
debug_info_node *Next;
|
||||||
|
debug_info_node *Prev;
|
||||||
|
string Message;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct debug_info
|
||||||
|
{
|
||||||
|
arena *Arena;
|
||||||
|
temp FrameTemp;
|
||||||
|
debug_info_node *First;
|
||||||
|
debug_info_node *Last;
|
||||||
|
v2_r32 RelativeP;
|
||||||
|
b32 Open;
|
||||||
|
r32 OpenT;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ sixten: Debug Info Functions
|
||||||
|
|
||||||
|
//- sixten: manage state
|
||||||
|
static debug_info *DI_DebugInfoAlloc(void);
|
||||||
|
static void DI_BeginFrame(debug_info *DebugInfo);
|
||||||
|
static void DI_EndFrame(void);
|
||||||
|
|
||||||
|
//- sixten: user interface
|
||||||
|
static void DI_Info(string Message);
|
||||||
|
static void DI_InfoF(char *Format, ...);
|
||||||
|
static void DI_BuildInfo(void);
|
||||||
|
|
||||||
|
#endif //VN_DEBUG_INFO_H
|
384
code/vn_font.cpp
|
@ -4,230 +4,230 @@ global read_only s32 Font_Oversample = 2;
|
||||||
|
|
||||||
inline s32 GetSubpixelSegmentAtP(r32 Value)
|
inline s32 GetSubpixelSegmentAtP(r32 Value)
|
||||||
{
|
{
|
||||||
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
|
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel)
|
static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||||
{
|
{
|
||||||
Glyph->Font = Font;
|
Glyph->Font = Font;
|
||||||
Glyph->Codepoint = Codepoint;
|
Glyph->Codepoint = Codepoint;
|
||||||
Glyph->Size = Size;
|
Glyph->Size = Size;
|
||||||
Glyph->Subpixel = Subpixel;
|
Glyph->Subpixel = Subpixel;
|
||||||
|
|
||||||
Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS);
|
Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS);
|
||||||
|
|
||||||
loaded_font *LoadedFont = Atlas->Fonts + Font;
|
loaded_font *LoadedFont = Atlas->Fonts + Font;
|
||||||
stbtt_fontinfo *Info = &LoadedFont->Info;
|
stbtt_fontinfo *Info = &LoadedFont->Info;
|
||||||
|
|
||||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size);
|
r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size);
|
||||||
|
|
||||||
s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs);
|
s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs);
|
||||||
s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize;
|
s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize;
|
||||||
|
|
||||||
v2_s32 BaseTextureOffset = V2S32((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize,
|
v2_s32 BaseTextureOffset = V2S32((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize,
|
||||||
(InternalIndex / GlyphsPerRow)*Atlas->GlyphSize);
|
(InternalIndex / GlyphsPerRow)*Atlas->GlyphSize);
|
||||||
|
|
||||||
int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint);
|
int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint);
|
||||||
|
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale,
|
stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale,
|
||||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||||
&Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y);
|
&Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y);
|
||||||
|
|
||||||
Fill(Atlas->BitmapBuffer, 0, Atlas->GlyphSize*Atlas->GlyphSize);
|
Fill(Atlas->BitmapBuffer, 0, Atlas->GlyphSize*Atlas->GlyphSize);
|
||||||
stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer,
|
stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer,
|
||||||
Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize,
|
Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize,
|
||||||
Scale, Scale,
|
Scale, Scale,
|
||||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||||
GlyphIndex);
|
GlyphIndex);
|
||||||
|
|
||||||
s32 Advance, LeftSideBearing;
|
s32 Advance, LeftSideBearing;
|
||||||
stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing);
|
stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing);
|
||||||
Glyph->Advance = Advance*Scale;
|
Glyph->Advance = Advance*Scale;
|
||||||
Glyph->Offset.x = LeftSideBearing*Scale;
|
Glyph->Offset.x = LeftSideBearing*Scale;
|
||||||
|
|
||||||
Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale;
|
Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale;
|
||||||
|
|
||||||
v2_s32 Dim = Glyph->P1 - Glyph->P0;
|
v2_s32 Dim = Glyph->P1 - Glyph->P0;
|
||||||
|
|
||||||
Glyph->P0 = BaseTextureOffset;
|
Glyph->P0 = BaseTextureOffset;
|
||||||
Glyph->P1 = BaseTextureOffset + Dim + V2S32(2, 2);
|
Glyph->P1 = BaseTextureOffset + Dim + V2S32(2, 2);
|
||||||
|
|
||||||
Atlas->RenderCommands->FillRegion(Atlas->Texture,
|
Atlas->RenderCommands->FillRegion(Atlas->Texture,
|
||||||
BaseTextureOffset, V2S32(Atlas->GlyphSize, Atlas->GlyphSize),
|
BaseTextureOffset, V2S32(Atlas->GlyphSize, Atlas->GlyphSize),
|
||||||
Atlas->BitmapBuffer);
|
Atlas->BitmapBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel)
|
static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||||
{
|
{
|
||||||
glyph *Glyph = 0;
|
glyph *Glyph = 0;
|
||||||
|
|
||||||
for(s32 GlyphIndex = 0;
|
for(s32 GlyphIndex = 0;
|
||||||
GlyphIndex < Atlas->GlyphsUsed;
|
GlyphIndex < Atlas->GlyphsUsed;
|
||||||
++GlyphIndex)
|
++GlyphIndex)
|
||||||
{
|
{
|
||||||
glyph *At = Atlas->Glyphs + GlyphIndex;
|
glyph *At = Atlas->Glyphs + GlyphIndex;
|
||||||
if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel))
|
if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel))
|
||||||
{
|
{
|
||||||
Glyph = At;
|
Glyph = At;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Glyph)
|
if(Glyph)
|
||||||
{
|
{
|
||||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount)
|
if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount)
|
||||||
{
|
{
|
||||||
Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++;
|
Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Glyph = Atlas->LRUFirst;
|
Glyph = Atlas->LRUFirst;
|
||||||
Assert(Glyph);
|
Assert(Glyph);
|
||||||
|
|
||||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel);
|
RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||||
|
|
||||||
return(Glyph);
|
return(Glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
|
static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
|
||||||
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
|
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
|
||||||
s32 GlyphSize = MAX_GLYPH_SIZE)
|
s32 GlyphSize = MAX_GLYPH_SIZE)
|
||||||
{
|
{
|
||||||
arena *Arena = ArenaAlloc(Megabytes(1), true);
|
arena *Arena = ArenaAlloc(Megabytes(1), true);
|
||||||
glyph_atlas *Atlas = PushStruct(Arena, glyph_atlas);
|
glyph_atlas *Atlas = PushStruct(Arena, glyph_atlas);
|
||||||
Atlas->Arena = Arena;
|
Atlas->Arena = Arena;
|
||||||
|
|
||||||
Atlas->BitmapSize = BitmapSize;
|
Atlas->BitmapSize = BitmapSize;
|
||||||
Atlas->GlyphSize = GlyphSize;
|
Atlas->GlyphSize = GlyphSize;
|
||||||
|
|
||||||
Atlas->MaxGlyphCount = (DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE)*(DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE);
|
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->RenderCommands = RenderCommands;
|
||||||
Atlas->Texture = RenderCommands->AllocateTexture(V2S32(BitmapSize, BitmapSize), Render_TextureFormat_R8, false, 0);
|
Atlas->Texture = RenderCommands->AllocateTexture(V2S32(BitmapSize, BitmapSize), Render_TextureFormat_R8, false, 0);
|
||||||
|
|
||||||
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Roboto-Regular.ttf"));
|
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Roboto-Regular.ttf"));
|
||||||
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Roboto-Bold.ttf"));
|
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Roboto-Bold.ttf"));
|
||||||
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/DejaVuSansMono.ttf"));
|
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/DejaVuSansMono.ttf"));
|
||||||
Atlas->Fonts[Font_MonospaceOblique].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/DejaVuSansMono-Oblique.ttf"));
|
Atlas->Fonts[Font_MonospaceOblique].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/DejaVuSansMono-Oblique.ttf"));
|
||||||
Atlas->Fonts[Font_Fancy].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Merriweather-Regular.ttf"));
|
Atlas->Fonts[Font_Fancy].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/Merriweather-Regular.ttf"));
|
||||||
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/icons.ttf"));
|
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/icons.ttf"));
|
||||||
|
|
||||||
for(s32 FontIndex = 0;
|
for(s32 FontIndex = 0;
|
||||||
FontIndex < Font_Count;
|
FontIndex < Font_Count;
|
||||||
++FontIndex)
|
++FontIndex)
|
||||||
{
|
{
|
||||||
loaded_font *Font = Atlas->Fonts + FontIndex;
|
loaded_font *Font = Atlas->Fonts + FontIndex;
|
||||||
stbtt_InitFont(&Font->Info,
|
stbtt_InitFont(&Font->Info,
|
||||||
Font->Data.Data,
|
Font->Data.Data,
|
||||||
stbtt_GetFontOffsetForIndex(Font->Data.Data, 0));
|
stbtt_GetFontOffsetForIndex(Font->Data.Data, 0));
|
||||||
|
|
||||||
stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap);
|
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);
|
return(Atlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static r32 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,
|
v2 P, r32 Size, v4 Color,
|
||||||
string Text)
|
string Text)
|
||||||
{
|
{
|
||||||
r32 OffsetX = 0;
|
r32 OffsetX = 0;
|
||||||
u8 *TextBegin = Text.Data;
|
u8 *TextBegin = Text.Data;
|
||||||
u8 *TextEnd = TextBegin+Text.Count;
|
u8 *TextEnd = TextBegin+Text.Count;
|
||||||
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
||||||
{
|
{
|
||||||
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
||||||
Byte += Decode.Size;
|
Byte += Decode.Size;
|
||||||
u32 Codepoint = Decode.Codepoint;
|
u32 Codepoint = Decode.Codepoint;
|
||||||
|
|
||||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(P.x*Font_Oversample));
|
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(P.x*Font_Oversample));
|
||||||
Assert(Glyph);
|
Assert(Glyph);
|
||||||
|
|
||||||
v2 GlyphP = P + Glyph->Offset*(1.0 / Font_Oversample) + V2(OffsetX, 1);
|
v2 GlyphP = P + Glyph->Offset*(1.0 / Font_Oversample) + V2(OffsetX, 1);
|
||||||
|
|
||||||
v2 RenderDim = ConvertV2ToR32(Glyph->P1 - Glyph->P0);
|
v2 RenderDim = ConvertV2ToR32(Glyph->P1 - Glyph->P0);
|
||||||
v2 Dim = RenderDim*(1.0 / Font_Oversample);
|
v2 Dim = RenderDim*(1.0 / Font_Oversample);
|
||||||
|
|
||||||
PushTexturedQuad(Group,
|
PushTexturedQuad(Group,
|
||||||
Range2R32(GlyphP, GlyphP+Dim),
|
Range2R32(GlyphP, GlyphP+Dim),
|
||||||
Range2R32(ConvertV2ToR32(Glyph->P0), ConvertV2ToR32(Glyph->P1)),
|
Range2R32(ConvertV2ToR32(Glyph->P0), ConvertV2ToR32(Glyph->P1)),
|
||||||
Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
|
Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
|
||||||
|
|
||||||
OffsetX += Glyph->Advance/Font_Oversample;
|
OffsetX += Glyph->Advance/Font_Oversample;
|
||||||
}
|
}
|
||||||
return(OffsetX);
|
return(OffsetX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
||||||
v2 P, r32 Size, v4 Color,
|
v2 P, r32 Size, v4 Color,
|
||||||
char *Format, ...)
|
char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temp Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
PushText(Group, Atlas, Font, P, Size, Color, String);
|
PushText(Group, Atlas, Font, P, Size, Color, String);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||||
{
|
{
|
||||||
r32 X = 0;
|
r32 X = 0;
|
||||||
|
|
||||||
u8 *TextBegin = Text.Data;
|
u8 *TextBegin = Text.Data;
|
||||||
u8 *TextEnd = TextBegin+Text.Count;
|
u8 *TextEnd = TextBegin+Text.Count;
|
||||||
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
||||||
{
|
{
|
||||||
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
||||||
Byte += Decode.Size;
|
Byte += Decode.Size;
|
||||||
u32 Codepoint = Decode.Codepoint;
|
u32 Codepoint = Decode.Codepoint;
|
||||||
|
|
||||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(X*Font_Oversample));
|
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Font_Oversample, GetSubpixelSegmentAtP(X*Font_Oversample));
|
||||||
Assert(Glyph);
|
Assert(Glyph);
|
||||||
|
|
||||||
X += Glyph->Advance/Font_Oversample;
|
X += Glyph->Advance/Font_Oversample;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(X);
|
return(X);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||||
{
|
{
|
||||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/
|
r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/
|
||||||
stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size);
|
stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size);
|
||||||
|
|
||||||
r32 Y = Size*Scale;
|
r32 Y = Size*Scale;
|
||||||
|
|
||||||
u8 *TextBegin = Text.Data;
|
u8 *TextBegin = Text.Data;
|
||||||
u8 *TextEnd = TextBegin+Text.Count;
|
u8 *TextEnd = TextBegin+Text.Count;
|
||||||
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
||||||
{
|
{
|
||||||
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
||||||
Byte += Decode.Size;
|
Byte += Decode.Size;
|
||||||
u32 Codepoint = Decode.Codepoint;
|
u32 Codepoint = Decode.Codepoint;
|
||||||
|
|
||||||
if(Codepoint == '\n')
|
if(Codepoint == '\n')
|
||||||
{
|
{
|
||||||
Y += Size*Scale;
|
Y += Size*Scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(Y);
|
return(Y);
|
||||||
}
|
}
|
|
@ -5,14 +5,14 @@
|
||||||
|
|
||||||
enum font_id
|
enum font_id
|
||||||
{
|
{
|
||||||
Font_Regular,
|
Font_Regular,
|
||||||
Font_Bold,
|
Font_Bold,
|
||||||
Font_Monospace,
|
Font_Monospace,
|
||||||
Font_MonospaceOblique,
|
Font_MonospaceOblique,
|
||||||
Font_Fancy,
|
Font_Fancy,
|
||||||
Font_Icons,
|
Font_Icons,
|
||||||
|
|
||||||
Font_Count,
|
Font_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FontIcon_None 0x0000
|
#define FontIcon_None 0x0000
|
||||||
|
@ -62,7 +62,7 @@ enum font_id
|
||||||
#define FontIcon_DocumentFileCode 0xf1c9
|
#define FontIcon_DocumentFileCode 0xf1c9
|
||||||
#define FontIcon_UserPlus 0xf234
|
#define FontIcon_UserPlus 0xf234
|
||||||
#define FontIcon_UserTimes 0xf235
|
#define FontIcon_UserTimes 0xf235
|
||||||
#define FontIcon_History 0xf235
|
#define FontIcon_History 0xf1da
|
||||||
#define FontIcon_Trash 0xf1f8
|
#define FontIcon_Trash 0xf1f8
|
||||||
#define FontIcon_Debug 0xf188
|
#define FontIcon_Debug 0xf188
|
||||||
#define FontIcon_Gamepad 0xf11b
|
#define FontIcon_Gamepad 0xf11b
|
||||||
|
@ -76,18 +76,18 @@ enum font_id
|
||||||
|
|
||||||
struct glyph
|
struct glyph
|
||||||
{
|
{
|
||||||
glyph *LRUNext;
|
glyph *LRUNext;
|
||||||
glyph *LRUPrev;
|
glyph *LRUPrev;
|
||||||
|
|
||||||
font_id Font;
|
font_id Font;
|
||||||
u32 Codepoint;
|
u32 Codepoint;
|
||||||
r32 Size;
|
r32 Size;
|
||||||
s32 Subpixel;
|
s32 Subpixel;
|
||||||
|
|
||||||
v2_s32 P0;
|
v2_s32 P0;
|
||||||
v2_s32 P1;
|
v2_s32 P1;
|
||||||
v2 Offset;
|
v2 Offset;
|
||||||
r32 Advance;
|
r32 Advance;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_GLYPH_ATLAS_DIM 1024*4
|
#define DEFAULT_GLYPH_ATLAS_DIM 1024*4
|
||||||
|
@ -98,33 +98,33 @@ struct glyph
|
||||||
|
|
||||||
struct loaded_font
|
struct loaded_font
|
||||||
{
|
{
|
||||||
stbtt_fontinfo Info;
|
stbtt_fontinfo Info;
|
||||||
string Data;
|
string Data;
|
||||||
|
|
||||||
s32 Ascent;
|
s32 Ascent;
|
||||||
s32 Descent;
|
s32 Descent;
|
||||||
s32 LineGap;
|
s32 LineGap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct glyph_atlas
|
struct glyph_atlas
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
|
|
||||||
s32 MaxGlyphCount;
|
s32 MaxGlyphCount;
|
||||||
s32 GlyphsUsed;
|
s32 GlyphsUsed;
|
||||||
glyph *Glyphs;
|
glyph *Glyphs;
|
||||||
|
|
||||||
glyph *LRUFirst;
|
glyph *LRUFirst;
|
||||||
glyph *LRULast;
|
glyph *LRULast;
|
||||||
|
|
||||||
vn_render_commands *RenderCommands;
|
vn_render_commands *RenderCommands;
|
||||||
render_handle Texture;
|
render_handle Texture;
|
||||||
|
|
||||||
u8 *BitmapBuffer;
|
u8 *BitmapBuffer;
|
||||||
s32 BitmapSize;
|
s32 BitmapSize;
|
||||||
s32 GlyphSize;
|
s32 GlyphSize;
|
||||||
|
|
||||||
loaded_font Fonts[Font_Count];
|
loaded_font Fonts[Font_Count];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //VN_FONT_H
|
#endif //VN_FONT_H
|
||||||
|
|
|
@ -13,119 +13,119 @@
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PlatformAccess_Read = 0x1,
|
PlatformAccess_Read = 0x1,
|
||||||
PlatformAccess_Write = 0x2,
|
PlatformAccess_Write = 0x2,
|
||||||
};
|
};
|
||||||
typedef u32 platform_access_flags;
|
typedef u32 platform_access_flags;
|
||||||
|
|
||||||
struct platform_file_handle
|
struct platform_file_handle
|
||||||
{
|
{
|
||||||
u64 Platform;
|
u64 Platform;
|
||||||
b32 IsValid;
|
b32 IsValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_file_info
|
struct platform_file_info
|
||||||
{
|
{
|
||||||
string Name;
|
string Name;
|
||||||
b32 IsDirectory;
|
b32 IsDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_file_iter
|
struct platform_file_iter
|
||||||
{
|
{
|
||||||
u64 U64[1024];
|
u64 U64[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum platform_cursor
|
enum platform_cursor
|
||||||
{
|
{
|
||||||
PlatformCursor_Arrow,
|
PlatformCursor_Arrow,
|
||||||
PlatformCursor_Cross,
|
PlatformCursor_Cross,
|
||||||
PlatformCursor_Hand,
|
PlatformCursor_Hand,
|
||||||
PlatformCursor_Help,
|
PlatformCursor_Help,
|
||||||
PlatformCursor_IBeam,
|
PlatformCursor_IBeam,
|
||||||
PlatformCursor_SlashedCircle,
|
PlatformCursor_SlashedCircle,
|
||||||
PlatformCursor_ArrowAll,
|
PlatformCursor_ArrowAll,
|
||||||
PlatformCursor_ArrowNESW,
|
PlatformCursor_ArrowNESW,
|
||||||
PlatformCursor_ArrowVertical,
|
PlatformCursor_ArrowVertical,
|
||||||
PlatformCursor_ArrowNWSE,
|
PlatformCursor_ArrowNWSE,
|
||||||
PlatformCursor_ArrowHorizontal,
|
PlatformCursor_ArrowHorizontal,
|
||||||
PlatformCursor_Wait,
|
PlatformCursor_Wait,
|
||||||
|
|
||||||
PlatformCursor_Count
|
PlatformCursor_Count
|
||||||
};
|
};
|
||||||
|
|
||||||
enum platform_message_type
|
enum platform_message_type
|
||||||
{
|
{
|
||||||
Platform_Message_Info,
|
Platform_Message_Info,
|
||||||
Platform_Message_Warning,
|
Platform_Message_Warning,
|
||||||
Platform_Message_Error,
|
Platform_Message_Error,
|
||||||
Platform_Message_Fatal,
|
Platform_Message_Fatal,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum platform_event_type
|
enum platform_event_type
|
||||||
{
|
{
|
||||||
PlatformEvent_Press,
|
PlatformEvent_Press,
|
||||||
PlatformEvent_Release,
|
PlatformEvent_Release,
|
||||||
PlatformEvent_Text,
|
PlatformEvent_Text,
|
||||||
PlatformEvent_MouseScroll,
|
PlatformEvent_MouseScroll,
|
||||||
PlatformEvent_WindowClose,
|
PlatformEvent_WindowClose,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum platform_key
|
enum platform_key
|
||||||
{
|
{
|
||||||
Key_Invalid,
|
Key_Invalid,
|
||||||
|
|
||||||
Key_A, Key_B, Key_C, Key_D,
|
Key_A, Key_B, Key_C, Key_D,
|
||||||
Key_E, Key_F, Key_G, Key_H,
|
Key_E, Key_F, Key_G, Key_H,
|
||||||
Key_I, Key_J, Key_K, Key_L,
|
Key_I, Key_J, Key_K, Key_L,
|
||||||
Key_M, Key_N, Key_O, Key_P,
|
Key_M, Key_N, Key_O, Key_P,
|
||||||
Key_Q, Key_R, Key_S, Key_T,
|
Key_Q, Key_R, Key_S, Key_T,
|
||||||
Key_U, Key_V, Key_W, Key_X,
|
Key_U, Key_V, Key_W, Key_X,
|
||||||
Key_Y, Key_Z,
|
Key_Y, Key_Z,
|
||||||
|
|
||||||
Key_F1, Key_F2, Key_F3, Key_F4,
|
Key_F1, Key_F2, Key_F3, Key_F4,
|
||||||
Key_F5, Key_F6, Key_F7, Key_F8,
|
Key_F5, Key_F6, Key_F7, Key_F8,
|
||||||
Key_F9, Key_F10, Key_F11, Key_F12,
|
Key_F9, Key_F10, Key_F11, Key_F12,
|
||||||
|
|
||||||
Key_Left, Key_Right, Key_Up, Key_Down,
|
Key_Left, Key_Right, Key_Up, Key_Down,
|
||||||
|
|
||||||
Key_Space, Key_Return,
|
Key_Space, Key_Return,
|
||||||
|
|
||||||
Key_PageUp, Key_PageDown,
|
Key_PageUp, Key_PageDown,
|
||||||
Key_Home, Key_End,
|
Key_Home, Key_End,
|
||||||
|
|
||||||
Key_Backspace, Key_Delete,
|
Key_Backspace, Key_Delete,
|
||||||
|
|
||||||
Key_Escape,
|
Key_Escape,
|
||||||
|
|
||||||
Key_MouseLeft, Key_MouseMiddle, Key_MouseRight,
|
Key_MouseLeft, Key_MouseMiddle, Key_MouseRight,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef u32 platform_modifiers;
|
typedef u32 platform_modifiers;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PlatformModifier_Ctrl = (1 << 0),
|
PlatformModifier_Ctrl = (1 << 0),
|
||||||
PlatformModifier_Shift = (1 << 1),
|
PlatformModifier_Shift = (1 << 1),
|
||||||
PlatformModifier_Alt = (1 << 2),
|
PlatformModifier_Alt = (1 << 2),
|
||||||
|
|
||||||
PlatformModifier_DoesNotMatter = -1
|
PlatformModifier_DoesNotMatter = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_event
|
struct platform_event
|
||||||
{
|
{
|
||||||
platform_event *Next;
|
platform_event *Next;
|
||||||
platform_event *Prev;
|
platform_event *Prev;
|
||||||
platform_event_type Type;
|
platform_event_type Type;
|
||||||
platform_modifiers Modifiers;
|
platform_modifiers Modifiers;
|
||||||
platform_key Key;
|
platform_key Key;
|
||||||
u32 Codepoint;
|
u32 Codepoint;
|
||||||
v2 P;
|
v2 P;
|
||||||
v2 Scroll;
|
v2 Scroll;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_event_list
|
struct platform_event_list
|
||||||
{
|
{
|
||||||
platform_event *First;
|
platform_event *First;
|
||||||
platform_event *Last;
|
platform_event *Last;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "generated/vn_platform.meta.h"
|
#include "generated/vn_platform.meta.h"
|
||||||
|
@ -139,58 +139,62 @@ static platform_api Platform;
|
||||||
#define RENDER_ALLOCATE_TEXTURE(name) render_handle name(v2_s32 Dim, render_texture_format Format, b32 GenerateMipmap, void *Data)
|
#define RENDER_ALLOCATE_TEXTURE(name) render_handle name(v2_s32 Dim, render_texture_format Format, b32 GenerateMipmap, void *Data)
|
||||||
typedef RENDER_ALLOCATE_TEXTURE(render_allocate_texture);
|
typedef RENDER_ALLOCATE_TEXTURE(render_allocate_texture);
|
||||||
|
|
||||||
|
#define RENDER_DEALLOCATE_TEXTURE(name) void name(render_handle Handle)
|
||||||
|
typedef RENDER_DEALLOCATE_TEXTURE(render_deallocate_texture);
|
||||||
|
|
||||||
#define RENDER_FILL_REGION(name) void name(render_handle Handle, v2_s32 DestP, v2_s32 DestDim, void *Data)
|
#define RENDER_FILL_REGION(name) void name(render_handle Handle, v2_s32 DestP, v2_s32 DestDim, void *Data)
|
||||||
typedef RENDER_FILL_REGION(render_fill_region);
|
typedef RENDER_FILL_REGION(render_fill_region);
|
||||||
|
|
||||||
struct vn_render_commands
|
struct vn_render_commands
|
||||||
{
|
{
|
||||||
render_allocate_texture *AllocateTexture;
|
render_allocate_texture *AllocateTexture;
|
||||||
render_fill_region *FillRegion;
|
render_deallocate_texture *DeallocateTexture;
|
||||||
|
render_fill_region *FillRegion;
|
||||||
render_handle WhiteTexture;
|
|
||||||
|
render_handle WhiteTexture;
|
||||||
u64 MaxPushBufferSize;
|
|
||||||
u8 *PushBufferBase;
|
u64 MaxPushBufferSize;
|
||||||
u8 *PushBufferAt;
|
u8 *PushBufferBase;
|
||||||
|
u8 *PushBufferAt;
|
||||||
|
|
||||||
#if VN_USE_INSTANCING
|
#if VN_USE_INSTANCING
|
||||||
s32 MaxInstancedQuadCount;
|
s32 MaxInstancedQuadCount;
|
||||||
instanced_quad *InstancedQuadBase;
|
instanced_quad *InstancedQuadBase;
|
||||||
s32 InstancedQuadCount;
|
s32 InstancedQuadCount;
|
||||||
#else
|
#else
|
||||||
s32 MaxQuadVertexCount;
|
s32 MaxQuadVertexCount;
|
||||||
quad_vertex *QuadVertexBase;
|
quad_vertex *QuadVertexBase;
|
||||||
s32 QuadVertexCount;
|
s32 QuadVertexCount;
|
||||||
|
|
||||||
s32 MaxQuadIndexCount;
|
s32 MaxQuadIndexCount;
|
||||||
s32 *QuadIndexBase;
|
s32 *QuadIndexBase;
|
||||||
s32 QuadIndexCount;
|
s32 QuadIndexCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
v2 RenderDim;
|
v2 RenderDim;
|
||||||
};
|
};
|
||||||
|
|
||||||
// sixten: Services the application provides to the platform
|
// sixten: Services the application provides to the platform
|
||||||
|
|
||||||
struct vn_input
|
struct vn_input
|
||||||
{
|
{
|
||||||
// sixten: Platform to application
|
// sixten: Platform to application
|
||||||
platform_event_list *EventList;
|
platform_event_list *EventList;
|
||||||
|
|
||||||
v2 MouseP;
|
v2 MouseP;
|
||||||
v2 dMouseP;
|
v2 dMouseP;
|
||||||
|
|
||||||
r32 dtForFrame;
|
r32 dtForFrame;
|
||||||
|
|
||||||
// sixten: Application to platform
|
// sixten: Application to platform
|
||||||
s32 RefreshRate;
|
s32 RefreshRate;
|
||||||
b32 ExitRequested;
|
b32 ExitRequested;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vn_memory
|
struct vn_memory
|
||||||
{
|
{
|
||||||
platform_api PlatformAPI;
|
platform_api PlatformAPI;
|
||||||
struct vn_state *State;
|
struct vn_state *State;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VN_UPDATE_AND_RENDER(name) void name(thread_context *ThreadContext, vn_memory *Memory, vn_input *Input, vn_render_commands *RenderCommands)
|
#define VN_UPDATE_AND_RENDER(name) void name(thread_context *ThreadContext, vn_memory *Memory, vn_input *Input, vn_render_commands *RenderCommands)
|
||||||
|
|
2093
code/vn_scene.cpp
449
code/vn_scene.h
|
@ -14,307 +14,312 @@
|
||||||
//~ sixten: Scene Compilation Types
|
//~ sixten: Scene Compilation Types
|
||||||
struct scene_compile_error
|
struct scene_compile_error
|
||||||
{
|
{
|
||||||
scene_compile_error *Next;
|
scene_compile_error *Next;
|
||||||
string Message;
|
string Message;
|
||||||
token Token;
|
token Token;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_compile_error_list
|
struct scene_compile_error_list
|
||||||
{
|
{
|
||||||
scene_compile_error *First;
|
scene_compile_error *First;
|
||||||
scene_compile_error *Last;
|
scene_compile_error *Last;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_opcode
|
enum scene_opcode
|
||||||
{
|
{
|
||||||
S_Op_Invalid = 0,
|
S_Op_Invalid = 0,
|
||||||
|
|
||||||
S_Op_Constant,
|
S_Op_Constant,
|
||||||
S_Op_Pop,
|
S_Op_Pop,
|
||||||
|
|
||||||
S_Op_Nil,
|
S_Op_Nil,
|
||||||
S_Op_True,
|
S_Op_True,
|
||||||
S_Op_False,
|
S_Op_False,
|
||||||
|
|
||||||
S_Op_Add,
|
S_Op_Add,
|
||||||
S_Op_Subtract,
|
S_Op_Subtract,
|
||||||
S_Op_Multiply,
|
S_Op_Multiply,
|
||||||
S_Op_Divide,
|
S_Op_Divide,
|
||||||
|
|
||||||
S_Op_Equal,
|
S_Op_Equal,
|
||||||
S_Op_Greater,
|
S_Op_Greater,
|
||||||
S_Op_Less,
|
S_Op_Less,
|
||||||
|
|
||||||
S_Op_Negate,
|
S_Op_Negate,
|
||||||
S_Op_Not,
|
S_Op_Not,
|
||||||
|
|
||||||
S_Op_DefineGlobal,
|
S_Op_DefineGlobal,
|
||||||
S_Op_GetGlobal,
|
S_Op_GetGlobal,
|
||||||
S_Op_SetGlobal,
|
S_Op_SetGlobal,
|
||||||
|
|
||||||
S_Op_Jump,
|
S_Op_Jump,
|
||||||
S_Op_JumpClose,
|
S_Op_JumpClose,
|
||||||
S_Op_AddBranch,
|
S_Op_AddBranch,
|
||||||
S_Op_Halt,
|
S_Op_Halt,
|
||||||
|
|
||||||
S_Op_AwaitInput,
|
S_Op_AwaitInput,
|
||||||
S_Op_ClearDialog,
|
S_Op_ClearDialog,
|
||||||
S_Op_LineEntry,
|
S_Op_LineEntry,
|
||||||
S_Op_ShowCharacter,
|
S_Op_ShowCharacter,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_bytecode_chunk
|
struct scene_bytecode_chunk
|
||||||
{
|
{
|
||||||
scene_bytecode_chunk *Next;
|
scene_bytecode_chunk *Next;
|
||||||
string Name;
|
string Name;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
u8 Data[4096];
|
u8 Data[4096];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_bytecode_bucket
|
struct scene_bytecode_bucket
|
||||||
{
|
{
|
||||||
scene_bytecode_chunk *First;
|
scene_bytecode_chunk *First;
|
||||||
scene_bytecode_chunk *Last;
|
scene_bytecode_chunk *Last;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_value_kind
|
enum scene_value_kind
|
||||||
{
|
{
|
||||||
S_ValueKind_Nil = 0,
|
S_ValueKind_Nil = 0,
|
||||||
S_ValueKind_Number,
|
S_ValueKind_Number,
|
||||||
S_ValueKind_Boolean,
|
S_ValueKind_Boolean,
|
||||||
S_ValueKind_Pointer,
|
S_ValueKind_Pointer,
|
||||||
S_ValueKind_SourceRef,
|
S_ValueKind_SourceRef,
|
||||||
S_ValueKind_String,
|
S_ValueKind_String,
|
||||||
S_ValueKind_Offset,
|
S_ValueKind_Offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_value
|
struct scene_value
|
||||||
{
|
{
|
||||||
scene_value_kind Kind;
|
scene_value_kind Kind;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
r64 Number;
|
r64 Number;
|
||||||
b32 Boolean;
|
b32 Boolean;
|
||||||
u64 Pointer;
|
u64 Pointer;
|
||||||
range1_s64 SourceRef;
|
range1_s64 SourceRef;
|
||||||
string String;
|
string String;
|
||||||
s64 Offset;
|
s64 Offset;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_value_chunk
|
struct scene_value_chunk
|
||||||
{
|
{
|
||||||
scene_value_chunk *Next;
|
scene_value_chunk *Next;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
scene_value Values[512];
|
scene_value Values[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_precedence
|
enum scene_precedence
|
||||||
{
|
{
|
||||||
S_Precedence_None,
|
S_Precedence_None,
|
||||||
S_Precedence_Assignment,
|
S_Precedence_Assignment,
|
||||||
S_Precedence_Or,
|
S_Precedence_Or,
|
||||||
S_Precedence_And,
|
S_Precedence_And,
|
||||||
S_Precedence_Equality,
|
S_Precedence_Equality,
|
||||||
S_Precedence_Comparison,
|
S_Precedence_Comparison,
|
||||||
S_Precedence_Term,
|
S_Precedence_Term,
|
||||||
S_Precedence_Factor,
|
S_Precedence_Factor,
|
||||||
S_Precedence_Unary,
|
S_Precedence_Unary,
|
||||||
S_Precedence_Call,
|
S_Precedence_Call,
|
||||||
S_Precedence_Primary,
|
S_Precedence_Primary,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void scene_parse_function(struct scene_compiler *Compiler, b32 CanAssign);
|
typedef void scene_parse_function(struct scene_compiler *Compiler, b32 CanAssign);
|
||||||
|
|
||||||
struct scene_parse_rule
|
struct scene_parse_rule
|
||||||
{
|
{
|
||||||
scene_parse_function *PrefixRule;
|
scene_parse_function *PrefixRule;
|
||||||
scene_parse_function *InfixRule;
|
scene_parse_function *InfixRule;
|
||||||
scene_precedence Precedence;
|
scene_precedence Precedence;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_emission_target_type
|
enum scene_emission_target_type
|
||||||
{
|
{
|
||||||
S_EmissionTarget_Raw,
|
S_EmissionTarget_Raw,
|
||||||
S_EmissionTarget_Named,
|
S_EmissionTarget_Named,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_emission_target
|
struct scene_emission_target
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
scene_bytecode_bucket *Bucket;
|
scene_bytecode_bucket *Bucket;
|
||||||
scene_emission_target_type Type;
|
scene_emission_target_type Type;
|
||||||
string Name;
|
string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_branch_case
|
struct scene_branch_case
|
||||||
{
|
{
|
||||||
scene_branch_case *Next;
|
scene_branch_case *Next;
|
||||||
token Name;
|
token Name;
|
||||||
scene_bytecode_bucket Bucket;
|
scene_bytecode_bucket Bucket;
|
||||||
scene_value *OffsetValue;
|
scene_value *OffsetValue;
|
||||||
scene_value *EndOffsetValue;
|
scene_value *EndOffsetValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_character_action
|
struct scene_character_action
|
||||||
{
|
{
|
||||||
scene_character_action *Next;
|
scene_character_action *Next;
|
||||||
scene_character_action *Prev;
|
scene_character_action *Prev;
|
||||||
|
|
||||||
string Target;
|
string Target;
|
||||||
character_state State;
|
character_state State;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_compiler
|
struct scene_compiler
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
|
|
||||||
b32 InPanicMode;
|
b32 InPanicMode;
|
||||||
b32 EncounteredError;
|
b32 EncounteredError;
|
||||||
scene_compile_error_list Errors;
|
scene_compile_error_list Errors;
|
||||||
|
|
||||||
string Text;
|
string Text;
|
||||||
token *TokensBegin;
|
token *TokensBegin;
|
||||||
token *TokensEnd;
|
token *TokensEnd;
|
||||||
token *At;
|
token *At;
|
||||||
|
|
||||||
scene_bytecode_bucket GlobalScope;
|
scene_bytecode_bucket GlobalScope;
|
||||||
scene_bytecode_bucket ProcBuckets[32];
|
scene_bytecode_bucket ProcBuckets[32];
|
||||||
|
|
||||||
scene_emission_target TargetStack[16];
|
scene_emission_target TargetStack[16];
|
||||||
s32 TargetStackIndex;
|
s32 TargetStackIndex;
|
||||||
|
|
||||||
scene_value_chunk *FirstValueChunk;
|
scene_value_chunk *FirstValueChunk;
|
||||||
scene_value_chunk *LastValueChunk;
|
scene_value_chunk *LastValueChunk;
|
||||||
s64 ValueCount;
|
s64 ValueCount;
|
||||||
|
|
||||||
|
string NavFileName;
|
||||||
|
asset_id BackgroundTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ sixten: Compiled Scene Types
|
//~ sixten: Compiled Scene Types
|
||||||
struct scene_proc
|
struct scene_proc
|
||||||
{
|
{
|
||||||
// sixten: scene data
|
// sixten: scene data
|
||||||
string Name;
|
string Name;
|
||||||
u8 *Data;
|
u8 *Data;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
|
|
||||||
// sixten: hash link
|
// sixten: hash link
|
||||||
scene_proc *Next;
|
scene_proc *Next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_proc_bucket
|
struct scene_proc_bucket
|
||||||
{
|
{
|
||||||
scene_proc *First;
|
scene_proc *First;
|
||||||
scene_proc *Last;
|
scene_proc *Last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct compiled_scene
|
struct compiled_scene
|
||||||
{
|
{
|
||||||
scene_proc *GlobalScope;
|
scene_proc *GlobalScope;
|
||||||
scene_proc_bucket Buckets[16];
|
scene_proc_bucket Buckets[16];
|
||||||
scene_value *Values;
|
scene_value *Values;
|
||||||
s64 ValueCount;
|
s64 ValueCount;
|
||||||
string Source;
|
string Source;
|
||||||
scene_compile_error_list Errors;
|
string NavFileName;
|
||||||
b32 IsValid;
|
asset_id BackgroundTexture;
|
||||||
|
scene_compile_error_list Errors;
|
||||||
|
b32 IsValid;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ sixten: Scene Runtime Types
|
//~ sixten: Scene Runtime Types
|
||||||
struct scene_runtime_error
|
struct scene_runtime_error
|
||||||
{
|
{
|
||||||
scene_runtime_error *Next;
|
scene_runtime_error *Next;
|
||||||
scene_runtime_error *Prev;
|
scene_runtime_error *Prev;
|
||||||
string Message;
|
string Message;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_runtime_error_list
|
struct scene_runtime_error_list
|
||||||
{
|
{
|
||||||
scene_runtime_error *First;
|
scene_runtime_error *First;
|
||||||
scene_runtime_error *Last;
|
scene_runtime_error *Last;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_named_value
|
struct scene_named_value
|
||||||
{
|
{
|
||||||
b32 Initialized;
|
b32 Initialized;
|
||||||
string Name;
|
string Name;
|
||||||
scene_value Value;
|
scene_value Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_named_value_node
|
struct scene_named_value_node
|
||||||
{
|
{
|
||||||
scene_named_value_node *Next;
|
scene_named_value_node *Next;
|
||||||
scene_named_value_node *Prev;
|
scene_named_value_node *Prev;
|
||||||
scene_named_value NamedValue;
|
scene_named_value NamedValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_named_value_bucket
|
struct scene_named_value_bucket
|
||||||
{
|
{
|
||||||
s64 Count;
|
s64 Count;
|
||||||
scene_named_value_node *First;
|
scene_named_value_node *First;
|
||||||
scene_named_value_node *Last;
|
scene_named_value_node *Last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_runtime_result
|
struct scene_runtime_result
|
||||||
{
|
{
|
||||||
b32 HadError;
|
b32 HadError;
|
||||||
b32 ReachedAwait;
|
b32 ReachedAwait;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_textbox_action_kind
|
enum scene_textbox_action_kind
|
||||||
{
|
{
|
||||||
S_TextboxActionKind_Set,
|
S_TextboxActionKind_Set,
|
||||||
S_TextboxActionKind_Append,
|
S_TextboxActionKind_Append,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_textbox_action
|
struct scene_textbox_action
|
||||||
{
|
{
|
||||||
scene_textbox_action *Next;
|
scene_textbox_action *Next;
|
||||||
scene_textbox_action_kind Kind;
|
scene_textbox_action_kind Kind;
|
||||||
string String;
|
string String;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct branch_case
|
struct branch_case
|
||||||
{
|
{
|
||||||
string Name;
|
string Name;
|
||||||
s64 Offset;
|
s64 Offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_runtime_stack
|
struct scene_runtime_stack
|
||||||
{
|
{
|
||||||
scene_value Stack[128];
|
scene_value Stack[128];
|
||||||
s32 Count;
|
s32 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_runtime
|
struct scene_runtime
|
||||||
{
|
{
|
||||||
compiled_scene Compiled;
|
compiled_scene Compiled;
|
||||||
|
|
||||||
// sixten: runtime state
|
// sixten: runtime state
|
||||||
arena *RuntimeArena;
|
arena *RuntimeArena;
|
||||||
scene_proc *CurrentProc;
|
scene_proc *CurrentProc;
|
||||||
s64 IP;
|
s64 IP;
|
||||||
scene_runtime_stack Stack;
|
scene_runtime_stack Stack;
|
||||||
scene_named_value_bucket GlobalVariableBuckets[16];
|
scene_named_value_bucket GlobalVariableBuckets[16];
|
||||||
scene_named_value_bucket GlobalVariableFreeList;
|
scene_named_value_bucket GlobalVariableFreeList;
|
||||||
|
|
||||||
// sixten: errors
|
// sixten: errors
|
||||||
arena *ErrorArena;
|
arena *ErrorArena;
|
||||||
scene_runtime_error_list Errors;
|
scene_runtime_error_list Errors;
|
||||||
|
|
||||||
// sixten: branches
|
// sixten: branches
|
||||||
branch_case Branches[16];
|
branch_case Branches[16];
|
||||||
s64 BranchCount;
|
s64 BranchCount;
|
||||||
|
|
||||||
// sixten: result
|
// sixten: result
|
||||||
scene_runtime_result LastResult;
|
scene_runtime_result LastResult;
|
||||||
scene_textbox_action *FirstTextboxAction;
|
scene_textbox_action *FirstTextboxAction;
|
||||||
scene_textbox_action *LastTextboxAction;
|
scene_textbox_action *LastTextboxAction;
|
||||||
scene_character_action *FirstCharacterAction;
|
scene_character_action *FirstCharacterAction;
|
||||||
scene_character_action *LastCharacterAction;
|
scene_character_action *LastCharacterAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -323,57 +328,57 @@ struct scene_runtime
|
||||||
//- sixten: value helpers
|
//- sixten: value helpers
|
||||||
inline scene_value S_MakeNil(void)
|
inline scene_value S_MakeNil(void)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_Nil;
|
Result.Kind = S_ValueKind_Nil;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakeNumber(r64 Value)
|
inline scene_value S_MakeNumber(r64 Value)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_Number;
|
Result.Kind = S_ValueKind_Number;
|
||||||
Result.Number = Value;
|
Result.Number = Value;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakeBoolean(b32 Value)
|
inline scene_value S_MakeBoolean(b32 Value)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_Boolean;
|
Result.Kind = S_ValueKind_Boolean;
|
||||||
Result.Boolean = Value;
|
Result.Boolean = Value;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakePointer(void *Value)
|
inline scene_value S_MakePointer(void *Value)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_Pointer;
|
Result.Kind = S_ValueKind_Pointer;
|
||||||
Result.Pointer = PointerToU64(Value);
|
Result.Pointer = PointerToU64(Value);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakeSourceRef(token Token)
|
inline scene_value S_MakeSourceRef(token Token)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_SourceRef;
|
Result.Kind = S_ValueKind_SourceRef;
|
||||||
Result.SourceRef = Token.Range;
|
Result.SourceRef = Token.Range;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakeSourceRef(range1_s64 Range)
|
inline scene_value S_MakeSourceRef(range1_s64 Range)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_SourceRef;
|
Result.Kind = S_ValueKind_SourceRef;
|
||||||
Result.SourceRef = Range;
|
Result.SourceRef = Range;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_value S_MakeOffset(s64 Offset)
|
inline scene_value S_MakeOffset(s64 Offset)
|
||||||
{
|
{
|
||||||
scene_value Result;
|
scene_value Result;
|
||||||
Result.Kind = S_ValueKind_Offset;
|
Result.Kind = S_ValueKind_Offset;
|
||||||
Result.Offset = Offset;
|
Result.Offset = Offset;
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: error messaging
|
//- sixten: error messaging
|
||||||
|
@ -392,21 +397,21 @@ static scene_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler,
|
||||||
|
|
||||||
inline scene_emission_target S_RawEmissionTarget(arena *Arena, scene_bytecode_bucket *Bucket)
|
inline scene_emission_target S_RawEmissionTarget(arena *Arena, scene_bytecode_bucket *Bucket)
|
||||||
{
|
{
|
||||||
scene_emission_target Target = {};
|
scene_emission_target Target = {};
|
||||||
Target.Arena = Arena;
|
Target.Arena = Arena;
|
||||||
Target.Bucket = Bucket;
|
Target.Bucket = Bucket;
|
||||||
Target.Type = S_EmissionTarget_Raw;
|
Target.Type = S_EmissionTarget_Raw;
|
||||||
return(Target);
|
return(Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline scene_emission_target S_NamedEmissionTarget(arena *Arena, scene_bytecode_bucket *Bucket, string Name)
|
inline scene_emission_target S_NamedEmissionTarget(arena *Arena, scene_bytecode_bucket *Bucket, string Name)
|
||||||
{
|
{
|
||||||
scene_emission_target Target = {};
|
scene_emission_target Target = {};
|
||||||
Target.Arena = Arena;
|
Target.Arena = Arena;
|
||||||
Target.Bucket = Bucket;
|
Target.Bucket = Bucket;
|
||||||
Target.Type = S_EmissionTarget_Named;
|
Target.Type = S_EmissionTarget_Named;
|
||||||
Target.Name = Name;
|
Target.Name = Name;
|
||||||
return(Target);
|
return(Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: parsing helpers
|
//- sixten: parsing helpers
|
||||||
|
@ -422,6 +427,8 @@ static void S_ParseDeclaration(scene_compiler *Compiler);
|
||||||
static void S_ParseVariableDeclaration(scene_compiler *Compiler);
|
static void S_ParseVariableDeclaration(scene_compiler *Compiler);
|
||||||
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign);
|
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign);
|
||||||
static void S_ParseNamedVariable(scene_compiler *Compiler, token Token, b32 CanAssign);
|
static void S_ParseNamedVariable(scene_compiler *Compiler, token Token, b32 CanAssign);
|
||||||
|
static void S_ParseNavFilePath(scene_compiler *Compiler);
|
||||||
|
static void S_ParseBackgroundAsset(scene_compiler *Compiler);
|
||||||
static void S_ParseLineEntry(scene_compiler *Compiler);
|
static void S_ParseLineEntry(scene_compiler *Compiler);
|
||||||
static void S_ParseJumpStatement(scene_compiler *Compiler);
|
static void S_ParseJumpStatement(scene_compiler *Compiler);
|
||||||
static void S_ParseBranchStatement(scene_compiler *Compiler);
|
static void S_ParseBranchStatement(scene_compiler *Compiler);
|
||||||
|
|
|
@ -5,100 +5,101 @@
|
||||||
|
|
||||||
struct textbox
|
struct textbox
|
||||||
{
|
{
|
||||||
string String;
|
string String;
|
||||||
s64 Capacity;
|
s64 Capacity;
|
||||||
r32 CharsRevealedT;
|
r32 CharsRevealedT;
|
||||||
r32 CharsRevealed;
|
r32 CharsRevealed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_view_character_texture_info
|
struct scene_view_character_texture_info
|
||||||
{
|
{
|
||||||
render_handle Texture;
|
render_handle Texture;
|
||||||
r32 Scale;
|
r32 Scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_view_character_data
|
struct scene_view_character_data
|
||||||
{
|
{
|
||||||
string Name;
|
string Name;
|
||||||
|
|
||||||
scene_view_character_texture_info Info;
|
scene_view_character_texture_info Info;
|
||||||
|
|
||||||
b32 Active;
|
b32 Active;
|
||||||
r32 ActiveT;
|
r32 ActiveT;
|
||||||
|
|
||||||
b32 Talking;
|
b32 Talking;
|
||||||
r32 TalkingT;
|
r32 TalkingT;
|
||||||
|
|
||||||
r32 PctP;
|
r32 PctP;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scene_nav_action_kind
|
enum scene_nav_action_kind
|
||||||
{
|
{
|
||||||
S_NavAction_None,
|
S_NavAction_None,
|
||||||
S_NavAction_Proc,
|
S_NavAction_Proc,
|
||||||
S_NavAction_Scene,
|
S_NavAction_Scene,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_nav_action
|
struct scene_nav_action
|
||||||
{
|
{
|
||||||
scene_nav_action_kind Kind;
|
scene_nav_action_kind Kind;
|
||||||
string Content;
|
string Content;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_nav_item
|
struct scene_nav_item
|
||||||
{
|
{
|
||||||
asset_id TextureID;
|
asset_id TextureID;
|
||||||
r32 Scale;
|
r32 Scale;
|
||||||
v2_r32 Origin;
|
v2_r32 Origin;
|
||||||
v2_r32 P;
|
v2_r32 P;
|
||||||
string HoverText;
|
string HoverText;
|
||||||
scene_nav_action Action;
|
scene_nav_action Action;
|
||||||
};
|
};
|
||||||
|
|
||||||
global read_only scene_nav_item G_DefaultSceneNavItem =
|
typedef u8 scene_nav_item_op;
|
||||||
|
enum
|
||||||
{
|
{
|
||||||
AssetID_ArthurNormal,
|
S_NavItemOp_None = 0,
|
||||||
0.01f,
|
S_NavItemOp_TextureID,
|
||||||
V2R32(0.5f, 1.0f),
|
S_NavItemOp_Scale,
|
||||||
V2R32(0.0f, 0.0f),
|
S_NavItemOp_Origin,
|
||||||
StrLit(""),
|
S_NavItemOp_P,
|
||||||
S_NavAction_None
|
S_NavItemOp_HoverText,
|
||||||
|
S_NavItemOp_Action,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_nav
|
struct scene_nav
|
||||||
{
|
{
|
||||||
scene_nav_item *Items;
|
scene_nav_item *Items;
|
||||||
s32 ItemCount;
|
s32 ItemCount;
|
||||||
s32 ItemMax;
|
s32 ItemMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_view
|
struct scene_view
|
||||||
{
|
{
|
||||||
arena *SceneArena;
|
arena *SceneArena;
|
||||||
|
|
||||||
//- sixten: state
|
//- sixten: state
|
||||||
scene_runtime Runtime;
|
scene_runtime Runtime;
|
||||||
textbox Textbox;
|
textbox Textbox;
|
||||||
|
|
||||||
u8 LastTalkingCharacterBuffer[32];
|
//- sixten: characters
|
||||||
string LastTalkingCharacter;
|
s32 CharacterCount;
|
||||||
|
scene_view_character_data Characters[16];
|
||||||
b32 CharacterIsTalking;
|
|
||||||
r32 CharacterIsTalkingT;
|
//- sixten: nav items
|
||||||
|
scene_nav_item *NavItems;
|
||||||
s32 OnscreenCharacterCount;
|
u64 NavItemCount;
|
||||||
scene_view_character_data OnscreenCharacters[16];
|
|
||||||
|
//- sixten: input per frame
|
||||||
//- sixten: input per frame
|
platform_event_list *EventList;
|
||||||
platform_event_list *EventList;
|
r32 dtForFrame;
|
||||||
r32 dtForFrame;
|
|
||||||
|
//- sixten: temporary texture hub
|
||||||
//- sixten: temporary texture hub
|
render_handle BackgroundTexture;
|
||||||
render_handle BackgroundTexture;
|
render_handle TestHappy;
|
||||||
render_handle TestHappy;
|
render_handle TestNormal;
|
||||||
render_handle TestNormal;
|
render_handle MonikaLeaning;
|
||||||
render_handle MonikaLeaning;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void SV_SetState(scene_view *View);
|
static void SV_SetState(scene_view *View);
|
||||||
|
@ -111,6 +112,9 @@ static void SV_Init(scene_view *View, arena *TextboxArena);
|
||||||
|
|
||||||
static b32 SV_CurrentlyInProc(void);
|
static b32 SV_CurrentlyInProc(void);
|
||||||
|
|
||||||
|
static scene_view_character_data *SV_FindTalkingCharacter(void);
|
||||||
|
static string SV_DisplayNameFromCharacter(scene_view_character_data *Character);
|
||||||
|
|
||||||
static void SV_DrawBackground(scene_view *SceneView, ui_box *Box, render_group *Group);
|
static void SV_DrawBackground(scene_view *SceneView, ui_box *Box, render_group *Group);
|
||||||
|
|
||||||
static ui_signal SV_BuildNavItem(scene_nav_item * Item, r32 GlobalScale, v2_r32 GlobalDim);
|
static ui_signal SV_BuildNavItem(scene_nav_item * Item, r32 GlobalScale, v2_r32 GlobalDim);
|
||||||
|
|
|
@ -7,55 +7,55 @@
|
||||||
|
|
||||||
struct thread_context
|
struct thread_context
|
||||||
{
|
{
|
||||||
memory_arena Arenas[2];
|
memory_arena Arenas[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
per_thread thread_context *ThreadLocal_ThreadContext = 0;
|
per_thread thread_context *ThreadLocal_ThreadContext = 0;
|
||||||
|
|
||||||
inline void SetThreadContext(thread_context *Context)
|
inline void SetThreadContext(thread_context *Context)
|
||||||
{
|
{
|
||||||
ThreadLocal_ThreadContext = Context;
|
ThreadLocal_ThreadContext = Context;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline thread_context *GetThreadContext(void)
|
inline thread_context *GetThreadContext(void)
|
||||||
{
|
{
|
||||||
return(ThreadLocal_ThreadContext);
|
return(ThreadLocal_ThreadContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
static temporary_memory GetScratch(memory_arena **Conflicts = 0, u64 ConflictCount = 0)
|
static temporary_memory GetScratch(memory_arena **Conflicts = 0, u64 ConflictCount = 0)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = {};
|
temporary_memory Scratch = {};
|
||||||
thread_context *Context = GetThreadContext();
|
thread_context *Context = GetThreadContext();
|
||||||
|
|
||||||
for(u64 ArenaIndex = 0;
|
for(u64 ArenaIndex = 0;
|
||||||
ArenaIndex < ArrayCount(Context->Arenas);
|
ArenaIndex < ArrayCount(Context->Arenas);
|
||||||
++ArenaIndex)
|
++ArenaIndex)
|
||||||
{
|
{
|
||||||
b32 FoundConflict = false;
|
b32 FoundConflict = false;
|
||||||
for(u64 ConflictIndex = 0;
|
for(u64 ConflictIndex = 0;
|
||||||
ConflictIndex < ConflictCount;
|
ConflictIndex < ConflictCount;
|
||||||
++ConflictIndex)
|
++ConflictIndex)
|
||||||
{
|
{
|
||||||
memory_arena *Conflict = Conflicts[ConflictIndex];
|
memory_arena *Conflict = Conflicts[ConflictIndex];
|
||||||
if(Conflict == Context->Arenas + ArenaIndex)
|
if(Conflict == Context->Arenas + ArenaIndex)
|
||||||
{
|
{
|
||||||
FoundConflict = true;
|
FoundConflict = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!FoundConflict)
|
if(!FoundConflict)
|
||||||
{
|
{
|
||||||
Scratch = BeginTemporaryMemory(Context->Arenas + ArenaIndex);
|
Scratch = BeginTemporaryMemory(Context->Arenas + ArenaIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(Scratch.Arena);
|
Assert(Scratch.Arena);
|
||||||
|
|
||||||
return(Scratch);
|
return(Scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ReleaseScratch(Scratch) EndTemporaryMemory(Scratch)
|
#define ReleaseScratch(Scratch) EndTemp(Scratch)
|
||||||
|
|
||||||
#endif //VN_THREAD_CONTEXT_H
|
#endif //VN_THREAD_CONTEXT_H
|
||||||
|
|
|
@ -3,38 +3,38 @@
|
||||||
|
|
||||||
static string T_StringFromToken(string Text, token Token)
|
static string T_StringFromToken(string Text, token Token)
|
||||||
{
|
{
|
||||||
string Result = Substring(Text, Token.Range);
|
string Result = Substring(Text, Token.Range);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void T_TokenChunkListPush(arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode)
|
static void T_TokenChunkListPush(arena *Arena, token_chunk_list *List, token Token, s64 MaxTokenCountPerNode)
|
||||||
{
|
{
|
||||||
token_chunk_node *Node = List->Last;
|
token_chunk_node *Node = List->Last;
|
||||||
if(!Node || Node->Count >= Node->MaxCount)
|
if(!Node || Node->Count >= Node->MaxCount)
|
||||||
{
|
{
|
||||||
Node = PushStruct(Arena, token_chunk_node);
|
Node = PushStruct(Arena, token_chunk_node);
|
||||||
Node->Count = 0;
|
Node->Count = 0;
|
||||||
Node->MaxCount = MaxTokenCountPerNode;
|
Node->MaxCount = MaxTokenCountPerNode;
|
||||||
Node->Tokens = PushArrayNoClear(Arena, token, Node->MaxCount);
|
Node->Tokens = PushArrayNoClear(Arena, token, Node->MaxCount);
|
||||||
QueuePush(List->First, List->Last, Node);
|
QueuePush(List->First, List->Last, Node);
|
||||||
}
|
}
|
||||||
Node->Tokens[Node->Count] = Token;
|
Node->Tokens[Node->Count] = Token;
|
||||||
Node->Count += 1;
|
Node->Count += 1;
|
||||||
List->Count += 1;
|
List->Count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static token_array T_TokenArrayFromList(arena *Arena, token_chunk_list *List)
|
static token_array T_TokenArrayFromList(arena *Arena, token_chunk_list *List)
|
||||||
{
|
{
|
||||||
token_array Result = {};
|
token_array Result = {};
|
||||||
Result.Tokens = PushArrayNoClear(Arena, token, List->Count);
|
Result.Tokens = PushArrayNoClear(Arena, token, List->Count);
|
||||||
Result.Count = List->Count;
|
Result.Count = List->Count;
|
||||||
s64 Index = 0;
|
s64 Index = 0;
|
||||||
for(token_chunk_node *Node = List->First; Node != 0; Node = Node->Next)
|
for(token_chunk_node *Node = List->First; Node != 0; Node = Node->Next)
|
||||||
{
|
{
|
||||||
Copy(Result.Tokens + Index, Node->Tokens, sizeof(token)*Node->Count);
|
Copy(Result.Tokens + Index, Node->Tokens, sizeof(token)*Node->Count);
|
||||||
Index += Node->Count;
|
Index += Node->Count;
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -42,11 +42,11 @@ static token_array T_TokenArrayFromList(arena *Arena, token_chunk_list *List)
|
||||||
|
|
||||||
static void T_MessageListPush(arena *Arena, tokenizer_message_list *List, tokenizer_message_kind Kind, s64 Offset, string String)
|
static void T_MessageListPush(arena *Arena, tokenizer_message_list *List, tokenizer_message_kind Kind, s64 Offset, string String)
|
||||||
{
|
{
|
||||||
tokenizer_message *Message = PushStructNoClear(Arena, tokenizer_message);
|
tokenizer_message *Message = PushStructNoClear(Arena, tokenizer_message);
|
||||||
Message->Kind = Kind;
|
Message->Kind = Kind;
|
||||||
Message->Offset = Offset;
|
Message->Offset = Offset;
|
||||||
Message->String = String;
|
Message->String = String;
|
||||||
QueuePush(List->First, List->Last, Message);
|
QueuePush(List->First, List->Last, Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -54,262 +54,263 @@ static void T_MessageListPush(arena *Arena, tokenizer_message_list *List, tokeni
|
||||||
|
|
||||||
static tokenize_result T_TokenizeFromText(arena *Arena, string Text, tokenizer_filter_function *ExcludeFilter)
|
static tokenize_result T_TokenizeFromText(arena *Arena, string Text, tokenizer_filter_function *ExcludeFilter)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(&Arena, 1);
|
temp Scratch = GetScratch(&Arena, 1);
|
||||||
token_chunk_list Tokens = {};
|
token_chunk_list Tokens = {};
|
||||||
tokenizer_message_list Messages = {};
|
tokenizer_message_list Messages = {};
|
||||||
u8 *TextStart = Text.Data;
|
u8 *TextStart = Text.Data;
|
||||||
u8 *TextEnd = TextStart + Text.Count;
|
u8 *TextEnd = TextStart + Text.Count;
|
||||||
u8 *Byte = TextStart;
|
u8 *Byte = TextStart;
|
||||||
s64 Line = 0;
|
s64 Line = 0;
|
||||||
|
|
||||||
//- sixten: scan string & produce tokens
|
//- sixten: scan string & produce tokens
|
||||||
for(;Byte < TextEnd;)
|
for(;Byte < TextEnd;)
|
||||||
{
|
{
|
||||||
token_kind TokenKind = TokenKind_None;
|
token_kind TokenKind = TokenKind_None;
|
||||||
u8 *TokenStart = 0;
|
u8 *TokenStart = 0;
|
||||||
u8 *TokenEnd = 0;
|
u8 *TokenEnd = 0;
|
||||||
|
|
||||||
//- sixten: whitespace
|
//- sixten: whitespace
|
||||||
if(TokenKind == TokenKind_None && (*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
if(TokenKind == TokenKind_None && (*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_Whitespace;
|
TokenKind = TokenKind_Whitespace;
|
||||||
TokenStart = Byte;
|
TokenStart = Byte;
|
||||||
TokenEnd = Byte;
|
TokenEnd = Byte;
|
||||||
Byte += 1;
|
Byte += 1;
|
||||||
for(;Byte <= TextEnd; Byte += 1)
|
for(;Byte <= TextEnd; Byte += 1)
|
||||||
{
|
{
|
||||||
TokenEnd += 1;
|
TokenEnd += 1;
|
||||||
if(Byte == TextEnd || !(*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
if(Byte == TextEnd || !(*Byte == ' ' || *Byte == '\t' || *Byte == '\v' || *Byte == '\r'))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: newlines
|
//- sixten: newlines
|
||||||
if(TokenKind == TokenKind_None && *Byte == '\n')
|
if(TokenKind == TokenKind_None && *Byte == '\n')
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_Newline;
|
TokenKind = TokenKind_Newline;
|
||||||
TokenStart = Byte;
|
TokenStart = Byte;
|
||||||
TokenEnd = Byte + 1;
|
TokenEnd = Byte + 1;
|
||||||
Line += 1;
|
Line += 1;
|
||||||
Byte += 1;
|
Byte += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: single-line comments
|
//- sixten: single-line comments
|
||||||
if(TokenKind == TokenKind_None && (Byte[0] == '/' && Byte[1] == '/'))
|
if(TokenKind == TokenKind_None && (Byte[0] == '/' && Byte[1] == '/'))
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_Comment;;
|
TokenKind = TokenKind_Comment;;
|
||||||
TokenStart = Byte;
|
TokenStart = Byte;
|
||||||
TokenEnd = Byte + 2;
|
TokenEnd = Byte + 2;
|
||||||
Byte += 2;
|
Byte += 2;
|
||||||
for(;Byte <= TextEnd; Byte += 1)
|
for(;Byte <= TextEnd; Byte += 1)
|
||||||
{
|
{
|
||||||
if(Byte == TextEnd || *Byte == '\n' || *Byte == '\r')
|
if(Byte == TextEnd || *Byte == '\n' || *Byte == '\r')
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TokenEnd += 1;
|
TokenEnd += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: multi-line comments
|
//- sixten: multi-line comments
|
||||||
if(TokenKind == TokenKind_None && (Byte+1 < TextEnd && Byte[0] == '/' && Byte[1] == '*'))
|
if(TokenKind == TokenKind_None && (Byte+1 < TextEnd && Byte[0] == '/' && Byte[1] == '*'))
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_Comment;
|
TokenKind = TokenKind_Comment;
|
||||||
TokenStart = Byte;
|
TokenStart = Byte;
|
||||||
TokenEnd = Byte + 2;
|
TokenEnd = Byte + 2;
|
||||||
Byte += 2;
|
Byte += 2;
|
||||||
for(;Byte <= TextEnd; Byte += 1)
|
for(;Byte <= TextEnd; Byte += 1)
|
||||||
{
|
{
|
||||||
// sixten(NOTE): This could potentially be wrong. The TokenEnd += 1 statement could currently make the token include the EOF.
|
// sixten(NOTE): This could potentially be wrong. The TokenEnd += 1 statement could currently make the token include the EOF.
|
||||||
if(Byte == TextEnd)
|
if(Byte == TextEnd)
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_BrokenComment;
|
TokenKind = TokenKind_BrokenComment;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TokenEnd += 1;
|
TokenEnd += 1;
|
||||||
if(Byte+1 < TextEnd && Byte[0] == '*' && Byte[1] == '/')
|
if(Byte+1 < TextEnd && Byte[0] == '*' && Byte[1] == '/')
|
||||||
{
|
{
|
||||||
TokenEnd += 1;
|
TokenEnd += 1;
|
||||||
Byte += 2;
|
Byte += 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: identifiers
|
//- sixten: identifiers
|
||||||
if(TokenKind == TokenKind_None && (('A' <= *Byte && *Byte <= 'Z') ||
|
if(TokenKind == TokenKind_None && (('A' <= *Byte && *Byte <= 'Z') ||
|
||||||
('a' <= *Byte && *Byte <= 'z') ||
|
('a' <= *Byte && *Byte <= 'z') ||
|
||||||
(UTF8Lengths[*Byte>>3] > 1) ||
|
(UTF8Lengths[*Byte>>3] > 1) ||
|
||||||
*Byte == '_'))
|
*Byte == '_'))
|
||||||
{
|
{
|
||||||
TokenKind = TokenKind_Identifier;
|
TokenKind = TokenKind_Identifier;
|
||||||
TokenStart = Byte;
|
TokenStart = Byte;
|
||||||
TokenEnd = Byte;
|
TokenEnd = Byte;
|
||||||
Byte += UTF8Lengths[*Byte>>3];
|
Byte += UTF8Lengths[*Byte>>3];
|
||||||
for(;Byte <= TextEnd; Byte += UTF8Lengths[*Byte>>3])
|
for(;Byte <= TextEnd; Byte += UTF8Lengths[*Byte>>3])
|
||||||
{
|
{
|
||||||
if(Byte == TextEnd || !(('A' <= *Byte && *Byte <= 'Z') ||
|
if(Byte == TextEnd || !(('A' <= *Byte && *Byte <= 'Z') ||
|
||||||
('a' <= *Byte && *Byte <= 'z') ||
|
('a' <= *Byte && *Byte <= 'z') ||
|
||||||
('0' <= *Byte && *Byte <= '9') ||
|
('0' <= *Byte && *Byte <= '9') ||
|
||||||
(UTF8Lengths[*Byte>>3] > 1) ||
|
(UTF8Lengths[*Byte>>3] > 1) ||
|
||||||
*Byte == '_'))
|
*Byte == '_'))
|
||||||
{
|
{
|
||||||
TokenEnd = Byte;
|
TokenEnd = Byte;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string String = MakeString(TokenStart, TokenEnd-TokenStart);
|
string String = MakeString(TokenStart, TokenEnd-TokenStart);
|
||||||
if(0) {}
|
if(0) {}
|
||||||
else if(AreEqual(String, StrLit("and"))) { TokenKind = TokenKind_And; }
|
else if(AreEqual(String, StrLit("and"))) { TokenKind = TokenKind_And; }
|
||||||
else if(AreEqual(String, StrLit("branch"))) { TokenKind = TokenKind_Branch; }
|
else if(AreEqual(String, StrLit("branch"))) { TokenKind = TokenKind_Branch; }
|
||||||
else if(AreEqual(String, StrLit("else"))) { TokenKind = TokenKind_Else; }
|
else if(AreEqual(String, StrLit("else"))) { TokenKind = TokenKind_Else; }
|
||||||
else if(AreEqual(String, StrLit("false"))) { TokenKind = TokenKind_False; }
|
else if(AreEqual(String, StrLit("false"))) { TokenKind = TokenKind_False; }
|
||||||
else if(AreEqual(String, StrLit("for"))) { TokenKind = TokenKind_For; }
|
else if(AreEqual(String, StrLit("for"))) { TokenKind = TokenKind_For; }
|
||||||
else if(AreEqual(String, StrLit("if"))) { TokenKind = TokenKind_If; }
|
else if(AreEqual(String, StrLit("if"))) { TokenKind = TokenKind_If; }
|
||||||
else if(AreEqual(String, StrLit("jump"))) { TokenKind = TokenKind_Jump; }
|
else if(AreEqual(String, StrLit("jump"))) { TokenKind = TokenKind_Jump; }
|
||||||
else if(AreEqual(String, StrLit("or"))) { TokenKind = TokenKind_Or; }
|
else if(AreEqual(String, StrLit("or"))) { TokenKind = TokenKind_Or; }
|
||||||
else if(AreEqual(String, StrLit("proc"))) { TokenKind = TokenKind_Proc; }
|
else if(AreEqual(String, StrLit("proc"))) { TokenKind = TokenKind_Proc; }
|
||||||
else if(AreEqual(String, StrLit("true"))) { TokenKind = TokenKind_True; }
|
else if(AreEqual(String, StrLit("true"))) { TokenKind = TokenKind_True; }
|
||||||
else if(AreEqual(String, StrLit("var"))) { TokenKind = TokenKind_Var; }
|
else if(AreEqual(String, StrLit("var"))) { TokenKind = TokenKind_Var; }
|
||||||
else if(AreEqual(String, StrLit("while"))) { TokenKind = TokenKind_While; }
|
else if(AreEqual(String, StrLit("while"))) { TokenKind = TokenKind_While; }
|
||||||
else if(AreEqual(String, StrLit("define"))) { TokenKind = TokenKind_Define; }
|
else if(AreEqual(String, StrLit("nav"))) { TokenKind = TokenKind_Nav; }
|
||||||
}
|
else if(AreEqual(String, StrLit("background"))) { TokenKind = TokenKind_Background; }
|
||||||
|
}
|
||||||
//- sixten: numerics
|
|
||||||
if(TokenKind == TokenKind_None && (('0' <= *Byte && *Byte <= '9') ||
|
//- sixten: numerics
|
||||||
(*Byte == '-' && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
|
if(TokenKind == TokenKind_None && (('0' <= *Byte && *Byte <= '9') ||
|
||||||
{
|
(*Byte == '-' && Byte + 1 < TextEnd && '0' <= Byte[1] && Byte[1] <= '9')))
|
||||||
TokenKind = TokenKind_Numeric;
|
{
|
||||||
TokenStart = Byte;
|
TokenKind = TokenKind_Numeric;
|
||||||
TokenEnd = Byte;
|
TokenStart = Byte;
|
||||||
Byte += 1;
|
TokenEnd = Byte;
|
||||||
for(;Byte <= TextEnd; Byte += 1)
|
Byte += 1;
|
||||||
{
|
for(;Byte <= TextEnd; Byte += 1)
|
||||||
TokenEnd += 1;
|
{
|
||||||
if(Byte == TextEnd ||
|
TokenEnd += 1;
|
||||||
!(('0' <= *Byte && *Byte <= '9') ||
|
if(Byte == TextEnd ||
|
||||||
*Byte == '_' || *Byte == '.'))
|
!(('0' <= *Byte && *Byte <= '9') ||
|
||||||
{
|
*Byte == '_' || *Byte == '.'))
|
||||||
break;
|
{
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//- sixten: string literals
|
|
||||||
if(TokenKind == TokenKind_None && *Byte == '"')
|
//- sixten: string literals
|
||||||
{
|
if(TokenKind == TokenKind_None && *Byte == '"')
|
||||||
TokenKind = TokenKind_StringLiteral;
|
{
|
||||||
TokenStart = Byte;
|
TokenKind = TokenKind_StringLiteral;
|
||||||
TokenEnd = Byte;
|
TokenStart = Byte;
|
||||||
Byte += 1;
|
TokenEnd = Byte;
|
||||||
for(;Byte <= TextEnd; Byte += 1)
|
Byte += 1;
|
||||||
{
|
for(;Byte <= TextEnd; Byte += 1)
|
||||||
TokenEnd += 1;
|
{
|
||||||
if(Byte == TextEnd || *Byte == '\n')
|
TokenEnd += 1;
|
||||||
{
|
if(Byte == TextEnd || *Byte == '\n')
|
||||||
TokenKind = TokenKind_BrokenStringLiteral;
|
{
|
||||||
break;
|
TokenKind = TokenKind_BrokenStringLiteral;
|
||||||
}
|
break;
|
||||||
if(*Byte == '"')
|
}
|
||||||
{
|
if(*Byte == '"')
|
||||||
Byte += 1;
|
{
|
||||||
TokenEnd += 1;
|
Byte += 1;
|
||||||
break;
|
TokenEnd += 1;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//- sixten: symbols
|
|
||||||
if(TokenKind == TokenKind_None && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
|
//- sixten: symbols
|
||||||
*Byte == ',' || *Byte == '.' || *Byte == '@' || *Byte == '#' ||
|
if(TokenKind == TokenKind_None && (*Byte == '{' || *Byte == '}' || *Byte == '(' || *Byte == ')' ||
|
||||||
*Byte == ';' || *Byte == '+' || *Byte == '-' || *Byte == '*' ||
|
*Byte == ',' || *Byte == '.' || *Byte == '@' || *Byte == '#' ||
|
||||||
*Byte == '/'))
|
*Byte == ';' || *Byte == '+' || *Byte == '-' || *Byte == '*' ||
|
||||||
{
|
*Byte == '/'))
|
||||||
TokenStart = Byte;
|
{
|
||||||
TokenEnd = Byte+1;
|
TokenStart = Byte;
|
||||||
|
TokenEnd = Byte+1;
|
||||||
switch(*Byte)
|
|
||||||
{
|
switch(*Byte)
|
||||||
case '{': { TokenKind = TokenKind_CurlyOpen; } break;
|
{
|
||||||
case '}': { TokenKind = TokenKind_CurlyClose; } break;
|
case '{': { TokenKind = TokenKind_CurlyOpen; } break;
|
||||||
case '(': { TokenKind = TokenKind_ParenthesisOpen; } break;
|
case '}': { TokenKind = TokenKind_CurlyClose; } break;
|
||||||
case ')': { TokenKind = TokenKind_ParenthesisClose; } break;
|
case '(': { TokenKind = TokenKind_ParenthesisOpen; } break;
|
||||||
case ',': { TokenKind = TokenKind_Comma; } break;
|
case ')': { TokenKind = TokenKind_ParenthesisClose; } break;
|
||||||
case '.': { TokenKind = TokenKind_Dot; } break;
|
case ',': { TokenKind = TokenKind_Comma; } break;
|
||||||
case '@': { TokenKind = TokenKind_At; } break;
|
case '.': { TokenKind = TokenKind_Dot; } break;
|
||||||
case '#': { TokenKind = TokenKind_PoundSign; } break;
|
case '@': { TokenKind = TokenKind_At; } break;
|
||||||
case ';': { TokenKind = TokenKind_Semicolon; } break;
|
case '#': { TokenKind = TokenKind_PoundSign; } break;
|
||||||
case '+': { TokenKind = TokenKind_Plus; } break;
|
case ';': { TokenKind = TokenKind_Semicolon; } break;
|
||||||
case '-': { TokenKind = TokenKind_Minus; } break;
|
case '+': { TokenKind = TokenKind_Plus; } break;
|
||||||
case '*': { TokenKind = TokenKind_Star; } break;
|
case '-': { TokenKind = TokenKind_Minus; } break;
|
||||||
case '/': { TokenKind = TokenKind_Slash; } break;
|
case '*': { TokenKind = TokenKind_Star; } break;
|
||||||
InvalidDefaultCase;
|
case '/': { TokenKind = TokenKind_Slash; } break;
|
||||||
}
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
Byte += 1;
|
|
||||||
}
|
Byte += 1;
|
||||||
if(TokenKind == TokenKind_None && (*Byte == '!' || *Byte == '=' || *Byte == '>' || *Byte == '<'))
|
}
|
||||||
{
|
if(TokenKind == TokenKind_None && (*Byte == '!' || *Byte == '=' || *Byte == '>' || *Byte == '<'))
|
||||||
TokenStart = Byte;
|
{
|
||||||
TokenEnd = Byte+1;
|
TokenStart = Byte;
|
||||||
|
TokenEnd = Byte+1;
|
||||||
switch(*Byte)
|
|
||||||
{
|
switch(*Byte)
|
||||||
case '!': { TokenKind = TokenKind_Bang; } break;
|
{
|
||||||
case '=': { TokenKind = TokenKind_Equal; } break;
|
case '!': { TokenKind = TokenKind_Bang; } break;
|
||||||
case '>': { TokenKind = TokenKind_Greater; } break;
|
case '=': { TokenKind = TokenKind_Equal; } break;
|
||||||
case '<': { TokenKind = TokenKind_Less; } break;
|
case '>': { TokenKind = TokenKind_Greater; } break;
|
||||||
InvalidDefaultCase;
|
case '<': { TokenKind = TokenKind_Less; } break;
|
||||||
}
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
Byte += 1;
|
|
||||||
|
Byte += 1;
|
||||||
if(Byte < TextEnd && (*Byte == '='))
|
|
||||||
{
|
if(Byte < TextEnd && (*Byte == '='))
|
||||||
TokenKind = (token_kind)(TokenKind + 1);
|
{
|
||||||
TokenEnd += 1;
|
TokenKind = (token_kind)(TokenKind + 1);
|
||||||
Byte += 1;
|
TokenEnd += 1;
|
||||||
}
|
Byte += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//- sixten: bad character
|
|
||||||
if(TokenKind == TokenKind_None)
|
//- sixten: bad character
|
||||||
{
|
if(TokenKind == TokenKind_None)
|
||||||
TokenKind = TokenKind_BadCharacter;
|
{
|
||||||
TokenStart = Byte;
|
TokenKind = TokenKind_BadCharacter;
|
||||||
TokenEnd = Byte + 1;
|
TokenStart = Byte;
|
||||||
Byte += 1;
|
TokenEnd = Byte + 1;
|
||||||
}
|
Byte += 1;
|
||||||
|
}
|
||||||
//- sixten: push token
|
|
||||||
if(TokenKind != 0 && (!ExcludeFilter || (ExcludeFilter && !ExcludeFilter(TokenKind))) && TokenStart != 0 && TokenEnd > TokenStart)
|
//- sixten: push token
|
||||||
{
|
if(TokenKind != 0 && (!ExcludeFilter || (ExcludeFilter && !ExcludeFilter(TokenKind))) && TokenStart != 0 && TokenEnd > TokenStart)
|
||||||
token Token = {TokenKind, {TokenStart - TextStart, TokenEnd - TextStart}, Line};
|
{
|
||||||
T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
|
token Token = {TokenKind, {TokenStart - TextStart, TokenEnd - TextStart}, Line};
|
||||||
}
|
T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
|
||||||
|
}
|
||||||
if(TokenKind == TokenKind_BrokenComment)
|
|
||||||
{
|
if(TokenKind == TokenKind_BrokenComment)
|
||||||
string Message = StrLit("broken comment");
|
{
|
||||||
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
string Message = StrLit("broken comment");
|
||||||
}
|
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
||||||
|
}
|
||||||
if(TokenKind == TokenKind_BrokenStringLiteral)
|
|
||||||
{
|
if(TokenKind == TokenKind_BrokenStringLiteral)
|
||||||
string Message = StrLit("broken string literal");
|
{
|
||||||
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
string Message = StrLit("broken string literal");
|
||||||
}
|
T_MessageListPush(Arena, &Messages, T_MessageKind_Error, TokenStart - TextStart, Message);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tokenize_result Result =
|
|
||||||
{
|
tokenize_result Result =
|
||||||
T_TokenArrayFromList(Arena, &Tokens),
|
{
|
||||||
Messages
|
T_TokenArrayFromList(Arena, &Tokens),
|
||||||
};
|
Messages
|
||||||
ReleaseScratch(Scratch);
|
};
|
||||||
return(Result);
|
ReleaseScratch(Scratch);
|
||||||
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,129 +7,130 @@
|
||||||
//~ sixten: Token Types
|
//~ sixten: Token Types
|
||||||
enum token_kind
|
enum token_kind
|
||||||
{
|
{
|
||||||
TokenKind_None,
|
TokenKind_None,
|
||||||
|
|
||||||
// sixten: labels
|
// sixten: labels
|
||||||
TokenKind_Identifier,
|
TokenKind_Identifier,
|
||||||
TokenKind_Numeric,
|
TokenKind_Numeric,
|
||||||
TokenKind_StringLiteral,
|
TokenKind_StringLiteral,
|
||||||
|
|
||||||
// sixten: symbols
|
// sixten: symbols
|
||||||
TokenKind_SymbolsBegin,
|
TokenKind_SymbolsBegin,
|
||||||
// sixten: (single char)
|
// sixten: (single char)
|
||||||
TokenKind_CurlyOpen,
|
TokenKind_CurlyOpen,
|
||||||
TokenKind_CurlyClose,
|
TokenKind_CurlyClose,
|
||||||
TokenKind_ParenthesisOpen,
|
TokenKind_ParenthesisOpen,
|
||||||
TokenKind_ParenthesisClose,
|
TokenKind_ParenthesisClose,
|
||||||
TokenKind_Comma,
|
TokenKind_Comma,
|
||||||
TokenKind_Dot,
|
TokenKind_Dot,
|
||||||
TokenKind_At,
|
TokenKind_At,
|
||||||
TokenKind_PoundSign,
|
TokenKind_PoundSign,
|
||||||
TokenKind_Semicolon,
|
TokenKind_Semicolon,
|
||||||
TokenKind_Plus,
|
TokenKind_Plus,
|
||||||
TokenKind_Minus,
|
TokenKind_Minus,
|
||||||
TokenKind_Star,
|
TokenKind_Star,
|
||||||
TokenKind_Slash,
|
TokenKind_Slash,
|
||||||
// sixten: (one or two chars)
|
// sixten: (one or two chars)
|
||||||
TokenKind_Bang,
|
TokenKind_Bang,
|
||||||
TokenKind_BangEqual,
|
TokenKind_BangEqual,
|
||||||
TokenKind_Equal,
|
TokenKind_Equal,
|
||||||
TokenKind_EqualEqual,
|
TokenKind_EqualEqual,
|
||||||
TokenKind_Greater,
|
TokenKind_Greater,
|
||||||
TokenKind_GreaterEqual,
|
TokenKind_GreaterEqual,
|
||||||
TokenKind_Less,
|
TokenKind_Less,
|
||||||
TokenKind_LessEqual,
|
TokenKind_LessEqual,
|
||||||
TokenKind_SymbolsEnd,
|
TokenKind_SymbolsEnd,
|
||||||
|
|
||||||
// sixten: keywords
|
// sixten: keywords
|
||||||
TokenKind_KeywordsBegin,
|
TokenKind_KeywordsBegin,
|
||||||
TokenKind_And,
|
TokenKind_And,
|
||||||
TokenKind_Branch,
|
TokenKind_Branch,
|
||||||
TokenKind_Else,
|
TokenKind_Else,
|
||||||
TokenKind_False,
|
TokenKind_False,
|
||||||
TokenKind_For,
|
TokenKind_For,
|
||||||
TokenKind_If,
|
TokenKind_If,
|
||||||
TokenKind_Jump,
|
TokenKind_Jump,
|
||||||
TokenKind_Or,
|
TokenKind_Or,
|
||||||
TokenKind_Proc,
|
TokenKind_Proc,
|
||||||
TokenKind_True,
|
TokenKind_True,
|
||||||
TokenKind_Var,
|
TokenKind_Var,
|
||||||
TokenKind_While,
|
TokenKind_While,
|
||||||
TokenKind_Define,
|
TokenKind_Nav,
|
||||||
TokenKind_KeywordsEnd,
|
TokenKind_Background,
|
||||||
|
TokenKind_KeywordsEnd,
|
||||||
// sixten: whitespace
|
|
||||||
TokenKind_Whitespace,
|
// sixten: whitespace
|
||||||
TokenKind_Newline,
|
TokenKind_Whitespace,
|
||||||
TokenKind_Comment,
|
TokenKind_Newline,
|
||||||
|
TokenKind_Comment,
|
||||||
// sixten: invalid kinds
|
|
||||||
TokenKind_BrokenComment,
|
// sixten: invalid kinds
|
||||||
TokenKind_BrokenStringLiteral,
|
TokenKind_BrokenComment,
|
||||||
TokenKind_BadCharacter,
|
TokenKind_BrokenStringLiteral,
|
||||||
|
TokenKind_BadCharacter,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef b32 tokenizer_filter_function(token_kind Kind);
|
typedef b32 tokenizer_filter_function(token_kind Kind);
|
||||||
|
|
||||||
struct token
|
struct token
|
||||||
{
|
{
|
||||||
token_kind Kind;
|
token_kind Kind;
|
||||||
range1_s64 Range;
|
range1_s64 Range;
|
||||||
s64 Line;
|
s64 Line;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct token_chunk_node
|
struct token_chunk_node
|
||||||
{
|
{
|
||||||
token *Tokens;
|
token *Tokens;
|
||||||
s64 MaxCount;
|
s64 MaxCount;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
token_chunk_node *Next;
|
token_chunk_node *Next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct token_chunk_list
|
struct token_chunk_list
|
||||||
{
|
{
|
||||||
token_chunk_node *First;
|
token_chunk_node *First;
|
||||||
token_chunk_node *Last;
|
token_chunk_node *Last;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct token_array
|
struct token_array
|
||||||
{
|
{
|
||||||
token *Tokens;
|
token *Tokens;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ sixten: Tokenizer Message Types
|
//~ sixten: Tokenizer Message Types
|
||||||
enum tokenizer_message_kind
|
enum tokenizer_message_kind
|
||||||
{
|
{
|
||||||
T_MessageKind_Invalid,
|
T_MessageKind_Invalid,
|
||||||
T_MessageKind_Note,
|
T_MessageKind_Note,
|
||||||
T_MessageKind_Warning,
|
T_MessageKind_Warning,
|
||||||
T_MessageKind_Error,
|
T_MessageKind_Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tokenizer_message
|
struct tokenizer_message
|
||||||
{
|
{
|
||||||
tokenizer_message *Next;
|
tokenizer_message *Next;
|
||||||
tokenizer_message_kind Kind;
|
tokenizer_message_kind Kind;
|
||||||
s64 Offset;
|
s64 Offset;
|
||||||
string String;
|
string String;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tokenizer_message_list
|
struct tokenizer_message_list
|
||||||
{
|
{
|
||||||
tokenizer_message *First;
|
tokenizer_message *First;
|
||||||
tokenizer_message *Last;
|
tokenizer_message *Last;
|
||||||
s64 Count;
|
s64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ sixten: Text -> Token Types
|
//~ sixten: Text -> Token Types
|
||||||
struct tokenize_result
|
struct tokenize_result
|
||||||
{
|
{
|
||||||
token_array Tokens;
|
token_array Tokens;
|
||||||
tokenizer_message_list Messages;
|
tokenizer_message_list Messages;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
1586
code/vn_ui.cpp
217
code/vn_ui.h
|
@ -6,29 +6,29 @@
|
||||||
//- sixten: Keying
|
//- sixten: Keying
|
||||||
struct ui_key
|
struct ui_key
|
||||||
{
|
{
|
||||||
u64 Value;
|
u64 Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline b32 AreEqual(ui_key A, ui_key B)
|
inline b32 AreEqual(ui_key A, ui_key B)
|
||||||
{
|
{
|
||||||
b32 Result = (A.Value == B.Value);
|
b32 Result = (A.Value == B.Value);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Semantic sizing
|
//- sixten: Semantic sizing
|
||||||
enum ui_size_kind
|
enum ui_size_kind
|
||||||
{
|
{
|
||||||
UI_SizeKind_Pixels,
|
UI_SizeKind_Pixels,
|
||||||
UI_SizeKind_TextContent,
|
UI_SizeKind_TextContent,
|
||||||
UI_SizeKind_PercentOfParent,
|
UI_SizeKind_PercentOfParent,
|
||||||
UI_SizeKind_ChildrenSum,
|
UI_SizeKind_ChildrenSum,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_size
|
struct ui_size
|
||||||
{
|
{
|
||||||
ui_size_kind Kind;
|
ui_size_kind Kind;
|
||||||
r32 Value;
|
r32 Value;
|
||||||
r32 Strictness;
|
r32 Strictness;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ui_size UI_MakeSize(ui_size_kind Kind, r32 Value, r32 Strictness);
|
static ui_size UI_MakeSize(ui_size_kind Kind, r32 Value, r32 Strictness);
|
||||||
|
@ -42,20 +42,19 @@ static ui_size UI_MakeSize(ui_size_kind Kind, r32 Value, r32 Strictness);
|
||||||
//- sixten: UI core
|
//- sixten: UI core
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
UI_BoxFlag_Clickable = (1 << 0),
|
UI_BoxFlag_Clickable = (1 << 0),
|
||||||
UI_BoxFlag_DrawText = (1 << 1),
|
UI_BoxFlag_DrawText = (1 << 1),
|
||||||
UI_BoxFlag_DrawBorder = (1 << 2),
|
UI_BoxFlag_DrawBorder = (1 << 2),
|
||||||
UI_BoxFlag_DrawBackground = (1 << 3),
|
UI_BoxFlag_DrawBackground = (1 << 3),
|
||||||
UI_BoxFlag_DrawDropShadow = (1 << 4),
|
UI_BoxFlag_DrawDropShadow = (1 << 4),
|
||||||
UI_BoxFlag_Clip = (1 << 5),
|
UI_BoxFlag_Clip = (1 << 5),
|
||||||
UI_BoxFlag_HotAnimation = (1 << 6),
|
UI_BoxFlag_HotAnimation = (1 << 6),
|
||||||
UI_BoxFlag_ActiveAnimation = (1 << 7),
|
UI_BoxFlag_ActiveAnimation = (1 << 7),
|
||||||
UI_BoxFlag_OverflowX = (1 << 8),
|
UI_BoxFlag_OverflowX = (1 << 8),
|
||||||
UI_BoxFlag_OverflowY = (1 << 9),
|
UI_BoxFlag_OverflowY = (1 << 9),
|
||||||
UI_BoxFlag_FloatingX = (1 << 10),
|
UI_BoxFlag_FloatingX = (1 << 10),
|
||||||
UI_BoxFlag_FloatingY = (1 << 11),
|
UI_BoxFlag_FloatingY = (1 << 11),
|
||||||
UI_BoxFlag_Scrollable = (1 << 12),
|
UI_BoxFlag_Scrollable = (1 << 12),
|
||||||
UI_BoxFlag_AnimatePosition = (1 << 13),
|
|
||||||
};
|
};
|
||||||
typedef u32 ui_box_flags;
|
typedef u32 ui_box_flags;
|
||||||
|
|
||||||
|
@ -64,103 +63,105 @@ typedef UI_CUSTOM_DRAW_CALLBACK(ui_custom_draw_callback);
|
||||||
|
|
||||||
struct ui_box
|
struct ui_box
|
||||||
{
|
{
|
||||||
// sixten: building
|
// sixten: building
|
||||||
ui_box *First;
|
ui_box *First;
|
||||||
ui_box *Last;
|
ui_box *Last;
|
||||||
ui_box *Next;
|
ui_box *Next;
|
||||||
ui_box *Prev;
|
ui_box *Prev;
|
||||||
ui_box *Parent;
|
ui_box *Parent;
|
||||||
|
|
||||||
// sixten: hashing
|
// sixten: hashing
|
||||||
ui_box *HashNext;
|
ui_box *HashNext;
|
||||||
ui_box *HashPrev;
|
ui_box *HashPrev;
|
||||||
ui_key Key;
|
ui_key Key;
|
||||||
ui_key Seed;
|
ui_key Seed;
|
||||||
u64 LastFrameTouched;
|
u64 LastFrameTouched;
|
||||||
|
|
||||||
// sixten: per-frame data
|
// sixten: per-frame data
|
||||||
ui_box_flags Flags;
|
ui_box_flags Flags;
|
||||||
string String;
|
string String;
|
||||||
ui_size SemanticSize[Axis2_Count];
|
ui_size SemanticSize[Axis2_Count];
|
||||||
v2 FixedP;
|
v2 FixedP;
|
||||||
v4 TextColor;
|
v4 TextColor;
|
||||||
v4 BackgroundColor;
|
v4 BackgroundColor;
|
||||||
v4 BorderColor;
|
v4 BorderColor;
|
||||||
r32 BorderThickness;
|
r32 BorderThickness;
|
||||||
axis2 LayoutAxis;
|
axis2 LayoutAxis;
|
||||||
r32 CornerRadius;
|
r32 CornerRadius;
|
||||||
font_id Font;
|
font_id Font;
|
||||||
r32 FontSize;
|
r32 FontSize;
|
||||||
v2 Offset;
|
v2 Offset;
|
||||||
platform_cursor HoverCursor;
|
platform_cursor HoverCursor;
|
||||||
ui_custom_draw_callback *DrawCallback;
|
ui_custom_draw_callback *DrawCallback;
|
||||||
void *DrawCallbackData;
|
void *DrawCallbackData;
|
||||||
|
|
||||||
v2 ComputedRelativeP;
|
v2 ComputedRelativeP;
|
||||||
v2 ComputedDim;
|
v2 ComputedDim;
|
||||||
|
|
||||||
// sixten: retained data
|
// sixten: retained data
|
||||||
range2_r32 Rect;
|
range2_r32 Rect;
|
||||||
r32 HotTransition;
|
r32 HotTransition;
|
||||||
r32 ActiveTransition;
|
r32 ActiveTransition;
|
||||||
v2 ApproachingRelativeP;
|
v2 ApproachingRelativeP;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_box_bucket
|
struct ui_box_bucket
|
||||||
{
|
{
|
||||||
ui_box *First;
|
ui_box *First;
|
||||||
ui_box *Last;
|
ui_box *Last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_signal
|
struct ui_signal
|
||||||
{
|
{
|
||||||
ui_box *Box;
|
ui_box *Box;
|
||||||
v2 MouseP;
|
v2 MouseP;
|
||||||
v2 dMouseP;
|
v2 dMouseP;
|
||||||
v2 DragDelta;
|
v2 DragDelta;
|
||||||
v2 Scroll;
|
v2 Scroll;
|
||||||
b8 Clicked;
|
b8 Clicked;
|
||||||
b8 Pressed;
|
b8 Pressed;
|
||||||
b8 PressedRight;
|
b8 PressedRight;
|
||||||
b8 Released;
|
b8 Released;
|
||||||
b8 Hovering;
|
b8 Hovering;
|
||||||
b8 Dragging;
|
b8 Dragging;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "generated/vn_ui.meta.h"
|
#include "generated/vn_ui.meta.h"
|
||||||
|
|
||||||
struct ui
|
struct ui
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
arena *FrameArena;
|
arena *FrameArena;
|
||||||
ui_box *FirstFreeBox;
|
ui_box *FirstFreeBox;
|
||||||
ui_box *LastFreeBox;
|
ui_box *LastFreeBox;
|
||||||
|
|
||||||
ui_box_bucket BoxBuckets[256];
|
ui_box_bucket BoxBuckets[256];
|
||||||
|
|
||||||
ui_box *RootNode;
|
ui_box *RootNode;
|
||||||
ui_box *TooltipNode;
|
ui_box *TooltipNode;
|
||||||
ui_box *ContainerNode;
|
ui_box *ContainerNode;
|
||||||
|
|
||||||
u64 CurrentFrame;
|
u64 CurrentFrame;
|
||||||
ui_key Hot;
|
ui_key Hot;
|
||||||
ui_key Active;
|
ui_key Active;
|
||||||
|
|
||||||
r64 Time;
|
r64 Time;
|
||||||
|
r64 BlinkTime;
|
||||||
ui_key NextHot;
|
r64 Blink;
|
||||||
b32 NextHotSet;
|
|
||||||
|
ui_key NextHot;
|
||||||
u64 DragData[8];
|
b32 NextHotSet;
|
||||||
v2 DragStartP;
|
|
||||||
|
u64 DragData[8];
|
||||||
ui_style_stacks Stacks;
|
v2 DragStartP;
|
||||||
|
|
||||||
platform_event_list *EventList;
|
ui_style_stacks Stacks;
|
||||||
v2 dMouseP;
|
|
||||||
v2 MouseP;
|
platform_event_list *EventList;
|
||||||
|
v2 dMouseP;
|
||||||
glyph_atlas *GlyphAtlas;
|
v2 MouseP;
|
||||||
|
|
||||||
|
glyph_atlas *GlyphAtlas;
|
||||||
};
|
};
|
||||||
|
|
||||||
//- sixten: State management
|
//- sixten: State management
|
||||||
|
@ -188,6 +189,8 @@ inline void *UI_GetDragDataPointer(void);
|
||||||
|
|
||||||
//- sixten: Helpers
|
//- sixten: Helpers
|
||||||
static r64 UI_Time(void);
|
static r64 UI_Time(void);
|
||||||
|
static r64 UI_Blink(void);
|
||||||
|
static void UI_ResetBlink(void);
|
||||||
|
|
||||||
//- sixten: Key functions
|
//- sixten: Key functions
|
||||||
static ui_key UI_EmptyKey(void);
|
static ui_key UI_EmptyKey(void);
|
||||||
|
|
|
@ -1,94 +1,94 @@
|
||||||
//- sixten: Rows and columns.
|
//- sixten: Rows and columns.
|
||||||
inline void UI_RowBegin(u32 Flags, string Name)
|
inline void UI_RowBegin(u32 Flags, string Name)
|
||||||
{
|
{
|
||||||
UI_SetNextLayoutAxis(Axis2_X);
|
UI_SetNextLayoutAxis(Axis2_X);
|
||||||
ui_box *Box = UI_MakeBox(Flags, Name);
|
ui_box *Box = UI_MakeBox(Flags, Name);
|
||||||
UI_PushParent(Box);
|
UI_PushParent(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void UI_RowEnd(void)
|
inline void UI_RowEnd(void)
|
||||||
{
|
{
|
||||||
UI_PopParent();
|
UI_PopParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void UI_ColumnBegin(u32 Flags, string Name)
|
inline void UI_ColumnBegin(u32 Flags, string Name)
|
||||||
{
|
{
|
||||||
UI_SetNextLayoutAxis(Axis2_Y);
|
UI_SetNextLayoutAxis(Axis2_Y);
|
||||||
ui_box *Box = UI_MakeBox(Flags, Name);
|
ui_box *Box = UI_MakeBox(Flags, Name);
|
||||||
UI_PushParent(Box);
|
UI_PushParent(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void UI_ColumnEnd(void)
|
inline void UI_ColumnEnd(void)
|
||||||
{
|
{
|
||||||
UI_PopParent();
|
UI_PopParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Compositions
|
//- sixten: Compositions
|
||||||
inline void UI_PushAxisSize(axis2 Axis, ui_size Size)
|
inline void UI_PushAxisSize(axis2 Axis, ui_size Size)
|
||||||
{
|
{
|
||||||
if(Axis == Axis2_X)
|
if(Axis == Axis2_X)
|
||||||
{
|
{
|
||||||
UI_PushWidth(Size);
|
UI_PushWidth(Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI_PushHeight(Size);
|
UI_PushHeight(Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void UI_PopAxisSize(axis2 Axis)
|
inline void UI_PopAxisSize(axis2 Axis)
|
||||||
{
|
{
|
||||||
if(Axis == Axis2_X)
|
if(Axis == Axis2_X)
|
||||||
{
|
{
|
||||||
UI_PopWidth();
|
UI_PopWidth();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI_PopHeight();
|
UI_PopHeight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size)
|
inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size)
|
||||||
{
|
{
|
||||||
if(Axis == Axis2_X)
|
if(Axis == Axis2_X)
|
||||||
{
|
{
|
||||||
UI_SetNextWidth(Size);
|
UI_SetNextWidth(Size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI_SetNextHeight(Size);
|
UI_SetNextHeight(Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Spacing
|
//- sixten: Spacing
|
||||||
static ui_box *UI_NamedSpacer(ui_size Size, string String)
|
static ui_box *UI_NamedSpacer(ui_size Size, string String)
|
||||||
{
|
{
|
||||||
ui_box *Parent = UI_TopParent();
|
ui_box *Parent = UI_TopParent();
|
||||||
UI_SetNextAxisSize(Parent->LayoutAxis, Size);
|
UI_SetNextAxisSize(Parent->LayoutAxis, Size);
|
||||||
|
|
||||||
ui_box *Box = UI_MakeBox(0, String);
|
ui_box *Box = UI_MakeBox(0, String);
|
||||||
return(Box);
|
return(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...)
|
static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temp Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
ui_box *Box = UI_NamedSpacer(Size, String);
|
ui_box *Box = UI_NamedSpacer(Size, String);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
return(Box);
|
return(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_box *UI_Spacer(ui_size Size)
|
static ui_box *UI_Spacer(ui_size Size)
|
||||||
{
|
{
|
||||||
return(UI_NamedSpacer(Size, StrLit("")));
|
return(UI_NamedSpacer(Size, StrLit("")));
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Scrollable regions
|
//- sixten: Scrollable regions
|
||||||
|
@ -97,340 +97,504 @@ static ui_box *UI_Spacer(ui_size Size)
|
||||||
//- sixten: Common widgets
|
//- sixten: Common widgets
|
||||||
static ui_box *UI_Label(string String)
|
static ui_box *UI_Label(string String)
|
||||||
{
|
{
|
||||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
||||||
return(Box);
|
return(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_box *UI_LabelF(char *Format, ...)
|
static ui_box *UI_LabelF(char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temp Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
return(Box);
|
return(Box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_signal UI_Button(string String)
|
static ui_signal UI_Button(string String)
|
||||||
{
|
{
|
||||||
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
||||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
||||||
UI_BoxFlag_DrawBackground|
|
UI_BoxFlag_DrawBackground|
|
||||||
UI_BoxFlag_DrawBorder|
|
UI_BoxFlag_DrawBorder|
|
||||||
UI_BoxFlag_HotAnimation|
|
UI_BoxFlag_HotAnimation|
|
||||||
UI_BoxFlag_ActiveAnimation|
|
UI_BoxFlag_ActiveAnimation|
|
||||||
UI_BoxFlag_Clickable,
|
UI_BoxFlag_Clickable,
|
||||||
String);
|
String);
|
||||||
ui_signal Signal = UI_SignalFromBox(Box);
|
ui_signal Signal = UI_SignalFromBox(Box);
|
||||||
return(Signal);
|
return(Signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_signal UI_ButtonF(char *Format, ...)
|
static ui_signal UI_ButtonF(char *Format, ...)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch(0, 0);
|
temp Scratch = GetScratch(0, 0);
|
||||||
|
|
||||||
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
||||||
|
|
||||||
va_list Arguments;
|
va_list Arguments;
|
||||||
va_start(Arguments, Format);
|
va_start(Arguments, Format);
|
||||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||||
va_end(Arguments);
|
va_end(Arguments);
|
||||||
|
|
||||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
||||||
UI_BoxFlag_DrawBackground|
|
UI_BoxFlag_DrawBackground|
|
||||||
UI_BoxFlag_DrawBorder|
|
UI_BoxFlag_DrawBorder|
|
||||||
UI_BoxFlag_HotAnimation|
|
UI_BoxFlag_HotAnimation|
|
||||||
UI_BoxFlag_ActiveAnimation|
|
UI_BoxFlag_ActiveAnimation|
|
||||||
UI_BoxFlag_Clickable,
|
UI_BoxFlag_Clickable,
|
||||||
String);
|
String);
|
||||||
ui_signal Signal = UI_SignalFromBox(Box);
|
ui_signal Signal = UI_SignalFromBox(Box);
|
||||||
|
|
||||||
ReleaseScratch(Scratch);
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
return(Signal);
|
return(Signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_signal UI_Checkbox(b32 *Checked, string String)
|
static ui_signal UI_Checkbox(b32 *Checked, string String)
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
|
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
|
||||||
UI_SetNextLayoutAxis(Axis2_X);
|
UI_SetNextLayoutAxis(Axis2_X);
|
||||||
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
||||||
ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
|
ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
|
||||||
UI_Parent(ContainerBox)
|
UI_Parent(ContainerBox)
|
||||||
{
|
{
|
||||||
r32 OpacityTransition = AC_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
|
r32 OpacityTransition = AC_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
|
||||||
|
|
||||||
v4 TextColor = UI_TopTextColor();
|
v4 TextColor = UI_TopTextColor();
|
||||||
TextColor.a = OpacityTransition;
|
TextColor.a = OpacityTransition;
|
||||||
|
|
||||||
UI_CornerRadius(2) UI_Size(UI_Em(1, 1), UI_Em(1, 1)) UI_Font(Font_Icons) UI_TextColor(TextColor)
|
UI_CornerRadius(2) UI_Size(UI_Em(1, 1), UI_Em(1, 1)) UI_Font(Font_Icons) UI_TextColor(TextColor)
|
||||||
UI_MakeBoxF(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
|
UI_MakeBoxF(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
|
||||||
|
|
||||||
UI_Size(UI_TextContent(15, 1), UI_Em(1, 1)) UI_Label(String);
|
UI_Size(UI_TextContent(15, 1), UI_Em(1, 1)) UI_Label(String);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_signal Signal = UI_SignalFromBox(ContainerBox);
|
ui_signal Signal = UI_SignalFromBox(ContainerBox);
|
||||||
|
|
||||||
if(Signal.Pressed)
|
if(Signal.Pressed)
|
||||||
{
|
{
|
||||||
*Checked = !*Checked;
|
*Checked = !*Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Signal);
|
return(Signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Scrollable regions
|
//- sixten: Scrollable regions
|
||||||
static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
|
static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
|
||||||
{
|
{
|
||||||
ui_signal Signal;
|
ui_signal Signal;
|
||||||
|
|
||||||
UI_SetNextAxisSize(Axis, UI_Percent(1, 0));
|
UI_SetNextAxisSize(Axis, UI_Percent(1, 0));
|
||||||
UI_SetNextAxisSize(Opposite(Axis), UI_Em(1, 1));
|
UI_SetNextAxisSize(Opposite(Axis), UI_Em(1, 1));
|
||||||
UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
|
UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
|
||||||
UI_SetNextLayoutAxis(Axis);
|
UI_SetNextLayoutAxis(Axis);
|
||||||
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, Name))
|
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, Name))
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
||||||
UI_SetNextFont(Font_Icons);
|
UI_SetNextFont(Font_Icons);
|
||||||
UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_UpDir:FontIcon_LeftDir);
|
UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_UpDir:FontIcon_LeftDir);
|
||||||
|
|
||||||
UI_Spacer(UI_Pixels(Offset, 1));
|
UI_Spacer(UI_Pixels(Offset, 1));
|
||||||
|
|
||||||
UI_SetNextCornerRadius(4.0f);
|
UI_SetNextCornerRadius(4.0f);
|
||||||
UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1));
|
UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1));
|
||||||
UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1));
|
UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1));
|
||||||
|
|
||||||
Signal = UI_SignalFromBox(UI_MakeBox(UI_BoxFlag_DrawBorder |
|
Signal = UI_SignalFromBox(UI_MakeBox(UI_BoxFlag_DrawBorder |
|
||||||
UI_BoxFlag_DrawBackground |
|
UI_BoxFlag_DrawBackground |
|
||||||
UI_BoxFlag_Clickable |
|
UI_BoxFlag_Clickable |
|
||||||
UI_BoxFlag_HotAnimation |
|
UI_BoxFlag_HotAnimation |
|
||||||
UI_BoxFlag_ActiveAnimation,
|
UI_BoxFlag_ActiveAnimation,
|
||||||
StrLit("Slider")));
|
StrLit("Slider")));
|
||||||
|
|
||||||
UI_Spacer(UI_Percent(1, 0));
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
|
|
||||||
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
||||||
UI_SetNextFont(Font_Icons);
|
UI_SetNextFont(Font_Icons);
|
||||||
UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_DownDir:FontIcon_RightDir);
|
UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_DownDir:FontIcon_RightDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(Signal);
|
return(Signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
|
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
|
||||||
{
|
{
|
||||||
b32 AllowOnX = (X != 0);
|
b32 AllowOnX = (X != 0);
|
||||||
b32 AllowOnY = (Y != 0);
|
b32 AllowOnY = (Y != 0);
|
||||||
|
|
||||||
UI_RowBegin(Flags, Name);
|
UI_RowBegin(Flags, Name);
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
||||||
UI_ColumnBegin();
|
UI_ColumnBegin();
|
||||||
{
|
{
|
||||||
u32 ScrollFlags = 0;
|
u32 ScrollFlags = 0;
|
||||||
if(AllowOnX)
|
if(AllowOnX)
|
||||||
{
|
{
|
||||||
ScrollFlags |= UI_BoxFlag_OverflowX;
|
ScrollFlags |= UI_BoxFlag_OverflowX;
|
||||||
UI_SetNextOffsetX(-AC_AnimateValueF(*X, *X, 0.2f, "Scroll %S X", Name));
|
UI_SetNextOffsetX(-AC_AnimateValueF(*X, *X, 0.2f, "Scroll %S X", Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(AllowOnY)
|
if(AllowOnY)
|
||||||
{
|
{
|
||||||
ScrollFlags |= UI_BoxFlag_OverflowY;
|
ScrollFlags |= UI_BoxFlag_OverflowY;
|
||||||
UI_SetNextOffsetY(-AC_AnimateValueF(*Y, *Y, 0.2f, "Scroll %S Y", Name));
|
UI_SetNextOffsetY(-AC_AnimateValueF(*Y, *Y, 0.2f, "Scroll %S Y", Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0),
|
UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0),
|
||||||
AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0));
|
AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0));
|
||||||
|
|
||||||
ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box"));
|
ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box"));
|
||||||
|
|
||||||
UI_PushParent(ScrollableBox);
|
UI_PushParent(ScrollableBox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
|
static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
|
||||||
{
|
{
|
||||||
b32 AllowOnX = (X != 0);
|
b32 AllowOnX = (X != 0);
|
||||||
b32 AllowOnY = (Y != 0);
|
b32 AllowOnY = (Y != 0);
|
||||||
|
|
||||||
r32 ScrollAmount = UI_TopFontSize()*4.0f;
|
r32 ScrollAmount = UI_TopFontSize()*4.0f;
|
||||||
|
|
||||||
ui_box *ScrollableBox = UI_TopParent();
|
ui_box *ScrollableBox = UI_TopParent();
|
||||||
ui_signal ScrollableBoxSignal = UI_SignalFromBox(ScrollableBox);
|
ui_signal ScrollableBoxSignal = UI_SignalFromBox(ScrollableBox);
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
UI_PopParent();
|
UI_PopParent();
|
||||||
|
|
||||||
if(AllowOnX)
|
if(AllowOnX)
|
||||||
{
|
{
|
||||||
r32 TotalWidth = UI_CalculateBoxSize(ScrollableBox, Axis2_X);
|
r32 TotalWidth = UI_CalculateBoxSize(ScrollableBox, Axis2_X);
|
||||||
r32 ViewWidth = UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_X);
|
r32 ViewWidth = UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_X);
|
||||||
|
|
||||||
if(ViewWidth / TotalWidth < 1)
|
if(ViewWidth / TotalWidth < 1)
|
||||||
{
|
{
|
||||||
r32 TotalScrollWidth = ViewWidth - ScrollableBox->FontSize*2;
|
r32 TotalScrollWidth = ViewWidth - ScrollableBox->FontSize*2;
|
||||||
r32 ScrollScale = TotalScrollWidth / TotalWidth;
|
r32 ScrollScale = TotalScrollWidth / TotalWidth;
|
||||||
|
|
||||||
// sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
|
// sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
|
||||||
r32 ScrollWidth = ViewWidth*ScrollScale;
|
r32 ScrollWidth = ViewWidth*ScrollScale;
|
||||||
r32 ScrollOffset = (*X)*ScrollScale;
|
r32 ScrollOffset = (*X)*ScrollScale;
|
||||||
|
|
||||||
ui_signal Signal = UI_Scrollbar(Axis2_X, StrLit("Scroll X"), ScrollWidth, ScrollOffset);
|
ui_signal Signal = UI_Scrollbar(Axis2_X, StrLit("Scroll X"), ScrollWidth, ScrollOffset);
|
||||||
{
|
{
|
||||||
if(Signal.Dragging)
|
if(Signal.Dragging)
|
||||||
{
|
{
|
||||||
if(Signal.Pressed)
|
if(Signal.Pressed)
|
||||||
{
|
{
|
||||||
UI_StoreDragR32(*X);
|
UI_StoreDragR32(*X);
|
||||||
}
|
}
|
||||||
|
|
||||||
r32 StartOffset = UI_GetDragR32();
|
r32 StartOffset = UI_GetDragR32();
|
||||||
r32 EndOffset = StartOffset + Signal.DragDelta.x/ScrollScale;
|
r32 EndOffset = StartOffset + Signal.DragDelta.x/ScrollScale;
|
||||||
|
|
||||||
*X = EndOffset;
|
*X = EndOffset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(platform_event *Event = UI_EventList()->First;
|
for(platform_event *Event = UI_EventList()->First;
|
||||||
Event != 0;
|
Event != 0;
|
||||||
Event = Event->Next)
|
Event = Event->Next)
|
||||||
{
|
{
|
||||||
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.x != 0)
|
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.x != 0)
|
||||||
{
|
{
|
||||||
*X -= Event->Scroll.x*ScrollAmount;
|
*X -= Event->Scroll.x*ScrollAmount;
|
||||||
Platform_ConsumeEvent(UI_EventList(), Event);
|
Platform_ConsumeEvent(UI_EventList(), Event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*X = Clamp(*X, 0, Max(0.0, TotalWidth - ViewWidth));
|
*X = Clamp(*X, 0, Max(0.0, TotalWidth - ViewWidth));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UI_ColumnEnd();
|
UI_ColumnEnd();
|
||||||
|
|
||||||
if(AllowOnY)
|
if(AllowOnY)
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_Percent(1, 0));
|
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_Percent(1, 0));
|
||||||
UI_Column()
|
UI_Column()
|
||||||
{
|
{
|
||||||
r32 TotalHeight = UI_CalculateBoxSize(ScrollableBox, Axis2_Y);
|
r32 TotalHeight = UI_CalculateBoxSize(ScrollableBox, Axis2_Y);
|
||||||
r32 ViewHeight = DimOfRange(ScrollableBox->Parent->Parent->Rect).y;//UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
|
r32 ViewHeight = DimOfRange(ScrollableBox->Parent->Parent->Rect).y;//UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
|
||||||
|
|
||||||
if(ViewHeight / TotalHeight < 1)
|
if(ViewHeight / TotalHeight < 1)
|
||||||
{
|
{
|
||||||
r32 TotalScrollHeight = ViewHeight - ScrollableBox->FontSize*2;
|
r32 TotalScrollHeight = ViewHeight - ScrollableBox->FontSize*2;
|
||||||
r32 ScrollScale = TotalScrollHeight / TotalHeight;
|
r32 ScrollScale = TotalScrollHeight / TotalHeight;
|
||||||
|
|
||||||
// sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
|
// sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
|
||||||
r32 ScrollHeight = ViewHeight*ScrollScale;
|
r32 ScrollHeight = ViewHeight*ScrollScale;
|
||||||
r32 ScrollOffset = (*Y)*ScrollScale;
|
r32 ScrollOffset = (*Y)*ScrollScale;
|
||||||
|
|
||||||
ui_signal Signal = UI_Scrollbar(Axis2_Y, StrLit("Scroll Y"), ScrollHeight, ScrollOffset);
|
ui_signal Signal = UI_Scrollbar(Axis2_Y, StrLit("Scroll Y"), ScrollHeight, ScrollOffset);
|
||||||
{
|
{
|
||||||
if(Signal.Dragging)
|
if(Signal.Dragging)
|
||||||
{
|
{
|
||||||
if(Signal.Pressed)
|
if(Signal.Pressed)
|
||||||
{
|
{
|
||||||
UI_StoreDragR32(*Y);
|
UI_StoreDragR32(*Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
r32 StartOffset = UI_GetDragR32();
|
r32 StartOffset = UI_GetDragR32();
|
||||||
r32 EndOffset = StartOffset + Signal.DragDelta.y/ScrollScale;
|
r32 EndOffset = StartOffset + Signal.DragDelta.y/ScrollScale;
|
||||||
|
|
||||||
*Y = EndOffset;
|
*Y = EndOffset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(platform_event *Event = UI_EventList()->First;
|
for(platform_event *Event = UI_EventList()->First;
|
||||||
Event != 0;
|
Event != 0;
|
||||||
Event = Event->Next)
|
Event = Event->Next)
|
||||||
{
|
{
|
||||||
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0)
|
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0)
|
||||||
{
|
{
|
||||||
*Y -= Event->Scroll.y*ScrollAmount;
|
*Y -= Event->Scroll.y*ScrollAmount;
|
||||||
Platform_ConsumeEvent(UI_EventList(), Event);
|
Platform_ConsumeEvent(UI_EventList(), Event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*Y = Clamp(*Y, 0, Max(0.0, TotalHeight - ViewHeight));
|
*Y = Clamp(*Y, 0, Max(0.0, TotalHeight - ViewHeight));
|
||||||
}
|
}
|
||||||
// sixten: Add padding
|
// sixten: Add padding
|
||||||
if(AllowOnX && AllowOnY)
|
if(AllowOnX && AllowOnY)
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
||||||
UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
|
UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
|
||||||
UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, StrLit("Padding"));
|
UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, StrLit("Padding"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UI_RowEnd();
|
UI_RowEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
static r32 UI_Slider(r32 Value, range1_r32 Range)
|
static r32 UI_Slider(r32 Value, range1_r32 Range)
|
||||||
{
|
{
|
||||||
r32 Result = Value;
|
r32 Result = Value;
|
||||||
UI_Column()
|
UI_Column()
|
||||||
{
|
{
|
||||||
UI_Spacer(UI_Em(1, 1));
|
UI_Spacer(UI_Em(1, 1));
|
||||||
UI_Height(UI_Em(1, 1)) UI_Row()
|
UI_Height(UI_Em(1, 1)) UI_Row()
|
||||||
{
|
{
|
||||||
UI_SetNextWidth(UI_Em(20, 1));
|
UI_SetNextWidth(UI_Em(20, 1));
|
||||||
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
||||||
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Scrollable");
|
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Scrollable");
|
||||||
UI_Parent(Container)
|
UI_Parent(Container)
|
||||||
{
|
{
|
||||||
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
|
||||||
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
|
||||||
UI_SetNextFixedX((DimOfRange(Container->Rect).x-UI_TopFontSize())*(Value-Range.Min)/DimOfRange(Range));
|
UI_SetNextFixedX((DimOfRange(Container->Rect).x-UI_TopFontSize())*(Value-Range.Min)/DimOfRange(Range));
|
||||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground|
|
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground|
|
||||||
UI_BoxFlag_DrawBorder|
|
UI_BoxFlag_DrawBorder|
|
||||||
UI_BoxFlag_HotAnimation|
|
UI_BoxFlag_HotAnimation|
|
||||||
UI_BoxFlag_ActiveAnimation|
|
UI_BoxFlag_ActiveAnimation|
|
||||||
UI_BoxFlag_Clickable|
|
UI_BoxFlag_Clickable|
|
||||||
UI_BoxFlag_FloatingX|
|
UI_BoxFlag_FloatingX|
|
||||||
0, "Dragable");
|
0, "Dragable");
|
||||||
ui_signal Signal = UI_SignalFromBox(Box);
|
ui_signal Signal = UI_SignalFromBox(Box);
|
||||||
if(Signal.Dragging)
|
if(Signal.Dragging)
|
||||||
{
|
{
|
||||||
if(Signal.Pressed)
|
if(Signal.Pressed)
|
||||||
{
|
{
|
||||||
UI_StoreDragR32(Value);
|
UI_StoreDragR32(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
r32 StartT = UI_GetDragR32();
|
r32 StartT = UI_GetDragR32();
|
||||||
r32 EndT = StartT + Signal.DragDelta.x/(DimOfRange(Container->Rect).x-UI_TopFontSize());
|
r32 EndT = StartT + Signal.DragDelta.x/(DimOfRange(Container->Rect).x-UI_TopFontSize());
|
||||||
Result = EndT*DimOfRange(Range)+Range.Min;
|
Result = EndT*DimOfRange(Range)+Range.Min;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UI_TooltipLabel(string Label, v2 P)
|
static void UI_TooltipLabel(string Label, v2 P)
|
||||||
{
|
{
|
||||||
UI_Tooltip
|
UI_Tooltip
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_TextContent(7, 1), UI_TextContent(3, 1));
|
UI_SetNextSize(UI_TextContent(7, 1), UI_TextContent(3, 1));
|
||||||
UI_CornerRadius(4);
|
UI_CornerRadius(4);
|
||||||
UI_SetNextFixedP(P+V2R32(15.0f, 0.0f));
|
UI_SetNextFixedP(P+V2R32(15.0f, 0.0f));
|
||||||
UI_MakeBox(UI_BoxFlag_DrawBorder |
|
UI_MakeBox(UI_BoxFlag_DrawBorder |
|
||||||
UI_BoxFlag_DrawBackground |
|
UI_BoxFlag_DrawBackground |
|
||||||
UI_BoxFlag_DrawText |
|
UI_BoxFlag_DrawText |
|
||||||
UI_BoxFlag_DrawDropShadow |
|
UI_BoxFlag_DrawDropShadow |
|
||||||
UI_BoxFlag_FloatingX |
|
UI_BoxFlag_FloatingX |
|
||||||
UI_BoxFlag_FloatingY,
|
UI_BoxFlag_FloatingY,
|
||||||
Label);
|
Label);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ui_line_edit_callback_data
|
||||||
|
{
|
||||||
|
text_edit_state State;
|
||||||
|
b32 Focus;
|
||||||
|
};
|
||||||
|
|
||||||
|
UI_CUSTOM_DRAW_CALLBACK(UI_LineEditCallback)
|
||||||
|
{
|
||||||
|
ui_line_edit_callback_data *EditData = (ui_line_edit_callback_data *)Data;
|
||||||
|
s64 ClampedCursor = Clamp(0, Box->String.Count, EditData->State.Cursor);
|
||||||
|
s64 ClampedMark = Clamp(0, Box->String.Count, EditData->State.Mark);
|
||||||
|
string ToCursor = MakeString(Box->String.Data, ClampedCursor);
|
||||||
|
string ToMark = MakeString(Box->String.Data, ClampedMark);
|
||||||
|
|
||||||
|
r32 TargetCursorX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToCursor);
|
||||||
|
r32 TargetMarkerX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToMark);
|
||||||
|
|
||||||
|
r32 CursorX = AC_AnimateValueF(TargetCursorX, 0, 0.175, "UI Input Cursor %p", Box);
|
||||||
|
r32 MarkerX = AC_AnimateValueF(TargetMarkerX, 0, 0.175, "UI Input Mark %p", Box);
|
||||||
|
|
||||||
|
v2 BoxDim = DimOfRange(Box->Rect);
|
||||||
|
|
||||||
|
// sixten: Draw selection
|
||||||
|
{
|
||||||
|
v2 Offset = V2(7.5, (BoxDim.y - Box->FontSize) / 2);
|
||||||
|
v2 Dim = V2(0, Box->FontSize);
|
||||||
|
if(CursorX > MarkerX)
|
||||||
|
{
|
||||||
|
Offset.x += MarkerX;
|
||||||
|
Dim.x = CursorX - MarkerX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Offset.x += CursorX;
|
||||||
|
Dim.x = MarkerX - CursorX;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2 P = Box->Rect.Min + Offset;
|
||||||
|
v4 Color = V4(0.4, 0.7, 0.8, 0.3);
|
||||||
|
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sixten: Draw cursor
|
||||||
|
{
|
||||||
|
range1_r32 CursorSpan = Range1R32(CursorX, TargetCursorX);
|
||||||
|
r32 Height = Box->FontSize + 4;
|
||||||
|
v2 Offset = V2(7.5F + CursorSpan.Min, (BoxDim.y - Height) / 2);
|
||||||
|
v2 Dim = V2(1.25F + CursorSpan.Max - CursorSpan.Min, Height);
|
||||||
|
r32 FocusT = AC_AnimateValueF(EditData->Focus, 0, 0.175, "UI Input Focus %p", Box);
|
||||||
|
|
||||||
|
v2 P = Box->Rect.Min + Offset;
|
||||||
|
v4 Color = SetAlpha(V4(0.3, 1, 0.3, 0.7), UI_Blink()*FocusT);
|
||||||
|
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sixten(NOTE): this function only kinda works. it is meant for single line text, if that is any indication of its scope.
|
||||||
|
static s64 UI_TextIndexFromP(ui_box *Box, v2_r32 P)
|
||||||
|
{
|
||||||
|
// sixten: yes, usually I don't like doing this, but hey there is only one glyph atlas used throughout the entire application, nobody will notice ._.
|
||||||
|
glyph_atlas *Atlas = UI_GetState()->GlyphAtlas;
|
||||||
|
|
||||||
|
s64 Result = 0;
|
||||||
|
// sixten(NOTE): from now on, we ignore the y-axis
|
||||||
|
r32 Dim = CalculateRasterizedTextWidth(UI_GetState()->GlyphAtlas, Box->Font, Box->FontSize, Box->String);
|
||||||
|
r32 Offset = P.x - Box->Rect.Min.x - (Box->Rect.Max.x - Box->Rect.Min.x - Dim)*0.5;
|
||||||
|
|
||||||
|
r32 Advance = 0;
|
||||||
|
u8 *TextBegin = Box->String.Data;
|
||||||
|
u8 *TextEnd = TextBegin+Box->String.Count;
|
||||||
|
for(u8 *Byte = TextBegin; Byte < TextEnd;)
|
||||||
|
{
|
||||||
|
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
|
||||||
|
Byte += Decode.Size;
|
||||||
|
u32 Codepoint = Decode.Codepoint;
|
||||||
|
|
||||||
|
glyph *Glyph = GetGlyph(Atlas, Box->Font, Codepoint, Box->FontSize*Font_Oversample, GetSubpixelSegmentAtP(Advance*Font_Oversample));
|
||||||
|
Assert(Glyph);
|
||||||
|
|
||||||
|
Advance += Glyph->Advance/Font_Oversample;
|
||||||
|
if(Advance > Offset)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ui_signal UI_LineEdit(text_edit_state *State, u64 BufferSize, u8 *Buffer, s64 *BufferUsed, string String, b32 Focused)
|
||||||
|
{
|
||||||
|
temp Scratch = GetScratch();
|
||||||
|
if(Focused)
|
||||||
|
{
|
||||||
|
for(platform_event *Event = UI_EventList()->First; Event != 0; Event = Event->Next)
|
||||||
|
{
|
||||||
|
if((Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text) && (Event->Codepoint != '/' && Event->Codepoint != '\\'))
|
||||||
|
{
|
||||||
|
text_action Action = SingleLineTextActionFromEvent(Event);
|
||||||
|
if(IsValid(&Action))
|
||||||
|
{
|
||||||
|
text_op Op = TextOpFromAction(Scratch.Arena, MakeString(Buffer, *BufferUsed), State, &Action);
|
||||||
|
if(Op.NewCursor >= 0 && Op.NewMark >= 0)
|
||||||
|
{
|
||||||
|
string Left = MakeString(Buffer, Op.Range.Min);
|
||||||
|
string Right = MakeString(Buffer + Op.Range.Max, *BufferUsed - Op.Range.Max);
|
||||||
|
|
||||||
|
u64 NewStringSize = Left.Count + Right.Count + Op.ReplaceString.Count;
|
||||||
|
char *NewString = PushArray(Scratch.Arena, char, NewStringSize);
|
||||||
|
Copy(NewString, Left.Data, Left.Count);
|
||||||
|
Copy(NewString + Left.Count, Op.ReplaceString.Data, Op.ReplaceString.Count);
|
||||||
|
Copy(NewString + Left.Count + Op.ReplaceString.Count, Right.Data, Right.Count);
|
||||||
|
*BufferUsed = Minimum(BufferSize, NewStringSize);
|
||||||
|
Copy(Buffer, NewString, *BufferUsed);
|
||||||
|
|
||||||
|
State->Cursor = Minimum(Op.NewCursor, *BufferUsed);
|
||||||
|
State->Mark = Minimum(Op.NewMark, *BufferUsed);
|
||||||
|
Platform_ConsumeEvent(UI_EventList(), Event);
|
||||||
|
|
||||||
|
UI_ResetBlink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_SetNextHoverCursor(PlatformCursor_IBeam);
|
||||||
|
ui_box *Container = UI_MakeBox(UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, String);
|
||||||
|
ui_box *InputBox = 0;
|
||||||
|
|
||||||
|
UI_Parent(Container) UI_Height(UI_Percent(1, 1))
|
||||||
|
{
|
||||||
|
UI_SetNextWidth(UI_TextContent(15, 1));
|
||||||
|
InputBox = UI_MakeBox(UI_BoxFlag_DrawText, StrLit("Text Input"));
|
||||||
|
UI_EquipBoxText(InputBox, MakeString(Buffer, *BufferUsed));
|
||||||
|
ui_line_edit_callback_data *Data = PushStruct(UI_FrameArena(), ui_line_edit_callback_data);
|
||||||
|
Data->State = *State;
|
||||||
|
Data->Focus = Focused;
|
||||||
|
UI_EquipBoxCustomDrawCallback(InputBox, UI_LineEditCallback, Data);
|
||||||
|
|
||||||
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
|
}
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
|
|
||||||
|
//- sixten: handle mouse dragging
|
||||||
|
ui_signal Signal = UI_SignalFromBox(Container);
|
||||||
|
if(Signal.Dragging)
|
||||||
|
{
|
||||||
|
if(Signal.Pressed)
|
||||||
|
{
|
||||||
|
State->Cursor = State->Mark = UI_TextIndexFromP(InputBox, UI_MouseP());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
State->Cursor = UI_TextIndexFromP(InputBox, UI_MouseP());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Signal);
|
||||||
}
|
}
|
|
@ -57,5 +57,6 @@ static ui_signal UI_ButtonF(char *Format, ...);
|
||||||
static ui_signal UI_Checkbox(b32 *Checked, string String);
|
static ui_signal UI_Checkbox(b32 *Checked, string String);
|
||||||
static r32 UI_Slider(r32 Value, range1_r32 Range);
|
static r32 UI_Slider(r32 Value, range1_r32 Range);
|
||||||
static void UI_TooltipLabel(string Label, v2 P);
|
static void UI_TooltipLabel(string Label, v2 P);
|
||||||
|
static b32 UI_LineEdit(text_edit_state *State, u64 BufferSize, u8 *Buffer, u64 *BufferUsed, string String, b32 Focused);
|
||||||
|
|
||||||
#endif //VN_UI_UTILS_H
|
#endif //VN_UI_UTILS_H
|
||||||
|
|
|
@ -1,173 +1,198 @@
|
||||||
WORKSPACE_COMMAND(W_Command_SplitPanelHorizontal)
|
WORKSPACE_COMMAND(W_Command_SplitPanelHorizontal)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
W_SplitPanel(Workspace->CurrentPanel, Axis2_X);
|
W_SplitPanel(Workspace->CurrentPanel, Axis2_X);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACE_COMMAND(W_Command_SplitPanelVertical)
|
WORKSPACE_COMMAND(W_Command_SplitPanelVertical)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
W_SplitPanel(Workspace->CurrentPanel, Axis2_Y);
|
W_SplitPanel(Workspace->CurrentPanel, Axis2_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACE_COMMAND(W_Command_ClosePanel)
|
WORKSPACE_COMMAND(W_Command_ClosePanel)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
|
|
||||||
workspace_panel *Panel = (workspace_panel *)Argument;
|
workspace_panel *Panel = (workspace_panel *)Argument;
|
||||||
if(!Panel)
|
if(!Panel)
|
||||||
{
|
{
|
||||||
Panel = Workspace->CurrentPanel;
|
Panel = Workspace->CurrentPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace_panel *Parent = Panel->Parent;
|
workspace_panel *Parent = Panel->Parent;
|
||||||
|
|
||||||
Assert(Parent);
|
Assert(Parent);
|
||||||
Assert(Panel != Workspace->RootPanel);
|
Assert(Panel != Workspace->RootPanel);
|
||||||
|
|
||||||
DLLRemove(Parent->First, Parent->Last, Panel);
|
DLLRemove(Parent->First, Parent->Last, Panel);
|
||||||
|
|
||||||
b32 OneChildRemains = (Parent->First == Parent->Last);
|
b32 OneChildRemains = (Parent->First == Parent->Last);
|
||||||
if(OneChildRemains)
|
if(OneChildRemains)
|
||||||
{
|
{
|
||||||
workspace_panel *Child = Parent->First;
|
workspace_panel *Child = Parent->First;
|
||||||
Assert(DLLIsEmpty(Parent->FirstView));
|
Assert(DLLIsEmpty(Parent->FirstView));
|
||||||
|
|
||||||
Parent->FirstView = Child->FirstView;
|
Parent->FirstView = Child->FirstView;
|
||||||
Parent->LastView = Child->LastView;
|
Parent->LastView = Child->LastView;
|
||||||
Parent->First = Child->First;
|
Parent->First = Child->First;
|
||||||
Parent->Last = Child->Last;
|
Parent->Last = Child->Last;
|
||||||
Parent->SplitAxis = Child->SplitAxis;
|
Parent->SplitAxis = Child->SplitAxis;
|
||||||
|
Parent->CurrentView = Child->CurrentView;
|
||||||
// sixten: Update the parents of the children.
|
|
||||||
for(workspace_view *View = Parent->FirstView;
|
// sixten: Update the parents of the children.
|
||||||
View != 0;
|
for(workspace_view *View = Parent->FirstView;
|
||||||
View = View->Next)
|
View != 0;
|
||||||
{
|
View = View->Next)
|
||||||
View->Parent = Parent;
|
{
|
||||||
}
|
View->Parent = Parent;
|
||||||
for(workspace_panel *ParentChild = Parent->First;
|
}
|
||||||
ParentChild != 0;
|
for(workspace_panel *ParentChild = Parent->First;
|
||||||
ParentChild = ParentChild->Next)
|
ParentChild != 0;
|
||||||
{
|
ParentChild = ParentChild->Next)
|
||||||
ParentChild->Parent = Parent;
|
{
|
||||||
}
|
ParentChild->Parent = Parent;
|
||||||
|
}
|
||||||
DLLRemove(Parent->First, Parent->Last, Child);
|
|
||||||
W_DeletePanel(Child);
|
DLLRemove(Parent->First, Parent->Last, Child);
|
||||||
}
|
W_DeletePanel(Child);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
s32 ChildCount = 0;
|
{
|
||||||
for(workspace_panel *Child = Parent->First;
|
s32 ChildCount = 0;
|
||||||
Child != 0;
|
for(workspace_panel *Child = Parent->First;
|
||||||
Child = Child->Next)
|
Child != 0;
|
||||||
{
|
Child = Child->Next)
|
||||||
++ChildCount;
|
{
|
||||||
}
|
++ChildCount;
|
||||||
|
}
|
||||||
r32 ToAppend = Panel->PercentOfParent / ChildCount;
|
|
||||||
for(workspace_panel *Child = Parent->First;
|
r32 ToAppend = Panel->PercentOfParent / ChildCount;
|
||||||
Child != 0;
|
for(workspace_panel *Child = Parent->First;
|
||||||
Child = Child->Next)
|
Child != 0;
|
||||||
{
|
Child = Child->Next)
|
||||||
Child->PercentOfParent += ToAppend;
|
{
|
||||||
}
|
Child->PercentOfParent += ToAppend;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// sixten: Delete all child views.
|
|
||||||
workspace_view *NextChild = 0;
|
// sixten: Delete all child views.
|
||||||
for(workspace_view *Child = Panel->FirstView;
|
workspace_view *NextChild = 0;
|
||||||
Child != 0;
|
for(workspace_view *Child = Panel->FirstView;
|
||||||
Child = NextChild)
|
Child != 0;
|
||||||
{
|
Child = NextChild)
|
||||||
NextChild = Child->Next;
|
{
|
||||||
W_DestroyView(Child);
|
NextChild = Child->Next;
|
||||||
}
|
W_DestroyView(Child);
|
||||||
|
}
|
||||||
W_DeletePanel(Panel);
|
|
||||||
|
W_DeletePanel(Panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACE_COMMAND(W_Command_OpenView)
|
WORKSPACE_COMMAND(W_Command_OpenView)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
W_CreateNewView((workspace_view_kind)Argument, Workspace->CurrentPanel);
|
W_CreateNewView((workspace_view_kind)Argument, Workspace->CurrentPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACE_COMMAND(W_Command_CloseView)
|
WORKSPACE_COMMAND(W_Command_CloseView)
|
||||||
{
|
{
|
||||||
workspace_view *View = (workspace_view *)U64ToPointer(Argument);
|
workspace_view *View = (workspace_view *)U64ToPointer(Argument);
|
||||||
workspace_panel *Panel = View->Parent;
|
workspace_panel *Panel = View->Parent;
|
||||||
|
|
||||||
DLLRemove(Panel->FirstView, Panel->LastView, View);
|
DLLRemove(Panel->FirstView, Panel->LastView, View);
|
||||||
if(Panel->CurrentView == View)
|
if(Panel->CurrentView == View)
|
||||||
{
|
{
|
||||||
Panel->CurrentView = Panel->FirstView;
|
Panel->CurrentView = Panel->FirstView;
|
||||||
}
|
}
|
||||||
|
|
||||||
W_DestroyView(View);
|
W_DestroyView(View);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACE_COMMAND(W_Command_OpenFile)
|
WORKSPACE_COMMAND(W_Command_OpenFile)
|
||||||
{
|
{
|
||||||
temporary_memory Scratch = GetScratch();
|
temp Scratch = GetScratch();
|
||||||
|
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
workspace_file_lister_action *Action = (workspace_file_lister_action *)U64ToPointer(Argument);
|
workspace_file_lister_action *Action = (workspace_file_lister_action *)U64ToPointer(Argument);
|
||||||
|
|
||||||
string Filepath = PushFormat(Scratch.Arena, "%S/%S", Action->Path, Action->Name);
|
string Filepath = PushFormat(Scratch.Arena, "%S/%S", Action->Path, Action->Name);
|
||||||
|
|
||||||
platform_file_handle File = Platform.OpenFile(Filepath, PlatformAccess_Read);
|
platform_file_handle File = Platform.OpenFile(Filepath, PlatformAccess_Read);
|
||||||
if(File.IsValid)
|
if(File.IsValid)
|
||||||
{
|
{
|
||||||
// sixten: retrieve file extension
|
// sixten: retrieve file extension
|
||||||
string FileExtension = Substring(Action->Name, Range1S64(LastIndexOf(Action->Name, '.')+1, Action->Name.Count));
|
string FileExtension = Substring(Action->Name, Range1S64(LastIndexOf(Action->Name, '.')+1, Action->Name.Count));
|
||||||
if(AreEqual(FileExtension, StrLit("vns")))
|
if(AreEqual(FileExtension, StrLit("vns")))
|
||||||
{
|
{
|
||||||
s64 FileSize = Platform.GetFileSize(File);
|
s64 FileSize = Platform.GetFileSize(File);
|
||||||
string ReplaceString = MakeString(PushArrayNoClear(Scratch.Arena, u8, FileSize+1), FileSize);
|
string ReplaceString = MakeString(PushArrayNoClear(Scratch.Arena, u8, FileSize+1), FileSize);
|
||||||
ReplaceString.Data[FileSize] = 0;
|
ReplaceString.Data[FileSize] = 0;
|
||||||
Platform.ReadFile(File, ReplaceString.Data, 0, FileSize);
|
Platform.ReadFile(File, ReplaceString.Data, 0, FileSize);
|
||||||
|
|
||||||
ReplaceString = RemoveAll(Scratch.Arena, ReplaceString, '\r');
|
ReplaceString = RemoveAll(Scratch.Arena, ReplaceString, '\r');
|
||||||
|
|
||||||
workspace_view *View = W_CreateNewView(W_ViewKind_TextEditor, Workspace->CurrentPanel);
|
workspace_view *View = W_CreateNewView(W_ViewKind_TextEditor, Workspace->CurrentPanel);
|
||||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||||
|
|
||||||
MutableStringReplaceRange(&Editor->Text, ReplaceString, Range1S64(0, 0));
|
MutableStringReplaceRange(&Editor->Text, ReplaceString, Range1S64(0, 0));
|
||||||
W_TextEditorApplyChanges(Editor);
|
W_TextEditorApplyChanges(Editor);
|
||||||
Editor->FileName = PushString(View->Arena, Action->Name);
|
Editor->FileName = PushString(View->Arena, Action->Name);
|
||||||
Editor->FilePath = PushString(View->Arena, Action->Path);
|
Editor->FilePath = PushString(View->Arena, Action->Path);
|
||||||
}
|
}
|
||||||
else if(AreEqual(FileExtension, StrLit("vnn")))
|
else if(AreEqual(FileExtension, StrLit("vnn")))
|
||||||
{
|
{
|
||||||
s64 FileSize = Platform.GetFileSize(File);
|
s64 FileSize = Platform.GetFileSize(File);
|
||||||
string Contents = MakeString(PushArrayNoClear(Scratch.Arena, u8, FileSize), FileSize);
|
string Contents = MakeString(PushArrayNoClear(Scratch.Arena, u8, FileSize), FileSize);
|
||||||
Platform.ReadFile(File, Contents.Data, 0, Contents.Count);
|
Platform.ReadFile(File, Contents.Data, 0, Contents.Count);
|
||||||
|
|
||||||
workspace_view *View = W_CreateNewView(W_ViewKind_NavEditor, Workspace->CurrentPanel);
|
workspace_view *View = W_CreateNewView(W_ViewKind_NavEditor, Workspace->CurrentPanel);
|
||||||
W_SetupNavEditor(View, Contents);
|
W_NavEditorSetup(View, Action->Path, Action->Name, Contents);
|
||||||
}
|
}
|
||||||
else
|
else if(AreEqual(FileExtension, StrLit("png")) || AreEqual(FileExtension, StrLit("jpg")))
|
||||||
{
|
{
|
||||||
workspace_view *View = W_CreateNewView(W_ViewKind_Error, Workspace->CurrentPanel);
|
s64 FileSize = Platform.GetFileSize(File);
|
||||||
workspace_view_error *Error = (workspace_view_error *)View->Data;
|
string Contents = MakeString(PushArrayNoClear(Scratch.Arena, u8, FileSize), FileSize);
|
||||||
Error->Message = PushFormat(View->Arena, "Unknown file extension: %S", FileExtension);
|
Platform.ReadFile(File, Contents.Data, 0, Contents.Count);
|
||||||
}
|
workspace_view *View = W_CreateNewView(W_ViewKind_ImageViewer, Workspace->CurrentPanel);
|
||||||
|
b32 CouldOpenImage = W_ImageViewerSetup(View, Action->Name, Contents);
|
||||||
Platform.CloseFile(File);
|
if(!CouldOpenImage)
|
||||||
}
|
{
|
||||||
else
|
//- sixten: destroy the view and show an error message instead
|
||||||
{
|
workspace_panel *Panel = View->Parent;
|
||||||
// sixten: what happens now??
|
|
||||||
}
|
DLLRemove(Panel->FirstView, Panel->LastView, View);
|
||||||
|
if(Panel->CurrentView == View)
|
||||||
ReleaseScratch(Scratch);
|
{
|
||||||
|
Panel->CurrentView = Panel->FirstView;
|
||||||
|
}
|
||||||
|
W_DestroyView(View);
|
||||||
|
|
||||||
|
View = W_CreateNewView(W_ViewKind_Error, Workspace->CurrentPanel);
|
||||||
|
workspace_view_error *Error = (workspace_view_error *)View->Data;
|
||||||
|
Error->Message = PushFormat(View->Arena, "Unknown to open file: %S", Filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
workspace_view *View = W_CreateNewView(W_ViewKind_Error, Workspace->CurrentPanel);
|
||||||
|
workspace_view_error *Error = (workspace_view_error *)View->Data;
|
||||||
|
Error->Message = PushFormat(View->Arena, "Unknown file extension: %S", FileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.CloseFile(File);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// sixten: what happens now??
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VN_INTERNAL
|
#if VN_INTERNAL
|
||||||
WORKSPACE_COMMAND(W_Command_ToggleRenderUIDebugRects)
|
WORKSPACE_COMMAND(W_Command_ToggleRenderUIDebugRects)
|
||||||
{
|
{
|
||||||
DEBUG_DebugSettings->RenderUIDebugRects = !DEBUG_DebugSettings->RenderUIDebugRects;
|
DEBUG_DebugSettings->RenderUIDebugRects = !DEBUG_DebugSettings->RenderUIDebugRects;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,246 +1,227 @@
|
||||||
static workspace_file_lister_action *W_FileListerActionCopy(arena *Arena, workspace_file_lister_action *Action)
|
static workspace_file_lister_action *W_FileListerActionCopy(arena *Arena, workspace_file_lister_action *Action)
|
||||||
{
|
{
|
||||||
workspace_file_lister_action *Result = PushStruct(Arena, workspace_file_lister_action);
|
workspace_file_lister_action *Result = PushStruct(Arena, workspace_file_lister_action);
|
||||||
Result->HasRequestedFile = Action->HasRequestedFile;
|
Result->HasRequestedFile = Action->HasRequestedFile;
|
||||||
Result->Path = PushString(Arena, Action->Path);
|
Result->Path = PushString(Arena, Action->Path);
|
||||||
Result->Name = PushString(Arena, Action->Name);
|
Result->Name = PushString(Arena, Action->Name);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_CUSTOM_DRAW_CALLBACK(W_FileListerInputCallback)
|
UI_CUSTOM_DRAW_CALLBACK(W_FileListerInputCallback)
|
||||||
{
|
{
|
||||||
workspace_view_file_lister *Lister = (workspace_view_file_lister *)Data;
|
workspace_view_file_lister *Lister = (workspace_view_file_lister *)Data;
|
||||||
s64 ClampedCursor = Clamp(0, Box->String.Count, Lister->InputEditState.Cursor);
|
s64 ClampedCursor = Clamp(0, Box->String.Count, Lister->InputEditState.Cursor);
|
||||||
s64 ClampedMark = Clamp(0, Box->String.Count, Lister->InputEditState.Mark);
|
s64 ClampedMark = Clamp(0, Box->String.Count, Lister->InputEditState.Mark);
|
||||||
string ToCursor = MakeString(Box->String.Data, ClampedCursor);
|
string ToCursor = MakeString(Box->String.Data, ClampedCursor);
|
||||||
string ToMark = MakeString(Box->String.Data, ClampedMark);
|
string ToMark = MakeString(Box->String.Data, ClampedMark);
|
||||||
|
|
||||||
r32 TargetCursorX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToCursor);
|
r32 TargetCursorX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToCursor);
|
||||||
r32 TargetMarkerX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToMark);
|
r32 TargetMarkerX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToMark);
|
||||||
|
|
||||||
r32 CursorX = AC_AnimateValueF(TargetCursorX, 0, 0.175, "Workspace View Input Cursor %p", Box);
|
r32 CursorX = AC_AnimateValueF(TargetCursorX, 0, 0.175, "Workspace View Input Cursor %p", Box);
|
||||||
r32 MarkerX = AC_AnimateValueF(TargetMarkerX, 0, 0.175, "Workspace View Input Mark %p", Box);
|
r32 MarkerX = AC_AnimateValueF(TargetMarkerX, 0, 0.175, "Workspace View Input Mark %p", Box);
|
||||||
|
|
||||||
v2 BoxDim = DimOfRange(Box->Rect);
|
v2 BoxDim = DimOfRange(Box->Rect);
|
||||||
|
|
||||||
// sixten: Draw selection
|
// sixten: Draw selection
|
||||||
{
|
{
|
||||||
v2 Offset = V2(7.5, (BoxDim.y - Box->FontSize) / 2);
|
v2 Offset = V2(7.5, (BoxDim.y - Box->FontSize) / 2);
|
||||||
v2 Dim = V2(0, Box->FontSize);
|
v2 Dim = V2(0, Box->FontSize);
|
||||||
if(CursorX > MarkerX)
|
if(CursorX > MarkerX)
|
||||||
{
|
{
|
||||||
Offset.x += MarkerX;
|
Offset.x += MarkerX;
|
||||||
Dim.x = CursorX - MarkerX;
|
Dim.x = CursorX - MarkerX;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Offset.x += CursorX;
|
Offset.x += CursorX;
|
||||||
Dim.x = MarkerX - CursorX;
|
Dim.x = MarkerX - CursorX;
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 P = Box->Rect.Min + Offset;
|
v2 P = Box->Rect.Min + Offset;
|
||||||
v4 Color = V4(0.4, 0.7, 0.8, 0.3);
|
v4 Color = V4(0.4, 0.7, 0.8, 0.3);
|
||||||
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sixten: Draw cursor
|
// sixten: Draw cursor
|
||||||
{
|
{
|
||||||
range1_r32 CursorSpan = Range1R32(CursorX, TargetCursorX);
|
range1_r32 CursorSpan = Range1R32(CursorX, TargetCursorX);
|
||||||
r32 Height = Box->FontSize + 4;
|
r32 Height = Box->FontSize + 4;
|
||||||
v2 Offset = V2(7.5F + CursorSpan.Min, (BoxDim.y - Height) / 2);
|
v2 Offset = V2(7.5F + CursorSpan.Min, (BoxDim.y - Height) / 2);
|
||||||
v2 Dim = V2(1.25F + CursorSpan.Max - CursorSpan.Min, Height);
|
v2 Dim = V2(1.25F + CursorSpan.Max - CursorSpan.Min, Height);
|
||||||
|
|
||||||
v2 P = Box->Rect.Min + Offset;
|
v2 P = Box->Rect.Min + Offset;
|
||||||
v4 Color = V4(0.3, 1, 0.3, 0.7);
|
v4 Color = V4(0.3, 1, 0.3, 0.7);
|
||||||
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static b32 W_BuildFileListerItem(string Text, u32 Icon, b32 Selected, b32 EnterPressed)
|
static b32 W_BuildFileListerItem(string Text, u32 Icon, b32 Selected, b32 EnterPressed)
|
||||||
{
|
{
|
||||||
b32 Result = false;
|
b32 Result = false;
|
||||||
UI_SetNextLayoutAxis(Axis2_X);
|
UI_SetNextLayoutAxis(Axis2_X);
|
||||||
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
||||||
r32 SelectedT = AC_AnimateValueF(Selected, 0, 0.3f, "Lister Item %S", Text);
|
r32 SelectedT = AC_AnimateValueF(Selected, 0, 0.3f, "Lister Item %S", Text);
|
||||||
UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Theme_HighlightBorderColor, SelectedT*0.5));
|
UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Theme_HighlightBorderColor, SelectedT*0.5));
|
||||||
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, SelectedT));
|
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, SelectedT));
|
||||||
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
|
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
|
||||||
UI_BoxFlag_DrawBackground |
|
UI_BoxFlag_DrawBackground |
|
||||||
UI_BoxFlag_Clickable |
|
UI_BoxFlag_Clickable |
|
||||||
UI_BoxFlag_HotAnimation |
|
UI_BoxFlag_HotAnimation |
|
||||||
UI_BoxFlag_ActiveAnimation|
|
UI_BoxFlag_ActiveAnimation|
|
||||||
UI_BoxFlag_DrawDropShadow,
|
UI_BoxFlag_DrawDropShadow,
|
||||||
"File Lister %S", Text);
|
"File Lister %S", Text);
|
||||||
UI_Parent(Container)
|
UI_Parent(Container)
|
||||||
{
|
{
|
||||||
UI_Width(UI_Em(2, 1)) UI_Font(Font_Icons) UI_LabelF("%U", Icon);
|
UI_Width(UI_Em(2, 1)) UI_Font(Font_Icons) UI_LabelF("%U", Icon);
|
||||||
UI_Width(UI_TextContent(0, 1)) UI_Label(Text);
|
UI_Width(UI_TextContent(0, 1)) UI_Label(Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_signal Signal = UI_SignalFromBox(Container);
|
ui_signal Signal = UI_SignalFromBox(Container);
|
||||||
if(Signal.Clicked || Selected&&EnterPressed)
|
if(Signal.Clicked || Selected&&EnterPressed)
|
||||||
{
|
{
|
||||||
Result = true;
|
Result = true;
|
||||||
}
|
}
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static workspace_file_lister_action W_BuildFileLister(workspace_view *View)
|
static workspace_file_lister_action W_BuildFileLister(workspace_view *View)
|
||||||
{
|
{
|
||||||
workspace_view_file_lister *Lister = (workspace_view_file_lister *)View->Data;
|
workspace_file_lister_action ListerAction = {};
|
||||||
|
|
||||||
workspace_file_lister_action ListerAction = {};
|
workspace_view_file_lister *Lister = (workspace_view_file_lister *)View->Data;
|
||||||
temporary_memory Scratch = GetScratch();
|
|
||||||
UI_Size(UI_Percent(1, 1), UI_Percent(1, 1))
|
b32 EnterPressed = Platform_KeyPress(UI_EventList(), Key_Return);
|
||||||
{
|
s32 SelectedItemDelta = 0;
|
||||||
|
s32 ListerCount = 0;
|
||||||
b32 EnterPressed = Platform_KeyPress(UI_EventList(), Key_Return);
|
s64 LastSlash = LastIndexOf(Lister->Path, '/');
|
||||||
s32 SelectedItemDelta = 0;
|
b32 RequestedParentDirectory = false;
|
||||||
|
|
||||||
s32 ListerCount = 0;
|
temp Scratch = GetScratch();
|
||||||
|
UI_Size(UI_Percent(1, 1), UI_Percent(1, 1))
|
||||||
//- sixten: filename input field
|
{
|
||||||
if(W_ViewIsCurrent(View))
|
//- sixten: filename input field
|
||||||
{
|
if(W_ViewIsCurrent(View))
|
||||||
for(platform_event *Event = UI_EventList()->First; Event != 0; Event = Event->Next)
|
{
|
||||||
{
|
for(platform_event *Event = UI_EventList()->First; Event != 0; Event = Event->Next)
|
||||||
if((Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text) && (Event->Codepoint != '/' && Event->Codepoint != '\\'))
|
{
|
||||||
{
|
if(Event->Type == PlatformEvent_Press && (Event->Key == Key_Up || Event->Key == Key_Down))
|
||||||
text_action Action = SingleLineTextActionFromEvent(Event);
|
{
|
||||||
if(IsValid(&Action))
|
SelectedItemDelta = Event->Key == Key_Up ? -1 : 1;
|
||||||
{
|
}
|
||||||
text_op Op = TextOpFromAction(Scratch.Arena, MakeString(Lister->Input, Lister->InputUsed), &Lister->InputEditState, &Action);
|
if(Event->Type == PlatformEvent_Press && Event->Key == Key_Backspace && Lister->InputEditState.Cursor == 0)
|
||||||
if(Op.NewCursor >= 0 && Op.NewMark >= 0)
|
{
|
||||||
{
|
RequestedParentDirectory = true;
|
||||||
string Left = MakeString(Lister->Input, Op.Range.Min);
|
}
|
||||||
string Right = MakeString(Lister->Input + Op.Range.Max, Lister->InputUsed - Op.Range.Max);
|
}
|
||||||
|
}
|
||||||
u64 NewStringSize = Left.Count + Right.Count + Op.ReplaceString.Count;
|
|
||||||
char *NewString = PushArray(Scratch.Arena, char, NewStringSize);
|
//- sixten: build navbar
|
||||||
Copy(NewString, Left.Data, Left.Count);
|
UI_Height(UI_Em(2, 1)) UI_Row(UI_BoxFlag_DrawBorder)
|
||||||
Copy(NewString + Left.Count, Op.ReplaceString.Data, Op.ReplaceString.Count);
|
{
|
||||||
Copy(NewString + Left.Count + Op.ReplaceString.Count, Right.Data, Right.Count);
|
|
||||||
Lister->InputUsed = Minimum(ArrayCount(Lister->Input), NewStringSize);
|
UI_SetNextBackgroundColor(ColorFromHex(0x2D5790FF));
|
||||||
Copy(Lister->Input, NewString, Lister->InputUsed);
|
UI_SetNextWidth(UI_TextContent(20, 1));
|
||||||
|
UI_MakeBox(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawText, Lister->Path);
|
||||||
Lister->InputEditState.Cursor = Minimum(Op.NewCursor, Lister->InputUsed);
|
|
||||||
Lister->InputEditState.Mark = Minimum(Op.NewMark, Lister->InputUsed);
|
UI_Width(UI_Percent(1, 0))
|
||||||
Platform_ConsumeEvent(UI_EventList(), Event);
|
UI_LineEdit(&Lister->InputEditState, ArrayCount(Lister->Input), Lister->Input, &Lister->InputUsed, StrLit("File Lister Text Input"), W_ViewIsCurrent(View));
|
||||||
}
|
|
||||||
}
|
UI_SetNextWidth(UI_TextContent(20, 1));
|
||||||
}
|
if(UI_ButtonF("Open/Create").Clicked || EnterPressed)
|
||||||
|
{
|
||||||
if(Event->Type == PlatformEvent_Press && (Event->Key == Key_Up || Event->Key == Key_Down))
|
ListerAction.HasRequestedFile = true;
|
||||||
{
|
ListerAction.Name = MakeString(Lister->Input, Lister->InputUsed);
|
||||||
SelectedItemDelta = Event->Key == Key_Up ? -1 : 1;
|
ListerAction.Path = Lister->Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
UI_Scroll(0, &Lister->Scroll)
|
||||||
//- sixten: build navbar
|
{
|
||||||
UI_Height(UI_Em(2, 1)) UI_Row(UI_BoxFlag_DrawBorder)
|
UI_Height(UI_Em(2, 1))
|
||||||
{
|
{
|
||||||
UI_SetNextBackgroundColor(ColorFromHex(0x2D5790FF));
|
//- sixten: display "parent directory button"
|
||||||
UI_SetNextWidth(UI_TextContent(20, 1));
|
if(LastSlash != -1)
|
||||||
UI_MakeBox(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawText, Lister->Path);
|
{
|
||||||
|
if(W_BuildFileListerItem(StrLit("Parent Directory"), FontIcon_Reply, Lister->SelectedItem == ListerCount, EnterPressed))
|
||||||
UI_SetNextWidth(UI_TextContent(15, 1));
|
{
|
||||||
ui_box *InputBox = UI_MakeBox(UI_BoxFlag_DrawText, StrLit("Text Lister Lister Input"));
|
RequestedParentDirectory = true;
|
||||||
UI_EquipBoxText(InputBox, MakeString(Lister->Input, Lister->InputUsed));
|
ListerAction.HasRequestedFile = false; // sixten: if we have selected a folder, but typed a name we want to open the folder.
|
||||||
UI_EquipBoxCustomDrawCallback(InputBox, W_FileListerInputCallback, Lister);
|
}
|
||||||
|
ListerCount += 1;
|
||||||
UI_Padding(UI_Percent(1, 0));
|
}
|
||||||
|
platform_file_info FileInfo;
|
||||||
UI_SetNextWidth(UI_TextContent(20, 1));
|
platform_file_iter *FileIter;
|
||||||
if(UI_ButtonF("Open/Create").Clicked || EnterPressed)
|
|
||||||
{
|
string Name = MakeString(Lister->Input, Lister->InputUsed);
|
||||||
ListerAction.HasRequestedFile = true;
|
string FullPath = PushFormat(Scratch.Arena, "%S/%S", Lister->Path, Name);
|
||||||
ListerAction.Name = MakeString(Lister->Input, Lister->InputUsed);
|
|
||||||
ListerAction.Path = Lister->Path;
|
//- sixten: display directories
|
||||||
}
|
{
|
||||||
}
|
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
||||||
|
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
||||||
UI_Scroll(0, &Lister->Scroll)
|
{
|
||||||
{
|
if(FileInfo.IsDirectory)
|
||||||
UI_Height(UI_Em(2, 1))
|
{
|
||||||
{
|
if(W_BuildFileListerItem(FileInfo.Name, FontIcon_Folder, Lister->SelectedItem == ListerCount, EnterPressed))
|
||||||
//- sixten: display "parent directory button"
|
{
|
||||||
s64 LastSlash = LastIndexOf(Lister->Path, '/');
|
Lister->Path = PushFormat(View->Arena, "%S/%S", Lister->Path, FileInfo.Name);
|
||||||
if(LastSlash != -1)
|
Lister->InputUsed = 0;
|
||||||
{
|
Lister->SelectedItem = -1;
|
||||||
b32 BackspacePressed = Lister->InputUsed == 0 && Platform_KeyPress(UI_EventList(), Key_Backspace);
|
ListerAction.HasRequestedFile = false; // sixten: if we have selected a folder, but typed a name we want to open the folder.
|
||||||
if(W_BuildFileListerItem(StrLit("Parent Directory"), FontIcon_Reply, Lister->SelectedItem == ListerCount, EnterPressed) ||
|
}
|
||||||
BackspacePressed)
|
ListerCount += 1;
|
||||||
{
|
}
|
||||||
Lister->Path = Prefix(Lister->Path, LastSlash);
|
}
|
||||||
Lister->InputUsed = 0;
|
}
|
||||||
Lister->SelectedItem = -1;
|
Platform.EndFileIter(FileIter);
|
||||||
}
|
|
||||||
ListerCount += 1;
|
//- sixten: display files
|
||||||
}
|
{
|
||||||
platform_file_info FileInfo;
|
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
||||||
platform_file_iter *FileIter;
|
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
||||||
|
{
|
||||||
string Name = MakeString(Lister->Input, Lister->InputUsed);
|
if(!FileInfo.IsDirectory)
|
||||||
string FullPath = PushFormat(Scratch.Arena, "%S/%S", Lister->Path, Name);
|
{
|
||||||
|
if(W_BuildFileListerItem(FileInfo.Name, FontIcon_Document, Lister->SelectedItem == ListerCount, EnterPressed))
|
||||||
//- sixten: display directories
|
{
|
||||||
{
|
ListerAction.HasRequestedFile = true;
|
||||||
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
Lister->SelectedItem = -1;
|
||||||
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
ListerAction.Name = PushString(View->Arena, FileInfo.Name);
|
||||||
{
|
ListerAction.Path = Lister->Path;
|
||||||
if(FileInfo.IsDirectory)
|
}
|
||||||
{
|
ListerCount += 1;
|
||||||
if(W_BuildFileListerItem(FileInfo.Name, FontIcon_Folder, Lister->SelectedItem == ListerCount, EnterPressed))
|
}
|
||||||
{
|
}
|
||||||
Lister->Path = PushFormat(View->Arena, "%S/%S", Lister->Path, FileInfo.Name);
|
}
|
||||||
Lister->InputUsed = 0;
|
|
||||||
Lister->SelectedItem = -1;
|
//- sixten: update selected item
|
||||||
ListerAction.HasRequestedFile = false; // sixten: if we have selected a folder, but typed a name we want to open the folder.
|
if(SelectedItemDelta != 0)
|
||||||
}
|
{
|
||||||
ListerCount += 1;
|
Lister->SelectedItem += SelectedItemDelta;
|
||||||
}
|
if(Lister->SelectedItem < 0)
|
||||||
}
|
{
|
||||||
}
|
Lister->SelectedItem = ListerCount - 1;
|
||||||
Platform.EndFileIter(FileIter);
|
}
|
||||||
|
else if(Lister->SelectedItem >= ListerCount)
|
||||||
//- sixten: display files
|
{
|
||||||
{
|
Lister->SelectedItem -= ListerCount;
|
||||||
FileIter = Platform.BeginFileIter(Scratch.Arena, FullPath);
|
}
|
||||||
for(;Platform.AdvanceFileIter(Scratch.Arena, FileIter, &FileInfo);)
|
}
|
||||||
{
|
|
||||||
if(!FileInfo.IsDirectory)
|
Platform.EndFileIter(FileIter);
|
||||||
{
|
}
|
||||||
if(W_BuildFileListerItem(FileInfo.Name, FontIcon_Document, Lister->SelectedItem == ListerCount, EnterPressed))
|
}
|
||||||
{
|
}
|
||||||
ListerAction.HasRequestedFile = true;
|
|
||||||
Lister->SelectedItem = -1;
|
//- sixten: goto parent directory
|
||||||
ListerAction.Name = PushString(View->Arena, FileInfo.Name);
|
if(RequestedParentDirectory && LastSlash != -1)
|
||||||
ListerAction.Path = Lister->Path;
|
{
|
||||||
}
|
Lister->Path = Prefix(Lister->Path, LastSlash);
|
||||||
ListerCount += 1;
|
Lister->InputUsed = 0;
|
||||||
}
|
Lister->SelectedItem = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
//- sixten: update selected item
|
return(ListerAction);
|
||||||
if(SelectedItemDelta != 0)
|
|
||||||
{
|
|
||||||
Lister->SelectedItem += SelectedItemDelta;
|
|
||||||
if(Lister->SelectedItem < 0)
|
|
||||||
{
|
|
||||||
Lister->SelectedItem += ListerCount;
|
|
||||||
}
|
|
||||||
else if(Lister->SelectedItem >= ListerCount)
|
|
||||||
{
|
|
||||||
Lister->SelectedItem -= ListerCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.EndFileIter(FileIter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ReleaseScratch(Scratch);
|
|
||||||
return(ListerAction);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,19 @@
|
||||||
|
|
||||||
struct workspace_file_lister_action
|
struct workspace_file_lister_action
|
||||||
{
|
{
|
||||||
b32 HasRequestedFile;
|
b32 HasRequestedFile;
|
||||||
string Path;
|
string Path;
|
||||||
string Name;
|
string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct workspace_view_file_lister
|
struct workspace_view_file_lister
|
||||||
{
|
{
|
||||||
string Path;
|
string Path;
|
||||||
r32 Scroll;
|
r32 Scroll;
|
||||||
u8 Input[256];
|
u8 Input[256];
|
||||||
s32 InputUsed;
|
s64 InputUsed;
|
||||||
text_edit_state InputEditState;
|
text_edit_state InputEditState;
|
||||||
s32 SelectedItem;
|
s32 SelectedItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
static workspace_file_lister_action *W_FileListerActionCopy(arena *Arena, workspace_file_lister_action *Action);
|
static workspace_file_lister_action *W_FileListerActionCopy(arena *Arena, workspace_file_lister_action *Action);
|
||||||
|
|
|
@ -1,160 +1,442 @@
|
||||||
UI_CUSTOM_DRAW_CALLBACK(BuildNavViewDrawCallback)
|
UI_CUSTOM_DRAW_CALLBACK(BuildNavViewDrawCallback)
|
||||||
{
|
{
|
||||||
scene_view *SceneView = (scene_view *)Data;
|
scene_view *SceneView = (scene_view *)Data;
|
||||||
SV_DrawBackground(SceneView, Box, Group);
|
SV_DrawBackground(SceneView, Box, Group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void W_NavEditorSerializeItems(workspace_view_nav_editor *Editor)
|
||||||
|
{
|
||||||
|
temp Scratch = GetScratch();
|
||||||
|
|
||||||
|
//- sixten: find total size
|
||||||
|
u64 TotalSize = sizeof(u16); // item count
|
||||||
|
for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next)
|
||||||
|
{
|
||||||
|
string AssetName = MakeString(AssetNameLUT[Node->Item.TextureID]);
|
||||||
|
|
||||||
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += AssetName.Count; // texture id
|
||||||
|
TotalSize += 1; TotalSize += sizeof(r32); // scale
|
||||||
|
TotalSize += 1; TotalSize += sizeof(v2_r32); // origin
|
||||||
|
TotalSize += 1; TotalSize += sizeof(v2_r32); // p
|
||||||
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += Node->Item.HoverText.Count; // hover text
|
||||||
|
TotalSize += 1; TotalSize += sizeof(u16); TotalSize += sizeof(u8); TotalSize += Node->Item.Action.Content.Count; // action
|
||||||
|
TotalSize += 1; // end of item
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *FileData = PushArray(Scratch.Arena, u8, TotalSize);
|
||||||
|
u8 *Data = FileData;
|
||||||
|
|
||||||
|
*(u16 *)Data = Editor->Items.Count;
|
||||||
|
Data += sizeof(u16);
|
||||||
|
|
||||||
|
#define WriteByte(Op) do { *Data++ = Op; } while(0)
|
||||||
|
#define WriteField(Op, type, Member) do { *Data++ = Op; *(type *)Data = Member; Data += sizeof(type); } while(0)
|
||||||
|
#define WriteString(String) do { *(u16 *)Data = (u16)String.Count; Data += sizeof(u16); Copy(Data, String.Data, String.Count); Data += String.Count; } while(0)
|
||||||
|
|
||||||
|
for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next)
|
||||||
|
{
|
||||||
|
scene_nav_item *Item = &Node->Item;
|
||||||
|
string AssetName = MakeString(AssetNameLUT[Node->Item.TextureID]);
|
||||||
|
WriteByte(S_NavItemOp_TextureID); WriteString(AssetName);
|
||||||
|
WriteField(S_NavItemOp_Scale, r32, Item->Scale);
|
||||||
|
WriteField(S_NavItemOp_Origin, v2_r32, Item->Origin);
|
||||||
|
WriteField(S_NavItemOp_P, v2_r32, Item->P);
|
||||||
|
WriteByte(S_NavItemOp_HoverText); WriteString(Item->HoverText);
|
||||||
|
WriteByte(S_NavItemOp_Action); WriteByte(Item->Action.Kind); WriteString(Item->Action.Content);
|
||||||
|
WriteByte(S_NavItemOp_None);
|
||||||
|
}
|
||||||
|
#undef WriteByte
|
||||||
|
#undef WriteField
|
||||||
|
#undef WriteString
|
||||||
|
|
||||||
|
platform_file_handle File = Platform.OpenFile(PushFormat(Scratch.Arena, "%S/%S", Editor->FilePath, Editor->FileName), PlatformAccess_Write);
|
||||||
|
if(File.IsValid)
|
||||||
|
{
|
||||||
|
Platform.WriteFile(File, FileData, 0, TotalSize);
|
||||||
|
Platform.CloseFile(File);
|
||||||
|
}
|
||||||
|
ReleaseScratch(Scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static workspace_string_chunk *W_StringChunkAlloc(arena *Arena, workspace_string_chunk_list *FreeList)
|
||||||
|
{
|
||||||
|
workspace_string_chunk *Result = FreeList->First;
|
||||||
|
if(Result)
|
||||||
|
{
|
||||||
|
DLLRemove(FreeList->First, FreeList->Last, Result);
|
||||||
|
*Result = {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = PushStruct(Arena, workspace_string_chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void W_StringChunkRelease(workspace_string_chunk_list *FreeList, workspace_string_chunk *Chunk)
|
||||||
|
{
|
||||||
|
DLLInsertLast(FreeList->First, FreeList->Last, Chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static scene_nav_item_node *W_SceneNavItemNodeAlloc(arena *Arena, workspace_view_nav_editor *Editor)
|
static scene_nav_item_node *W_SceneNavItemNodeAlloc(arena *Arena, workspace_view_nav_editor *Editor)
|
||||||
{
|
{
|
||||||
scene_nav_item_node *Result = Editor->FirstFree;
|
scene_nav_item_node *Result = Editor->FirstFree;
|
||||||
if(Result)
|
if(Result)
|
||||||
{
|
{
|
||||||
DLLRemove(Editor->FirstFree, Editor->LastFree, Result);
|
DLLRemove(Editor->FirstFree, Editor->LastFree, Result);
|
||||||
*Result = {};
|
*Result = {};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Result = PushStruct(Arena, scene_nav_item_node);
|
Result = PushStruct(Arena, scene_nav_item_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLInsertLast(Editor->Items.First, Editor->Items.Last, Result);
|
Result->HoverTextStringChunk = W_StringChunkAlloc(Arena, &Editor->FreeStrings);
|
||||||
Editor->Items.Count += 1;
|
Result->ActionStringChunk = W_StringChunkAlloc(Arena, &Editor->FreeStrings);
|
||||||
return(Result);
|
|
||||||
|
Result->Item.HoverText.Data = Result->HoverTextStringChunk->Data;
|
||||||
|
Result->Item.Action.Content.Data = Result->ActionStringChunk->Data;
|
||||||
|
|
||||||
|
DLLInsertLast(Editor->Items.First, Editor->Items.Last, Result);
|
||||||
|
Editor->Items.Count += 1;
|
||||||
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_SceneNavItemNodeRelease(workspace_view_nav_editor *Editor, scene_nav_item_node *Node)
|
static void W_SceneNavItemNodeRelease(workspace_view_nav_editor *Editor, scene_nav_item_node *Node)
|
||||||
{
|
{
|
||||||
DLLInsertLast(Editor->FirstFree, Editor->LastFree, Node);
|
W_StringChunkRelease(&Editor->FreeStrings, Node->HoverTextStringChunk);
|
||||||
Editor->Items.Count -= 1;
|
W_StringChunkRelease(&Editor->FreeStrings, Node->ActionStringChunk);
|
||||||
|
DLLRemove(Editor->Items.First, Editor->Items.Last, Node);
|
||||||
|
DLLInsertLast(Editor->FirstFree, Editor->LastFree, Node);
|
||||||
|
Editor->Items.Count -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_SetupNavEditor(workspace_view *View, string FileContents)
|
static void W_NavEditorInspectNode(workspace_view_nav_editor *Editor, scene_nav_item_node *Node)
|
||||||
{
|
{
|
||||||
//- sixten(TODO): deserialize data
|
Editor->SelectedItem = Node;
|
||||||
|
Editor->TextureDropdownOpen = false;
|
||||||
|
Editor->NavActionDropdownOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void W_NavEditorSetup(workspace_view *View, string FilePath, string FileName, string FileContents)
|
||||||
|
{
|
||||||
|
workspace_view_nav_editor *Editor = (workspace_view_nav_editor *)View->Data;
|
||||||
|
|
||||||
|
//- sixten: setup file info
|
||||||
|
Editor->FileName = PushString(View->Arena, FileName);
|
||||||
|
Editor->FilePath = PushString(View->Arena, FilePath);
|
||||||
|
|
||||||
|
//- sixten: deserialize data
|
||||||
|
if(FileContents.Count != 0)
|
||||||
|
{
|
||||||
|
u8 *DataBegin = FileContents.Data;
|
||||||
|
u8 *Byte = DataBegin;
|
||||||
|
|
||||||
|
u16 ItemCount = *(u16 *)Byte;
|
||||||
|
Byte += 2;
|
||||||
|
|
||||||
|
//- sixten: parse items
|
||||||
|
for(u64 ItemIndex = 0; ItemIndex < ItemCount; ItemIndex += 1)
|
||||||
|
{
|
||||||
|
scene_nav_item_node *Node = W_SceneNavItemNodeAlloc(View->Arena, Editor);
|
||||||
|
scene_nav_item *Item = &Node->Item;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
switch(*Byte++)
|
||||||
|
{
|
||||||
|
case S_NavItemOp_TextureID:
|
||||||
|
{
|
||||||
|
string AssetName;
|
||||||
|
AssetName.Count = *(u16 *)Byte;
|
||||||
|
Byte += sizeof(u16);
|
||||||
|
AssetName.Data = Byte;
|
||||||
|
Byte += AssetName.Count;
|
||||||
|
|
||||||
|
Item->TextureID = AssetID_Error;
|
||||||
|
for(u64 AssetIndex = 0; AssetIndex < AssetID_COUNT; AssetIndex += 1)
|
||||||
|
{
|
||||||
|
if(AreEqual(MakeString(AssetNameLUT[AssetIndex]), AssetName))
|
||||||
|
{
|
||||||
|
Item->TextureID = AssetIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} goto Next;
|
||||||
|
case S_NavItemOp_Scale:
|
||||||
|
{
|
||||||
|
Item->Scale = *(r32 *)Byte;
|
||||||
|
Byte += sizeof(r32);
|
||||||
|
} goto Next;
|
||||||
|
case S_NavItemOp_Origin:
|
||||||
|
{
|
||||||
|
Item->Origin = *(v2_r32 *)Byte;
|
||||||
|
Byte += sizeof(v2_r32);
|
||||||
|
} goto Next;
|
||||||
|
case S_NavItemOp_P:
|
||||||
|
{
|
||||||
|
Item->P = *(v2_r32 *)Byte;
|
||||||
|
Byte += sizeof(v2_r32);
|
||||||
|
} goto Next;
|
||||||
|
case S_NavItemOp_HoverText:
|
||||||
|
{
|
||||||
|
Item->HoverText.Count = *(u16 *)Byte;
|
||||||
|
Byte += 2;
|
||||||
|
Assert(Item->HoverText.Count <= W_STRING_CHUNK_SIZE-2*sizeof(void *));
|
||||||
|
|
||||||
|
Copy(Item->HoverText.Data, Byte, Item->HoverText.Count);
|
||||||
|
Byte += Item->HoverText.Count;
|
||||||
|
} goto Next;
|
||||||
|
case S_NavItemOp_Action:
|
||||||
|
{
|
||||||
|
Item->Action.Kind = (scene_nav_action_kind)*Byte;
|
||||||
|
Byte += 1;
|
||||||
|
|
||||||
|
Item->Action.Content.Count = *(u16 *)Byte;
|
||||||
|
Byte += 2;
|
||||||
|
Assert(Item->Action.Content.Count <= W_STRING_CHUNK_SIZE-2*sizeof(void *));
|
||||||
|
|
||||||
|
Copy(Item->Action.Content.Data, Byte, Item->Action.Content.Count);
|
||||||
|
Byte += Item->Action.Content.Count;
|
||||||
|
} goto Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: no op found, assume item done
|
||||||
|
break;
|
||||||
|
|
||||||
|
Next:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_BuildNavEditor(workspace_view *View)
|
static void W_BuildNavEditor(workspace_view *View)
|
||||||
{
|
{
|
||||||
workspace_view_nav_editor *Editor = (workspace_view_nav_editor *)View->Data;
|
workspace_view_nav_editor *Editor = (workspace_view_nav_editor *)View->Data;
|
||||||
scene_view *SceneView = SV_GetState();
|
scene_view *SceneView = SV_GetState();
|
||||||
|
|
||||||
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
|
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
|
||||||
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
|
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
|
||||||
UI_WidthFill UI_Height(UI_Em(2.0f, 1.0f))
|
UI_WidthFill UI_Height(UI_Em(2.0f, 1.0f))
|
||||||
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Workspace Nav Editor Toolbar"))
|
UI_LayoutAxis(Axis2_X)
|
||||||
{
|
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Workspace Nav Editor Toolbar"))
|
||||||
UI_Width(UI_TextContent(10, 1.0f)) UI_Font(Font_Icons) if(UI_ButtonF("%U", FontIcon_UserPlus).Clicked)
|
{
|
||||||
{
|
UI_Width(UI_Em(2.0f, 1.0f)) UI_Font(Font_Icons) UI_CornerRadius(4.0f)
|
||||||
scene_nav_item_node *NewNode = W_SceneNavItemNodeAlloc(View->Arena, Editor);
|
{
|
||||||
NewNode->Item = G_DefaultSceneNavItem;
|
//- sixten: create nav item button
|
||||||
}
|
if(UI_ButtonF("%U", FontIcon_UserPlus).Clicked)
|
||||||
}
|
{
|
||||||
|
scene_nav_item_node *Node = W_SceneNavItemNodeAlloc(View->Arena, Editor);
|
||||||
UI_Row()
|
|
||||||
{
|
//- sixten: apply default options
|
||||||
//- sixten: build inspector panel
|
Node->Item.Scale = 0.01f;
|
||||||
UI_Width(UI_Percent(0.2f, 1.0f)) UI_HeightFill
|
Node->Item.Origin = V2R32(0.5, 1.0f);
|
||||||
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder, StrLit("Workspace Nav Editor Inspector")))
|
Node->Item.P = V2R32(0.0, 0.0f);
|
||||||
{
|
Node->Item.TextureID = AssetID_ArthurNormal;
|
||||||
scene_nav_item_node *SelectedItem = Editor->SelectedItem;
|
}
|
||||||
if(SelectedItem)
|
|
||||||
{
|
//- sixten: create save nav items button
|
||||||
}
|
if(UI_ButtonF("%U", FontIcon_Floppy).Clicked)
|
||||||
else UI_WidthFill
|
{
|
||||||
{
|
W_NavEditorSerializeItems(Editor);
|
||||||
UI_LabelF("No item selected.");
|
}
|
||||||
}
|
|
||||||
}
|
//- sixten: create force reload
|
||||||
|
if(UI_ButtonF("%U", FontIcon_ArrowsCW).Clicked)
|
||||||
//- sixten: build nav view
|
{
|
||||||
UI_Row()
|
SV_LoadNavItems();
|
||||||
{
|
}
|
||||||
//- sixten: calculate nav view size
|
}
|
||||||
r32 VerticalPad = 0;
|
}
|
||||||
r32 HorizontalPad = 0;
|
|
||||||
{
|
UI_Row()
|
||||||
ui_box *ParentBox = UI_TopParent();
|
{
|
||||||
v2_r32 ParentDim = DimOfRange(ParentBox->Rect);
|
//- sixten: build inspector panel
|
||||||
|
scene_nav_item_node *SelectedItem = Editor->SelectedItem;
|
||||||
r32 WidthOverHeight = ParentDim.x / ParentDim.y;
|
UI_SetNextLayoutAxis(Axis2_X);
|
||||||
r32 TargetRatio = 16.0f / 9.0f;
|
UI_Width(UI_Em(24.0f*AC_AnimateValueF(SelectedItem != 0, 0, 0.3f, "Workspace Nav Editor Inspector %p", Editor), 1.0f)) UI_HeightFill
|
||||||
if(WidthOverHeight > TargetRatio)
|
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder, StrLit("Workspace Nav Editor Inspector")))
|
||||||
{
|
UI_Padding(UI_Em(1, 1)) UI_Width(UI_Percent(1.0f, 0.0f)) UI_Column()
|
||||||
VerticalPad = ParentDim.x - ParentDim.y*TargetRatio;
|
{
|
||||||
}
|
if(SelectedItem)
|
||||||
else
|
{
|
||||||
{
|
UI_CornerRadius(4.0f) UI_Width(UI_Percent(1, 1)) UI_Height(UI_TextContent(15, 1))
|
||||||
HorizontalPad = ParentDim.y - ParentDim.x/TargetRatio;
|
{
|
||||||
}
|
//- sixten: inspect position
|
||||||
}
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f)) {UI_LabelF("Position X:"); UI_Font(Font_Monospace) UI_LabelF("%f", SelectedItem->Item.P.x);}
|
||||||
//- sixten: do the building of the nav view
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f)) {UI_LabelF("Position Y:"); UI_Font(Font_Monospace) UI_LabelF("%f", SelectedItem->Item.P.y);}
|
||||||
UI_Padding(UI_Pixels(VerticalPad/2, 1))
|
|
||||||
{
|
//- sixten: inspect scale
|
||||||
UI_Column() UI_Padding(UI_Pixels(HorizontalPad/2, 1))
|
UI_Row() UI_Width(UI_Percent(0.5f, 1.0f))
|
||||||
{
|
{
|
||||||
UI_SetNextWidth(UI_Percent(1, 0));
|
UI_LabelF("Scale:");
|
||||||
UI_SetNextHeight(UI_Percent(1, 0));
|
UI_Font(Font_Monospace)
|
||||||
UI_SetNextLayoutAxis(Axis2_Y);
|
{
|
||||||
|
UI_SetNextHoverCursor(PlatformCursor_ArrowHorizontal);
|
||||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_Clip, StrLit("Nav View"));
|
ui_box *ScaleBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%f##Scale", SelectedItem->Item.Scale);
|
||||||
UI_EquipBoxCustomDrawCallback(Box, BuildNavViewDrawCallback, SceneView);
|
|
||||||
|
ui_signal ScaleSignal = UI_SignalFromBox(ScaleBox);
|
||||||
v2_r32 BoxDim = UI_CalculateBoxDim(Box);
|
if(ScaleSignal.Dragging)
|
||||||
r32 GlobalScale = CalculateGlobalScaleFromDim(BoxDim);
|
{
|
||||||
|
if(ScaleSignal.Pressed)
|
||||||
//- sixten: build all nav items
|
{
|
||||||
s32 ItemIndex = 0;
|
UI_StoreDragR32(SelectedItem->Item.Scale);
|
||||||
for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next, ItemIndex += 1)
|
}
|
||||||
{
|
|
||||||
scene_nav_item *Item = &Node->Item;
|
SelectedItem->Item.Scale = UI_GetDragR32() + ScaleSignal.DragDelta.x*0.001f;
|
||||||
|
}
|
||||||
//- sixten: calculate item position
|
}
|
||||||
r32 AppliedScale = GlobalScale*Item->Scale;
|
}
|
||||||
render_handle Texture = TextureFromAssetID(Item->TextureID);
|
|
||||||
v2_r32 TextureDim = ConvertV2ToR32(DimFromTexture(Texture));
|
//- sixten: inspect texture
|
||||||
v2_r32 TextureOrigin = Hadamard(TextureDim, Item->Origin);
|
UI_Row(0, StrLit("Texture")) UI_Width(UI_Percent(0.5f, 1.0f))
|
||||||
v2_r32 Dim = TextureDim*AppliedScale;
|
{
|
||||||
v2_r32 OriginP = TextureOrigin*AppliedScale;
|
UI_LabelF("Texture:");
|
||||||
|
UI_DropdownSelection(AssetNameLUT, ArrayCount(AssetNameLUT), &Editor->TextureDropdownOpen, &SelectedItem->Item.TextureID);
|
||||||
//- sixten: build the item
|
}
|
||||||
scene_nav_item_info *Data = PushStruct(UI_FrameArena(), scene_nav_item_info);
|
|
||||||
Data->Item = Item;
|
//- sixten: inspect nav action kind
|
||||||
|
UI_Row(0, StrLit("Nav Action")) UI_Width(UI_Percent(0.5f, 1.0f))
|
||||||
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
{
|
||||||
UI_SetNextSize(UI_Pixels(Dim.x, 1), UI_Pixels(Dim.y, 1));
|
UI_LabelF("Nav Action Type:");
|
||||||
ui_box *ItemBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY,
|
char *Actions[] = { "None", "Trigger Proc", "Change Scene" };
|
||||||
"View Item Box %i", ItemIndex);
|
UI_DropdownSelection(Actions, ArrayCount(Actions), &Editor->NavActionDropdownOpen, (s32 *)&SelectedItem->Item.Action);
|
||||||
UI_EquipBoxCustomDrawCallback(ItemBox, BuildNavItemDrawCallback, Data);
|
}
|
||||||
|
|
||||||
//- sixten: handle signals
|
//- sixten: inspect nav action contents
|
||||||
{
|
UI_Row(0, StrLit("Nav Action String")) UI_Width(UI_Percent(0.5f, 1.0f))
|
||||||
ui_signal Signal = UI_SignalFromBox(ItemBox);
|
{
|
||||||
Data->Signal = Signal;
|
UI_LabelF("Nav Action Contents:");
|
||||||
|
ui_signal Signal = UI_LineEdit(&Editor->NavActionStringEditState, ArrayCount(SelectedItem->ActionStringChunk->Data), SelectedItem->ActionStringChunk->Data, &SelectedItem->Item.Action.Content.Count, StrLit("Nav Action Text"), Editor->ActiveTextThing == 1);
|
||||||
//- sixten: inspect pressed item
|
if(AreEqual(UI_ActiveKey(), Signal.Box->Key))
|
||||||
if(Signal.Pressed)
|
{
|
||||||
{
|
Editor->ActiveTextThing = 1;
|
||||||
Editor->SelectedItem = Node;
|
}
|
||||||
}
|
else if(!AreEqual(UI_ActiveKey(), UI_EmptyKey()) && Editor->ActiveTextThing == 1)
|
||||||
|
{
|
||||||
//- sixten: handle dragging
|
Editor->ActiveTextThing = 0;
|
||||||
if(Signal.Dragging)
|
}
|
||||||
{
|
}
|
||||||
if(Signal.Pressed)
|
|
||||||
{
|
//- sixten: inspect hover text
|
||||||
UI_StoreDragV2(Item->P);
|
UI_Row(0, StrLit("Hover Text")) UI_Width(UI_Percent(0.5f, 1.0f))
|
||||||
}
|
{
|
||||||
|
UI_LabelF("Hover Text:");
|
||||||
Item->P = UI_GetDragV2() + Signal.DragDelta/BoxDim*2;
|
ui_signal Signal = UI_LineEdit(&Editor->HoverTextEditState, ArrayCount(SelectedItem->HoverTextStringChunk->Data), SelectedItem->HoverTextStringChunk->Data, &SelectedItem->Item.HoverText.Count, StrLit("Hover Text Input"), Editor->ActiveTextThing == 2);
|
||||||
}
|
if(AreEqual(UI_ActiveKey(), Signal.Box->Key))
|
||||||
}
|
{
|
||||||
|
Editor->ActiveTextThing = 2;
|
||||||
//- sixten: apply the calculated position
|
}
|
||||||
v2_r32 OffsetP = BoxDim*(V2R32(1, 1) + Item->P)*0.5f;
|
else if(!AreEqual(UI_ActiveKey(), UI_EmptyKey()) && Editor->ActiveTextThing == 2)
|
||||||
ItemBox->FixedP = (OffsetP-OriginP);
|
{
|
||||||
}
|
Editor->ActiveTextThing = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
UI_Spacer(UI_TextContent(15, 1));
|
||||||
|
|
||||||
|
UI_Row() UI_FillPadding
|
||||||
|
{
|
||||||
|
UI_Width(UI_TextContent(15, 1)) if(UI_ButtonF("Remove Item").Pressed)
|
||||||
|
{
|
||||||
|
W_SceneNavItemNodeRelease(Editor, SelectedItem);
|
||||||
|
Editor->SelectedItem = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: build nav view
|
||||||
|
UI_Width(UI_Percent(1, 0)) UI_Height(UI_Percent(1, 0)) UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip, "Workspace View Nav Editor Thing"))
|
||||||
|
{
|
||||||
|
//- sixten: calculate nav view size
|
||||||
|
v2_r32 ParentDim = DimOfRange(UI_TopParent()->Rect);
|
||||||
|
v2_r32 BoxDim = ParentDim;
|
||||||
|
|
||||||
|
r32 TargetRatio = 16.0f/9.0f;
|
||||||
|
r32 ActualRatio = ParentDim.x/ParentDim.y;
|
||||||
|
|
||||||
|
if(ActualRatio>TargetRatio)
|
||||||
|
{
|
||||||
|
BoxDim.x = BoxDim.y*TargetRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BoxDim.y = BoxDim.x/TargetRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_SetNextWidth(UI_Pixels(BoxDim.x, 1));
|
||||||
|
UI_SetNextHeight(UI_Pixels(BoxDim.y, 1));
|
||||||
|
UI_SetNextLayoutAxis(Axis2_Y);
|
||||||
|
UI_SetNextFixedP((ParentDim-BoxDim)*0.5f);
|
||||||
|
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_Clickable, "Nav View %p", View);
|
||||||
|
UI_EquipBoxCustomDrawCallback(Box, BuildNavViewDrawCallback, SceneView);
|
||||||
|
|
||||||
|
r32 GlobalScale = CalculateGlobalScaleFromDim(BoxDim);
|
||||||
|
|
||||||
|
//- sixten: build all nav items
|
||||||
|
s32 ItemIndex = 0;
|
||||||
|
UI_Parent(Box) for(scene_nav_item_node *Node = Editor->Items.First; Node != 0; Node = Node->Next, ItemIndex += 1)
|
||||||
|
{
|
||||||
|
scene_nav_item *Item = &Node->Item;
|
||||||
|
|
||||||
|
//- sixten: calculate item position
|
||||||
|
r32 AppliedScale = GlobalScale*Item->Scale;
|
||||||
|
render_handle Texture = TextureFromAssetID(Item->TextureID);
|
||||||
|
v2_r32 TextureDim = ConvertV2ToR32(DimFromTexture(Texture));
|
||||||
|
v2_r32 TextureOrigin = Hadamard(TextureDim, Item->Origin);
|
||||||
|
v2_r32 Dim = TextureDim*AppliedScale;
|
||||||
|
v2_r32 OriginP = TextureOrigin*AppliedScale;
|
||||||
|
|
||||||
|
//- sixten: build the item
|
||||||
|
scene_nav_item_info *Data = PushStruct(UI_FrameArena(), scene_nav_item_info);
|
||||||
|
Data->Item = Item;
|
||||||
|
|
||||||
|
UI_SetNextHoverCursor(PlatformCursor_Hand);
|
||||||
|
UI_SetNextSize(UI_Pixels(Dim.x, 1), UI_Pixels(Dim.y, 1));
|
||||||
|
ui_box *ItemBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|((Node==Editor->SelectedItem)?UI_BoxFlag_DrawBorder:0),
|
||||||
|
"View Item Box %i", ItemIndex);
|
||||||
|
UI_EquipBoxCustomDrawCallback(ItemBox, BuildNavItemDrawCallback, Data);
|
||||||
|
|
||||||
|
if(Node == Editor->SelectedItem)
|
||||||
|
{
|
||||||
|
// sixten(TODO): this:
|
||||||
|
//ui_box *OriginBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, "View Item Origin Box %i", ItemIndex);
|
||||||
|
}
|
||||||
|
//- sixten: handle signals
|
||||||
|
{
|
||||||
|
ui_signal Signal = UI_SignalFromBox(ItemBox);
|
||||||
|
Data->Signal = Signal;
|
||||||
|
|
||||||
|
//- sixten: inspect pressed item
|
||||||
|
if(Signal.Clicked && Signal.DragDelta == V2R32(0, 0))
|
||||||
|
{
|
||||||
|
W_NavEditorInspectNode(Editor, Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: handle dragging
|
||||||
|
if(Signal.Dragging)
|
||||||
|
{
|
||||||
|
if(Signal.Pressed)
|
||||||
|
{
|
||||||
|
UI_StoreDragV2(Item->P);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item->P = UI_GetDragV2() + Signal.DragDelta/BoxDim*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sixten: apply the calculated position
|
||||||
|
v2_r32 OffsetP = BoxDim*(V2R32(1, 1) + Item->P)*0.5f;
|
||||||
|
ItemBox->FixedP = (OffsetP-OriginP);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_signal BackgroundSignal = UI_SignalFromBox(Box);
|
||||||
|
if(BackgroundSignal.Pressed)
|
||||||
|
{
|
||||||
|
W_NavEditorInspectNode(Editor, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,35 +3,68 @@
|
||||||
#ifndef VN_WORKSPACE_NAV_EDITOR_H
|
#ifndef VN_WORKSPACE_NAV_EDITOR_H
|
||||||
#define VN_WORKSPACE_NAV_EDITOR_H
|
#define VN_WORKSPACE_NAV_EDITOR_H
|
||||||
|
|
||||||
|
#define W_STRING_CHUNK_SIZE 128
|
||||||
|
|
||||||
|
struct workspace_string_chunk
|
||||||
|
{
|
||||||
|
workspace_string_chunk *Next;
|
||||||
|
workspace_string_chunk *Prev;
|
||||||
|
u8 Data[W_STRING_CHUNK_SIZE - 2*sizeof(workspace_string_chunk *)];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct workspace_string_chunk_list
|
||||||
|
{
|
||||||
|
workspace_string_chunk *First;
|
||||||
|
workspace_string_chunk *Last;
|
||||||
|
};
|
||||||
|
|
||||||
struct scene_nav_item_node
|
struct scene_nav_item_node
|
||||||
{
|
{
|
||||||
scene_nav_item_node *Next;
|
scene_nav_item_node *Next;
|
||||||
scene_nav_item_node *Prev;
|
scene_nav_item_node *Prev;
|
||||||
|
|
||||||
scene_nav_item Item;
|
workspace_string_chunk *HoverTextStringChunk;
|
||||||
|
workspace_string_chunk *ActionStringChunk;
|
||||||
|
scene_nav_item Item;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scene_nav_item_list
|
struct scene_nav_item_list
|
||||||
{
|
{
|
||||||
scene_nav_item_node *First;
|
scene_nav_item_node *First;
|
||||||
scene_nav_item_node *Last;
|
scene_nav_item_node *Last;
|
||||||
u64 Count;
|
u64 Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct workspace_view_nav_editor
|
struct workspace_view_nav_editor
|
||||||
{
|
{
|
||||||
//- sixten: items
|
//- sixten: items
|
||||||
scene_nav_item_list Items;
|
scene_nav_item_list Items;
|
||||||
scene_nav_item_node *FirstFree;
|
scene_nav_item_node *FirstFree;
|
||||||
scene_nav_item_node *LastFree;
|
scene_nav_item_node *LastFree;
|
||||||
|
|
||||||
scene_nav_item_node *SelectedItem;
|
//- sixten: strings
|
||||||
|
workspace_string_chunk_list FreeStrings;
|
||||||
|
|
||||||
|
//- sixten: inspect info
|
||||||
|
scene_nav_item_node *SelectedItem;
|
||||||
|
b32 TextureDropdownOpen;
|
||||||
|
b32 NavActionDropdownOpen;
|
||||||
|
text_edit_state NavActionStringEditState;
|
||||||
|
text_edit_state HoverTextEditState;
|
||||||
|
s32 ActiveTextThing;
|
||||||
|
|
||||||
|
//- sixten: file info
|
||||||
|
string FileName;
|
||||||
|
string FilePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void W_NavEditorSerializeItems(workspace_view_nav_editor *Editor);
|
||||||
|
|
||||||
static scene_nav_item_node *W_SceneNavItemNodeAlloc(arena *Arena, workspace_view_nav_editor *Editor);
|
static scene_nav_item_node *W_SceneNavItemNodeAlloc(arena *Arena, workspace_view_nav_editor *Editor);
|
||||||
static void W_SceneNavItemNodeRelease(workspace_view_nav_editor *Editor, scene_nav_item_node *Node);
|
static void W_SceneNavItemNodeRelease(workspace_view_nav_editor *Editor, scene_nav_item_node *Node);
|
||||||
|
|
||||||
static void W_SetupNavEditor(workspace_view *View, string FileContents);
|
static void W_NavEditorInspectNode(scene_nav_item_node *Node);
|
||||||
|
static void W_NavEditorSetup(workspace_view *View, string FilePath, string FileName, string FileContents);
|
||||||
static void W_BuildNavEditor(workspace_view *View);
|
static void W_BuildNavEditor(workspace_view *View);
|
||||||
|
|
||||||
#endif //VN_WORKSPACE_NAV_EDITOR_H
|
#endif //VN_WORKSPACE_NAV_EDITOR_H
|
||||||
|
|
|
@ -1,435 +1,559 @@
|
||||||
//- sixten: Views
|
//- sixten: Views
|
||||||
inline workspace_view *W_CreateNewView(workspace_view_kind Kind, workspace_panel *Parent)
|
inline workspace_view *W_CreateNewView(workspace_view_kind Kind, workspace_panel *Parent)
|
||||||
{
|
{
|
||||||
arena *Arena = ArenaAlloc(Kilobytes(4), true);
|
arena *Arena = ArenaAlloc(Kilobytes(4), true);
|
||||||
workspace_view *View = PushStruct(Arena, workspace_view);
|
workspace_view *View = PushStruct(Arena, workspace_view);
|
||||||
View->Arena = Arena;
|
View->Arena = Arena;
|
||||||
View->Kind = Kind;
|
View->Kind = Kind;
|
||||||
View->Parent = Parent;
|
View->Parent = Parent;
|
||||||
|
|
||||||
switch(View->Kind)
|
switch(View->Kind)
|
||||||
{
|
{
|
||||||
case W_ViewKind_Settings:
|
case W_ViewKind_Settings:
|
||||||
{
|
{
|
||||||
View->Data = PushStruct(View->Arena, workspace_view_settings);
|
View->Data = PushStruct(View->Arena, workspace_view_settings);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case W_ViewKind_FileLister:
|
case W_ViewKind_FileLister:
|
||||||
{
|
{
|
||||||
workspace_view_file_lister *Lister = PushStruct(View->Arena, workspace_view_file_lister);
|
workspace_view_file_lister *Lister = PushStruct(View->Arena, workspace_view_file_lister);
|
||||||
View->Data = Lister;
|
View->Data = Lister;
|
||||||
|
Lister->Path = StrLit("data");
|
||||||
Lister->SelectedItem = -1;
|
|
||||||
} break;
|
Lister->SelectedItem = -1;
|
||||||
|
} break;
|
||||||
case W_ViewKind_TextEditor:
|
|
||||||
{
|
case W_ViewKind_TextEditor:
|
||||||
View->Data = PushStruct(View->Arena, workspace_view_text_editor);
|
{
|
||||||
|
View->Data = PushStruct(View->Arena, workspace_view_text_editor);
|
||||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
|
||||||
Editor->ProcessingArena = ArenaAlloc(Gigabytes(1));
|
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||||
Editor->Text = MutableStringAllocate(Gigabytes(1));
|
Editor->ProcessingArena = ArenaAlloc(Gigabytes(1));
|
||||||
Editor->HistoryArena = ArenaAlloc(Gigabytes(1));
|
Editor->Text = MutableStringAllocate(Gigabytes(1));
|
||||||
|
Editor->HistoryArena = ArenaAlloc(Gigabytes(1));
|
||||||
SenDLLInit(&Editor->History.Sentinel);
|
|
||||||
Editor->History.At = &Editor->History.Sentinel;
|
SenDLLInit(&Editor->History.Sentinel);
|
||||||
Editor->SavePoint = Editor->History.At;
|
Editor->History.At = &Editor->History.Sentinel;
|
||||||
|
Editor->SavePoint = Editor->History.At;
|
||||||
workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String);
|
|
||||||
Editor->Tokens = TextData.Tokens;
|
workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String);
|
||||||
Editor->Lines = TextData.Lines;
|
Editor->Tokens = TextData.Tokens;
|
||||||
} break;
|
Editor->Lines = TextData.Lines;
|
||||||
|
} break;
|
||||||
case W_ViewKind_NavEditor:
|
|
||||||
{
|
case W_ViewKind_NavEditor:
|
||||||
View->Data = PushStruct(View->Arena, workspace_view_nav_editor);
|
{
|
||||||
} break;
|
View->Data = PushStruct(View->Arena, workspace_view_nav_editor);
|
||||||
|
} break;
|
||||||
case W_ViewKind_Error:
|
|
||||||
{
|
case W_ViewKind_ImageViewer:
|
||||||
View->Data = PushStruct(View->Arena, workspace_view_error);
|
{
|
||||||
} break;
|
View->Data = PushStruct(View->Arena, workspace_view_image_viewer);
|
||||||
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)View->Data;
|
||||||
default: break;
|
Viewer->Scale = 1.0f;
|
||||||
}
|
//- sixten(TODO): write an image viewer
|
||||||
|
// beign with loading the image from the file lister load thingy
|
||||||
DLLInsertLast(Parent->FirstView, Parent->LastView, View);
|
// show it on build
|
||||||
|
// release the handle when done (and add a way to remove texture ig)
|
||||||
if(View->Parent)
|
} break;
|
||||||
{
|
|
||||||
Parent->CurrentView = View;
|
case W_ViewKind_Error:
|
||||||
}
|
{
|
||||||
|
View->Data = PushStruct(View->Arena, workspace_view_error);
|
||||||
return(View);
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLInsertLast(Parent->FirstView, Parent->LastView, View);
|
||||||
|
|
||||||
|
if(View->Parent)
|
||||||
|
{
|
||||||
|
Parent->CurrentView = View;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(View);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void W_DestroyView(workspace_view *View)
|
inline void W_DestroyView(workspace_view *View)
|
||||||
{
|
{
|
||||||
switch(View->Kind)
|
switch(View->Kind)
|
||||||
{
|
{
|
||||||
case W_ViewKind_TextEditor:
|
case W_ViewKind_TextEditor:
|
||||||
{
|
{
|
||||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||||
ArenaRelease(Editor->ProcessingArena);
|
ArenaRelease(Editor->ProcessingArena);
|
||||||
MutableStringRelease(&Editor->Text);
|
MutableStringRelease(&Editor->Text);
|
||||||
ArenaRelease(Editor->HistoryArena);
|
ArenaRelease(Editor->HistoryArena);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
case W_ViewKind_ImageViewer:
|
||||||
}
|
{
|
||||||
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)View->Data;
|
||||||
// sixten(NOTE): This function does not ensure that the view is not being used anywhere else.
|
GlobalRenderCommands->DeallocateTexture(Viewer->Texture);
|
||||||
ArenaRelease(View->Arena);
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sixten(NOTE): This function does not ensure that the view is not being used anywhere else.
|
||||||
|
ArenaRelease(View->Arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline b32 W_ViewIsCurrent(workspace_view *View)
|
inline b32 W_ViewIsCurrent(workspace_view *View)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
|
|
||||||
b32 Result = (Workspace->CurrentPanel && Workspace->CurrentPanel->CurrentView == View);
|
b32 Result = (Workspace->CurrentPanel && Workspace->CurrentPanel->CurrentView == View);
|
||||||
return(Result);
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string W_GetViewName(arena *Arena, workspace_view *View)
|
inline string W_NameFromView(arena *Arena, workspace_view *View)
|
||||||
{
|
{
|
||||||
string Result = StrLit("Unnamed view");
|
string Result = StrLit("Unnamed view");
|
||||||
switch(View->Kind)
|
switch(View->Kind)
|
||||||
{
|
{
|
||||||
case W_ViewKind_Startup: { Result = StrLit("Welcome"); } break;
|
case W_ViewKind_Startup: { Result = StrLit("Welcome"); } break;
|
||||||
case W_ViewKind_Settings: { Result = StrLit("Settings"); } break;
|
case W_ViewKind_Settings: { Result = StrLit("Settings"); } break;
|
||||||
case W_ViewKind_TextEditor:
|
case W_ViewKind_TextEditor:
|
||||||
{
|
{
|
||||||
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
|
||||||
if(AreEqual(Editor->FileName, StrLit("")))
|
if(AreEqual(Editor->FileName, StrLit("")))
|
||||||
{
|
{
|
||||||
Result = StrLit("Open File");
|
Result = StrLit("Open File");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//if(Editor->History.At == &Editor->History.Sentinel)
|
if(Editor->History.At == Editor->SavePoint)
|
||||||
if(Editor->History.At == Editor->SavePoint)
|
{
|
||||||
{
|
Result = PushString(Arena, Editor->FileName);
|
||||||
Result = PushString(Arena, Editor->FileName);
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
Result = PushFormat(Arena, "* %S", Editor->FileName);
|
||||||
Result = PushFormat(Arena, "* %S", Editor->FileName);
|
}
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
} break;
|
case W_ViewKind_SceneView: { Result = StrLit("Scene View"); } break;
|
||||||
case W_ViewKind_SceneView: { Result = StrLit("Scene View"); } break;
|
case W_ViewKind_NavEditor: { Result = StrLit("Navigation Editor"); } break;
|
||||||
case W_ViewKind_NavEditor: { Result = StrLit("Navigation Editor"); } break;
|
case W_ViewKind_FileLister: { Result = StrLit("File Lister"); } break;
|
||||||
case W_ViewKind_FileLister: { Result = StrLit("File Lister"); } break;
|
case W_ViewKind_ImageViewer:
|
||||||
case W_ViewKind_Error: { Result = StrLit("Error"); } break;
|
{
|
||||||
default: {} break;
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)View->Data;
|
||||||
}
|
Result = PushString(Arena, Viewer->FileName);
|
||||||
|
} break;
|
||||||
return(Result);
|
case W_ViewKind_Error: { Result = StrLit("Error"); } break;
|
||||||
|
default: {} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static b32 W_ImageViewerSetup(workspace_view *View, string Name, string Contents)
|
||||||
|
{
|
||||||
|
b32 Result = false;
|
||||||
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)View->Data;
|
||||||
|
Viewer->Texture = EmptyRenderHandle();
|
||||||
|
if(Contents.Count && Contents.Data)
|
||||||
|
{
|
||||||
|
s32 Width, Height, BPP;
|
||||||
|
u8 *TextureData = stbi_load_from_memory(Contents.Data, Contents.Count, &Width, &Height, &BPP, 0);
|
||||||
|
if(TextureData)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Viewer->Texture = GlobalRenderCommands->AllocateTexture(V2S32(Width, Height), TextureFormat, true, TextureData);
|
||||||
|
|
||||||
|
Result = true;
|
||||||
|
|
||||||
|
stbi_image_free(TextureData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Viewer->FileName = PushString(View->Arena, Name);
|
||||||
|
|
||||||
|
return(Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- sixten: Builder code
|
//- sixten: Builder code
|
||||||
|
|
||||||
static void W_BuildSettingsTabButton(workspace_view_settings *Settings, char *Name, workspace_settings_category Category)
|
static void W_BuildSettingsTabButton(workspace_view_settings *Settings, char *Name, workspace_settings_category Category)
|
||||||
{
|
{
|
||||||
b32 IsSelected = (Settings->Category == Category);
|
b32 IsSelected = (Settings->Category == Category);
|
||||||
|
|
||||||
v4 Color = LinearBlend(Theme_TextColor, Theme_HighlightBorderColor, AC_AnimateValueF(IsSelected, IsSelected, 0.3, "Workspace Settings %s %p", Name, Settings));
|
v4 Color = LinearBlend(Theme_TextColor, Theme_HighlightBorderColor, AC_AnimateValueF(IsSelected, IsSelected, 0.3, "Workspace Settings %s %p", Name, Settings));
|
||||||
|
|
||||||
UI_SetNextFont(Font_Bold);
|
UI_SetNextFont(Font_Bold);
|
||||||
UI_SetNextHeight(UI_TextContent(0, 1));
|
UI_SetNextHeight(UI_TextContent(0, 1));
|
||||||
UI_SetNextTextColor(Color);
|
UI_SetNextTextColor(Color);
|
||||||
|
|
||||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawText |
|
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawText |
|
||||||
UI_BoxFlag_Clickable,
|
UI_BoxFlag_Clickable,
|
||||||
Name);
|
Name);
|
||||||
|
|
||||||
ui_signal Signal = UI_SignalFromBox(Box);
|
ui_signal Signal = UI_SignalFromBox(Box);
|
||||||
if(Signal.Hovering)
|
if(Signal.Hovering)
|
||||||
{
|
{
|
||||||
Platform.SetCursor(PlatformCursor_Hand);
|
Platform.SetCursor(PlatformCursor_Hand);
|
||||||
}
|
}
|
||||||
if(Signal.Pressed)
|
if(Signal.Pressed)
|
||||||
{
|
{
|
||||||
Settings->Category = Category;
|
Settings->Category = Category;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *Open, s32 *Selected)
|
static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *Open, s32 *Selected)
|
||||||
{
|
{
|
||||||
b32 Result = false;
|
b32 Result = false;
|
||||||
|
b32 ActiveInDropdown = false;
|
||||||
UI_SetNextLayoutAxis(Axis2_X);
|
|
||||||
UI_Parent(UI_MakeBoxF(0, ""))
|
UI_SetNextLayoutAxis(Axis2_X);
|
||||||
{
|
ui_box *DropdownBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||||
UI_LabelF("Refresh Rate:");
|
UI_BoxFlag_DrawBorder |
|
||||||
UI_Spacer(UI_Pixels(10, 1));
|
UI_BoxFlag_HotAnimation |
|
||||||
|
UI_BoxFlag_ActiveAnimation |
|
||||||
b32 ActiveInDropdown = false;
|
UI_BoxFlag_Clickable,
|
||||||
|
"Dropdown");
|
||||||
UI_SetNextWidth(UI_Pixels(200, 1));
|
UI_Parent(DropdownBox)
|
||||||
UI_SetNextCornerRadius(4);
|
{
|
||||||
UI_SetNextLayoutAxis(Axis2_X);
|
UI_Width(UI_Percent(1, 0)) UI_LabelF(Alternatives[*Selected]);
|
||||||
ui_box *DropdownBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
UI_BackgroundColor(Theme_BorderColor) UI_Width(UI_Pixels(1, 1)) UI_MakeBoxF(UI_BoxFlag_DrawBackground, "");
|
||||||
UI_BoxFlag_DrawBorder |
|
UI_Width(UI_Pixels(25, 1)) UI_Font(Font_Icons) UI_LabelF("%U", *Open?FontIcon_DownDir:FontIcon_RightDir);
|
||||||
UI_BoxFlag_HotAnimation |
|
}
|
||||||
UI_BoxFlag_ActiveAnimation |
|
|
||||||
UI_BoxFlag_Clickable,
|
ui_signal DropdownSignal = UI_SignalFromBox(DropdownBox);
|
||||||
"Dropdown");
|
if(DropdownSignal.Pressed)
|
||||||
UI_Parent(DropdownBox)
|
{
|
||||||
{
|
*Open = !(*Open);
|
||||||
UI_Width(UI_Percent(1, 0)) UI_LabelF(Alternatives[*Selected]);
|
}
|
||||||
UI_BackgroundColor(Theme_BorderColor) UI_Width(UI_Pixels(1, 1)) UI_MakeBoxF(UI_BoxFlag_DrawBackground, "");
|
|
||||||
UI_Width(UI_Pixels(25, 1)) UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_DownDir);
|
if(AreEqual(UI_ActiveKey(), DropdownBox->Key))
|
||||||
}
|
{
|
||||||
|
ActiveInDropdown = true;
|
||||||
ui_signal DropdownSignal = UI_SignalFromBox(DropdownBox);
|
}
|
||||||
if(DropdownSignal.Pressed)
|
|
||||||
{
|
r32 OpenTransition = AC_AnimateValueF(*Open, 0, 0.175, "UI Dropdown %p%p", Alternatives, Open);
|
||||||
*Open = !(*Open);
|
|
||||||
}
|
if(OpenTransition > 0.1)
|
||||||
|
{
|
||||||
if(AreEqual(UI_ActiveKey(), DropdownBox->Key))
|
UI_Tooltip
|
||||||
{
|
{
|
||||||
ActiveInDropdown = true;
|
UI_SetNextFixedP(V2(DropdownBox->Rect.Min.x, DropdownBox->Rect.Max.y));
|
||||||
}
|
UI_SetNextCornerRadius(4);
|
||||||
|
UI_SetNextWidth(UI_Pixels(200, 1));
|
||||||
r32 OpenTransition = AC_AnimateValueF(*Open, 0, 0.175, "UI Dropdown %p%p", Alternatives, Open);
|
UI_SetNextHeight(UI_ChildrenSum(OpenTransition, 1));
|
||||||
|
UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip |
|
||||||
if(OpenTransition > 0.1)
|
UI_BoxFlag_DrawDropShadow |
|
||||||
{
|
UI_BoxFlag_FloatingX |
|
||||||
UI_Tooltip
|
UI_BoxFlag_FloatingY, "Dropdown Contents %p%p", Alternatives, Open))
|
||||||
{
|
{
|
||||||
UI_SetNextFixedP(V2(DropdownBox->Rect.Min.x, DropdownBox->Rect.Max.y));
|
UI_PushWidth(UI_Percent(1, 1));
|
||||||
UI_SetNextCornerRadius(4);
|
|
||||||
UI_SetNextWidth(UI_Pixels(200, 1));
|
for(s64 Index = 0;
|
||||||
UI_SetNextHeight(UI_ChildrenSum(OpenTransition, 1));
|
Index < Round(AlternativeCount*OpenTransition);
|
||||||
UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip |
|
++Index)
|
||||||
UI_BoxFlag_DrawDropShadow |
|
{
|
||||||
UI_BoxFlag_FloatingX |
|
ui_signal ButtonSignal = UI_ButtonF(Alternatives[Index]);
|
||||||
UI_BoxFlag_FloatingY, "Dropdown Contents"))
|
if(AreEqual(UI_ActiveKey(), ButtonSignal.Box->Key))
|
||||||
{
|
{
|
||||||
UI_PushWidth(UI_Percent(1, 1));
|
ActiveInDropdown = true;
|
||||||
|
}
|
||||||
for(s64 Index = 0;
|
|
||||||
Index < Round(AlternativeCount*OpenTransition);
|
if(ButtonSignal.Pressed)
|
||||||
++Index)
|
{
|
||||||
{
|
*Selected = Index;
|
||||||
ui_signal ButtonSignal = UI_ButtonF(Alternatives[Index]);
|
Result = true;
|
||||||
if(AreEqual(UI_ActiveKey(), ButtonSignal.Box->Key))
|
}
|
||||||
{
|
}
|
||||||
ActiveInDropdown = true;
|
|
||||||
}
|
UI_PopWidth();
|
||||||
|
}
|
||||||
if(ButtonSignal.Pressed)
|
}
|
||||||
{
|
}
|
||||||
*Selected = Index;
|
|
||||||
Result = true;
|
if(!ActiveInDropdown && !AreEqual(UI_ActiveKey(), UI_EmptyKey()))
|
||||||
}
|
{
|
||||||
}
|
*Open = false;
|
||||||
|
}
|
||||||
UI_PopWidth();
|
|
||||||
}
|
return(Result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!ActiveInDropdown && !AreEqual(UI_ActiveKey(), UI_EmptyKey()))
|
UI_CUSTOM_DRAW_CALLBACK(W_ImageViewerUICallback)
|
||||||
{
|
{
|
||||||
*Open = false;
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)Data;
|
||||||
}
|
v2_r32 ImageDim = ConvertV2ToR32(DimFromTexture(Viewer->Texture));
|
||||||
}
|
v2_r32 ScaleImageDim = ImageDim*Viewer->Scale;
|
||||||
|
|
||||||
return(Result);
|
v4 Color = Color_White;
|
||||||
|
range2_r32 Dest;
|
||||||
|
Dest.Min = (Box->Rect.Max+Box->Rect.Min)*0.5-ScaleImageDim*0.5+Viewer->Offset*Viewer->Scale;
|
||||||
|
Dest.Max = Dest.Min+ScaleImageDim;
|
||||||
|
range2_r32 Source = Range2R32(V2R32(0, 0), ImageDim);
|
||||||
|
PushTexturedQuad(Group, Dest, Source, Color, Color, Color, Color, 0, 0, 0, Viewer->Texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void W_BuildImageViewer(workspace_view *View)
|
||||||
|
{
|
||||||
|
workspace_view_image_viewer *Viewer = (workspace_view_image_viewer *)View->Data;
|
||||||
|
|
||||||
|
//- sixten: find image dim
|
||||||
|
v2_r32 ImageDim = ConvertV2ToR32(DimFromTexture(Viewer->Texture));
|
||||||
|
|
||||||
|
UI_WidthFill UI_HeightFill
|
||||||
|
{
|
||||||
|
ui_box *ImageBox = UI_MakeBoxF(UI_BoxFlag_DrawBorder|UI_BoxFlag_Clickable, "Workspace View Image Viewer %p", View);
|
||||||
|
UI_EquipBoxCustomDrawCallback(ImageBox, W_ImageViewerUICallback, Viewer);
|
||||||
|
|
||||||
|
//- sixten: handle scrolling
|
||||||
|
if(AreEqual(UI_HotKey(), ImageBox->Key))
|
||||||
|
{
|
||||||
|
for(platform_event *Event = UI_EventList()->First;
|
||||||
|
Event != 0;
|
||||||
|
Event = Event->Next)
|
||||||
|
{
|
||||||
|
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0)
|
||||||
|
{
|
||||||
|
Viewer->Scale *= Pow(1.10f, Event->Scroll.y);
|
||||||
|
Platform_ConsumeEvent(UI_EventList(), Event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_signal Signal = UI_SignalFromBox(ImageBox);
|
||||||
|
if(Signal.Dragging)
|
||||||
|
{
|
||||||
|
if(Signal.Pressed)
|
||||||
|
{
|
||||||
|
UI_StoreDragV2(Viewer->Offset);
|
||||||
|
}
|
||||||
|
v2_r32 StartOffset = UI_GetDragV2();
|
||||||
|
v2_r32 EndOffset = StartOffset+Signal.DragDelta*(1.0f/Viewer->Scale);
|
||||||
|
|
||||||
|
Viewer->Offset = EndOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UI_WidthFill UI_Height(UI_Em(3, 1))
|
||||||
|
UI_Row(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder)
|
||||||
|
{
|
||||||
|
UI_Width(UI_TextContent(15, 1))
|
||||||
|
{
|
||||||
|
UI_Label(Viewer->FileName);
|
||||||
|
UI_LabelF("Width: %i Height: %i", (int)ImageDim.x, (int)ImageDim.y);
|
||||||
|
}
|
||||||
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_BuildSceneView(workspace_view *View)
|
static void W_BuildSceneView(workspace_view *View)
|
||||||
{
|
{
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
SV_BuildSceneView(Workspace->Input);
|
SV_BuildSceneView(Workspace->Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_BuildSettings(workspace_view *View)
|
static void W_BuildSettings(workspace_view *View)
|
||||||
{
|
{
|
||||||
workspace_view_settings *Settings = (workspace_view_settings *)View->Data;
|
workspace_view_settings *Settings = (workspace_view_settings *)View->Data;
|
||||||
workspace *Workspace = W_GetState();
|
workspace *Workspace = W_GetState();
|
||||||
|
|
||||||
UI_Height(UI_ChildrenSum(1, 1))
|
UI_Height(UI_ChildrenSum(1, 1))
|
||||||
UI_Column() UI_Padding(UI_Pixels(50, 0))
|
UI_Column() UI_Padding(UI_Pixels(50, 0))
|
||||||
UI_Row() UI_Padding(UI_Pixels(50, 0))
|
UI_Row() UI_Padding(UI_Pixels(50, 0))
|
||||||
{
|
{
|
||||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||||
UI_Font(Font_Bold) UI_FontSize(36)
|
UI_Font(Font_Bold) UI_FontSize(36)
|
||||||
UI_LabelF("Settings");
|
UI_LabelF("Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_LayoutAxis(Axis2_X)
|
UI_LayoutAxis(Axis2_X)
|
||||||
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
||||||
UI_Parent(UI_MakeBoxF(0, ""))
|
UI_Parent(UI_MakeBoxF(0, ""))
|
||||||
{
|
{
|
||||||
UI_Width(UI_Pixels(300, 1))
|
UI_Width(UI_Pixels(300, 1))
|
||||||
UI_Parent(UI_MakeBoxF(0, "Navigation"))
|
UI_Parent(UI_MakeBoxF(0, "Navigation"))
|
||||||
{
|
{
|
||||||
UI_Row() UI_Padding(UI_Pixels(50, 1))
|
UI_Row() UI_Padding(UI_Pixels(50, 1))
|
||||||
UI_Width(UI_Percent(1, 0)) UI_Column() UI_Padding(UI_Percent(1, 0))
|
UI_Width(UI_Percent(1, 0)) UI_Column() UI_Padding(UI_Percent(1, 0))
|
||||||
UI_Height(UI_ChildrenSum(1, 1)) UI_LayoutAxis(Axis2_Y) UI_Parent(UI_MakeBoxF(0, ""))
|
UI_Height(UI_ChildrenSum(1, 1)) UI_LayoutAxis(Axis2_Y) UI_Parent(UI_MakeBoxF(0, ""))
|
||||||
{
|
{
|
||||||
W_BuildSettingsTabButton(Settings, "All", W_Settings_All);
|
W_BuildSettingsTabButton(Settings, "All", W_Settings_All);
|
||||||
UI_Spacer(UI_Pixels(30, 1));
|
UI_Spacer(UI_Pixels(30, 1));
|
||||||
W_BuildSettingsTabButton(Settings, "General", W_Settings_General);
|
W_BuildSettingsTabButton(Settings, "General", W_Settings_General);
|
||||||
UI_Spacer(UI_Pixels(30, 1));
|
UI_Spacer(UI_Pixels(30, 1));
|
||||||
W_BuildSettingsTabButton(Settings, "Developer", W_Settings_Developer);
|
W_BuildSettingsTabButton(Settings, "Developer", W_Settings_Developer);
|
||||||
|
|
||||||
UI_Spacer(UI_Pixels(150, 1));
|
UI_Spacer(UI_Pixels(150, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_CornerRadius(5)
|
UI_CornerRadius(5)
|
||||||
UI_Width(UI_Pixels(1.25, 1))
|
UI_Width(UI_Pixels(1.25, 1))
|
||||||
UI_BackgroundColor(Color_Grey)
|
UI_BackgroundColor(Color_Grey)
|
||||||
UI_MakeBoxF(UI_BoxFlag_DrawBackground, "Separator");
|
UI_MakeBoxF(UI_BoxFlag_DrawBackground, "Separator");
|
||||||
|
|
||||||
UI_Padding(UI_Pixels(70, 0))
|
UI_Padding(UI_Pixels(70, 0))
|
||||||
UI_LayoutAxis(Axis2_Y)
|
UI_LayoutAxis(Axis2_Y)
|
||||||
UI_Width(UI_Percent(1, 0))
|
UI_Width(UI_Percent(1, 0))
|
||||||
UI_Parent(UI_MakeBoxF(0, "Tab"))
|
UI_Parent(UI_MakeBoxF(0, "Tab"))
|
||||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||||
{
|
{
|
||||||
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
||||||
UI_Scroll(0, &Settings->GlobalScroll, UI_BoxFlag_Clip)
|
UI_Scroll(0, &Settings->GlobalScroll, UI_BoxFlag_Clip)
|
||||||
{
|
{
|
||||||
workspace_settings_category Category = Settings->Category;
|
workspace_settings_category Category = Settings->Category;
|
||||||
if(!Category || (Category == W_Settings_General))
|
if(!Category || (Category == W_Settings_General))
|
||||||
{
|
{
|
||||||
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("General");
|
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("General");
|
||||||
|
|
||||||
char *Alternatives[] = {"15 Hz", "30 Hz", "60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
|
char *Alternatives[] = {"15 Hz", "30 Hz", "60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
|
||||||
s64 AlternativeMapping[] = {15, 30, 60, 120, 144, -1, 0};
|
s64 AlternativeMapping[] = {15, 30, 60, 120, 144, -1, 0};
|
||||||
|
|
||||||
s32 DropdownSelected;
|
s32 DropdownSelected;
|
||||||
FindIndexOfElement(DropdownSelected, AlternativeMapping, 0, Workspace->Input->RefreshRate);
|
FindIndexOfElement(DropdownSelected, AlternativeMapping, 0, Workspace->Input->RefreshRate);
|
||||||
|
|
||||||
if(UI_DropdownSelection(Alternatives, ArrayCount(Alternatives),
|
UI_Row()
|
||||||
&Settings->GeneralDropdownOpen, &DropdownSelected))
|
{
|
||||||
{
|
UI_LabelF("Refresh Rate:");
|
||||||
Workspace->Input->RefreshRate = AlternativeMapping[DropdownSelected];
|
UI_Spacer(UI_Pixels(10, 1));
|
||||||
Settings->GeneralDropdownOpen = false;
|
|
||||||
}
|
UI_SetNextWidth(UI_Pixels(200, 1));
|
||||||
|
UI_SetNextCornerRadius(4);
|
||||||
UI_Spacer(UI_Pixels(50, 1));
|
if(UI_DropdownSelection(Alternatives, ArrayCount(Alternatives),
|
||||||
}
|
&Settings->GeneralDropdownOpen, &DropdownSelected))
|
||||||
|
{
|
||||||
if(!Category || (Category == W_Settings_Developer))
|
Workspace->Input->RefreshRate = AlternativeMapping[DropdownSelected];
|
||||||
{
|
Settings->GeneralDropdownOpen = false;
|
||||||
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer");
|
}
|
||||||
UI_Checkbox(&DEBUG_DebugSettings->RenderUIDebugRects, StrLit("Render UI Debug Rects"));
|
}
|
||||||
UI_Spacer(UI_Pixels(5, 1));
|
|
||||||
UI_Checkbox(&DEBUG_DebugSettings->RenderFPSCounter, StrLit("Render FPS Counter"));
|
UI_Spacer(UI_Pixels(50, 1));
|
||||||
UI_Spacer(UI_Pixels(5, 1));
|
}
|
||||||
UI_Checkbox(&DEBUG_DebugSettings->ListHotAndActive, StrLit("List Hot & Active"));
|
|
||||||
|
if(!Category || (Category == W_Settings_Developer))
|
||||||
UI_Spacer(UI_Pixels(50, 1));
|
{
|
||||||
}
|
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer");
|
||||||
}
|
UI_Checkbox(&DEBUG_DebugSettings->RenderUIDebugRects, StrLit("Render UI Debug Rects"));
|
||||||
}
|
UI_Spacer(UI_Pixels(5, 1));
|
||||||
}
|
UI_Checkbox(&DEBUG_DebugSettings->RenderFPSCounter, StrLit("Render FPS Counter"));
|
||||||
|
UI_Spacer(UI_Pixels(5, 1));
|
||||||
UI_Spacer(UI_Pixels(50, 1));
|
UI_Checkbox(&DEBUG_DebugSettings->ListHotAndActive, StrLit("List Hot & Active"));
|
||||||
|
|
||||||
|
UI_Spacer(UI_Pixels(50, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_Spacer(UI_Pixels(50, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void W_BuildView(workspace_view *View)
|
static void W_BuildView(workspace_view *View)
|
||||||
{
|
{
|
||||||
r32 ViewHighlightTransition =
|
r32 ViewHighlightTransition =
|
||||||
AC_AnimateValueF(W_ViewIsCurrent(View), 0, 0.25, "Workspace View Highlight %p", View);
|
AC_AnimateValueF(W_ViewIsCurrent(View), 0, 0.25, "Workspace View Highlight %p", View);
|
||||||
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, ViewHighlightTransition));
|
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, ViewHighlightTransition));
|
||||||
UI_PushBackgroundColor(Theme_BackgroundColor);
|
UI_PushBackgroundColor(Theme_BackgroundColor);
|
||||||
UI_SetNextCornerRadius(3);
|
UI_SetNextCornerRadius(3);
|
||||||
|
|
||||||
ui_box *ViewBox = UI_MakeBoxF(UI_BoxFlag_Clickable |
|
ui_box *ViewBox = UI_MakeBoxF(UI_BoxFlag_Clickable |
|
||||||
UI_BoxFlag_DrawBackground |
|
UI_BoxFlag_DrawBackground |
|
||||||
UI_BoxFlag_DrawBorder |
|
UI_BoxFlag_DrawBorder |
|
||||||
UI_BoxFlag_Clip,
|
UI_BoxFlag_Clip,
|
||||||
"Workspace View %p", View);
|
"Workspace View %p", View);
|
||||||
|
|
||||||
UI_Parent(ViewBox)
|
UI_Parent(ViewBox)
|
||||||
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
||||||
{
|
{
|
||||||
switch(View->Kind)
|
switch(View->Kind)
|
||||||
{
|
{
|
||||||
case W_ViewKind_None: {} break;
|
case W_ViewKind_None: {} break;
|
||||||
|
|
||||||
case W_ViewKind_Startup:
|
case W_ViewKind_Startup:
|
||||||
{
|
{
|
||||||
UI_Row() UI_Padding(UI_Pixels(50, 0))
|
UI_Row() UI_Padding(UI_Pixels(50, 0))
|
||||||
UI_Width(UI_ChildrenSum(1, 1)) UI_Column() UI_Padding(UI_Pixels(50, 0))
|
UI_Width(UI_ChildrenSum(1, 1)) UI_Column() UI_Padding(UI_Pixels(50, 0))
|
||||||
{
|
{
|
||||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||||
{
|
{
|
||||||
UI_Font(Font_Bold) UI_FontSize(36)
|
UI_Font(Font_Bold) UI_FontSize(36)
|
||||||
UI_LabelF("Welcome to VN");
|
UI_LabelF("Welcome to VN");
|
||||||
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
|
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
|
||||||
|
|
||||||
UI_Spacer(UI_Percent(1, 0));
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
|
|
||||||
UI_Checkbox(&DEBUG_DebugSettings->ShowWelcomeMessage, StrLit("Show this message on startup"));
|
UI_Checkbox(&DEBUG_DebugSettings->ShowWelcomeMessage, StrLit("Show this message on startup"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case W_ViewKind_Settings:
|
case W_ViewKind_Settings:
|
||||||
{
|
{
|
||||||
W_BuildSettings(View);
|
W_BuildSettings(View);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case W_ViewKind_TextEditor:
|
case W_ViewKind_ImageViewer:
|
||||||
{
|
{
|
||||||
W_BuildTextEditor(View);
|
W_BuildImageViewer(View);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case W_ViewKind_SceneView:
|
case W_ViewKind_TextEditor:
|
||||||
{
|
{
|
||||||
W_BuildSceneView(View);
|
W_BuildTextEditor(View);
|
||||||
} break;
|
} break;
|
||||||
case W_ViewKind_NavEditor:
|
|
||||||
{
|
case W_ViewKind_SceneView:
|
||||||
W_BuildNavEditor(View);
|
{
|
||||||
} break;
|
W_BuildSceneView(View);
|
||||||
case W_ViewKind_FileLister:
|
} break;
|
||||||
{
|
case W_ViewKind_NavEditor:
|
||||||
workspace_file_lister_action Action = W_BuildFileLister(View);
|
{
|
||||||
if(Action.HasRequestedFile)
|
W_BuildNavEditor(View);
|
||||||
{
|
} break;
|
||||||
workspace_file_lister_action *ActionOnDataArena = W_FileListerActionCopy(W_GetState()->CommandDataArena, &Action);
|
case W_ViewKind_FileLister:
|
||||||
W_IssueCommand(W_Command_OpenFile, PointerToU64(ActionOnDataArena));
|
{
|
||||||
|
workspace_file_lister_action Action = W_BuildFileLister(View);
|
||||||
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
|
if(Action.HasRequestedFile)
|
||||||
}
|
{
|
||||||
} break;
|
workspace_file_lister_action *ActionOnDataArena = W_FileListerActionCopy(W_GetState()->CommandDataArena, &Action);
|
||||||
|
W_IssueCommand(W_Command_OpenFile, PointerToU64(ActionOnDataArena));
|
||||||
case W_ViewKind_Error:
|
|
||||||
{
|
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
|
||||||
workspace_view_error *Error = (workspace_view_error *)View->Data;
|
}
|
||||||
UI_WidthFill UI_HeightFill
|
} break;
|
||||||
UI_Column()
|
|
||||||
{
|
case W_ViewKind_Error:
|
||||||
UI_Label(Error->Message);
|
{
|
||||||
|
workspace_view_error *Error = (workspace_view_error *)View->Data;
|
||||||
UI_Height(UI_Em(2, 1)) UI_Row()
|
UI_WidthFill UI_HeightFill
|
||||||
{
|
UI_Column()
|
||||||
UI_Spacer(UI_Percent(1, 0));
|
{
|
||||||
|
UI_Label(Error->Message);
|
||||||
UI_Width(UI_TextContent(15, 1)) UI_CornerRadius(4.0f)
|
|
||||||
if(UI_Button(StrLit("Close View")).Clicked)
|
UI_Height(UI_Em(2, 1)) UI_Row()
|
||||||
{
|
{
|
||||||
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
|
UI_Spacer(UI_Percent(1, 0));
|
||||||
}
|
|
||||||
UI_Spacer(UI_Em(1, 1));
|
UI_Width(UI_TextContent(15, 1)) UI_CornerRadius(4.0f)
|
||||||
}
|
if(UI_Button(StrLit("Close View")).Clicked)
|
||||||
UI_Spacer(UI_Em(1, 1));
|
{
|
||||||
}
|
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
|
||||||
} break;
|
}
|
||||||
}
|
UI_Spacer(UI_Em(1, 1));
|
||||||
}
|
}
|
||||||
|
UI_Spacer(UI_Em(1, 1));
|
||||||
UI_PopBackgroundColor();
|
}
|
||||||
|
} break;
|
||||||
UI_SignalFromBox(ViewBox);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_PopBackgroundColor();
|
||||||
|
|
||||||
|
UI_SignalFromBox(ViewBox);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,47 +8,56 @@
|
||||||
|
|
||||||
struct workspace_view
|
struct workspace_view
|
||||||
{
|
{
|
||||||
arena *Arena;
|
arena *Arena;
|
||||||
|
|
||||||
workspace_panel *Parent;
|
workspace_panel *Parent;
|
||||||
workspace_view *Next;
|
workspace_view *Next;
|
||||||
workspace_view *Prev;
|
workspace_view *Prev;
|
||||||
|
|
||||||
enum workspace_view_kind Kind;
|
enum workspace_view_kind Kind;
|
||||||
void *Data;
|
void *Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum workspace_view_kind
|
enum workspace_view_kind
|
||||||
{
|
{
|
||||||
W_ViewKind_None,
|
W_ViewKind_None,
|
||||||
W_ViewKind_Startup,
|
W_ViewKind_Startup,
|
||||||
W_ViewKind_Settings,
|
W_ViewKind_Settings,
|
||||||
W_ViewKind_FileLister,
|
W_ViewKind_FileLister,
|
||||||
W_ViewKind_TextEditor,
|
W_ViewKind_TextEditor,
|
||||||
W_ViewKind_SceneView,
|
W_ViewKind_SceneView,
|
||||||
W_ViewKind_NavEditor,
|
W_ViewKind_NavEditor,
|
||||||
W_ViewKind_Error,
|
W_ViewKind_ImageViewer,
|
||||||
|
W_ViewKind_Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct workspace_view_error
|
struct workspace_view_error
|
||||||
{
|
{
|
||||||
string Message;
|
string Message;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum workspace_settings_category
|
enum workspace_settings_category
|
||||||
{
|
{
|
||||||
W_Settings_All,
|
W_Settings_All,
|
||||||
W_Settings_General,
|
W_Settings_General,
|
||||||
W_Settings_Developer,
|
W_Settings_Developer,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct workspace_view_settings
|
struct workspace_view_settings
|
||||||
{
|
{
|
||||||
workspace_settings_category Category;
|
workspace_settings_category Category;
|
||||||
r32 GlobalScroll;
|
r32 GlobalScroll;
|
||||||
|
|
||||||
// sixten: General
|
// sixten: General
|
||||||
b32 GeneralDropdownOpen;
|
b32 GeneralDropdownOpen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct workspace_view_image_viewer
|
||||||
|
{
|
||||||
|
string FileName;
|
||||||
|
render_handle Texture;
|
||||||
|
r32 Scale;
|
||||||
|
v2_r32 Offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -58,11 +67,18 @@ struct workspace_view_settings
|
||||||
inline workspace_view *W_CreateNewView(workspace_view_kind Type, workspace_panel *Parent);
|
inline workspace_view *W_CreateNewView(workspace_view_kind Type, workspace_panel *Parent);
|
||||||
inline void W_DestroyView(workspace_view *View);
|
inline void W_DestroyView(workspace_view *View);
|
||||||
inline b32 W_ViewIsCurrent(workspace_view *View);
|
inline b32 W_ViewIsCurrent(workspace_view *View);
|
||||||
inline string W_GetViewName(arena *Arena, workspace_view *View);
|
inline string W_NameFromView(arena *Arena, workspace_view *View);
|
||||||
|
|
||||||
//- sixten: Builder code
|
//- sixten: Builder code
|
||||||
static void W_ViewListerInputCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
|
static void W_ViewListerInputCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
|
||||||
static void W_BuildViewTypeLister(workspace_view *View);
|
static void W_BuildViewTypeLister(workspace_view *View);
|
||||||
static void W_BuildView(workspace_view *View);
|
static void W_BuildView(workspace_view *View);
|
||||||
|
|
||||||
|
//- sixten: View Implementations
|
||||||
|
static b32 W_ImageViewerSetup(workspace_view *View, string Name, string Contents);
|
||||||
|
static void W_BuildImageViewer(workspace_view *View);
|
||||||
|
static void W_BuildSceneView(workspace_view *View);
|
||||||
|
static void W_BuildSettings(workspace_view *View);
|
||||||
|
|
||||||
|
|
||||||
#endif //VN_WORKSPACE_VIEW_H
|
#endif //VN_WORKSPACE_VIEW_H
|
||||||
|
|
1392
code/win32_main.cpp
|
@ -1,6 +1,6 @@
|
||||||
Platform
|
Platform
|
||||||
{
|
{
|
||||||
RefreshRate = 144;
|
RefreshRate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dev
|
Dev
|
||||||
|
|
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 833 KiB |
Before Width: | Height: | Size: 758 KiB |
Before Width: | Height: | Size: 969 KiB |
Before Width: | Height: | Size: 969 KiB |
Before Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.2 MiB |
|
@ -1,22 +0,0 @@
|
||||||
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!
|
|
Before Width: | Height: | Size: 994 KiB |
Before Width: | Height: | Size: 871 KiB |
Before Width: | Height: | Size: 999 KiB |
Before Width: | Height: | Size: 951 KiB |
Before Width: | Height: | Size: 626 KiB |
Before Width: | Height: | Size: 793 KiB |
Before Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 4.1 KiB |
|
@ -1,12 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"One line test";
|
|
||||||
@arthur(normal) "Welcome to this fine estate!";
|
|
||||||
@arthur(happy) "I am pleased to see you.";
|
|
||||||
|
|
||||||
"An inbetweener if you were";
|
|
||||||
|
|
||||||
@arthur(none);
|
|
||||||
|
|
||||||
jump main; // return to start
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"There's a ghost, in my home - but it's better than being alone. Reading read receipts with no replying.";
|
|
||||||
"Yes my house is haunted. That's just what I wanted. Read receipts with no replying.";
|
|
||||||
"Scene test 123" #noclear;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"I see an annoying girl running toward me from the distance, waving her arms in the air like she's totally oblivious to any attention she might draw to herself.";
|
|
||||||
"That girl is Sayori, my neighbor and good friend since we were children.";
|
|
||||||
"You know, the kind of friend you'd never see yourself making today, but it just kind of works out because you've known each other for so long?";
|
|
||||||
"We used to walk to school together on days like this, but starting around high school she would oversleep more and more frequently, and I would get tired of waiting up.";
|
|
||||||
"But if she's going to chase after me like this, I almost feel better off running away.";
|
|
||||||
"However, I just sigh and idle in front of the crosswalk and let Sayori catch up to me.";
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
var monika = "Monika";
|
|
||||||
var arthur = "Arthur";
|
|
||||||
|
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"hello, line, paint, color, design, address, brightness";
|
|
||||||
|
|
||||||
@monika(leaning) "Hi";
|
|
||||||
|
|
||||||
@arthur(normal) "Wasssap!";
|
|
||||||
|
|
||||||
@monika(leaning) "This is completely normal";
|
|
||||||
|
|
||||||
@monika(none);
|
|
||||||
|
|
||||||
@arthur(normal) "Wow, what a rude person";
|
|
||||||
@arthur(happy) "But hey! They left atleast!";
|
|
||||||
|
|
||||||
@arthur(none);
|
|
||||||
|
|
||||||
"Something inbetween!";
|
|
||||||
|
|
||||||
@monika(leaning) @arthur(happy) "BOOOO!";
|
|
||||||
|
|
||||||
"Gotcha'!";
|
|
||||||
|
|
||||||
@arthur(none) @monika(none);
|
|
||||||
|
|
||||||
jump main;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"This is the editor";
|
|
||||||
"You can write text in here";
|
|
||||||
|
|
||||||
"If you want to add a branch, you use the branch keyword";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jump main; // to not hit the "end of proc" error
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
for(var idx = 0; idx < 10; idx = idx + 1)
|
|
||||||
{
|
|
||||||
print("hello, line, paint, color, design, address, brightness");
|
|
||||||
}
|
|
||||||
}
|
|
51
data/gpt.vns
|
@ -1,51 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"morning, sunlight, birdsong, aroma, coffee, kitchen";
|
|
||||||
|
|
||||||
"You wake up to the sound of birds singing outside your window. The sunlight filters through the curtains, casting a warm glow on your room.";
|
|
||||||
|
|
||||||
branch
|
|
||||||
{
|
|
||||||
"Get up and make coffee"
|
|
||||||
{
|
|
||||||
"You head to the kitchen and start brewing a fresh pot of coffee. The aroma fills the air, and you can't help but smile as you anticipate that first sip.";
|
|
||||||
|
|
||||||
branch
|
|
||||||
{
|
|
||||||
"Enjoy the coffee in peace"
|
|
||||||
{
|
|
||||||
"You take your coffee to the cozy corner by the window. As you sip it, you watch the world go by outside, feeling a sense of calm wash over you.";
|
|
||||||
}
|
|
||||||
|
|
||||||
"Invite your roommate to join"
|
|
||||||
{
|
|
||||||
"You hear your roommate stirring in their room. You decide to invite them over to share the morning coffee.";
|
|
||||||
|
|
||||||
branch
|
|
||||||
{
|
|
||||||
"Roommate joins you"
|
|
||||||
{
|
|
||||||
"Your roommate joins you at the table. You both chat about your plans for the day and share a few laughs as you enjoy your coffee together.";
|
|
||||||
}
|
|
||||||
|
|
||||||
"Roommate declines"
|
|
||||||
{
|
|
||||||
"Your roommate declines your invitation, mentioning they have some work to catch up on. You enjoy your coffee solo, lost in your thoughts.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Stay in bed a little longer"
|
|
||||||
{
|
|
||||||
"You decide to indulge yourself and stay in bed a little longer. The warmth of the blankets cocoon you, and you drift in and out of pleasant dreams.";
|
|
||||||
|
|
||||||
"Eventually, you decide it's time to start the day.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Time seems to pass peacefully as you enjoy the simple pleasures of the morning.";
|
|
||||||
|
|
||||||
jump main;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"人類社会のすべての構成員の固有の尊厳と平等で譲ることのできない権利とを承認することは";
|
|
||||||
"Yup, I added fucking support for japanese.";
|
|
||||||
"WHY DID I DO THIS!?!?!?!" #noawait;
|
|
||||||
branch
|
|
||||||
{
|
|
||||||
"Because you're stupid"
|
|
||||||
{
|
|
||||||
"HEY! You don't get to call me stupid!";
|
|
||||||
}
|
|
||||||
|
|
||||||
"Because you're dumb"
|
|
||||||
{
|
|
||||||
"Yeah, fair enough...";
|
|
||||||
}
|
|
||||||
|
|
||||||
"Because you're SOOO smart"
|
|
||||||
{
|
|
||||||
"HEY! NO SARCASM ALLOWED ON THIS CHRISTIAN MINECRAFT SERVER OKAY?";
|
|
||||||
"I WANT TO SEE ABSOLUTELY ZERO, OKAY!?!?!?!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Anyways, we're going to another function now, okay?";
|
|
||||||
jump test;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc test
|
|
||||||
{
|
|
||||||
"hi it's me sans undertale, from undertale";
|
|
||||||
"let me show you some lit memmes";
|
|
||||||
"DUHDUH DUH DUH - DUH DUH DUH DUHDUHDUH";
|
|
||||||
jump main;
|
|
||||||
}
|
|
BIN
data/scene.vnn
|
@ -1,3 +1,6 @@
|
||||||
|
nav "data/scene.vnn";
|
||||||
|
background DemoBackground;
|
||||||
|
|
||||||
var arthur = "Arthur";
|
var arthur = "Arthur";
|
||||||
var monika = "Monika";
|
var monika = "Monika";
|
||||||
|
|
||||||
|
@ -6,7 +9,7 @@ proc main
|
||||||
@arthur(normal) "Welcome to the Scene Test!";
|
@arthur(normal) "Welcome to the Scene Test!";
|
||||||
@arthur(happy) "Feel free to move around.";
|
@arthur(happy) "Feel free to move around.";
|
||||||
|
|
||||||
branch
|
branch
|
||||||
{
|
{
|
||||||
"No! Sooth me with your voice one more time."
|
"No! Sooth me with your voice one more time."
|
||||||
{
|
{
|
||||||
|
@ -20,6 +23,13 @@ proc main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc item
|
||||||
|
{
|
||||||
|
"I inspect the strange element";
|
||||||
|
"It's shimmering outlines intrigue me, however I do not dare lay a finger on it";
|
||||||
|
"Well, no time to waste!";
|
||||||
|
}
|
||||||
|
|
||||||
proc arthur_talk
|
proc arthur_talk
|
||||||
{
|
{
|
||||||
@arthur(normal) "Hi! Thanks for talking to me.";
|
@arthur(normal) "Hi! Thanks for talking to me.";
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// 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";
|
|
||||||
}
|
|
37
data/vns.txt
|
@ -1,37 +0,0 @@
|
||||||
program -> declaration* EOF;
|
|
||||||
|
|
||||||
declaration -> proc_decl |
|
|
||||||
var_decl |
|
|
||||||
statement;
|
|
||||||
|
|
||||||
proc_decl -> "proc" IDENTIFIER block;
|
|
||||||
var_decl -> "var" IDENTIFIER ("=" expression)? ";";
|
|
||||||
|
|
||||||
statement -> expression_statement |
|
|
||||||
for_statement |
|
|
||||||
if_statement |
|
|
||||||
block;
|
|
||||||
|
|
||||||
expression_statement -> expression ";";
|
|
||||||
for_statement -> "for" "(" (var_decl|expression_statement|";")
|
|
||||||
expression? ";" expression? ")" statement;
|
|
||||||
if_statement -> "if" "(" expression ")" statement
|
|
||||||
("else" statement)?;
|
|
||||||
block -> "{" declaration* "}";
|
|
||||||
|
|
||||||
expression -> assignment;
|
|
||||||
|
|
||||||
assignment -> (call ".")? IDENTIFIER "=" assignment |
|
|
||||||
logic_or;
|
|
||||||
|
|
||||||
logic_or -> logic_and ("or" logic_and)*;
|
|
||||||
logic_and -> equality ("and" equality)*;
|
|
||||||
equality -> comparison (("!=" | "==") comparison)*;
|
|
||||||
comparison -> term ((">" | ">=" < "<" | "<=") term)*;
|
|
||||||
term -> factor (("-" | "+") factor)*;
|
|
||||||
factor -> unary (("/" | "*") unary)*;
|
|
||||||
|
|
||||||
unary -> ("!" | "-") unary | call;
|
|
||||||
call -> primary "(" arguments? ")";
|
|
||||||
primary -> "true" | "false" | NUMBER | STRING |
|
|
||||||
IDENTIFIER | "(" expression ")";
|
|
|
@ -1,5 +0,0 @@
|
||||||
vn - release 1
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Right, so we need to have some tools to make a visual novel. In lieu of actual GOOD tools, we will deal with subpar ones instead. Thusly, this first release will only include the bearest tools to get you started, but it should be enough for some basic (text only) scenes.
|
|
||||||
|
|
31
test
|
@ -1,31 +0,0 @@
|
||||||
proc main
|
|
||||||
{
|
|
||||||
"Hello!";
|
|
||||||
|
|
||||||
"This is a little text editor with syntax highlighting";
|
|
||||||
|
|
||||||
"Is it cool?" #noawait;
|
|
||||||
|
|
||||||
branch
|
|
||||||
{
|
|
||||||
"Yes"
|
|
||||||
{
|
|
||||||
"I know right?";
|
|
||||||
}
|
|
||||||
|
|
||||||
"No"
|
|
||||||
{
|
|
||||||
"Wow, no need to be a hater dude.";
|
|
||||||
"Seriously";
|
|
||||||
"...";
|
|
||||||
"Grow up";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Oh, forgot to mention that it also supports unicode.";
|
|
||||||
"Which makes it able to use all langages that use left to right writing.";
|
|
||||||
"Assuming that the character system isn't too complex.";
|
|
||||||
"Мой домашний питомец";
|
|
||||||
"悠輝さんに渡すつもりです";
|
|
||||||
jump main;
|
|
||||||
}
|
|
12
todo.txt
|
@ -1,12 +0,0 @@
|
||||||
This is a list of things that needs doing in a SUGGESTED order.
|
|
||||||
|
|
||||||
* UI
|
|
||||||
- Incorrect behaviour when closing panels in a certain order, most likely some things are not being copied over properly.
|
|
||||||
|
|
||||||
* Rendering
|
|
||||||
- Fix texture clipping
|
|
||||||
- Control over each corner when rounding
|
|
||||||
|
|
||||||
Completed
|
|
||||||
* UI
|
|
||||||
- Settings / Preferences view. (Including saving and loading of these settings/preferences)
|
|
18
weeks.txt
|
@ -1,18 +0,0 @@
|
||||||
[0] - Characters
|
|
||||||
- Get characters names displaying while they talk V
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
[1] - Environments & Time
|
|
||||||
|
|
||||||
[2] - Map & Notebook
|
|
||||||
|
|
||||||
[3] - UI
|
|
||||||
- Keyboard Navigation
|
|
||||||
- Blinking Caret
|
|
||||||
|
|
||||||
[4] - Minigames
|
|
||||||
|
|
||||||
[5] - Rendering
|
|
||||||
- Check up on texture mappings, something seems to be weird
|
|
||||||
|
|
||||||
[6] - Data Submission
|
|