Added scene view and runtime.

main
sixtenhugosson 2023-08-22 05:19:51 +02:00
parent a3e2314fd0
commit e96b3a7850
53 changed files with 2572 additions and 654 deletions

View File

@ -1,11 +1,11 @@
@echo off
set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /Oi /W4 /WX /wd4996 /wd4201 /wd4305 /wd4244 /wd4100 /wd4505 /std:c++17
set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /DVN_USE_INSTANCING=1 /Oi /W4 /WX /wd4996 /wd4201 /wd4305 /wd4244 /wd4100 /wd4505 /std:c++17
if not exist "../build" mkdir "../build"
pushd "../build/"
rem cl /Zi /nologo /FC ../code/third_party/codegen/codegen.c
cl /Zi /nologo /FC ../code/third_party/codegen/codegen.c
codegen ../code/
cl %CommonCompilerOptions% ../code/vn.cpp /LD /link /export:VN_UpdateAndRender /incremental:no

View File

@ -35,12 +35,24 @@ inline string MakeString(u8 *Data, s64 Count)
return(Result);
}
inline string MakeString(u8 *Start, u8 *End)
{
string Result = {(s64)(End-Start), Start};
return(Result);
}
inline string MakeString(char *CString)
{
string Result = {StringLength(CString), (u8 *)CString};
return(Result);
}
inline string16 MakeString16(u16 *Data, s64 Count)
{
string16 Result = {Count, Data};
return(Result);
}
//- sixten: Equality
static b32 AreEqual(string A, string B)
@ -351,6 +363,17 @@ static s64 StringLength(char *String)
return(Result);
}
static s64 StringLength16(u16 *String)
{
s64 Result = 0;
while(*String++)
{
++Result;
}
return(Result);
}
//~ sixten: String list
@ -553,7 +576,7 @@ static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint)
u32 Size = 0;
u8 DummyDest[4];
Dest = Dest?Dest:DummyDest;
if(Codepoint < (1<<8))
if(Codepoint < (1<<7))
{
Dest[0] = Codepoint;
Size = 1;

View File

@ -64,8 +64,11 @@ inline b32 IsLetter(char C);
//- sixten: Basic constructors
inline string MakeString(u8 *Data, s64 Count);
inline string MakeString(u8 *Start, u8 *End);
inline string MakeString(char *CString);
#define StrLit(String) MakeString((u8 *)String, ArrayCount(String) - 1)
#define StrLit(String) MakeString((u8 *)String, (s64)(ArrayCount(String) - 1))
inline string16 MakeString16(u16 *Data, s64 Count);
//- sixten: Equality
@ -109,6 +112,7 @@ static string RemoveAll(memory_arena *Arena, string Text, char ToRemove);
//- sixten: "C Style" strings
static s64 StringLength(char *String);
static s64 StringLength16(u16 *String);
#if 0

View File

@ -13,6 +13,8 @@
#define PLATFORM_BEGIN_FILE_ITER(name) platform_file_iter * name(memory_arena *Arena, string Path)
#define PLATFORM_ADVANCE_FILE_ITER(name) b32 name(memory_arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo)
#define PLATFORM_END_FILE_ITER(name) void name(platform_file_iter *Iter)
#define PLATFORM_SET_CLIPBOARD(name) void name(string String)
#define PLATFORM_GET_CLIPBOARD(name) string name(memory_arena *Arena)
typedef PLATFORM_RESERVE(platform_reserve);
typedef PLATFORM_RELEASE(platform_release);
@ -29,6 +31,8 @@ typedef PLATFORM_SHOW_MESSAGE(platform_show_message);
typedef PLATFORM_BEGIN_FILE_ITER(platform_begin_file_iter);
typedef PLATFORM_ADVANCE_FILE_ITER(platform_advance_file_iter);
typedef PLATFORM_END_FILE_ITER(platform_end_file_iter);
typedef PLATFORM_SET_CLIPBOARD(platform_set_clipboard);
typedef PLATFORM_GET_CLIPBOARD(platform_get_clipboard);
struct platform_api
{
@ -47,6 +51,8 @@ platform_show_message *ShowMessage;
platform_begin_file_iter *BeginFileIter;
platform_advance_file_iter *AdvanceFileIter;
platform_end_file_iter *EndFileIter;
platform_set_clipboard *SetClipboard;
platform_get_clipboard *GetClipboard;
};
#define RegisterPlatformFunctions(PlatformName)\
@ -65,4 +71,6 @@ Platform.ShowMessage = PlatformName##_ShowMessage;\
Platform.BeginFileIter = PlatformName##_BeginFileIter;\
Platform.AdvanceFileIter = PlatformName##_AdvanceFileIter;\
Platform.EndFileIter = PlatformName##_EndFileIter;\
Platform.SetClipboard = PlatformName##_SetClipboard;\
Platform.GetClipboard = PlatformName##_GetClipboard;\

View File

@ -13,6 +13,7 @@ inline void UI_PushFont(font_id Element) { ui *UI = UI_GetState(); Ass
inline void UI_PushFontSize(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontSizeStackUsed + 1 < ArrayCount(UI->Stacks.FontSizeStack)); UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed++] = Element; }
inline void UI_PushOffsetX(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetXStackUsed + 1 < ArrayCount(UI->Stacks.OffsetXStack)); UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed++] = Element; }
inline void UI_PushOffsetY(r32 Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetYStackUsed + 1 < ArrayCount(UI->Stacks.OffsetYStack)); UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed++] = Element; }
inline void UI_PushHoverCursor(platform_cursor Element) { ui *UI = UI_GetState(); Assert(UI->Stacks.HoverCursorStackUsed + 1 < ArrayCount(UI->Stacks.HoverCursorStack)); UI->Stacks.HoverCursorStack[UI->Stacks.HoverCursorStackUsed++] = Element; }
inline void UI_PopParent(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.ParentStackUsed > 0); --UI->Stacks.ParentStackUsed; }
inline void UI_PopWidth(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.WidthStackUsed > 0); --UI->Stacks.WidthStackUsed; }
inline void UI_PopHeight(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.HeightStackUsed > 0); --UI->Stacks.HeightStackUsed; }
@ -28,6 +29,7 @@ inline void UI_PopFont(void) { ui *UI = UI_GetState(); Ass
inline void UI_PopFontSize(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.FontSizeStackUsed > 0); --UI->Stacks.FontSizeStackUsed; }
inline void UI_PopOffsetX(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetXStackUsed > 0); --UI->Stacks.OffsetXStackUsed; }
inline void UI_PopOffsetY(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.OffsetYStackUsed > 0); --UI->Stacks.OffsetYStackUsed; }
inline void UI_PopHoverCursor(void) { ui *UI = UI_GetState(); Assert(UI->Stacks.HoverCursorStackUsed > 0); --UI->Stacks.HoverCursorStackUsed; }
inline void UI_SetNextParent(ui_box * Element) { ui *UI = UI_GetState(); UI_PushParent(Element); UI->Stacks.AutoPopParent = true; }
inline void UI_SetNextWidth(ui_size Element) { ui *UI = UI_GetState(); UI_PushWidth(Element); UI->Stacks.AutoPopWidth = true; }
inline void UI_SetNextHeight(ui_size Element) { ui *UI = UI_GetState(); UI_PushHeight(Element); UI->Stacks.AutoPopHeight = true; }
@ -43,6 +45,7 @@ inline void UI_SetNextFont(font_id Element) { ui *UI = UI_GetState(); UI_PushFon
inline void UI_SetNextFontSize(r32 Element) { ui *UI = UI_GetState(); UI_PushFontSize(Element); UI->Stacks.AutoPopFontSize = true; }
inline void UI_SetNextOffsetX(r32 Element) { ui *UI = UI_GetState(); UI_PushOffsetX(Element); UI->Stacks.AutoPopOffsetX = true; }
inline void UI_SetNextOffsetY(r32 Element) { ui *UI = UI_GetState(); UI_PushOffsetY(Element); UI->Stacks.AutoPopOffsetY = true; }
inline void UI_SetNextHoverCursor(platform_cursor Element) { ui *UI = UI_GetState(); UI_PushHoverCursor(Element); UI->Stacks.AutoPopHoverCursor = true; }
inline ui_box * UI_FirstParent(void) { ui *UI = UI_GetState(); return(UI->Stacks.ParentStack[0]); }
inline ui_size UI_FirstWidth(void) { ui *UI = UI_GetState(); return(UI->Stacks.WidthStack[0]); }
inline ui_size UI_FirstHeight(void) { ui *UI = UI_GetState(); return(UI->Stacks.HeightStack[0]); }
@ -58,6 +61,7 @@ inline font_id UI_FirstFont(void) { ui *UI = UI_GetState(); return(UI->Stacks.Fo
inline r32 UI_FirstFontSize(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontSizeStack[0]); }
inline r32 UI_FirstOffsetX(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetXStack[0]); }
inline r32 UI_FirstOffsetY(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetYStack[0]); }
inline platform_cursor UI_FirstHoverCursor(void) { ui *UI = UI_GetState(); return(UI->Stacks.HoverCursorStack[0]); }
inline ui_box * UI_TopParent(void) { ui *UI = UI_GetState(); return(UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1]); }
inline ui_size UI_TopWidth(void) { ui *UI = UI_GetState(); return(UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1]); }
inline ui_size UI_TopHeight(void) { ui *UI = UI_GetState(); return(UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1]); }
@ -73,6 +77,7 @@ inline font_id UI_TopFont(void) { ui *UI = UI_GetState(); return(UI->Stacks.Font
inline r32 UI_TopFontSize(void) { ui *UI = UI_GetState(); return(UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]); }
inline r32 UI_TopOffsetX(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1]); }
inline r32 UI_TopOffsetY(void) { ui *UI = UI_GetState(); return(UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1]); }
inline platform_cursor UI_TopHoverCursor(void) { ui *UI = UI_GetState(); return(UI->Stacks.HoverCursorStack[UI->Stacks.HoverCursorStackUsed - 1]); }
#define UI_Parent(Element) DeferLoop(UI_PushParent(Element), UI_PopParent())
#define UI_Width(Element) DeferLoop(UI_PushWidth(Element), UI_PopWidth())
#define UI_Height(Element) DeferLoop(UI_PushHeight(Element), UI_PopHeight())
@ -88,6 +93,7 @@ inline r32 UI_TopOffsetY(void) { ui *UI = UI_GetState(); return(UI->Stacks.Offse
#define UI_FontSize(Element) DeferLoop(UI_PushFontSize(Element), UI_PopFontSize())
#define UI_OffsetX(Element) DeferLoop(UI_PushOffsetX(Element), UI_PopOffsetX())
#define UI_OffsetY(Element) DeferLoop(UI_PushOffsetY(Element), UI_PopOffsetY())
#define UI_HoverCursor(Element) DeferLoop(UI_PushHoverCursor(Element), UI_PopHoverCursor())
static void UI_ApplyStyles(ui_box *Box)
{
@ -107,5 +113,6 @@ Assert(UI->Stacks.FontStackUsed > 0); Box->Font = UI
Assert(UI->Stacks.FontSizeStackUsed > 0); Box->FontSize = UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]; if(UI->Stacks.AutoPopFontSize) { UI_PopFontSize(); UI->Stacks.AutoPopFontSize = false; }
Assert(UI->Stacks.OffsetXStackUsed > 0); Box->Offset.x = UI->Stacks.OffsetXStack[UI->Stacks.OffsetXStackUsed - 1]; if(UI->Stacks.AutoPopOffsetX) { UI_PopOffsetX(); UI->Stacks.AutoPopOffsetX = false; }
Assert(UI->Stacks.OffsetYStackUsed > 0); Box->Offset.y = UI->Stacks.OffsetYStack[UI->Stacks.OffsetYStackUsed - 1]; if(UI->Stacks.AutoPopOffsetY) { UI_PopOffsetY(); UI->Stacks.AutoPopOffsetY = false; }
Assert(UI->Stacks.HoverCursorStackUsed > 0); Box->HoverCursor = UI->Stacks.HoverCursorStack[UI->Stacks.HoverCursorStackUsed - 1]; if(UI->Stacks.AutoPopHoverCursor) { UI_PopHoverCursor(); UI->Stacks.AutoPopHoverCursor = false; }
}

View File

@ -15,5 +15,6 @@ font_id FontStack[64]; s32 FontStackUsed; b32 AutoPopFont;
r32 FontSizeStack[64]; s32 FontSizeStackUsed; b32 AutoPopFontSize;
r32 OffsetXStack[64]; s32 OffsetXStackUsed; b32 AutoPopOffsetX;
r32 OffsetYStack[64]; s32 OffsetYStackUsed; b32 AutoPopOffsetY;
platform_cursor HoverCursorStack[64]; s32 HoverCursorStackUsed; b32 AutoPopHoverCursor;
};

View File

@ -353,11 +353,157 @@ Out_Color = Color*TextureFactor*BorderFactor*SDFFactor;
return(Program);
}
static instanced_quad_program OpenGL_CompileInstacedQuadProgram(void)
{
char *VertexSource =
R"GLSL(
in v4 In_Dest;
in v4 In_Source;
in s32 In_TextureIndex;
in u32 In_Color[4];
in r32 In_CornerRadius;
in r32 In_EdgeSoftness;
in r32 In_BorderThickness;
)GLSL"
"uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];"
R"GLSL(
uniform v2 Uniform_Resolution;
out v2 DestP;
out v2 DestHalfSize;
out v2 DestCenter;
out v2 SourceP;
out v4 Color;
out r32 CornerRadius;
out r32 EdgeSoftness;
out r32 BorderThickness;
flat out s32 TextureIndex;
void main()
{
v2[] Vertices = V2[](V2(0, 0), V2(0, 1), V2(1, 0), V2(1, 1));
DestP = In_Dest.xy + (In_Dest.zw-In_Dest.xy)*Vertices[gl_VertexID];
DestHalfSize = (In_Dest.zw-In_Dest.xy)/2;
DestCenter = (In_Dest.xy+In_Dest.zw)/2;
v2 SourceDim = In_Source.zw-In_Source.xy;
SourceP = In_Source.xy + SourceDim*Vertices[gl_VertexID];
v2 ScreenP = V2(DestP.x / Uniform_Resolution.x, DestP.y / Uniform_Resolution.y);
ScreenP = ScreenP*2 - 1;
ScreenP.y = -ScreenP.y;
gl_Position = V4(ScreenP, 0, 1);
u32 ColorData = In_Color[gl_VertexID];
Color.r = r32((ColorData >> 24) & 255u)/255.0;
Color.g = r32((ColorData >> 16) & 255u)/255.0;
Color.b = r32((ColorData >> 8) & 255u)/255.0;
Color.a = r32((ColorData >> 0) & 255u)/255.0;
CornerRadius = In_CornerRadius;
EdgeSoftness = In_EdgeSoftness;
BorderThickness = In_BorderThickness;
TextureIndex = In_TextureIndex;
}
)GLSL";
char *FragmentSource =
R"GLSL(
in v2 DestP;
in v2 DestHalfSize;
in v2 DestCenter;
in v2 SourceP;
in v4 Color;
in r32 CornerRadius;
in r32 EdgeSoftness;
in r32 BorderThickness;
flat in s32 TextureIndex;
)GLSL"
"uniform sampler2D TextureSamplers[" Stringify(MAX_BOUND_TEXTURES) "];"
R"GLSL(
out v4 Out_Color;
r32 RoundedRect(v2 P, v2 Center, v2 HalfSize, r32 r)
{
v2 d2 = AbsoluteValue(Center - P) - HalfSize + r;
r32 Result = Min(Max(d2.x, d2.y), 0) + Length(Max(d2, 0)) - r;
return(Result);
}
void main()
{
r32 SoftnessPadding = Max(0, EdgeSoftness*2-1);
r32 Dist = RoundedRect(DestP, DestCenter, DestHalfSize - SoftnessPadding, CornerRadius);
r32 SDFFactor = 1 - smoothstep(0, 2*EdgeSoftness, Dist);
r32 BorderFactor = 1;
if(BorderThickness != 0)
{
v2 InteriorHalfSize = DestHalfSize - BorderThickness;
r32 InteriorRadiusReduce = Min(InteriorHalfSize.x / DestHalfSize.x, InteriorHalfSize.y / DestHalfSize.y);
r32 InteriorCornerRadius = CornerRadius*InteriorRadiusReduce*InteriorRadiusReduce;
r32 InsideDist = RoundedRect(DestP, DestCenter, InteriorHalfSize - SoftnessPadding, InteriorCornerRadius);
BorderFactor = smoothstep(0, 2*EdgeSoftness, InsideDist);
}
v4 TextureFactor = texture(TextureSamplers[TextureIndex], SourceP);
Out_Color = Color*SDFFactor*BorderFactor*TextureFactor;
}
)GLSL";
instanced_quad_program Program = {};
Program.ID = OpenGL_CompileShaderProgram(VertexSource, FragmentSource);
Program.DestID = glGetAttribLocation(Program.ID, "In_Dest");
Program.SourceID = glGetAttribLocation(Program.ID, "In_Source");
Program.TextureIndexID = glGetAttribLocation(Program.ID, "In_TextureIndex");
Program.ColorID[0] = glGetAttribLocation(Program.ID, "In_Color[0]");
Program.ColorID[1] = glGetAttribLocation(Program.ID, "In_Color[1]");
Program.ColorID[2] = glGetAttribLocation(Program.ID, "In_Color[2]");
Program.ColorID[3] = glGetAttribLocation(Program.ID, "In_Color[3]");
Program.CornerRadiusID = glGetAttribLocation(Program.ID, "In_CornerRadius");
Program.EdgeSoftnessID = glGetAttribLocation(Program.ID, "In_EdgeSoftness");
Program.BorderThicknessID = glGetAttribLocation(Program.ID, "In_BorderThickness");
glUseProgram(Program.ID);
Program.UniformResolutionLocation = glGetUniformLocation(Program.ID, "Uniform_Resolution");
temporary_memory Scratch = GetScratch(0, 0);
for(s32 TextureIndex = 0;
TextureIndex < MAX_BOUND_TEXTURES;
++TextureIndex)
{
string Name = PushFormat(Scratch.Arena, "TextureSamplers[%i]", TextureIndex);
s32 Location = glGetUniformLocation(Program.ID, (char *)Name.Data);
glUniform1i(Location, TextureIndex);
}
ReleaseScratch(Scratch);
glUseProgram(0);
return(Program);
}
#define OpenGL_EnableFloatVertexAttribute(Index, Size, Type, type, Member)\
if(Index != -1)\
{\
glEnableVertexAttribArray(Index);\
glVertexAttribPointer(Index, Size, Type, GL_FALSE, sizeof(type), (void *)OffsetOf(type, Member));\
if(VN_USE_INSTANCING)\
{\
glVertexAttribDivisor(Index, 1);\
}\
}
#define OpenGL_EnableIntegerVertexAttribute(Index, Size, Type, type, Member)\
@ -365,6 +511,10 @@ if(Index != -1)\
{\
glEnableVertexAttribArray(Index);\
glVertexAttribIPointer(Index, Size, Type, sizeof(type), (void *)OffsetOf(type, Member));\
if(VN_USE_INSTANCING)\
{\
glVertexAttribDivisor(Index, 1);\
}\
}
#define OpenGL_DisableVertexAttribute(Index)\
@ -403,6 +553,38 @@ static void OpenGL_EndProgram(quad_program *Program)
glUseProgram(0);
}
static void OpenGL_BeginProgram(instanced_quad_program *Program)
{
glUseProgram(Program->ID);
OpenGL_EnableFloatVertexAttribute(Program->DestID, 4, GL_FLOAT, instanced_quad, Dest);
OpenGL_EnableFloatVertexAttribute(Program->SourceID, 4, GL_FLOAT, instanced_quad, Source);
OpenGL_EnableIntegerVertexAttribute(Program->TextureIndexID, 1, GL_UNSIGNED_INT, instanced_quad, TextureIndex);
OpenGL_EnableIntegerVertexAttribute(Program->ColorID[0], 1, GL_UNSIGNED_INT, instanced_quad, Color[0]);
OpenGL_EnableIntegerVertexAttribute(Program->ColorID[1], 1, GL_UNSIGNED_INT, instanced_quad, Color[1]);
OpenGL_EnableIntegerVertexAttribute(Program->ColorID[2], 1, GL_UNSIGNED_INT, instanced_quad, Color[2]);
OpenGL_EnableIntegerVertexAttribute(Program->ColorID[3], 1, GL_UNSIGNED_INT, instanced_quad, Color[3]);
OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID, 1, GL_FLOAT, instanced_quad, CornerRadius);
OpenGL_EnableFloatVertexAttribute(Program->EdgeSoftnessID, 1, GL_FLOAT, instanced_quad, EdgeSoftness);
OpenGL_EnableFloatVertexAttribute(Program->BorderThicknessID, 1, GL_FLOAT, instanced_quad, BorderThickness);
}
static void OpenGL_EndProgram(instanced_quad_program *Program)
{
OpenGL_DisableVertexAttribute(Program->DestID);
OpenGL_DisableVertexAttribute(Program->SourceID);
OpenGL_DisableVertexAttribute(Program->TextureIndexID);
OpenGL_DisableVertexAttribute(Program->ColorID[0]);
OpenGL_DisableVertexAttribute(Program->ColorID[1]);
OpenGL_DisableVertexAttribute(Program->ColorID[2]);
OpenGL_DisableVertexAttribute(Program->ColorID[3]);
OpenGL_DisableVertexAttribute(Program->CornerRadiusID);
OpenGL_DisableVertexAttribute(Program->EdgeSoftnessID);
OpenGL_DisableVertexAttribute(Program->BorderThicknessID);
glUseProgram(0);
}
static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, umm MaxPushBufferSize)
{
opengl_context Context = {};
@ -410,22 +592,35 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
RenderCommands->MaxPushBufferSize = MaxPushBufferSize;
RenderCommands->PushBufferBase = (u8 *)OpenGL_AllocateMemory(RenderCommands->MaxPushBufferSize);
#if VN_USE_INSTANCING
RenderCommands->MaxInstancedQuadCount = MAX_QUAD_COUNT;
RenderCommands->InstancedQuadBase = (instanced_quad *)OpenGL_AllocateMemory(RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad));
#else
RenderCommands->MaxQuadVertexCount = MAX_QUAD_COUNT*4;
RenderCommands->QuadVertexBase = (quad_vertex *)OpenGL_AllocateMemory(RenderCommands->MaxQuadVertexCount*sizeof(quad_vertex));
RenderCommands->MaxQuadIndexCount = MAX_QUAD_COUNT*6;
RenderCommands->QuadIndexBase = (s32 *)OpenGL_AllocateMemory(RenderCommands->MaxQuadIndexCount*sizeof(s32));
#if 0
RenderCommands->MaxInstancedQuadCount = MAX_QUAD_COUNT;
RenderCommands->InstancedQuadBase = (instanced_quad *)OpenGL_AllocateMemory(RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad));
#endif
#if VN_USE_INSTANCING
Context.InstancedQuadProgram = OpenGL_CompileInstacedQuadProgram();
#else
Context.QuadProgram = OpenGL_CompileQuadProgram();
#endif
#if VN_USE_INSTANCING
glGenBuffers(1, &Context.InstancedQuadBuffer);
#else
glGenBuffers(1, &Context.VertexBuffer);
glGenBuffers(1, &Context.IndexBuffer);
#endif
#if VN_USE_INSTANCING
glBindBuffer(GL_ARRAY_BUFFER, Context.InstancedQuadBuffer);
glBufferData(GL_ARRAY_BUFFER, RenderCommands->MaxInstancedQuadCount*sizeof(instanced_quad), 0, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
#else
glBindBuffer(GL_ARRAY_BUFFER, Context.VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, RenderCommands->MaxQuadVertexCount*sizeof(quad_vertex), 0, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -433,6 +628,7 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Context.IndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, RenderCommands->MaxQuadIndexCount*sizeof(s32), 0, GL_STREAM_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif
u32 WhiteData = 0xFFFFFFFF;
RenderCommands->WhiteTexture = OpenGL_AllocateTexture(V2S32(1, 1), Render_TextureFormat_RGBA8, &WhiteData);
@ -440,7 +636,7 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
RenderCommands->AllocateTexture = OpenGL_AllocateTexture;
RenderCommands->FillRegion = OpenGL_FillRegion;
#if VN_SLOW
#if VN_SLOW&&0
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(OpenGL_DebugMessageCallback, 0);
@ -456,10 +652,11 @@ static opengl_context OpenGL_SetupContext(vn_render_commands *RenderCommands, um
static void OpenGL_BeginFrame(vn_render_commands *RenderCommands, v2 RenderDim)
{
RenderCommands->PushBufferAt = RenderCommands->PushBufferBase;
#if VN_USE_INSTANCING
RenderCommands->InstancedQuadCount = 0;
#else
RenderCommands->QuadVertexCount = 0;
RenderCommands->QuadIndexCount = 0;
#if 0
RenderCommands->InstancedQuadCount = 0;
#endif
RenderCommands->RenderDim = RenderDim;
@ -475,6 +672,7 @@ static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderC
glEnable(GL_SCISSOR_TEST);
#if !VN_USE_INSTANCING
glBindBuffer(GL_ARRAY_BUFFER, Context->VertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Context->IndexBuffer);
@ -485,10 +683,7 @@ static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderC
void *IndexData = RenderCommands->QuadIndexBase;
umm IndexSize = RenderCommands->QuadIndexCount*sizeof(s32);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, IndexSize, IndexData);
OpenGL_BeginProgram(&Context->QuadProgram);
glUniform2f(Context->QuadProgram.UniformResolutionLocation,
RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
#endif
for(u8 *PushBufferAt = RenderCommands->PushBufferBase;
PushBufferAt < RenderCommands->PushBufferAt;)
@ -507,60 +702,90 @@ static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderC
glClear(GL_COLOR_BUFFER_BIT);
} break;
case Render_Command_render_command_quads:
{
render_command_quads *Command = (render_command_quads *)PushBufferAt;
PushBufferAt += sizeof(*Command);
for(s32 TextureIndex = 0;
TextureIndex < Command->TexturesUsed;
++TextureIndex)
{
opengl_texture Texture = OpenGL_GetTextureFromHandle(Command->Textures[TextureIndex]);
glActiveTexture(GL_TEXTURE0 + TextureIndex);
glBindTexture(GL_TEXTURE_2D, Texture.ID);
}
glDrawElements(GL_TRIANGLES, Command->QuadCount*6, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
} break;
#if 0
#if VN_USE_INSTANCING
case Render_Command_render_command_instanced_quads:
{
render_command_quads *Command = (render_command_quads *)PushBufferAt;
render_command_instanced_quads *Command = (render_command_instanced_quads *)PushBufferAt;
PushBufferAt += sizeof(*Command);
render_texture_mapping *Mapping = &Command->Mapping;
for(s32 TextureIndex = 0;
TextureIndex < Command->TexturesUsed;
TextureIndex < Mapping->TexturesUsed;
++TextureIndex)
{
opengl_texture Texture = OpenGL_GetTextureFromHandle(Command->Textures[TextureIndex]);
opengl_texture Texture = OpenGL_GetTextureFromHandle(Mapping->Textures[TextureIndex]);
glActiveTexture(GL_TEXTURE0 + TextureIndex);
glBindTexture(GL_TEXTURE_2D, Texture.ID);
}
glDrawElements(GL_TRIANGLES, Command->QuadCount*6, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, Context->InstancedQuadBuffer);
void *VertexData = RenderCommands->InstancedQuadBase+Command->QuadBufferIndex;
umm VertexSize = Command->QuadCount*sizeof(instanced_quad);
glBufferSubData(GL_ARRAY_BUFFER, 0, VertexSize, VertexData);
OpenGL_BeginProgram(&Context->InstancedQuadProgram);
glUniform2f(Context->InstancedQuadProgram.UniformResolutionLocation,
RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, Command->QuadCount);
OpenGL_EndProgram(&Context->InstancedQuadProgram);
glBindTexture(GL_TEXTURE_2D, 0);
} break;
#endif
case Render_Command_render_command_clip:
{
render_command_clip *Command = (render_command_clip *)PushBufferAt;
PushBufferAt += sizeof(*Command);
#if 0
glScissor(Command->ClipRect.P.x, RenderCommands->RenderDim.y - Command->ClipRect.P.y - Command->ClipRect.Dim.y,
Command->ClipRect.Dim.x, Command->ClipRect.Dim.y);
#endif
v2_r32 P = Command->ClipRect.Min;
P.x = Max(Round(P.x), 0.0f);
P.y = Max(Round(P.y), 0.0f);
v2_r32 Dim = DimOfRange(Command->ClipRect);
Dim.x = Max(Round(Dim.x), 0.0f);
Dim.y = Max(Round(Dim.y), 0.0f);
v2_r32 FlippedP = V2R32(P.x, RenderCommands->RenderDim.y-Dim.y-P.y);
glScissor(FlippedP.x, FlippedP.y, Dim.x, Dim.y);
} break;
#else
case Render_Command_render_command_quads:
{
render_command_quads *Command = (render_command_quads *)PushBufferAt;
PushBufferAt += sizeof(*Command);
OpenGL_BeginProgram(&Context->QuadProgram);
glUniform2f(Context->QuadProgram.UniformResolutionLocation,
RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
render_texture_mapping *Mapping = &Command->Mapping;
for(s32 TextureIndex = 0;
TextureIndex < Mapping->TexturesUsed;
++TextureIndex)
{
opengl_texture Texture = OpenGL_GetTextureFromHandle(Mapping->Textures[TextureIndex]);
glActiveTexture(GL_TEXTURE0 + TextureIndex);
glBindTexture(GL_TEXTURE_2D, Texture.ID);
}
}
glDrawElements(GL_TRIANGLES, Command->QuadCount*6, GL_UNSIGNED_INT, 0);
OpenGL_EndProgram(&Context->QuadProgram);
glBindTexture(GL_TEXTURE_2D, 0);
} break;
#endif
InvalidDefaultCase;
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

View File

@ -3,8 +3,8 @@
#ifndef OPENGL_RENDER_H
#define OPENGL_RENDER_H
#include "vn_opengl_defines.h"
#include "generated/vn_opengl_functions.meta.h"
#include "opengl_defines.h"
#include "generated/opengl_functions.meta.h"
struct opengl_texture
{
@ -30,12 +30,31 @@ struct quad_program
u32 UniformResolutionLocation;
};
struct instanced_quad_program
{
u32 ID;
u32 DestID;
u32 SourceID;
u32 TextureIndexID;
u32 ColorID[4];
u32 CornerRadiusID;
u32 EdgeSoftnessID;
u32 BorderThicknessID;
u32 UniformResolutionLocation;
};
struct opengl_context
{
#if VN_USE_INSTANCING
u32 InstancedQuadBuffer;
instanced_quad_program InstancedQuadProgram;
#else
u32 VertexBuffer;
u32 IndexBuffer;
quad_program QuadProgram;
#endif
};
#endif //OPENGL_RENDER_H

View File

@ -22,10 +22,11 @@ global debug_settings *DEBUG_DebugSettings = 0;
#include "vn_text_op.h"
#include "vn_ui.h"
#include "vn_ui_utils.h"
#include "vn_scene.h"
#include "vn_scene_view.h"
#include "vn_workspace.h"
#include "vn_animation_curve.h"
#include "vn_theme_dark.h"
#include "vn_scene.h"
#include "vn_tokenizer.cpp"
#include "vn_config.cpp"
@ -34,12 +35,15 @@ global debug_settings *DEBUG_DebugSettings = 0;
#include "vn_ui.cpp"
#include "vn_ui_utils.cpp"
#include "vn_animation_curve.cpp"
#include "vn_workspace.cpp"
#include "vn_scene.cpp"
#include "vn_scene_view.cpp"
#include "vn_workspace.cpp"
struct vn_state
{
memory_arena *Arena;
memory_arena *FrameArena;
glyph_atlas *GlyphAtlas;
config *Config;
@ -50,8 +54,7 @@ struct vn_state
render_handle BackgroundTexture;
memory_arena *SceneArena;
compiled_scene CompiledScene;
scene_view SceneView;
#if VN_INTERNAL
debug_settings DebugSettings;
@ -92,6 +95,7 @@ static render_handle CreateTextureFromPath(vn_render_commands *Commands, string
return(Result);
}
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
{
SetThreadContext(ThreadContext);
@ -105,12 +109,13 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
memory_arena *Arena = ArenaAllocate(Gigabytes(1));
State = Memory->State = PushStruct(Arena, vn_state);
State->Arena = Arena;
State->FrameArena = ArenaAllocate(Gigabytes(1));
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
State->Config = CreateConfig();
//- sixten: load assets
//State->BackgroundTexture = CreateTextureFromPath(RenderCommands, StrLit("data/backgrounds/Futon_Room.png"));
State->BackgroundTexture = CreateTextureFromPath(RenderCommands, StrLit("data/backgrounds/test.png"));
//- sixten: setup config binds and load current config
{
@ -123,17 +128,17 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
Config_BindB32(State->Config, StrLit("Dev/ShowWelcomeMessage"), &DEBUG_DebugSettings->ShowWelcomeMessage, 1);
#endif
Config_ReadFile(State->Config, StrLit("config.vn"));
}
//- sixten: load startup scene
State->SceneArena = ArenaAllocate(Gigabytes(1));
State->CompiledScene = S_ScriptFromText(State->SceneArena, Platform_ReadEntireFile(State->SceneArena, StrLit("data/compiler_test.vns")));
scene_view *SceneView = &State->SceneView;
SV_Init(SceneView, State->Arena);
SceneView->BackgroundTexture = State->BackgroundTexture;
UI_Init(&State->UI);
Workspace_Init(&State->Workspace);
AnimationCurve_Init(&State->AnimationCurveState);
W_Init(&State->Workspace);
AC_Init(&State->AnimationCurveState);
}
#if VN_INTERNAL
@ -141,17 +146,30 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
#endif
//- sixten: begin new frame
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
ArenaClear(State->FrameArena);
AC_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP, State->GlyphAtlas);
SV_SetState(&State->SceneView);
//- sixten: build the ui
UI_BeginBuild(RenderCommands->RenderDim);
{
Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
b32 EditorMode = true;
if(EditorMode)
{
W_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
}
else
{
SV_BuildSceneView(Input);
}
}
UI_EndBuild();
//- sixten: update the scene
SV_Update(State->FrameArena, Input);
//- sixten: consume all remaining evetns
for(platform_event *Event = Input->EventList->First;
Event != 0;
@ -171,13 +189,6 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
render_group Group = BeginRenderGroup(RenderCommands);
PushClear(&Group, V3(0.1, 0.1, 0.1));
#if 0
PushTexturedQuad(&Group,
Range2R32(V2R32(0, 0), RenderCommands->RenderDim),
Range2R32(V2R32(0, 0), ConvertV2ToR32(DimFromTexture(State->BackgroundTexture))),
Color_White, Color_White, Color_White, Color_White, 0, 0, 0, State->BackgroundTexture);
#endif
UI_RenderFrame(&Group, State->GlyphAtlas);
if(DEBUG_DebugSettings->ListHotAndActive)

View File

@ -1,21 +1,24 @@
global animation_curve_state *Global_AnimationCurveState = 0;
inline animation_curve_state *AnimationCurve_GetState(void)
////////////////////////////////
//~ sixten: Animation Curve Functions
inline animation_curve_state *AC_GetState(void)
{
return(Global_AnimationCurveState);
}
inline void AnimationCurve_SetState(animation_curve_state *State)
inline void AC_SetState(animation_curve_state *State)
{
Global_AnimationCurveState = State;
}
static void AnimationCurve_Init(animation_curve_state *State)
static void AC_Init(animation_curve_state *State)
{
State->Arena = ArenaAllocate(Gigabytes(1));
}
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String)
inline animation_curve_key AC_GenerateKeyFromString(string String)
{
animation_curve_key Key;
Key.Value = HashString(String);
@ -23,9 +26,9 @@ inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String)
return(Key);
}
static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial)
static animation_curve_entry *AC_GetEntryByKey(animation_curve_key Key, r32 Initial)
{
animation_curve_state *State = AnimationCurve_GetState();
animation_curve_state *State = AC_GetState();
u64 Hash = Key.Value;
u64 Slot = Hash % ArrayCount(State->Buckets);
@ -67,26 +70,26 @@ static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key K
return(Result);
}
inline r32 AnimationCurve_GetValue(string Name, r32 Initial)
inline r32 AC_GetValue(string Name, r32 Initial)
{
animation_curve_key Key = AnimationCurve_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Initial);
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
r32 Result = Entry->Value;
return(Result);
}
inline void AnimationCurve_SetValue(string Name, r32 Value)
inline void AC_SetValue(string Name, r32 Value)
{
animation_curve_key Key = AnimationCurve_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Value);
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Value);
Entry->Value = Value;
}
inline r32 AnimationCurve_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
inline r32 AC_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
{
animation_curve_state *State = AnimationCurve_GetState();
animation_curve_state *State = AC_GetState();
r32 Result = *Value;
@ -96,16 +99,16 @@ inline r32 AnimationCurve_AnimateValueDirect(r32 Target, r32 Duration, r32 *Valu
return(Result);
}
inline r32 AnimationCurve_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 = AnimationCurve_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Initial);
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
r32 Result = AnimationCurve_AnimateValueDirect(Target, Duration, &Entry->Value);
r32 Result = AC_AnimateValueDirect(Target, Duration, &Entry->Value);
return(Result);
}
inline r32 AnimationCurve_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);
@ -114,16 +117,16 @@ inline r32 AnimationCurve_AnimateValueF(r32 Target, r32 Initial, r32 Duration, c
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
va_end(Arguments);
r32 Result = AnimationCurve_AnimateValue(Target, Initial, Duration, String);
r32 Result = AC_AnimateValue(Target, Initial, Duration, String);
ReleaseScratch(Scratch);
return(Result);
}
static void AnimationCurve_NewFrame(animation_curve_state *State, r32 dtForFrame)
static void AC_NewFrame(animation_curve_state *State, r32 dtForFrame)
{
AnimationCurve_SetState(State);
AC_SetState(State);
State->dtForFrame = dtForFrame;
// sixten: Prune untouched entries.

View File

@ -3,17 +3,14 @@
#ifndef VN_ANIMATION_CURVE_H
#define VN_ANIMATION_CURVE_H
////////////////////////////////
//~ sixten: Animation Curve Types
struct animation_curve_key
{
u64 Value;
};
inline b32 AreEqual(animation_curve_key A, animation_curve_key B)
{
b32 Result = (A.Value == B.Value);
return(Result);
}
struct animation_curve_entry
{
animation_curve_key Key;
@ -46,15 +43,24 @@ struct animation_curve_state
animation_curve_entry *LastFreeEntry;
};
inline void AnimationCurve_SetState(animation_curve_state *State);
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String);
static void AnimationCurve_Init(animation_curve_state *State);
static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial = 0);
inline r32 AnimationCurve_GetValue(string Name, r32 Initial);
inline void AnimationCurve_SetValue(string Name, r32 Value);
inline r32 AnimationCurve_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value);
inline r32 AnimationCurve_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name);
inline r32 AnimationCurve_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...);
static void AnimationCurve_NewFrame(animation_curve_state *State, r32 dtForFrame);
////////////////////////////////
//~ sixten: Animation Curve Functions
inline b32 AreEqual(animation_curve_key A, animation_curve_key B)
{
b32 Result = (A.Value == B.Value);
return(Result);
}
static void AC_SetState(animation_curve_state *State);
static animation_curve_key AC_GenerateKeyFromString(string String);
static void AC_Init(animation_curve_state *State);
static animation_curve_entry *AC_GetEntryByKey(animation_curve_key Key, r32 Initial = 0);
static r32 AC_GetValue(string Name, r32 Initial);
static void AC_SetValue(string Name, r32 Value);
static r32 AC_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value);
static r32 AC_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name);
static r32 AC_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...);
static void AC_NewFrame(animation_curve_state *State, r32 dtForFrame);
#endif //VN_ANIMATION_CURVE_H

View File

@ -252,7 +252,7 @@ static void Config_WriteFile(config *Config, string Path)
string_list Out = {};
temporary_memory Scratch = GetScratch();
string LastDir = MakeString(0, 0);
string LastDir = MakeString(0, 0LL);
for(config_entry *Entry = Config->FirstInternal;
Entry != 0;
Entry = Entry->NextInternal)
@ -265,7 +265,7 @@ static void Config_WriteFile(config *Config, string Path)
if(!AreEqual(Dir, LastDir))
{
if(!AreEqual(LastDir, MakeString(0, 0)))
if(!AreEqual(LastDir, MakeString(0, 0LL)))
{
AppendString(&Out, StrLit("}\n\n"), Scratch.Arena);
}
@ -309,7 +309,7 @@ static void Config_WriteFile(config *Config, string Path)
AppendString(&Out, StrLit(";\n"), Scratch.Arena);
}
if(!AreEqual(LastDir, MakeString(0, 0)))
if(!AreEqual(LastDir, MakeString(0, 0LL)))
{
AppendString(&Out, StrLit("}"), Scratch.Arena);
}

View File

@ -122,6 +122,8 @@ static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/DejaVuSansMono.ttf"));
Atlas->Fonts[Font_MonospaceOblique].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/DejaVuSansMono-Oblique.ttf"));
Atlas->Fonts[Font_Hand].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/PatrickHand-Regular.ttf"));
Atlas->Fonts[Font_Fancy].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/Merriweather-Regular.ttf"));
Atlas->Fonts[Font_Japanese].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/NotoSansJP-Regular.ttf"));
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("fonts/icons.ttf"));
for(s32 FontIndex = 0;

View File

@ -10,6 +10,8 @@ enum font_id
Font_Monospace,
Font_MonospaceOblique,
Font_Hand,
Font_Fancy,
Font_Japanese,
Font_Icons,
Font_Count,
@ -41,7 +43,7 @@ enum font_id
#define FontIcon_Reply 0xf112
#define FontIcon_Terminal 0xf120
#define FontIcon_Ellipsis 0xf141
#define FontIcon_Document 0xf15b
#define FontIcon_Document 0xe819
#define FontIcon_DocumentText 0xf15c
#define FontIcon_Eyedropper 0xf1fb
#define FontIcon_WindowMaximize 0xf2d0
@ -60,6 +62,19 @@ enum font_id
#define FontIcon_DocumentFileImage 0xf1c5
#define FontIcon_DocumentFileAudio 0xf1c7
#define FontIcon_DocumentFileCode 0xf1c9
#define FontIcon_UserPlus 0xf234
#define FontIcon_UserTimes 0xf235
#define FontIcon_History 0xf235
#define FontIcon_Trash 0xf1f8
#define FontIcon_Debug 0xf188
#define FontIcon_Gamepad 0xf11b
#define FontIcon_Paste 0xf0ea
#define FontIcon_Cut 0xe825
#define FontIcon_Lock 0xe821
#define FontIcon_LockOpen 0xe822
#define FontIcon_Pin 0xe820
#define FontIcon_User 0xe81e
#define FontIcon_Users 0xe81f
struct glyph
{
@ -78,7 +93,7 @@ struct glyph
};
#define DEFAULT_GLYPH_ATLAS_DIM 1024*4
#define MAX_GLYPH_SIZE 64
#define MAX_GLYPH_SIZE 128
#define STB_TRUETYPE_IMPLEMENTATION
#include "third_party/stb_truetype.h"

View File

@ -151,6 +151,11 @@ struct vn_render_commands
u8 *PushBufferBase;
u8 *PushBufferAt;
#if VN_USE_INSTANCING
s32 MaxInstancedQuadCount;
instanced_quad *InstancedQuadBase;
s32 InstancedQuadCount;
#else
s32 MaxQuadVertexCount;
quad_vertex *QuadVertexBase;
s32 QuadVertexCount;
@ -158,6 +163,7 @@ struct vn_render_commands
s32 MaxQuadIndexCount;
s32 *QuadIndexBase;
s32 QuadIndexCount;
#endif
v2 RenderDim;
};

View File

@ -15,6 +15,8 @@
{ BeginFileIter begin_file_iter BEGIN_FILE_ITER `platform_file_iter *` `memory_arena *Arena, string Path` }
{ AdvanceFileIter advance_file_iter ADVANCE_FILE_ITER `b32` `memory_arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo` }
{ EndFileIter end_file_iter END_FILE_ITER `void` `platform_file_iter *Iter` }
{ SetClipboard set_clipboard SET_CLIPBOARD `void` `string String` }
{ GetClipboard get_clipboard GET_CLIPBOARD `string` `memory_arena *Arena` }
}
@table_gen

View File

@ -66,7 +66,7 @@ inline void PushClear(render_group *Group, v3 Color)
Command->Color = Color;
}
inline s32 GetTextureIndexForCommand(render_command_quads *Command, render_handle Handle)
inline s32 GetTextureIndexForCommand(render_texture_mapping *Mapping, render_handle Handle)
{
s32 Result = -1;
@ -74,15 +74,15 @@ inline s32 GetTextureIndexForCommand(render_command_quads *Command, render_handl
TextureIndex < MAX_BOUND_TEXTURES;
++TextureIndex)
{
if(AreEqual(Command->Textures[TextureIndex], EmptyRenderHandle()))
if(AreEqual(Mapping->Textures[TextureIndex], EmptyRenderHandle()))
{
Assert(Command->TexturesUsed == TextureIndex);
Assert(Mapping->TexturesUsed == TextureIndex);
Command->Textures[TextureIndex] = Handle;
++Command->TexturesUsed;
Mapping->Textures[TextureIndex] = Handle;
++Mapping->TexturesUsed;
}
if(AreEqual(Command->Textures[TextureIndex], Handle))
if(AreEqual(Mapping->Textures[TextureIndex], Handle))
{
Result = TextureIndex;
break;
@ -102,8 +102,8 @@ inline u32 PackV4ToU32(v4 V)
return(Result);
}
#if 0
static void PushTexturedQuadAsInstances(render_group *Group,
#if VN_USE_INSTANCING
static void PushTexturedQuad(render_group *Group,
range2_r32 Dest,
range2_r32 Source,
v4 Color00, v4 Color10, v4 Color01, v4 Color11,
@ -115,33 +115,42 @@ static void PushTexturedQuadAsInstances(render_group *Group,
render_command_instanced_quads *Command = (render_command_instanced_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_instanced_quads &&
(TextureIndex = GetTextureIndexForCommand((render_command_quads *)Command, Texture)) != -1))
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
{
Command = PushCommand(Group, render_command_instanced_quads);
TextureIndex = GetTextureIndexForCommand((render_command_quads *)Command, Texture);
Command->QuadBufferIndex = Commands->QuadIndexCount;
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
Command->QuadBufferIndex = Commands->InstancedQuadCount;
}
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
range2_r32 FinalDest = Intersection(Dest, Clip);
if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
//if(InRange(Clip, Dest.Min) || InRange(Clip, Dest.Max))
{
v2_s32 TextureSize = DimFromTexture(Texture);
v2_r32 TextureSizeReal = ConvertV2ToR32(TextureSize);
Source.Min /= TextureSizeReal;
Source.Max /= TextureSizeReal;
#if 0
Dest.Min.x = Round(Dest.Min.x);
Dest.Min.y = Round(Dest.Min.y);
#endif
instanced_quad *Quad = Commands->InstancedQuadBase + Commands->InstancedQuadCount++;
Quad->Dest = Dest;
Quad->Source = Source;
Quad->TextureIndex = TextureIndex;
Quad->Colors[0] = PackV4ToU32(Color00);
Quad->Colors[1] = PackV4ToU32(Color10);
Quad->Colors[2] = PackV4ToU32(Color01);
Quad->Colors[3] = PackV4ToU32(Color11);
Quad->Color[0] = PackV4ToU32(Color00);
Quad->Color[1] = PackV4ToU32(Color01);
Quad->Color[2] = PackV4ToU32(Color10);
Quad->Color[3] = PackV4ToU32(Color11);
Quad->CornerRadius = CornerRadius;
Quad->EdgeSoftness = EdgeSoftness;
Quad->BorderThickness = BorderThickness;
}
}
#endif
Command->QuadCount += 1;
}
}
#else
static void PushTexturedQuad(render_group *Group,
range2_r32 Dest,
range2_r32 Source,
@ -154,11 +163,11 @@ static void PushTexturedQuad(render_group *Group,
render_command_quads *Command = (render_command_quads *)(Group->CurrentCommand + 1);
s32 TextureIndex;
if(!(Group->CurrentCommand && Group->CurrentCommand->Type == Render_Command_render_command_quads &&
(TextureIndex = GetTextureIndexForCommand(Command, Texture)) != -1))
(TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture)) != -1))
{
Command = PushCommand(Group, render_command_quads);
Command->QuadBufferIndex = Commands->QuadIndexCount;
TextureIndex = GetTextureIndexForCommand(Command, Texture);
TextureIndex = GetTextureIndexForCommand(&Command->Mapping, Texture);
}
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
@ -242,13 +251,8 @@ static void PushTexturedQuad(render_group *Group,
++Command->QuadCount;
}
#if 0
else
{
int BreakMe = 0;
}
#endif
}
inline void PushQuad(render_group *Group, range2_r32 Dest,
v4 Color00, v4 Color01, v4 Color10, v4 Color11,
@ -270,12 +274,21 @@ inline void PushClip(render_group *Group, range2_r32 Clip)
{
Assert(Group->ClipStackUsed + 1 < ArrayCount(Group->ClipStack));
#if VN_USE_INSTANCING
render_command_clip *Command = PushCommand(Group, render_command_clip);
Command->ClipRect = Group->ClipStack[++Group->ClipStackUsed] = Clip;
#else
Group->ClipStack[++Group->ClipStackUsed] = Clip;
#endif
}
inline void PopClip(render_group *Group)
{
Assert(Group->ClipStackUsed > 0);
Group->ClipStack[--Group->ClipStackUsed];
#if VN_USE_INSTANCING
render_command_clip *Command = PushCommand(Group, render_command_clip);
Command->ClipRect = Group->ClipStack[--Group->ClipStackUsed];
#else
--Group->ClipStackUsed;
#endif
}

View File

@ -44,7 +44,7 @@ enum render_command_type
{
Render_Command_render_command_clear,
Render_Command_render_command_quads,
//Render_Command_render_command_instanced_quads,
Render_Command_render_command_instanced_quads,
Render_Command_render_command_clip,
};
@ -53,15 +53,26 @@ struct render_command_clear
v3 Color;
};
struct render_command_quads
struct render_texture_mapping
{
u64 QuadCount;
u64 QuadBufferIndex;
s32 TexturesUsed;
render_handle Textures[16];
};
struct render_command_quads
{
render_texture_mapping Mapping;
u64 QuadCount;
u64 QuadBufferIndex;
};
struct render_command_instanced_quads
{
render_texture_mapping Mapping;
u64 QuadCount;
u64 QuadBufferIndex;
};
struct render_command_clip
{
range2_r32 ClipRect;
@ -82,18 +93,16 @@ struct render_group
s32 ClipStackUsed;
};
#if 0
struct instanced_quad
{
range2_r32 Dest;
range2_r32 Source;
u32 TextureIndex;
u32 Colors[4];
u32 Color[4];
r32 CornerRadius;
r32 EdgeSoftness;
r32 BorderThickness;
};
#endif
struct quad_vertex
{

View File

@ -1,14 +1,29 @@
#include "generated/vn_scene.meta.h"
#include "generated/vn_scene.meta.c"
////////////////////////////////
//~ sixten: Scene Compiler Functions
static void S_ParseError(scene_compiler *Compiler, char *Message, s64 TokenOffset)
{
Compiler->EncounteredError = true;
Compiler->InPanicMode = true;
scene_compile_error *Error = PushStruct(Compiler->Arena, scene_compile_error);
Error->Message = PushFormat(Compiler->Arena, Message);
Error->Token = Compiler->At[TokenOffset];
QueuePush(Compiler->Errors.First, Compiler->Errors.Last, Error);
Compiler->Errors.Count += 1;
}
static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
{
scene_annotated_bytecode_bucket *Bucket = Compiler->CurrentBucket;
scene_emission_target *Target = &Compiler->TargetStack[Compiler->TargetStackIndex];
scene_annotated_bytecode_bucket *Bucket = Target->Bucket;
scene_annotated_bytecode_chunk *Chunk = Bucket->Last;
if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Data) || !AreEqual(Chunk->Name, Compiler->CurrentName))
if(!Chunk || Chunk->Count >= ArrayCount(Chunk->Data) || (Target->Type == S_EmissionTarget_Named && !AreEqual(Chunk->Name, Target->Name)))
{
Chunk = PushStruct(Compiler->Arena, scene_annotated_bytecode_chunk);
Chunk->Name = Compiler->CurrentName;
Chunk = PushStruct(Target->Arena, scene_annotated_bytecode_chunk);
Chunk->Name = Target->Name;
QueuePush(Bucket->First, Bucket->Last, Chunk);
Bucket->Count += 1;
@ -17,6 +32,17 @@ static void S_EmitByte(scene_compiler *Compiler, u8 Byte)
Chunk->Count += 1;
}
static void S_EmitBucket(scene_compiler *Compiler, scene_annotated_bytecode_bucket *Bucket)
{
for(scene_annotated_bytecode_chunk *Chunk = Bucket->First; Chunk != 0; Chunk = Chunk->Next)
{
for(s64 Index = 0; Index < Chunk->Count; Index += 1)
{
S_EmitByte(Compiler, Chunk->Data[Index]);
}
}
}
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
{
scene_value_chunk *Chunk = Compiler->LastValueChunk;
@ -32,27 +58,30 @@ static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value)
return(Result);
}
static void S_EmitVariableLength(scene_compiler *Compiler, u64 Value)
static s64 S_EmitVariableLength(scene_compiler *Compiler, u64 Value)
{
s64 Length = 1;
u64 Index = Value;
for(;Index > 0x7F; Index >>= 7)
{
S_EmitByte(Compiler, Index|0x80);
Length += 1;
InvalidCodepath;
}
S_EmitByte(Compiler, Index);
return(Length);
}
static u64 S_ReadVariableLength(u8 **BytePtr)
static scene_variable_read S_ReadVariableLength(u8 *Byte)
{
u64 Result = 0;
u8 *Byte = *BytePtr;
scene_variable_read Result = {};
u8 *StartByte = Byte;
for(;*Byte & 0x80; Byte += 1)
{
Result = (Result<<7)|(*Byte & 0x7F);
Result.Value = (Result.Value<<7)|(*Byte & 0x7F);
}
Result = (Result<<7)|(*Byte & 0x7F);
*BytePtr = Byte;
Result.Value = (Result.Value<<7)|(*Byte & 0x7F);
Result.Size = Byte-StartByte+1;
return(Result);
}
@ -62,19 +91,20 @@ static void S_EmitConstant(scene_compiler *Compiler, scene_value Value)
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, Value));
}
static void S_SetEmissionTarget(scene_compiler *Compiler, string Target)
static void S_SetEmissionTarget(scene_compiler *Compiler, scene_emission_target Target)
{
if(AreEqual(Target, StrLit("")))
{
Compiler->CurrentBucket = &Compiler->GlobalScope;
Compiler->CurrentName = StrLit("Global Scope");
Compiler->TargetStack[Compiler->TargetStackIndex] = Target;
}
else
static void S_PushEmissionTarget(scene_compiler *Compiler, scene_emission_target Target)
{
u64 Hash = HashString(Target);
Compiler->CurrentBucket = &Compiler->ProcBuckets[Hash % ArrayCount(Compiler->ProcBuckets)];
Compiler->CurrentName = Target;
Compiler->TargetStackIndex += 1;
Compiler->TargetStack[Compiler->TargetStackIndex] = Target;
}
static void S_PopEmissionTarget(scene_compiler *Compiler)
{
Compiler->TargetStackIndex -= 1;
}
static scene_annotated_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name)
@ -166,7 +196,8 @@ static void S_ParseTopLevelDeclaration(scene_compiler *Compiler)
}
else
{
S_ParseError(Compiler, "Expected top-level declaration (proc or var)..");
S_ParseError(Compiler, "Expected top-level declaration (proc or var).", 0);
Compiler->At += 1;
}
}
@ -175,7 +206,11 @@ static void S_ParseProcedure(scene_compiler *Compiler)
token NameToken = S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected procedure name after 'proc'");
S_ConsumeToken(Compiler, TokenKind_CurlyOpen, "Expected '{' after procedure name.");
S_SetEmissionTarget(Compiler, T_StringFromToken(Compiler->Text, NameToken));
if(!Compiler->InPanicMode)
{
string Name = T_StringFromToken(Compiler->Text, NameToken);
scene_annotated_bytecode_bucket *Bucket = &Compiler->ProcBuckets[HashString(Name)%ArrayCount(Compiler->ProcBuckets)];
S_SetEmissionTarget(Compiler, S_NamedEmissionTarget(Compiler->Arena, Bucket, Name));
for(;Compiler->At < Compiler->TokensEnd;)
{
@ -190,7 +225,7 @@ static void S_ParseProcedure(scene_compiler *Compiler)
}
}
}
}
static void S_ParseDeclaration(scene_compiler *Compiler)
{
switch(Compiler->At[0].Kind)
@ -205,17 +240,51 @@ static void S_ParseDeclaration(scene_compiler *Compiler)
Compiler->At += 1;
S_ParseLineEntry(Compiler);
} break;
case TokenKind_Jump:
{
Compiler->At += 1;
S_ParseJumpStatement(Compiler);
} break;
case TokenKind_Branch:
{
Compiler->At += 1;
S_ParseBranchStatement(Compiler);
} break;
default:
{
S_ParseStatement(Compiler);
} break;
}
if(Compiler->InPanicMode)
{
for(;Compiler->At < Compiler->TokensEnd;)
{
if(Compiler->At[0].Kind == TokenKind_Semicolon)
{
goto End;
}
switch(Compiler->At[-1].Kind)
{
case TokenKind_Var: goto End;
case TokenKind_StringLiteral: goto End;
case TokenKind_Jump: goto End;
case TokenKind_Branch: goto End;
}
Compiler->At += 1;
}
End:
Compiler->InPanicMode = false;
}
}
static void S_ParseVariableDeclaration(scene_compiler *Compiler)
{
S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected variable name.");
u64 NameConstant = S_MakeConstant(Compiler, S_MakePointer(&Compiler->At[-1]));
u64 NameConstant = S_MakeConstant(Compiler, S_MakeSourceRef(Compiler->At[-1]));
if(Compiler->At[0].Kind == TokenKind_Equal)
{
@ -241,12 +310,12 @@ static void S_ParseVariableDeclaration(scene_compiler *Compiler)
static void S_ParseVariable(scene_compiler *Compiler, b32 CanAssign)
{
S_ParseNamedVariable(Compiler, &Compiler->At[-1], CanAssign);
S_ParseNamedVariable(Compiler, Compiler->At[-1], CanAssign);
}
static void S_ParseNamedVariable(scene_compiler *Compiler, token *Token, b32 CanAssign)
static void S_ParseNamedVariable(scene_compiler *Compiler, token Token, b32 CanAssign)
{
u64 NameConstant = S_MakeConstant(Compiler, S_MakePointer(Token));
u64 NameConstant = S_MakeConstant(Compiler, S_MakeSourceRef(Token));
if(CanAssign && Compiler->At[0].Kind == TokenKind_Equal)
{
Compiler->At += 1;
@ -262,7 +331,7 @@ static void S_ParseNamedVariable(scene_compiler *Compiler, token *Token, b32 Can
static void S_ParseLineEntry(scene_compiler *Compiler)
{
token *LineToken = &Compiler->At[-1];
token LineToken = Compiler->At[-1];
b32 EmitAwait = true;
@ -290,13 +359,129 @@ static void S_ParseLineEntry(scene_compiler *Compiler)
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after line entry.");
S_EmitByte(Compiler, S_Op_LineEntry|Flags);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakePointer(LineToken)));
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(LineToken)));
if(EmitAwait)
{
S_EmitByte(Compiler, S_Op_AwaitInput);
}
}
static void S_ParseJumpStatement(scene_compiler *Compiler)
{
S_ConsumeToken(Compiler, TokenKind_Identifier, "Expected jump destination.");
token DestToken = Compiler->At[-1];
S_EmitByte(Compiler, S_Op_Jump);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(DestToken)));
S_ConsumeToken(Compiler, TokenKind_Semicolon, "Expected ';' after jump statement.");
}
static void S_ParseBranchStatement(scene_compiler *Compiler)
{
temporary_memory Scratch = GetScratch();
scene_branch_case *FirstBranch = 0, *LastBranch = 0;
S_ConsumeToken(Compiler, TokenKind_CurlyOpen, "Expected '{' after 'branch'.");
for(;Compiler->At < Compiler->TokensEnd;)
{
if(Compiler->At[0].Kind == TokenKind_CurlyClose)
{
Compiler->At += 1;
break;
}
else
{
//- sixten: parse branch declarations
switch(Compiler->At[0].Kind)
{
case TokenKind_StringLiteral:
{
scene_branch_case *Branch = S_ParseBranchCase(Compiler, Scratch.Arena);
QueuePush(FirstBranch, LastBranch, Branch);
} break;
default:
{
S_ParseError(Compiler, "Expected branch case.");
Compiler->At += 1;
} break;
}
}
}
//- sixten: emit add_branch calls
for(scene_branch_case *Branch = FirstBranch; Branch != 0; Branch = Branch->Next)
{
S_EmitByte(Compiler, S_Op_AddBranch);
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeSourceRef(Branch->Name)));
S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeOffset(0)));
scene_value_chunk *Chunk = Compiler->LastValueChunk;
Branch->OffsetValue = &Chunk->Values[Chunk->Count-1];
}
S_EmitByte(Compiler, S_Op_Halt);
// sixten: We need to keep track of the amount of bytes that have been emitted between branch cases, such that we can patch our relative jumps
// to point to the correct address.
s64 BaseOffset = 0;
//- sixten: emit branch contents
for(scene_branch_case *Branch = FirstBranch; Branch != 0; Branch = Branch->Next)
{
//- sixten: patch branch jump dest
Branch->OffsetValue->Offset = BaseOffset;
if(Branch->Bucket.Count > 0)
{
S_EmitBucket(Compiler, &Branch->Bucket);
BaseOffset += (Branch->Bucket.Count - 1)*ArrayCount(scene_bytecode_chunk::Data)+Branch->Bucket.Last->Count;
}
S_EmitByte(Compiler, S_Op_JumpClose);
BaseOffset += 1;
BaseOffset += S_EmitVariableLength(Compiler, S_MakeConstant(Compiler, S_MakeOffset(BaseOffset)));
scene_value_chunk *Chunk = Compiler->LastValueChunk;
Branch->EndOffsetValue = &Chunk->Values[Chunk->Count-1];
}
//- sixten: patch the last jump
for(scene_branch_case *Branch = FirstBranch; Branch != 0; Branch = Branch->Next)
{
Branch->EndOffsetValue->Offset = BaseOffset-Branch->EndOffsetValue->Offset;
}
ReleaseScratch(Scratch);
}
static scene_branch_case *S_ParseBranchCase(scene_compiler *Compiler, memory_arena *Arena)
{
scene_branch_case *Branch = PushStruct(Arena, scene_branch_case);
Branch->Name = S_ConsumeToken(Compiler, TokenKind_StringLiteral, "Expected branch label at start of branch case.");
S_ConsumeToken(Compiler, TokenKind_CurlyOpen, "Expected '{' after branch label.");
S_PushEmissionTarget(Compiler, S_RawEmissionTarget(Arena, &Branch->Bucket));
for(;Compiler->At < Compiler->TokensEnd;)
{
if(Compiler->At[0].Kind == TokenKind_CurlyClose)
{
Compiler->At += 1;
break;
}
else
{
S_ParseDeclaration(Compiler);
}
}
S_PopEmissionTarget(Compiler);
return(Branch);
}
static void S_ParseStatement(scene_compiler *Compiler)
{
S_ParseExpression(Compiler);
@ -404,15 +589,16 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
u8 *ChunkBegin = Chunk->Data;
u8 *ChunkEnd = ChunkBegin + Chunk->Count;
for(u8 *Data = ChunkBegin; Data < ChunkEnd; Data += 1)
for(u8 *Data = ChunkBegin; Data < ChunkEnd;)
{
switch(*Data)
{
case S_Op_Constant:
{
Data += 1;
u64 ValueIndex = S_ReadVariableLength(&Data);
scene_value Value = Compiler->FirstValueChunk->Values[ValueIndex];
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
scene_value Value = Compiler->FirstValueChunk->Values[VariableRead.Value];
AppendString(&List, StrLit("Constant: "), Scratch.Arena);
switch(Value.Kind)
{
@ -421,24 +607,24 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
case S_ValueKind_Pointer: { AppendString(&List, PushFormat(Scratch.Arena, "%x (pointer)\n", Value.Pointer), Scratch.Arena); } break;
}
} break;
case S_Op_Nil: { AppendString(&List, StrLit("Nil\n"), Scratch.Arena); } break;
case S_Op_True: { AppendString(&List, StrLit("True\n"), Scratch.Arena); } break;
case S_Op_False: { AppendString(&List, StrLit("False\n"), Scratch.Arena); } break;
case S_Op_Negate: { AppendString(&List, StrLit("Negate\n"), Scratch.Arena); } break;
case S_Op_Not: { AppendString(&List, StrLit("Not\n"), Scratch.Arena); } break;
case S_Op_Add: { AppendString(&List, StrLit("Add\n"), Scratch.Arena); } break;
case S_Op_Subtract: { AppendString(&List, StrLit("Subtract\n"), Scratch.Arena); } break;
case S_Op_Multiply: { AppendString(&List, StrLit("Multiply\n"), Scratch.Arena); } break;
case S_Op_Divide: { AppendString(&List, StrLit("Divide\n"), Scratch.Arena); } break;
case S_Op_Equal: { AppendString(&List, StrLit("Equal\n"), Scratch.Arena); } break;
case S_Op_Greater: { AppendString(&List, StrLit("Greater\n"), Scratch.Arena); } break;
case S_Op_Less: { AppendString(&List, StrLit("Less\n"), Scratch.Arena); } break;
case S_Op_Nil: { AppendString(&List, StrLit("Nil\n"), Scratch.Arena); Data += 1; } break;
case S_Op_True: { AppendString(&List, StrLit("True\n"), Scratch.Arena); Data += 1; } break;
case S_Op_False: { AppendString(&List, StrLit("False\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Negate: { AppendString(&List, StrLit("Negate\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Not: { AppendString(&List, StrLit("Not\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Add: { AppendString(&List, StrLit("Add\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Subtract: { AppendString(&List, StrLit("Subtract\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Multiply: { AppendString(&List, StrLit("Multiply\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Divide: { AppendString(&List, StrLit("Divide\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Equal: { AppendString(&List, StrLit("Equal\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Greater: { AppendString(&List, StrLit("Greater\n"), Scratch.Arena); Data += 1; } break;
case S_Op_Less: { AppendString(&List, StrLit("Less\n"), Scratch.Arena); Data += 1; } break;
case S_Op_DefineGlobal:
{
Data += 1;
u64 Index = S_ReadVariableLength(&Data);
u64 Pointer = Compiler->FirstValueChunk->Values[Index].Pointer;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, StrLit("Define Global: "), Scratch.Arena);
@ -449,7 +635,9 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
case S_Op_GetGlobal:
{
Data += 1;
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, PushFormat(Scratch.Arena, "Get Global: %S\n", String), Scratch.Arena);
@ -457,7 +645,9 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
case S_Op_SetGlobal:
{
Data += 1;
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = T_StringFromToken(Compiler->Text, *Token);
AppendString(&List, PushFormat(Scratch.Arena, "Set Global: %S\n", String), Scratch.Arena);
@ -468,7 +658,9 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
if(*Data & S_Op_LineEntry)
{
Data += 1;
u64 Pointer = Compiler->FirstValueChunk->Values[S_ReadVariableLength(&Data)].Pointer;
scene_variable_read VariableRead = S_ReadVariableLength(Data);
Data += VariableRead.Size;
u64 Pointer = Compiler->FirstValueChunk->Values[VariableRead.Value].Pointer;
token *Token = (token *)Pointer;
string String = Substring(Compiler->Text, Pad(Token->Range, -1));
AppendString(&List, PushFormat(Scratch.Arena, "Line Entry: %S\n", String), Scratch.Arena);
@ -476,6 +668,7 @@ static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_by
else
{
AppendString(&List, StrLit("Unknown Op\n"), Scratch.Arena);
Data += 1;
}
} break;
}
@ -539,9 +732,6 @@ static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text)
temporary_memory Scratch = GetScratch(&Arena, 1);
tokenize_result TokenizeResult = T_TokenizeFromText(Arena, Text, T_IsIrregular);
// sixten(TODO): append token errors
//- sixten: tokens -> bytecode
scene_compiler Compiler = {};
{
Compiler.Arena = Scratch.Arena;
@ -550,13 +740,27 @@ static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text)
Compiler.TokensEnd = Compiler.TokensBegin+TokenizeResult.Tokens.Count;
Compiler.At = Compiler.TokensBegin;
};
S_SetEmissionTarget(&Compiler, S_RawEmissionTarget(Compiler.Arena, &Compiler.GlobalScope));
S_SetEmissionTarget(&Compiler, StrLit(""));
//- sixten: append tokenization errors
b32 FoundTokenizationError = false;
for(tokenizer_message *Message = TokenizeResult.Messages.First; Message != 0; Message = Message->Next)
{
if(Message->Kind == T_MessageKind_Error)
{
S_ParseError(&Compiler, (char *)Message->String.Data);
FoundTokenizationError = true;
}
}
//- sixten: tokens -> bytecode
if(!FoundTokenizationError)
{
for(;Compiler.At < Compiler.TokensEnd;)
{
S_ParseTopLevelDeclaration(&Compiler);
}
}
//- sixten: bake compiled chunks
for(s64 BucketIndex = 0; BucketIndex < ArrayCount(Compiler.ProcBuckets); BucketIndex += 1)
@ -579,14 +783,252 @@ static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text)
scene_value *Dest = Result.Values;
for(scene_value_chunk *Chunk = Compiler.FirstValueChunk; Chunk != 0; Chunk = Chunk->Next)
{
Copy(Dest, Chunk->Values, Chunk->Count);
Copy(Dest, Chunk->Values, Chunk->Count*sizeof(scene_value));
Dest += Chunk->Count;
}
}
//- sixten: copy errors
for(scene_compile_error *Error = Compiler.Errors.First; Error != 0; Error = Error->Next)
{
scene_compile_error *New = PushStruct(Arena, scene_compile_error);
New->Message = PushString(Arena, Error->Message);
New->Token = Error->Token;
QueuePush(Result.Errors.First, Result.Errors.Last, New);
}
Result.Errors.Count = Compiler.Errors.Count;
// sixten(IMPORTANT): The text is assumed to remain in memory for the duration of the scene.
Result.Source = Text;
Result.IsValid = !Compiler.EncounteredError;
ReleaseScratch(Scratch);
return(Result);
}
static compiled_scene S_CopyCompiledScene(memory_arena *Arena, compiled_scene *Compiled)
{
compiled_scene Result = {};
Assert(Compiled->Errors.Count == 0);
//- sixten: copy the procs
for(s64 BucketIndex = 0; BucketIndex < ArrayCount(Compiled->Buckets); BucketIndex += 1)
{
scene_proc_bucket *SourceBucket = &Compiled->Buckets[BucketIndex];
scene_proc_bucket *DestBucket = &Result.Buckets[BucketIndex];
for(scene_proc *Proc = SourceBucket->First; Proc != 0; Proc = Proc->Next)
{
scene_proc *NewProc = PushStruct(Arena, scene_proc);
NewProc->Name = PushString(Arena, Proc->Name);
NewProc->Data = PushArray(Arena, u8, Proc->Count);
Copy(NewProc->Data, Proc->Data, Proc->Count);
NewProc->Count = Proc->Count;
QueuePush(DestBucket->First, DestBucket->Last, NewProc);
}
}
//- sixten: copy the values
Result.Values = PushArray(Arena, scene_value, Compiled->ValueCount);
Copy(Result.Values, Compiled->Values, Compiled->ValueCount*sizeof(scene_value));
Result.ValueCount = Compiled->ValueCount;
//- sixten: copy the source
Result.Source = PushString(Arena, Compiled->Source);
Result.IsValid = true;//Compiled->IsValid;
return(Result);
}
////////////////////////////////
//~ sixten: Scene Runtime Functions
static void S_RuntimeError(scene_runtime *Runtime, string Message)
{
scene_runtime_error *Error = PushStruct(Runtime->ErrorArena, scene_runtime_error);
Error->Message = PushString(Runtime->ErrorArena, Message);
DLLInsertLast(Runtime->FirstError, Runtime->LastError, Error);
}
static void S_RuntimeErrorF(scene_runtime *Runtime, char *Format, ...)
{
va_list Arguments;
va_start(Arguments, Format);
scene_runtime_error *Error = PushStruct(Runtime->ErrorArena, scene_runtime_error);
Error->Message = PushFormatVariadic(Runtime->ErrorArena, Format, Arguments);
DLLInsertLast(Runtime->FirstError, Runtime->LastError, Error);
va_end(Arguments);
}
static scene_proc *S_FindProcByName(compiled_scene *Compiled, string Name)
{
scene_proc *Result = 0;
u64 Hash = HashString(Name);
scene_proc_bucket *Bucket = &Compiled->Buckets[Hash%ArrayCount(Compiled->Buckets)];
for(scene_proc *Proc = Bucket->First; Proc != 0; Proc = Proc->Next)
{
if(AreEqual(Proc->Name, Name))
{
Result = Proc;
break;
}
}
return(Result);
}
static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameArena, b32 AdvanceOnAwait)
{
scene_runtime_result Result = {};
compiled_scene *Compiled = &Runtime->Compiled;
Assert(Runtime != 0);
Assert(Compiled->IsValid);
if(Runtime->CurrentProc == 0)
{
Runtime->CurrentProc = S_FindProcByName(Compiled, StrLit("main"));
}
if(Runtime->CurrentProc)
{
if(Runtime->IP < Runtime->CurrentProc->Count)
{
u8 *Data = Runtime->CurrentProc->Data;
switch(Data[Runtime->IP])
{
case S_Op_Jump:
{
Runtime->IP += 1;
scene_variable_read VariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
Runtime->IP += VariableRead.Size;
scene_value Value = Compiled->Values[VariableRead.Value];
if(Value.Kind == S_ValueKind_SourceRef)
{
string JumpDest = Substring(Compiled->Source, Value.SourceRef);
scene_proc *Dest = S_FindProcByName(Compiled, JumpDest);
if(Dest)
{
Runtime->CurrentProc = Dest;
Runtime->IP = 0;
}
else
{
S_RuntimeErrorF(Runtime, "Trying to jump to unknown proc: %S", JumpDest);
}
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving jump destination.");
}
} break;
case S_Op_JumpClose:
{
Runtime->IP += 1;
scene_variable_read OffsetVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value OffsetValue = Compiled->Values[OffsetVariableRead.Value];
if(OffsetValue.Kind == S_ValueKind_Offset)
{
Runtime->IP += OffsetValue.Offset;
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving offset.");
}
} break;
case S_Op_AddBranch:
{
Runtime->IP += 1;
scene_variable_read BranchVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value BranchName = Compiled->Values[BranchVariableRead.Value];
Runtime->IP += BranchVariableRead.Size;
if(BranchName.Kind == S_ValueKind_SourceRef)
{
scene_variable_read OffsetVariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
scene_value Offset = Compiled->Values[OffsetVariableRead.Value];
Runtime->IP += OffsetVariableRead.Size;
if(Offset.Kind == S_ValueKind_Offset)
{
branch_case *Branch = &Runtime->Branches[Runtime->BranchCount];
Branch->Name = Substring(Compiled->Source, Pad(BranchName.SourceRef, -1));
Branch->Offset = Offset.Offset;
Runtime->BranchCount += 1;
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving offset.");
}
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving branch name.");
}
} break;
case S_Op_Halt: { Result.ReachedAwait = true; } break;
case S_Op_AwaitInput:
{
if(AdvanceOnAwait)
{
Runtime->IP += 1;
}
Result.ReachedAwait = true;
} break;
default:
{
if(Data[Runtime->IP] & S_Op_LineEntry)
{
textbox_action *Action = PushStructNoClear(FrameArena, textbox_action);
if(Data[Runtime->IP] & S_LineEntryFlag_NoClear)
{
Action->Kind = TextboxActionKind_Append;
}
else
{
Action->Kind = TextboxActionKind_Set;
}
Runtime->IP += 1;
scene_variable_read VariableRead = S_ReadVariableLength(&Data[Runtime->IP]);
Runtime->IP += VariableRead.Size;
scene_value Value = Compiled->Values[VariableRead.Value];
if(Value.Kind == S_ValueKind_SourceRef)
{
Action->String = Substring(Compiled->Source, Pad(Value.SourceRef, -1));
QueuePush(Runtime->FirstTextboxAction, Runtime->LastTextboxAction, Action);
}
else
{
S_RuntimeErrorF(Runtime, "Incorrect value kind when retrieving line entry.");
}
}
else
{
S_RuntimeErrorF(Runtime, "Unknown bytecode op: 0x%02x", Data[Runtime->IP]);
}
} break;
}
}
else
{
S_RuntimeErrorF(Runtime, "Reached end of proc.");
}
}
else
{
S_RuntimeErrorF(Runtime, "No main entry was found");
}
Result.HadError = !DLLIsEmpty(Runtime->FirstError);
Runtime->LastResult = Result;
return(Result);
}

View File

@ -12,6 +12,20 @@
////////////////////////////////
//~ sixten: Scene Compilation Types
struct scene_compile_error
{
scene_compile_error *Next;
string Message;
token Token;
};
struct scene_compile_error_list
{
scene_compile_error *First;
scene_compile_error *Last;
s64 Count;
};
typedef u64 scene_line_entry_flag;
enum
{
@ -44,6 +58,11 @@ enum scene_opcode
S_Op_GetGlobal,
S_Op_SetGlobal,
S_Op_Jump,
S_Op_JumpClose,
S_Op_AddBranch,
S_Op_Halt,
S_Op_AwaitInput,
S_Op_LineEntry = 0x80, // sixten(NOTE): All opcoodes above are reserved.
@ -76,6 +95,8 @@ enum scene_value_kind
S_ValueKind_Number,
S_ValueKind_Boolean,
S_ValueKind_Pointer,
S_ValueKind_SourceRef,
S_ValueKind_Offset,
};
struct scene_value
@ -86,6 +107,8 @@ struct scene_value
r64 Number;
b32 Boolean;
u64 Pointer;
range1_s64 SourceRef;
s64 Offset;
};
};
@ -96,6 +119,12 @@ struct scene_value_chunk
scene_value Values[512];
};
struct scene_variable_read
{
u64 Value;
s64 Size;
};
enum scene_precedence
{
S_Precedence_None,
@ -120,10 +149,37 @@ struct scene_parse_rule
scene_precedence Precedence;
};
enum scene_emission_target_type
{
S_EmissionTarget_Raw,
S_EmissionTarget_Named,
};
struct scene_emission_target
{
memory_arena *Arena;
scene_annotated_bytecode_bucket *Bucket;
scene_emission_target_type Type;
string Name;
};
struct scene_branch_case
{
scene_branch_case *Next;
token Name;
scene_annotated_bytecode_bucket Bucket;
scene_value *OffsetValue;
scene_value *EndOffsetValue;
};
struct scene_compiler
{
memory_arena *Arena;
b32 InPanicMode;
b32 EncounteredError;
scene_compile_error_list Errors;
string Text;
token *TokensBegin;
token *TokensEnd;
@ -132,8 +188,8 @@ struct scene_compiler
scene_annotated_bytecode_bucket GlobalScope;
scene_annotated_bytecode_bucket ProcBuckets[32];
scene_annotated_bytecode_bucket *CurrentBucket;
string CurrentName;
scene_emission_target TargetStack[16];
s32 TargetStackIndex;
scene_value_chunk *FirstValueChunk;
scene_value_chunk *LastValueChunk;
@ -165,10 +221,71 @@ struct compiled_scene
scene_value *Values;
s64 ValueCount;
string Source;
scene_compile_error_list Errors;
b32 IsValid;
};
////////////////////////////////
//~ sixten: Scene Runtime Types
struct scene_runtime_error
{
scene_runtime_error *Next;
scene_runtime_error *Prev;
string Message;
};
struct scene_runtime_result
{
b32 HadError;
b32 ReachedAwait;
};
enum textbox_action_kind
{
TextboxActionKind_Set,
TextboxActionKind_Append,
};
struct textbox_action
{
textbox_action *Next;
textbox_action_kind Kind;
string String;
};
struct branch_case
{
string Name;
s64 Offset;
};
struct scene_runtime
{
compiled_scene Compiled;
// sixten: runtime state
scene_proc *CurrentProc;
s64 IP;
// sixten: errors
memory_arena *ErrorArena;
scene_runtime_error *FirstError;
scene_runtime_error *LastError;
// sixten: branches
branch_case Branches[16];
s64 BranchCount;
// sixten: result
textbox_action *FirstTextboxAction;
textbox_action *LastTextboxAction;
branch_case *FirstBranchCase;
scene_runtime_result LastResult;
};
////////////////////////////////
//~ sixten: Scene Compiler Functions
//- sixten: value helpers
inline scene_value S_MakeNumber(r64 Value)
{
@ -194,18 +311,56 @@ inline scene_value S_MakePointer(void *Value)
return(Result);
}
inline scene_value S_MakeSourceRef(token Token)
{
scene_value Result;
Result.Kind = S_ValueKind_SourceRef;
Result.SourceRef = Token.Range;
return(Result);
}
inline scene_value S_MakeOffset(s64 Offset)
{
scene_value Result;
Result.Kind = S_ValueKind_Offset;
Result.Offset = Offset;
return(Result);
}
//- sixten: error messaging
static void S_ParseError(scene_compiler *Compiler, char *Message) { InvalidCodepath; }
static void S_ParseError(scene_compiler *Compiler, char *Message, s64 TokenOffset = -1);
//- sixten: bytecode helpers
static void S_EmitByte(scene_compiler *Compiler, u8 Byte);
static void S_EmitBucket(scene_compiler *Compiler, scene_annotated_bytecode_bucket *Bucket);
static u64 S_MakeConstant(scene_compiler *Compiler, scene_value Value);
static void S_EmitVariableLength(scene_compiler *Compiler, u64 Value);
static u64 S_ReadVariableLength(u8 **BytePtr);
static s64 S_EmitVariableLength(scene_compiler *Compiler, u64 Value);
static scene_variable_read S_ReadVariableLength(u8 *Byte);
static void S_EmitConstant(scene_compiler *Compiler, scene_value Value);
static void S_SetEmissionTarget(scene_compiler *Compiler, string Target);
static void S_SetEmissionTarget(scene_compiler *Compiler, scene_emission_target Target);
static void S_PushEmissionTarget(scene_compiler *Compiler, scene_emission_target Target);
static void S_PopEmissionTarget(scene_compiler *Compiler);
static scene_annotated_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name);
inline scene_emission_target S_RawEmissionTarget(memory_arena *Arena, scene_annotated_bytecode_bucket *Bucket)
{
scene_emission_target Target = {};
Target.Arena = Arena;
Target.Bucket = Bucket;
Target.Type = S_EmissionTarget_Raw;
return(Target);
}
inline scene_emission_target S_NamedEmissionTarget(memory_arena *Arena, scene_annotated_bytecode_bucket *Bucket, string Name)
{
scene_emission_target Target = {};
Target.Arena = Arena;
Target.Bucket = Bucket;
Target.Type = S_EmissionTarget_Named;
Target.Name = Name;
return(Target);
}
//- sixten: parsing helpers
static void S_AdvanceCompiler(scene_compiler *Compiler);
static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Token);
@ -218,8 +373,11 @@ static void S_ParseProcedure(scene_compiler *Compiler);
static void S_ParseDeclaration(scene_compiler *Compiler);
static void S_ParseVariableDeclaration(scene_compiler *Compiler);
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_ParseLineEntry(scene_compiler *Compiler);
static void S_ParseJumpStatement(scene_compiler *Compiler);
static void S_ParseBranchStatement(scene_compiler *Compiler);
static scene_branch_case *S_ParseBranchCase(scene_compiler *Compiler, memory_arena *Arena);
static void S_ParseStatement(scene_compiler *Compiler);
static void S_ParseExpression(scene_compiler *Compiler);
static void S_ParseLiteral(scene_compiler *Compiler, b32 CanAssign);
@ -232,9 +390,13 @@ static void S_ParsePrecedence(scene_compiler *Compiler, scene_precedence Precede
//- sixten: debugging
static string S_DisassembleBytecode(scene_compiler *Compiler, scene_annotated_bytecode_chunk *Chunk, memory_arena *Arena);
//- sixten: api
//- sixten: compilation
static compiled_scene S_ScriptFromText(memory_arena *Arena, string Text);
static compiled_scene S_CopyCompiledScene(memory_arena *Arena, compiled_scene *Compiled);
////////////////////////////////
//~ sixten: Scene Runtime Functions
static scene_proc *S_FindProcByName(compiled_scene *Compiled, string Name);
static scene_runtime_result S_Run(scene_runtime *Runtime, memory_arena *FrameArena, b32 AdvanceOnAwait);
#endif //VN_SCENE_H

View File

@ -0,0 +1,342 @@
thread_local scene_view *ThreadLocal_SceneView = 0;
static void SV_SetState(scene_view *View)
{
ThreadLocal_SceneView = View;
}
static scene_view *SV_GetState()
{
return(ThreadLocal_SceneView);
}
static void SV_SetCurrentSource(compiled_scene *Compiled)
{
scene_view *SceneView = SV_GetState();
// sixten(TODO): extract runtime information required to seamlessly transition between compilations
ArenaClear(SceneView->SceneArena);
SceneView->Runtime.Compiled = S_CopyCompiledScene(SceneView->SceneArena, Compiled);
SceneView->Runtime.IP = 0;
}
static void SV_Init(scene_view *SceneView, memory_arena *TextboxArena)
{
SV_SetState(SceneView);
SceneView->SceneArena = ArenaAllocate(Gigabytes(1));
SceneView->Runtime.ErrorArena = ArenaAllocate(Megabytes(1));
SceneView->Textbox.Capacity = 4096;
SceneView->Textbox.String.Data = PushArray(TextboxArena, u8, SceneView->Textbox.Capacity);
SceneView->Textbox.String.Count = 0;
}
struct text_properties
{
font_id Font;
r32 FontSize;
r32 LineHeight;
};
static void RenderAnimatedText(render_group *Group, glyph_atlas *Atlas, text_properties Properties, string Text, r32 CharsToRender, v2_r32 P, r32 WrapWidth)
{
v2_r32 Offset = V2R32(0, 0);
u8 *TextBegin = Text.Data;
u8 *TextEnd = TextBegin+Text.Count;
u8 *Byte = TextBegin;
u8 *WordBegin = TextBegin;
u8 *WordEnd = WordBegin;
u8 *TrueWordEnd = WordBegin;
string_decode LastVisibleDecode = {};
Byte = TextBegin;
for(;Byte<=TextEnd;)
{
string_decode Decode = DecodeUTF8Codepoint(Byte, TextEnd-Byte);
if(CharsToRender >= 1)
{
LastVisibleDecode = Decode;
}
if(Decode.Codepoint == ' ' || Byte==TextEnd)
{
string TrueWord = MakeString(WordBegin, TrueWordEnd);
string Word = MakeString(WordBegin, WordEnd);
r32 WordWidth = CalculateRasterizedTextWidth(Atlas, Properties.Font, Properties.FontSize, TrueWord);
if(Offset.x+WordWidth > WrapWidth)
{
Offset.x = 0;
Offset.y += Properties.LineHeight;
}
Offset.x += PushText(Group, Atlas, Properties.Font, P+Offset, Properties.FontSize, Color_White, Word);
if(WordEnd != TrueWordEnd)
{
string LastChar = MakeString(WordEnd, LastVisibleDecode.Size);
r32 TransitionAmount = Mod(CharsToRender, 1);
Offset.y += (1-TransitionAmount)*5;
PushText(Group, Atlas, Properties.Font, P+Offset, Properties.FontSize, SetAlpha(Color_White, TransitionAmount), LastChar);
}
WordBegin = TrueWordEnd;
if(Byte==TextEnd || CharsToRender < 1)
{
break;
}
}
Byte += Decode.Size;
TrueWordEnd += Decode.Size;
if(CharsToRender >= 1)
{
WordEnd += Decode.Size;
CharsToRender -= 1;
}
}
}
static r32 CalculateGlobalScaleFromRootBox(ui_box *Box)
{
v2 RenderDim = DimOfRange(Box->Rect);
r32 GlobalScale = SquareRoot(RenderDim.x*RenderDim.y)/45;
return(GlobalScale);
}
struct scene_textbox_data
{
textbox *Textbox;
ui_box *SceneViewBox;
};
UI_CUSTOM_DRAW_CALLBACK(BuildSceneTextboxDrawCallback)
{
scene_textbox_data *TextboxData = (scene_textbox_data *)Data;
textbox *Textbox = TextboxData->Textbox;
//- sixten: render textbox
v4 TopColor = V4(0, 0, 0, 0.8f);
v4 BottomColor = V4(0, 0, 0, 0.5f);
range2_r32 Dest = Range2R32(Box->Rect.Min, Box->Rect.Max);
PushQuad(Group, Dest, TopColor, TopColor, BottomColor, BottomColor, 0, 0, 0);
//- sixten: render text
string Text = Textbox->String;
r32 CharsRevealed = Textbox->CharsRevealed;
r32 GlobalScale = CalculateGlobalScaleFromRootBox(TextboxData->SceneViewBox);
text_properties Properties = {};
Properties.Font = Font_Japanese;
Properties.FontSize = GlobalScale;
Properties.LineHeight = GlobalScale*1.5f;
r32 Padding = 1.5f*GlobalScale;
v2 Offset = V2R32(Padding, Padding);
RenderAnimatedText(Group, Atlas, Properties, Text, CharsRevealed, Box->Rect.Min+Offset, DimOfRange(Box->Rect).x-2*Padding);
}
// sixten(NOTE): This is most likely temporarary and just contains all the data required to render the scene.
struct scene_render_data
{
render_handle BackgroundTexture;
scene_runtime *Runtime;
};
UI_CUSTOM_DRAW_CALLBACK(BuildSceneDrawCallback)
{
scene_render_data *RenderData = (scene_render_data *)Data;
//- sixten: render background
// sixten(TODO, but soon): Currently we add Box->Rect.Min to everything, but that should really be a transform
// on the render group.
v2 RenderDim = DimOfRange(Box->Rect);
range2_r32 Dest = Range2R32(Box->Rect.Min, RenderDim+Box->Rect.Min);
range2_r32 Source = Range2R32(V2R32(0, 0), ConvertV2ToR32(DimFromTexture(RenderData->BackgroundTexture)));
PushTexturedQuad(Group, Dest, Source, Color_White, Color_White, Color_White, Color_White, 0, 0, 0, RenderData->BackgroundTexture);
}
static void BuildScene(scene_runtime *Runtime, render_handle BackgroundTexture, textbox *Textbox)
{
UI_SetNextWidth(UI_Percent(1, 0));
UI_SetNextHeight(UI_Percent(1, 0));
UI_SetNextLayoutAxis(Axis2_Y);
ui_box *Box = UI_MakeBox(0, StrLit("Scene View"));
scene_render_data *Data = PushStruct(UI_FrameArena(), scene_render_data);
Data->BackgroundTexture = BackgroundTexture;
Data->Runtime = Runtime;
UI_EquipBoxCustomDrawCallback(Box, BuildSceneDrawCallback, Data);
UI_Parent(Box)
{
UI_WidthFill UI_Height(UI_Percent(1, 0)) UI_Row() UI_FillPadding UI_Column() UI_FillPadding
{
b32 FoundOffset = false;
s64 Offset = 0;
for(s32 BranchIndex = 0; BranchIndex < Runtime->BranchCount; BranchIndex += 1)
{
branch_case *Branch = &Runtime->Branches[BranchIndex];
if(UI_ButtonF("%S#%i", Branch->Name, BranchIndex).Clicked)
{
Offset = Branch->Offset;
FoundOffset = true;
}
}
if(FoundOffset)
{
Runtime->IP += 1+Offset;
Runtime->BranchCount = 0;
}
}
UI_SetNextWidth(UI_Percent(1, 1));
UI_SetNextHeight(UI_Percent(0.3, 1));
ui_box *TextBox = UI_MakeBox(0, StrLit("Scene Textbox"));
scene_textbox_data *TextboxData = PushStruct(UI_FrameArena(), scene_textbox_data);
TextboxData->Textbox = Textbox;
TextboxData->SceneViewBox = Box;
UI_EquipBoxCustomDrawCallback(TextBox, BuildSceneTextboxDrawCallback, TextboxData);
}
}
static void BuildErrorScreen(scene_runtime *Runtime, vn_input *Input)
{
UI_SetNextLayoutAxis(Axis2_X);
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit("Container")))
{
UI_Padding(UI_Em(3, 1)) UI_Width(UI_Percent(1, 0)) UI_Column() UI_Padding(UI_Em(3, 1))
{
UI_Font(Font_Bold) UI_Size(UI_TextContent(0, 1), UI_TextContent(0, 1)) UI_FontSize(32) UI_LabelF("A runtime error has occurred");
s64 ErrorIndex = 0;
for(scene_runtime_error *Error = Runtime->FirstError; Error != 0; Error = Error->Next, ErrorIndex += 1)
{
UI_Spacer(UI_Em(3, 1));
UI_SetNextCornerRadius(3);
UI_Size(UI_Percent(1, 1), UI_Percent(1, 0)) UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBorder, "%i", ErrorIndex))
UI_Size(UI_TextContent(30, 1), UI_TextContent(30, 1))
{
UI_LabelF("Message: %S", Error->Message);
}
}
UI_Spacer(UI_Em(3, 1));
UI_Size(UI_Percent(1, 1), UI_Em(2, 1)) UI_Row()
UI_Width(UI_TextContent(30, 1)) UI_CornerRadius(4)
{
ui_signal IgnoreSignal = UI_ButtonF("Ignore");
if(IgnoreSignal.Hovering)
{
UI_TooltipLabel(StrLit("Continue running the script, may lead to more errors."), UI_MouseP());
}
if(IgnoreSignal.Clicked)
{
Runtime->FirstError = Runtime->LastError = 0;
ArenaClear(Runtime->ErrorArena);
}
UI_Spacer(UI_Em(1, 1));
ui_signal RestartSignal = UI_ButtonF("Restart");
if(RestartSignal.Hovering)
{
UI_TooltipLabel(StrLit("Restarts the script, may lose progress."), UI_MouseP());
}
if(RestartSignal.Clicked)
{
Runtime->FirstError = Runtime->LastError = 0;
Runtime->IP = 0;
Runtime->CurrentProc = 0;
ArenaClear(Runtime->ErrorArena);
}
UI_Spacer(UI_Em(1, 1));
if(UI_ButtonF("Exit Program").Clicked)
{
Input->ExitRequested = true;
}
}
}
}
}
static void SV_Update(memory_arena *FrameArena, vn_input *Input)
{
scene_view *SceneView = SV_GetState();
textbox *Textbox = &SceneView->Textbox;
scene_runtime *Runtime = &SceneView->Runtime;
platform_event_list *EventList = Input->EventList;
compiled_scene *Compiled = &Runtime->Compiled;
if(Compiled && Compiled->IsValid)
{
b32 PlayerAction = (Platform_KeyPress(EventList, Key_Space)||Platform_KeyPress(EventList, Key_MouseLeft));
if(DLLIsEmpty(Runtime->FirstError))
{
b32 AdvanceOnAwait = (Textbox->CharsRevealed >= Textbox->String.Count) && PlayerAction;
for(;;)
{
scene_runtime_result RunResult = S_Run(Runtime, FrameArena, AdvanceOnAwait);
if(RunResult.ReachedAwait || RunResult.HadError)
{
break;
}
}
}
r32 CharsPerSecond = 15.0f;//35.0f;
Textbox->CharsRevealed += Input->dtForFrame*CharsPerSecond;
Textbox->CharsRevealed = Min(Textbox->CharsRevealed, (r32)Textbox->String.Count);
if(Textbox->CharsRevealed < Textbox->String.Count && PlayerAction)
{
Textbox->CharsRevealed = Textbox->String.Count;
}
//- sixten: apply the textbox actions
for(textbox_action *Action = Runtime->FirstTextboxAction; Action != 0; Action = Action->Next)
{
if(Action->Kind == TextboxActionKind_Set)
{
string ReplaceString = Action->String;
Textbox->String.Count = Min(ReplaceString.Count, Textbox->Capacity);
Copy(Textbox->String.Data, ReplaceString.Data, Textbox->String.Count);
Textbox->CharsRevealed = 0;
}
else if(Action->Kind == TextboxActionKind_Append)
{
string Addend = Action->String;
Textbox->CharsRevealed = Textbox->String.Count;
s64 NewCount = Min(Textbox->String.Count+Addend.Count, Textbox->Capacity-1);
Copy(Textbox->String.Data+Textbox->String.Count, Action->String.Data, NewCount-Textbox->String.Count);
Textbox->String.Count = NewCount;
}
else
{
InvalidCodepath;
}
}
Runtime->FirstTextboxAction = Runtime->LastTextboxAction = 0;
}
}
static void SV_BuildSceneView(vn_input *Input)
{
scene_view *SceneView = SV_GetState();
scene_runtime_result LastRun = SceneView->Runtime.LastResult;
if(LastRun.HadError)
{
BuildErrorScreen(&SceneView->Runtime, Input);
}
else if(SceneView->Runtime.Compiled.IsValid)
{
BuildScene(&SceneView->Runtime, SceneView->BackgroundTexture, &SceneView->Textbox);
}
else
{
UI_LabelF("Invalid source");
}
}

View File

@ -0,0 +1,28 @@
/* date = August 14th 2023 5:00 pm */
#ifndef VN_SCENE_VIEW_H
#define VN_SCENE_VIEW_H
struct textbox
{
string String;
s64 Capacity;
r32 CharsRevealed;
};
struct scene_view
{
memory_arena *SceneArena;
scene_runtime Runtime;
textbox Textbox;
render_handle BackgroundTexture;
};
static void SV_SetState(scene_view *View);
static scene_view *SV_GetState();
static void SV_SetCurrentSource(compiled_scene *Compiled);
static void SV_Init(scene_view *View, memory_arena *TextboxArena);
static void SV_BuildSceneView(vn_input *Input);
#endif //VN_SCENE_VIEW_H

View File

@ -26,8 +26,10 @@ enum
TextActionFlag_Delete = (1<<2),
TextActionFlag_ZeroDeltaWithSelection = (1<<3),
TextActionFlag_DeltaPicksSelectionSide = (1<<4),
TextActionFlag_OperateOnLine = (1<<5),
TextActionFlag_StopOnNewline = (1<<6),
TextActionFlag_Copy = (1<<5),
TextActionFlag_Paste = (1<<6),
TextActionFlag_OperateOnLine = (1<<7),
TextActionFlag_StopOnNewline = (1<<8),
TextActionFlag_EmptyLineScan = TextActionFlag_WordScan,
};
@ -96,6 +98,21 @@ static text_action SingleLineTextActionFromEvent(platform_event *Event)
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
} break;
case Key_C: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Copy;
} break;
case Key_V: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Paste;
} break;
case Key_X: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Copy|TextActionFlag_Delete;
} break;
default: {} break;
}
}
@ -171,6 +188,21 @@ static text_action MultiLineTextActionFromEvent(platform_event *Event)
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
} break;
case Key_C: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Copy;
} break;
case Key_V: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Paste;
} break;
case Key_X: if(Event->Modifiers & PlatformModifier_Ctrl)
{
Action.Flags |= TextActionFlag_Copy|TextActionFlag_Delete;
} break;
default: {} break;
}
}
@ -308,6 +340,25 @@ static s64 WordScan(string String, s64 Index, s64 Delta)
return(Result);
}
static b32 StringIsWhitespace(string String)
{
b32 Result = true;
u8 *StringBegin = String.Data;
u8 *StringEnd = StringBegin+String.Count;
for(u8 *Char = StringBegin; Char < StringEnd; Char += 1)
{
if(!IsWhitespace(*Char) && *Char != '\0')
{
Result = false;
break;
}
}
return(Result);
}
static text_op TextOpFromAction(memory_arena *Arena, string String,
text_edit_state *State, text_action *Action,
range1_s64_array *Lines = 0, s64 LastColumnIndex = 0)
@ -319,17 +370,14 @@ static text_op TextOpFromAction(memory_arena *Arena, string String,
Op.Range = Range1S64(0, 0);
Op.ReplaceString = StrLit("");
//- sixten: navtigation
s64 Delta = 0;
if(Action->Flags & TextActionFlag_OperateOnLine)
{
if(Action->Flags & TextActionFlag_EmptyLineScan)
{
}
else
{
//- sixten: determine what line we are on.
s64 LineIndex = 0;
s64 ColumnIndex = 0;
{
u8 *TextBegin = String.Data;
u8 *TextEnd = TextBegin + State->Cursor;
u8 *Char = TextBegin;
@ -342,24 +390,86 @@ static text_op TextOpFromAction(memory_arena *Arena, string String,
ColumnIndex = 0;
}
}
u64 ColumnOffset = Max(LastColumnIndex - ColumnIndex, 0LLU);
}
//- sixten: check that the line we are trying to access is inbouse, else just go to the start or end of the text.
if(InRange(Range1S64(0, Lines->Count), LineIndex + Action->Delta))
s64 LineDelta = Action->Delta;
if(Action->Flags & TextActionFlag_EmptyLineScan)
{
Delta = Lines->Ranges[LineIndex+Action->Delta].Min - Lines->Ranges[LineIndex].Min + ColumnOffset;
if(!InRange(Lines->Ranges[LineIndex+Action->Delta], State->Cursor + Delta))
// sixten: if the line we start on is blank, we want to make sure that there has been a text containing non-whitespace before stopping.
b32 IgnoreFirstWhitespace = StringIsWhitespace(Substring(String, Lines->Ranges[LineIndex]));
for(;0 <= LineIndex && LineIndex < Lines->Count; LineIndex += Action->Delta)
{
Delta = Lines->Ranges[LineIndex+Action->Delta].Max - State->Cursor - 1;
string Line = Substring(String, Lines->Ranges[LineIndex+Action->Delta]);
if(StringIsWhitespace(Line))
{
if(!IgnoreFirstWhitespace)
{
break;
}
}
else
{
s64 TempDelta = (Action->Delta > 0)?S64_Max:S64_Min;
IgnoreFirstWhitespace = false;
}
#if 0
u8 *LineBegin = Line.Data;
u8 *LineEnd = LineBegin+Line.Count;
u8 *Char = (Action->Delta > 0)?LineBegin:LineEnd;
if(Action->Delta > 0)
{
for(;Char <= LineEnd; Char += 1)
{
if(Char == LineEnd)
{
goto FoundLine;
}
if(!IsWhitespace(*Char))
{
break;
}
}
}
else if(Action->Delta < 0)
{
for(;LineBegin <= Char; Char -= 1)
{
if(!IsWhitespace(*Char))
{
break;
}
if(Char == LineBegin)
{
goto FoundLine;
}
}
}
#endif
}
}
u64 ColumnOffset = Max(LastColumnIndex - ColumnIndex, 0LLU);
//- sixten: check that the line we are trying to access is inbounds, else just go to the start or end of the text.
if(InRange(Range1S64(0, Lines->Count), LineIndex + LineDelta))
{
Delta = Lines->Ranges[LineIndex+LineDelta].Min - Lines->Ranges[LineIndex].Min + ColumnOffset;
if(!InRange(Lines->Ranges[LineIndex+LineDelta], State->Cursor + Delta))
{
Delta = Lines->Ranges[LineIndex+LineDelta].Max - State->Cursor - 1;
}
}
else
{
s64 TempDelta = (LineDelta > 0)?S64_Max:S64_Min;
Delta = CodepointScan(String, State->Cursor, TempDelta, Action->Flags & TextActionFlag_StopOnNewline);
}
}
}
else
{
if(Action->Flags & TextActionFlag_WordScan)
@ -391,9 +501,15 @@ static text_op TextOpFromAction(memory_arena *Arena, string String,
Op.NewCursor = Minimum(State->Cursor, State->Mark);
}
}
else
{
Op.NewCursor = State->Cursor + Delta;
//- sixten: post-navigation
if(Action->Flags & TextActionFlag_Copy)
{
string CopyString = Substring(String, Range1S64(Op.NewCursor, Op.NewMark));
Platform.SetClipboard(CopyString);
}
if(Action->Flags & TextActionFlag_Delete)
@ -417,6 +533,12 @@ static text_op TextOpFromAction(memory_arena *Arena, string String,
Op.Range = Range1S64(State->Cursor, State->Mark);
}
}
else if(Action->Flags & TextActionFlag_Paste)
{
Op.ReplaceString = Platform.GetClipboard(Arena);
Op.Range = Range1S64(State->Cursor, State->Cursor);
Op.NewCursor += Op.ReplaceString.Count;
}
if(!(Action->Flags & TextActionFlag_KeepMark))
{

View File

@ -1,6 +1,6 @@
////////////////////////////////
//~ sixten: Token Type Functions
static string T_StringFromToken(string Text, token Token)
{
string Result = Substring(Text, Token.Range);
@ -60,6 +60,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, toke
u8 *TextStart = Text.Data;
u8 *TextEnd = TextStart + Text.Count;
u8 *Byte = TextStart;
s64 Line = 0;
//- sixten: scan string & produce tokens
for(;Byte < TextEnd;)
@ -91,6 +92,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, toke
TokenKind = TokenKind_Newline;
TokenStart = Byte;
TokenEnd = Byte + 1;
Line += 1;
Byte += 1;
}
@ -284,7 +286,7 @@ static tokenize_result T_TokenizeFromText(memory_arena *Arena, string Text, toke
//- sixten: push token
if(TokenKind != 0 && (!ExcludeFilter || (ExcludeFilter && !ExcludeFilter(TokenKind))) && TokenStart != 0 && TokenEnd > TokenStart)
{
token Token = {TokenKind, {TokenStart - TextStart, TokenEnd - TextStart}};
token Token = {TokenKind, {TokenStart - TextStart, TokenEnd - TextStart}, Line};
T_TokenChunkListPush(Scratch.Arena, &Tokens, Token, 4096);
}

View File

@ -70,21 +70,11 @@ enum token_kind
typedef b32 tokenizer_filter_function(token_kind Kind);
inline b32 T_IsComment(token_kind Kind) { return(Kind == TokenKind_Comment); }
inline b32 T_IsWhitespace(token_kind Kind) { return(Kind == TokenKind_Whitespace ||
Kind == TokenKind_Newline); }
inline b32 T_IsIrregular(token_kind Kind) { return(T_IsComment(Kind) ||
T_IsWhitespace(Kind)); }
inline b32 T_IsRegular(token_kind Kind) { return(!T_IsIrregular(Kind)); }
inline b32 T_IsInvalid(token_kind Kind) { return(Kind == TokenKind_None ||
Kind == TokenKind_BrokenComment ||
Kind == TokenKind_BrokenStringLiteral ||
Kind == TokenKind_BadCharacter); }
struct token
{
token_kind Kind;
range1_s64 Range;
s64 Line;
};
struct token_chunk_node
@ -141,6 +131,19 @@ struct tokenize_result
tokenizer_message_list Messages;
};
////////////////////////////////
//~ sixten: Token Filter Helper Functions
inline b32 T_IsComment(token_kind Kind) { return(Kind == TokenKind_Comment); }
inline b32 T_IsWhitespace(token_kind Kind) { return(Kind == TokenKind_Whitespace ||
Kind == TokenKind_Newline); }
inline b32 T_IsIrregular(token_kind Kind) { return(T_IsComment(Kind) ||
T_IsWhitespace(Kind)); }
inline b32 T_IsRegular(token_kind Kind) { return(!T_IsIrregular(Kind)); }
inline b32 T_IsInvalid(token_kind Kind) { return(Kind == TokenKind_None ||
Kind == TokenKind_BrokenComment ||
Kind == TokenKind_BrokenStringLiteral ||
Kind == TokenKind_BadCharacter); }
////////////////////////////////
//~ sixten: Token Type Functions
static string T_StringFromToken(string Text, token Token);

View File

@ -60,7 +60,13 @@ inline platform_event_list *UI_EventList(void)
return(UI->EventList);
}
inline v2 UI_MouseP(void)
inline memory_arena *UI_FrameArena(void)
{
ui *UI = UI_GetState();
return(UI->FrameArena);
}
inline v2_r32 UI_MouseP(void)
{
ui *UI = UI_GetState();
return(UI->MouseP);
@ -322,6 +328,17 @@ inline void UI_SetNextHot(ui_key Key)
}
}
static void UI_EquipBoxText(ui_box *Box, string String)
{
Box->String = PushString(UI_FrameArena(), String);
}
static void UI_EquipBoxCustomDrawCallback(ui_box *Box, ui_custom_draw_callback *DrawCallback, void *Data)
{
Box->DrawCallback = DrawCallback;
Box->DrawCallbackData = Data;
}
// sixten(NOTE): ClippingRect = Intersection(TrueClippingRect, Parent->Rect);
static b32 UI_ChildrenContainsP(ui_box *Parent, v2 P, range2_r32 Clip)
{
@ -473,6 +490,11 @@ static ui_signal UI_SignalFromBox(ui_box *Box)
}
}
if(AreEqual(UI->Hot, Box->Key))
{
Platform.SetCursor(Box->HoverCursor);
}
Signal.MouseP = UI->MouseP;
Signal.DragDelta = UI->MouseP - UI->DragStartP;
Signal.Box = Box;
@ -784,8 +806,8 @@ static void UI_LayoutBox(ui_box *Box)
{
if(Child->Flags & UI_BoxFlag_AnimatePosition)
{
Child->ApproachingRelativeP.x = AnimationCurve_AnimateValueF(Child->ComputedRelativeP.x, Child->ComputedRelativeP.x, 0.1, "Box P.X %p", Child);
Child->ApproachingRelativeP.y = AnimationCurve_AnimateValueF(Child->ComputedRelativeP.y, Child->ComputedRelativeP.y, 0.1, "Box P.Y %p", Child);
Child->ApproachingRelativeP.x = AC_AnimateValueF(Child->ComputedRelativeP.x, Child->ComputedRelativeP.x, 0.1, "Box P.X %p", Child);
Child->ApproachingRelativeP.y = AC_AnimateValueF(Child->ComputedRelativeP.y, Child->ComputedRelativeP.y, 0.1, "Box P.Y %p", Child);
Child->Rect.Min = Box->Rect.Min + Child->ApproachingRelativeP + Box->Offset;
Child->Rect.Max = Child->Rect.Min + Child->ComputedDim;
@ -824,6 +846,7 @@ static void UI_BeginBuild(v2 ScreenDim)
UI_PushFontSize(15.0f);
UI_PushOffsetX(0);
UI_PushOffsetY(0);
UI_PushHoverCursor(PlatformCursor_Arrow);
UI->RootNode = UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit("UI Root Node"));
UI->Stacks.ParentStack[0] = UI->RootNode;
@ -862,6 +885,7 @@ static void UI_EndBuild(void)
UI_PopFontSize();
UI_PopOffsetX();
UI_PopOffsetY();
UI_PopHoverCursor();
UI_LayoutBox(UI->RootNode);
}

View File

@ -90,6 +90,7 @@ struct ui_box
font_id Font;
r32 FontSize;
v2 Offset;
platform_cursor HoverCursor;
ui_custom_draw_callback *DrawCallback;
void *DrawCallbackData;
@ -159,11 +160,10 @@ struct ui
//- sixten: State management
inline void UI_SetState(ui *UI);
inline ui *UI_GetState(void);
inline ui_key UI_GetHot(void);
inline ui_key UI_GetActive(void);
inline platform_event_list *UI_EventList(void);
inline memory_arena *UI_FrameArena(void);
inline v2 UI_MouseP(void);
inline glyph_atlas *UI_GlyphAtlas(void);
@ -190,6 +190,8 @@ static ui_box *UI_GetBoxByKey(ui *UI, ui_key Key);
//- sixten: Box creation
static ui_box *UI_MakeBox(ui_box_flags Flags, string String);
static ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...);
static void UI_EquipBoxText(ui_box *Box, string String);
static void UI_EquipBoxCustomDrawCallback(ui_box *Box, ui_custom_draw_callback *DrawCallback, void *Data);
//- sixten: User interaction
static ui_signal UI_SignalFromBox(ui_box *Box);

View File

@ -16,6 +16,7 @@ UIStyleStacks:
{ FontSize `r32` `FontSize` }
{ OffsetX `r32` `Offset.x` }
{ OffsetY `r32` `Offset.y` }
{ HoverCursor `platform_cursor` `HoverCursor` }
}
@table_gen

View File

@ -86,9 +86,9 @@ static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...)
return(Box);
}
static void UI_Spacer(ui_size Size)
static ui_box *UI_Spacer(ui_size Size)
{
UI_NamedSpacer(Size, StrLit(""));
return(UI_NamedSpacer(Size, StrLit("")));
}
//- sixten: Scrollable regions
@ -119,6 +119,7 @@ static ui_box *UI_LabelF(char *Format, ...)
static ui_signal UI_Button(string String)
{
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
UI_BoxFlag_DrawBackground|
UI_BoxFlag_DrawBorder|
@ -134,6 +135,8 @@ static ui_signal UI_ButtonF(char *Format, ...)
{
temporary_memory Scratch = GetScratch(0, 0);
UI_SetNextHoverCursor(PlatformCursor_Hand);
va_list Arguments;
va_start(Arguments, Format);
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
@ -157,11 +160,11 @@ static ui_signal UI_Checkbox(b32 *Checked, string String)
{
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
UI_Parent(ContainerBox)
{
r32 OpacityTransition = AnimationCurve_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
r32 OpacityTransition = AC_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
v4 TextColor = UI_TopTextColor();
TextColor.a = OpacityTransition;
@ -173,10 +176,6 @@ static ui_signal UI_Checkbox(b32 *Checked, string String)
}
ui_signal Signal = UI_SignalFromBox(ContainerBox);
if(Signal.Hovering)
{
Platform.SetCursor(PlatformCursor_Hand);
}
if(Signal.Pressed)
{
@ -223,41 +222,41 @@ static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
return(Signal);
}
static void UI_ScrollBegin(r32 *X, r32 *Y, string Name)
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
{
u32 Flags = 0;
b32 AllowOnX = (X != 0);
b32 AllowOnY = (Y != 0);
UI_RowBegin(UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder, Name);
UI_RowBegin(Flags, Name);
{
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
UI_ColumnBegin();
{
u32 ScrollFlags = 0;
if(AllowOnX)
{
Flags |= UI_BoxFlag_OverflowX;
ScrollFlags |= UI_BoxFlag_OverflowX;
UI_SetNextOffsetX(-(*X));
}
if(AllowOnY)
{
Flags |= UI_BoxFlag_OverflowY;
ScrollFlags |= UI_BoxFlag_OverflowY;
UI_SetNextOffsetY(-(*Y));
}
UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0),
AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0));
ui_box *ScrollableBox = UI_MakeBox(Flags, StrLit("Scrollable Box"));
ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box"));
UI_PushParent(ScrollableBox);
}
}
}
static void UI_ScrollEnd(r32 *X, r32 *Y)
static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
{
b32 AllowOnX = (X != 0);
b32 AllowOnY = (Y != 0);
@ -294,7 +293,7 @@ static void UI_ScrollEnd(r32 *X, r32 *Y)
r32 StartOffset = UI_GetDragR32();
r32 EndOffset = StartOffset + Signal.DragDelta.x/ScrollScale;
AnimationCurve_AnimateValueDirect(EndOffset, 0.2, X);
AC_AnimateValueDirect(EndOffset, 0.2, X);
}
}
}
@ -332,7 +331,7 @@ static void UI_ScrollEnd(r32 *X, r32 *Y)
r32 StartOffset = UI_GetDragR32();
r32 EndOffset = StartOffset + Signal.DragDelta.y/ScrollScale;
AnimationCurve_AnimateValueDirect(EndOffset, 0.2, Y);
AC_AnimateValueDirect(EndOffset, 0.2, Y);
}
}
}
@ -349,3 +348,61 @@ static void UI_ScrollEnd(r32 *X, r32 *Y)
}
UI_RowEnd();
}
static r32 UI_Slider(r32 Value, range1_r32 Range)
{
r32 Result = Value;
UI_Column()
{
UI_Spacer(UI_Em(1, 1));
UI_Height(UI_Em(1, 1)) UI_Row()
{
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())*(Value-Range.Min)/DimOfRange(Range));
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(Value);
}
r32 StartT = UI_GetDragR32();
r32 EndT = StartT + Signal.DragDelta.x/(DimOfRange(Container->Rect).x-UI_TopFontSize());
Result = EndT*DimOfRange(Range)+Range.Min;
}
}
}
}
return(Result);
}
static void UI_TooltipLabel(string Label, v2 P)
{
UI_Tooltip
{
UI_SetNextSize(UI_TextContent(7, 1), UI_TextContent(3, 1));
UI_CornerRadius(4);
UI_SetNextFixedP(P+V2R32(15.0f, 0.0f));
UI_MakeBox(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawText |
UI_BoxFlag_DrawDropShadow |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY,
Label);
}
}

View File

@ -19,6 +19,9 @@ inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size);
#define UI_AxisSize(Axis, Size) DeferLoop(UI_PushAxisSize(Axis, Size), UI_PopAxisSize(Axis))
#define UI_WidthFill UI_Width(UI_Percent(1, 0))
#define UI_HeightFill UI_Height(UI_Percent(1, 0))
#define UI_Size(Width, Height) UI_Width(Width) UI_Height(Height)
#define UI_PushSize(Width, Height) UI_PushWidth(Width); UI_PushHeight(Height)
#define UI_PopSize() UI_PopWidth(); UI_PopHeight()
@ -30,7 +33,7 @@ inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size);
#define UI_SetNextOffset(x, y) UI_SetNextOffsetX(x); UI_SetNextOffsetY(y)
#define UI_FixedP(Value) UI_FixedX(Value.x) UI_FixedY(Value.y)
#define UI_SetNextFixedP(Value) UI_SetNextFixedX(Value.x); UI_SetNextFixedY(Value.y)
#define UI_SetNextFixedP(Value) UI_SetNextFixedX((Value).x); UI_SetNextFixedY((Value).y)
//- sixten: Spacing
static ui_box *UI_NamedSpacer(ui_size Size, string String);
@ -38,9 +41,11 @@ static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...);
#define UI_Padding(Size) DeferLoop(UI_Spacer(Size), UI_Spacer(Size))
#define UI_FillPadding UI_Padding(UI_Percent(1, 0))
//- sixten: Scrollable regions
static void UI_ScrollBegin(r32 *X, r32 *Y, string Name = StrLit("Scrollable Region Container"));
static void UI_ScrollEnd(r32 *X, r32 *Y, string Name);
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags=UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder, string Name = StrLit("Scrollable Region Container"));
static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags=UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder, string Name = StrLit("Scrollable Region Container"));
#define UI_Scroll(...) DeferLoop(UI_ScrollBegin(__VA_ARGS__), UI_ScrollEnd(__VA_ARGS__))
@ -53,4 +58,8 @@ static ui_signal UI_ButtonF(char *Format, ...);
static ui_signal UI_Checkbox(b32 *Checked, string String);
static r32 UI_Slider(r32 Value, range1_r32 Range);
static void UI_TooltipLabel(string Label, v2 P);
#endif //VN_UI_UTILS_H

View File

@ -6,27 +6,40 @@
//- sixten: State management
per_thread workspace *ThreadLocal_Workspace;
static void Workspace_SetState(workspace *Workspace)
static workspace_keybind Workspace_Keybinds[] =
{
{Key_P, PlatformModifier_Ctrl, W_Command_SplitPanelHorizontal},
{Key_L, PlatformModifier_Ctrl, W_Command_SplitPanelVertical},
{Key_O, PlatformModifier_Ctrl, W_Command_OpenView, W_View_TextEditor},
{Key_T, PlatformModifier_Ctrl, W_Command_Test},
#if VN_INTERNAL
{Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, W_Command_ToggleRenderUIDebugRects},
#endif
};
static void W_SetState(workspace *Workspace)
{
ThreadLocal_Workspace = Workspace;
}
static workspace *Workspace_GetState(void)
static workspace *W_GetState(void)
{
return(ThreadLocal_Workspace);
}
static memory_arena *Workspace_FrameArena(void)
static memory_arena *W_FrameArena(void)
{
return(ThreadLocal_Workspace->FrameArena);
}
//- sixten: Commands
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
static void W_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
{
workspace_command *Result = 0;
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
if(Workspace->FirstFreeCommand)
{
@ -44,9 +57,9 @@ static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument = 0)
DLLInsertLast(Workspace->FirstCommand, Workspace->LastCommand, Result);
}
static void Workspace_ProcessCommands(void)
static void W_ProcessCommands(void)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
workspace_command *Command = Workspace->FirstCommand;
while(Command != 0)
@ -62,9 +75,9 @@ static void Workspace_ProcessCommands(void)
}
}
static void Workspace_ProcessKeyBinds()
static void W_ProcessKeyBinds()
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
platform_event_list *EventList = Workspace->EventList;
@ -75,13 +88,13 @@ static void Workspace_ProcessKeyBinds()
if(Event->Type == PlatformEvent_Press)
{
for(s32 KeybindIndex = 0;
KeybindIndex < Workspace->KeybindCount;
KeybindIndex < ArrayCount(Workspace_Keybinds);
++KeybindIndex)
{
workspace_keybind *Keybind = Workspace->Keybinds + KeybindIndex;
workspace_keybind *Keybind = Workspace_Keybinds + KeybindIndex;
if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers))
{
Workspace_IssueCommand(Keybind->Command, Keybind->Argument);
W_IssueCommand(Keybind->Command, Keybind->Argument);
}
}
}
@ -90,9 +103,9 @@ static void Workspace_ProcessKeyBinds()
//- sixten: Builder code
static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu)
static ui_signal W_BuildToolbarButton(char *Text, toolbar_menu Menu)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
UI_SetNextWidth(UI_TextContent(20, 1));
UI_SetNextHeight(UI_Pixels(30, 1));
@ -134,11 +147,12 @@ static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu)
return(Signal);
}
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
static ui_signal W_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
{
temporary_memory Scratch = GetScratch(0, 0);
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawBorder |
@ -163,9 +177,9 @@ static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
return(Signal);
}
static void Workspace_BuildToolbar()
static void W_BuildToolbar()
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHeight(UI_Pixels(30, 1));
@ -176,9 +190,9 @@ static void Workspace_BuildToolbar()
UI_Parent(ToolbarBox)
{
Workspace_BuildToolbarButton("Panel", ToolbarMenu_Panel);
Workspace_BuildToolbarButton("View", ToolbarMenu_View);
Workspace_BuildToolbarButton("Window", ToolbarMenu_Window);
W_BuildToolbarButton("Panel", ToolbarMenu_Panel);
W_BuildToolbarButton("View", ToolbarMenu_View);
W_BuildToolbarButton("Window", ToolbarMenu_Window);
}
if(Workspace->Menu != ToolbarMenu_None)
@ -206,14 +220,14 @@ static void Workspace_BuildToolbar()
{
if(Workspace->Menu == ToolbarMenu_Panel)
{
if(Workspace_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
if(W_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
{
Workspace_IssueCommand(Workspace_Command_SplitPanelHorizontal);
W_IssueCommand(W_Command_SplitPanelHorizontal);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
if(W_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
{
Workspace_IssueCommand(Workspace_Command_SplitPanelVertical);
W_IssueCommand(W_Command_SplitPanelVertical);
Workspace->Menu = ToolbarMenu_None;
}
}
@ -225,32 +239,37 @@ static void Workspace_BuildToolbar()
// commmands instead. (since we want all things that deals with major state changes to occur at a fixed
// point in our programs execution)
if(Workspace_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked)
if(W_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_Startup, CurrentPanel);
W_CreateNewView(W_View_Startup, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_Pencil, "Script Editor", "Ctrl + O").Clicked)
if(W_BuildMenuItem(FontIcon_Pencil, "Script Editor", "Ctrl + O").Clicked)
{
Workspace_CreateNewView(Workspace_View_TextEditor, CurrentPanel);
W_CreateNewView(W_View_TextEditor, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
if(W_BuildMenuItem(FontIcon_Terminal, "Scene View", "").Clicked)
{
Workspace_CreateNewView(Workspace_View_Settings, CurrentPanel);
W_CreateNewView(W_View_SceneView, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
if(W_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
{
W_CreateNewView(W_View_Settings, CurrentPanel);
Workspace->Menu = ToolbarMenu_None;
}
}
else if(Workspace->Menu == ToolbarMenu_Window)
{
if(Workspace_BuildMenuItem(FontIcon_WindowMaximize, "ToggleFullscreen", "Alt + Enter").Clicked)
if(W_BuildMenuItem(FontIcon_WindowMaximize, "ToggleFullscreen", "Alt + Enter").Clicked)
{
Platform.ToggleFullscreen();
Workspace->Menu = ToolbarMenu_None;
}
}
AnimationCurve_AnimateValueDirect(1, 0.1, &Workspace->MenuTransition);
AC_AnimateValueDirect(1, 0.1, &Workspace->MenuTransition);
}
// sixten: Unless the mouse press was captured, we close the menu.
@ -262,11 +281,11 @@ static void Workspace_BuildToolbar()
}
//- sixten: Panels
static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent)
static workspace_panel *W_CreateNewPanel(workspace_panel *Parent)
{
workspace_panel *Result = 0;
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
if(DLLIsEmpty(Workspace->FirstFreePanel))
{
@ -285,9 +304,9 @@ static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent)
return(Result);
}
static void Workspace_DeletePanel(workspace_panel *Panel)
static void W_DeletePanel(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
if(Workspace->CurrentPanel == Panel)
{
@ -298,9 +317,9 @@ static void Workspace_DeletePanel(workspace_panel *Panel)
DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel);
}
static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
static void W_SplitPanel(workspace_panel *Panel, axis2 Axis)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
if(Panel)
{
@ -308,14 +327,14 @@ static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
if(Parent && (Parent->SplitAxis == Axis))
{
workspace_panel *NewPanel = Workspace_CreateNewPanel(Parent);
workspace_panel *NewPanel = W_CreateNewPanel(Parent);
NewPanel->PercentOfParent = Panel->PercentOfParent = Panel->PercentOfParent * 0.5;
DLLInsert_NP(Parent->First, Parent->Last, Panel, NewPanel, Next, Prev);
}
else
{
workspace_panel *NewPanel = Workspace_CreateNewPanel(Panel);
workspace_panel *NewPanel = W_CreateNewPanel(Panel);
NewPanel->FirstView = Panel->FirstView;
NewPanel->LastView = Panel->LastView;
@ -331,7 +350,7 @@ static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
NewPanel = Workspace_CreateNewPanel(Panel);
NewPanel = W_CreateNewPanel(Panel);
NewPanel->PercentOfParent = 0.5;
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
@ -348,36 +367,36 @@ static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis)
}
}
inline void Workspace_BeginDrag(workspace_drag_payload *Payload)
inline void W_BeginDrag(workspace_drag_payload *Payload)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
// sixten(TODO): Right now, if you spam-click a draggable item, you can trigger this
// assertion. I don't know what I want to do about this at the moment, but I'm sure
// future me will have a soulution at hand. ^.^
Assert(Workspace->DragPayloadState == Workspace_DragPayload_Inactive);
Assert(Workspace->DragPayloadState == W_DragPayload_Inactive);
Workspace->DragPayload = *Payload;
Workspace->DragPayloadState = Workspace_DragPayload_Active;
Workspace->DragPayloadState = W_DragPayload_Active;
}
inline b32 Workspace_GetDragPayload(workspace_drag_payload *Dest)
inline b32 W_GetDragPayload(workspace_drag_payload *Dest)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
b32 Result = (Workspace->DragPayloadState != Workspace_DragPayload_Inactive);
b32 Result = (Workspace->DragPayloadState != W_DragPayload_Inactive);
*Dest = Workspace->DragPayload;
return(Result);
}
static void Workspace_BuildTabItem(workspace_panel *Panel, workspace_view *View)
static void W_BuildTabItem(workspace_panel *Panel, workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
b32 ViewIsCurrent = (Panel->CurrentView == View);
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
string Name = Workspace_GetViewName(View);
string Name = W_GetViewName(View);
v4 BackgroundColor = ViewIsCurrent ? (PanelIsCurrent ? Theme_HighlightBorderColor : Theme_BorderColor) : ColorFromHex(0x353738FF);
@ -405,21 +424,16 @@ static void Workspace_BuildTabItem(workspace_panel *Panel, workspace_view *View)
{
UI_SetNextFont(Font_Icons);
UI_SetNextSize(UI_TextContent(1, 1), UI_Percent(1, 1));
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%U", FontIcon_Cancel);
CloseBox->TextColor = LinearBlend(TabBox->BackgroundColor, Color_Black,
0.3 - CloseBox->HotTransition*0.8);
CloseBox->TextColor = LinearBlend(TabBox->BackgroundColor, Color_Black, 0.3 - CloseBox->HotTransition*0.8);
ui_signal Signal = UI_SignalFromBox(CloseBox);
if(Signal.Clicked)
{
DLLRemove(Panel->FirstView, Panel->LastView, View);
if(ViewIsCurrent)
{
Panel->CurrentView = Panel->FirstView;
}
// sixten(TODO): Issue a "DeleteView" command.
W_IssueCommand(W_Command_CloseView, PointerToU64(View));
}
}
}
@ -440,14 +454,14 @@ static void Workspace_BuildTabItem(workspace_panel *Panel, workspace_view *View)
Payload.View = View;
Payload.Key = TabBox->Key;
Workspace_BeginDrag(&Payload);
W_BeginDrag(&Payload);
}
}
}
static void Workspace_BuildPanelHeader(workspace_panel *Panel)
static void W_BuildPanelHeader(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
@ -460,7 +474,7 @@ static void Workspace_BuildPanelHeader(workspace_panel *Panel)
View != 0;
View = View->Next)
{
Workspace_BuildTabItem(Panel, View);
W_BuildTabItem(Panel, View);
}
// sixten: Panel Close Button
@ -473,6 +487,7 @@ static void Workspace_BuildPanelHeader(workspace_panel *Panel)
UI_SetNextBorderColor(ColorFromHex(0xA6514288));
UI_SetNextBackgroundColor(ColorFromHex(0xC24630BB));
UI_SetNextCornerRadius(4);
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_HotAnimation |
UI_BoxFlag_ActiveAnimation |
@ -485,7 +500,7 @@ static void Workspace_BuildPanelHeader(workspace_panel *Panel)
ui_signal Signal = UI_SignalFromBox(CloseBox);
if(Signal.Clicked)
{
Workspace_IssueCommand(Workspace_Command_ClosePanel, PointerToU64(Panel));
W_IssueCommand(W_Command_ClosePanel, PointerToU64(Panel));
}
}
@ -493,9 +508,9 @@ static void Workspace_BuildPanelHeader(workspace_panel *Panel)
}
}
static void Workspace_BuildPanel(workspace_panel *Panel)
static void W_BuildPanel(workspace_panel *Panel)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
// sixten: Fill remaining percent of parent.
workspace_panel *Parent = Panel->Parent;
@ -520,7 +535,7 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
{
if(DLLIsEmpty(Panel->First))
{
Workspace_BuildPanelHeader(Panel);
W_BuildPanelHeader(Panel);
// sixten: Main body
{
@ -528,7 +543,7 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
UI_PushSize(UI_Percent(1, 0), UI_Percent(1, 0));
r32 HighlightTransition = AnimationCurve_AnimateValueF(PanelIsCurrent, 0, 0.25, "Workspace Panel Highlight %p", Panel);
r32 HighlightTransition = AC_AnimateValueF(PanelIsCurrent, 0, 0.25, "Workspace Panel Highlight %p", Panel);
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, HighlightTransition));
UI_SetNextBackgroundColor(Theme_BackgroundColor);
@ -562,7 +577,7 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
{
ui_key CurrentActive = UI_GetActive();
Workspace_BuildView(Panel->CurrentView);
W_BuildView(Panel->CurrentView);
if(!AreEqual(CurrentActive, UI_GetActive()))
{
@ -573,19 +588,19 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
// sixten: Draw dragged view overlay.
{
workspace_drag_payload Payload;
b32 DragActive = Workspace_GetDragPayload(&Payload);
b32 DragActive = W_GetDragPayload(&Payload);
b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) &&
InRange(BodyBox->Rect, UI_GetState()->MouseP));
if(OverlayActive && Workspace->DragPayloadState == Workspace_DragPayload_Released)
if(OverlayActive && Workspace->DragPayloadState == W_DragPayload_Released)
{
// sixten(NOTE): I need to be careful here. If something else sees that a payload has
// been released and tries to act upon on it may lead to unwanted behaviour. Just
// keep that in mind.
// sixten(NOTE): On that previous note, I could just:
Workspace->DragPayloadState = Workspace_DragPayload_Inactive;
Workspace->DragPayloadState = W_DragPayload_Inactive;
// sixten(TODO): Pull out the code below into separate functions.
@ -618,7 +633,7 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
}
}
r32 OverlayTransition = AnimationCurve_AnimateValueF(OverlayActive, 0, 0.25, "Panel Drag Overlay %p", Panel);
r32 OverlayTransition = AC_AnimateValueF(OverlayActive, 0, 0.25, "Panel Drag Overlay %p", Panel);
v4 OverlayColor = LinearBlend(Color_Grey, Theme_HighlightBorderColor, 0.75);
OverlayColor.a = 0.5*OverlayTransition;
@ -670,7 +685,7 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
{
UI_SetNextAxisSize(Panel->SplitAxis, UI_Percent(Child->PercentOfParent*SizeScalar, 0));
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
Workspace_BuildPanel(Child);
W_BuildPanel(Child);
// sixten: Create drag area
if(Child->Next)
@ -708,88 +723,68 @@ static void Workspace_BuildPanel(workspace_panel *Panel)
}
}
static void Workspace_BuildDragPayload()
static void W_BuildDragPayload()
{
workspace *Workspace = Workspace_GetState();
vn_input *Input = Workspace->Input;
workspace *Workspace = W_GetState();
workspace_drag_payload Payload;
if(Workspace_GetDragPayload(&Payload))
if(W_GetDragPayload(&Payload))
{
if(Workspace->DragPayloadState == Workspace_DragPayload_Released)
if(Workspace->DragPayloadState == W_DragPayload_Released)
{
Workspace->DragPayloadState = Workspace_DragPayload_Inactive;
Workspace->DragPayloadState = W_DragPayload_Inactive;
}
if(AreEqual(Payload.Key, UI_GetActive()))
{
workspace_view *DraggedView = Payload.View;
UI_Tooltip
{
UI_SetNextWidth(UI_TextContent(5, 1));
UI_SetNextHeight(UI_TextContent(5, 1));
UI_SetNextFixedX(Input->MouseP.x + 10);
UI_SetNextFixedY(Input->MouseP.y);
UI_MakeBox(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawText |
UI_BoxFlag_FloatingX |
UI_BoxFlag_FloatingY,
Workspace_GetViewName(DraggedView));
}
UI_SetNextCornerRadius(4);
UI_TooltipLabel(W_GetViewName(DraggedView), UI_MouseP());
}
else
{
if(Workspace->DragPayloadState == Workspace_DragPayload_Active)
if(Workspace->DragPayloadState == W_DragPayload_Active)
{
Workspace->DragPayloadState = Workspace_DragPayload_Released;
Workspace->DragPayloadState = W_DragPayload_Released;
}
}
}
}
//- sixten: Workspace
static void Workspace_Init(workspace *Workspace)
static void W_Init(workspace *Workspace)
{
Workspace_SetState(Workspace);
W_SetState(Workspace);
Workspace->FrameArena = ArenaAllocate(Gigabytes(1));
Workspace->CommandArena = ArenaAllocate(Gigabytes(1));
Workspace->PanelArena = ArenaAllocate(Gigabytes(1));
Workspace->RootPanel = Workspace->CurrentPanel = Workspace_CreateNewPanel(0);
Workspace->RootPanel = Workspace->CurrentPanel = W_CreateNewPanel(0);
if(DEBUG_DebugSettings->ShowWelcomeMessage)
{
Workspace_CreateNewView(Workspace_View_Startup, Workspace->RootPanel);
W_CreateNewView(W_View_Startup, Workspace->RootPanel);
}
// sixten: Setup keybinds
{
#define BIND_COMMAND(...) Workspace->Keybinds[Workspace->KeybindCount++] = {__VA_ARGS__}
BIND_COMMAND(Key_P, PlatformModifier_Ctrl, Workspace_Command_SplitPanelHorizontal);
BIND_COMMAND(Key_L, PlatformModifier_Ctrl, Workspace_Command_SplitPanelVertical);
BIND_COMMAND(Key_O, PlatformModifier_Ctrl, Workspace_Command_OpenView, Workspace_View_TextEditor);
#if VN_INTERNAL
BIND_COMMAND(Key_U, PlatformModifier_Ctrl|PlatformModifier_Shift, Workspace_Command_ToggleRenderUIDebugRects);
#endif
#undef BIND_COMMAND
}
W_CreateNewView(W_View_TextEditor, Workspace->RootPanel);
W_SplitPanel(Workspace->RootPanel, Axis2_X);
W_CreateNewView(W_View_SceneView, Workspace->RootPanel->Last);
}
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
static void W_Update(workspace *Workspace, vn_render_commands *RenderCommands,
vn_input *Input, glyph_atlas *GlyphAtlas)
{
Workspace_SetState(Workspace);
W_SetState(Workspace);
ArenaClear(Workspace->FrameArena);
Workspace->Input = Input;
Workspace->EventList = Input->EventList;
// sixten: Process the keybinds and commands.
W_ProcessKeyBinds();
W_ProcessCommands();
// sixten: Make sure that a view/panel is always selected.
if(!Workspace->CurrentPanel)
{
@ -802,16 +797,12 @@ static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCom
// sixten: Build the UI.
{
Workspace_BuildToolbar();
W_BuildToolbar();
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
Workspace_BuildPanel(Workspace->RootPanel);
W_BuildPanel(Workspace->RootPanel);
Workspace_BuildDragPayload();
W_BuildDragPayload();
}
// sixten: Process the keybinds and commands.
Workspace_ProcessKeyBinds();
Workspace_ProcessCommands();
}

View File

@ -3,8 +3,8 @@
#ifndef VN_WORKSPACE_H
#define VN_WORKSPACE_H
#include "vn_workspace_editor.h"
#include "vn_workspace_text_editor.h"
////////////////////////////////
//~ sixten: Workspace Types
// sixten(TODO): Remove this type entirely.
enum toolbar_menu
@ -32,8 +32,6 @@ struct workspace_panel
r32 PercentOfParent;
};
#include "vn_workspace_view.h"
#define WORKSPACE_COMMAND(name, ...) void name(u64 Argument)
typedef WORKSPACE_COMMAND(workspace_command_sig);
@ -56,9 +54,9 @@ struct workspace_keybind
enum workspace_drag_payload_state
{
Workspace_DragPayload_Inactive = 0,
Workspace_DragPayload_Active,
Workspace_DragPayload_Released,
W_DragPayload_Inactive = 0,
W_DragPayload_Active,
W_DragPayload_Released,
};
struct workspace_drag_payload
@ -84,10 +82,6 @@ struct workspace
workspace_command *FirstCommand;
workspace_command *LastCommand;
// sixten: Keybinds
workspace_keybind Keybinds[256];
s32 KeybindCount;
// sixten: Panels
memory_arena *PanelArena;
workspace_panel *FirstFreePanel;
@ -104,28 +98,34 @@ struct workspace
workspace_panel *CurrentPanel;
};
#include "vn_workspace_editor.h"
#include "vn_workspace_text_editor.h"
#include "vn_workspace_view.h"
////////////////////////////////
//~ sixten: Workspace Functions
//- sixten: State management
static void Workspace_SetState(workspace *Workspace);
static workspace *Workspace_GetState(void);
static memory_arena *Workspace_FrameArena(void);
static void W_SetState(workspace *Workspace);
static workspace *W_GetState(void);
static memory_arena *W_FrameArena(void);
//- sixten: Commands
static void Workspace_IssueCommand(workspace_command_sig *Sig, u64 Argument);
static void Workspace_ProcessCommands(void);
static void W_IssueCommand(workspace_command_sig *Sig, u64 Argument);
static void W_ProcessCommands(void);
//- sixten: Panels
static workspace_panel *Workspace_CreateNewPanel(workspace_panel *Parent);
static void Workspace_DeletePanel(workspace_panel *Panel);
static void Workspace_SplitPanel(workspace_panel *Panel, axis2 Axis);
static workspace_panel *W_CreateNewPanel(workspace_panel *Parent);
static void W_DeletePanel(workspace_panel *Panel);
static void W_SplitPanel(workspace_panel *Panel, axis2 Axis);
//- sixten: Builder code
static ui_signal Workspace_BuildToolbarButton(char *Text, toolbar_menu Menu);
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut);
static void Workspace_BuildToolbar(r32 dtForFrame);
static ui_signal W_BuildToolbarButton(char *Text, toolbar_menu Menu);
static ui_signal W_BuildMenuItem(u32 Icon, char *Text, char *Shortcut);
static void W_BuildToolbar(r32 dtForFrame);
//- sixten: Workspace
static void Workspace_Init(workspace *Workspace);
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
vn_input *Input, glyph_atlas *GlyphAtlas);
static void W_Init(workspace *Workspace);
static void W_Update(workspace *Workspace, vn_render_commands *RenderCommands, vn_input *Input, glyph_atlas *GlyphAtlas);
#endif //VN_WORKSPACE_H

View File

@ -1,18 +1,18 @@
WORKSPACE_COMMAND(Workspace_Command_SplitPanelHorizontal)
WORKSPACE_COMMAND(W_Command_SplitPanelHorizontal)
{
workspace *Workspace = Workspace_GetState();
Workspace_SplitPanel(Workspace->CurrentPanel, Axis2_X);
workspace *Workspace = W_GetState();
W_SplitPanel(Workspace->CurrentPanel, Axis2_X);
}
WORKSPACE_COMMAND(Workspace_Command_SplitPanelVertical)
WORKSPACE_COMMAND(W_Command_SplitPanelVertical)
{
workspace *Workspace = Workspace_GetState();
Workspace_SplitPanel(Workspace->CurrentPanel, Axis2_Y);
workspace *Workspace = W_GetState();
W_SplitPanel(Workspace->CurrentPanel, Axis2_Y);
}
WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
WORKSPACE_COMMAND(W_Command_ClosePanel)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
workspace_panel *Panel = (workspace_panel *)Argument;
if(!Panel)
@ -54,7 +54,7 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
}
DLLRemove(Parent->First, Parent->Last, Child);
Workspace_DeletePanel(Child);
W_DeletePanel(Child);
}
else
{
@ -76,25 +76,50 @@ WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
}
// sixten: Delete all child views.
workspace_view *NextChild = 0;
for(workspace_view *Child = Panel->FirstView;
Child != 0;
Child = Child->Next)
Child = NextChild)
{
//Workspace_DeleteView(Child);
NextChild = Child->Next;
W_DestroyView(Child);
}
Workspace_DeletePanel(Panel);
W_DeletePanel(Panel);
}
WORKSPACE_COMMAND(Workspace_Command_OpenView)
WORKSPACE_COMMAND(W_Command_OpenView)
{
workspace *Workspace = Workspace_GetState();
Workspace_CreateNewView((workspace_view_type)Argument, Workspace->CurrentPanel);
workspace *Workspace = W_GetState();
W_CreateNewView((workspace_view_type)Argument, Workspace->CurrentPanel);
}
WORKSPACE_COMMAND(W_Command_CloseView)
{
workspace_view *View = (workspace_view *)U64ToPointer(Argument);
workspace_panel *Panel = View->Parent;
DLLRemove(Panel->FirstView, Panel->LastView, View);
if(Panel->CurrentView == View)
{
Panel->CurrentView = Panel->FirstView;
}
W_DestroyView(View);
}
#if VN_INTERNAL
WORKSPACE_COMMAND(Workspace_Command_ToggleRenderUIDebugRects)
WORKSPACE_COMMAND(W_Command_ToggleRenderUIDebugRects)
{
DEBUG_DebugSettings->RenderUIDebugRects = !DEBUG_DebugSettings->RenderUIDebugRects;
}
#endif
WORKSPACE_COMMAND(W_Command_Test)
{
for(s32 Index = 0; Index < 10000; Index += 1)
{
W_IssueCommand(W_Command_OpenView, W_View_TextEditor);
W_IssueCommand(W_Command_CloseView, 0);
}
}

View File

@ -1,7 +1,7 @@
//- sixten: Managing nodes
static workspace_editor_node *Workspace_GetNewEditorNode(workspace_view *View)
{
Assert(View->Type == Workspace_View_Editor);
Assert(View->Type == W_View_Editor);
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
@ -70,7 +70,7 @@ static void Workspace_BuildEditorListerDropdown(workspace_editor_lister_dropdown
UI_PushBackgroundColor(SetAlpha(Color_Black, 0.3));
UI_PushBorderColor(SetAlpha(Color_Black, 0.7));
r32 HeightTransition = AnimationCurve_AnimateValueF(1, 0, 0.3, "Editor Lister Dropdown %p", ListerDropdown);
r32 HeightTransition = AC_AnimateValueF(1, 0, 0.3, "Editor Lister Dropdown %p", ListerDropdown);
UI_SetNextSize(UI_Em(15, 1), UI_Em(25*HeightTransition, 1));
UI_SetNextCornerRadius(4.0);
@ -145,7 +145,7 @@ static void Workspace_BuildEditorListerDropdown(workspace_editor_lister_dropdown
UI_SetNextCornerRadius(3.0);
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
UI_SetNextBackgroundColor(SetAlpha(Theme_HighlightBorderColor,
AnimationCurve_AnimateValueF(TargetHot, TargetHot, 0.1, "Editor Lister %s%p",
AC_AnimateValueF(TargetHot, TargetHot, 0.1, "Editor Lister %s%p",
Option->Text, ListerDropdown)));
UI_SetNextLayoutAxis(Axis2_X);
ui_box *HighlightBox = UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit(""));
@ -219,7 +219,7 @@ static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas
static void Workspace_BuildEditor(workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
@ -227,10 +227,9 @@ static void Workspace_BuildEditor(workspace_view *View)
UI_SetNextHeight(UI_Percent(1, 1));
ui_box *EditorBox = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "Workspace Editor %p", View);
EditorBox->DrawCallback = Workspace_EditorDrawCallback;
EditorBox->DrawCallbackData = Editor;
UI_EquipBoxCustomDrawCallback(EditorBox, Workspace_EditorDrawCallback, Editor);
r32 AnimatedZoomLevel = AnimationCurve_AnimateValueF(Editor->ZoomLevel, 0, 0.25, "Workspace Editor Zoom");
r32 AnimatedZoomLevel = AC_AnimateValueF(Editor->ZoomLevel, 0, 0.25, "Workspace Editor Zoom");
Editor->Scale = Workspace_CalculateScaleFromZoomLevel(AnimatedZoomLevel);
v2 EditorDim = DimOfRange(EditorBox->Rect);

View File

@ -6,7 +6,7 @@ static mutable_string MutableStringAllocate(u64 Size)
mutable_string Result = {};
Result.Arena = ArenaAllocate(Size);
ArenaSetAlign(Result.Arena, 1);
Result.String = MakeString(PushArray(Result.Arena, u8, 1), 0);
Result.String = MakeString(PushArray(Result.Arena, u8, 1), 0LL);
return(Result);
}
@ -60,9 +60,9 @@ static void AppendToHistory(memory_arena *Arena, history_list *List, history_ent
}
////////////////////////////////
//~ sixten: Workspace Text Editor Functions
//~ sixten: Workspace Text Editing Functions
static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *Arena, string Text)
static workspace_text_data W_TextDataFromString(memory_arena *Arena, string Text)
{
temporary_memory Scratch = GetScratch(&Arena, 1);
@ -102,14 +102,41 @@ static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *A
return(Result);
}
static void Workspace_TextEditorApplyChanges(workspace_view_text_editor *Editor)
static void W_TextEditorApplyChanges(workspace_view_text_editor *Editor)
{
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String);
Editor->Tokens = TextData.Tokens;
Editor->Lines = TextData.Lines;
Editor->Compiled = S_ScriptFromText(Editor->ProcessingArena, Editor->Text.String);
if(Editor->Compiled.IsValid)
{
SV_SetCurrentSource(&Editor->Compiled);
}
}
static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
static void W_SaveTextEditorToFile(workspace_view_text_editor *Editor)
{
temporary_memory Scratch = GetScratch();
if(Editor->SavePoint != Editor->History.At)
{
string Path = PushFormat(Scratch.Arena, "%S/%S", Editor->FilePath, Editor->FileName);
platform_file_handle Handle = Platform.OpenFile(Path, PlatformAccess_Write);
if(Handle.IsValid)
{
Platform.WriteFile(Handle, Editor->Text.String.Data, 0, Editor->Text.String.Count);
Platform.CloseFile(Handle);
}
Editor->SavePoint = Editor->History.At;
}
ReleaseScratch(Scratch);
}
////////////////////////////////
//~ sixten: Workspace Text Editor Builder Functions
static UI_CUSTOM_DRAW_CALLBACK(W_TextEditorDrawCallback)
{
temporary_memory Scratch = GetScratch();
workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data;
@ -224,6 +251,18 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
Color = Theme_TextColor;
}
//- sixten: check for errors
b32 ConsideredError = false;
for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next)
{
if(Error->Token.Range.Min == Token->Range.Min &&
Error->Token.Range.Max == Token->Range.Max)
{
ConsideredError = true;
break;
}
}
//- sixten: render & advance by token
if(!(T_IsWhitespace(Token->Kind)))
{
@ -251,7 +290,16 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
}
else
{
TokenP.x += PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString);
r32 TokenWidth = PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString);
//- sixten: render error highlight
if(ConsideredError)
{
range2_r32 Dest = Range2R32(TokenP+V2R32(0, LineHeight-3), TokenP+V2R32(TokenWidth, LineHeight));
v4_r32 ErrorColor = V4R32(0.9f, 0.3f, 0.3f, 0.8f);
PushQuad(Group, Dest, ErrorColor, ErrorColor, ErrorColor, ErrorColor, 3, 0.4, 0);
}
TokenP.x += TokenWidth;
}
}
else
@ -284,8 +332,8 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
s64 ColumnOffset = UTF8OffsetFromIndex(Line, ColumnIndex);
v2 TargetCursorP = Box->Rect.Min+V2(LineMarginDim.x+ColumnOffset*GlyphAdvance, LineIndex*LineHeight);
v2 CursorP = V2(AnimationCurve_AnimateValueF(TargetCursorP.x, TargetCursorP.x, 0.1, "Workspace Text Editor Cursor X %p", Editor),
AnimationCurve_AnimateValueF(TargetCursorP.y, TargetCursorP.y, 0.1, "Workspace Text Editor Cursor Y %p", Editor));
v2 CursorP = V2(AC_AnimateValueF(TargetCursorP.x, TargetCursorP.x, 0.1, "Workspace Text Editor Cursor X %p", Editor),
AC_AnimateValueF(TargetCursorP.y, TargetCursorP.y, 0.1, "Workspace Text Editor Cursor Y %p", Editor));
v2 CursorDim = V2(2, LineHeight);
range2_r32 CursorRect = Range2R32(CursorP, CursorP+CursorDim);
v4 CursorColor = ColorFromHex(0x10FF20FF);
@ -329,11 +377,60 @@ static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback)
}
ReleaseScratch(Scratch);
}
UI_CUSTOM_DRAW_CALLBACK(W_TextEditorListerInputCallback)
{
workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data;
s64 ClampedCursor = Clamp(0, Box->String.Count, Editor->ListerInputEditState.Cursor);
s64 ClampedMark = Clamp(0, Box->String.Count, Editor->ListerInputEditState.Mark);
string ToCursor = MakeString(Box->String.Data, ClampedCursor);
string ToMark = MakeString(Box->String.Data, ClampedMark);
static b32 Workspace_BuildTextEditorListerItem(string Text, u32 Icon)
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, "Workspace View Input Cursor %p", Box);
r32 MarkerX = AC_AnimateValueF(TargetMarkerX, 0, 0.175, "Workspace View 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);
v2 P = Box->Rect.Min + Offset;
v4 Color = V4(0.3, 1, 0.3, 0.7);
PushQuad(Group, Range2R32(P, P+Dim), Color, 0, 0, 0);
}
}
static b32 W_BuildTextEditorListerItem(string Text, u32 Icon)
{
b32 Result = false;
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
UI_BoxFlag_DrawBackground |
UI_BoxFlag_Clickable |
@ -355,7 +452,7 @@ static b32 Workspace_BuildTextEditorListerItem(string Text, u32 Icon)
return(Result);
}
static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(workspace_view *View, workspace_view_text_editor *Editor)
static workspace_text_editor_lister_action W_BuildTextEditorLister(workspace_view *View, workspace_view_text_editor *Editor)
{
workspace_text_editor_lister_action ListerAction = {};
temporary_memory Scratch = GetScratch();
@ -364,7 +461,7 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
UI_Height(UI_Em(2, 1))
{
//- sixten: filename input field
if(Workspace_ViewIsCurrent(View))
if(W_ViewIsCurrent(View))
{
for(platform_event *Event = UI_EventList()->First; Event != 0; Event = Event->Next)
{
@ -402,7 +499,9 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
UI_MakeBox(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawText, Editor->Path);
UI_SetNextWidth(UI_TextContent(15, 1));
UI_Label(MakeString(Editor->ListerInput, Editor->ListerInputUsed));
ui_box *InputBox = UI_MakeBox(UI_BoxFlag_DrawText, StrLit("Text Editor Lister Input"));
UI_EquipBoxText(InputBox, MakeString(Editor->ListerInput, Editor->ListerInputUsed));
UI_EquipBoxCustomDrawCallback(InputBox, W_TextEditorListerInputCallback, Editor);
UI_Padding(UI_Percent(1, 0));
@ -419,7 +518,7 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
s64 LastSlash = LastIndexOf(Editor->Path, '/');
if(LastSlash != -1)
{
if(Workspace_BuildTextEditorListerItem(StrLit("Parent Directory"), FontIcon_Reply))
if(W_BuildTextEditorListerItem(StrLit("Parent Directory"), FontIcon_Reply))
{
Editor->Path = Prefix(Editor->Path, LastSlash);
Editor->ListerInputUsed = 0;
@ -438,7 +537,7 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
{
if(FileInfo.IsDirectory)
{
if(Workspace_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Folder))
if(W_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Folder))
{
Editor->Path = PushFormat(View->Arena, "%S/%S", Editor->Path, FileInfo.Name);
Editor->ListerInputUsed = 0;
@ -455,7 +554,7 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
{
if(!FileInfo.IsDirectory)
{
if(Workspace_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Document))
if(W_BuildTextEditorListerItem(FileInfo.Name, FontIcon_Document))
{
ListerAction.HasRequestedFile = true;
ListerAction.Name = PushString(View->Arena, FileInfo.Name);
@ -471,7 +570,7 @@ static workspace_text_editor_lister_action Workspace_BuildTextEditorLister(works
return(ListerAction);
}
static b32 Workspace_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform_event *Event)
static b32 W_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform_event *Event)
{
b32 CursorHasBeenModified = false;
temporary_memory Scratch = GetScratch();
@ -502,8 +601,9 @@ static b32 Workspace_ProcessTextEditorEvent(workspace_view_text_editor *Editor,
List->At = List->Sentinel.Prev;
}
//- sixten: apply the text action
MutableStringReplaceRange(&Editor->Text, Op.ReplaceString, Op.Range);
Workspace_TextEditorApplyChanges(Editor);
string ReplaceString = RemoveAll(Scratch.Arena, Op.ReplaceString, '\r');
MutableStringReplaceRange(&Editor->Text, ReplaceString, Op.Range);
W_TextEditorApplyChanges(Editor);
}
CursorHasBeenModified = true;
@ -514,14 +614,28 @@ static b32 Workspace_ProcessTextEditorEvent(workspace_view_text_editor *Editor,
return(CursorHasBeenModified);
}
static void Workspace_BuildTextEditor(workspace_view *View)
static void W_BuildTextEditorInfoBar(workspace_view_text_editor *Editor)
{
UI_SetNextLayoutAxis(Axis2_X);
UI_WidthFill UI_Height(UI_Em(1.75f, 1)) UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawDropShadow, "")) UI_Padding(UI_Em(1, 1))
{
UI_Width(UI_TextContent(0, 1))
{
UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Attention);
UI_Spacer(UI_Em(0.5f, 1));
UI_LabelF("%i", Editor->Compiled.Errors.Count);
}
}
}
static void W_BuildTextEditor(workspace_view *View)
{
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
temporary_memory Scratch = GetScratch();
//- sixten: rendering properties
r32 FontSize = Editor->FontSize = 14.0f;
r32 FontSize = Editor->FontSize = 13.0f;
r32 LineHeight = FontSize + 4.0f;
//- sixten: calculate the dimensions of the glyphs
@ -537,7 +651,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
if(InFileListMode)
{
//- sixten: build & handle file lister
workspace_text_editor_lister_action Action = Workspace_BuildTextEditorLister(View, Editor);
workspace_text_editor_lister_action Action = W_BuildTextEditorLister(View, Editor);
if(Action.HasRequestedFile)
{
//- sixten: try to load file
@ -553,7 +667,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
ReplaceString = RemoveAll(Scratch.Arena, ReplaceString, '\r');
MutableStringReplaceRange(&Editor->Text, ReplaceString, Range1S64(0, 0));
Workspace_TextEditorApplyChanges(Editor);
W_TextEditorApplyChanges(Editor);
Editor->FileName = Action.Name;
Editor->FilePath = Action.Path;
@ -570,7 +684,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
{
//- sixten: build & handle the text editor
ui_box *EditorBox = 0;
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
UI_Scroll(0, &Editor->Offset.y)
{
//- sixten: find the container box for the scrollable region
@ -578,13 +692,52 @@ static void Workspace_BuildTextEditor(workspace_view *View)
UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1));
EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View);
EditorBox->DrawCallback = Workspace_TextEditorDrawCallback;
EditorBox->DrawCallbackData = Editor;
UI_EquipBoxCustomDrawCallback(EditorBox, W_TextEditorDrawCallback, Editor);
}
//- sixten: build footer
W_BuildTextEditorInfoBar(Editor);
r32 TargetFooterHeightEm = 2.25f*Min(Editor->Compiled.Errors.Count, 10LL);
UI_Size(UI_Percent(1, 0), UI_Em(AC_AnimateValueF(TargetFooterHeightEm, TargetFooterHeightEm, 0.3, "Error Lister %p", Editor), 1)) UI_Column() UI_Height(UI_TextContent(0, 1))
{
s64 Index = 0;
for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next, Index += 1)
{
UI_SetNextHeight(UI_ChildrenSum(1, 1));
UI_SetNextLayoutAxis(Axis2_X);
UI_Parent(UI_MakeBoxF(0, "Editor Error Lister Container %p", Error)) UI_Padding(UI_Em(1, 1)) UI_Height(UI_Em(1.75f, 1))
{
UI_SetNextBackgroundColor(SetAlpha(Theme_BorderColor, 0.8f));
UI_SetNextCornerRadius(4);
UI_SetNextLayoutAxis(Axis2_X);
UI_SetNextHoverCursor(PlatformCursor_Hand);
ui_box *ContainerBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBorder, "Container Box");
UI_Parent(ContainerBox) UI_Padding(UI_Em(1, 1)) UI_Width(UI_TextContent(0, 1))
{
UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Attention);
UI_Spacer(UI_Em(0.5f, 1));
// sixten(TODO): this is dumb, slow and downright stupid.
text_point Point = TextPointFromOffset(Editor->Text.String, Error->Token.Range.Min);
UI_LabelF("%i:%i", Point.Line, Point.Column);
UI_Spacer(UI_Em(0.5f, 1));
UI_Label(Error->Message);
UI_Spacer(UI_Percent(1, 0));
}
ui_signal Signal = UI_SignalFromBox(ContainerBox);
if(Signal.Hovering)
{
UI_TooltipLabel(StrLit("Goto in source"), UI_MouseP());
}
}
UI_Spacer(UI_Em(0.5, 1));
}
}
b32 CursorHasBeenModified = false;
if(Workspace_ViewIsCurrent(View))
if(W_ViewIsCurrent(View))
{
//- sixten: handle history
{
@ -599,7 +752,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
//- sixten: get entry & apply
history_entry Entry = Node->Backward;
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
Workspace_TextEditorApplyChanges(Editor);
W_TextEditorApplyChanges(Editor);
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
CursorHasBeenModified = true;
@ -616,7 +769,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
//- sixten: get entry & apply
history_entry Entry = Node->Forward;
MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range);
Workspace_TextEditorApplyChanges(Editor);
W_TextEditorApplyChanges(Editor);
Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count;
CursorHasBeenModified = true;
@ -625,6 +778,12 @@ static void Workspace_BuildTextEditor(workspace_view *View)
}
}
//- sixten: save
if(Platform_KeyPress(UI_EventList(), Key_S, PlatformModifier_Ctrl))
{
W_SaveTextEditorToFile(Editor);
}
//- sixten: select all
if(Platform_KeyPress(UI_EventList(), Key_A, PlatformModifier_Ctrl))
{
@ -655,18 +814,31 @@ static void Workspace_BuildTextEditor(workspace_view *View)
}
}
//- sixten: auto close bracket
if(Event->Codepoint == '{')
{
platform_event FakeEvent = {};
FakeEvent.Codepoint = '}';
FakeEvent.Type = PlatformEvent_Text;
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeEvent);
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent);
FakeEvent.Key = Key_Left;;
FakeEvent.Type = PlatformEvent_Press;
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeEvent);
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent);
}
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, Event);
//- sixten: auto close string literal
if(Event->Codepoint == '"')
{
platform_event FakeEvent = {};
FakeEvent.Codepoint = '"';
FakeEvent.Type = PlatformEvent_Text;
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent);
FakeEvent.Key = Key_Left;;
FakeEvent.Type = PlatformEvent_Press;
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent);
}
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, Event);
//- sixten: apply indent
{
@ -676,7 +848,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
for(s64 IndentIndex = 0; IndentIndex < Indent; IndentIndex += 1)
{
CursorHasBeenModified |= Workspace_ProcessTextEditorEvent(Editor, &FakeTab);
CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeTab);
}
}
}
@ -691,7 +863,7 @@ static void Workspace_BuildTextEditor(workspace_view *View)
{
UI_SetNextFixedP(Editor->DropdownP);
UI_SetNextWidth(UI_Em(20, 1));
UI_SetNextHeight(UI_ChildrenSum(AnimationCurve_AnimateValueDirect(1, 0.2, &Editor->DropdownTransition), 1));
UI_SetNextHeight(UI_ChildrenSum(AC_AnimateValueDirect(1, 0.2, &Editor->DropdownTransition), 1));
UI_SetNextCornerRadius(4);
UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBackground |
UI_BoxFlag_DrawDropShadow |
@ -703,13 +875,31 @@ static void Workspace_BuildTextEditor(workspace_view *View)
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
UI_CornerRadius(2)
{
UI_ButtonF("Hello");
UI_ButtonF("Line");
UI_ButtonF("Paint");
UI_ButtonF("Color");
UI_ButtonF("Design");
UI_ButtonF("Address");
UI_ButtonF("Brightness");
if(W_BuildMenuItem(FontIcon_Gamepad, "Run in scene view", "").Clicked)
{
SV_SetCurrentSource(&Editor->Compiled);
Editor->DropdownActive = false;
}
if(Editor->EditState.Cursor != Editor->EditState.Mark)
{
if(W_BuildMenuItem(FontIcon_Document, "Copy", "Ctrl+C").Clicked)
{
Editor->DropdownActive = false;
}
if(W_BuildMenuItem(FontIcon_Cut, "Cut", "Ctrl+X").Clicked)
{
Editor->DropdownActive = false;
}
}
if(W_BuildMenuItem(FontIcon_Paste, "Paste", "Ctrl+V").Clicked)
{
Editor->DropdownActive = false;
}
if(W_BuildMenuItem(FontIcon_Floppy, "Save", "Ctrl+S").Clicked)
{
W_SaveTextEditorToFile(Editor);
Editor->DropdownActive = false;
}
}
}
}

View File

@ -57,6 +57,7 @@ struct workspace_view_text_editor
memory_arena *ProcessingArena;
token_array Tokens;
range1_s64_array Lines;
compiled_scene Compiled;
// sixten: text being edited
string FileName;
@ -73,6 +74,7 @@ struct workspace_view_text_editor
// sixten: history
memory_arena *HistoryArena;
history_list History;
history_node *SavePoint;
// sixten: ui building & rendering
ui_box *ContainerBox;
@ -104,10 +106,20 @@ static history_entry HistoryEntry(memory_arena *Arena, string ReplaceString, ran
static void AppendToHistory(memory_arena *Arena, history_list *List, history_entry Forward, history_entry Backward);
////////////////////////////////
//~ sixten: Workspace Text Editor Functions
//~ sixten: Workspace Text Editing Functions
static workspace_text_data Workspace_TextDataFromStringChunkList(memory_arena *Arena, string Text);
static UI_CUSTOM_DRAW_CALLBACK(Workspace_TextEditorDrawCallback);
static void Workspace_BuildTextEditor(workspace_view *View);
static workspace_text_data W_TextDataFromString(memory_arena *Arena, string Text);
static void W_TextEditorApplyChanges(workspace_view_text_editor *Editor);
static void W_SaveTextEditorToFile(workspace_view_text_editor *Editor);
////////////////////////////////
//~ sixten: Workspace Text Editor Builder Functions
static UI_CUSTOM_DRAW_CALLBACK(W_TextEditorDrawCallback);
static b32 W_BuildTextEditorListerItem(string Text, u32 Icon);
static workspace_text_editor_lister_action W_BuildTextEditorLister(workspace_view *View, workspace_view_text_editor *Editor);
static b32 W_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform_event *Event);
static void W_BuildTextEditorInfoBar(workspace_view_text_editor *Editor);
static void W_BuildTextEditor(workspace_view *View);
#endif //VN_WORKSPACE_TEXT_EDITOR_H

View File

@ -1,5 +1,5 @@
//- sixten: Views
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent)
inline workspace_view *W_CreateNewView(workspace_view_type Type, workspace_panel *Parent)
{
memory_arena *Arena = ArenaAllocate(Gigabytes(1));
workspace_view *View = PushStruct(Arena, workspace_view);
@ -9,22 +9,22 @@ inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspa
switch(View->Type)
{
case Workspace_View_Editor:
case W_View_Editor:
{
View->Data = PushStruct(View->Arena, workspace_view_editor);
} break;
case Workspace_View_CommandPalette:
case W_View_CommandPalette:
{
View->Data = PushStruct(View->Arena, workspace_view_command_palette);
} break;
case Workspace_View_Settings:
case W_View_Settings:
{
View->Data = PushStruct(View->Arena, workspace_view_settings);
} break;
case Workspace_View_TextEditor:
case W_View_TextEditor:
{
View->Data = PushStruct(View->Arena, workspace_view_text_editor);
@ -35,8 +35,9 @@ inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspa
SenDLLInit(&Editor->History.Sentinel);
Editor->History.At = &Editor->History.Sentinel;
Editor->SavePoint = Editor->History.At;
workspace_text_data TextData = Workspace_TextDataFromStringChunkList(Editor->ProcessingArena, Editor->Text.String);
workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String);
Editor->Tokens = TextData.Tokens;
Editor->Lines = TextData.Lines;
} break;
@ -52,11 +53,11 @@ inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspa
return(View);
}
inline void Workspace_DestroyView(workspace_view *View)
inline void W_DestroyView(workspace_view *View)
{
switch(View->Type)
{
case Workspace_View_TextEditor:
case W_View_TextEditor:
{
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
ArenaRelease(Editor->ProcessingArena);
@ -69,23 +70,23 @@ inline void Workspace_DestroyView(workspace_view *View)
ArenaRelease(View->Arena);
}
inline b32 Workspace_ViewIsCurrent(workspace_view *View)
inline b32 W_ViewIsCurrent(workspace_view *View)
{
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
b32 Result = (Workspace->CurrentPanel && Workspace->CurrentPanel->CurrentView == View);
return(Result);
}
inline string Workspace_GetViewName(workspace_view *View)
inline string W_GetViewName(workspace_view *View)
{
string Result = StrLit("Unnamed view");
switch(View->Type)
{
case Workspace_View_Startup: { Result = StrLit("Welcome"); } break;
case Workspace_View_Editor: { Result = StrLit("Editor"); } break;
case Workspace_View_Settings: { Result = StrLit("Settings"); } break;
case Workspace_View_TextEditor:
case W_View_Startup: { Result = StrLit("Welcome"); } break;
case W_View_Editor: { Result = StrLit("Editor"); } break;
case W_View_Settings: { Result = StrLit("Settings"); } break;
case W_View_TextEditor:
{
workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data;
if(AreEqual(Editor->FileName, StrLit("")))
@ -94,23 +95,25 @@ inline string Workspace_GetViewName(workspace_view *View)
}
else
{
if(Editor->History.At == &Editor->History.Sentinel)
//if(Editor->History.At == &Editor->History.Sentinel)
if(Editor->History.At == Editor->SavePoint)
{
Result = PushString(Workspace_FrameArena(), Editor->FileName);
Result = PushString(W_FrameArena(), Editor->FileName);
}
else
{
Result = PushFormat(Workspace_FrameArena(), "* %S", Editor->FileName);
Result = PushFormat(W_FrameArena(), "* %S", Editor->FileName);
}
}
} break;
case W_View_SceneView: { Result = StrLit("Scene View"); } break;
}
return(Result);
}
//- sixten: Builder code
static void Workspace_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)
{
workspace_view_command_palette *CommandPalette = (workspace_view_command_palette *)Data;
string ToCursor = MakeString(Box->String.Data, CommandPalette->ListerInputEditState.Cursor);
@ -119,8 +122,8 @@ static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *
r32 TargetCursorX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToCursor);
r32 TargetMarkerX = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, ToMark);
r32 CursorX = AnimationCurve_AnimateValueF(TargetCursorX, 0, 0.175, "Workspace View Input Cursor %p", Box);
r32 MarkerX = AnimationCurve_AnimateValueF(TargetMarkerX, 0, 0.175, "Workspace View Input Mark %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);
v2 BoxDim = DimOfRange(Box->Rect);
@ -158,11 +161,11 @@ static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *
}
}
static void Workspace_BuildViewTypeLister(workspace_view *View)
static void W_BuildViewTypeLister(workspace_view *View)
{
workspace_view_command_palette *CommandPalette = (workspace_view_command_palette *)View->Data;
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
temporary_memory Scratch = GetScratch(0, 0);
@ -184,7 +187,7 @@ static void Workspace_BuildViewTypeLister(workspace_view *View)
// sixten: Input Field.
{
r32 SelectedTransition = AnimationCurve_AnimateValueF(CommandPalette->ListerFieldSelected ? 1.0 : 0.0,
r32 SelectedTransition = AC_AnimateValueF(CommandPalette->ListerFieldSelected ? 1.0 : 0.0,
0, 0.125, "View Input Field %p", View);
v4 BorderColor = UI_TopBackgroundColor()*2;
@ -206,8 +209,7 @@ static void Workspace_BuildViewTypeLister(workspace_view *View)
ui_box *InputTextBox = UI_MakeBox(UI_BoxFlag_DrawText, StrLit("Workspace View Lister"));
InputTextBox->String = MakeString(CommandPalette->ListerInput, CommandPalette->ListerInputUsed);
InputTextBox->DrawCallback = Workspace_ViewListerInputCallback;
InputTextBox->DrawCallbackData = CommandPalette;
UI_EquipBoxCustomDrawCallback(InputTextBox, W_ViewListerInputCallback, CommandPalette);
}
UI_Spacer(UI_Pixels(4, 1));
@ -282,11 +284,11 @@ static void Workspace_BuildViewTypeLister(workspace_view *View)
ReleaseScratch(Scratch);
}
static void Workspace_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);
v4 Color = LinearBlend(Theme_TextColor, Theme_HighlightBorderColor, AnimationCurve_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_SetNextHeight(UI_TextContent(0, 1));
@ -346,7 +348,7 @@ static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *
ActiveInDropdown = true;
}
r32 OpenTransition = AnimationCurve_AnimateValueF(*Open, 0, 0.175, "UI Dropdown %p%p", Alternatives, Open);
r32 OpenTransition = AC_AnimateValueF(*Open, 0, 0.175, "UI Dropdown %p%p", Alternatives, Open);
if(OpenTransition > 0.1)
{
@ -394,11 +396,16 @@ static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *
return(Result);
}
static void Workspace_BuildSettings(workspace_view *View)
static void W_BuildSceneView(workspace_view *View)
{
workspace *Workspace = W_GetState();
SV_BuildSceneView(Workspace->Input);
}
static void W_BuildSettings(workspace_view *View)
{
workspace_view_settings *Settings = (workspace_view_settings *)View->Data;
workspace *Workspace = Workspace_GetState();
workspace *Workspace = W_GetState();
UI_Height(UI_ChildrenSum(1, 1))
UI_Column() UI_Padding(UI_Pixels(50, 0))
@ -420,13 +427,13 @@ static void Workspace_BuildSettings(workspace_view *View)
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, ""))
{
Workspace_BuildSettingsTabButton(Settings, "All", Workspace_Settings_All);
W_BuildSettingsTabButton(Settings, "All", W_Settings_All);
UI_Spacer(UI_Pixels(30, 1));
Workspace_BuildSettingsTabButton(Settings, "General", Workspace_Settings_General);
W_BuildSettingsTabButton(Settings, "General", W_Settings_General);
UI_Spacer(UI_Pixels(30, 1));
Workspace_BuildSettingsTabButton(Settings, "Theme", Workspace_Settings_Theme);
W_BuildSettingsTabButton(Settings, "Theme", W_Settings_Theme);
UI_Spacer(UI_Pixels(30, 1));
Workspace_BuildSettingsTabButton(Settings, "Developer", Workspace_Settings_Developer);
W_BuildSettingsTabButton(Settings, "Developer", W_Settings_Developer);
UI_Spacer(UI_Pixels(150, 1));
}
@ -442,9 +449,12 @@ static void Workspace_BuildSettings(workspace_view *View)
UI_Width(UI_Percent(1, 0))
UI_Parent(UI_MakeBoxF(0, "Tab"))
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
{
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
UI_Scroll(0, &Settings->GlobalScroll, UI_BoxFlag_Clip)
{
workspace_settings_category Category = Settings->Category;
if(!Category || (Category == Workspace_Settings_General))
if(!Category || (Category == W_Settings_General))
{
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("General");
@ -464,7 +474,7 @@ static void Workspace_BuildSettings(workspace_view *View)
UI_Spacer(UI_Pixels(50, 1));
}
if(!Category || (Category == Workspace_Settings_Theme))
if(!Category || (Category == W_Settings_Theme))
{
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Theme");
@ -492,7 +502,7 @@ static void Workspace_BuildSettings(workspace_view *View)
UI_Spacer(UI_Pixels(50, 1));
}
if(!Category || (Category == Workspace_Settings_Developer))
if(!Category || (Category == W_Settings_Developer))
{
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer");
UI_Checkbox(&DEBUG_DebugSettings->RenderUIDebugRects, StrLit("Render UI Debug Rects"));
@ -504,16 +514,16 @@ static void Workspace_BuildSettings(workspace_view *View)
UI_Spacer(UI_Pixels(50, 1));
}
}
}
}
UI_Spacer(UI_Pixels(50, 1));
}
static void Workspace_BuildView(workspace_view *View)
static void W_BuildView(workspace_view *View)
{
r32 ViewHighlightTransition =
AnimationCurve_AnimateValueF(Workspace_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_PushBackgroundColor(Theme_BackgroundColor);
UI_SetNextCornerRadius(3);
@ -527,7 +537,7 @@ static void Workspace_BuildView(workspace_view *View)
UI_Parent(ViewBox)
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
{
if(View->Type == Workspace_View_Startup)
if(View->Type == W_View_Startup)
{
UI_Row() UI_Padding(UI_Pixels(50, 0))
UI_Width(UI_ChildrenSum(1, 1)) UI_Column() UI_Padding(UI_Pixels(50, 0))
@ -544,21 +554,25 @@ static void Workspace_BuildView(workspace_view *View)
}
}
}
else if(View->Type == Workspace_View_CommandPalette)
else if(View->Type == W_View_CommandPalette)
{
Workspace_BuildViewTypeLister(View);
W_BuildViewTypeLister(View);
}
else if(View->Type == Workspace_View_Editor)
else if(View->Type == W_View_Editor)
{
Workspace_BuildEditor(View);
}
else if(View->Type == Workspace_View_Settings)
else if(View->Type == W_View_Settings)
{
Workspace_BuildSettings(View);
W_BuildSettings(View);
}
else if(View->Type == Workspace_View_TextEditor)
else if(View->Type == W_View_TextEditor)
{
Workspace_BuildTextEditor(View);
W_BuildTextEditor(View);
}
else if(View->Type == W_View_SceneView)
{
W_BuildSceneView(View);
}
}

View File

@ -3,6 +3,9 @@
#ifndef VN_WORKSPACE_VIEW_H
#define VN_WORKSPACE_VIEW_H
////////////////////////////////
//~ sixten: Workspace View Types
struct workspace_view
{
memory_arena *Arena;
@ -17,11 +20,12 @@ struct workspace_view
enum workspace_view_type
{
Workspace_View_Startup,
Workspace_View_Editor,
Workspace_View_CommandPalette,
Workspace_View_Settings,
Workspace_View_TextEditor,
W_View_Startup,
W_View_Editor,
W_View_CommandPalette,
W_View_Settings,
W_View_TextEditor,
W_View_SceneView,
};
struct workspace_view_editor
@ -47,15 +51,16 @@ struct workspace_view_command_palette
enum workspace_settings_category
{
Workspace_Settings_All,
Workspace_Settings_General,
Workspace_Settings_Theme,
Workspace_Settings_Developer,
W_Settings_All,
W_Settings_General,
W_Settings_Theme,
W_Settings_Developer,
};
struct workspace_view_settings
{
workspace_settings_category Category;
r32 GlobalScroll;
// sixten: General
b32 GeneralDropdownOpen;
@ -64,15 +69,18 @@ struct workspace_view_settings
r32 ThemeScroll;
};
////////////////////////////////
//~ sixten: Workspace View Functions
//- sixten: Views
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent);
inline void Workspace_DestroyView(workspace_view *View);
inline b32 Workspace_ViewIsCurrent(workspace_view *View);
inline string Workspace_GetViewName(workspace_view *View);
inline workspace_view *W_CreateNewView(workspace_view_type Type, workspace_panel *Parent);
inline void W_DestroyView(workspace_view *View);
inline b32 W_ViewIsCurrent(workspace_view *View);
inline string W_GetViewName(workspace_view *View);
//- sixten: Builder code
static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
static void Workspace_BuildViewTypeLister(workspace_view *View);
static void Workspace_BuildView(workspace_view *View);
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_BuildView(workspace_view *View);
#endif //VN_WORKSPACE_VIEW_H

View File

@ -314,7 +314,7 @@ static void Win32_UpdateCode(win32_loaded_code *Code)
*Code = Win32_LoadCode();
// sixten(NOTE): Sometimes the program decides to crash upon reloads, so we just wait for those to be over...
Sleep(200);
Sleep(500);
}
}
@ -348,6 +348,50 @@ static PLATFORM_TOGGLE_FULLSCREEN(Win32_ToggleFullscreen)
}
}
static PLATFORM_SET_CLIPBOARD(Win32_SetClipboard)
{
temporary_memory Scratch = GetScratch();
if(OpenClipboard(0))
{
EmptyClipboard();
string16 String16 = String16FromString8(Scratch.Arena, String);
HANDLE CopyHandle = GlobalAlloc(GMEM_MOVEABLE, String16.Count*sizeof(u16)+1);
if(CopyHandle)
{
u16 *CopyBuffer = (u16 *)GlobalLock(CopyHandle);
Copy(CopyBuffer, String16.Data, String16.Count*sizeof(u16));
CopyBuffer[String.Count] = 0;
GlobalUnlock(CopyHandle);
SetClipboardData(CF_UNICODETEXT, CopyHandle);
}
CloseClipboard();
}
ReleaseScratch(Scratch);
}
static PLATFORM_GET_CLIPBOARD(Win32_GetClipboard)
{
string Result = {};
if(IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(0))
{
HANDLE DataHandle = GetClipboardData(CF_UNICODETEXT);
if(DataHandle)
{
u16 *Data = (u16 *)GlobalLock(DataHandle);
if(Data)
{
s64 Count = StringLength16(Data);
Result = String8FromString16(Arena, MakeString16(Data, Count));
GlobalUnlock(DataHandle);
}
}
CloseClipboard();
}
return(Result);
}
inline v2 Win32_GetMouseP(HWND Window)
{
POINT Point;
@ -604,14 +648,7 @@ static void Win32_ProcessInput(vn_input *Input, HWND Window, r32 dtForFrame)
{
win32_state *State = &Global_Win32State;
{
if(State->EventArenaTemp.Arena)
{
EndTemporaryMemory(State->EventArenaTemp);
}
State->EventArenaTemp = BeginTemporaryMemory(State->EventArena);
}
ArenaClear(State->EventArena);
MSG Message;
while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE))
@ -722,7 +759,7 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i
{
HWND Window = CreateWindowEx(0,
WindowClass.lpszClassName,
"vn - July 2023 Build",
"vn - August 2023 Build",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,

View File

@ -11,7 +11,6 @@ struct win32_state
HWND Window;
memory_arena *EventArena;
temporary_memory EventArenaTemp;
platform_event_list EventList;
char EXEPath[512];

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

View File

@ -1,5 +1,6 @@
proc main
{
"Hello!";
"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;
}

9
data/ddlc.vns 100644
View File

@ -0,0 +1,9 @@
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.";
}

51
data/gpt.vns 100644
View File

@ -0,0 +1,51 @@
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;
}

34
data/japanese.vns 100644
View File

@ -0,0 +1,34 @@
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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.