Initial commit
commit
0c10dab363
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -0,0 +1,12 @@
|
|||
@echo off
|
||||
|
||||
set CommonCompilerOptions=/Zi /FC /nologo /DVN_INTERNAL=1 /DVN_SLOW=1 /Oi /W4 /WL /WX /wd4201 /wd4305 /wd4244 /wd4100 /wd4505
|
||||
|
||||
pushd "../build/"
|
||||
|
||||
REM cl %CommonCompilerOptions% ../code/gen.cpp
|
||||
REM gen.exe
|
||||
|
||||
cl %CommonCompilerOptions% ../code/vn.cpp /LD /link /export:VN_UpdateAndRender /incremental:no
|
||||
cl %CommonCompilerOptions% ../code/win32_main.cpp /link user32.lib gdi32.lib winmm.lib opengl32.lib
|
||||
popd
|
|
@ -0,0 +1,15 @@
|
|||
#include "vn_core.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0]))
|
||||
|
||||
#include "gen_opengl.cpp"
|
||||
#include "gen_ui.cpp"
|
||||
|
||||
int main(int ArgumentCount, char **Arguments)
|
||||
{
|
||||
GenOpenGL();
|
||||
GenUI();
|
||||
|
||||
return(0);
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
struct opengl_function
|
||||
{
|
||||
char *Name;
|
||||
char *Type;
|
||||
char *Arguments;
|
||||
};
|
||||
|
||||
struct opengl_function OpenGLFunctionEntries[] =
|
||||
{
|
||||
{"BindTexture", "void", "GLenum target, GLuint texture"},
|
||||
{"BlendFunc", "void", "GLenum sfactor, GLenum dfactor"},
|
||||
{"Clear", "void", "GLbitfield mask"},
|
||||
{"ClearAccum", "void", "GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha"},
|
||||
{"ClearColor", "void", "GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha"},
|
||||
{"ClearDepth", "void", "GLclampd depth"},
|
||||
{"ClearIndex", "void", "GLfloat c"},
|
||||
{"ClearStencil", "void", "GLint s"},
|
||||
{"ClipPlane", "void", "GLenum plane, const GLdouble *equation"},
|
||||
{"CullFace", "void", "GLenum mode"},
|
||||
{"DeleteTextures", "void", "GLsizei n, const GLuint *textures"},
|
||||
{"Disable", "void", "GLenum cap"},
|
||||
{"DrawArrays", "void", "GLenum mode, GLint first, GLsizei count"},
|
||||
{"DrawBuffer", "void", "GLenum mode"},
|
||||
{"DrawElements", "void", "GLenum mode, GLsizei count, GLenum type, const GLvoid *indices"},
|
||||
{"DrawArraysInstanced", "void", "GLenum mode, GLint first, GLsizei count, GLsizei instancecount"},
|
||||
{"Enable", "void", "GLenum cap"},
|
||||
{"GenTextures", "void", "GLsizei n, GLuint *textures"},
|
||||
{"GetClipPlane", "void", "GLenum plane, GLdouble *equation"},
|
||||
{"GetDoublev", "void", "GLenum pname, GLdouble *params"},
|
||||
{"GetError", "GLenum", "void"},
|
||||
{"GetFloatv", "void", "GLenum pname, GLfloat *params"},
|
||||
{"GetIntegerv", "void", "GLenum pname, GLint *params"},
|
||||
{"GetPointerv", "void", "GLenum pname, GLvoid* *params"},
|
||||
{"GetString", "const GLubyte *", "GLenum name"},
|
||||
{"GetTexEnvfv", "void", "GLenum target, GLenum pname, GLfloat *params"},
|
||||
{"GetTexEnviv", "void", "GLenum target, GLenum pname, GLint *params"},
|
||||
{"GetTexGendv", "void", "GLenum coord, GLenum pname, GLdouble *params"},
|
||||
{"GetTexGenfv", "void", "GLenum coord, GLenum pname, GLfloat *params"},
|
||||
{"GetTexGeniv", "void", "GLenum coord, GLenum pname, GLint *params"},
|
||||
{"GetTexImage", "void", "GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels"},
|
||||
{"GetTexLevelParameterfv", "void", "GLenum target, GLint level, GLenum pname, GLfloat *params"},
|
||||
{"GetTexLevelParameteriv", "void", "GLenum target, GLint level, GLenum pname, GLint *params"},
|
||||
{"GetTexParameterfv", "void", "GLenum target, GLenum pname, GLfloat *params"},
|
||||
{"GetTexParameteriv", "void", "GLenum target, GLenum pname, GLint *params"},
|
||||
{"Hint", "void", "GLenum target, GLenum mode"},
|
||||
{"IsTexture", "GLboolean", "GLuint texture"},
|
||||
{"LineWidth", "void", "GLfloat width"},
|
||||
{"ListBase", "void", "GLuint base"},
|
||||
{"LoadName", "void", "GLuint name"},
|
||||
{"LogicOp", "void", "GLenum opcode"},
|
||||
{"PointSize", "void", "GLfloat size"},
|
||||
{"PolygonMode", "void", "GLenum face, GLenum mode"},
|
||||
{"Scissor", "void", "GLint x, GLint y, GLsizei width, GLsizei height"},
|
||||
{"TexImage1D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels"},
|
||||
{"TexImage2D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels"},
|
||||
{"TexParameterf", "void", "GLenum target, GLenum pname, GLfloat param"},
|
||||
{"TexParameterfv", "void", "GLenum target, GLenum pname, const GLfloat *params"},
|
||||
{"TexParameteri", "void", "GLenum target, GLenum pname, GLint param"},
|
||||
{"TexParameteriv", "void", "GLenum target, GLenum pname, const GLint *params"},
|
||||
{"TexSubImage1D", "void", "GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels"},
|
||||
{"TexSubImage2D", "void", "GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels"},
|
||||
{"CompressedTexImage2D", "void", "GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels"},
|
||||
{"ActiveTexture", "void", "GLenum texture"},
|
||||
{"Viewport", "void", "GLint x, GLint y, GLsizei width, GLsizei height"},
|
||||
{"GenBuffers", "void", "GLsizei n, GLuint *buffers"},
|
||||
{"BindBuffer", "void", "GLenum target, GLuint buffer"},
|
||||
{"BufferData", "void", "GLenum target, GLsizeiptr size, const void *data, GLenum usage"},
|
||||
{"BufferSubData", "void", "GLenum target, GLintptr offset, GLsizeiptr size, const void *data"},
|
||||
{"GenVertexArrays", "void", "GLsizei n, GLuint *arrays"},
|
||||
{"BindVertexArray", "void", "GLenum array"},
|
||||
{"GetAttribLocation", "GLint", "GLuint program, const GLchar *name"},
|
||||
{"EnableVertexAttribArray", "void", "GLuint index"},
|
||||
{"DisableVertexAttribArray", "void", "GLuint index"},
|
||||
{"VertexAttribPointer", "void", "GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer"},
|
||||
{"VertexAttribIPointer", "void", "GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer"},
|
||||
{"VertexAttribLPointer", "void", "GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer"},
|
||||
{"VertexAttribDivisor", "void", "GLuint index, GLuint divisor"},
|
||||
{"CreateShader", "GLuint", "GLenum type"},
|
||||
{"ShaderSource", "void", "GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length"},
|
||||
{"CompileShader", "void", "GLuint shader"},
|
||||
{"DeleteShader", "void", "GLuint shader"},
|
||||
{"GetShaderiv", "void", "GLuint shader, GLenum pname, GLint *params"},
|
||||
{"GetShaderInfoLog", "void", "GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog"},
|
||||
{"CreateProgram", "GLuint", "void"},
|
||||
{"UseProgram", "void", "GLuint program"},
|
||||
{"AttachShader", "void", "GLuint program, GLuint shader"},
|
||||
{"DeleteProgram", "void", "GLuint program"},
|
||||
{"LinkProgram", "void", "GLuint program"},
|
||||
{"GetProgramiv", "void", "GLuint program, GLenum pname, GLint *params"},
|
||||
{"GetProgramInfoLog", "void", "GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog"},
|
||||
{"GetUniformLocation", "GLint", "GLuint program, const GLchar *name"},
|
||||
{"Uniform1i", "void", "GLint location, GLint v0"},
|
||||
{"Uniform2f", "void", "GLint location, GLfloat v0, GLfloat v1"},
|
||||
{"Uniform3f", "void", "GLint location, GLfloat v0, GLfloat v1, GLfloat v2"},
|
||||
{"UniformMatrix4fv", "void", "GLint location, GLsizei count, GLboolean transpose, const GLfloat *value"},
|
||||
{"DebugMessageCallback", "void", "void (*)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar *, const void *), const void *userParam"},
|
||||
};
|
||||
|
||||
static void GenOpenGL(void)
|
||||
{
|
||||
FILE *Out = fopen("../code/generated/vn_opengl_functions.h", "wb");
|
||||
if(Out)
|
||||
{
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(OpenGLFunctionEntries);
|
||||
++Index)
|
||||
{
|
||||
struct opengl_function *Function = OpenGLFunctionEntries + Index;
|
||||
fprintf(Out, "typedef %s opengl_%s(%s);\n", Function->Type, Function->Name, Function->Arguments);
|
||||
}
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(OpenGLFunctionEntries);
|
||||
++Index)
|
||||
{
|
||||
struct opengl_function *Function = OpenGLFunctionEntries + Index;
|
||||
fprintf(Out, "global opengl_%s *gl%s = 0;\n", Function->Name, Function->Name);
|
||||
}
|
||||
|
||||
fprintf(Out, "\n");
|
||||
fprintf(Out, "extern void *OpenGL_LoadFunction(char *);\n");
|
||||
fprintf(Out, "\n");
|
||||
fprintf(Out, "static void OpenGL_LoadAllFunctions(void)\n");
|
||||
fprintf(Out, "{\n");
|
||||
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(OpenGLFunctionEntries);
|
||||
++Index)
|
||||
{
|
||||
struct opengl_function *Function = OpenGLFunctionEntries + Index;
|
||||
fprintf(Out, "\tgl%s = (opengl_%s *)OpenGL_LoadFunction(\"gl%s\");\n", Function->Name, Function->Name, Function->Name);
|
||||
}
|
||||
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fclose(Out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
struct ui_style_stack
|
||||
{
|
||||
char *Name;
|
||||
char *Type;
|
||||
char *MemberName;
|
||||
};
|
||||
|
||||
ui_style_stack UIStyleStacks[] =
|
||||
{
|
||||
{ "Parent", "ui_box *", "Parent" },
|
||||
{ "Width", "ui_size", "SemanticSize[Axis2_X]" },
|
||||
{ "Height", "ui_size", "SemanticSize[Axis2_Y]" },
|
||||
{ "FixedX", "r32", "FixedP.E[Axis2_X]" },
|
||||
{ "FixedY", "r32", "FixedP.E[Axis2_Y]" },
|
||||
{ "TextColor", "v4", "TextColor" },
|
||||
{ "BackgroundColor", "v4", "BackgroundColor" },
|
||||
{ "BorderColor", "v4", "BorderColor" },
|
||||
{ "BorderThickness", "r32", "BorderThickness" },
|
||||
{ "LayoutAxis", "axis2", "LayoutAxis" },
|
||||
{ "CornerRadius", "r32", "CornerRadius" },
|
||||
{ "Font", "font_id", "Font" },
|
||||
{ "FontSize", "r32", "FontSize" },
|
||||
};
|
||||
|
||||
static void GenUI(void)
|
||||
{
|
||||
FILE *Out = fopen("../code/generated/vn_generated_ui.h", "wb");
|
||||
if(Out)
|
||||
{
|
||||
fprintf(Out, "struct ui_style_stacks\n");
|
||||
fprintf(Out, "{\n");
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(UIStyleStacks);
|
||||
++Index)
|
||||
{
|
||||
ui_style_stack Stack = UIStyleStacks[Index];
|
||||
fprintf(Out, "\t%s %sStack[64];\n", Stack.Type, Stack.Name);
|
||||
fprintf(Out, "\ts32 %sStackUsed;\n", Stack.Name);
|
||||
fprintf(Out, "\tb32 AutoPop%s;\n", Stack.Name);
|
||||
}
|
||||
fprintf(Out, "};\n");
|
||||
fclose(Out);
|
||||
}
|
||||
|
||||
Out = fopen("../code/generated/vn_generated_ui.cpp", "wb");
|
||||
if(Out)
|
||||
{
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(UIStyleStacks);
|
||||
++Index)
|
||||
{
|
||||
ui_style_stack Stack = UIStyleStacks[Index];
|
||||
fprintf(Out, "inline void UI_Push%s(%s Element)\n", Stack.Name, Stack.Type);
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed + 1 < ArrayCount(UI->Stacks.%sStack));\n", Stack.Name, Stack.Name);
|
||||
fprintf(Out, "\tUI->Stacks.%sStack[UI->Stacks.%sStackUsed++] = Element;\n", Stack.Name, Stack.Name);
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "inline void UI_Pop%s(void)\n", Stack.Name);
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed > 0);\n", Stack.Name);
|
||||
fprintf(Out, "\t--UI->Stacks.%sStackUsed;\n", Stack.Name, Stack.Name);
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "inline void UI_SetNext%s(%s Element)\n", Stack.Name, Stack.Type);
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
fprintf(Out, "\tUI_Push%s(Element);\n", Stack.Name);
|
||||
fprintf(Out, "\tUI->Stacks.AutoPop%s = true;\n", Stack.Name);
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "inline %s UI_First%s(void)\n", Stack.Type, Stack.Name);
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
fprintf(Out, "\treturn(UI->Stacks.%sStack[0]);\n", Stack.Name);
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "inline %s UI_Top%s(void)\n", Stack.Type, Stack.Name);
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
fprintf(Out, "\treturn(UI->Stacks.%sStack[UI->Stacks.%sStackUsed - 1]);\n", Stack.Name, Stack.Name);
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "#define UI_%s(Element) DeferLoop(UI_Push%s(Element), UI_Pop%s())\n",
|
||||
Stack.Name, Stack.Name, Stack.Name);
|
||||
|
||||
fprintf(Out, "\n");
|
||||
}
|
||||
|
||||
fprintf(Out, "\n");
|
||||
|
||||
fprintf(Out, "inline void UI_ApplyStyles(ui_box *Box)\n");
|
||||
fprintf(Out, "{\n");
|
||||
fprintf(Out, "\tui *UI = UI_GetState();\n");
|
||||
for(s32 Index = 0;
|
||||
Index < ArrayCount(UIStyleStacks);
|
||||
++Index)
|
||||
{
|
||||
ui_style_stack Stack = UIStyleStacks[Index];
|
||||
fprintf(Out, "\tAssert(UI->Stacks.%sStackUsed > 0);\n", Stack.Name);
|
||||
fprintf(Out, "\tBox->%s = UI->Stacks.%sStack[UI->Stacks.%sStackUsed - 1];\n",
|
||||
Stack.MemberName, Stack.Name, Stack.Name);
|
||||
fprintf(Out, "\tif(UI->Stacks.AutoPop%s)\n", Stack.Name);
|
||||
fprintf(Out, "\t{\n");
|
||||
fprintf(Out, "\t\tUI_Pop%s();\n", Stack.Name);
|
||||
fprintf(Out, "\t\tUI->Stacks.AutoPop%s = false;\n", Stack.Name);
|
||||
fprintf(Out, "\t}\n\n");
|
||||
}
|
||||
|
||||
fprintf(Out, "}\n");
|
||||
|
||||
|
||||
fclose(Out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,564 @@
|
|||
inline void UI_PushParent(ui_box * Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.ParentStackUsed + 1 < ArrayCount(UI->Stacks.ParentStack));
|
||||
UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopParent(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.ParentStackUsed > 0);
|
||||
--UI->Stacks.ParentStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextParent(ui_box * Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushParent(Element);
|
||||
UI->Stacks.AutoPopParent = true;
|
||||
}
|
||||
|
||||
inline ui_box * UI_FirstParent(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.ParentStack[0]);
|
||||
}
|
||||
|
||||
inline ui_box * UI_TopParent(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_Parent(Element) DeferLoop(UI_PushParent(Element), UI_PopParent())
|
||||
|
||||
inline void UI_PushWidth(ui_size Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.WidthStackUsed + 1 < ArrayCount(UI->Stacks.WidthStack));
|
||||
UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopWidth(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.WidthStackUsed > 0);
|
||||
--UI->Stacks.WidthStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextWidth(ui_size Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushWidth(Element);
|
||||
UI->Stacks.AutoPopWidth = true;
|
||||
}
|
||||
|
||||
inline ui_size UI_FirstWidth(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.WidthStack[0]);
|
||||
}
|
||||
|
||||
inline ui_size UI_TopWidth(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_Width(Element) DeferLoop(UI_PushWidth(Element), UI_PopWidth())
|
||||
|
||||
inline void UI_PushHeight(ui_size Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.HeightStackUsed + 1 < ArrayCount(UI->Stacks.HeightStack));
|
||||
UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopHeight(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.HeightStackUsed > 0);
|
||||
--UI->Stacks.HeightStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextHeight(ui_size Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushHeight(Element);
|
||||
UI->Stacks.AutoPopHeight = true;
|
||||
}
|
||||
|
||||
inline ui_size UI_FirstHeight(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.HeightStack[0]);
|
||||
}
|
||||
|
||||
inline ui_size UI_TopHeight(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_Height(Element) DeferLoop(UI_PushHeight(Element), UI_PopHeight())
|
||||
|
||||
inline void UI_PushFixedX(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FixedXStackUsed + 1 < ArrayCount(UI->Stacks.FixedXStack));
|
||||
UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopFixedX(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FixedXStackUsed > 0);
|
||||
--UI->Stacks.FixedXStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextFixedX(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushFixedX(Element);
|
||||
UI->Stacks.AutoPopFixedX = true;
|
||||
}
|
||||
|
||||
inline r32 UI_FirstFixedX(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FixedXStack[0]);
|
||||
}
|
||||
|
||||
inline r32 UI_TopFixedX(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_FixedX(Element) DeferLoop(UI_PushFixedX(Element), UI_PopFixedX())
|
||||
|
||||
inline void UI_PushFixedY(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FixedYStackUsed + 1 < ArrayCount(UI->Stacks.FixedYStack));
|
||||
UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopFixedY(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FixedYStackUsed > 0);
|
||||
--UI->Stacks.FixedYStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextFixedY(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushFixedY(Element);
|
||||
UI->Stacks.AutoPopFixedY = true;
|
||||
}
|
||||
|
||||
inline r32 UI_FirstFixedY(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FixedYStack[0]);
|
||||
}
|
||||
|
||||
inline r32 UI_TopFixedY(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_FixedY(Element) DeferLoop(UI_PushFixedY(Element), UI_PopFixedY())
|
||||
|
||||
inline void UI_PushTextColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.TextColorStackUsed + 1 < ArrayCount(UI->Stacks.TextColorStack));
|
||||
UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopTextColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.TextColorStackUsed > 0);
|
||||
--UI->Stacks.TextColorStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextTextColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushTextColor(Element);
|
||||
UI->Stacks.AutoPopTextColor = true;
|
||||
}
|
||||
|
||||
inline v4 UI_FirstTextColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.TextColorStack[0]);
|
||||
}
|
||||
|
||||
inline v4 UI_TopTextColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_TextColor(Element) DeferLoop(UI_PushTextColor(Element), UI_PopTextColor())
|
||||
|
||||
inline void UI_PushBackgroundColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BackgroundColorStackUsed + 1 < ArrayCount(UI->Stacks.BackgroundColorStack));
|
||||
UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopBackgroundColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BackgroundColorStackUsed > 0);
|
||||
--UI->Stacks.BackgroundColorStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextBackgroundColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushBackgroundColor(Element);
|
||||
UI->Stacks.AutoPopBackgroundColor = true;
|
||||
}
|
||||
|
||||
inline v4 UI_FirstBackgroundColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BackgroundColorStack[0]);
|
||||
}
|
||||
|
||||
inline v4 UI_TopBackgroundColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_BackgroundColor(Element) DeferLoop(UI_PushBackgroundColor(Element), UI_PopBackgroundColor())
|
||||
|
||||
inline void UI_PushBorderColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BorderColorStackUsed + 1 < ArrayCount(UI->Stacks.BorderColorStack));
|
||||
UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopBorderColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BorderColorStackUsed > 0);
|
||||
--UI->Stacks.BorderColorStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextBorderColor(v4 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushBorderColor(Element);
|
||||
UI->Stacks.AutoPopBorderColor = true;
|
||||
}
|
||||
|
||||
inline v4 UI_FirstBorderColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BorderColorStack[0]);
|
||||
}
|
||||
|
||||
inline v4 UI_TopBorderColor(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_BorderColor(Element) DeferLoop(UI_PushBorderColor(Element), UI_PopBorderColor())
|
||||
|
||||
inline void UI_PushBorderThickness(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BorderThicknessStackUsed + 1 < ArrayCount(UI->Stacks.BorderThicknessStack));
|
||||
UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopBorderThickness(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.BorderThicknessStackUsed > 0);
|
||||
--UI->Stacks.BorderThicknessStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextBorderThickness(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushBorderThickness(Element);
|
||||
UI->Stacks.AutoPopBorderThickness = true;
|
||||
}
|
||||
|
||||
inline r32 UI_FirstBorderThickness(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BorderThicknessStack[0]);
|
||||
}
|
||||
|
||||
inline r32 UI_TopBorderThickness(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_BorderThickness(Element) DeferLoop(UI_PushBorderThickness(Element), UI_PopBorderThickness())
|
||||
|
||||
inline void UI_PushLayoutAxis(axis2 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.LayoutAxisStackUsed + 1 < ArrayCount(UI->Stacks.LayoutAxisStack));
|
||||
UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopLayoutAxis(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.LayoutAxisStackUsed > 0);
|
||||
--UI->Stacks.LayoutAxisStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextLayoutAxis(axis2 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushLayoutAxis(Element);
|
||||
UI->Stacks.AutoPopLayoutAxis = true;
|
||||
}
|
||||
|
||||
inline axis2 UI_FirstLayoutAxis(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.LayoutAxisStack[0]);
|
||||
}
|
||||
|
||||
inline axis2 UI_TopLayoutAxis(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_LayoutAxis(Element) DeferLoop(UI_PushLayoutAxis(Element), UI_PopLayoutAxis())
|
||||
|
||||
inline void UI_PushCornerRadius(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.CornerRadiusStackUsed + 1 < ArrayCount(UI->Stacks.CornerRadiusStack));
|
||||
UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopCornerRadius(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.CornerRadiusStackUsed > 0);
|
||||
--UI->Stacks.CornerRadiusStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextCornerRadius(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushCornerRadius(Element);
|
||||
UI->Stacks.AutoPopCornerRadius = true;
|
||||
}
|
||||
|
||||
inline r32 UI_FirstCornerRadius(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.CornerRadiusStack[0]);
|
||||
}
|
||||
|
||||
inline r32 UI_TopCornerRadius(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_CornerRadius(Element) DeferLoop(UI_PushCornerRadius(Element), UI_PopCornerRadius())
|
||||
|
||||
inline void UI_PushFont(font_id Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FontStackUsed + 1 < ArrayCount(UI->Stacks.FontStack));
|
||||
UI->Stacks.FontStack[UI->Stacks.FontStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopFont(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FontStackUsed > 0);
|
||||
--UI->Stacks.FontStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextFont(font_id Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushFont(Element);
|
||||
UI->Stacks.AutoPopFont = true;
|
||||
}
|
||||
|
||||
inline font_id UI_FirstFont(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FontStack[0]);
|
||||
}
|
||||
|
||||
inline font_id UI_TopFont(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_Font(Element) DeferLoop(UI_PushFont(Element), UI_PopFont())
|
||||
|
||||
inline void UI_PushFontSize(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FontSizeStackUsed + 1 < ArrayCount(UI->Stacks.FontSizeStack));
|
||||
UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed++] = Element;
|
||||
}
|
||||
|
||||
inline void UI_PopFontSize(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.FontSizeStackUsed > 0);
|
||||
--UI->Stacks.FontSizeStackUsed;
|
||||
}
|
||||
|
||||
inline void UI_SetNextFontSize(r32 Element)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushFontSize(Element);
|
||||
UI->Stacks.AutoPopFontSize = true;
|
||||
}
|
||||
|
||||
inline r32 UI_FirstFontSize(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FontSizeStack[0]);
|
||||
}
|
||||
|
||||
inline r32 UI_TopFontSize(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1]);
|
||||
}
|
||||
|
||||
#define UI_FontSize(Element) DeferLoop(UI_PushFontSize(Element), UI_PopFontSize())
|
||||
|
||||
|
||||
inline void UI_ApplyStyles(ui_box *Box)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Assert(UI->Stacks.ParentStackUsed > 0);
|
||||
Box->Parent = UI->Stacks.ParentStack[UI->Stacks.ParentStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopParent)
|
||||
{
|
||||
UI_PopParent();
|
||||
UI->Stacks.AutoPopParent = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.WidthStackUsed > 0);
|
||||
Box->SemanticSize[Axis2_X] = UI->Stacks.WidthStack[UI->Stacks.WidthStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopWidth)
|
||||
{
|
||||
UI_PopWidth();
|
||||
UI->Stacks.AutoPopWidth = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.HeightStackUsed > 0);
|
||||
Box->SemanticSize[Axis2_Y] = UI->Stacks.HeightStack[UI->Stacks.HeightStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopHeight)
|
||||
{
|
||||
UI_PopHeight();
|
||||
UI->Stacks.AutoPopHeight = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.FixedXStackUsed > 0);
|
||||
Box->FixedP.E[Axis2_X] = UI->Stacks.FixedXStack[UI->Stacks.FixedXStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopFixedX)
|
||||
{
|
||||
UI_PopFixedX();
|
||||
UI->Stacks.AutoPopFixedX = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.FixedYStackUsed > 0);
|
||||
Box->FixedP.E[Axis2_Y] = UI->Stacks.FixedYStack[UI->Stacks.FixedYStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopFixedY)
|
||||
{
|
||||
UI_PopFixedY();
|
||||
UI->Stacks.AutoPopFixedY = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.TextColorStackUsed > 0);
|
||||
Box->TextColor = UI->Stacks.TextColorStack[UI->Stacks.TextColorStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopTextColor)
|
||||
{
|
||||
UI_PopTextColor();
|
||||
UI->Stacks.AutoPopTextColor = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.BackgroundColorStackUsed > 0);
|
||||
Box->BackgroundColor = UI->Stacks.BackgroundColorStack[UI->Stacks.BackgroundColorStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopBackgroundColor)
|
||||
{
|
||||
UI_PopBackgroundColor();
|
||||
UI->Stacks.AutoPopBackgroundColor = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.BorderColorStackUsed > 0);
|
||||
Box->BorderColor = UI->Stacks.BorderColorStack[UI->Stacks.BorderColorStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopBorderColor)
|
||||
{
|
||||
UI_PopBorderColor();
|
||||
UI->Stacks.AutoPopBorderColor = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.BorderThicknessStackUsed > 0);
|
||||
Box->BorderThickness = UI->Stacks.BorderThicknessStack[UI->Stacks.BorderThicknessStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopBorderThickness)
|
||||
{
|
||||
UI_PopBorderThickness();
|
||||
UI->Stacks.AutoPopBorderThickness = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.LayoutAxisStackUsed > 0);
|
||||
Box->LayoutAxis = UI->Stacks.LayoutAxisStack[UI->Stacks.LayoutAxisStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopLayoutAxis)
|
||||
{
|
||||
UI_PopLayoutAxis();
|
||||
UI->Stacks.AutoPopLayoutAxis = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.CornerRadiusStackUsed > 0);
|
||||
Box->CornerRadius = UI->Stacks.CornerRadiusStack[UI->Stacks.CornerRadiusStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopCornerRadius)
|
||||
{
|
||||
UI_PopCornerRadius();
|
||||
UI->Stacks.AutoPopCornerRadius = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.FontStackUsed > 0);
|
||||
Box->Font = UI->Stacks.FontStack[UI->Stacks.FontStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopFont)
|
||||
{
|
||||
UI_PopFont();
|
||||
UI->Stacks.AutoPopFont = false;
|
||||
}
|
||||
|
||||
Assert(UI->Stacks.FontSizeStackUsed > 0);
|
||||
Box->FontSize = UI->Stacks.FontSizeStack[UI->Stacks.FontSizeStackUsed - 1];
|
||||
if(UI->Stacks.AutoPopFontSize)
|
||||
{
|
||||
UI_PopFontSize();
|
||||
UI->Stacks.AutoPopFontSize = false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
struct ui_style_stacks
|
||||
{
|
||||
ui_box * ParentStack[64];
|
||||
s32 ParentStackUsed;
|
||||
b32 AutoPopParent;
|
||||
ui_size WidthStack[64];
|
||||
s32 WidthStackUsed;
|
||||
b32 AutoPopWidth;
|
||||
ui_size HeightStack[64];
|
||||
s32 HeightStackUsed;
|
||||
b32 AutoPopHeight;
|
||||
r32 FixedXStack[64];
|
||||
s32 FixedXStackUsed;
|
||||
b32 AutoPopFixedX;
|
||||
r32 FixedYStack[64];
|
||||
s32 FixedYStackUsed;
|
||||
b32 AutoPopFixedY;
|
||||
v4 TextColorStack[64];
|
||||
s32 TextColorStackUsed;
|
||||
b32 AutoPopTextColor;
|
||||
v4 BackgroundColorStack[64];
|
||||
s32 BackgroundColorStackUsed;
|
||||
b32 AutoPopBackgroundColor;
|
||||
v4 BorderColorStack[64];
|
||||
s32 BorderColorStackUsed;
|
||||
b32 AutoPopBorderColor;
|
||||
r32 BorderThicknessStack[64];
|
||||
s32 BorderThicknessStackUsed;
|
||||
b32 AutoPopBorderThickness;
|
||||
axis2 LayoutAxisStack[64];
|
||||
s32 LayoutAxisStackUsed;
|
||||
b32 AutoPopLayoutAxis;
|
||||
r32 CornerRadiusStack[64];
|
||||
s32 CornerRadiusStackUsed;
|
||||
b32 AutoPopCornerRadius;
|
||||
font_id FontStack[64];
|
||||
s32 FontStackUsed;
|
||||
b32 AutoPopFont;
|
||||
r32 FontSizeStack[64];
|
||||
s32 FontSizeStackUsed;
|
||||
b32 AutoPopFontSize;
|
||||
};
|
|
@ -0,0 +1,268 @@
|
|||
typedef void opengl_BindTexture(GLenum target, GLuint texture);
|
||||
typedef void opengl_BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
typedef void opengl_Clear(GLbitfield mask);
|
||||
typedef void opengl_ClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
typedef void opengl_ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
typedef void opengl_ClearDepth(GLclampd depth);
|
||||
typedef void opengl_ClearIndex(GLfloat c);
|
||||
typedef void opengl_ClearStencil(GLint s);
|
||||
typedef void opengl_ClipPlane(GLenum plane, const GLdouble *equation);
|
||||
typedef void opengl_CullFace(GLenum mode);
|
||||
typedef void opengl_DeleteTextures(GLsizei n, const GLuint *textures);
|
||||
typedef void opengl_Disable(GLenum cap);
|
||||
typedef void opengl_DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
typedef void opengl_DrawBuffer(GLenum mode);
|
||||
typedef void opengl_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
|
||||
typedef void opengl_DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
typedef void opengl_Enable(GLenum cap);
|
||||
typedef void opengl_GenTextures(GLsizei n, GLuint *textures);
|
||||
typedef void opengl_GetClipPlane(GLenum plane, GLdouble *equation);
|
||||
typedef void opengl_GetDoublev(GLenum pname, GLdouble *params);
|
||||
typedef GLenum opengl_GetError(void);
|
||||
typedef void opengl_GetFloatv(GLenum pname, GLfloat *params);
|
||||
typedef void opengl_GetIntegerv(GLenum pname, GLint *params);
|
||||
typedef void opengl_GetPointerv(GLenum pname, GLvoid* *params);
|
||||
typedef const GLubyte * opengl_GetString(GLenum name);
|
||||
typedef void opengl_GetTexEnvfv(GLenum target, GLenum pname, GLfloat *params);
|
||||
typedef void opengl_GetTexEnviv(GLenum target, GLenum pname, GLint *params);
|
||||
typedef void opengl_GetTexGendv(GLenum coord, GLenum pname, GLdouble *params);
|
||||
typedef void opengl_GetTexGenfv(GLenum coord, GLenum pname, GLfloat *params);
|
||||
typedef void opengl_GetTexGeniv(GLenum coord, GLenum pname, GLint *params);
|
||||
typedef void opengl_GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
|
||||
typedef void opengl_GetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params);
|
||||
typedef void opengl_GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params);
|
||||
typedef void opengl_GetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
|
||||
typedef void opengl_GetTexParameteriv(GLenum target, GLenum pname, GLint *params);
|
||||
typedef void opengl_Hint(GLenum target, GLenum mode);
|
||||
typedef GLboolean opengl_IsTexture(GLuint texture);
|
||||
typedef void opengl_LineWidth(GLfloat width);
|
||||
typedef void opengl_ListBase(GLuint base);
|
||||
typedef void opengl_LoadName(GLuint name);
|
||||
typedef void opengl_LogicOp(GLenum opcode);
|
||||
typedef void opengl_PointSize(GLfloat size);
|
||||
typedef void opengl_PolygonMode(GLenum face, GLenum mode);
|
||||
typedef void opengl_Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void opengl_TexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
typedef void opengl_TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
typedef void opengl_TexParameterf(GLenum target, GLenum pname, GLfloat param);
|
||||
typedef void opengl_TexParameterfv(GLenum target, GLenum pname, const GLfloat *params);
|
||||
typedef void opengl_TexParameteri(GLenum target, GLenum pname, GLint param);
|
||||
typedef void opengl_TexParameteriv(GLenum target, GLenum pname, const GLint *params);
|
||||
typedef void opengl_TexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
typedef void opengl_TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
typedef void opengl_CompressedTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels);
|
||||
typedef void opengl_ActiveTexture(GLenum texture);
|
||||
typedef void opengl_Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void opengl_GenBuffers(GLsizei n, GLuint *buffers);
|
||||
typedef void opengl_BindBuffer(GLenum target, GLuint buffer);
|
||||
typedef void opengl_BufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
typedef void opengl_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
typedef void opengl_GenVertexArrays(GLsizei n, GLuint *arrays);
|
||||
typedef void opengl_BindVertexArray(GLenum array);
|
||||
typedef GLint opengl_GetAttribLocation(GLuint program, const GLchar *name);
|
||||
typedef void opengl_EnableVertexAttribArray(GLuint index);
|
||||
typedef void opengl_DisableVertexAttribArray(GLuint index);
|
||||
typedef void opengl_VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
typedef void opengl_VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);
|
||||
typedef void opengl_VertexAttribLPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);
|
||||
typedef void opengl_VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
typedef GLuint opengl_CreateShader(GLenum type);
|
||||
typedef void opengl_ShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef void opengl_CompileShader(GLuint shader);
|
||||
typedef void opengl_DeleteShader(GLuint shader);
|
||||
typedef void opengl_GetShaderiv(GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void opengl_GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLuint opengl_CreateProgram(void);
|
||||
typedef void opengl_UseProgram(GLuint program);
|
||||
typedef void opengl_AttachShader(GLuint program, GLuint shader);
|
||||
typedef void opengl_DeleteProgram(GLuint program);
|
||||
typedef void opengl_LinkProgram(GLuint program);
|
||||
typedef void opengl_GetProgramiv(GLuint program, GLenum pname, GLint *params);
|
||||
typedef void opengl_GetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLint opengl_GetUniformLocation(GLuint program, const GLchar *name);
|
||||
typedef void opengl_Uniform1i(GLint location, GLint v0);
|
||||
typedef void opengl_Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
typedef void opengl_Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
typedef void opengl_UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
typedef void opengl_DebugMessageCallback(void (*)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar *, const void *), const void *userParam);
|
||||
|
||||
global opengl_BindTexture *glBindTexture = 0;
|
||||
global opengl_BlendFunc *glBlendFunc = 0;
|
||||
global opengl_Clear *glClear = 0;
|
||||
global opengl_ClearAccum *glClearAccum = 0;
|
||||
global opengl_ClearColor *glClearColor = 0;
|
||||
global opengl_ClearDepth *glClearDepth = 0;
|
||||
global opengl_ClearIndex *glClearIndex = 0;
|
||||
global opengl_ClearStencil *glClearStencil = 0;
|
||||
global opengl_ClipPlane *glClipPlane = 0;
|
||||
global opengl_CullFace *glCullFace = 0;
|
||||
global opengl_DeleteTextures *glDeleteTextures = 0;
|
||||
global opengl_Disable *glDisable = 0;
|
||||
global opengl_DrawArrays *glDrawArrays = 0;
|
||||
global opengl_DrawBuffer *glDrawBuffer = 0;
|
||||
global opengl_DrawElements *glDrawElements = 0;
|
||||
global opengl_DrawArraysInstanced *glDrawArraysInstanced = 0;
|
||||
global opengl_Enable *glEnable = 0;
|
||||
global opengl_GenTextures *glGenTextures = 0;
|
||||
global opengl_GetClipPlane *glGetClipPlane = 0;
|
||||
global opengl_GetDoublev *glGetDoublev = 0;
|
||||
global opengl_GetError *glGetError = 0;
|
||||
global opengl_GetFloatv *glGetFloatv = 0;
|
||||
global opengl_GetIntegerv *glGetIntegerv = 0;
|
||||
global opengl_GetPointerv *glGetPointerv = 0;
|
||||
global opengl_GetString *glGetString = 0;
|
||||
global opengl_GetTexEnvfv *glGetTexEnvfv = 0;
|
||||
global opengl_GetTexEnviv *glGetTexEnviv = 0;
|
||||
global opengl_GetTexGendv *glGetTexGendv = 0;
|
||||
global opengl_GetTexGenfv *glGetTexGenfv = 0;
|
||||
global opengl_GetTexGeniv *glGetTexGeniv = 0;
|
||||
global opengl_GetTexImage *glGetTexImage = 0;
|
||||
global opengl_GetTexLevelParameterfv *glGetTexLevelParameterfv = 0;
|
||||
global opengl_GetTexLevelParameteriv *glGetTexLevelParameteriv = 0;
|
||||
global opengl_GetTexParameterfv *glGetTexParameterfv = 0;
|
||||
global opengl_GetTexParameteriv *glGetTexParameteriv = 0;
|
||||
global opengl_Hint *glHint = 0;
|
||||
global opengl_IsTexture *glIsTexture = 0;
|
||||
global opengl_LineWidth *glLineWidth = 0;
|
||||
global opengl_ListBase *glListBase = 0;
|
||||
global opengl_LoadName *glLoadName = 0;
|
||||
global opengl_LogicOp *glLogicOp = 0;
|
||||
global opengl_PointSize *glPointSize = 0;
|
||||
global opengl_PolygonMode *glPolygonMode = 0;
|
||||
global opengl_Scissor *glScissor = 0;
|
||||
global opengl_TexImage1D *glTexImage1D = 0;
|
||||
global opengl_TexImage2D *glTexImage2D = 0;
|
||||
global opengl_TexParameterf *glTexParameterf = 0;
|
||||
global opengl_TexParameterfv *glTexParameterfv = 0;
|
||||
global opengl_TexParameteri *glTexParameteri = 0;
|
||||
global opengl_TexParameteriv *glTexParameteriv = 0;
|
||||
global opengl_TexSubImage1D *glTexSubImage1D = 0;
|
||||
global opengl_TexSubImage2D *glTexSubImage2D = 0;
|
||||
global opengl_CompressedTexImage2D *glCompressedTexImage2D = 0;
|
||||
global opengl_ActiveTexture *glActiveTexture = 0;
|
||||
global opengl_Viewport *glViewport = 0;
|
||||
global opengl_GenBuffers *glGenBuffers = 0;
|
||||
global opengl_BindBuffer *glBindBuffer = 0;
|
||||
global opengl_BufferData *glBufferData = 0;
|
||||
global opengl_BufferSubData *glBufferSubData = 0;
|
||||
global opengl_GenVertexArrays *glGenVertexArrays = 0;
|
||||
global opengl_BindVertexArray *glBindVertexArray = 0;
|
||||
global opengl_GetAttribLocation *glGetAttribLocation = 0;
|
||||
global opengl_EnableVertexAttribArray *glEnableVertexAttribArray = 0;
|
||||
global opengl_DisableVertexAttribArray *glDisableVertexAttribArray = 0;
|
||||
global opengl_VertexAttribPointer *glVertexAttribPointer = 0;
|
||||
global opengl_VertexAttribIPointer *glVertexAttribIPointer = 0;
|
||||
global opengl_VertexAttribLPointer *glVertexAttribLPointer = 0;
|
||||
global opengl_VertexAttribDivisor *glVertexAttribDivisor = 0;
|
||||
global opengl_CreateShader *glCreateShader = 0;
|
||||
global opengl_ShaderSource *glShaderSource = 0;
|
||||
global opengl_CompileShader *glCompileShader = 0;
|
||||
global opengl_DeleteShader *glDeleteShader = 0;
|
||||
global opengl_GetShaderiv *glGetShaderiv = 0;
|
||||
global opengl_GetShaderInfoLog *glGetShaderInfoLog = 0;
|
||||
global opengl_CreateProgram *glCreateProgram = 0;
|
||||
global opengl_UseProgram *glUseProgram = 0;
|
||||
global opengl_AttachShader *glAttachShader = 0;
|
||||
global opengl_DeleteProgram *glDeleteProgram = 0;
|
||||
global opengl_LinkProgram *glLinkProgram = 0;
|
||||
global opengl_GetProgramiv *glGetProgramiv = 0;
|
||||
global opengl_GetProgramInfoLog *glGetProgramInfoLog = 0;
|
||||
global opengl_GetUniformLocation *glGetUniformLocation = 0;
|
||||
global opengl_Uniform1i *glUniform1i = 0;
|
||||
global opengl_Uniform2f *glUniform2f = 0;
|
||||
global opengl_Uniform3f *glUniform3f = 0;
|
||||
global opengl_UniformMatrix4fv *glUniformMatrix4fv = 0;
|
||||
global opengl_DebugMessageCallback *glDebugMessageCallback = 0;
|
||||
|
||||
extern void *OpenGL_LoadFunction(char *);
|
||||
|
||||
static void OpenGL_LoadAllFunctions(void)
|
||||
{
|
||||
glBindTexture = (opengl_BindTexture *)OpenGL_LoadFunction("glBindTexture");
|
||||
glBlendFunc = (opengl_BlendFunc *)OpenGL_LoadFunction("glBlendFunc");
|
||||
glClear = (opengl_Clear *)OpenGL_LoadFunction("glClear");
|
||||
glClearAccum = (opengl_ClearAccum *)OpenGL_LoadFunction("glClearAccum");
|
||||
glClearColor = (opengl_ClearColor *)OpenGL_LoadFunction("glClearColor");
|
||||
glClearDepth = (opengl_ClearDepth *)OpenGL_LoadFunction("glClearDepth");
|
||||
glClearIndex = (opengl_ClearIndex *)OpenGL_LoadFunction("glClearIndex");
|
||||
glClearStencil = (opengl_ClearStencil *)OpenGL_LoadFunction("glClearStencil");
|
||||
glClipPlane = (opengl_ClipPlane *)OpenGL_LoadFunction("glClipPlane");
|
||||
glCullFace = (opengl_CullFace *)OpenGL_LoadFunction("glCullFace");
|
||||
glDeleteTextures = (opengl_DeleteTextures *)OpenGL_LoadFunction("glDeleteTextures");
|
||||
glDisable = (opengl_Disable *)OpenGL_LoadFunction("glDisable");
|
||||
glDrawArrays = (opengl_DrawArrays *)OpenGL_LoadFunction("glDrawArrays");
|
||||
glDrawBuffer = (opengl_DrawBuffer *)OpenGL_LoadFunction("glDrawBuffer");
|
||||
glDrawElements = (opengl_DrawElements *)OpenGL_LoadFunction("glDrawElements");
|
||||
glDrawArraysInstanced = (opengl_DrawArraysInstanced *)OpenGL_LoadFunction("glDrawArraysInstanced");
|
||||
glEnable = (opengl_Enable *)OpenGL_LoadFunction("glEnable");
|
||||
glGenTextures = (opengl_GenTextures *)OpenGL_LoadFunction("glGenTextures");
|
||||
glGetClipPlane = (opengl_GetClipPlane *)OpenGL_LoadFunction("glGetClipPlane");
|
||||
glGetDoublev = (opengl_GetDoublev *)OpenGL_LoadFunction("glGetDoublev");
|
||||
glGetError = (opengl_GetError *)OpenGL_LoadFunction("glGetError");
|
||||
glGetFloatv = (opengl_GetFloatv *)OpenGL_LoadFunction("glGetFloatv");
|
||||
glGetIntegerv = (opengl_GetIntegerv *)OpenGL_LoadFunction("glGetIntegerv");
|
||||
glGetPointerv = (opengl_GetPointerv *)OpenGL_LoadFunction("glGetPointerv");
|
||||
glGetString = (opengl_GetString *)OpenGL_LoadFunction("glGetString");
|
||||
glGetTexEnvfv = (opengl_GetTexEnvfv *)OpenGL_LoadFunction("glGetTexEnvfv");
|
||||
glGetTexEnviv = (opengl_GetTexEnviv *)OpenGL_LoadFunction("glGetTexEnviv");
|
||||
glGetTexGendv = (opengl_GetTexGendv *)OpenGL_LoadFunction("glGetTexGendv");
|
||||
glGetTexGenfv = (opengl_GetTexGenfv *)OpenGL_LoadFunction("glGetTexGenfv");
|
||||
glGetTexGeniv = (opengl_GetTexGeniv *)OpenGL_LoadFunction("glGetTexGeniv");
|
||||
glGetTexImage = (opengl_GetTexImage *)OpenGL_LoadFunction("glGetTexImage");
|
||||
glGetTexLevelParameterfv = (opengl_GetTexLevelParameterfv *)OpenGL_LoadFunction("glGetTexLevelParameterfv");
|
||||
glGetTexLevelParameteriv = (opengl_GetTexLevelParameteriv *)OpenGL_LoadFunction("glGetTexLevelParameteriv");
|
||||
glGetTexParameterfv = (opengl_GetTexParameterfv *)OpenGL_LoadFunction("glGetTexParameterfv");
|
||||
glGetTexParameteriv = (opengl_GetTexParameteriv *)OpenGL_LoadFunction("glGetTexParameteriv");
|
||||
glHint = (opengl_Hint *)OpenGL_LoadFunction("glHint");
|
||||
glIsTexture = (opengl_IsTexture *)OpenGL_LoadFunction("glIsTexture");
|
||||
glLineWidth = (opengl_LineWidth *)OpenGL_LoadFunction("glLineWidth");
|
||||
glListBase = (opengl_ListBase *)OpenGL_LoadFunction("glListBase");
|
||||
glLoadName = (opengl_LoadName *)OpenGL_LoadFunction("glLoadName");
|
||||
glLogicOp = (opengl_LogicOp *)OpenGL_LoadFunction("glLogicOp");
|
||||
glPointSize = (opengl_PointSize *)OpenGL_LoadFunction("glPointSize");
|
||||
glPolygonMode = (opengl_PolygonMode *)OpenGL_LoadFunction("glPolygonMode");
|
||||
glScissor = (opengl_Scissor *)OpenGL_LoadFunction("glScissor");
|
||||
glTexImage1D = (opengl_TexImage1D *)OpenGL_LoadFunction("glTexImage1D");
|
||||
glTexImage2D = (opengl_TexImage2D *)OpenGL_LoadFunction("glTexImage2D");
|
||||
glTexParameterf = (opengl_TexParameterf *)OpenGL_LoadFunction("glTexParameterf");
|
||||
glTexParameterfv = (opengl_TexParameterfv *)OpenGL_LoadFunction("glTexParameterfv");
|
||||
glTexParameteri = (opengl_TexParameteri *)OpenGL_LoadFunction("glTexParameteri");
|
||||
glTexParameteriv = (opengl_TexParameteriv *)OpenGL_LoadFunction("glTexParameteriv");
|
||||
glTexSubImage1D = (opengl_TexSubImage1D *)OpenGL_LoadFunction("glTexSubImage1D");
|
||||
glTexSubImage2D = (opengl_TexSubImage2D *)OpenGL_LoadFunction("glTexSubImage2D");
|
||||
glCompressedTexImage2D = (opengl_CompressedTexImage2D *)OpenGL_LoadFunction("glCompressedTexImage2D");
|
||||
glActiveTexture = (opengl_ActiveTexture *)OpenGL_LoadFunction("glActiveTexture");
|
||||
glViewport = (opengl_Viewport *)OpenGL_LoadFunction("glViewport");
|
||||
glGenBuffers = (opengl_GenBuffers *)OpenGL_LoadFunction("glGenBuffers");
|
||||
glBindBuffer = (opengl_BindBuffer *)OpenGL_LoadFunction("glBindBuffer");
|
||||
glBufferData = (opengl_BufferData *)OpenGL_LoadFunction("glBufferData");
|
||||
glBufferSubData = (opengl_BufferSubData *)OpenGL_LoadFunction("glBufferSubData");
|
||||
glGenVertexArrays = (opengl_GenVertexArrays *)OpenGL_LoadFunction("glGenVertexArrays");
|
||||
glBindVertexArray = (opengl_BindVertexArray *)OpenGL_LoadFunction("glBindVertexArray");
|
||||
glGetAttribLocation = (opengl_GetAttribLocation *)OpenGL_LoadFunction("glGetAttribLocation");
|
||||
glEnableVertexAttribArray = (opengl_EnableVertexAttribArray *)OpenGL_LoadFunction("glEnableVertexAttribArray");
|
||||
glDisableVertexAttribArray = (opengl_DisableVertexAttribArray *)OpenGL_LoadFunction("glDisableVertexAttribArray");
|
||||
glVertexAttribPointer = (opengl_VertexAttribPointer *)OpenGL_LoadFunction("glVertexAttribPointer");
|
||||
glVertexAttribIPointer = (opengl_VertexAttribIPointer *)OpenGL_LoadFunction("glVertexAttribIPointer");
|
||||
glVertexAttribLPointer = (opengl_VertexAttribLPointer *)OpenGL_LoadFunction("glVertexAttribLPointer");
|
||||
glVertexAttribDivisor = (opengl_VertexAttribDivisor *)OpenGL_LoadFunction("glVertexAttribDivisor");
|
||||
glCreateShader = (opengl_CreateShader *)OpenGL_LoadFunction("glCreateShader");
|
||||
glShaderSource = (opengl_ShaderSource *)OpenGL_LoadFunction("glShaderSource");
|
||||
glCompileShader = (opengl_CompileShader *)OpenGL_LoadFunction("glCompileShader");
|
||||
glDeleteShader = (opengl_DeleteShader *)OpenGL_LoadFunction("glDeleteShader");
|
||||
glGetShaderiv = (opengl_GetShaderiv *)OpenGL_LoadFunction("glGetShaderiv");
|
||||
glGetShaderInfoLog = (opengl_GetShaderInfoLog *)OpenGL_LoadFunction("glGetShaderInfoLog");
|
||||
glCreateProgram = (opengl_CreateProgram *)OpenGL_LoadFunction("glCreateProgram");
|
||||
glUseProgram = (opengl_UseProgram *)OpenGL_LoadFunction("glUseProgram");
|
||||
glAttachShader = (opengl_AttachShader *)OpenGL_LoadFunction("glAttachShader");
|
||||
glDeleteProgram = (opengl_DeleteProgram *)OpenGL_LoadFunction("glDeleteProgram");
|
||||
glLinkProgram = (opengl_LinkProgram *)OpenGL_LoadFunction("glLinkProgram");
|
||||
glGetProgramiv = (opengl_GetProgramiv *)OpenGL_LoadFunction("glGetProgramiv");
|
||||
glGetProgramInfoLog = (opengl_GetProgramInfoLog *)OpenGL_LoadFunction("glGetProgramInfoLog");
|
||||
glGetUniformLocation = (opengl_GetUniformLocation *)OpenGL_LoadFunction("glGetUniformLocation");
|
||||
glUniform1i = (opengl_Uniform1i *)OpenGL_LoadFunction("glUniform1i");
|
||||
glUniform2f = (opengl_Uniform2f *)OpenGL_LoadFunction("glUniform2f");
|
||||
glUniform3f = (opengl_Uniform3f *)OpenGL_LoadFunction("glUniform3f");
|
||||
glUniformMatrix4fv = (opengl_UniformMatrix4fv *)OpenGL_LoadFunction("glUniformMatrix4fv");
|
||||
glDebugMessageCallback = (opengl_DebugMessageCallback *)OpenGL_LoadFunction("glDebugMessageCallback");
|
||||
}
|
|
@ -0,0 +1,537 @@
|
|||
// sixten: Functions implemented by the platform layer
|
||||
static void *OpenGL_AllocateMemory(umm Size);
|
||||
inline void *OpenGL_LoadFunction(char *Name);
|
||||
static void OpenGL_DeallocateMemory(void *Memory);
|
||||
|
||||
//- sixten: OpenGL Render Layer
|
||||
static void OpenGL_DebugMessageCallback(GLenum Source, GLenum Type, GLuint ID, GLenum Severity,
|
||||
GLsizei Length, const GLchar *Message, const void *UserParam)
|
||||
{
|
||||
if(Severity == GL_DEBUG_SEVERITY_HIGH)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
}
|
||||
|
||||
inline render_handle OpenGL_GetHandleFromTexture(opengl_texture Texture)
|
||||
{
|
||||
render_handle Result = {};
|
||||
Result.U32[0] = Texture.ID;
|
||||
Result.U32[1] = Texture.Format;
|
||||
Result.U32[2] = Texture.Dim.x;
|
||||
Result.U32[3] = Texture.Dim.y;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline opengl_texture OpenGL_GetTextureFromHandle(render_handle Handle)
|
||||
{
|
||||
opengl_texture Result = {};
|
||||
Result.ID = Handle.U32[0];
|
||||
Result.Format = (render_texture_format)Handle.U32[1];
|
||||
Result.Dim.x = Handle.U32[2];
|
||||
Result.Dim.y = Handle.U32[3];
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u32 OpenGL_GetInternalFormatFromTextureFormat(render_texture_format Format)
|
||||
{
|
||||
u32 InternalFormat = GL_INVALID_ENUM;
|
||||
|
||||
if(Format == Render_TextureFormat_R8)
|
||||
{
|
||||
InternalFormat = GL_RED;
|
||||
}
|
||||
else if(Format == Render_TextureFormat_RGB8)
|
||||
{
|
||||
InternalFormat = GL_RGB;
|
||||
}
|
||||
else if(Format == Render_TextureFormat_RGBA8)
|
||||
{
|
||||
InternalFormat = GL_RGBA;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidCodepath;
|
||||
}
|
||||
|
||||
return(InternalFormat);
|
||||
}
|
||||
|
||||
global GLint Global_OpenGL_SwizzleMaskR8[4] = {GL_ONE, GL_ONE, GL_ONE, GL_RED};
|
||||
global GLint Global_OpenGL_SwizzleMaskRGB8[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ONE};
|
||||
global GLint Global_OpenGL_SwizzleMaskRGBA8[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
|
||||
|
||||
inline GLint *OpenGL_GetSwizzleFromTextureFormat(render_texture_format Format)
|
||||
{
|
||||
GLint *Swizzle = 0;
|
||||
if(Format == Render_TextureFormat_R8)
|
||||
{
|
||||
Swizzle = Global_OpenGL_SwizzleMaskR8;
|
||||
}
|
||||
else if(Format == Render_TextureFormat_RGB8)
|
||||
{
|
||||
Swizzle = Global_OpenGL_SwizzleMaskRGB8;
|
||||
}
|
||||
else if(Format == Render_TextureFormat_RGBA8)
|
||||
{
|
||||
Swizzle = Global_OpenGL_SwizzleMaskRGBA8;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidCodepath;
|
||||
}
|
||||
|
||||
return(Swizzle);
|
||||
}
|
||||
|
||||
static RENDER_ALLOCATE_TEXTURE(OpenGL_AllocateTexture)
|
||||
{
|
||||
opengl_texture Texture = {};
|
||||
Texture.Dim = Dim;
|
||||
Texture.Format = Format;
|
||||
|
||||
glGenTextures(1, &Texture.ID);
|
||||
Assert(Texture.ID);
|
||||
|
||||
u32 InternalFormat = OpenGL_GetInternalFormatFromTextureFormat(Format);
|
||||
GLint *SwizzleMask = OpenGL_GetSwizzleFromTextureFormat(Format);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, Texture.ID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Dim.x, Dim.y, 0, InternalFormat, GL_UNSIGNED_BYTE, Data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, SwizzleMask);
|
||||
|
||||
render_handle Handle = OpenGL_GetHandleFromTexture(Texture);
|
||||
return(Handle);
|
||||
}
|
||||
|
||||
static RENDER_FILL_REGION(OpenGL_FillRegion)
|
||||
{
|
||||
opengl_texture Texture = OpenGL_GetTextureFromHandle(Handle);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, Texture.ID);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
DestP.x, DestP.y, DestDim.x, DestDim.y,
|
||||
OpenGL_GetInternalFormatFromTextureFormat(Texture.Format),
|
||||
GL_UNSIGNED_BYTE, Data);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
global char *OpenGL_ShaderHeader =
|
||||
R"GLSL(
|
||||
#version 330 core
|
||||
|
||||
#define s32 int
|
||||
#define u32 uint
|
||||
#define v2s ivec2
|
||||
#define v2u uvec2
|
||||
#define r32 float
|
||||
#define v2 vec2
|
||||
#define v3 vec3
|
||||
#define v4 vec4
|
||||
#define m4x4 mat4x4
|
||||
|
||||
#define V2 vec2
|
||||
#define V3 vec3
|
||||
#define V4 vec4
|
||||
|
||||
#define Min(a, b) min(a, b)
|
||||
#define Max(a, b) max(a, b)
|
||||
#define Clamp(x, min, max), clamp(x, min, max)
|
||||
#define Clamp01(x), Clamp(x, 0, 1)
|
||||
#define LinearBlend(A, B, C) mix(A, B, C)
|
||||
#define AbsoluteValue(x) abs(x)
|
||||
#define Length(x) length(x)
|
||||
#define Pow(x, y) pow(x, y)
|
||||
|
||||
)GLSL";
|
||||
|
||||
static u32 OpenGL_CompileShaderProgram(char *VertexSource, char *FragmentSource)
|
||||
{
|
||||
u32 Result = 0;
|
||||
|
||||
u32 VertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
char *VertexSources[] =
|
||||
{
|
||||
OpenGL_ShaderHeader,
|
||||
VertexSource
|
||||
};
|
||||
glShaderSource(VertexShader, ArrayCount(VertexSources), VertexSources, 0);
|
||||
glCompileShader(VertexShader);
|
||||
|
||||
s32 VertexCompilationStatus;
|
||||
glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &VertexCompilationStatus);
|
||||
if(VertexCompilationStatus)
|
||||
{
|
||||
u32 FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
char *FragmentSources[] =
|
||||
{
|
||||
OpenGL_ShaderHeader,
|
||||
FragmentSource
|
||||
};
|
||||
glShaderSource(FragmentShader, ArrayCount(FragmentSources), FragmentSources, 0);
|
||||
glCompileShader(FragmentShader);
|
||||
|
||||
s32 FragmentCompilationStatus;
|
||||
glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &FragmentCompilationStatus);
|
||||
if(FragmentCompilationStatus)
|
||||
{
|
||||
u32 Program = glCreateProgram();
|
||||
|
||||
glAttachShader(Program, VertexShader);
|
||||
glAttachShader(Program, FragmentShader);
|
||||
glLinkProgram(Program);
|
||||
|
||||
glDeleteShader(VertexShader);
|
||||
glDeleteShader(FragmentShader);
|
||||
|
||||
s32 ProgramLinkStatus;
|
||||
glGetProgramiv(Program, GL_LINK_STATUS, &ProgramLinkStatus);
|
||||
if(ProgramLinkStatus)
|
||||
{
|
||||
Result = Program;
|
||||
}
|
||||
else
|
||||
{
|
||||
char InfoLog[1024];
|
||||
glGetProgramInfoLog(Program, ArrayCount(InfoLog), 0, InfoLog);
|
||||
|
||||
InvalidCodepath;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char InfoLog[1024];
|
||||
glGetShaderInfoLog(FragmentShader, ArrayCount(InfoLog), 0, InfoLog);
|
||||
|
||||
InvalidCodepath;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char InfoLog[1024];
|
||||
glGetShaderInfoLog(VertexShader, ArrayCount(InfoLog), 0, InfoLog);
|
||||
|
||||
InvalidCodepath;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static quad_program OpenGL_CompileQuadProgram(void)
|
||||
{
|
||||
char *VertexSource =
|
||||
R"GLSL(
|
||||
in v2 In_P;
|
||||
in v2 In_SourceP;
|
||||
in s32 In_TextureIndex;
|
||||
in u32 In_Color;
|
||||
in v2 In_ToCenter;
|
||||
in v2 In_HalfSize;
|
||||
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;
|
||||
|
||||
flat out s32 TextureIndex;
|
||||
out v2 DestP;
|
||||
out v2 DestHalfSize;
|
||||
out v2 DestCenter;
|
||||
out v2 SourceP;
|
||||
out v4 Color;
|
||||
out r32 CornerRadius;
|
||||
out r32 EdgeSoftness;
|
||||
out r32 BorderThickness;
|
||||
|
||||
void main()
|
||||
{
|
||||
DestP = In_P;
|
||||
DestCenter = In_P + In_ToCenter;
|
||||
DestHalfSize = In_HalfSize;
|
||||
|
||||
SourceP = In_SourceP;
|
||||
|
||||
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);
|
||||
Color.r = r32((In_Color >> 24) & 255u)/255.0;
|
||||
Color.g = r32((In_Color >> 16) & 255u)/255.0;
|
||||
Color.b = r32((In_Color >> 8) & 255u)/255.0;
|
||||
Color.a = r32((In_Color >> 0) & 255u)/255.0;
|
||||
|
||||
TextureIndex = In_TextureIndex;
|
||||
CornerRadius = In_CornerRadius;
|
||||
EdgeSoftness = In_EdgeSoftness;
|
||||
BorderThickness = In_BorderThickness;
|
||||
})GLSL";
|
||||
|
||||
char *FragmentSource =
|
||||
R"GLSL(
|
||||
|
||||
flat in s32 TextureIndex;
|
||||
in v2 DestP;
|
||||
in v2 DestHalfSize;
|
||||
in v2 DestCenter;
|
||||
in v2 SourceP;
|
||||
in v4 Color;
|
||||
in r32 CornerRadius;
|
||||
in r32 EdgeSoftness;
|
||||
in r32 BorderThickness;
|
||||
)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*TextureFactor*BorderFactor*SDFFactor;
|
||||
})GLSL";
|
||||
|
||||
quad_program Program = {};
|
||||
Program.ID = OpenGL_CompileShaderProgram(VertexSource, FragmentSource);
|
||||
|
||||
Program.PID = glGetAttribLocation(Program.ID, "In_P");
|
||||
Program.SourcePID = glGetAttribLocation(Program.ID, "In_SourceP");
|
||||
Program.TextureIndexID = glGetAttribLocation(Program.ID, "In_TextureIndex");
|
||||
Program.ColorID = glGetAttribLocation(Program.ID, "In_Color");
|
||||
Program.ToCenterID = glGetAttribLocation(Program.ID, "In_ToCenter");
|
||||
Program.HalfSizeID = glGetAttribLocation(Program.ID, "In_HalfSize");
|
||||
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));\
|
||||
}
|
||||
|
||||
#define OpenGL_EnableIntegerVertexAttribute(Index, Size, Type, type, Member)\
|
||||
if(Index != -1)\
|
||||
{\
|
||||
glEnableVertexAttribArray(Index);\
|
||||
glVertexAttribIPointer(Index, Size, Type, sizeof(type), (void *)OffsetOf(type, Member));\
|
||||
}
|
||||
|
||||
#define OpenGL_DisableVertexAttribute(Index)\
|
||||
if(Index != -1)\
|
||||
{\
|
||||
glDisableVertexAttribArray(Index);\
|
||||
}
|
||||
|
||||
static void OpenGL_BeginProgram(quad_program *Program)
|
||||
{
|
||||
glUseProgram(Program->ID);
|
||||
|
||||
OpenGL_EnableFloatVertexAttribute(Program->PID, 2, GL_FLOAT, quad_vertex, P);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->SourcePID, 2, GL_FLOAT, quad_vertex, SourceP);
|
||||
OpenGL_EnableIntegerVertexAttribute(Program->TextureIndexID, 1, GL_UNSIGNED_INT, quad_vertex, TextureIndex);
|
||||
OpenGL_EnableIntegerVertexAttribute(Program->ColorID, 1, GL_UNSIGNED_INT, quad_vertex, Color);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->ToCenterID, 2, GL_FLOAT, quad_vertex, ToCenter);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->HalfSizeID, 2, GL_FLOAT, quad_vertex, HalfSize);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->CornerRadiusID, 1, GL_FLOAT, quad_vertex, CornerRadius);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->EdgeSoftnessID, 1, GL_FLOAT, quad_vertex, EdgeSoftness);
|
||||
OpenGL_EnableFloatVertexAttribute(Program->BorderThicknessID, 1, GL_FLOAT, quad_vertex, BorderThickness);
|
||||
}
|
||||
|
||||
static void OpenGL_EndProgram(quad_program *Program)
|
||||
{
|
||||
OpenGL_DisableVertexAttribute(Program->PID);
|
||||
OpenGL_DisableVertexAttribute(Program->SourcePID);
|
||||
OpenGL_DisableVertexAttribute(Program->TextureIndexID);
|
||||
OpenGL_DisableVertexAttribute(Program->ColorID);
|
||||
OpenGL_DisableVertexAttribute(Program->ToCenterID);
|
||||
OpenGL_DisableVertexAttribute(Program->HalfSizeID);
|
||||
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 = {};
|
||||
|
||||
RenderCommands->MaxPushBufferSize = MaxPushBufferSize;
|
||||
RenderCommands->PushBufferBase = (u8 *)OpenGL_AllocateMemory(RenderCommands->MaxPushBufferSize);
|
||||
|
||||
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));
|
||||
|
||||
Context.QuadProgram = OpenGL_CompileQuadProgram();
|
||||
|
||||
glGenBuffers(1, &Context.VertexBuffer);
|
||||
glGenBuffers(1, &Context.IndexBuffer);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, Context.VertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, RenderCommands->MaxQuadVertexCount*sizeof(quad_vertex), 0, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
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);
|
||||
|
||||
u32 WhiteData = 0xFFFFFFFF;
|
||||
RenderCommands->WhiteTexture = OpenGL_AllocateTexture(V2S(1, 1), Render_TextureFormat_RGBA8, &WhiteData);
|
||||
|
||||
RenderCommands->AllocateTexture = OpenGL_AllocateTexture;
|
||||
RenderCommands->FillRegion = OpenGL_FillRegion;
|
||||
|
||||
#if VN_SLOW
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glDebugMessageCallback(OpenGL_DebugMessageCallback, 0);
|
||||
#endif
|
||||
|
||||
u32 DummyVertexArray;
|
||||
glGenVertexArrays(1, &DummyVertexArray);
|
||||
glBindVertexArray(DummyVertexArray);
|
||||
|
||||
return(Context);
|
||||
}
|
||||
|
||||
static void OpenGL_BeginFrame(vn_render_commands *RenderCommands, v2 RenderDim)
|
||||
{
|
||||
RenderCommands->PushBufferAt = RenderCommands->PushBufferBase;
|
||||
RenderCommands->QuadVertexCount = 0;
|
||||
RenderCommands->QuadIndexCount = 0;
|
||||
|
||||
RenderCommands->RenderDim = RenderDim;
|
||||
}
|
||||
|
||||
static void OpenGL_EndFrame(opengl_context *Context, vn_render_commands *RenderCommands)
|
||||
{
|
||||
glViewport(0, 0, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
|
||||
glScissor(0, 0, RenderCommands->RenderDim.x, RenderCommands->RenderDim.y);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, Context->VertexBuffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Context->IndexBuffer);
|
||||
|
||||
void *VertexData = RenderCommands->QuadVertexBase;
|
||||
umm VertexSize = RenderCommands->QuadVertexCount*sizeof(quad_vertex);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, VertexSize, VertexData);
|
||||
|
||||
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);
|
||||
|
||||
for(u8 *PushBufferAt = RenderCommands->PushBufferBase;
|
||||
PushBufferAt < RenderCommands->PushBufferAt;)
|
||||
{
|
||||
render_command_header *Header = (render_command_header *)PushBufferAt;
|
||||
PushBufferAt += sizeof(*Header);
|
||||
|
||||
switch(Header->Type)
|
||||
{
|
||||
case Render_Command_render_command_clear:
|
||||
{
|
||||
render_command_clear *Command = (render_command_clear *)PushBufferAt;
|
||||
PushBufferAt += sizeof(*Command);
|
||||
|
||||
glClearColor(Command->Color.r, Command->Color.g, Command->Color.b, 1.0);
|
||||
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;
|
||||
|
||||
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
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenGL_EndProgram(&Context->QuadProgram);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* date = May 7th 2023 9:49 am */
|
||||
|
||||
#ifndef OPENGL_RENDER_H
|
||||
#define OPENGL_RENDER_H
|
||||
|
||||
#include "vn_opengl_defines.h"
|
||||
#include "generated/vn_opengl_functions.h"
|
||||
|
||||
struct opengl_texture
|
||||
{
|
||||
u32 ID;
|
||||
render_texture_format Format;
|
||||
v2s Dim;
|
||||
};
|
||||
|
||||
struct quad_program
|
||||
{
|
||||
u32 ID;
|
||||
|
||||
u32 PID;
|
||||
u32 SourcePID;
|
||||
u32 TextureIndexID;
|
||||
u32 ColorID;
|
||||
u32 ToCenterID;
|
||||
u32 HalfSizeID;
|
||||
u32 CornerRadiusID;
|
||||
u32 EdgeSoftnessID;
|
||||
u32 BorderThicknessID;
|
||||
|
||||
u32 UniformResolutionLocation;
|
||||
};
|
||||
|
||||
struct opengl_context
|
||||
{
|
||||
u32 VertexBuffer;
|
||||
u32 IndexBuffer;
|
||||
|
||||
quad_program QuadProgram;
|
||||
};
|
||||
|
||||
#endif //OPENGL_RENDER_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
#include "vn_platform.h"
|
||||
#include "vn_platform.cpp"
|
||||
|
||||
#include "vn_font.h"
|
||||
#include "vn_text_op.h"
|
||||
#include "vn_ui.h"
|
||||
#include "vn_workspace.h"
|
||||
#include "vn_theme_dark.h"
|
||||
#include "vn_animation_curve.h"
|
||||
|
||||
#include "vn_render.cpp"
|
||||
#include "vn_font.cpp"
|
||||
#include "vn_ui.cpp"
|
||||
#include "vn_ui_utils.cpp"
|
||||
#include "vn_animation_curve.cpp"
|
||||
#include "vn_workspace.cpp"
|
||||
|
||||
struct vn_state
|
||||
{
|
||||
memory_arena Arena;
|
||||
glyph_atlas *GlyphAtlas;
|
||||
|
||||
ui UI;
|
||||
workspace Workspace;
|
||||
animation_curve_state AnimationCurveState;
|
||||
};
|
||||
|
||||
VN_UPDATE_AND_RENDER(VN_UpdateAndRender)
|
||||
{
|
||||
SetThreadContext(ThreadContext);
|
||||
Platform = Memory->PlatformAPI;
|
||||
|
||||
vn_state *State = Memory->State;
|
||||
|
||||
if(!Memory->State)
|
||||
{
|
||||
State = Memory->State = BootstrapPushStruct(vn_state, Arena);
|
||||
|
||||
State->GlyphAtlas = CreateGlyphAtlas(RenderCommands);
|
||||
|
||||
Workspace_Init(&State->Workspace);
|
||||
}
|
||||
|
||||
AnimationCurve_NewFrame(&State->AnimationCurveState, Input->dtForFrame);
|
||||
UI_NewFrame(&State->UI, Input->EventList, Input->MouseP);
|
||||
|
||||
Workspace_Update(&State->Workspace, RenderCommands, Input, State->GlyphAtlas);
|
||||
// sixten(NOTE): This allows us to check for
|
||||
UI_SignalFromBox(UI_GetState()->ContainerNode);
|
||||
|
||||
for(platform_event *Event = Input->EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
Platform_ConsumeEvent(Input->EventList, Event);
|
||||
}
|
||||
|
||||
render_group Group = BeginRenderGroup(RenderCommands);
|
||||
PushClear(&Group, V3(0.1, 0.1, 0.1));
|
||||
|
||||
UI_RenderFrame(&Group, State->GlyphAtlas);
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
global animation_curve_state *Global_AnimationCurveState = 0;
|
||||
|
||||
inline animation_curve_state *AnimationCurve_GetState(void)
|
||||
{
|
||||
return(Global_AnimationCurveState);
|
||||
}
|
||||
|
||||
inline void AnimationCurve_SetState(animation_curve_state *State)
|
||||
{
|
||||
Global_AnimationCurveState = State;
|
||||
}
|
||||
|
||||
inline animation_curve_key AnimationCurve_GenerateKeyFromString(string String)
|
||||
{
|
||||
animation_curve_key Key;
|
||||
Key.Value = HashString(String);
|
||||
|
||||
return(Key);
|
||||
}
|
||||
|
||||
static animation_curve_entry *AnimationCurve_GetEntryByKey(animation_curve_key Key, r32 Initial = 0)
|
||||
{
|
||||
animation_curve_state *State = AnimationCurve_GetState();
|
||||
|
||||
u64 Hash = Key.Value;
|
||||
u64 Slot = Hash % ArrayCount(State->Buckets);
|
||||
|
||||
animation_curve_bucket *Bucket = State->Buckets + Slot;
|
||||
|
||||
animation_curve_entry *Result = 0;
|
||||
for(animation_curve_entry *Entry = Bucket->First;
|
||||
Entry != 0;
|
||||
Entry = Entry->Next)
|
||||
{
|
||||
if(AreEqual(Entry->Key, Key))
|
||||
{
|
||||
Result = Entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!Result)
|
||||
{
|
||||
if(DLLIsEmpty(State->FirstFreeEntry))
|
||||
{
|
||||
Result = PushStruct(&State->Arena, animation_curve_entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = State->FirstFreeEntry;
|
||||
DLLRemove(State->FirstFreeEntry, State->LastFreeEntry, Result);
|
||||
}
|
||||
|
||||
DLLInsertLast(Bucket->First, Bucket->Last, Result);
|
||||
|
||||
Result->Value = Initial;
|
||||
}
|
||||
|
||||
Result->Key = Key;
|
||||
Result->LastFrameTouched = State->CurrentFrame;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 AnimationCurve_GetValue(string Name, r32 Initial)
|
||||
{
|
||||
animation_curve_key Key = AnimationCurve_GenerateKeyFromString(Name);
|
||||
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Initial);
|
||||
|
||||
r32 Result = Entry->Value;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void AnimationCurve_SetValue(string Name, r32 Value)
|
||||
{
|
||||
animation_curve_key Key = AnimationCurve_GenerateKeyFromString(Name);
|
||||
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Value);
|
||||
|
||||
Entry->Value = Value;
|
||||
}
|
||||
|
||||
inline r32 AnimationCurve_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
|
||||
{
|
||||
animation_curve_state *State = AnimationCurve_GetState();
|
||||
|
||||
r32 Result = *Value;
|
||||
|
||||
r32 Rate = 1.0 - Pow(2, -(10.0 / Duration * State->dtForFrame));
|
||||
*Value += (Target - *Value) * Rate;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 AnimationCurve_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name)
|
||||
{
|
||||
animation_curve_key Key = AnimationCurve_GenerateKeyFromString(Name);
|
||||
animation_curve_entry *Entry = AnimationCurve_GetEntryByKey(Key, Initial);
|
||||
|
||||
r32 Result = AnimationCurve_AnimateValueDirect(Target, Duration, &Entry->Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 AnimationCurve_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
r32 Result = AnimationCurve_AnimateValue(Target, Initial, Duration, String);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void AnimationCurve_NewFrame(animation_curve_state *State, r32 dtForFrame)
|
||||
{
|
||||
AnimationCurve_SetState(State);
|
||||
State->dtForFrame = dtForFrame;
|
||||
|
||||
// sixten: Prune untouched entries.
|
||||
for(s32 BucketIndex = 0;
|
||||
BucketIndex < ArrayCount(State->Buckets);
|
||||
++BucketIndex)
|
||||
{
|
||||
animation_curve_bucket *Bucket = State->Buckets + BucketIndex;
|
||||
|
||||
animation_curve_entry *Entry = Bucket->First;
|
||||
while(Entry != 0)
|
||||
{
|
||||
if(Entry->LastFrameTouched != State->CurrentFrame)
|
||||
{
|
||||
animation_curve_entry *ToRemove = Entry;
|
||||
Entry = Entry->Next;
|
||||
|
||||
DLLRemove(Bucket->First, Bucket->Last, ToRemove);
|
||||
DLLInsertLast(State->FirstFreeEntry, State->LastFreeEntry, ToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry = Entry->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++State->CurrentFrame;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/* date = May 7th 2023 0:37 pm */
|
||||
|
||||
#ifndef VN_ANIMATION_CURVE_H
|
||||
#define VN_ANIMATION_CURVE_H
|
||||
|
||||
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;
|
||||
u32 LastFrameTouched;
|
||||
|
||||
r32 Value;
|
||||
|
||||
animation_curve_entry *Next;
|
||||
animation_curve_entry *Prev;
|
||||
};
|
||||
|
||||
struct animation_curve_bucket
|
||||
{
|
||||
animation_curve_entry *First;
|
||||
animation_curve_entry *Last;
|
||||
};
|
||||
|
||||
struct animation_curve_state
|
||||
{
|
||||
memory_arena Arena;
|
||||
|
||||
u32 CurrentFrame;
|
||||
r32 dtForFrame;
|
||||
|
||||
// sixten: Hash map
|
||||
animation_curve_bucket Buckets[256];
|
||||
|
||||
// sixten: Free list
|
||||
animation_curve_entry *FirstFreeEntry;
|
||||
animation_curve_entry *LastFreeEntry;
|
||||
};
|
||||
|
||||
#endif //VN_ANIMATION_CURVE_H
|
|
@ -0,0 +1,162 @@
|
|||
/* date = April 26th 2023 8:58 pm */
|
||||
|
||||
#ifndef VN_CORE_H
|
||||
#define VN_CORE_H
|
||||
|
||||
#define global static
|
||||
#define persist static
|
||||
|
||||
#pragma section(".roglob", read)
|
||||
#define read_only __declspec(allocate(".roglob"))
|
||||
|
||||
#define fallthrough
|
||||
|
||||
#if VN_SLOW
|
||||
#define Assert(Statement) if(!(Statement)) { *(int *)0 = 0; }
|
||||
#else
|
||||
#define Assert(Statement)
|
||||
#endif
|
||||
|
||||
#define CTAssert(Statement) static_assert(Statement)
|
||||
|
||||
#define InvokeDebugger __debugbreak()
|
||||
#define UnimplementedCodepath Assert(!"Unimplemented codepath")
|
||||
|
||||
#define InvalidCodepath Assert(!"Invalid codepath")
|
||||
#define InvalidDefaultCase default: { Assert(!"Invalid codepath"); } break
|
||||
|
||||
#define ArrayCount(Array) (sizeof(Array)/sizeof((Array)[0]))
|
||||
#define OffsetOf(type, Member) (umm) &(((type *)0)->Member)
|
||||
|
||||
#define Minimum(A, B) (((A)<(B))?(A):(B))
|
||||
#define Maximum(A, B) (((A)>(B))?(A):(B))
|
||||
|
||||
#define Clamp(Value, Min, Max) Minimum(Maximum(Value, Min), Max)
|
||||
#define Clamp01(Value) Clamp(Value, 0, 1)
|
||||
|
||||
#define DeferLoop(Start, End) for(s32 ___ = ((Start), 0); ___ == 0; ++___, (End))
|
||||
|
||||
#define _Stringify(x) #x
|
||||
#define Stringify(x) _Stringify(x)
|
||||
|
||||
#define IsNull(x) ((x) == 0)
|
||||
#define SetNull(x) ((x) = 0)
|
||||
|
||||
#define DLLInsert_NP(f,l,p,n,next,prev) \
|
||||
(IsNull(f) ? (((f) = (l) = (n)), SetNull((n)->next), SetNull((n)->prev)) :\
|
||||
IsNull(p) ? (SetNull((n)->prev), (n)->next = (f), (IsNull(f) ? (0) : ((f)->prev = (n))), (f) = (n)) :\
|
||||
((IsNull((p)->next) ? (0) : (((p)->next->prev) = (n))), (n)->next = (p)->next, (n)->prev = (p), (p)->next = (n),\
|
||||
((p) == (l) ? (l) = (n) : (0))))
|
||||
|
||||
#define DLLInsertLast_NP(f,l,n,next,prev) DLLInsert_NP(f,l,l,n,next,prev)
|
||||
#define DLLInsertFirst_NP(f,l,n,next,prev) DLLInsert_NP(l,f,f,n,prev,next)
|
||||
|
||||
#define DLLRemove_NP(f,l,n,next,prev)\
|
||||
(((f)==(n))?\
|
||||
((f)=(f)->next, (IsNull(f) ? (SetNull(l)) : SetNull((f)->prev))):\
|
||||
((l)==(n))?\
|
||||
((l)=(l)->prev, (IsNull(l) ? (SetNull(f)) : SetNull((l)->next))):\
|
||||
((IsNull((n)->next) ? (0) : ((n)->next->prev=(n)->prev)),\
|
||||
(IsNull((n)->prev) ? (0) : ((n)->prev->next=(n)->next))))
|
||||
|
||||
#define DLLInsertFirst(First, Last, Element) DLLInsertFirst_NP(First, Last, Element, Next, Prev)
|
||||
#define DLLInsertLast(First, Last, Element) DLLInsertLast_NP(First, Last, Element, Next, Prev)
|
||||
#define DLLRemove(First, Last, Element) DLLRemove_NP(First, Last, Element, Next, Prev)
|
||||
#define DLLIsEmpty(First) ((First) == 0)
|
||||
|
||||
#include "vn_types.h"
|
||||
#include "vn_math.h"
|
||||
#include "vn_string.h"
|
||||
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "third_party/stb_sprintf.h"
|
||||
|
||||
inline void Copy(void *Dest_, void *Source_, umm Count)
|
||||
{
|
||||
u8 *Dest = (u8 *)Dest_;
|
||||
u8 *Source = (u8 *)Source_;
|
||||
|
||||
while(Count--)
|
||||
{
|
||||
*Dest++ = *Source++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ZeroSize(void *Dest_, umm Count)
|
||||
{
|
||||
u8 *Dest = (u8 *)Dest_;
|
||||
while(Count--)
|
||||
{
|
||||
*Dest++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void *U64ToPointer(u64 Value)
|
||||
{
|
||||
void *Result = (void *)Value;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u64 PointerToU64(void *Value)
|
||||
{
|
||||
u64 Result = (u64)Value;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u64 AtomicExchangeU64(u64 volatile *Value, u64 New)
|
||||
{
|
||||
u64 Result = _InterlockedExchange64((__int64 volatile *)Value, New);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u64 AtomicAddU64(u64 volatile *Value, u64 Addend)
|
||||
{
|
||||
u64 Result = _InterlockedExchangeAdd64((__int64 volatile *)Value, Addend);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void BeginTicketMutex(ticket_mutex *Mutex)
|
||||
{
|
||||
u64 Ticket = AtomicAddU64(&Mutex->Ticket, 1);
|
||||
while(Ticket != Mutex->Serving) { _mm_pause(); }
|
||||
}
|
||||
|
||||
inline void EndTicketMutex(ticket_mutex *Mutex)
|
||||
{
|
||||
AtomicAddU64(&Mutex->Serving, 1);
|
||||
}
|
||||
|
||||
inline b32 InRange(range2_r32 Range, v2 P)
|
||||
{
|
||||
b32 Result = ((P.x >= Range.Min.x) &&
|
||||
(P.y >= Range.Min.y) &&
|
||||
(P.x < Range.Max.x) &&
|
||||
(P.y < Range.Max.y));
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range_s64 RangeS64(s64 A, s64 B)
|
||||
{
|
||||
range_s64 Result = {Minimum(A, B), Maximum(A, B)};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range_r32 RangeR32(r32 A, r32 B)
|
||||
{
|
||||
range_r32 Result = {Minimum(A, B), Maximum(A, B)};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline range2_r32 Range2R32(v2 A, v2 B)
|
||||
{
|
||||
range2_r32 Result = { Min(A, B), Max(A, B) };
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 DimOfRange(range2_r32 Range)
|
||||
{
|
||||
v2 Dim = Range.Max - Range.Min;
|
||||
return(Dim);
|
||||
}
|
||||
|
||||
#endif //VN_CORE_H
|
|
@ -0,0 +1,224 @@
|
|||
#define GLYPH_SUBPIXEL_SEGMENTS 3
|
||||
|
||||
inline s32 GetSubpixelSegmentAtP(r32 Value)
|
||||
{
|
||||
s32 Result = (s32)(Value - Floor(Value))*GLYPH_SUBPIXEL_SEGMENTS;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||
{
|
||||
Glyph->Font = Font;
|
||||
Glyph->Codepoint = Codepoint;
|
||||
Glyph->Size = Size;
|
||||
Glyph->Subpixel = Subpixel;
|
||||
|
||||
Assert(Subpixel < GLYPH_SUBPIXEL_SEGMENTS);
|
||||
|
||||
loaded_font *LoadedFont = Atlas->Fonts + Font;
|
||||
stbtt_fontinfo *Info = &LoadedFont->Info;
|
||||
|
||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(Info, Size);
|
||||
|
||||
s32 InternalIndex = (s32)(Glyph - Atlas->Glyphs);
|
||||
s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize;
|
||||
|
||||
v2s BaseTextureOffset = V2S((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize,
|
||||
(InternalIndex / GlyphsPerRow)*Atlas->GlyphSize);
|
||||
|
||||
int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint);
|
||||
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale,
|
||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||
&Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y);
|
||||
|
||||
ZeroSize(Atlas->BitmapBuffer, Atlas->GlyphSize*Atlas->GlyphSize);
|
||||
stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer,
|
||||
Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize,
|
||||
Scale, Scale,
|
||||
(r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0,
|
||||
GlyphIndex);
|
||||
|
||||
s32 Advance, LeftSideBearing;
|
||||
stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing);
|
||||
Glyph->Advance = Advance*Scale;
|
||||
Glyph->Offset.x = LeftSideBearing*Scale;
|
||||
|
||||
Glyph->Offset.y = Glyph->P0.y + (LoadedFont->Ascent + LoadedFont->LineGap)*Scale;
|
||||
|
||||
v2s Dim = Glyph->P1 - Glyph->P0;
|
||||
|
||||
Glyph->P0 = BaseTextureOffset;
|
||||
Glyph->P1 = BaseTextureOffset + Dim + V2S(2, 2);
|
||||
|
||||
Atlas->RenderCommands->FillRegion(Atlas->Texture,
|
||||
BaseTextureOffset, V2S(Atlas->GlyphSize, Atlas->GlyphSize),
|
||||
Atlas->BitmapBuffer);
|
||||
}
|
||||
|
||||
static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel)
|
||||
{
|
||||
glyph *Glyph = 0;
|
||||
|
||||
for(s32 GlyphIndex = 0;
|
||||
GlyphIndex < Atlas->GlyphsUsed;
|
||||
++GlyphIndex)
|
||||
{
|
||||
glyph *At = Atlas->Glyphs + GlyphIndex;
|
||||
if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel))
|
||||
{
|
||||
Glyph = At;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(Glyph)
|
||||
{
|
||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Atlas->GlyphsUsed < Atlas->MaxGlyphCount)
|
||||
{
|
||||
Glyph = Atlas->Glyphs + Atlas->GlyphsUsed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Glyph = Atlas->LRUFirst;
|
||||
Assert(Glyph);
|
||||
|
||||
DLLRemove_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||
}
|
||||
|
||||
RasterizeGlyph(Atlas, Font, Glyph, Codepoint, Size, Subpixel);
|
||||
}
|
||||
|
||||
DLLInsertLast_NP(Atlas->LRUFirst, Atlas->LRULast, Glyph, LRUNext, LRUPrev);
|
||||
|
||||
return(Glyph);
|
||||
}
|
||||
|
||||
static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands,
|
||||
s32 BitmapSize = DEFAULT_GLYPH_ATLAS_DIM,
|
||||
s32 GlyphSize = MAX_GLYPH_SIZE)
|
||||
{
|
||||
glyph_atlas *Atlas = BootstrapPushStruct(glyph_atlas, Arena);
|
||||
|
||||
Atlas->BitmapSize = BitmapSize;
|
||||
Atlas->GlyphSize = GlyphSize;
|
||||
|
||||
Atlas->MaxGlyphCount = (DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE)*(DEFAULT_GLYPH_ATLAS_DIM / MAX_GLYPH_SIZE);
|
||||
Atlas->Glyphs = PushArray(&Atlas->Arena, glyph, Atlas->MaxGlyphCount);
|
||||
|
||||
Atlas->RenderCommands = RenderCommands;
|
||||
Atlas->Texture = RenderCommands->AllocateTexture(V2S(BitmapSize, BitmapSize), Render_TextureFormat_R8, 0);
|
||||
|
||||
Atlas->Fonts[Font_Regular].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Roboto-Regular.ttf"));
|
||||
Atlas->Fonts[Font_Bold].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Roboto-Bold.ttf"));
|
||||
Atlas->Fonts[Font_Monospace].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/Liberation-Mono.ttf"));
|
||||
Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(&Atlas->Arena, StrLit("../fonts/icons.ttf"));
|
||||
|
||||
for(s32 FontIndex = 0;
|
||||
FontIndex < Font_Count;
|
||||
++FontIndex)
|
||||
{
|
||||
loaded_font *Font = Atlas->Fonts + FontIndex;
|
||||
stbtt_InitFont(&Font->Info,
|
||||
Font->Data.Data,
|
||||
stbtt_GetFontOffsetForIndex(Font->Data.Data, 0));
|
||||
|
||||
stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap);
|
||||
}
|
||||
|
||||
Atlas->BitmapBuffer = PushArray(&Atlas->Arena, u8, GlyphSize*GlyphSize);
|
||||
|
||||
return(Atlas);
|
||||
}
|
||||
|
||||
static void PushText(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
||||
v2 P, r32 Size, v4 Color,
|
||||
string Text)
|
||||
{
|
||||
r32 Oversample = 2;
|
||||
|
||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||
Iter.Codepoint != 0;
|
||||
Advance(&Iter))
|
||||
{
|
||||
u32 Codepoint = Iter.Codepoint;
|
||||
|
||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(P.x*Oversample));
|
||||
Assert(Glyph);
|
||||
|
||||
v2 GlyphP = P;
|
||||
GlyphP.x += Glyph->Offset.x/Oversample;
|
||||
GlyphP.y += Glyph->Offset.y/Oversample;
|
||||
|
||||
v2 RenderDim = V2(Glyph->P1 - Glyph->P0);
|
||||
v2 Dim = RenderDim;
|
||||
Dim.x /= Oversample;
|
||||
Dim.y /= Oversample;
|
||||
|
||||
PushTexturedQuad(Group, GlyphP, Dim, V2(Glyph->P0), RenderDim, Color, Color, Color, Color, 0, 0, 0, Atlas->Texture);
|
||||
|
||||
P.x += Glyph->Advance/Oversample;
|
||||
}
|
||||
}
|
||||
|
||||
static void PushTextF(render_group *Group, glyph_atlas *Atlas, font_id Font,
|
||||
v2 P, r32 Size, v4 Color,
|
||||
char *Format, ...)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
PushText(Group, Atlas, Font, P, Size, Color, String);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
}
|
||||
|
||||
inline r32 CalculateRasterizedTextWidth(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||
{
|
||||
r32 Oversample = 2;
|
||||
|
||||
r32 X = 0;
|
||||
|
||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||
Iter.Codepoint != 0;
|
||||
Advance(&Iter))
|
||||
{
|
||||
u32 Codepoint = Iter.Codepoint;
|
||||
|
||||
glyph *Glyph = GetGlyph(Atlas, Font, Codepoint, Size*Oversample, GetSubpixelSegmentAtP(X*Oversample));
|
||||
Assert(Glyph);
|
||||
|
||||
X += Glyph->Advance/Oversample;
|
||||
}
|
||||
|
||||
return(X);
|
||||
}
|
||||
|
||||
inline r32 CalculateRasterizedTextHeight(glyph_atlas *Atlas, font_id Font, r32 Size, string Text)
|
||||
{
|
||||
r32 Scale = stbtt_ScaleForMappingEmToPixels(&Atlas->Fonts[Font].Info, Size)/
|
||||
stbtt_ScaleForPixelHeight(&Atlas->Fonts[Font].Info, Size);
|
||||
|
||||
r32 Y = Size*Scale;
|
||||
|
||||
for(utf8_iterator Iter = IterateUTF8String(Text);
|
||||
Iter.Codepoint != 0;
|
||||
Advance(&Iter))
|
||||
{
|
||||
u32 Codepoint = Iter.Codepoint;
|
||||
|
||||
if(Codepoint == '\n')
|
||||
{
|
||||
Y += Size*Scale;
|
||||
}
|
||||
}
|
||||
return(Y);
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/* date = May 7th 2023 10:16 am */
|
||||
|
||||
#ifndef VN_FONT_H
|
||||
#define VN_FONT_H
|
||||
|
||||
enum font_id
|
||||
{
|
||||
Font_Regular,
|
||||
Font_Bold,
|
||||
Font_Monospace,
|
||||
Font_Icons,
|
||||
|
||||
Font_Count,
|
||||
};
|
||||
|
||||
#define FontIcon_None 0x0000
|
||||
#define FontIcon_Pencil 0xe800
|
||||
#define FontIcon_Forward 0xe801
|
||||
#define FontIcon_Book 0xe802
|
||||
#define FontIcon_FolderOpen 0xe803
|
||||
#define FontIcon_Wrench 0xe804
|
||||
#define FontIcon_CW 0xe805
|
||||
#define FontIcon_CCW 0xe806
|
||||
#define FontIcon_ArrowsCW 0xe807
|
||||
#define FontIcon_ResizeVertical 0xe808
|
||||
#define FontIcon_ResizeHorizontal 0xe809
|
||||
#define FontIcon_Play 0xe80a
|
||||
#define FontIcon_Stop 0xe80b
|
||||
#define FontIcon_Floppy 0xe80c
|
||||
#define FontIcon_Pause 0xe80d
|
||||
#define FontIcon_Folder 0xe80e
|
||||
#define FontIcon_Cog 0xe80f
|
||||
#define FontIcon_Attention 0xe810
|
||||
#define FontIcon_Cancel 0xe811
|
||||
#define FontIcon_Filter 0xf0b0
|
||||
#define FontIcon_Menu 0xf0c9
|
||||
#define FontIcon_CircleEmpty 0xf10c
|
||||
#define FontIcon_Circle 0xf111
|
||||
#define FontIcon_Reply 0xf112
|
||||
#define FontIcon_Terminal 0xf120
|
||||
#define FontIcon_Ellipsis 0xf141
|
||||
#define FontIcon_Document 0xf15b
|
||||
#define FontIcon_DocumentText 0xf15c
|
||||
#define FontIcon_Eyedropper 0xf1fb
|
||||
#define FontIcon_WindowMaximize 0xf2d0
|
||||
#define FontIcon_WindowMinimize 0xf2d1
|
||||
#define FontIcon_WindowRestore 0xf2d2
|
||||
#define FontIcon_WindowClose 0xf2d4
|
||||
#define FontIcon_DownDir 0xe812
|
||||
#define FontIcon_UpDir 0xe813
|
||||
#define FontIcon_LeftDir 0xe814
|
||||
#define FontIcon_RightDir 0xe815
|
||||
#define FontIcon_TextAlignLeft 0xe816
|
||||
#define FontIcon_TextAlignCenter 0xe817
|
||||
#define FontIcon_TextAlignRight 0xe818
|
||||
|
||||
struct glyph
|
||||
{
|
||||
glyph *LRUNext;
|
||||
glyph *LRUPrev;
|
||||
|
||||
font_id Font;
|
||||
u32 Codepoint;
|
||||
r32 Size;
|
||||
s32 Subpixel;
|
||||
|
||||
v2s P0;
|
||||
v2s P1;
|
||||
v2 Offset;
|
||||
r32 Advance;
|
||||
};
|
||||
|
||||
#define DEFAULT_GLYPH_ATLAS_DIM 1024
|
||||
#define MAX_GLYPH_SIZE 64
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "third_party/stb_truetype.h"
|
||||
|
||||
struct loaded_font
|
||||
{
|
||||
stbtt_fontinfo Info;
|
||||
string Data;
|
||||
|
||||
s32 Ascent;
|
||||
s32 Descent;
|
||||
s32 LineGap;
|
||||
};
|
||||
|
||||
struct glyph_atlas
|
||||
{
|
||||
memory_arena Arena;
|
||||
|
||||
s32 MaxGlyphCount;
|
||||
s32 GlyphsUsed;
|
||||
glyph *Glyphs;
|
||||
|
||||
glyph *LRUFirst;
|
||||
glyph *LRULast;
|
||||
|
||||
vn_render_commands *RenderCommands;
|
||||
render_handle Texture;
|
||||
|
||||
u8 *BitmapBuffer;
|
||||
s32 BitmapSize;
|
||||
s32 GlyphSize;
|
||||
|
||||
loaded_font Fonts[Font_Count];
|
||||
};
|
||||
|
||||
#endif //VN_FONT_H
|
|
@ -0,0 +1,114 @@
|
|||
/* date = April 29th 2023 3:06 pm */
|
||||
|
||||
#ifndef VN_MATH_H
|
||||
#define VN_MATH_H
|
||||
|
||||
#include "math.h"
|
||||
|
||||
inline r32 Floor(r32 Value)
|
||||
{
|
||||
r32 Result = floorf(Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 Pow(r32 Base, r32 Exponent)
|
||||
{
|
||||
r32 Result = powf(Base, Exponent);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 AbsoluteValue(r32 Value)
|
||||
{
|
||||
r32 Result = fabsf(Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline b32 AreAlmostEqual(r32 A, r32 B)
|
||||
{
|
||||
b32 Result = false;
|
||||
|
||||
r32 Epsilon = 0.001;
|
||||
if(AbsoluteValue(A - B) < Epsilon)
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2s operator+(v2s A, v2s B)
|
||||
{
|
||||
v2s Result = {A.x + B.x, A.y + B.y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2s operator-(v2s A, v2s B)
|
||||
{
|
||||
v2s Result = {A.x - B.x, A.y - B.y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2s operator+=(v2s &A, v2s B) { return A = A + B; }
|
||||
inline v2s operator-=(v2s &A, v2s B) { return A = A - B; }
|
||||
|
||||
inline v2 operator+(v2 A, v2 B)
|
||||
{
|
||||
v2 Result = {A.x + B.x, A.y + B.y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 operator-(v2 A, v2 B)
|
||||
{
|
||||
v2 Result = {A.x - B.x, A.y - B.y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 operator*(v2 A, r32 B)
|
||||
{
|
||||
v2 Result = {A.x*B, A.y*B};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 operator+=(v2 &A, v2 B) { return A = A + B; }
|
||||
inline v2 operator-=(v2 &A, v2 B) { return A = A - B; }
|
||||
|
||||
inline v2 Min(v2 A, v2 B)
|
||||
{
|
||||
v2 Result = V2(Minimum(A.x, B.x), Minimum(A.y, B.y));
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 Max(v2 A, v2 B)
|
||||
{
|
||||
v2 Result = V2(Maximum(A.x, B.x), Maximum(A.y, B.y));
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v4 operator+(v4 A, v4 B)
|
||||
{
|
||||
v4 Result = {A.x + B.x, A.y + B.y, A.z + B.z, A.w + B.w};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v4 operator-(v4 A, v4 B)
|
||||
{
|
||||
v4 Result = {A.x - B.x, A.y - B.y, A.z - B.z, A.w - B.w};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v4 operator*(v4 A, r32 B)
|
||||
{
|
||||
v4 Result = {A.x*B, A.y*B, A.z*B, A.w*B};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v4 operator+=(v4 &A, v4 B) { return A = A + B; }
|
||||
inline v4 operator-=(v4 &A, v4 B) { return A = A - B; }
|
||||
|
||||
inline v4 LinearBlend(v4 A, v4 B, r32 C)
|
||||
{
|
||||
v4 Result = A + (B - A) * C;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#endif //VN_MATH_H
|
|
@ -0,0 +1,222 @@
|
|||
/* date = April 26th 2023 10:11 pm */
|
||||
|
||||
#ifndef VN_MEMORY_H
|
||||
#define VN_MEMORY_H
|
||||
|
||||
struct memory_arena
|
||||
{
|
||||
platform_memory_block *CurrentBlock;
|
||||
umm MinimumBlockSize;
|
||||
s32 TemporaryMemoryCount;
|
||||
};
|
||||
|
||||
struct temporary_memory
|
||||
{
|
||||
memory_arena *Arena;
|
||||
platform_memory_block *Block;
|
||||
umm Used;
|
||||
};
|
||||
|
||||
inline temporary_memory BeginTemporaryMemory(memory_arena *Arena)
|
||||
{
|
||||
temporary_memory Result;
|
||||
Result.Arena = Arena;
|
||||
Result.Block = Arena->CurrentBlock;
|
||||
Result.Used = Arena->CurrentBlock ? Arena->CurrentBlock->Used : 0;
|
||||
|
||||
++Arena->TemporaryMemoryCount;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void EndTemporaryMemory(temporary_memory Temp)
|
||||
{
|
||||
memory_arena *Arena = Temp.Arena;
|
||||
while(Arena->CurrentBlock != Temp.Block)
|
||||
{
|
||||
platform_memory_block *MemoryBlock = Arena->CurrentBlock;
|
||||
Arena->CurrentBlock = MemoryBlock->ArenaPrev;
|
||||
Platform.DeallocateMemory(MemoryBlock);
|
||||
}
|
||||
|
||||
if(Arena->CurrentBlock)
|
||||
{
|
||||
Assert(Arena->CurrentBlock->Used >= Temp.Used);
|
||||
Arena->CurrentBlock->Used = Temp.Used;
|
||||
}
|
||||
|
||||
Assert(Arena->TemporaryMemoryCount > 0);
|
||||
--Arena->TemporaryMemoryCount;
|
||||
}
|
||||
|
||||
static void Release(memory_arena *Arena)
|
||||
{
|
||||
while(Arena->CurrentBlock != 0)
|
||||
{
|
||||
platform_memory_block *MemoryBlock = Arena->CurrentBlock;
|
||||
b32 IsLastBlock = MemoryBlock->ArenaPrev == 0;
|
||||
Arena->CurrentBlock = MemoryBlock->ArenaPrev;
|
||||
Platform.DeallocateMemory(MemoryBlock);
|
||||
|
||||
if(IsLastBlock)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum arena_push_flag
|
||||
{
|
||||
ArenaFlag_ClearToZero = 0x1,
|
||||
};
|
||||
|
||||
struct arena_push_params
|
||||
{
|
||||
u32 Flags;
|
||||
u32 Alignment;
|
||||
};
|
||||
|
||||
inline arena_push_params DefaultArenaParams(void)
|
||||
{
|
||||
arena_push_params Params = {};
|
||||
Params.Flags = ArenaFlag_ClearToZero;
|
||||
Params.Alignment = 4;
|
||||
return(Params);
|
||||
}
|
||||
|
||||
inline arena_push_params NoClear(void)
|
||||
{
|
||||
arena_push_params Params = DefaultArenaParams();
|
||||
Params.Flags &= ~ArenaFlag_ClearToZero;
|
||||
return(Params);
|
||||
}
|
||||
|
||||
inline umm GetAlignmentOffset(memory_arena *Arena, umm Alignment)
|
||||
{
|
||||
umm AlignmentOffset = 0;
|
||||
|
||||
umm ResultPointer = (umm)Arena->CurrentBlock + Arena->CurrentBlock->Used;
|
||||
umm AlignmentMask = Alignment - 1;
|
||||
if(ResultPointer & AlignmentMask)
|
||||
{
|
||||
AlignmentOffset = Alignment - (ResultPointer & AlignmentMask);
|
||||
}
|
||||
|
||||
return(AlignmentOffset);
|
||||
}
|
||||
|
||||
inline umm GetEffectiveSizeFor(memory_arena *Arena, umm InitialSize, arena_push_params Params)
|
||||
{
|
||||
umm Size = InitialSize;
|
||||
|
||||
umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment);
|
||||
Size += AlignmentOffset;
|
||||
|
||||
return(Size);
|
||||
}
|
||||
|
||||
#define PushSize(Arena, InitialSize, ...) PushSize_(Arena, InitialSize, __VA_ARGS__)
|
||||
#define PushStruct(Arena, type, ...) (type *)PushSize_(Arena, sizeof(type), __VA_ARGS__)
|
||||
#define PushArray(Arena, type, Count, ...) (type *)PushSize_(Arena, sizeof(type)*Count, __VA_ARGS__)
|
||||
|
||||
inline void *PushSize_(memory_arena *Arena, umm InitialSize, arena_push_params Params = DefaultArenaParams())
|
||||
{
|
||||
void *Result = 0;
|
||||
|
||||
umm Size = 0;
|
||||
if(Arena->CurrentBlock)
|
||||
{
|
||||
Size = GetEffectiveSizeFor(Arena, InitialSize, Params);
|
||||
}
|
||||
|
||||
if(!Arena->CurrentBlock || ((Arena->CurrentBlock->Used + Size) > Arena->CurrentBlock->Size))
|
||||
{
|
||||
Size = InitialSize;
|
||||
|
||||
if(!Arena->MinimumBlockSize)
|
||||
{
|
||||
Arena->MinimumBlockSize = 1024*1024;
|
||||
}
|
||||
|
||||
umm BlockSize = Maximum(Size, Arena->MinimumBlockSize);
|
||||
|
||||
platform_memory_block *NewBlock = Platform.AllocateMemory(BlockSize);
|
||||
NewBlock->ArenaPrev = Arena->CurrentBlock;
|
||||
Arena->CurrentBlock = NewBlock;
|
||||
}
|
||||
|
||||
Assert((Arena->CurrentBlock->Used + Size) <= Arena->CurrentBlock->Size);
|
||||
|
||||
umm AlignmentOffset = GetAlignmentOffset(Arena, Params.Alignment);
|
||||
umm OffsetInBlock = Arena->CurrentBlock->Used + AlignmentOffset;
|
||||
Result = Arena->CurrentBlock->Base + OffsetInBlock;
|
||||
Arena->CurrentBlock->Used += Size;
|
||||
|
||||
Assert(Size >= InitialSize);
|
||||
Assert(Arena->CurrentBlock->Used <= Arena->CurrentBlock->Size);
|
||||
|
||||
if(Params.Flags & ArenaFlag_ClearToZero)
|
||||
{
|
||||
ZeroSize(Result, InitialSize);
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void *BootstrapPushSize(umm Size, umm OffsetToArena)
|
||||
{
|
||||
memory_arena Arena = {};
|
||||
void *Result = PushSize(&Arena, Size);
|
||||
*(memory_arena *)((u8 *)Result + OffsetToArena) = Arena;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#define BootstrapPushStruct(type, Member) (type *)BootstrapPushSize(sizeof(type), OffsetOf(type, Member))
|
||||
|
||||
static string PushString(memory_arena *Arena, string String)
|
||||
{
|
||||
string Result = MakeString(PushArray(Arena, char, String.Count + 1), String.Count);
|
||||
Copy(Result.Data, String.Data, String.Count);
|
||||
|
||||
Result.Data[Result.Count] = 0;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static string PushFormatVariadic(memory_arena *Arena, char *Format, va_list Arguments)
|
||||
{
|
||||
va_list ArgumentsCopy;
|
||||
va_copy(ArgumentsCopy, Arguments);
|
||||
|
||||
string Result;
|
||||
Result.Count = stbsp_vsnprintf(0, 0, Format, ArgumentsCopy);
|
||||
Result.Data = (u8 *)PushSize(Arena, Result.Count + 1, NoClear());
|
||||
Result.Data[Result.Count] = 0;
|
||||
|
||||
stbsp_vsnprintf((char *)Result.Data, (s32)Result.Count + 1, Format, Arguments);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline string PushFormat(memory_arena *Arena, char *Format, ...)
|
||||
{
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string Result = PushFormatVariadic(Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline string PushCString(memory_arena *Arena, char *CString)
|
||||
{
|
||||
string Result;
|
||||
Result.Count = StringLength(CString);
|
||||
Result.Data = PushArray(Arena, u8, Result.Count);
|
||||
Copy(Result.Data, CString, Result.Count);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#endif //VN_MEMORY_H
|
|
@ -0,0 +1,611 @@
|
|||
/* date = March 18th 2023 7:14 pm */
|
||||
|
||||
#ifndef VN_OPENGL_DEFINES_H
|
||||
#define VN_OPENGL_DEFINES_H
|
||||
|
||||
typedef s8 GLbyte;
|
||||
typedef r32 GLclampf;
|
||||
typedef r64 GLclampd;
|
||||
typedef s16 GLshort;
|
||||
typedef u16 GLushort;
|
||||
typedef void GLvoid;
|
||||
typedef unsigned int GLenum;
|
||||
typedef r32 GLfloat;
|
||||
typedef r64 GLdouble;
|
||||
typedef s32 GLfixed;
|
||||
typedef unsigned int GLuint;
|
||||
typedef size_t GLsizeiptr;
|
||||
typedef intptr_t GLintptr;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef int GLint;
|
||||
typedef char GLchar;
|
||||
typedef u8 GLubyte;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef int GLsizei;
|
||||
typedef s32 GLclampx;
|
||||
|
||||
#define GL_VERSION_1_1 1
|
||||
#define GL_ACCUM 0x0100
|
||||
#define GL_LOAD 0x0101
|
||||
#define GL_RETURN 0x0102
|
||||
#define GL_MULT 0x0103
|
||||
#define GL_ADD 0x0104
|
||||
#define GL_NEVER 0x0200
|
||||
#define GL_LESS 0x0201
|
||||
#define GL_EQUAL 0x0202
|
||||
#define GL_LEQUAL 0x0203
|
||||
#define GL_GREATER 0x0204
|
||||
#define GL_NOTEQUAL 0x0205
|
||||
#define GL_GEQUAL 0x0206
|
||||
#define GL_ALWAYS 0x0207
|
||||
#define GL_CURRENT_BIT 0x00000001
|
||||
#define GL_POINT_BIT 0x00000002
|
||||
#define GL_LINE_BIT 0x00000004
|
||||
#define GL_POLYGON_BIT 0x00000008
|
||||
#define GL_POLYGON_STIPPLE_BIT 0x00000010
|
||||
#define GL_PIXEL_MODE_BIT 0x00000020
|
||||
#define GL_LIGHTING_BIT 0x00000040
|
||||
#define GL_FOG_BIT 0x00000080
|
||||
#define GL_DEPTH_BUFFER_BIT 0x00000100
|
||||
#define GL_ACCUM_BUFFER_BIT 0x00000200
|
||||
#define GL_STENCIL_BUFFER_BIT 0x00000400
|
||||
#define GL_VIEWPORT_BIT 0x00000800
|
||||
#define GL_TRANSFORM_BIT 0x00001000
|
||||
#define GL_ENABLE_BIT 0x00002000
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_HINT_BIT 0x00008000
|
||||
#define GL_EVAL_BIT 0x00010000
|
||||
#define GL_LIST_BIT 0x00020000
|
||||
#define GL_TEXTURE_BIT 0x00040000
|
||||
#define GL_SCISSOR_BIT 0x00080000
|
||||
#define GL_ALL_ATTRIB_BITS 0x000fffff
|
||||
#define GL_POINTS 0x0000
|
||||
#define GL_LINES 0x0001
|
||||
#define GL_LINE_LOOP 0x0002
|
||||
#define GL_LINE_STRIP 0x0003
|
||||
#define GL_TRIANGLES 0x0004
|
||||
#define GL_TRIANGLE_STRIP 0x0005
|
||||
#define GL_TRIANGLE_FAN 0x0006
|
||||
#define GL_QUADS 0x0007
|
||||
#define GL_QUAD_STRIP 0x0008
|
||||
#define GL_POLYGON 0x0009
|
||||
#define GL_ZERO 0
|
||||
#define GL_ONE 1
|
||||
#define GL_SRC_COLOR 0x0300
|
||||
#define GL_ONE_MINUS_SRC_COLOR 0x0301
|
||||
#define GL_SRC_ALPHA 0x0302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
|
||||
#define GL_DST_ALPHA 0x0304
|
||||
#define GL_ONE_MINUS_DST_ALPHA 0x0305
|
||||
#define GL_DST_COLOR 0x0306
|
||||
#define GL_ONE_MINUS_DST_COLOR 0x0307
|
||||
#define GL_SRC_ALPHA_SATURATE 0x0308
|
||||
#define GL_TRUE 1
|
||||
#define GL_FALSE 0
|
||||
#define GL_CLIP_PLANE0 0x3000
|
||||
#define GL_CLIP_PLANE1 0x3001
|
||||
#define GL_CLIP_PLANE2 0x3002
|
||||
#define GL_CLIP_PLANE3 0x3003
|
||||
#define GL_CLIP_PLANE4 0x3004
|
||||
#define GL_CLIP_PLANE5 0x3005
|
||||
#define GL_BYTE 0x1400
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_SHORT 0x1402
|
||||
#define GL_UNSIGNED_SHORT 0x1403
|
||||
#define GL_INT 0x1404
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_2_BYTES 0x1407
|
||||
#define GL_3_BYTES 0x1408
|
||||
#define GL_4_BYTES 0x1409
|
||||
#define GL_DOUBLE 0x140A
|
||||
#define GL_NONE 0
|
||||
#define GL_FRONT_LEFT 0x0400
|
||||
#define GL_FRONT_RIGHT 0x0401
|
||||
#define GL_BACK_LEFT 0x0402
|
||||
#define GL_BACK_RIGHT 0x0403
|
||||
#define GL_FRONT 0x0404
|
||||
#define GL_BACK 0x0405
|
||||
#define GL_LEFT 0x0406
|
||||
#define GL_RIGHT 0x0407
|
||||
#define GL_FRONT_AND_BACK 0x0408
|
||||
#define GL_AUX0 0x0409
|
||||
#define GL_AUX1 0x040A
|
||||
#define GL_AUX2 0x040B
|
||||
#define GL_AUX3 0x040C
|
||||
#define GL_NO_ERROR 0
|
||||
#define GL_INVALID_ENUM 0x0500
|
||||
#define GL_INVALID_VALUE 0x0501
|
||||
#define GL_INVALID_OPERATION 0x0502
|
||||
#define GL_STACK_OVERFLOW 0x0503
|
||||
#define GL_STACK_UNDERFLOW 0x0504
|
||||
#define GL_OUT_OF_MEMORY 0x0505
|
||||
#define GL_2D 0x0600
|
||||
#define GL_3D 0x0601
|
||||
#define GL_3D_COLOR 0x0602
|
||||
#define GL_3D_COLOR_TEXTURE 0x0603
|
||||
#define GL_4D_COLOR_TEXTURE 0x0604
|
||||
#define GL_PASS_THROUGH_TOKEN 0x0700
|
||||
#define GL_POINT_TOKEN 0x0701
|
||||
#define GL_LINE_TOKEN 0x0702
|
||||
#define GL_POLYGON_TOKEN 0x0703
|
||||
#define GL_BITMAP_TOKEN 0x0704
|
||||
#define GL_DRAW_PIXEL_TOKEN 0x0705
|
||||
#define GL_COPY_PIXEL_TOKEN 0x0706
|
||||
#define GL_LINE_RESET_TOKEN 0x0707
|
||||
#define GL_EXP 0x0800
|
||||
#define GL_EXP2 0x0801
|
||||
#define GL_CW 0x0900
|
||||
#define GL_CCW 0x0901
|
||||
#define GL_COEFF 0x0A00
|
||||
#define GL_ORDER 0x0A01
|
||||
#define GL_DOMAIN 0x0A02
|
||||
#define GL_CURRENT_COLOR 0x0B00
|
||||
#define GL_CURRENT_INDEX 0x0B01
|
||||
#define GL_CURRENT_NORMAL 0x0B02
|
||||
#define GL_CURRENT_TEXTURE_COORDS 0x0B03
|
||||
#define GL_CURRENT_RASTER_COLOR 0x0B04
|
||||
#define GL_CURRENT_RASTER_INDEX 0x0B05
|
||||
#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06
|
||||
#define GL_CURRENT_RASTER_POSITION 0x0B07
|
||||
#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08
|
||||
#define GL_CURRENT_RASTER_DISTANCE 0x0B09
|
||||
#define GL_POINT_SMOOTH 0x0B10
|
||||
#define GL_POINT_SIZE 0x0B11
|
||||
#define GL_POINT_SIZE_RANGE 0x0B12
|
||||
#define GL_POINT_SIZE_GRANULARITY 0x0B13
|
||||
#define GL_LINE_SMOOTH 0x0B20
|
||||
#define GL_LINE_WIDTH 0x0B21
|
||||
#define GL_LINE_WIDTH_RANGE 0x0B22
|
||||
#define GL_LINE_WIDTH_GRANULARITY 0x0B23
|
||||
#define GL_LINE_STIPPLE 0x0B24
|
||||
#define GL_LINE_STIPPLE_PATTERN 0x0B25
|
||||
#define GL_LINE_STIPPLE_REPEAT 0x0B26
|
||||
#define GL_LIST_MODE 0x0B30
|
||||
#define GL_MAX_LIST_NESTING 0x0B31
|
||||
#define GL_LIST_BASE 0x0B32
|
||||
#define GL_LIST_INDEX 0x0B33
|
||||
#define GL_POLYGON_MODE 0x0B40
|
||||
#define GL_POLYGON_SMOOTH 0x0B41
|
||||
#define GL_POLYGON_STIPPLE 0x0B42
|
||||
#define GL_EDGE_FLAG 0x0B43
|
||||
#define GL_CULL_FACE 0x0B44
|
||||
#define GL_CULL_FACE_MODE 0x0B45
|
||||
#define GL_FRONT_FACE 0x0B46
|
||||
#define GL_LIGHTING 0x0B50
|
||||
#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51
|
||||
#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
|
||||
#define GL_LIGHT_MODEL_AMBIENT 0x0B53
|
||||
#define GL_SHADE_MODEL 0x0B54
|
||||
#define GL_COLOR_MATERIAL_FACE 0x0B55
|
||||
#define GL_COLOR_MATERIAL_PARAMETER 0x0B56
|
||||
#define GL_COLOR_MATERIAL 0x0B57
|
||||
#define GL_FOG 0x0B60
|
||||
#define GL_FOG_INDEX 0x0B61
|
||||
#define GL_FOG_DENSITY 0x0B62
|
||||
#define GL_FOG_START 0x0B63
|
||||
#define GL_FOG_END 0x0B64
|
||||
#define GL_FOG_MODE 0x0B65
|
||||
#define GL_FOG_COLOR 0x0B66
|
||||
#define GL_DEPTH_RANGE 0x0B70
|
||||
#define GL_DEPTH_TEST 0x0B71
|
||||
#define GL_DEPTH_WRITEMASK 0x0B72
|
||||
#define GL_DEPTH_CLEAR_VALUE 0x0B73
|
||||
#define GL_DEPTH_FUNC 0x0B74
|
||||
#define GL_ACCUM_CLEAR_VALUE 0x0B80
|
||||
#define GL_STENCIL_TEST 0x0B90
|
||||
#define GL_STENCIL_CLEAR_VALUE 0x0B91
|
||||
#define GL_STENCIL_FUNC 0x0B92
|
||||
#define GL_STENCIL_VALUE_MASK 0x0B93
|
||||
#define GL_STENCIL_FAIL 0x0B94
|
||||
#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
|
||||
#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
|
||||
#define GL_STENCIL_REF 0x0B97
|
||||
#define GL_STENCIL_WRITEMASK 0x0B98
|
||||
#define GL_MATRIX_MODE 0x0BA0
|
||||
#define GL_NORMALIZE 0x0BA1
|
||||
#define GL_VIEWPORT 0x0BA2
|
||||
#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
|
||||
#define GL_PROJECTION_STACK_DEPTH 0x0BA4
|
||||
#define GL_TEXTURE_STACK_DEPTH 0x0BA5
|
||||
#define GL_MODELVIEW_MATRIX 0x0BA6
|
||||
#define GL_PROJECTION_MATRIX 0x0BA7
|
||||
#define GL_TEXTURE_MATRIX 0x0BA8
|
||||
#define GL_ATTRIB_STACK_DEPTH 0x0BB0
|
||||
#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
|
||||
#define GL_ALPHA_TEST 0x0BC0
|
||||
#define GL_ALPHA_TEST_FUNC 0x0BC1
|
||||
#define GL_ALPHA_TEST_REF 0x0BC2
|
||||
#define GL_DITHER 0x0BD0
|
||||
#define GL_BLEND_DST 0x0BE0
|
||||
#define GL_BLEND_SRC 0x0BE1
|
||||
#define GL_BLEND 0x0BE2
|
||||
#define GL_LOGIC_OP_MODE 0x0BF0
|
||||
#define GL_INDEX_LOGIC_OP 0x0BF1
|
||||
#define GL_COLOR_LOGIC_OP 0x0BF2
|
||||
#define GL_AUX_BUFFERS 0x0C00
|
||||
#define GL_DRAW_BUFFER 0x0C01
|
||||
#define GL_READ_BUFFER 0x0C02
|
||||
#define GL_SCISSOR_BOX 0x0C10
|
||||
#define GL_SCISSOR_TEST 0x0C11
|
||||
#define GL_INDEX_CLEAR_VALUE 0x0C20
|
||||
#define GL_INDEX_WRITEMASK 0x0C21
|
||||
#define GL_COLOR_CLEAR_VALUE 0x0C22
|
||||
#define GL_COLOR_WRITEMASK 0x0C23
|
||||
#define GL_INDEX_MODE 0x0C30
|
||||
#define GL_RGBA_MODE 0x0C31
|
||||
#define GL_DOUBLEBUFFER 0x0C32
|
||||
#define GL_STEREO 0x0C33
|
||||
#define GL_RENDER_MODE 0x0C40
|
||||
#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
|
||||
#define GL_POINT_SMOOTH_HINT 0x0C51
|
||||
#define GL_LINE_SMOOTH_HINT 0x0C52
|
||||
#define GL_POLYGON_SMOOTH_HINT 0x0C53
|
||||
#define GL_FOG_HINT 0x0C54
|
||||
#define GL_TEXTURE_GEN_S 0x0C60
|
||||
#define GL_TEXTURE_GEN_T 0x0C61
|
||||
#define GL_TEXTURE_GEN_R 0x0C62
|
||||
#define GL_TEXTURE_GEN_Q 0x0C63
|
||||
#define GL_PIXEL_MAP_I_TO_I 0x0C70
|
||||
#define GL_PIXEL_MAP_S_TO_S 0x0C71
|
||||
#define GL_PIXEL_MAP_I_TO_R 0x0C72
|
||||
#define GL_PIXEL_MAP_I_TO_G 0x0C73
|
||||
#define GL_PIXEL_MAP_I_TO_B 0x0C74
|
||||
#define GL_PIXEL_MAP_I_TO_A 0x0C75
|
||||
#define GL_PIXEL_MAP_R_TO_R 0x0C76
|
||||
#define GL_PIXEL_MAP_G_TO_G 0x0C77
|
||||
#define GL_PIXEL_MAP_B_TO_B 0x0C78
|
||||
#define GL_PIXEL_MAP_A_TO_A 0x0C79
|
||||
#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0
|
||||
#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1
|
||||
#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2
|
||||
#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3
|
||||
#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4
|
||||
#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5
|
||||
#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6
|
||||
#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7
|
||||
#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8
|
||||
#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9
|
||||
#define GL_UNPACK_SWAP_BYTES 0x0CF0
|
||||
#define GL_UNPACK_LSB_FIRST 0x0CF1
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#define GL_UNPACK_SKIP_ROWS 0x0CF3
|
||||
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
|
||||
#define GL_UNPACK_ALIGNMENT 0x0CF5
|
||||
#define GL_PACK_SWAP_BYTES 0x0D00
|
||||
#define GL_PACK_LSB_FIRST 0x0D01
|
||||
#define GL_PACK_ROW_LENGTH 0x0D02
|
||||
#define GL_PACK_SKIP_ROWS 0x0D03
|
||||
#define GL_PACK_SKIP_PIXELS 0x0D04
|
||||
#define GL_PACK_ALIGNMENT 0x0D05
|
||||
#define GL_MAP_COLOR 0x0D10
|
||||
#define GL_MAP_STENCIL 0x0D11
|
||||
#define GL_INDEX_SHIFT 0x0D12
|
||||
#define GL_INDEX_OFFSET 0x0D13
|
||||
#define GL_RED_SCALE 0x0D14
|
||||
#define GL_RED_BIAS 0x0D15
|
||||
#define GL_ZOOM_X 0x0D16
|
||||
#define GL_ZOOM_Y 0x0D17
|
||||
#define GL_GREEN_SCALE 0x0D18
|
||||
#define GL_GREEN_BIAS 0x0D19
|
||||
#define GL_BLUE_SCALE 0x0D1A
|
||||
#define GL_BLUE_BIAS 0x0D1B
|
||||
#define GL_ALPHA_SCALE 0x0D1C
|
||||
#define GL_ALPHA_BIAS 0x0D1D
|
||||
#define GL_DEPTH_SCALE 0x0D1E
|
||||
#define GL_DEPTH_BIAS 0x0D1F
|
||||
#define GL_MAX_EVAL_ORDER 0x0D30
|
||||
#define GL_MAX_LIGHTS 0x0D31
|
||||
#define GL_MAX_CLIP_PLANES 0x0D32
|
||||
#define GL_MAX_TEXTURE_SIZE 0x0D33
|
||||
#define GL_MAX_PIXEL_MAP_TABLE 0x0D34
|
||||
#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35
|
||||
#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
|
||||
#define GL_MAX_NAME_STACK_DEPTH 0x0D37
|
||||
#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
|
||||
#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
|
||||
#define GL_MAX_VIEWPORT_DIMS 0x0D3A
|
||||
#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B
|
||||
#define GL_SUBPIXEL_BITS 0x0D50
|
||||
#define GL_INDEX_BITS 0x0D51
|
||||
#define GL_RED_BITS 0x0D52
|
||||
#define GL_GREEN_BITS 0x0D53
|
||||
#define GL_BLUE_BITS 0x0D54
|
||||
#define GL_ALPHA_BITS 0x0D55
|
||||
#define GL_DEPTH_BITS 0x0D56
|
||||
#define GL_STENCIL_BITS 0x0D57
|
||||
#define GL_ACCUM_RED_BITS 0x0D58
|
||||
#define GL_ACCUM_GREEN_BITS 0x0D59
|
||||
#define GL_ACCUM_BLUE_BITS 0x0D5A
|
||||
#define GL_ACCUM_ALPHA_BITS 0x0D5B
|
||||
#define GL_NAME_STACK_DEPTH 0x0D70
|
||||
#define GL_AUTO_NORMAL 0x0D80
|
||||
#define GL_MAP1_COLOR_4 0x0D90
|
||||
#define GL_MAP1_INDEX 0x0D91
|
||||
#define GL_MAP1_NORMAL 0x0D92
|
||||
#define GL_MAP1_TEXTURE_COORD_1 0x0D93
|
||||
#define GL_MAP1_TEXTURE_COORD_2 0x0D94
|
||||
#define GL_MAP1_TEXTURE_COORD_3 0x0D95
|
||||
#define GL_MAP1_TEXTURE_COORD_4 0x0D96
|
||||
#define GL_MAP1_VERTEX_3 0x0D97
|
||||
#define GL_MAP1_VERTEX_4 0x0D98
|
||||
#define GL_MAP2_COLOR_4 0x0DB0
|
||||
#define GL_MAP2_INDEX 0x0DB1
|
||||
#define GL_MAP2_NORMAL 0x0DB2
|
||||
#define GL_MAP2_TEXTURE_COORD_1 0x0DB3
|
||||
#define GL_MAP2_TEXTURE_COORD_2 0x0DB4
|
||||
#define GL_MAP2_TEXTURE_COORD_3 0x0DB5
|
||||
#define GL_MAP2_TEXTURE_COORD_4 0x0DB6
|
||||
#define GL_MAP2_VERTEX_3 0x0DB7
|
||||
#define GL_MAP2_VERTEX_4 0x0DB8
|
||||
#define GL_MAP1_GRID_DOMAIN 0x0DD0
|
||||
#define GL_MAP1_GRID_SEGMENTS 0x0DD1
|
||||
#define GL_MAP2_GRID_DOMAIN 0x0DD2
|
||||
#define GL_MAP2_GRID_SEGMENTS 0x0DD3
|
||||
#define GL_TEXTURE_1D 0x0DE0
|
||||
#define GL_TEXTURE_2D 0x0DE1
|
||||
#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0
|
||||
#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1
|
||||
#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2
|
||||
#define GL_SELECTION_BUFFER_POINTER 0x0DF3
|
||||
#define GL_SELECTION_BUFFER_SIZE 0x0DF4
|
||||
#define GL_TEXTURE_WIDTH 0x1000
|
||||
#define GL_TEXTURE_HEIGHT 0x1001
|
||||
#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
|
||||
#define GL_TEXTURE_BORDER_COLOR 0x1004
|
||||
#define GL_TEXTURE_BORDER 0x1005
|
||||
#define GL_DONT_CARE 0x1100
|
||||
#define GL_FASTEST 0x1101
|
||||
#define GL_NICEST 0x1102
|
||||
#define GL_LIGHT0 0x4000
|
||||
#define GL_LIGHT1 0x4001
|
||||
#define GL_LIGHT2 0x4002
|
||||
#define GL_LIGHT3 0x4003
|
||||
#define GL_LIGHT4 0x4004
|
||||
#define GL_LIGHT5 0x4005
|
||||
#define GL_LIGHT6 0x4006
|
||||
#define GL_LIGHT7 0x4007
|
||||
#define GL_AMBIENT 0x1200
|
||||
#define GL_DIFFUSE 0x1201
|
||||
#define GL_SPECULAR 0x1202
|
||||
#define GL_POSITION 0x1203
|
||||
#define GL_SPOT_DIRECTION 0x1204
|
||||
#define GL_SPOT_EXPONENT 0x1205
|
||||
#define GL_SPOT_CUTOFF 0x1206
|
||||
#define GL_CONSTANT_ATTENUATION 0x1207
|
||||
#define GL_LINEAR_ATTENUATION 0x1208
|
||||
#define GL_QUADRATIC_ATTENUATION 0x1209
|
||||
#define GL_COMPILE 0x1300
|
||||
#define GL_COMPILE_AND_EXECUTE 0x1301
|
||||
#define GL_CLEAR 0x1500
|
||||
#define GL_AND 0x1501
|
||||
#define GL_AND_REVERSE 0x1502
|
||||
#define GL_COPY 0x1503
|
||||
#define GL_AND_INVERTED 0x1504
|
||||
#define GL_NOOP 0x1505
|
||||
#define GL_XOR 0x1506
|
||||
#define GL_OR 0x1507
|
||||
#define GL_NOR 0x1508
|
||||
#define GL_EQUIV 0x1509
|
||||
#define GL_INVERT 0x150A
|
||||
#define GL_OR_REVERSE 0x150B
|
||||
#define GL_COPY_INVERTED 0x150C
|
||||
#define GL_OR_INVERTED 0x150D
|
||||
#define GL_NAND 0x150E
|
||||
#define GL_SET 0x150F
|
||||
#define GL_EMISSION 0x1600
|
||||
#define GL_SHININESS 0x1601
|
||||
#define GL_AMBIENT_AND_DIFFUSE 0x1602
|
||||
#define GL_COLOR_INDEXES 0x1603
|
||||
#define GL_MODELVIEW 0x1700
|
||||
#define GL_PROJECTION 0x1701
|
||||
#define GL_TEXTURE 0x1702
|
||||
#define GL_COLOR 0x1800
|
||||
#define GL_DEPTH 0x1801
|
||||
#define GL_STENCIL 0x1802
|
||||
#define GL_COLOR_INDEX 0x1900
|
||||
#define GL_STENCIL_INDEX 0x1901
|
||||
#define GL_DEPTH_COMPONENT 0x1902
|
||||
#define GL_RED 0x1903
|
||||
#define GL_GREEN 0x1904
|
||||
#define GL_BLUE 0x1905
|
||||
#define GL_ALPHA 0x1906
|
||||
#define GL_RGB 0x1907
|
||||
#define GL_RGBA 0x1908
|
||||
#define GL_LUMINANCE 0x1909
|
||||
#define GL_LUMINANCE_ALPHA 0x190A
|
||||
#define GL_BITMAP 0x1A00
|
||||
#define GL_POINT 0x1B00
|
||||
#define GL_LINE 0x1B01
|
||||
#define GL_FILL 0x1B02
|
||||
#define GL_RENDER 0x1C00
|
||||
#define GL_FEEDBACK 0x1C01
|
||||
#define GL_SELECT 0x1C02
|
||||
#define GL_FLAT 0x1D00
|
||||
#define GL_SMOOTH 0x1D01
|
||||
#define GL_KEEP 0x1E00
|
||||
#define GL_REPLACE 0x1E01
|
||||
#define GL_INCR 0x1E02
|
||||
#define GL_DECR 0x1E03
|
||||
#define GL_VENDOR 0x1F00
|
||||
#define GL_RENDERER 0x1F01
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_S 0x2000
|
||||
#define GL_T 0x2001
|
||||
#define GL_R 0x2002
|
||||
#define GL_Q 0x2003
|
||||
#define GL_MODULATE 0x2100
|
||||
#define GL_DECAL 0x2101
|
||||
#define GL_TEXTURE_ENV_MODE 0x2200
|
||||
#define GL_TEXTURE_ENV_COLOR 0x2201
|
||||
#define GL_TEXTURE_ENV 0x2300
|
||||
#define GL_EYE_LINEAR 0x2400
|
||||
#define GL_OBJECT_LINEAR 0x2401
|
||||
#define GL_SPHERE_MAP 0x2402
|
||||
#define GL_TEXTURE_GEN_MODE 0x2500
|
||||
#define GL_OBJECT_PLANE 0x2501
|
||||
#define GL_EYE_PLANE 0x2502
|
||||
#define GL_NEAREST 0x2600
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
|
||||
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
|
||||
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
|
||||
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
#define GL_TEXTURE_WRAP_S 0x2802
|
||||
#define GL_TEXTURE_WRAP_T 0x2803
|
||||
#define GL_CLAMP 0x2900
|
||||
#define GL_REPEAT 0x2901
|
||||
#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001
|
||||
#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002
|
||||
#define GL_CLIENT_ALL_ATTRIB_BITS 0xffffffff
|
||||
#define GL_POLYGON_OFFSET_FACTOR 0x8038
|
||||
#define GL_POLYGON_OFFSET_UNITS 0x2A00
|
||||
#define GL_POLYGON_OFFSET_POINT 0x2A01
|
||||
#define GL_POLYGON_OFFSET_LINE 0x2A02
|
||||
#define GL_POLYGON_OFFSET_FILL 0x8037
|
||||
#define GL_ALPHA4 0x803B
|
||||
#define GL_ALPHA8 0x803C
|
||||
#define GL_ALPHA12 0x803D
|
||||
#define GL_ALPHA16 0x803E
|
||||
#define GL_LUMINANCE4 0x803F
|
||||
#define GL_LUMINANCE8 0x8040
|
||||
#define GL_LUMINANCE12 0x8041
|
||||
#define GL_LUMINANCE16 0x8042
|
||||
#define GL_LUMINANCE4_ALPHA4 0x8043
|
||||
#define GL_LUMINANCE6_ALPHA2 0x8044
|
||||
#define GL_LUMINANCE8_ALPHA8 0x8045
|
||||
#define GL_LUMINANCE12_ALPHA4 0x8046
|
||||
#define GL_LUMINANCE12_ALPHA12 0x8047
|
||||
#define GL_LUMINANCE16_ALPHA16 0x8048
|
||||
#define GL_INTENSITY 0x8049
|
||||
#define GL_INTENSITY4 0x804A
|
||||
#define GL_INTENSITY8 0x804B
|
||||
#define GL_INTENSITY12 0x804C
|
||||
#define GL_INTENSITY16 0x804D
|
||||
#define GL_R3_G3_B2 0x2A10
|
||||
#define GL_RGB4 0x804F
|
||||
#define GL_RGB5 0x8050
|
||||
#define GL_RGB8 0x8051
|
||||
#define GL_RGB10 0x8052
|
||||
#define GL_RGB12 0x8053
|
||||
#define GL_RGB16 0x8054
|
||||
#define GL_RGBA2 0x8055
|
||||
#define GL_RGBA4 0x8056
|
||||
#define GL_RGB5_A1 0x8057
|
||||
#define GL_RGBA8 0x8058
|
||||
#define GL_RGB10_A2 0x8059
|
||||
#define GL_RGBA12 0x805A
|
||||
#define GL_RGBA16 0x805B
|
||||
#define GL_TEXTURE_RED_SIZE 0x805C
|
||||
#define GL_TEXTURE_GREEN_SIZE 0x805D
|
||||
#define GL_TEXTURE_BLUE_SIZE 0x805E
|
||||
#define GL_TEXTURE_ALPHA_SIZE 0x805F
|
||||
#define GL_TEXTURE_LUMINANCE_SIZE 0x8060
|
||||
#define GL_TEXTURE_INTENSITY_SIZE 0x8061
|
||||
#define GL_PROXY_TEXTURE_1D 0x8063
|
||||
#define GL_PROXY_TEXTURE_2D 0x8064
|
||||
#define GL_TEXTURE_PRIORITY 0x8066
|
||||
#define GL_TEXTURE_RESIDENT 0x8067
|
||||
#define GL_TEXTURE_BINDING_1D 0x8068
|
||||
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||
#define GL_VERTEX_ARRAY 0x8074
|
||||
#define GL_NORMAL_ARRAY 0x8075
|
||||
#define GL_COLOR_ARRAY 0x8076
|
||||
#define GL_INDEX_ARRAY 0x8077
|
||||
#define GL_TEXTURE_COORD_ARRAY 0x8078
|
||||
#define GL_EDGE_FLAG_ARRAY 0x8079
|
||||
#define GL_VERTEX_ARRAY_SIZE 0x807A
|
||||
#define GL_VERTEX_ARRAY_TYPE 0x807B
|
||||
#define GL_VERTEX_ARRAY_STRIDE 0x807C
|
||||
#define GL_NORMAL_ARRAY_TYPE 0x807E
|
||||
#define GL_NORMAL_ARRAY_STRIDE 0x807F
|
||||
#define GL_COLOR_ARRAY_SIZE 0x8081
|
||||
#define GL_COLOR_ARRAY_TYPE 0x8082
|
||||
#define GL_COLOR_ARRAY_STRIDE 0x8083
|
||||
#define GL_INDEX_ARRAY_TYPE 0x8085
|
||||
#define GL_INDEX_ARRAY_STRIDE 0x8086
|
||||
#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
|
||||
#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
|
||||
#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
|
||||
#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C
|
||||
#define GL_VERTEX_ARRAY_POINTER 0x808E
|
||||
#define GL_NORMAL_ARRAY_POINTER 0x808F
|
||||
#define GL_COLOR_ARRAY_POINTER 0x8090
|
||||
#define GL_INDEX_ARRAY_POINTER 0x8091
|
||||
#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
|
||||
#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093
|
||||
#define GL_V2F 0x2A20
|
||||
#define GL_V3F 0x2A21
|
||||
#define GL_C4UB_V2F 0x2A22
|
||||
#define GL_C4UB_V3F 0x2A23
|
||||
#define GL_C3F_V3F 0x2A24
|
||||
#define GL_N3F_V3F 0x2A25
|
||||
#define GL_C4F_N3F_V3F 0x2A26
|
||||
#define GL_T2F_V3F 0x2A27
|
||||
#define GL_T4F_V4F 0x2A28
|
||||
#define GL_T2F_C4UB_V3F 0x2A29
|
||||
#define GL_T2F_C3F_V3F 0x2A2A
|
||||
#define GL_T2F_N3F_V3F 0x2A2B
|
||||
#define GL_T2F_C4F_N3F_V3F 0x2A2C
|
||||
#define GL_T4F_C4F_N3F_V4F 0x2A2D
|
||||
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||
#define GL_STATIC_DRAW 0x88E4
|
||||
#define GL_DYNAMIC_DRAW 0x88E8
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
|
||||
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_TEXTURE1 0x84C1
|
||||
#define GL_TEXTURE2 0x84C2
|
||||
#define GL_TEXTURE3 0x84C3
|
||||
#define GL_TEXTURE4 0x84C4
|
||||
#define GL_TEXTURE5 0x84C5
|
||||
#define GL_TEXTURE6 0x84C6
|
||||
#define GL_TEXTURE7 0x84C7
|
||||
#define GL_TEXTURE8 0x84C8
|
||||
#define GL_TEXTURE9 0x84C9
|
||||
#define GL_TEXTURE10 0x84CA
|
||||
#define GL_TEXTURE11 0x84CB
|
||||
#define GL_TEXTURE12 0x84CC
|
||||
#define GL_TEXTURE13 0x84CD
|
||||
#define GL_TEXTURE14 0x84CE
|
||||
#define GL_TEXTURE15 0x84CF
|
||||
#define GL_TEXTURE16 0x84D0
|
||||
#define GL_TEXTURE17 0x84D1
|
||||
#define GL_TEXTURE18 0x84D2
|
||||
#define GL_TEXTURE19 0x84D3
|
||||
#define GL_TEXTURE20 0x84D4
|
||||
#define GL_TEXTURE21 0x84D5
|
||||
#define GL_TEXTURE22 0x84D6
|
||||
#define GL_TEXTURE23 0x84D7
|
||||
#define GL_TEXTURE24 0x84D8
|
||||
#define GL_TEXTURE25 0x84D9
|
||||
#define GL_TEXTURE26 0x84DA
|
||||
#define GL_TEXTURE27 0x84DB
|
||||
#define GL_TEXTURE28 0x84DC
|
||||
#define GL_TEXTURE29 0x84DD
|
||||
#define GL_TEXTURE30 0x84DE
|
||||
#define GL_TEXTURE31 0x84DF
|
||||
|
||||
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
|
||||
#define GL_DEBUG_SEVERITY_HIGH 0x9146
|
||||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
|
||||
|
||||
#endif //VN_OPENGL_DEFINES_H
|
|
@ -0,0 +1,69 @@
|
|||
inline void Platform_ConsumeEvent(platform_event_list *EventList, platform_event *Event)
|
||||
{
|
||||
DLLRemove(EventList->First, EventList->Last, Event);
|
||||
}
|
||||
|
||||
inline b32 Platform_KeyPress(platform_event_list *EventList, platform_key Key,
|
||||
platform_modifiers Modifiers = PlatformModifier_DoesNotMatter)
|
||||
{
|
||||
b32 Result = false;
|
||||
|
||||
for(platform_event *Event = EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if((Event->Type == PlatformEvent_Press) &&
|
||||
(Event->Key == Key) &&
|
||||
((Modifiers == PlatformModifier_DoesNotMatter) ||
|
||||
(Event->Modifiers ^ Modifiers) == 0))
|
||||
{
|
||||
Result = true;
|
||||
Platform_ConsumeEvent(EventList, Event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline b32 Platform_KeyRelease(platform_event_list *EventList, platform_key Key,
|
||||
platform_modifiers Modifiers = PlatformModifier_DoesNotMatter)
|
||||
{
|
||||
b32 Result = false;
|
||||
|
||||
for(platform_event *Event = EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if((Event->Type == PlatformEvent_Release) &&
|
||||
(Event->Key == Key) &&
|
||||
((Modifiers == PlatformModifier_DoesNotMatter) ||
|
||||
((Event->Modifiers & Modifiers) != 0) ||
|
||||
((Event->Modifiers == 0) && (Modifiers == 0))))
|
||||
{
|
||||
Result = true;
|
||||
Platform_ConsumeEvent(EventList, Event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static string Platform_ReadEntireFile(memory_arena *Arena, string Path)
|
||||
{
|
||||
string Result = {};
|
||||
|
||||
platform_file_handle File = Platform.OpenFile(Path, PlatformAccess_Read);
|
||||
if(File.IsValid)
|
||||
{
|
||||
Result.Count = Platform.GetFileSize(File);
|
||||
|
||||
Result.Data = PushArray(Arena, u8, Result.Count);
|
||||
Platform.ReadFile(File, Result.Data, 0, Result.Count);
|
||||
|
||||
Platform.CloseFile(File);
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/* date = April 26th 2023 5:12 pm */
|
||||
|
||||
#ifndef VN_PLATFORM_H
|
||||
#define VN_PLATFORM_H
|
||||
|
||||
#include "vn_core.h"
|
||||
|
||||
// sixten: Services the platform provides to the game
|
||||
|
||||
struct platform_memory_block
|
||||
{
|
||||
u8 *Base;
|
||||
u64 Size;
|
||||
|
||||
u64 Used;
|
||||
platform_memory_block *ArenaPrev;
|
||||
};
|
||||
|
||||
#define PLATFORM_ALLOCATE_MEMORY(name) platform_memory_block *name(u64 Size)
|
||||
typedef PLATFORM_ALLOCATE_MEMORY(platform_allocate_memory);
|
||||
|
||||
#define PLATFORM_DEALLOCATE_MEMORY(name) b32 name(platform_memory_block *Block)
|
||||
typedef PLATFORM_DEALLOCATE_MEMORY(platform_deallocate_memory);
|
||||
|
||||
enum
|
||||
{
|
||||
PlatformAccess_Read = 0x1,
|
||||
PlatformAccess_Write = 0x2,
|
||||
};
|
||||
typedef u32 platform_access_flags;
|
||||
|
||||
struct platform_file_handle
|
||||
{
|
||||
u64 Platform;
|
||||
b32 IsValid;
|
||||
};
|
||||
|
||||
#define PLATFORM_OPEN_FILE(name) platform_file_handle name(string Path, platform_access_flags FileAccess)
|
||||
typedef PLATFORM_OPEN_FILE(platform_open_file);
|
||||
|
||||
#define PLATFORM_CLOSE_FILE(name) void name(platform_file_handle Handle)
|
||||
typedef PLATFORM_CLOSE_FILE(platform_close_file);
|
||||
|
||||
#define PLATFORM_READ_FILE(name) void name(platform_file_handle Handle, void *Dest, u64 Offset, u64 Size)
|
||||
typedef PLATFORM_READ_FILE(platform_read_file);
|
||||
|
||||
#define PLATFORM_GET_FILE_SIZE(name) u64 name(platform_file_handle Handle)
|
||||
typedef PLATFORM_GET_FILE_SIZE(platform_get_file_size);
|
||||
|
||||
enum platform_cursor
|
||||
{
|
||||
PlatformCursor_Arrow,
|
||||
PlatformCursor_Cross,
|
||||
PlatformCursor_Hand,
|
||||
PlatformCursor_Help,
|
||||
PlatformCursor_IBeam,
|
||||
PlatformCursor_SlashedCircle,
|
||||
PlatformCursor_ArrowAll,
|
||||
PlatformCursor_ArrowNESW,
|
||||
PlatformCursor_ArrowVertical,
|
||||
PlatformCursor_ArrowNWSE,
|
||||
PlatformCursor_ArrowHorizontal,
|
||||
PlatformCursor_Wait,
|
||||
|
||||
PlatformCursor_Count
|
||||
};
|
||||
|
||||
#define PLATFORM_SET_CURSOR(name) void name(platform_cursor Cursor)
|
||||
typedef PLATFORM_SET_CURSOR(platform_set_cursor);
|
||||
|
||||
#define PLATFORM_TOGGLE_FULLSCREEN(name) void name(void)
|
||||
typedef PLATFORM_TOGGLE_FULLSCREEN(platform_toggle_fullscreen);
|
||||
|
||||
struct platform_api
|
||||
{
|
||||
platform_allocate_memory *AllocateMemory;
|
||||
platform_deallocate_memory *DeallocateMemory;
|
||||
|
||||
platform_open_file *OpenFile;
|
||||
platform_close_file *CloseFile;
|
||||
platform_read_file *ReadFile;
|
||||
platform_get_file_size *GetFileSize;
|
||||
|
||||
platform_set_cursor *SetCursor;
|
||||
platform_toggle_fullscreen *ToggleFullscreen;
|
||||
};
|
||||
|
||||
enum platform_event_type
|
||||
{
|
||||
PlatformEvent_Press,
|
||||
PlatformEvent_Release,
|
||||
PlatformEvent_Text,
|
||||
PlatformEvent_MouseScroll,
|
||||
};
|
||||
|
||||
enum platform_key
|
||||
{
|
||||
Key_Invalid,
|
||||
|
||||
Key_A, Key_B, Key_C, Key_D,
|
||||
Key_E, Key_F, Key_G, Key_H,
|
||||
Key_I, Key_J, Key_K, Key_L,
|
||||
Key_M, Key_N, Key_O, Key_P,
|
||||
Key_Q, Key_R, Key_S, Key_T,
|
||||
Key_U, Key_V, Key_W, Key_X,
|
||||
Key_Y, Key_Z,
|
||||
|
||||
Key_F1, Key_F2, Key_F3, Key_F4,
|
||||
Key_F5, Key_F6, Key_F7, Key_F8,
|
||||
Key_F9, Key_F10, Key_F11, Key_F12,
|
||||
|
||||
Key_Left, Key_Right, Key_Up, Key_Down,
|
||||
|
||||
Key_Space,
|
||||
|
||||
Key_PageUp, Key_PageDown,
|
||||
Key_Home, Key_End,
|
||||
|
||||
Key_Backspace, Key_Delete,
|
||||
|
||||
Key_MouseLeft, Key_MouseMiddle, Key_MouseRight,
|
||||
};
|
||||
|
||||
typedef u32 platform_modifiers;
|
||||
enum
|
||||
{
|
||||
PlatformModifier_Ctrl = (1 << 0),
|
||||
PlatformModifier_Shift = (1 << 1),
|
||||
PlatformModifier_Alt = (1 << 2),
|
||||
|
||||
PlatformModifier_DoesNotMatter = -1
|
||||
};
|
||||
|
||||
struct platform_event
|
||||
{
|
||||
platform_event *Next;
|
||||
platform_event *Prev;
|
||||
platform_event_type Type;
|
||||
platform_modifiers Modifiers;
|
||||
platform_key Key;
|
||||
u32 Codepoint;
|
||||
v2 P;
|
||||
v2 Scroll;
|
||||
};
|
||||
|
||||
struct platform_event_list
|
||||
{
|
||||
platform_event *First;
|
||||
platform_event *Last;
|
||||
};
|
||||
|
||||
static platform_api Platform;
|
||||
|
||||
// sixten: Services that the render backend provides to the game
|
||||
|
||||
#include "vn_render.h"
|
||||
|
||||
#define RENDER_ALLOCATE_TEXTURE(name) render_handle name(v2s Dim, render_texture_format Format, void *Data)
|
||||
typedef RENDER_ALLOCATE_TEXTURE(render_allocate_texture);
|
||||
|
||||
#define RENDER_FILL_REGION(name) void name(render_handle Handle, v2s DestP, v2s DestDim, void *Data)
|
||||
typedef RENDER_FILL_REGION(render_fill_region);
|
||||
|
||||
struct vn_render_commands
|
||||
{
|
||||
render_allocate_texture *AllocateTexture;
|
||||
render_fill_region *FillRegion;
|
||||
|
||||
render_handle WhiteTexture;
|
||||
|
||||
u64 MaxPushBufferSize;
|
||||
u8 *PushBufferBase;
|
||||
u8 *PushBufferAt;
|
||||
|
||||
s32 MaxQuadVertexCount;
|
||||
quad_vertex *QuadVertexBase;
|
||||
s32 QuadVertexCount;
|
||||
|
||||
s32 MaxQuadIndexCount;
|
||||
s32 *QuadIndexBase;
|
||||
s32 QuadIndexCount;
|
||||
|
||||
v2 RenderDim;
|
||||
};
|
||||
|
||||
#include "vn_memory.h"
|
||||
#include "vn_string.h"
|
||||
#include "vn_thread_context.h"
|
||||
|
||||
// sixten: Services the game provides to the platform
|
||||
|
||||
struct vn_input
|
||||
{
|
||||
platform_event_list *EventList;
|
||||
|
||||
v2 MouseP;
|
||||
v2 dMouseP;
|
||||
|
||||
r32 dtForFrame;
|
||||
};
|
||||
|
||||
struct vn_memory
|
||||
{
|
||||
platform_api PlatformAPI;
|
||||
|
||||
struct vn_state *State;
|
||||
};
|
||||
|
||||
#define VN_UPDATE_AND_RENDER(name) void name(thread_context *ThreadContext, vn_memory *Memory, vn_input *Input, vn_render_commands *RenderCommands)
|
||||
typedef VN_UPDATE_AND_RENDER(vn_update_and_render);
|
||||
|
||||
#endif //VN_PLATFORM_H
|
|
@ -0,0 +1,244 @@
|
|||
inline b32 AreEqual(render_handle A, render_handle B)
|
||||
{
|
||||
b32 Result = false;
|
||||
if((A.U64[0] == B.U64[0]) && (A.U64[1] == B.U64[1]) &&
|
||||
(A.U64[2] == B.U64[2]) && (A.U64[3] == B.U64[3]))
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2s GetTextureDim(render_handle Handle)
|
||||
{
|
||||
v2s Result = V2S(Handle.U32[2], Handle.U32[3]);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline render_handle EmptyRenderHandle(void)
|
||||
{
|
||||
render_handle Result = {};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#define PushCommand(Group, type) (type *)PushCommand_(Group, Render_Command_##type, sizeof(type))
|
||||
static void *PushCommand_(render_group *Group, render_command_type Type, u64 Size)
|
||||
{
|
||||
void *Result = 0;
|
||||
|
||||
vn_render_commands *Commands = Group->Commands;
|
||||
|
||||
u64 TotalSize = Size + sizeof(render_command_header);
|
||||
|
||||
u8 *PushBufferEnd = Commands->PushBufferBase + Commands->MaxPushBufferSize;
|
||||
if((Commands->PushBufferAt + TotalSize) <= PushBufferEnd)
|
||||
{
|
||||
render_command_header *Header = (render_command_header *)Commands->PushBufferAt;
|
||||
Header->Type = Type;
|
||||
|
||||
Commands->PushBufferAt += sizeof(*Header);
|
||||
|
||||
Group->CurrentCommand = Header;
|
||||
|
||||
Result = Commands->PushBufferAt;
|
||||
Commands->PushBufferAt += Size;
|
||||
ZeroSize(Result, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidCodepath;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline render_group BeginRenderGroup(vn_render_commands *Commands)
|
||||
{
|
||||
render_group Group = {};
|
||||
Group.Commands = Commands;
|
||||
Group.ClipStack[0].Max = Commands->RenderDim;
|
||||
return(Group);
|
||||
}
|
||||
|
||||
inline void PushClear(render_group *Group, v3 Color)
|
||||
{
|
||||
render_command_clear *Command = PushCommand(Group, render_command_clear);
|
||||
Command->Color = Color;
|
||||
}
|
||||
|
||||
inline s32 GetTextureIndexForCommand(render_command_quads *Command, render_handle Handle)
|
||||
{
|
||||
s32 Result = -1;
|
||||
|
||||
for(s32 TextureIndex = 0;
|
||||
TextureIndex < MAX_BOUND_TEXTURES;
|
||||
++TextureIndex)
|
||||
{
|
||||
if(AreEqual(Command->Textures[TextureIndex], EmptyRenderHandle()))
|
||||
{
|
||||
Assert(Command->TexturesUsed == TextureIndex);
|
||||
|
||||
Command->Textures[TextureIndex] = Handle;
|
||||
++Command->TexturesUsed;
|
||||
}
|
||||
|
||||
if(AreEqual(Command->Textures[TextureIndex], Handle))
|
||||
{
|
||||
Result = TextureIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u32 PackV4ToU32(v4 V)
|
||||
{
|
||||
u32 Result =
|
||||
((u8)(Clamp01(V.x)*255.0)<<24) |
|
||||
((u8)(Clamp01(V.y)*255.0)<<16) |
|
||||
((u8)(Clamp01(V.z)*255.0)<<8) |
|
||||
((u8)(Clamp01(V.w)*255.0)<<0);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void PushTexturedQuad(render_group *Group,
|
||||
v2 P, v2 Dim,
|
||||
v2 SourceP, v2 SourceDim,
|
||||
v4 Color00, v4 Color10, v4 Color01, v4 Color11,
|
||||
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness,
|
||||
render_handle Texture)
|
||||
{
|
||||
vn_render_commands *Commands = Group->Commands;
|
||||
|
||||
render_command_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))
|
||||
{
|
||||
Command = PushCommand(Group, render_command_quads);
|
||||
Command->QuadBufferIndex = Commands->QuadIndexCount;
|
||||
TextureIndex = GetTextureIndexForCommand(Command, Texture);
|
||||
}
|
||||
|
||||
range2_r32 Clip = Group->ClipStack[Group->ClipStackUsed];
|
||||
range2_r32 Dest = Range2R32(P, P + Dim);
|
||||
|
||||
v2 DestMin = Max(Dest.Min, Clip.Min);
|
||||
v2 DestMax = Min(Dest.Max, Clip.Max);
|
||||
|
||||
//if(InRange(Clip, P) || InRange(Clip, P + Dim))
|
||||
{
|
||||
v2 HalfSize = Dim*0.5;
|
||||
|
||||
v2 P00 = V2(DestMin.x, DestMin.y);
|
||||
v2 P01 = V2(DestMin.x, DestMax.y);
|
||||
v2 P10 = V2(DestMax.x, DestMin.y);
|
||||
v2 P11 = V2(DestMax.x, DestMax.y);
|
||||
v2 Center = P + HalfSize;
|
||||
|
||||
u32 Width = Texture.U32[2];
|
||||
u32 Height = Texture.U32[3];
|
||||
|
||||
SourceP.x /= Width;
|
||||
SourceP.y /= Height;
|
||||
SourceDim.x /= Width;
|
||||
SourceDim.y /= Height;
|
||||
|
||||
v2 Source00 = SourceP;
|
||||
v2 Source01 = SourceP + V2(0, SourceDim.y);
|
||||
v2 Source10 = SourceP + V2(SourceDim.x, 0);
|
||||
v2 Source11 = SourceP + SourceDim;
|
||||
|
||||
s32 BaseVertex = Commands->QuadVertexCount;
|
||||
|
||||
quad_vertex *Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
|
||||
Vertex->P = P00;
|
||||
Vertex->SourceP = Source00;
|
||||
Vertex->TextureIndex = TextureIndex;
|
||||
Vertex->Color = PackV4ToU32(Color00);
|
||||
Vertex->ToCenter = Center - P00;
|
||||
Vertex->HalfSize = HalfSize;
|
||||
Vertex->CornerRadius = CornerRadius;
|
||||
Vertex->EdgeSoftness = EdgeSoftness;
|
||||
Vertex->BorderThickness = BorderThickness;
|
||||
|
||||
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
|
||||
Vertex->P = P10;
|
||||
Vertex->SourceP = Source10;
|
||||
Vertex->TextureIndex = TextureIndex;
|
||||
Vertex->Color = PackV4ToU32(Color10);
|
||||
Vertex->ToCenter = Center - P10;
|
||||
Vertex->HalfSize = HalfSize;
|
||||
Vertex->CornerRadius = CornerRadius;
|
||||
Vertex->EdgeSoftness = EdgeSoftness;
|
||||
Vertex->BorderThickness = BorderThickness;
|
||||
|
||||
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
|
||||
Vertex->P = P01;
|
||||
Vertex->SourceP = Source01;
|
||||
Vertex->TextureIndex = TextureIndex;
|
||||
Vertex->Color = PackV4ToU32(Color01);
|
||||
Vertex->ToCenter = Center - P01;
|
||||
Vertex->HalfSize = HalfSize;
|
||||
Vertex->CornerRadius = CornerRadius;
|
||||
Vertex->EdgeSoftness = EdgeSoftness;
|
||||
Vertex->BorderThickness = BorderThickness;
|
||||
|
||||
Vertex = Commands->QuadVertexBase + Commands->QuadVertexCount++;
|
||||
Vertex->P = P11;
|
||||
Vertex->SourceP = Source11;
|
||||
Vertex->TextureIndex = TextureIndex;
|
||||
Vertex->Color = PackV4ToU32(Color11);
|
||||
Vertex->ToCenter = Center - P11;
|
||||
Vertex->HalfSize = HalfSize;
|
||||
Vertex->CornerRadius = CornerRadius;
|
||||
Vertex->EdgeSoftness = EdgeSoftness;
|
||||
Vertex->BorderThickness = BorderThickness;
|
||||
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 1;
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 0;
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 2;
|
||||
Commands->QuadIndexBase[Commands->QuadIndexCount++] = BaseVertex + 3;
|
||||
|
||||
++Command->QuadCount;
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
int BreakMe = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void PushQuad(render_group *Group, v2 P, v2 Dim,
|
||||
v4 Color00, v4 Color01, v4 Color10, v4 Color11,
|
||||
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness)
|
||||
{
|
||||
PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color00, Color01, Color10, Color11,
|
||||
CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture);
|
||||
}
|
||||
|
||||
inline void PushQuad(render_group *Group, v2 P, v2 Dim,
|
||||
v4 Color,
|
||||
r32 CornerRadius, r32 EdgeSoftness, r32 BorderThickness)
|
||||
{
|
||||
PushTexturedQuad(Group, P, Dim, V2(0, 0), V2(0, 0), Color, Color, Color, Color,
|
||||
CornerRadius, EdgeSoftness, BorderThickness, Group->Commands->WhiteTexture);
|
||||
}
|
||||
|
||||
inline void PushClip(render_group *Group, range2_r32 Clip)
|
||||
{
|
||||
Assert(Group->ClipStackUsed + 1 < ArrayCount(Group->ClipStack));
|
||||
|
||||
Group->ClipStack[++Group->ClipStackUsed] = Clip;
|
||||
}
|
||||
|
||||
inline void PopClip(render_group *Group)
|
||||
{
|
||||
Assert(Group->ClipStackUsed > 0);
|
||||
|
||||
Group->ClipStack[--Group->ClipStackUsed];
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* date = April 26th 2023 11:04 pm */
|
||||
|
||||
#ifndef VN_RENDER_H
|
||||
#define VN_RENDER_H
|
||||
|
||||
#define MAX_BOUND_TEXTURES 16
|
||||
#define MAX_QUAD_COUNT 16*1024
|
||||
|
||||
#define ColorFromHex(Value) V4((((Value) >> 24) & 0xFF) / 255.0, (((Value) >> 16) & 0xFF) / 255.0, (((Value) >> 8) & 0xFF) / 255.0, (((Value) >> 0) & 0xFF) / 255.0)
|
||||
|
||||
read_only v4 Color_Black = V4(0, 0, 0, 1);
|
||||
read_only v4 Color_White = V4(1, 1, 1, 1);
|
||||
read_only v4 Color_Grey = V4(0.5, 0.5, 0.5, 1);
|
||||
read_only v4 Color_Red = V4(1, 0, 0, 1);
|
||||
read_only v4 Color_Green = V4(0, 1, 0, 1);
|
||||
read_only v4 Color_Blue = V4(0, 0, 1, 1);
|
||||
read_only v4 Color_Yellow = V4(1, 1, 0, 1);
|
||||
read_only v4 Color_Magenta = V4(1, 0, 1, 1);
|
||||
read_only v4 Color_Cyan = V4(0, 1, 1, 1);
|
||||
|
||||
enum render_texture_format
|
||||
{
|
||||
Render_TextureFormat_R8,
|
||||
Render_TextureFormat_RGB8,
|
||||
Render_TextureFormat_RGBA8,
|
||||
};
|
||||
|
||||
struct render_handle
|
||||
{
|
||||
union
|
||||
{
|
||||
u64 U64[4];
|
||||
u32 U32[8];
|
||||
};
|
||||
};
|
||||
|
||||
enum render_command_type
|
||||
{
|
||||
Render_Command_render_command_clear,
|
||||
Render_Command_render_command_quads,
|
||||
Render_Command_render_command_clip,
|
||||
};
|
||||
|
||||
struct render_command_clear
|
||||
{
|
||||
v3 Color;
|
||||
};
|
||||
|
||||
struct render_command_quads
|
||||
{
|
||||
u64 QuadCount;
|
||||
u64 QuadBufferIndex;
|
||||
|
||||
s32 TexturesUsed;
|
||||
render_handle Textures[16];
|
||||
};
|
||||
|
||||
struct render_command_clip
|
||||
{
|
||||
range2_r32 ClipRect;
|
||||
};
|
||||
|
||||
struct render_command_header
|
||||
{
|
||||
render_command_type Type;
|
||||
};
|
||||
|
||||
struct render_group
|
||||
{
|
||||
struct vn_render_commands *Commands;
|
||||
|
||||
render_command_header *CurrentCommand;
|
||||
|
||||
range2_r32 ClipStack[64];
|
||||
s32 ClipStackUsed;
|
||||
};
|
||||
|
||||
struct quad_vertex
|
||||
{
|
||||
v2 P;
|
||||
v2 SourceP;
|
||||
u32 TextureIndex;
|
||||
u32 Color;
|
||||
v2 ToCenter; // sixten: ToCenter = Center - P
|
||||
v2 HalfSize;
|
||||
r32 CornerRadius;
|
||||
r32 EdgeSoftness;
|
||||
r32 BorderThickness;
|
||||
};
|
||||
|
||||
#endif //VN_RENDER_H
|
|
@ -0,0 +1,227 @@
|
|||
/* date = May 7th 2023 9:01 pm */
|
||||
|
||||
#ifndef VN_STRING_H
|
||||
#define VN_STRING_H
|
||||
|
||||
inline b32 IsWhitespace(char C)
|
||||
{
|
||||
b32 Result = ((C == ' ') ||
|
||||
(C == '\n') ||
|
||||
(C == '\t') ||
|
||||
(C == '\r'));
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline s64 StringLength(char *String)
|
||||
{
|
||||
s64 Result = 0;
|
||||
while(*String++)
|
||||
{
|
||||
++Result;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline u64 HashString(string String)
|
||||
{
|
||||
u64 Result = 5731;
|
||||
for(s64 Index = 0;
|
||||
Index < String.Count;
|
||||
++Index)
|
||||
{
|
||||
Result += String.Data[Index];
|
||||
Result ^= Result << 13;
|
||||
Result ^= Result >> 7;
|
||||
Result ^= Result << 17;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline string MakeStringFromCString(char *Data)
|
||||
{
|
||||
string Result = {StringLength(Data), (u8 *)Data};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline s64 FirstIndexOf(string String, char Char)
|
||||
{
|
||||
s64 Result = -1;
|
||||
for(s64 Index = 0;
|
||||
Index < String.Count;
|
||||
++Index)
|
||||
{
|
||||
if(String.Data[Index] == Char)
|
||||
{
|
||||
Result = Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline s64 LastIndexOf(string String, char Char)
|
||||
{
|
||||
s64 Result = -1;
|
||||
for(s64 Index = String.Count-1;
|
||||
Index >= 0;
|
||||
--Index)
|
||||
{
|
||||
if(String.Data[Index] == Char)
|
||||
{
|
||||
Result = Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline b32 AreEqual(string A, string B)
|
||||
{
|
||||
b32 Result = false;
|
||||
if(A.Count == B.Count)
|
||||
{
|
||||
Result = true;
|
||||
|
||||
for(s64 Index = 0;
|
||||
Index < A.Count;
|
||||
++Index)
|
||||
{
|
||||
if(A.Data[Index] != B.Data[Index])
|
||||
{
|
||||
Result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint)
|
||||
{
|
||||
s64 Length = 0;
|
||||
if(Codepoint <= 0x7F)
|
||||
{
|
||||
Out[0] = (u8)Codepoint;
|
||||
Length = 1;
|
||||
}
|
||||
else if(Codepoint <= 0x7FF)
|
||||
{
|
||||
Out[0] = (0x3 << 6) | ((Codepoint >> 6) & 0x1F);
|
||||
Out[1] = 0x80 | ( Codepoint & 0x3F);
|
||||
Length = 2;
|
||||
}
|
||||
else if(Codepoint <= 0xFFFF)
|
||||
{
|
||||
Out[0] = (0x7 << 5) | ((Codepoint >> 12) & 0x0F);
|
||||
Out[1] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
||||
Out[2] = 0x80 | ( Codepoint & 0x3F);
|
||||
Length = 3;
|
||||
}
|
||||
else if(Codepoint <= 0x10FFFF)
|
||||
{
|
||||
Out[0] = (0xF << 4) | ((Codepoint >> 12) & 0x07);
|
||||
Out[1] = 0x80 | ((Codepoint >> 12) & 0x3F);
|
||||
Out[2] = 0x80 | ((Codepoint >> 6) & 0x3F);
|
||||
Out[3] = 0x80 | ( Codepoint & 0x3F);
|
||||
Length = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Out[0] = '?';
|
||||
Length = 1;
|
||||
}
|
||||
|
||||
return(Length);
|
||||
}
|
||||
|
||||
inline s64 GetCodepointSize(u32 Codepoint)
|
||||
{
|
||||
s64 Result = 0;
|
||||
if(Codepoint <= 0x7F)
|
||||
{
|
||||
Result = 1;
|
||||
}
|
||||
else if(Codepoint <= 0x7FF)
|
||||
{
|
||||
Result = 2;
|
||||
}
|
||||
else if(Codepoint <= 0xFFFF)
|
||||
{
|
||||
Result = 3;
|
||||
}
|
||||
else if(Codepoint <= 0x10FFFF)
|
||||
{
|
||||
Result = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = 1;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
// sixten(TODO): Remove this forward decl.
|
||||
inline string PushCString(struct memory_arena *Arena, char *CString);
|
||||
|
||||
inline string StringFromCodepoint(struct memory_arena *Arena, u32 Codepoint)
|
||||
{
|
||||
char Buffer[5] = {};
|
||||
UTF8FromCodepoint((u8 *)Buffer, Codepoint);
|
||||
|
||||
string Result = PushCString(Arena, Buffer);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct utf8_iterator
|
||||
{
|
||||
string Data;
|
||||
s64 Index;
|
||||
|
||||
u32 Codepoint;
|
||||
};
|
||||
|
||||
inline void Advance(utf8_iterator *Iter)
|
||||
{
|
||||
u8 *At = Iter->Data.Data + Iter->Index;
|
||||
|
||||
if(Iter->Index < Iter->Data.Count)
|
||||
{
|
||||
if((At[0] & 0x80) == 0x00)
|
||||
{
|
||||
Iter->Codepoint = (At[0] & 0x7F);
|
||||
Iter->Index += 1;
|
||||
}
|
||||
else if((At[0] & 0xE0) == 0xC0)
|
||||
{
|
||||
Iter->Codepoint = ((At[0] & 0x1F) << 6)|(At[1] & 0x3F);
|
||||
Iter->Index += 2;
|
||||
}
|
||||
else if((At[0] & 0xF0) == 0xE0)
|
||||
{
|
||||
Iter->Codepoint = ((At[0] & 0x0F) << 12)|((At[1] & 0x3F) << 6)|(At[2] & 0x3F);
|
||||
Iter->Index += 3;
|
||||
}
|
||||
else if((Iter->Data.Data[Iter->Index] & 0xF8) == 0xF0)
|
||||
{
|
||||
Iter->Codepoint = ((At[0] & 0x0F) << 18)|((At[1] & 0x3F) << 12)|((At[2] & 0x3F) << 6)|(At[3] & 0x3F);
|
||||
Iter->Index += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Iter->Codepoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline utf8_iterator IterateUTF8String(string String)
|
||||
{
|
||||
utf8_iterator Iter = {};
|
||||
Iter.Data = String;
|
||||
Advance(&Iter);
|
||||
|
||||
return(Iter);
|
||||
}
|
||||
|
||||
#endif //VN_STRING_H
|
|
@ -0,0 +1,295 @@
|
|||
/* date = May 7th 2023 7:16 pm */
|
||||
|
||||
#ifndef VN_TEXT_OP_H
|
||||
#define VN_TEXT_OP_H
|
||||
|
||||
struct text_op
|
||||
{
|
||||
range_s64 Range;
|
||||
string ReplaceString;
|
||||
string CopyString;
|
||||
s64 NewCursor;
|
||||
s64 NewMark;
|
||||
};
|
||||
|
||||
struct text_edit_state
|
||||
{
|
||||
s64 Cursor;
|
||||
s64 Mark;
|
||||
};
|
||||
|
||||
typedef u32 text_action_flags;
|
||||
enum
|
||||
{
|
||||
TextActionFlag_WordScan = (1<<0),
|
||||
TextActionFlag_KeepMark = (1<<1),
|
||||
TextActionFlag_Delete = (1<<2),
|
||||
TextActionFlag_ZeroDeltaWithSelection = (1<<3),
|
||||
TextActionFlag_DeltaPicksSelectionSide = (1<<4),
|
||||
};
|
||||
|
||||
struct text_action
|
||||
{
|
||||
text_action_flags Flags;
|
||||
s64 Delta;
|
||||
u32 Codepoint;
|
||||
};
|
||||
|
||||
inline b32 IsValid(text_action *Action)
|
||||
{
|
||||
b32 Result = !(Action->Flags == 0 && Action->Delta == 0 && Action->Codepoint == 0);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static text_action SingleLineTextActionFromEvent(platform_event *Event)
|
||||
{
|
||||
text_action Action = {};
|
||||
|
||||
if(Event->Type == PlatformEvent_Text)
|
||||
{
|
||||
if(Event->Codepoint != '\n')
|
||||
{
|
||||
Action.Codepoint = Event->Codepoint;
|
||||
}
|
||||
}
|
||||
else if(Event->Type == PlatformEvent_Press)
|
||||
{
|
||||
if(Event->Modifiers & PlatformModifier_Ctrl)
|
||||
{
|
||||
Action.Flags |= TextActionFlag_WordScan;
|
||||
}
|
||||
if(Event->Modifiers & PlatformModifier_Shift)
|
||||
{
|
||||
Action.Flags |= TextActionFlag_KeepMark;
|
||||
}
|
||||
|
||||
switch(Event->Key)
|
||||
{
|
||||
case Key_Right:
|
||||
{
|
||||
Action.Delta = +1;
|
||||
Action.Flags |= TextActionFlag_DeltaPicksSelectionSide;
|
||||
} break;
|
||||
|
||||
case Key_Left:
|
||||
{
|
||||
Action.Delta = -1;
|
||||
Action.Flags |= TextActionFlag_DeltaPicksSelectionSide;
|
||||
} break;
|
||||
|
||||
case Key_Home: { Action.Delta = S64_Min; } break;
|
||||
case Key_End: { Action.Delta = S64_Max; } break;
|
||||
|
||||
case Key_Backspace:
|
||||
{
|
||||
Action.Delta = -1;
|
||||
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
|
||||
} break;
|
||||
|
||||
case Key_Delete:
|
||||
{
|
||||
Action.Delta = +1;
|
||||
Action.Flags |= TextActionFlag_Delete|TextActionFlag_ZeroDeltaWithSelection;
|
||||
} break;
|
||||
|
||||
default: {} break;
|
||||
}
|
||||
}
|
||||
return(Action);
|
||||
}
|
||||
|
||||
inline s64 CodepointScan(string String, s64 Index, s64 Delta)
|
||||
{
|
||||
s64 Result = 0;
|
||||
if(Delta > 0)
|
||||
{
|
||||
while(Index < String.Count && Delta)
|
||||
{
|
||||
u8 Base = String.Data[Index];
|
||||
s64 ToMove = 0;
|
||||
|
||||
if((Base & 0x80) == 0x00)
|
||||
{
|
||||
ToMove = 1;
|
||||
}
|
||||
else if((Base & 0xE0) == 0xC0)
|
||||
{
|
||||
ToMove = 2;
|
||||
}
|
||||
else if((Base & 0xF0) == 0xE0)
|
||||
{
|
||||
ToMove = 3;
|
||||
}
|
||||
else if((Base & 0xF8) == 0xF0)
|
||||
{
|
||||
ToMove = 4;
|
||||
}
|
||||
|
||||
Result += ToMove;
|
||||
Index += ToMove;
|
||||
|
||||
--Delta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Index -= 1;
|
||||
|
||||
while(Index >= 0 && (Delta != 0))
|
||||
{
|
||||
u8 Base = String.Data[Index];
|
||||
if(((Base & 0x80) == 0) || !((Base & 0xC0) == 0x80))
|
||||
{
|
||||
++Delta;
|
||||
}
|
||||
|
||||
--Result;
|
||||
--Index;
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline b32 IsWordBoundary(string String, s64 Index)
|
||||
{
|
||||
b32 Result;
|
||||
if(Index > 0)
|
||||
{
|
||||
Result = IsWhitespace(String.Data[Index - 1]) && !(IsWhitespace(String.Data[Index]));
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static s64 WordScan(string String, s64 Index, s64 Delta)
|
||||
{
|
||||
s64 Result = 0;
|
||||
|
||||
while(Delta)
|
||||
{
|
||||
if(Delta > 0)
|
||||
{
|
||||
++Index;
|
||||
++Result;
|
||||
|
||||
while(Index < String.Count && !IsWordBoundary(String, Index))
|
||||
{
|
||||
++Index;
|
||||
++Result;
|
||||
}
|
||||
|
||||
if(Index > String.Count)
|
||||
{
|
||||
Result -= Index - String.Count;
|
||||
Index = String.Count;
|
||||
goto End;
|
||||
}
|
||||
|
||||
--Delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
--Index;
|
||||
--Result;
|
||||
|
||||
while(Index >= 0 && !IsWordBoundary(String, Index))
|
||||
{
|
||||
--Index;
|
||||
--Result;
|
||||
}
|
||||
|
||||
if(Index < 0)
|
||||
{
|
||||
Result -= Index;
|
||||
Index = 0;
|
||||
goto End;
|
||||
}
|
||||
|
||||
++Delta;
|
||||
}
|
||||
}
|
||||
|
||||
End:
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static text_op TextOpFromAction(memory_arena *Arena, string String,
|
||||
text_edit_state *State, text_action *Action)
|
||||
{
|
||||
text_op Op = {};
|
||||
|
||||
Op.NewCursor = State->Cursor;
|
||||
Op.NewMark = State->Mark;
|
||||
Op.Range = RangeS64(0, 0);
|
||||
Op.ReplaceString = StrLit("");
|
||||
|
||||
s64 Delta = 0;
|
||||
if(Action->Flags & TextActionFlag_WordScan)
|
||||
{
|
||||
Delta = WordScan(String, State->Cursor, Action->Delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
Delta = CodepointScan(String, State->Cursor, Action->Delta);
|
||||
}
|
||||
|
||||
if(State->Cursor != State->Mark &&
|
||||
Action->Flags & TextActionFlag_ZeroDeltaWithSelection)
|
||||
{
|
||||
Delta = 0;
|
||||
}
|
||||
|
||||
if(State->Cursor != State->Mark &&
|
||||
Action->Flags & TextActionFlag_DeltaPicksSelectionSide &&
|
||||
!(Action->Flags & TextActionFlag_KeepMark))
|
||||
{
|
||||
Delta = 0;
|
||||
if(Action->Delta > 0)
|
||||
{
|
||||
Op.NewCursor = Maximum(State->Cursor, State->Mark);
|
||||
}
|
||||
else if(Action->Delta < 0)
|
||||
{
|
||||
Op.NewCursor = Minimum(State->Cursor, State->Mark);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Op.NewCursor = State->Cursor + Delta;
|
||||
}
|
||||
|
||||
if(Action->Flags & TextActionFlag_Delete)
|
||||
{
|
||||
Op.Range = RangeS64(Op.NewCursor, Op.NewMark);
|
||||
Op.NewCursor = Op.NewMark = Op.Range.Min;
|
||||
}
|
||||
|
||||
if(Action->Codepoint != 0)
|
||||
{
|
||||
Op.ReplaceString = StringFromCodepoint(Arena, Action->Codepoint);
|
||||
|
||||
if(State->Cursor == State->Mark)
|
||||
{
|
||||
Op.NewCursor += Op.ReplaceString.Count;
|
||||
Op.Range = RangeS64(State->Cursor, State->Cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Op.NewCursor += Op.ReplaceString.Count;
|
||||
Op.Range = RangeS64(State->Cursor, State->Mark);
|
||||
}
|
||||
}
|
||||
|
||||
if(!(Action->Flags & TextActionFlag_KeepMark))
|
||||
{
|
||||
Op.NewMark = Op.NewCursor;
|
||||
}
|
||||
|
||||
return(Op);
|
||||
}
|
||||
|
||||
#endif //VN_TEXT_OP_H
|
|
@ -0,0 +1,11 @@
|
|||
/* date = May 7th 2023 0:16 pm */
|
||||
|
||||
#ifndef VN_THEME_DARK_H
|
||||
#define VN_THEME_DARK_H
|
||||
|
||||
read_only v4 Theme_TextColor = V4(0.8, 0.8, 0.8, 1.0);
|
||||
read_only v4 Theme_BackgroundColor = V4(0.1, 0.1, 0.1, 1.0);
|
||||
read_only v4 Theme_BorderColor = V4(0.3, 0.3, 0.3, 1.0);
|
||||
read_only v4 Theme_HighlightBorderColor = V4(0.6, 0.3, 0.1, 1.0);
|
||||
|
||||
#endif //VN_THEME_DARK_H
|
|
@ -0,0 +1,61 @@
|
|||
/* date = April 30th 2023 11:35 am */
|
||||
|
||||
#ifndef VN_THREAD_CONTEXT_H
|
||||
#define VN_THREAD_CONTEXT_H
|
||||
|
||||
#define per_thread __declspec(thread)
|
||||
|
||||
struct thread_context
|
||||
{
|
||||
memory_arena Arenas[2];
|
||||
};
|
||||
|
||||
per_thread thread_context *ThreadLocal_ThreadContext = 0;
|
||||
|
||||
inline void SetThreadContext(thread_context *Context)
|
||||
{
|
||||
ThreadLocal_ThreadContext = Context;
|
||||
}
|
||||
|
||||
inline thread_context *GetThreadContext(void)
|
||||
{
|
||||
return(ThreadLocal_ThreadContext);
|
||||
}
|
||||
|
||||
static temporary_memory GetScratch(memory_arena **Conflicts, u64 ConflictCount)
|
||||
{
|
||||
temporary_memory Scratch = {};
|
||||
thread_context *Context = GetThreadContext();
|
||||
|
||||
for(u64 ArenaIndex = 0;
|
||||
ArenaIndex < ArrayCount(Context->Arenas);
|
||||
++ArenaIndex)
|
||||
{
|
||||
b32 FoundConflict = false;
|
||||
for(u64 ConflictIndex = 0;
|
||||
ConflictIndex < ConflictCount;
|
||||
++ConflictIndex)
|
||||
{
|
||||
memory_arena *Conflict = Conflicts[ConflictIndex];
|
||||
if(Conflict == Context->Arenas + ArenaIndex)
|
||||
{
|
||||
FoundConflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!FoundConflict)
|
||||
{
|
||||
Scratch = BeginTemporaryMemory(Context->Arenas + ArenaIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(Scratch.Arena);
|
||||
|
||||
return(Scratch);
|
||||
}
|
||||
|
||||
#define ReleaseScratch(Scratch) EndTemporaryMemory(Scratch)
|
||||
|
||||
#endif //VN_THREAD_CONTEXT_H
|
|
@ -0,0 +1,198 @@
|
|||
/* date = April 26th 2023 4:55 pm */
|
||||
|
||||
#ifndef VN_TYPES_H
|
||||
#define VN_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <intrin.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
typedef float r32;
|
||||
typedef double r64;
|
||||
typedef u8 b8;
|
||||
typedef u16 b16;
|
||||
typedef u32 b32;
|
||||
typedef uintptr_t umm;
|
||||
typedef intptr_t smm;
|
||||
|
||||
#define U8_Min 0x00
|
||||
#define U8_Max 0xFF
|
||||
#define U16_Min 0x0000
|
||||
#define U16_Max 0xFFFF
|
||||
#define U32_Min 0x00000000
|
||||
#define U32_Max 0xFFFFFFFF
|
||||
#define U64_Min 0x0000000000000000
|
||||
#define U64_Max 0xFFFFFFFFFFFFFFFF
|
||||
#define S8_Min 0x80
|
||||
#define S8_Max 0x7F
|
||||
#define S16_Min 0x8000
|
||||
#define S16_Max 0x7FFF
|
||||
#define S32_Min 0x80000000
|
||||
#define S32_Max 0x7FFFFFFF
|
||||
#define S64_Min 0x8000000000000000
|
||||
#define S64_Max 0x7FFFFFFFFFFFFFFF
|
||||
|
||||
struct string
|
||||
{
|
||||
s64 Count;
|
||||
u8 *Data;
|
||||
};
|
||||
|
||||
struct string16
|
||||
{
|
||||
s64 Count;
|
||||
s16 *Data;
|
||||
};
|
||||
|
||||
typedef string buffer;
|
||||
typedef string16 buffer16;
|
||||
|
||||
#define StrLit(String) MakeString(String, ArrayCount(String) - 1)
|
||||
#define Str16Lit(String) MakeString16(String, ArrayCount(String) - 1)
|
||||
|
||||
inline string MakeString(char *Data, s64 Count)
|
||||
{
|
||||
string Result = {Count, (u8 *)Data};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline string MakeString16(wchar_t *Data, s64 Count)
|
||||
{
|
||||
string Result = {Count, (u8 *)Data};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct v2s
|
||||
{
|
||||
s32 x, y;
|
||||
};
|
||||
|
||||
inline v2s V2S(s32 x, s32 y)
|
||||
{
|
||||
v2s Result = {x, y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct v2u
|
||||
{
|
||||
u32 x, y;
|
||||
};
|
||||
|
||||
inline v2u V2U(u32 x, u32 y)
|
||||
{
|
||||
v2u Result = {x, y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct v2
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
r32 x, y;
|
||||
};
|
||||
r32 E[2];
|
||||
};
|
||||
};
|
||||
|
||||
inline v2 V2(r32 x, r32 y)
|
||||
{
|
||||
v2 Result = {x, y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 V2(v2s V)
|
||||
{
|
||||
v2 Result = {(r32)V.x, (r32)V.y};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct v3
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
r32 x, y, z;
|
||||
};
|
||||
struct
|
||||
{
|
||||
r32 r, g, b;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline v3 V3(r32 x, r32 y, r32 z)
|
||||
{
|
||||
v3 Result = {x, y, z};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct v4
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
r32 x, y, z, w;
|
||||
};
|
||||
struct
|
||||
{
|
||||
r32 r, g, b, a;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline v4 V4(r32 x, r32 y, r32 z, r32 w)
|
||||
{
|
||||
v4 Result = {x, y, z, w};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
enum axis2
|
||||
{
|
||||
Axis2_X,
|
||||
Axis2_Y,
|
||||
Axis2_Count,
|
||||
};
|
||||
|
||||
inline axis2 Opposite(axis2 Axis)
|
||||
{
|
||||
axis2 Result = (axis2)(!(u32)Axis);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
struct range_s64
|
||||
{
|
||||
s64 Min;
|
||||
s64 Max;
|
||||
};
|
||||
|
||||
struct range_r32
|
||||
{
|
||||
r32 Min;
|
||||
r32 Max;
|
||||
};
|
||||
|
||||
struct range2_r32
|
||||
{
|
||||
v2 Min;
|
||||
v2 Max;
|
||||
};
|
||||
|
||||
struct ticket_mutex
|
||||
{
|
||||
u64 volatile Ticket;
|
||||
u64 volatile Serving;
|
||||
};
|
||||
|
||||
#endif //VN_TYPES_H
|
|
@ -0,0 +1,842 @@
|
|||
per_thread ui *ThreadLocal_UI;
|
||||
|
||||
inline void UI_SetState(ui *UI)
|
||||
{
|
||||
ThreadLocal_UI = UI;
|
||||
}
|
||||
|
||||
inline ui *UI_GetState(void)
|
||||
{
|
||||
return(ThreadLocal_UI);
|
||||
}
|
||||
|
||||
inline ui_key UI_GetHot(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Hot);
|
||||
}
|
||||
|
||||
inline ui_key UI_GetActive(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->Active);
|
||||
}
|
||||
|
||||
inline void UI_SetDragStartP(v2 P)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI->DragStartP = P;
|
||||
}
|
||||
|
||||
inline void UI_UpdateDragStartP(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI->DragStartP = UI->MouseP;
|
||||
}
|
||||
|
||||
inline v2 UI_GetDragStartP(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
return(UI->DragStartP);
|
||||
}
|
||||
|
||||
inline void UI_StoreDragV2(v2 DragData)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
*(v2 *)&UI->DragData = DragData;
|
||||
}
|
||||
|
||||
inline v2 UI_GetDragV2(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
v2 Result = *(v2 *)UI->DragData;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void UI_StoreDragR32(r32 DragData)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
*(r32 *)&UI->DragData = DragData;
|
||||
}
|
||||
|
||||
inline r32 UI_GetDragR32(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
r32 Result = *(r32 *)UI->DragData;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline void UI_StoreDragPayload(void *Source)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Copy(UI->DragData, Source, sizeof(UI->DragData));
|
||||
}
|
||||
|
||||
inline void UI_GetDragPayload(void *Dest)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Copy(Dest, UI->DragData, sizeof(UI->DragData));
|
||||
}
|
||||
|
||||
inline void UI_StoreDragPointer(void *Data)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
*(void **)&UI->DragData = Data;
|
||||
}
|
||||
|
||||
inline void *UI_GetDragDataPointer(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
void *Result = *(void **)UI->DragData;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_key UI_EmptyKey(void)
|
||||
{
|
||||
ui_key Key = {};
|
||||
return(Key);
|
||||
}
|
||||
|
||||
inline ui_key UI_SeedKey(ui_key Key, ui_key Seed)
|
||||
{
|
||||
ui_key Result = {((Key.Value + Seed.Value) << 5) + Key.Value};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_key UI_GenerateKeyFromString(string String)
|
||||
{
|
||||
ui_key Key;
|
||||
if(String.Count)
|
||||
{
|
||||
Key.Value = HashString(String);
|
||||
}
|
||||
else
|
||||
{
|
||||
Key = UI_EmptyKey();
|
||||
}
|
||||
|
||||
return(Key);
|
||||
}
|
||||
|
||||
static string UI_GetBoxNameByKey(ui_key Key)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
string Result = StrLit("Empty or Not Found");
|
||||
|
||||
if(!AreEqual(Key, UI_EmptyKey()))
|
||||
{
|
||||
for(s32 BucketIndex = 0;
|
||||
BucketIndex < ArrayCount(UI->BoxBuckets);
|
||||
++BucketIndex)
|
||||
{
|
||||
ui_box_bucket *Bucket = UI->BoxBuckets + BucketIndex;
|
||||
for(ui_box *Box = Bucket->First;
|
||||
Box != 0;
|
||||
Box = Box->HashNext)
|
||||
{
|
||||
if(AreEqual(Key, Box->Key))
|
||||
{
|
||||
Result = Box->String;
|
||||
goto FoundName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FoundName:
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_box *UI_GetBoxByKey(ui *UI, ui_key Key)
|
||||
{
|
||||
u64 Hash = Key.Value;
|
||||
u64 Slot = Hash % ArrayCount(UI->BoxBuckets);
|
||||
|
||||
ui_box_bucket *Bucket = UI->BoxBuckets + Slot;
|
||||
|
||||
ui_box *Result = 0;
|
||||
if(!AreEqual(Key, UI_EmptyKey()))
|
||||
{
|
||||
for(ui_box *Box = Bucket->First;
|
||||
Box != 0;
|
||||
Box = Box->HashNext)
|
||||
{
|
||||
if(AreEqual(Box->Key, Key))
|
||||
{
|
||||
Result = Box;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!Result)
|
||||
{
|
||||
// sixten: Check if we have already allocated a box
|
||||
if(DLLIsEmpty(UI->FirstFreeBox))
|
||||
{
|
||||
// sixten: If not, simply allocate one
|
||||
Result = PushStruct(&UI->Arena, ui_box);
|
||||
}
|
||||
else
|
||||
{
|
||||
// sixten: If there exists an already allocated, remove it from the free list and use it.
|
||||
Result = UI->FirstFreeBox;
|
||||
DLLRemove_NP(UI->FirstFreeBox, UI->LastFreeBox, Result, HashNext, HashPrev);
|
||||
}
|
||||
|
||||
// sixten: Insert the box into the hashmap.
|
||||
DLLInsertLast_NP(Bucket->First, Bucket->Last, Result, HashNext, HashPrev);
|
||||
}
|
||||
|
||||
Result->Key = Key;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#include "generated/vn_generated_ui.cpp"
|
||||
|
||||
inline ui_box *UI_MakeBox(ui_box_flags Flags, string String)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
ui_box *Parent = UI_TopParent();
|
||||
|
||||
ui_key BaseKey = UI_GenerateKeyFromString(String);
|
||||
ui_key Seed = UI_SeedKey(BaseKey, Parent ? Parent->Seed : UI_EmptyKey());
|
||||
ui_key Key = BaseKey.Value ? Seed : UI_EmptyKey();
|
||||
|
||||
// sixten: Check for duplicate keys.
|
||||
#if VN_SLOW
|
||||
if(Parent && !AreEqual(Key, UI_EmptyKey()))
|
||||
{
|
||||
for(ui_box *Child = Parent->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
Assert(!AreEqual(Child->Key, Key));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ui_box *Box = UI_GetBoxByKey(UI, Key);
|
||||
Box->Seed = Seed;
|
||||
|
||||
Box->First = Box->Last = Box->Next = Box->Prev = Box->Parent = 0;
|
||||
|
||||
Box->ComputedRelativeP = V2(0, 0);
|
||||
Box->ComputedDim = V2(0, 0);
|
||||
|
||||
Box->LastFrameTouched = UI->CurrentFrame;
|
||||
|
||||
Box->Flags = Flags;
|
||||
Box->String = PushString(&UI->FrameArena, String);
|
||||
|
||||
UI_ApplyStyles(Box);
|
||||
|
||||
if(Parent)
|
||||
{
|
||||
DLLInsertLast(Parent->First, Parent->Last, Box);
|
||||
}
|
||||
|
||||
return(Box);
|
||||
}
|
||||
|
||||
inline ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
// sixten(TODO): Allocate on scratch, copy to frame arena
|
||||
// (alternatively keep two versions of UI_MakeBox, to make sure everything works)
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(&UI->FrameArena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
ui_box *Box = UI_MakeBox(Flags, String);
|
||||
return(Box);
|
||||
}
|
||||
|
||||
inline void UI_SetNextHot(ui_key Key)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
if(!UI->NextHotSet)
|
||||
{
|
||||
UI->NextHot = Key;
|
||||
UI->NextHotSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
inline b32 UI_ChildrenContainsP(ui_box *Box, v2 P)
|
||||
{
|
||||
b32 Result = false;
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_Clickable && InRange(Box->Rect, P))
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Box->First)
|
||||
{
|
||||
Result = UI_ChildrenContainsP(Box->First, P);
|
||||
}
|
||||
|
||||
if(!Result)
|
||||
{
|
||||
if(Box->Next)
|
||||
{
|
||||
Result = UI_ChildrenContainsP(Box->Next, P);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static ui_signal UI_SignalFromBox(ui_box *Box)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
ui_signal Signal = {};
|
||||
|
||||
Signal.Hovering = InRange(Box->Rect, UI->MouseP) &&
|
||||
!(Box->First && UI_ChildrenContainsP(Box->First, UI->MouseP)) &&
|
||||
!(Box->Next && UI_ChildrenContainsP(Box->Next, UI->MouseP));
|
||||
|
||||
// sixten: Make sure the tooltip is not overlapping.
|
||||
{
|
||||
// sixten: Are we the tooltip?
|
||||
b32 FoundTooltip = false;
|
||||
for(ui_box *Parent = Box->Parent;
|
||||
Parent != 0;
|
||||
Parent = Parent->Parent)
|
||||
{
|
||||
if(Parent == UI->TooltipNode)
|
||||
{
|
||||
FoundTooltip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!FoundTooltip && UI->TooltipNode->First)
|
||||
{
|
||||
Signal.Hovering &= ~UI_ChildrenContainsP(UI->TooltipNode->First, UI->MouseP);
|
||||
}
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_Clickable)
|
||||
{
|
||||
if(AreEqual(UI->Active, Box->Key))
|
||||
{
|
||||
if(Platform_KeyRelease(UI->EventList, Key_MouseLeft))
|
||||
{
|
||||
Signal.Clicked = Signal.Hovering;
|
||||
Signal.Released = true;
|
||||
|
||||
UI->Active = UI_EmptyKey();
|
||||
|
||||
if(!Signal.Hovering)
|
||||
{
|
||||
UI_SetNextHot(UI_EmptyKey());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Signal.Dragging = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(AreEqual(UI->Hot, Box->Key))
|
||||
{
|
||||
if(Platform_KeyPress(UI->EventList, Key_MouseLeft))
|
||||
{
|
||||
UI->Active = Box->Key;
|
||||
UI->DragStartP = UI->MouseP;
|
||||
|
||||
Signal.Dragging = true;
|
||||
Signal.Pressed = true;
|
||||
}
|
||||
else if(!Signal.Hovering)
|
||||
{
|
||||
UI_SetNextHot(UI_EmptyKey());
|
||||
}
|
||||
|
||||
if(Platform_KeyPress(UI->EventList, Key_MouseRight))
|
||||
{
|
||||
Signal.PressedRight = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(AreEqual(UI->Hot, UI_EmptyKey()) && Signal.Hovering)
|
||||
{
|
||||
UI_SetNextHot(Box->Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Signal.MouseP = UI->MouseP;
|
||||
Signal.DragDelta = UI->MouseP - UI->DragStartP;
|
||||
Signal.Box = Box;
|
||||
|
||||
return(Signal);
|
||||
}
|
||||
|
||||
static void UI_CalculateStandaloneSize(ui_box *Box, axis2 Axis, glyph_atlas *Atlas)
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
UI_CalculateStandaloneSize(Child, Axis, Atlas);
|
||||
}
|
||||
|
||||
if(Box->SemanticSize[Axis].Type == UI_SizeType_Pixels)
|
||||
{
|
||||
Box->ComputedDim.E[Axis] = Box->SemanticSize[Axis].Value;
|
||||
}
|
||||
else if(Box->SemanticSize[Axis].Type == UI_SizeType_TextContent)
|
||||
{
|
||||
if(Axis == Axis2_X)
|
||||
{
|
||||
Box->ComputedDim.E[Axis] = CalculateRasterizedTextWidth(Atlas, Box->Font, Box->FontSize, Box->String);
|
||||
}
|
||||
else if(Axis == Axis2_Y)
|
||||
{
|
||||
Box->ComputedDim.E[Axis] = CalculateRasterizedTextHeight(Atlas, Box->Font, Box->FontSize, Box->String);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidCodepath;
|
||||
}
|
||||
|
||||
Box->ComputedDim.E[Axis] += Box->SemanticSize[Axis].Value;
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_CalculateUpwardsDependentSize(ui_box *Box, axis2 Axis)
|
||||
{
|
||||
if(Box->SemanticSize[Axis].Type == UI_SizeType_PercentOfParent)
|
||||
{
|
||||
Box->ComputedDim.E[Axis] = Box->Parent->ComputedDim.E[Axis]*Box->SemanticSize[Axis].Value;
|
||||
}
|
||||
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
UI_CalculateUpwardsDependentSize(Child, Axis);
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_CalculateDownwardsDependentSize(ui_box *Box, axis2 Axis)
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
UI_CalculateDownwardsDependentSize(Child, Axis);
|
||||
}
|
||||
|
||||
if(Box->SemanticSize[Axis].Type == UI_SizeType_ChildrenSum)
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if(Box->LayoutAxis == Axis)
|
||||
{
|
||||
Box->ComputedDim.E[Axis] += Child->ComputedDim.E[Axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
Box->ComputedDim.E[Axis] = Maximum(Box->ComputedDim.E[Axis], Child->ComputedDim.E[Axis]);
|
||||
}
|
||||
|
||||
Box->ComputedDim.E[Axis] *= Box->SemanticSize[Axis].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_SolveSizeViolations(ui_box *Box, axis2 Axis)
|
||||
{
|
||||
r32 TotalSpace = 0;
|
||||
r32 FixupBudget = 0;
|
||||
|
||||
if(!(Box->Flags & (UI_BoxFlag_OverflowX<<Axis)))
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if(!(Child->Flags & (UI_BoxFlag_FloatingX<<Axis)))
|
||||
{
|
||||
if(Axis == Box->LayoutAxis)
|
||||
{
|
||||
TotalSpace += Child->ComputedDim.E[Axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
TotalSpace = Maximum(TotalSpace, Child->ComputedDim.E[Axis]);
|
||||
}
|
||||
FixupBudget += Child->ComputedDim.E[Axis] * (1 - Child->SemanticSize[Axis].Strictness);
|
||||
}
|
||||
}
|
||||
|
||||
r32 Violation = TotalSpace - Box->ComputedDim.E[Axis];
|
||||
if(Violation > 0 && FixupBudget > 0)
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if(!(Child->Flags & (UI_BoxFlag_FloatingX<<Axis)))
|
||||
{
|
||||
r32 ChildFixupBudget = Child->ComputedDim.E[Axis] * (1 - Child->SemanticSize[Axis].Strictness);
|
||||
r32 ChildFixupSize = 0;
|
||||
if(Axis == Box->LayoutAxis)
|
||||
{
|
||||
ChildFixupSize = ChildFixupBudget * (Violation / FixupBudget);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChildFixupSize = Child->ComputedDim.E[Axis] - Box->ComputedDim.E[Axis];
|
||||
}
|
||||
|
||||
ChildFixupSize = Clamp(ChildFixupSize, 0, ChildFixupBudget);
|
||||
Child->ComputedDim.E[Axis] -= ChildFixupSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Axis == Box->LayoutAxis)
|
||||
{
|
||||
r32 Position = 0;
|
||||
for(ui_box *Child = Box->First;
|
||||
Child;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if((Child->Flags & (UI_BoxFlag_FloatingX<<Axis)))
|
||||
{
|
||||
Child->ComputedRelativeP.E[Axis] = Child->FixedP.E[Axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
Child->ComputedRelativeP.E[Axis] = Position;
|
||||
Position += Child->ComputedDim.E[Axis];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(ui_box *Child = Box->First;
|
||||
Child;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if((Child->Flags & (UI_BoxFlag_FloatingX<<Axis)))
|
||||
{
|
||||
Child->ComputedRelativeP.E[Axis] = Child->FixedP.E[Axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
Child->ComputedRelativeP.E[Axis] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(ui_box *Child = Box->First;
|
||||
Child;
|
||||
Child = Child->Next)
|
||||
{
|
||||
Child->Rect.Min.E[Axis] = Box->Rect.Min.E[Axis] + Child->ComputedRelativeP.E[Axis];
|
||||
Child->Rect.Max.E[Axis] = Child->Rect.Min.E[Axis] + Child->ComputedDim.E[Axis];
|
||||
|
||||
UI_SolveSizeViolations(Child, Axis);
|
||||
}
|
||||
}
|
||||
|
||||
inline void UI_BeginTooltip(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_PushParent(UI->TooltipNode);
|
||||
}
|
||||
|
||||
inline void UI_EndTooltip(void)
|
||||
{
|
||||
UI_PopParent();
|
||||
}
|
||||
|
||||
inline void UI_SetNextTooltip(void)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_SetNextParent(UI->TooltipNode);
|
||||
}
|
||||
|
||||
#define UI_Tooltip DeferLoop(UI_BeginTooltip(), UI_EndTooltip())
|
||||
|
||||
static void UI_DrawBox(ui_box *Box, render_group *Group, glyph_atlas *GlyphAtlas)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
Box->HotTransition += ((r32)AreEqual(UI->Hot, Box->Key) - Box->HotTransition) * 0.6f;
|
||||
Box->ActiveTransition += ((r32)AreEqual(UI->Active, Box->Key) - Box->ActiveTransition) * 0.6f;
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_DrawBackground)
|
||||
{
|
||||
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Box->BackgroundColor, Box->CornerRadius, 0, 0);
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_HotAnimation)
|
||||
{
|
||||
v4 Top = V4(1, 1, 1, 0.06F*Box->HotTransition);
|
||||
v4 Bottom = V4(1, 1, 1, 0.0);
|
||||
|
||||
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_ActiveAnimation)
|
||||
{
|
||||
v4 Top = V4(0, 0, 0, 0.5F*Box->ActiveTransition);
|
||||
v4 Bottom = V4(0, 0, 0, 0.1F*Box->ActiveTransition);
|
||||
|
||||
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Top, Top, Bottom, Bottom, Box->CornerRadius, 0, 0);
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_DrawText)
|
||||
{
|
||||
v2 TextDim = V2(CalculateRasterizedTextWidth(GlyphAtlas, Box->Font, Box->FontSize, Box->String),
|
||||
CalculateRasterizedTextHeight(GlyphAtlas, Box->Font, Box->FontSize, Box->String));
|
||||
|
||||
v2 P = Box->Rect.Min + (Box->ComputedDim - TextDim)*0.5;
|
||||
|
||||
PushText(Group, GlyphAtlas, Box->Font, P, Box->FontSize, Box->TextColor, Box->String);
|
||||
}
|
||||
|
||||
if(Box->DrawCallback)
|
||||
{
|
||||
Box->DrawCallback(Group, GlyphAtlas, Box, Box->DrawCallbackData);
|
||||
}
|
||||
|
||||
#if 0 // sixten: Render debug rects around boxes.
|
||||
r32 R = (((Box->Key.Value >> 0) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
|
||||
r32 G = (((Box->Key.Value >> 21) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
|
||||
r32 B = (((Box->Key.Value >> 42) & ((1 << 22) - 1)) / (r32)((1 << 22) - 1));
|
||||
v4 Red = V4(R, G, B, 1);
|
||||
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Red, Red, Red, Red, 0, 1.8, 1.8);
|
||||
#endif
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_Clip)
|
||||
{
|
||||
PushClip(Group, Box->Rect);
|
||||
}
|
||||
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if(Child->Flags & UI_BoxFlag_DrawDropShadow)
|
||||
{
|
||||
r32 ShadowRadius = 10;
|
||||
v2 P = Child->Rect.Min - V2(ShadowRadius, ShadowRadius);
|
||||
v2 Dim = Child->ComputedDim + V2(ShadowRadius, ShadowRadius)*2;
|
||||
|
||||
v4 ShadowColor = V4(0, 0, 0, 0.7);
|
||||
|
||||
PushQuad(Group, P, Dim, ShadowColor, 0, ShadowRadius, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(ui_box *Child = Box->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
UI_DrawBox(Child, Group, GlyphAtlas);
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_Clip)
|
||||
{
|
||||
PopClip(Group);
|
||||
}
|
||||
|
||||
if(Box->Flags & UI_BoxFlag_DrawBorder)
|
||||
{
|
||||
PushQuad(Group, Box->Rect.Min, Box->ComputedDim, Box->BorderColor, Box->CornerRadius, 0.8, Box->BorderThickness);
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_BeginBuild(v2 ScreenDim)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
UI_PushParent(0);
|
||||
UI_PushWidth(UI_Pixels(ScreenDim.x, 1));
|
||||
UI_PushHeight(UI_Pixels(ScreenDim.y, 1));
|
||||
UI_PushFixedX(0);
|
||||
UI_PushFixedY(0);
|
||||
UI_PushTextColor(Theme_TextColor);
|
||||
UI_PushBackgroundColor(ColorFromHex(0x111111FF));
|
||||
UI_PushBorderColor(Theme_BorderColor);
|
||||
UI_PushBorderThickness(1.8);
|
||||
UI_PushLayoutAxis(Axis2_Y);
|
||||
UI_PushCornerRadius(0);
|
||||
UI_PushFont(Font_Regular);
|
||||
UI_PushFontSize(15.0f);
|
||||
|
||||
UI->RootNode = UI_MakeBox(UI_BoxFlag_DrawBackground, StrLit("UI Root Node"));
|
||||
UI->Stacks.ParentStack[0] = UI->RootNode;
|
||||
|
||||
UI->ContainerNode = UI_MakeBox(UI_BoxFlag_Clickable, StrLit("UI Container Node"));
|
||||
UI->TooltipNode = UI_MakeBox(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, StrLit("UI Tooltip Node"));
|
||||
|
||||
UI->Stacks.ParentStack[0] = UI->ContainerNode;
|
||||
|
||||
UI->NextHotSet = false;
|
||||
}
|
||||
|
||||
static void UI_EndBuild(glyph_atlas *GlyphAtlas)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
if(UI->NextHotSet)
|
||||
{
|
||||
UI->Hot = UI->NextHot;
|
||||
}
|
||||
|
||||
UI_PopParent();
|
||||
UI_PopWidth();
|
||||
UI_PopHeight();
|
||||
UI_PopFixedX();
|
||||
UI_PopFixedY();
|
||||
UI_PopTextColor();
|
||||
UI_PopBackgroundColor();
|
||||
UI_PopBorderColor();
|
||||
UI_PopBorderThickness();
|
||||
UI_PopLayoutAxis();
|
||||
UI_PopCornerRadius();
|
||||
UI_PopFont();
|
||||
UI_PopFontSize();
|
||||
|
||||
UI_CalculateStandaloneSize(UI->RootNode, Axis2_X, GlyphAtlas);
|
||||
UI_CalculateStandaloneSize(UI->RootNode, Axis2_Y, GlyphAtlas);
|
||||
|
||||
UI_CalculateUpwardsDependentSize(UI->RootNode, Axis2_X);
|
||||
UI_CalculateUpwardsDependentSize(UI->RootNode, Axis2_Y);
|
||||
|
||||
UI_CalculateDownwardsDependentSize(UI->RootNode, Axis2_X);
|
||||
UI_CalculateDownwardsDependentSize(UI->RootNode, Axis2_Y);
|
||||
|
||||
UI_SolveSizeViolations(UI->RootNode, Axis2_X);
|
||||
UI_SolveSizeViolations(UI->RootNode, Axis2_Y);
|
||||
}
|
||||
|
||||
static void UI_RenderFrame(render_group *Group, glyph_atlas *GlyphAtlas)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
UI_DrawBox(UI->RootNode, Group, GlyphAtlas);
|
||||
}
|
||||
|
||||
inline void UI_ScanForHotAndActive(ui_box *Box, b32 *FoundHot, b32 *FoundActive)
|
||||
{
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
if(AreEqual(UI->Hot, Box->Key) && (Box->Flags & UI_BoxFlag_Clickable))
|
||||
{
|
||||
*FoundHot = true;
|
||||
}
|
||||
if(AreEqual(UI->Active, Box->Key) && (Box->Flags & UI_BoxFlag_Clickable))
|
||||
{
|
||||
*FoundActive = true;
|
||||
}
|
||||
|
||||
if(Box->First)
|
||||
{
|
||||
UI_ScanForHotAndActive(Box->First, FoundHot, FoundActive);
|
||||
}
|
||||
if(Box->Next)
|
||||
{
|
||||
UI_ScanForHotAndActive(Box->Next, FoundHot, FoundActive);
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_NewFrame(ui *UI, platform_event_list *EventList, v2 MouseP)
|
||||
{
|
||||
UI_SetState(UI);
|
||||
|
||||
if(UI->FrameMemory.Arena)
|
||||
{
|
||||
EndTemporaryMemory(UI->FrameMemory);
|
||||
}
|
||||
|
||||
UI->FrameMemory = BeginTemporaryMemory(&UI->FrameArena);
|
||||
|
||||
UI->EventList = EventList;
|
||||
UI->MouseP = MouseP;
|
||||
|
||||
// sixten: Make sure that the hot and active boxes are valid.
|
||||
if(UI->RootNode)
|
||||
{
|
||||
b32 FoundHot = false;
|
||||
b32 FoundActive = false;
|
||||
UI_ScanForHotAndActive(UI->RootNode, &FoundHot, &FoundActive);
|
||||
|
||||
// sixten(TODO): Do we inform the builder code about this somehow?
|
||||
if(!FoundHot)
|
||||
{
|
||||
UI->Hot = UI_EmptyKey();
|
||||
}
|
||||
if(!FoundActive)
|
||||
{
|
||||
UI->Active = UI_EmptyKey();
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Prune uncached boxes.
|
||||
ui_box_bucket *FirstBucket = UI->BoxBuckets;
|
||||
for(ui_box *Box = FirstBucket->First; Box != 0;)
|
||||
{
|
||||
if(AreEqual(Box->Key, UI_EmptyKey()))
|
||||
{
|
||||
ui_box *ToRemove = Box;
|
||||
Box = Box->HashNext;
|
||||
|
||||
DLLRemove_NP(FirstBucket->First, FirstBucket->Last, ToRemove, HashNext, HashPrev);
|
||||
*ToRemove = {};
|
||||
|
||||
DLLInsertLast_NP(UI->FirstFreeBox, UI->LastFreeBox, ToRemove, HashNext, HashPrev);
|
||||
}
|
||||
else
|
||||
{
|
||||
Box = Box->HashNext;
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Prune any unused boxes.
|
||||
for(s32 BucketIndex = 0;
|
||||
BucketIndex < ArrayCount(UI->BoxBuckets);
|
||||
++BucketIndex)
|
||||
{
|
||||
ui_box_bucket *Bucket = UI->BoxBuckets + BucketIndex;
|
||||
for(ui_box *Box = Bucket->First; Box != 0;)
|
||||
{
|
||||
if(Box->LastFrameTouched != UI->CurrentFrame)
|
||||
{
|
||||
ui_box *ToRemove = Box;
|
||||
Box = Box->HashNext;
|
||||
|
||||
DLLRemove_NP(Bucket->First, Bucket->Last, ToRemove, HashNext, HashPrev);
|
||||
*ToRemove = {};
|
||||
|
||||
DLLInsertLast_NP(UI->FirstFreeBox, UI->LastFreeBox, ToRemove, HashNext, HashPrev);
|
||||
}
|
||||
else
|
||||
{
|
||||
Box = Box->HashNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++UI->CurrentFrame;
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/* date = April 29th 2023 8:22 pm */
|
||||
|
||||
#ifndef VN_UI_H
|
||||
#define VN_UI_H
|
||||
|
||||
struct ui_key
|
||||
{
|
||||
u64 Value;
|
||||
};
|
||||
|
||||
inline b32 AreEqual(ui_key A, ui_key B)
|
||||
{
|
||||
b32 Result = (A.Value == B.Value);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
UI_BoxFlag_Clickable = (1 << 0),
|
||||
UI_BoxFlag_DrawText = (1 << 1),
|
||||
UI_BoxFlag_DrawBorder = (1 << 2),
|
||||
UI_BoxFlag_DrawBackground = (1 << 3),
|
||||
UI_BoxFlag_DrawDropShadow = (1 << 4),
|
||||
UI_BoxFlag_Clip = (1 << 5),
|
||||
UI_BoxFlag_HotAnimation = (1 << 6),
|
||||
UI_BoxFlag_ActiveAnimation = (1 << 7),
|
||||
UI_BoxFlag_OverflowX = (1 << 8),
|
||||
UI_BoxFlag_OverflowY = (1 << 9),
|
||||
UI_BoxFlag_FloatingX = (1 << 10),
|
||||
UI_BoxFlag_FloatingY = (1 << 11),
|
||||
};
|
||||
typedef u32 ui_box_flags;
|
||||
|
||||
enum ui_size_type
|
||||
{
|
||||
UI_SizeType_Pixels,
|
||||
UI_SizeType_TextContent,
|
||||
UI_SizeType_PercentOfParent,
|
||||
UI_SizeType_ChildrenSum,
|
||||
};
|
||||
|
||||
struct ui_size
|
||||
{
|
||||
ui_size_type Type;
|
||||
r32 Value;
|
||||
r32 Strictness;
|
||||
};
|
||||
|
||||
inline ui_size UI_Pixels(r32 Value, r32 Strictness)
|
||||
{
|
||||
ui_size Result = {UI_SizeType_Pixels, Value, Strictness};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_size UI_TextContent(r32 Value, r32 Strictness)
|
||||
{
|
||||
ui_size Result = {UI_SizeType_TextContent, Value, Strictness};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_size UI_Percent(r32 Value, r32 Strictness)
|
||||
{
|
||||
ui_size Result = {UI_SizeType_PercentOfParent, Value, Strictness};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline ui_size UI_ChildrenSum(r32 Value, r32 Strictness)
|
||||
{
|
||||
ui_size Result = {UI_SizeType_ChildrenSum, Value, Strictness};
|
||||
return(Result);
|
||||
}
|
||||
|
||||
typedef void ui_draw_callback(render_group *Group, glyph_atlas *Atlas, struct ui_box *Box, void *Data);
|
||||
|
||||
struct ui_box
|
||||
{
|
||||
ui_box *First;
|
||||
ui_box *Last;
|
||||
ui_box *Next;
|
||||
ui_box *Prev;
|
||||
ui_box *Parent;
|
||||
|
||||
ui_box *HashNext;
|
||||
ui_box *HashPrev;
|
||||
|
||||
ui_key Key;
|
||||
ui_key Seed;
|
||||
u64 LastFrameTouched;
|
||||
|
||||
ui_box_flags Flags;
|
||||
string String;
|
||||
ui_size SemanticSize[Axis2_Count];
|
||||
v2 FixedP;
|
||||
v4 TextColor;
|
||||
v4 BackgroundColor;
|
||||
v4 BorderColor;
|
||||
r32 BorderThickness;
|
||||
axis2 LayoutAxis;
|
||||
r32 CornerRadius;
|
||||
font_id Font;
|
||||
r32 FontSize;
|
||||
|
||||
ui_draw_callback *DrawCallback;
|
||||
void *DrawCallbackData;
|
||||
|
||||
v2 ComputedRelativeP;
|
||||
v2 ComputedDim;
|
||||
|
||||
range2_r32 Rect;
|
||||
|
||||
r32 HotTransition;
|
||||
r32 ActiveTransition;
|
||||
};
|
||||
|
||||
struct ui_box_bucket
|
||||
{
|
||||
ui_box *First;
|
||||
ui_box *Last;
|
||||
};
|
||||
|
||||
struct ui_signal
|
||||
{
|
||||
ui_box *Box;
|
||||
v2 MouseP;
|
||||
v2 DragDelta;
|
||||
b8 Clicked;
|
||||
b8 Pressed;
|
||||
b8 PressedRight;
|
||||
b8 Released;
|
||||
b8 Hovering;
|
||||
b8 Dragging;
|
||||
};
|
||||
|
||||
#include "generated/vn_generated_ui.h"
|
||||
|
||||
struct ui
|
||||
{
|
||||
memory_arena Arena;
|
||||
memory_arena FrameArena;
|
||||
temporary_memory FrameMemory;
|
||||
ui_box *FirstFreeBox;
|
||||
ui_box *LastFreeBox;
|
||||
|
||||
ui_box_bucket BoxBuckets[256];
|
||||
|
||||
ui_box *RootNode;
|
||||
ui_box *TooltipNode;
|
||||
ui_box *ContainerNode;
|
||||
|
||||
u64 CurrentFrame;
|
||||
ui_key Hot;
|
||||
ui_key Active;
|
||||
|
||||
ui_key NextHot;
|
||||
b32 NextHotSet;
|
||||
|
||||
platform_event_list *EventList;
|
||||
v2 MouseP;
|
||||
|
||||
u64 DragData[8];
|
||||
v2 DragStartP;
|
||||
|
||||
ui_style_stacks Stacks;
|
||||
};
|
||||
|
||||
//- 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);
|
||||
|
||||
//- sixten: Drag helpers
|
||||
inline void UI_SetDragStartP(v2 P);
|
||||
inline void UI_UpdateDragStartP(void);
|
||||
inline v2 UI_GetDragStartP(void);
|
||||
inline void UI_StoreDragV2(v2 DragData);
|
||||
inline v2 UI_GetDragV2(void);
|
||||
inline void UI_StoreDragR32(r32 DragData);
|
||||
inline r32 UI_GetDragR32(void);
|
||||
inline void UI_StoreDragPayload(void *Data); // sixten(NOTE): Payload MUST be 64-bytes.
|
||||
inline void UI_GetDragDataPayload(void *Data);
|
||||
inline void UI_StoreDragPointer(void *Data);
|
||||
inline void *UI_GetDragDataPointer(void);
|
||||
|
||||
//- sixten: Key functions
|
||||
inline ui_key UI_EmptyKey(void);
|
||||
inline ui_key UI_SeedKey(ui_key Key, ui_key Seed);
|
||||
inline ui_key UI_GenerateKeyFromString(string String);
|
||||
static string UI_GetBoxNameByKey(ui_key Key);
|
||||
inline ui_box *UI_GetBoxByKey(ui *UI, ui_key Key);
|
||||
|
||||
//- sixten: Box creation
|
||||
inline ui_box *UI_MakeBox(ui_box_flags Flags, string String);
|
||||
inline ui_box *UI_MakeBoxF(ui_box_flags Flags, char *Format, ...);
|
||||
|
||||
//- sixten: Building and rendering
|
||||
static void UI_BeginBuild(ui *UI, v2 ScreenDim);
|
||||
static void UI_EndBuild(glyph_atlas *GlyphAtlas);
|
||||
static void UI_RenderFrame(render_group *RenderGroup, glyph_atlas *GlyphAtlas);
|
||||
static void UI_NewFrame(ui *UI, platform_event_list *EventList, v2 MouseP);
|
||||
|
||||
#endif //VN_UI_H
|
|
@ -0,0 +1,166 @@
|
|||
// sixten: Rows and columns.
|
||||
inline void UI_RowBegin(void)
|
||||
{
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
ui_box *Box = UI_MakeBox(0, StrLit(""));
|
||||
UI_PushParent(Box);
|
||||
}
|
||||
|
||||
inline void UI_RowEnd(void)
|
||||
{
|
||||
UI_PopParent();
|
||||
}
|
||||
|
||||
inline void UI_ColumnBegin(void)
|
||||
{
|
||||
UI_SetNextLayoutAxis(Axis2_Y);
|
||||
ui_box *Box = UI_MakeBox(0, StrLit(""));
|
||||
UI_PushParent(Box);
|
||||
}
|
||||
|
||||
inline void UI_ColumnEnd(void)
|
||||
{
|
||||
UI_PopParent();
|
||||
}
|
||||
|
||||
#define UI_Row DeferLoop(UI_RowBegin(), UI_RowEnd())
|
||||
#define UI_Column DeferLoop(UI_ColumnBegin(), UI_ColumnEnd())
|
||||
|
||||
// sixten: Compositions
|
||||
inline void UI_PushAxisSize(axis2 Axis, ui_size Size)
|
||||
{
|
||||
if(Axis == Axis2_X)
|
||||
{
|
||||
UI_PushWidth(Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_PushHeight(Size);
|
||||
}
|
||||
}
|
||||
|
||||
inline void UI_PopAxisSize(axis2 Axis)
|
||||
{
|
||||
if(Axis == Axis2_X)
|
||||
{
|
||||
UI_PopWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_PopHeight();
|
||||
}
|
||||
}
|
||||
|
||||
inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size)
|
||||
{
|
||||
if(Axis == Axis2_X)
|
||||
{
|
||||
UI_SetNextWidth(Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_SetNextHeight(Size);
|
||||
}
|
||||
}
|
||||
|
||||
#define UI_AxisSize(Axis, Size) DeferLoop(UI_PushAxisSize(Axis, Size), UI_PopAxisSize(Axis))
|
||||
|
||||
#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()
|
||||
#define UI_SetNextSize(Width, Height) UI_SetNextWidth(Width); UI_SetNextHeight(Height)
|
||||
|
||||
#define UI_FixedP(Value) UI_FixedX(Value.x) UI_FixedY(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)
|
||||
{
|
||||
ui_box *Parent = UI_TopParent();
|
||||
UI_SetNextAxisSize(Parent->LayoutAxis, Size);
|
||||
|
||||
ui_box *Box = UI_MakeBox(0, String);
|
||||
return(Box);
|
||||
}
|
||||
|
||||
static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
ui_box *Box = UI_NamedSpacer(Size, String);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
return(Box);
|
||||
}
|
||||
|
||||
static void UI_Spacer(ui_size Size)
|
||||
{
|
||||
UI_NamedSpacer(Size, StrLit(""));
|
||||
}
|
||||
|
||||
#define UI_Padding(Size) DeferLoop(UI_Spacer(Size), UI_Spacer(Size))
|
||||
|
||||
// sixten: Common widgets
|
||||
static ui_box *UI_Label(string String)
|
||||
{
|
||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
||||
return(Box);
|
||||
}
|
||||
|
||||
static ui_box *UI_LabelF(char *Format, ...)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
return(Box);
|
||||
}
|
||||
|
||||
static ui_signal UI_Button(string String)
|
||||
{
|
||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
||||
UI_BoxFlag_DrawBackground|
|
||||
UI_BoxFlag_DrawBorder|
|
||||
UI_BoxFlag_HotAnimation|
|
||||
UI_BoxFlag_ActiveAnimation|
|
||||
UI_BoxFlag_Clickable,
|
||||
String);
|
||||
ui_signal Signal = UI_SignalFromBox(Box);
|
||||
return(Signal);
|
||||
}
|
||||
|
||||
static ui_signal UI_ButtonF(char *Format, ...)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Format);
|
||||
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
|
||||
va_end(Arguments);
|
||||
|
||||
ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
|
||||
UI_BoxFlag_DrawBackground|
|
||||
UI_BoxFlag_DrawBorder|
|
||||
UI_BoxFlag_HotAnimation|
|
||||
UI_BoxFlag_ActiveAnimation|
|
||||
UI_BoxFlag_Clickable,
|
||||
String);
|
||||
ui_signal Signal = UI_SignalFromBox(Box);
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
return(Signal);
|
||||
}
|
|
@ -0,0 +1,758 @@
|
|||
#include "vn_workspace_view.cpp"
|
||||
#include "vn_workspace_editor.cpp"
|
||||
#include "vn_workspace_commands.cpp"
|
||||
|
||||
//- sixten: Commands
|
||||
static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *Sig, u64 Argument = 0)
|
||||
{
|
||||
workspace_command *Result = 0;
|
||||
|
||||
if(Workspace->FirstFreeCommand)
|
||||
{
|
||||
Result = Workspace->FirstFreeCommand;
|
||||
DLLRemove(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, Result);
|
||||
}
|
||||
|
||||
if(!Result)
|
||||
{
|
||||
Result = PushStruct(&Workspace->CommandArena, workspace_command);
|
||||
}
|
||||
|
||||
Result->Command = Sig;
|
||||
Result->Argument = Argument;
|
||||
DLLInsertLast(Workspace->FirstCommand, Workspace->LastCommand, Result);
|
||||
}
|
||||
|
||||
static void Workspace_ProcessCommands(workspace *Workspace)
|
||||
{
|
||||
workspace_command *Command = Workspace->FirstCommand;
|
||||
while(Command != 0)
|
||||
{
|
||||
Command->Command(Workspace, Command->Argument);
|
||||
|
||||
workspace_command *ToRemove = Command;
|
||||
Command = Command->Next;
|
||||
|
||||
DLLRemove(Workspace->FirstCommand, Workspace->LastCommand, ToRemove);
|
||||
ZeroSize(ToRemove, sizeof(workspace_command));
|
||||
DLLInsertLast(Workspace->FirstFreeCommand, Workspace->LastFreeCommand, ToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_ProcessKeyBinds(workspace *Workspace)
|
||||
{
|
||||
platform_event_list *EventList = Workspace->EventList;
|
||||
|
||||
for(platform_event *Event = EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if(Event->Type == PlatformEvent_Press)
|
||||
{
|
||||
for(s32 KeybindIndex = 0;
|
||||
KeybindIndex < Workspace->KeybindCount;
|
||||
++KeybindIndex)
|
||||
{
|
||||
workspace_keybind *Keybind = Workspace->Keybinds + KeybindIndex;
|
||||
if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers))
|
||||
{
|
||||
Workspace_IssueCommand(Workspace, Keybind->Command, Keybind->Argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//- sixten: Builder code
|
||||
static ui_signal Workspace_BuildToolbarButton(workspace *Workspace, char *Text, toolbar_menu Menu)
|
||||
{
|
||||
UI_SetNextWidth(UI_TextContent(20, 1));
|
||||
UI_SetNextHeight(UI_Pixels(30, 1));
|
||||
UI_SetNextCornerRadius(4);
|
||||
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
|
||||
|
||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_DrawText |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
UI_BoxFlag_Clickable,
|
||||
Text);
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(Box);
|
||||
|
||||
if(Workspace->Menu == ToolbarMenu_None)
|
||||
{
|
||||
if(Signal.Clicked)
|
||||
{
|
||||
Workspace->Menu = Menu;
|
||||
Workspace->MenuTransition = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Signal.Hovering)
|
||||
{
|
||||
if(Workspace->Menu != Menu)
|
||||
{
|
||||
Workspace->MenuTransition = 0;
|
||||
}
|
||||
|
||||
Workspace->Menu = Menu;
|
||||
Workspace->MenuP = V2(Box->Rect.Min.x, Box->Rect.Max.y);
|
||||
}
|
||||
}
|
||||
|
||||
return(Signal);
|
||||
}
|
||||
|
||||
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut)
|
||||
{
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
|
||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
UI_BoxFlag_Clickable,
|
||||
"Menu Item %s", Text);
|
||||
|
||||
UI_Parent(Box)
|
||||
{
|
||||
UI_Width(UI_Pixels(25, 1)) UI_Font(Font_Icons) UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Icon);
|
||||
UI_Width(UI_TextContent(5, 1)) UI_MakeBoxF(UI_BoxFlag_DrawText, Text);
|
||||
UI_Spacer(UI_Percent(1, 0));
|
||||
|
||||
UI_TextColor(V4(0.5, 0.5, 0.5, 1.0)) UI_Width(UI_TextContent(15, 1))
|
||||
UI_MakeBoxF(UI_BoxFlag_DrawText, Shortcut);
|
||||
}
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(Box);
|
||||
return(Signal);
|
||||
}
|
||||
|
||||
static void Workspace_BuildToolbar(workspace *Workspace, r32 dtForFrame)
|
||||
{
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
UI_SetNextHeight(UI_Pixels(30, 1));
|
||||
UI_SetNextBackgroundColor(Theme_BackgroundColor);
|
||||
|
||||
ui_box *ToolbarBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder,
|
||||
"Workspace Toolbar");
|
||||
|
||||
UI_Parent(ToolbarBox)
|
||||
{
|
||||
Workspace_BuildToolbarButton(Workspace, "Panel", ToolbarMenu_Panel);
|
||||
Workspace_BuildToolbarButton(Workspace, "View", ToolbarMenu_View);
|
||||
Workspace_BuildToolbarButton(Workspace, "Window", ToolbarMenu_Window);
|
||||
|
||||
UI_Spacer(UI_Percent(1, 0));
|
||||
}
|
||||
|
||||
if(Workspace->Menu != ToolbarMenu_None)
|
||||
{
|
||||
r32 MenuTransition = Workspace->MenuTransition;
|
||||
|
||||
UI_SetNextTooltip();
|
||||
UI_SetNextFixedX(Workspace->MenuP.x);
|
||||
UI_SetNextFixedY(Workspace->MenuP.y);
|
||||
UI_SetNextLayoutAxis(Axis2_Y);
|
||||
UI_SetNextWidth(UI_Pixels(250, 1));
|
||||
UI_SetNextHeight(UI_ChildrenSum(MenuTransition, 1));
|
||||
ui_box *Dropdown = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawDropShadow |
|
||||
UI_BoxFlag_Clip |
|
||||
UI_BoxFlag_FloatingX |
|
||||
UI_BoxFlag_FloatingY,
|
||||
"Workspace Dropdown");
|
||||
|
||||
UI_Parent(Dropdown)
|
||||
UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1))
|
||||
UI_BorderColor(V4(0.45, 0.45, 0.45, 1))
|
||||
UI_CornerRadius(2)
|
||||
UI_Size(UI_Percent(1, 1), UI_Pixels(25, 1))
|
||||
{
|
||||
if(Workspace->Menu == ToolbarMenu_Panel)
|
||||
{
|
||||
if(Workspace_BuildMenuItem(FontIcon_ResizeHorizontal, "Split Horizontal", "Ctrl + P").Clicked)
|
||||
{
|
||||
Workspace_IssueCommand(Workspace, Workspace_Command_SplitPanelHorizontal);
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
|
||||
if(Workspace_BuildMenuItem(FontIcon_ResizeVertical, "Split Vertical", "Ctrl + L").Clicked)
|
||||
{
|
||||
Workspace_IssueCommand(Workspace, Workspace_Command_SplitPanelVertical);
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
}
|
||||
else if(Workspace->Menu == ToolbarMenu_View)
|
||||
{
|
||||
workspace_panel *CurrentPanel = Workspace->CurrentPanel;
|
||||
|
||||
if(Workspace_BuildMenuItem(FontIcon_None, "Welcome", "").Clicked)
|
||||
{
|
||||
workspace_view *NewView = Workspace_CreateNewView(Workspace_View_Startup, CurrentPanel);
|
||||
DLLInsertLast(CurrentPanel->FirstView, CurrentPanel->LastView, NewView);
|
||||
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
if(Workspace_BuildMenuItem(FontIcon_None, "Editor", "").Clicked)
|
||||
{
|
||||
workspace_view *NewView = Workspace_CreateNewView(Workspace_View_Editor, CurrentPanel);
|
||||
DLLInsertLast(CurrentPanel->FirstView, CurrentPanel->LastView, NewView);
|
||||
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
if(Workspace_BuildMenuItem(FontIcon_Wrench, "Settings", "").Clicked)
|
||||
{
|
||||
workspace_view *NewView = Workspace_CreateNewView(Workspace_View_Settings, CurrentPanel);
|
||||
DLLInsertLast(CurrentPanel->FirstView, CurrentPanel->LastView, NewView);
|
||||
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
}
|
||||
else if(Workspace->Menu == ToolbarMenu_Window)
|
||||
{
|
||||
if(Workspace_BuildMenuItem(FontIcon_WindowMaximize, "ToggleFullscreen", "Alt + Enter").Clicked)
|
||||
{
|
||||
Platform.ToggleFullscreen();
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationCurve_AnimateValueDirect(1, 0.1, &Workspace->MenuTransition);
|
||||
}
|
||||
|
||||
// sixten: Unless the mouse press was captured, we close the menu.
|
||||
if(Platform_KeyPress(Workspace->EventList, Key_MouseLeft))
|
||||
{
|
||||
Workspace->Menu = ToolbarMenu_None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: Panels
|
||||
static workspace_panel *Workspace_CreateNewPanel(workspace *Workspace, workspace_panel *Parent)
|
||||
{
|
||||
workspace_panel *Result = 0;
|
||||
|
||||
if(DLLIsEmpty(Workspace->FirstFreePanel))
|
||||
{
|
||||
Result = PushStruct(&Workspace->PanelArena, workspace_panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Workspace->FirstFreePanel;
|
||||
DLLRemove(Workspace->FirstFreePanel, Workspace->LastFreePanel, Result);
|
||||
|
||||
*Result = {};
|
||||
}
|
||||
|
||||
Result->Parent = Parent;
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void Workspace_DeletePanel(workspace *Workspace, workspace_panel *Panel)
|
||||
{
|
||||
if(Workspace->CurrentPanel == Panel)
|
||||
{
|
||||
Workspace->CurrentPanel = 0;
|
||||
}
|
||||
|
||||
*Panel = {};
|
||||
DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel);
|
||||
}
|
||||
|
||||
static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, axis2 Axis)
|
||||
{
|
||||
if(Panel)
|
||||
{
|
||||
workspace_panel *Parent = Panel->Parent;
|
||||
|
||||
if(Parent && (Parent->SplitAxis == Axis))
|
||||
{
|
||||
workspace_panel *NewPanel = Workspace_CreateNewPanel(Workspace, Parent);
|
||||
NewPanel->PercentOfParent = Panel->PercentOfParent = Panel->PercentOfParent * 0.5;
|
||||
|
||||
DLLInsert_NP(Parent->First, Parent->Last, Panel, NewPanel, Next, Prev);
|
||||
}
|
||||
else
|
||||
{
|
||||
workspace_panel *NewPanel = Workspace_CreateNewPanel(Workspace, Panel);
|
||||
NewPanel->FirstView = Panel->FirstView;
|
||||
NewPanel->LastView = Panel->LastView;
|
||||
|
||||
// sixten: Update the parents of the children.
|
||||
for(workspace_view *Child = NewPanel->FirstView;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
Child->Parent = NewPanel;
|
||||
}
|
||||
|
||||
NewPanel->CurrentView = Panel->CurrentView;
|
||||
NewPanel->PercentOfParent = 0.5;
|
||||
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
|
||||
|
||||
NewPanel = Workspace_CreateNewPanel(Workspace, Panel);
|
||||
NewPanel->PercentOfParent = 0.5;
|
||||
DLLInsertLast(Panel->First, Panel->Last, NewPanel);
|
||||
|
||||
Panel->FirstView = 0;
|
||||
Panel->LastView = 0;
|
||||
Panel->CurrentView = 0;
|
||||
Panel->SplitAxis = Axis;
|
||||
|
||||
if(Workspace->CurrentPanel == Panel)
|
||||
{
|
||||
Workspace->CurrentPanel = Panel->First;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Workspace_BeginDrag(workspace *Workspace, workspace_drag_payload *Payload)
|
||||
{
|
||||
// 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);
|
||||
|
||||
Workspace->DragPayload = *Payload;
|
||||
Workspace->DragPayloadState = Workspace_DragPayload_Active;
|
||||
}
|
||||
|
||||
inline b32 Workspace_GetDragPayload(workspace *Workspace, workspace_drag_payload *Dest)
|
||||
{
|
||||
b32 Result = (Workspace->DragPayloadState != Workspace_DragPayload_Inactive);
|
||||
*Dest = Workspace->DragPayload;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void Workspace_BuildTabItem(workspace *Workspace, workspace_panel *Panel, workspace_view *View)
|
||||
{
|
||||
b32 ViewIsCurrent = (Panel->CurrentView == View);
|
||||
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
|
||||
|
||||
string Name = Workspace_GetViewName(View);
|
||||
|
||||
v4 BackgroundColor = ViewIsCurrent ? (PanelIsCurrent ? Theme_HighlightBorderColor : Theme_BorderColor) : ColorFromHex(0x353738FF);
|
||||
|
||||
UI_SetNextWidth(UI_ChildrenSum(1, 1));
|
||||
UI_SetNextHeight(UI_Percent(1, 1));
|
||||
UI_SetNextBackgroundColor(BackgroundColor);
|
||||
UI_SetNextBorderColor(LinearBlend(UI_TopBackgroundColor(), Color_Grey, 0.5));
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
UI_SetNextCornerRadius(0.0);
|
||||
|
||||
ui_box *TabBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawDropShadow |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
UI_BoxFlag_Clickable,
|
||||
"Workspace Panel Tab Item %S#%p", Name, View);
|
||||
|
||||
UI_Parent(TabBox)
|
||||
UI_Padding(UI_Pixels(5, 1))
|
||||
{
|
||||
UI_Size(UI_TextContent(1, 1), UI_Percent(1, 1)) UI_Label(Name);
|
||||
UI_Spacer(UI_Pixels(5, 1));
|
||||
|
||||
// sixten: Build close button
|
||||
{
|
||||
UI_SetNextFont(Font_Icons);
|
||||
UI_SetNextSize(UI_TextContent(1, 1), UI_Percent(1, 1));
|
||||
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);
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(TabBox);
|
||||
if(Signal.Clicked)
|
||||
{
|
||||
Workspace->CurrentPanel = Panel;
|
||||
Panel->CurrentView = View;
|
||||
}
|
||||
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
workspace_drag_payload Payload = {};
|
||||
Payload.View = View;
|
||||
Payload.Key = TabBox->Key;
|
||||
|
||||
Workspace_BeginDrag(Workspace, &Payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildPanelHeader(workspace *Workspace, workspace_panel *Panel)
|
||||
{
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
UI_SetNextBackgroundColor(ColorFromHex(0x252728FF));
|
||||
UI_SetNextCornerRadius(0);
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(30, 1));
|
||||
|
||||
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "Workspace Panel Header"))
|
||||
{
|
||||
for(workspace_view *View = Panel->FirstView;
|
||||
View != 0;
|
||||
View = View->Next)
|
||||
{
|
||||
Workspace_BuildTabItem(Workspace, Panel, View);
|
||||
}
|
||||
|
||||
UI_Spacer(UI_Percent(1, 0));
|
||||
|
||||
// sixten: Panel Close Button
|
||||
if(Panel != Workspace->RootPanel)
|
||||
{
|
||||
UI_SetNextSize(UI_Pixels(30, 1), UI_Pixels(30, 1));
|
||||
UI_SetNextFont(Font_Icons);
|
||||
UI_SetNextBorderColor(ColorFromHex(0xA6514288));
|
||||
UI_SetNextBackgroundColor(ColorFromHex(0xC24630BB));
|
||||
UI_SetNextCornerRadius(4);
|
||||
|
||||
ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
//UI_BoxFlag_DrawBackground |
|
||||
//UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_DrawText |
|
||||
UI_BoxFlag_Clickable,
|
||||
"%U", FontIcon_Cancel);
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(CloseBox);
|
||||
if(Signal.Clicked)
|
||||
{
|
||||
Workspace_IssueCommand(Workspace, Workspace_Command_ClosePanel, PointerToU64(Panel));
|
||||
}
|
||||
}
|
||||
|
||||
UI_Spacer(UI_Pixels(2, 1));
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildPanel(workspace *Workspace, workspace_panel *Panel)
|
||||
{
|
||||
// sixten: Fill remaining percent of parent.
|
||||
workspace_panel *Parent = Panel->Parent;
|
||||
if(Parent && Panel != Parent->First)
|
||||
{
|
||||
r32 TotalOfParent = 0;
|
||||
for(workspace_panel *Child = Parent->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
if(Child != Panel)
|
||||
{
|
||||
TotalOfParent += Child->PercentOfParent;
|
||||
}
|
||||
}
|
||||
|
||||
Panel->PercentOfParent = 1.0 - TotalOfParent;
|
||||
}
|
||||
|
||||
ui_box *PanelBox = UI_MakeBoxF(0, "Workspace Panel %p", Panel);
|
||||
UI_Parent(PanelBox)
|
||||
{
|
||||
if(DLLIsEmpty(Panel->First))
|
||||
{
|
||||
Workspace_BuildPanelHeader(Workspace, Panel);
|
||||
|
||||
// sixten: Main body
|
||||
{
|
||||
b32 PanelIsCurrent = (Workspace->CurrentPanel == Panel);
|
||||
|
||||
UI_PushSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
||||
|
||||
r32 HighlightTransition = AnimationCurve_AnimateValueF(PanelIsCurrent, 0, 0.25, "Workspace Panel Highlight %p", Panel);
|
||||
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, HighlightTransition));
|
||||
UI_SetNextBackgroundColor(Theme_BackgroundColor);
|
||||
|
||||
ui_box *BodyBox = UI_MakeBoxF(UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_Clip |
|
||||
UI_BoxFlag_Clickable,
|
||||
"Workspace Panel Body");
|
||||
UI_Parent(BodyBox)
|
||||
{
|
||||
if(Panel->FirstView)
|
||||
{
|
||||
if(!Panel->CurrentView)
|
||||
{
|
||||
Panel->CurrentView = Panel->FirstView;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_Column UI_Padding(UI_Percent(1, 0))
|
||||
UI_Height(UI_ChildrenSum(1, 1)) UI_Row UI_Padding(UI_Percent(1, 0))
|
||||
{
|
||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||
{
|
||||
UI_LabelF("- empty -");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Panel->CurrentView)
|
||||
{
|
||||
ui_key CurrentActive = UI_GetActive();
|
||||
|
||||
Workspace_BuildView(Workspace, Panel->CurrentView);
|
||||
|
||||
if(!AreEqual(CurrentActive, UI_GetActive()))
|
||||
{
|
||||
Workspace->CurrentPanel = Panel;
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Draw dragged view overlay.
|
||||
{
|
||||
workspace_drag_payload Payload;
|
||||
b32 DragActive = Workspace_GetDragPayload(Workspace, &Payload);
|
||||
|
||||
b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) &&
|
||||
InRange(BodyBox->Rect, UI_GetState()->MouseP));
|
||||
|
||||
if(OverlayActive && Workspace->DragPayloadState == Workspace_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;
|
||||
|
||||
// sixten(TODO): Pull out the code below into separate functions.
|
||||
|
||||
// sixten: Move view
|
||||
workspace_view *View = Payload.View;
|
||||
{
|
||||
workspace_panel *OldParent = View->Parent;
|
||||
b32 ViewWasCurrent = ((OldParent->CurrentView == View) &&
|
||||
(Workspace->CurrentPanel == OldParent));
|
||||
|
||||
// sixten: Detatch view
|
||||
{
|
||||
Assert(OldParent);
|
||||
|
||||
if(OldParent->CurrentView == View)
|
||||
{
|
||||
OldParent->CurrentView = 0;
|
||||
}
|
||||
DLLRemove(OldParent->FirstView, OldParent->LastView, View);
|
||||
}
|
||||
|
||||
View->Parent = Panel;
|
||||
DLLInsertLast(Panel->FirstView, Panel->LastView, View);
|
||||
|
||||
if(ViewWasCurrent)
|
||||
{
|
||||
Workspace->CurrentPanel = Panel;
|
||||
Panel->CurrentView = View;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r32 OverlayTransition = AnimationCurve_AnimateValueF(OverlayActive, 0, 0.25, "Panel Drag Overlay %p", Panel);
|
||||
|
||||
v4 OverlayColor = LinearBlend(Color_Grey, Theme_HighlightBorderColor, 0.75);
|
||||
OverlayColor.a = 0.5*OverlayTransition;
|
||||
|
||||
UI_SetNextBackgroundColor(OverlayColor);
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1));
|
||||
|
||||
UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_FloatingX |
|
||||
UI_BoxFlag_FloatingY,
|
||||
"Workspace Panel Drag Hover");
|
||||
}
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(BodyBox);
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
Workspace->CurrentPanel = Panel;
|
||||
}
|
||||
|
||||
UI_PopSize();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
|
||||
UI_SetNextLayoutAxis(Panel->SplitAxis);
|
||||
|
||||
UI_Parent(UI_MakeBoxF(0, ""))
|
||||
{
|
||||
s32 ChildCount = 0;
|
||||
for(workspace_panel *Child = Panel->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
++ChildCount;
|
||||
}
|
||||
|
||||
v2 PanelDim = DimOfRange(PanelBox->Rect);
|
||||
|
||||
r32 PaddingSize = 5;
|
||||
r32 PaddedSpace = (ChildCount - 1)*PaddingSize;
|
||||
r32 PercentPaddedSpace = PaddedSpace / PanelDim.E[Panel->SplitAxis];
|
||||
r32 SizeScalar = 1.0 - PercentPaddedSpace;
|
||||
|
||||
for(workspace_panel *Child = Panel->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
UI_SetNextAxisSize(Panel->SplitAxis, UI_Percent(Child->PercentOfParent*SizeScalar, 0));
|
||||
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
|
||||
Workspace_BuildPanel(Workspace, Child);
|
||||
|
||||
if(Child->Next)
|
||||
{
|
||||
UI_SetNextAxisSize(Panel->SplitAxis, UI_Pixels(PaddingSize, 1));
|
||||
UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0));
|
||||
ui_box *DragBox = UI_MakeBoxF(UI_BoxFlag_Clickable, "Workspace Panel Drag %p", Child);
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(DragBox);
|
||||
if(Signal.Hovering || Signal.Dragging)
|
||||
{
|
||||
Platform.SetCursor((Panel->SplitAxis == Axis2_X) ?
|
||||
PlatformCursor_ArrowHorizontal :
|
||||
PlatformCursor_ArrowVertical);
|
||||
}
|
||||
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
UI_StoreDragR32(Child->PercentOfParent);
|
||||
}
|
||||
|
||||
r32 Delta = Signal.DragDelta.E[Panel->SplitAxis]/PanelDim.E[Panel->SplitAxis];
|
||||
|
||||
r32 StartOffset = UI_GetDragR32();
|
||||
r32 EndOffset = StartOffset + Delta;
|
||||
|
||||
Child->PercentOfParent = Clamp(EndOffset, 0.05, 0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildDragPayload(workspace *Workspace, vn_input *Input)
|
||||
{
|
||||
workspace_drag_payload Payload;
|
||||
if(Workspace_GetDragPayload(Workspace, &Payload))
|
||||
{
|
||||
if(Workspace->DragPayloadState == Workspace_DragPayload_Released)
|
||||
{
|
||||
Workspace->DragPayloadState = Workspace_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));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Workspace->DragPayloadState == Workspace_DragPayload_Active)
|
||||
{
|
||||
Workspace->DragPayloadState = Workspace_DragPayload_Released;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- sixten: Workspace
|
||||
static void Workspace_Init(workspace *Workspace)
|
||||
{
|
||||
Workspace->RootPanel = Workspace->CurrentPanel = Workspace_CreateNewPanel(Workspace, 0);
|
||||
|
||||
// sixten(TEMP): Add mock views.
|
||||
{
|
||||
workspace_view *View1 = Workspace_CreateNewView(Workspace_View_Startup, Workspace->RootPanel);
|
||||
DLLInsertLast(Workspace->RootPanel->FirstView, Workspace->RootPanel->LastView, View1);
|
||||
}
|
||||
|
||||
// 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);
|
||||
#undef BIND_COMMAND
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_Update(workspace *Workspace, vn_render_commands *RenderCommands,
|
||||
vn_input *Input, glyph_atlas *GlyphAtlas)
|
||||
{
|
||||
Workspace->EventList = Input->EventList;
|
||||
|
||||
// sixten: Process last frame's commands.
|
||||
Workspace_ProcessKeyBinds(Workspace);
|
||||
Workspace_ProcessCommands(Workspace);
|
||||
|
||||
if(!Workspace->CurrentPanel)
|
||||
{
|
||||
Workspace->CurrentPanel = Workspace->RootPanel;
|
||||
while(Workspace->CurrentPanel->First != 0)
|
||||
{
|
||||
Workspace->CurrentPanel = Workspace->CurrentPanel->First;
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Build the UI.
|
||||
UI_BeginBuild(RenderCommands->RenderDim);
|
||||
{
|
||||
Workspace_BuildToolbar(Workspace, Input->dtForFrame);
|
||||
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0));
|
||||
Workspace_BuildPanel(Workspace, Workspace->RootPanel);
|
||||
|
||||
Workspace_BuildDragPayload(Workspace, Input);
|
||||
}
|
||||
|
||||
UI_EndBuild(GlyphAtlas);
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* date = May 5th 2023 10:12 am */
|
||||
|
||||
#ifndef VN_WORKSPACE_H
|
||||
#define VN_WORKSPACE_H
|
||||
|
||||
#include "vn_workspace_editor.h"
|
||||
|
||||
// sixten(TODO): Remove this type entirely.
|
||||
enum toolbar_menu
|
||||
{
|
||||
ToolbarMenu_None = 0,
|
||||
ToolbarMenu_Panel,
|
||||
ToolbarMenu_View,
|
||||
ToolbarMenu_Window,
|
||||
};
|
||||
|
||||
struct workspace_panel
|
||||
{
|
||||
workspace_panel *First;
|
||||
workspace_panel *Last;
|
||||
workspace_panel *Next;
|
||||
workspace_panel *Prev;
|
||||
workspace_panel *Parent;
|
||||
|
||||
struct workspace_view *FirstView;
|
||||
struct workspace_view *LastView;
|
||||
|
||||
struct workspace_view *CurrentView;
|
||||
|
||||
axis2 SplitAxis;
|
||||
r32 PercentOfParent;
|
||||
};
|
||||
|
||||
#include "vn_workspace_view.h"
|
||||
|
||||
#define WORKSPACE_COMMAND(name, ...) void name(workspace *Workspace, u64 Argument)
|
||||
typedef WORKSPACE_COMMAND(workspace_command_sig);
|
||||
|
||||
struct workspace_command
|
||||
{
|
||||
workspace_command_sig *Command;
|
||||
u64 Argument;
|
||||
|
||||
workspace_command *Next;
|
||||
workspace_command *Prev;
|
||||
};
|
||||
|
||||
struct workspace_keybind
|
||||
{
|
||||
platform_key Key;
|
||||
platform_modifiers Modifiers;
|
||||
workspace_command_sig *Command;
|
||||
u64 Argument;
|
||||
};
|
||||
|
||||
enum workspace_drag_payload_state
|
||||
{
|
||||
Workspace_DragPayload_Inactive = 0,
|
||||
Workspace_DragPayload_Active,
|
||||
Workspace_DragPayload_Released,
|
||||
};
|
||||
|
||||
struct workspace_drag_payload
|
||||
{
|
||||
ui_key Key;
|
||||
workspace_view *View;
|
||||
};
|
||||
|
||||
struct workspace
|
||||
{
|
||||
platform_event_list *EventList;
|
||||
|
||||
// sixten: Command Allocation
|
||||
memory_arena CommandArena;
|
||||
workspace_command *FirstFreeCommand;
|
||||
workspace_command *LastFreeCommand;
|
||||
|
||||
// sixten: Command List
|
||||
workspace_command *FirstCommand;
|
||||
workspace_command *LastCommand;
|
||||
|
||||
// sixten: Keybinds
|
||||
workspace_keybind Keybinds[256];
|
||||
s32 KeybindCount;
|
||||
|
||||
// sixten: Panels
|
||||
memory_arena PanelArena;
|
||||
workspace_panel *FirstFreePanel;
|
||||
workspace_panel *LastFreePanel;
|
||||
|
||||
workspace_drag_payload_state DragPayloadState;
|
||||
workspace_drag_payload DragPayload;
|
||||
|
||||
toolbar_menu Menu;
|
||||
v2 MenuP;
|
||||
r32 MenuTransition;
|
||||
|
||||
workspace_panel *RootPanel;
|
||||
workspace_panel *CurrentPanel;
|
||||
};
|
||||
|
||||
//- sixten: Commands
|
||||
static void Workspace_IssueCommand(workspace *Workspace, workspace_command_sig *Sig, u64 Argument);
|
||||
static void Workspace_ProcessCommands(workspace *Workspace);
|
||||
|
||||
//- sixten: Panels
|
||||
static workspace_panel *Workspace_CreateNewPanel(workspace *Workspace, workspace_panel *Parent);
|
||||
static void Workspace_DeletePanel(workspace *Workspace, workspace_panel *Panel);
|
||||
static void Workspace_SplitPanel(workspace *Workspace, workspace_panel *Panel, axis2 Axis);
|
||||
|
||||
//- sixten: Builder code
|
||||
static ui_signal Workspace_BuildToolbarButton(workspace *Workspace, char *Text, toolbar_menu Menu);
|
||||
static ui_signal Workspace_BuildMenuItem(u32 Icon, char *Text, char *Shortcut);
|
||||
static void Workspace_BuildToolbar(workspace *Workspace, 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);
|
||||
|
||||
#endif //VN_WORKSPACE_H
|
|
@ -0,0 +1,83 @@
|
|||
WORKSPACE_COMMAND(Workspace_Command_SplitPanelHorizontal)
|
||||
{
|
||||
Workspace_SplitPanel(Workspace, Workspace->CurrentPanel, Axis2_X);
|
||||
}
|
||||
|
||||
WORKSPACE_COMMAND(Workspace_Command_SplitPanelVertical)
|
||||
{
|
||||
Workspace_SplitPanel(Workspace, Workspace->CurrentPanel, Axis2_Y);
|
||||
}
|
||||
|
||||
WORKSPACE_COMMAND(Workspace_Command_ClosePanel)
|
||||
{
|
||||
workspace_panel *Panel = (workspace_panel *)Argument;
|
||||
if(!Panel)
|
||||
{
|
||||
Panel = Workspace->CurrentPanel;
|
||||
}
|
||||
|
||||
workspace_panel *Parent = Panel->Parent;
|
||||
|
||||
Assert(Parent);
|
||||
Assert(Panel != Workspace->RootPanel);
|
||||
|
||||
DLLRemove(Parent->First, Parent->Last, Panel);
|
||||
|
||||
b32 OneChildRemains = (Parent->First == Parent->Last);
|
||||
if(OneChildRemains)
|
||||
{
|
||||
workspace_panel *Child = Parent->First;
|
||||
Assert(DLLIsEmpty(Parent->FirstView));
|
||||
|
||||
Parent->FirstView = Child->FirstView;
|
||||
Parent->LastView = Child->LastView;
|
||||
Parent->First = Child->First;
|
||||
Parent->Last = Child->Last;
|
||||
Parent->SplitAxis = Child->SplitAxis;
|
||||
|
||||
// sixten: Update the parents of the children.
|
||||
for(workspace_view *View = Parent->FirstView;
|
||||
View != 0;
|
||||
View = View->Next)
|
||||
{
|
||||
View->Parent = Parent;
|
||||
}
|
||||
for(workspace_panel *ParentChild = Parent->First;
|
||||
ParentChild != 0;
|
||||
ParentChild = ParentChild->Next)
|
||||
{
|
||||
ParentChild->Parent = Parent;
|
||||
}
|
||||
|
||||
DLLRemove(Parent->First, Parent->Last, Child);
|
||||
Workspace_DeletePanel(Workspace, Child);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 ChildCount = 0;
|
||||
for(workspace_panel *Child = Parent->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
++ChildCount;
|
||||
}
|
||||
|
||||
r32 ToAppend = Panel->PercentOfParent / ChildCount;
|
||||
for(workspace_panel *Child = Parent->First;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
Child->PercentOfParent += ToAppend;
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Delete all child views.
|
||||
for(workspace_view *Child = Panel->FirstView;
|
||||
Child != 0;
|
||||
Child = Child->Next)
|
||||
{
|
||||
//Workspace_DeleteView(Child);
|
||||
}
|
||||
|
||||
Workspace_DeletePanel(Workspace, Panel);
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
//- sixten: Managing nodes
|
||||
static workspace_editor_node *Workspace_GetNewEditorNode(workspace_view *View)
|
||||
{
|
||||
Assert(View->Type == Workspace_View_Editor);
|
||||
|
||||
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
|
||||
|
||||
workspace_editor_node *Result = 0;
|
||||
|
||||
if(DLLIsEmpty(Editor->FirstFreeNode))
|
||||
{
|
||||
Result = PushStruct(&View->Arena, workspace_editor_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Editor->FirstFreeNode;
|
||||
DLLRemove(Editor->FirstFreeNode, Editor->LastFreeNode, Result);
|
||||
}
|
||||
|
||||
if(Result)
|
||||
{
|
||||
*Result = {};
|
||||
DLLInsertLast(Editor->FirstNode, Editor->LastNode, Result);
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
//- sixten: Transformations
|
||||
inline r32 Workspace_ViewToWorld(r32 Offset, r32 Scale, r32 Dim, r32 P)
|
||||
{
|
||||
r32 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 Workspace_WorldToView(r32 Offset, r32 Scale, r32 Dim, r32 P)
|
||||
{
|
||||
r32 Result = (P + Offset)*Scale + Dim*0.5;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 Workspace_ViewToWorld(v2 Offset, r32 Scale, v2 Dim, v2 P)
|
||||
{
|
||||
v2 Result = (P - Dim*0.5)*(1.0/Scale) - Offset;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 Workspace_WorldToView(v2 Offset, r32 Scale, v2 Dim, v2 P)
|
||||
{
|
||||
v2 Result = (P + Offset)*Scale + Dim*0.5;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel)
|
||||
{
|
||||
r32 PixelsPerUnit = 100.0;
|
||||
|
||||
r32 Scale = PixelsPerUnit*Pow(1.25, ZoomLevel);
|
||||
return(Scale);
|
||||
}
|
||||
|
||||
//- sixten: Commands
|
||||
|
||||
|
||||
//- sixten: Builder code
|
||||
static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data)
|
||||
{
|
||||
workspace_view_editor *Editor = (workspace_view_editor *)Data;
|
||||
|
||||
r32 Scale = Editor->Scale;
|
||||
|
||||
v4 LineColor = Theme_BorderColor;
|
||||
|
||||
v2 Dim = DimOfRange(Box->Rect);
|
||||
|
||||
s32 VerticalLineCount = Dim.x / Scale + 4;
|
||||
for(s32 LineIndex = -VerticalLineCount/2;
|
||||
LineIndex < VerticalLineCount/2;
|
||||
++LineIndex)
|
||||
{
|
||||
r32 OffsetX = Workspace_WorldToView(Editor->Offset.x, Scale, Dim.x, LineIndex - (s32)Editor->Offset.x);
|
||||
PushQuad(Group, Box->Rect.Min + V2(OffsetX, 0), V2(1.5, Dim.y), LineColor, 0, 1.2, 0);
|
||||
}
|
||||
|
||||
s32 HorizontalLineCount = Dim.y / Scale + 4;
|
||||
for(s32 LineIndex = -HorizontalLineCount/2;
|
||||
LineIndex < HorizontalLineCount/2;
|
||||
++LineIndex)
|
||||
{
|
||||
r32 OffsetY = Workspace_WorldToView(Editor->Offset.y, Scale, Dim.y, LineIndex - (s32)Editor->Offset.y);
|
||||
|
||||
PushQuad(Group, Box->Rect.Min + V2(0, OffsetY), V2(Dim.x, 1.5), LineColor, 0, 1.2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildEditor(workspace *Workspace, workspace_view *View)
|
||||
{
|
||||
workspace_view_editor *Editor = (workspace_view_editor *)View->Data;
|
||||
|
||||
// sixten(TODO): These should be able to have a strictness of 1, but they can't. Fix that.
|
||||
UI_SetNextWidth(UI_Percent(1, 0));
|
||||
UI_SetNextHeight(UI_Percent(1, 0));
|
||||
|
||||
ui_box *EditorBox = UI_MakeBoxF(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "Workspace Editor %p", View);
|
||||
EditorBox->DrawCallback = Workspace_EditorDrawCallback;
|
||||
EditorBox->DrawCallbackData = Editor;
|
||||
|
||||
r32 AnimatedZoomLevel = AnimationCurve_AnimateValueF(Editor->ZoomLevel, 0, 0.25, "Workspace Editor Zoom");
|
||||
Editor->Scale = Workspace_CalculateScaleFromZoomLevel(AnimatedZoomLevel);
|
||||
|
||||
v2 EditorDim = DimOfRange(EditorBox->Rect);
|
||||
|
||||
// sixten: Build the node boxes.
|
||||
for(workspace_editor_node *Node = Editor->FirstNode;
|
||||
Node != 0;
|
||||
Node = Node->Next)
|
||||
{
|
||||
v2 ViewDim = V2(2, 1.5)*Editor->Scale;
|
||||
v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
|
||||
|
||||
UI_SetNextSize(UI_Pixels(ViewDim.x, 1), UI_Pixels(ViewDim.y, 1));
|
||||
UI_SetNextFixedP(ViewP);
|
||||
UI_SetNextLayoutAxis(Axis2_Y);
|
||||
|
||||
Node->Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_FloatingX |
|
||||
UI_BoxFlag_FloatingY |
|
||||
UI_BoxFlag_DrawDropShadow,
|
||||
"Workspace Editor Node %p", Node);
|
||||
|
||||
UI_Parent(Node->Box)
|
||||
{
|
||||
UI_SetNextBackgroundColor(LinearBlend(Theme_BackgroundColor, Color_Black, 0.3));
|
||||
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(20, 1));
|
||||
Node->TitleBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_Clickable,
|
||||
"Workspace Editor Node Title");
|
||||
|
||||
UI_Parent(Node->TitleBox)
|
||||
{
|
||||
UI_Width(UI_TextContent(7, 0)) UI_Font(Font_Bold) UI_LabelF("Node");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Get input from boxes.
|
||||
{
|
||||
workspace_editor_node *Next = 0;
|
||||
for(workspace_editor_node *Node = Editor->FirstNode;
|
||||
Node != 0;
|
||||
Node = Next)
|
||||
{
|
||||
Next = Node->Next;
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(Node->TitleBox);
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
UI_StoreDragV2(Node->P);
|
||||
}
|
||||
|
||||
v2 StartP = UI_GetDragV2();
|
||||
v2 EndP = StartP + Signal.DragDelta*(1.0 / Editor->Scale);
|
||||
|
||||
Node->P = EndP;
|
||||
}
|
||||
|
||||
if(Signal.Dragging || Signal.Hovering)
|
||||
{
|
||||
Platform.SetCursor(PlatformCursor_ArrowAll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Process the movement of the node.
|
||||
{
|
||||
}
|
||||
|
||||
// sixten: Process panning and zooming of the editor.
|
||||
ui_signal Signal = UI_SignalFromBox(EditorBox);
|
||||
{
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
UI_StoreDragV2(Editor->Offset);
|
||||
}
|
||||
|
||||
v2 StartOffset = UI_GetDragV2();
|
||||
v2 EndOffset = StartOffset + Signal.DragDelta*(1.0 / Editor->Scale);
|
||||
|
||||
Editor->Offset = EndOffset;
|
||||
|
||||
// sixten: Update node positions, as to not get a one frame delay.
|
||||
for(workspace_editor_node *Node = 0;
|
||||
Node != 0;
|
||||
Node = Node->Next)
|
||||
{
|
||||
v2 ViewDim = V2(2, 1.5)*Editor->Scale;
|
||||
v2 ViewP = Workspace_WorldToView(Editor->Offset, Editor->Scale, EditorDim, Node->P) - ViewDim*0.5;
|
||||
|
||||
Node->Box->FixedP = ViewP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(platform_event *Event = Workspace->EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if(Event->Type == PlatformEvent_MouseScroll)
|
||||
{
|
||||
if(Signal.Dragging)
|
||||
{
|
||||
UI_StoreDragV2(Editor->Offset);
|
||||
UI_UpdateDragStartP();
|
||||
}
|
||||
|
||||
Editor->ZoomLevel = Clamp(Editor->ZoomLevel + Event->Scroll.y, -4, 5);
|
||||
}
|
||||
}
|
||||
|
||||
// sixten: Process shortcuts.
|
||||
if(Platform_KeyPress(Workspace->EventList, Key_Space, PlatformModifier_Ctrl))
|
||||
{
|
||||
Workspace_GetNewEditorNode(View);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* date = May 13th 2023 6:20 pm */
|
||||
|
||||
#ifndef VN_WORKSPACE_EDITOR_H
|
||||
#define VN_WORKSPACE_EDITOR_H
|
||||
|
||||
/* sixten(NOTE): Node types
|
||||
*
|
||||
* Text(String, opt. Character) -> Node
|
||||
* Menu(Strings[0..n]) -> Nodes[0..n]
|
||||
*
|
||||
*/
|
||||
|
||||
enum workspace_editor_node_type
|
||||
{
|
||||
Workspace_EditorNode_None,
|
||||
Workspace_EditorNode_Text,
|
||||
Workspace_EditorNode_Menu,
|
||||
};
|
||||
|
||||
struct workspace_editor_node
|
||||
{
|
||||
workspace_editor_node_type Type;
|
||||
|
||||
workspace_editor_node *Next;
|
||||
workspace_editor_node *Prev;
|
||||
|
||||
ui_box *Box;
|
||||
ui_box *TitleBox;
|
||||
|
||||
v2 P;
|
||||
};
|
||||
|
||||
//- sixten: Managing nodes
|
||||
static workspace_editor_node *Workspace_GetNewEditorNode(struct workspace_view *View);
|
||||
|
||||
//- sixten: Transformations
|
||||
inline v2 Workspace_ViewToWorld(v2 Offset, r32 Scale, v2 Dim, v2 P);
|
||||
inline v2 Workspace_WorldToView(v2 Offset, r32 Scale, v2 Dim, v2 P);
|
||||
inline r32 Workspace_CalculateScaleFromZoomLevel(r32 ZoomLevel);
|
||||
|
||||
//- sixten: Builder code
|
||||
static void Workspace_EditorDrawCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
|
||||
static void Workspace_BuildEditor(struct workspace *Workspace, struct workspace_view *View);
|
||||
|
||||
#endif //VN_WORKSPACE_EDITOR_H
|
|
@ -0,0 +1,419 @@
|
|||
//- sixten: Views
|
||||
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent)
|
||||
{
|
||||
workspace_view *View = BootstrapPushStruct(workspace_view, Arena);
|
||||
View->Type = Type;
|
||||
View->Parent = Parent;
|
||||
|
||||
switch(View->Type)
|
||||
{
|
||||
case Workspace_View_Editor:
|
||||
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_editor)); } break;
|
||||
case Workspace_View_CommandPalette:
|
||||
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_command_palette)); } break;
|
||||
case Workspace_View_Settings:
|
||||
{ View->Data = PushSize(&View->Arena, sizeof(workspace_view_settings)); } break;
|
||||
}
|
||||
|
||||
return(View);
|
||||
}
|
||||
|
||||
inline void Workspace_DestroyView(workspace_view *View)
|
||||
{
|
||||
// sixten(NOTE): This function does not ensure that the view is not being used anywhere else.
|
||||
Release(&View->Arena);
|
||||
}
|
||||
|
||||
inline b32 Workspace_ViewIsCurrent(workspace *Workspace, workspace_view *View)
|
||||
{
|
||||
b32 Result = (Workspace->CurrentPanel && Workspace->CurrentPanel->CurrentView == View);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline string Workspace_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;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
//- sixten: Builder code
|
||||
static void Workspace_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((char *)Box->String.Data, CommandPalette->ListerInputEditState.Cursor);
|
||||
string ToMark = MakeString((char *)Box->String.Data, CommandPalette->ListerInputEditState.Mark);
|
||||
|
||||
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);
|
||||
|
||||
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, P, Dim, Color, 0, 0, 0);
|
||||
}
|
||||
|
||||
// sixten: Draw cursor
|
||||
if(CommandPalette->ListerFieldSelected)
|
||||
{
|
||||
range_r32 CursorSpan = RangeR32(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, P, Dim, Color, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildViewTypeLister(workspace *Workspace, workspace_view *View)
|
||||
{
|
||||
workspace_view_command_palette *CommandPalette = (workspace_view_command_palette *)View->Data;
|
||||
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
UI_Size(UI_Percent(1, 1), UI_Percent(1, 1))
|
||||
UI_Parent(UI_MakeBox(0, StrLit("")))
|
||||
{
|
||||
UI_Spacer(UI_Pixels(1.25, 1));
|
||||
UI_CornerRadius(4)
|
||||
UI_BackgroundColor(V4(0.5, 0.2, 0.3, 1.0))
|
||||
UI_LayoutAxis(Axis2_X)
|
||||
UI_Height(UI_Pixels(30, 1))
|
||||
UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, "Workspace View Lister Header"))
|
||||
{
|
||||
UI_Spacer(UI_Pixels(5, 1));
|
||||
|
||||
UI_Width(UI_TextContent(10, 1)) UI_LabelF("Open View:");
|
||||
|
||||
UI_Spacer(UI_Pixels(15, 1));
|
||||
|
||||
// sixten: Input Field.
|
||||
{
|
||||
r32 SelectedTransition = AnimationCurve_AnimateValueF(CommandPalette->ListerFieldSelected ? 1.0 : 0.0,
|
||||
0, 0.125, "View Input Field %p", View);
|
||||
|
||||
v4 BorderColor = UI_TopBackgroundColor()*2;
|
||||
BorderColor.w = SelectedTransition;
|
||||
|
||||
UI_SetNextBorderColor(BorderColor);
|
||||
|
||||
UI_SetNextBackgroundColor(LinearBlend(V4(0, 0, 0, 1), UI_TopBackgroundColor(), 0.5));
|
||||
UI_SetNextWidth(UI_Percent(1, 0));
|
||||
|
||||
ui_box *InputBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_Clickable |
|
||||
UI_BoxFlag_DrawBorder,
|
||||
"View Type Lister Input");
|
||||
|
||||
UI_Parent(InputBox)
|
||||
{
|
||||
UI_SetNextWidth(UI_TextContent(15, 1));
|
||||
|
||||
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 = View;
|
||||
}
|
||||
|
||||
UI_Spacer(UI_Pixels(4, 1));
|
||||
|
||||
if(CommandPalette->ListerFieldSelected)
|
||||
{
|
||||
for(platform_event *Event = Workspace->EventList->First;
|
||||
Event != 0;
|
||||
Event = Event->Next)
|
||||
{
|
||||
if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text)
|
||||
{
|
||||
text_action Action = SingleLineTextActionFromEvent(Event);
|
||||
if(IsValid(&Action))
|
||||
{
|
||||
text_op Op = TextOpFromAction(Scratch.Arena, MakeString(CommandPalette->ListerInput, CommandPalette->ListerInputUsed),
|
||||
&CommandPalette->ListerInputEditState, &Action);
|
||||
|
||||
string Left = MakeString(CommandPalette->ListerInput, Op.Range.Min);
|
||||
string Right = MakeString(CommandPalette->ListerInput + Op.Range.Max, CommandPalette->ListerInputUsed - Op.Range.Max);
|
||||
|
||||
u64 NewStringSize = Left.Count + Right.Count + Op.ReplaceString.Count;
|
||||
char *NewString = PushArray(Scratch.Arena, char, NewStringSize);
|
||||
Copy(NewString, Left.Data, Left.Count);
|
||||
Copy(NewString + Left.Count, Op.ReplaceString.Data, Op.ReplaceString.Count);
|
||||
Copy(NewString + Left.Count + Op.ReplaceString.Count, Right.Data, Right.Count);
|
||||
|
||||
CommandPalette->ListerInputUsed = Minimum(ArrayCount(CommandPalette->ListerInput), NewStringSize);
|
||||
Copy(CommandPalette->ListerInput, NewString, CommandPalette->ListerInputUsed);
|
||||
|
||||
CommandPalette->ListerInputEditState.Cursor = Minimum(Op.NewCursor, CommandPalette->ListerInputUsed);
|
||||
CommandPalette->ListerInputEditState.Mark = Minimum(Op.NewMark, CommandPalette->ListerInputUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(UI_SignalFromBox(InputBox).Pressed)
|
||||
{
|
||||
CommandPalette->ListerFieldSelected = true;
|
||||
}
|
||||
|
||||
ui *UI = UI_GetState();
|
||||
|
||||
if(!(AreEqual(UI->Active, UI_EmptyKey()) || AreEqual(UI->Active, InputBox->Key)))
|
||||
{
|
||||
CommandPalette->ListerFieldSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UI_Spacer(UI_Pixels(15, 1));
|
||||
|
||||
{
|
||||
UI_SetNextCornerRadius(10);
|
||||
UI_SetNextBackgroundColor(V4(0.15, 0.15, 0.15, 1.0));
|
||||
UI_SetNextBorderColor(V4(0.35, 0.35, 0.35, 1.0));
|
||||
UI_SetNextSize(UI_Percent(1, 1), UI_Pixels(100, 1));
|
||||
UI_SetNextLayoutAxis(Axis2_Y);
|
||||
|
||||
ui_box *ButtonBox = UI_MakeBox(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
UI_BoxFlag_Clickable,
|
||||
StrLit("Type Lister Box"));
|
||||
|
||||
UI_SignalFromBox(ButtonBox);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
}
|
||||
|
||||
static void Workspace_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, 0, 0.3, "Workspace Settings %s %p", Name, Settings));
|
||||
|
||||
UI_SetNextFont(Font_Bold);
|
||||
UI_SetNextHeight(UI_TextContent(0, 1));
|
||||
UI_SetNextTextColor(Color);
|
||||
|
||||
ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawText |
|
||||
UI_BoxFlag_Clickable,
|
||||
Name);
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(Box);
|
||||
if(Signal.Hovering)
|
||||
{
|
||||
Platform.SetCursor(PlatformCursor_Hand);
|
||||
}
|
||||
if(Signal.Clicked)
|
||||
{
|
||||
Settings->Category = Category;
|
||||
}
|
||||
}
|
||||
|
||||
static void UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 *Open, s32 *Selected)
|
||||
{
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
UI_Parent(UI_MakeBoxF(0, ""))
|
||||
{
|
||||
UI_LabelF("Refresh Rate:");
|
||||
UI_Spacer(UI_Pixels(10, 1));
|
||||
|
||||
UI_SetNextWidth(UI_Pixels(200, 1));
|
||||
UI_SetNextCornerRadius(4);
|
||||
UI_SetNextLayoutAxis(Axis2_X);
|
||||
ui_box *DropdownBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_HotAnimation |
|
||||
UI_BoxFlag_ActiveAnimation |
|
||||
UI_BoxFlag_Clickable,
|
||||
"Dropdown");
|
||||
UI_Parent(DropdownBox)
|
||||
{
|
||||
UI_Width(UI_Percent(1, 0)) UI_LabelF(Alternatives[*Selected]);
|
||||
UI_BackgroundColor(Theme_BorderColor) UI_Width(UI_Pixels(1, 1)) UI_MakeBoxF(UI_BoxFlag_DrawBackground, "");
|
||||
UI_Width(UI_Pixels(25, 1)) UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_DownDir);
|
||||
}
|
||||
|
||||
ui_signal Signal = UI_SignalFromBox(DropdownBox);
|
||||
if(Signal.Pressed)
|
||||
{
|
||||
*Open = true;
|
||||
}
|
||||
|
||||
if(*Open)
|
||||
{
|
||||
UI_Tooltip
|
||||
{
|
||||
UI_SetNextFixedP(V2(DropdownBox->Rect.Min.x, DropdownBox->Rect.Max.y));
|
||||
UI_SetNextCornerRadius(4);
|
||||
UI_SetNextWidth(UI_Pixels(200, 1));
|
||||
UI_SetNextHeight(UI_ChildrenSum(AnimationCurve_AnimateValueF(1, 0, 0.3, "UI Dropdown %p%p", Alternatives, Open), 1));
|
||||
UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip |
|
||||
UI_BoxFlag_DrawDropShadow |
|
||||
UI_BoxFlag_FloatingX |
|
||||
UI_BoxFlag_FloatingY, "Dropdown Contents"))
|
||||
{
|
||||
for(s64 Index = 0;
|
||||
Index < AlternativeCount;
|
||||
++Index)
|
||||
{
|
||||
UI_Width(UI_Percent(1, 1)) UI_ButtonF(Alternatives[Index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Workspace_BuildSettings(workspace *Workspace, workspace_view *View)
|
||||
{
|
||||
workspace_view_settings *Settings = (workspace_view_settings *)View->Data;
|
||||
|
||||
UI_Height(UI_ChildrenSum(1, 1))
|
||||
UI_Column UI_Padding(UI_Pixels(50, 0))
|
||||
UI_Row UI_Padding(UI_Pixels(50, 0))
|
||||
{
|
||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||
UI_Font(Font_Bold) UI_FontSize(36)
|
||||
UI_LabelF("Settings");
|
||||
}
|
||||
|
||||
UI_LayoutAxis(Axis2_X)
|
||||
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
||||
UI_Parent(UI_MakeBoxF(0, ""))
|
||||
{
|
||||
UI_Width(UI_Pixels(300, 1))
|
||||
UI_Parent(UI_MakeBoxF(0, "Navigation"))
|
||||
{
|
||||
UI_Row UI_Padding(UI_Pixels(50, 1))
|
||||
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);
|
||||
UI_Spacer(UI_Pixels(30, 1));
|
||||
Workspace_BuildSettingsTabButton(Settings, "General", Workspace_Settings_General);
|
||||
UI_Spacer(UI_Pixels(30, 1));
|
||||
Workspace_BuildSettingsTabButton(Settings, "Developer", Workspace_Settings_Developer);
|
||||
|
||||
UI_Spacer(UI_Pixels(150, 1));
|
||||
}
|
||||
}
|
||||
|
||||
UI_CornerRadius(5)
|
||||
UI_Width(UI_Pixels(1.25, 1))
|
||||
UI_BackgroundColor(Color_Grey)
|
||||
UI_MakeBoxF(UI_BoxFlag_DrawBackground, "Separator");
|
||||
|
||||
UI_Padding(UI_Pixels(70, 0))
|
||||
UI_LayoutAxis(Axis2_Y)
|
||||
UI_Width(UI_Percent(1, 0))
|
||||
UI_Parent(UI_MakeBoxF(0, "Tab"))
|
||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||
{
|
||||
workspace_settings_category Category = Settings->Category;
|
||||
if(!Category || (Category == Workspace_Settings_General))
|
||||
{
|
||||
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("General");
|
||||
|
||||
char *Alternatives[] = {"60 Hz", "120 Hz", "144 Hz", "Uncapped", "V-Sync"};
|
||||
|
||||
persist b32 DropdownOpen = false;
|
||||
persist s32 DropdownSelected = 0;
|
||||
UI_DropdownSelection(Alternatives, ArrayCount(Alternatives), &DropdownOpen, &DropdownSelected);
|
||||
|
||||
UI_Spacer(UI_Pixels(50, 1));
|
||||
}
|
||||
|
||||
if(!Category || (Category == Workspace_Settings_Developer))
|
||||
{
|
||||
UI_Font(Font_Bold) UI_FontSize(36) UI_LabelF("Developer");
|
||||
UI_LabelF("Render UI Debug Rects:");
|
||||
UI_LabelF("Render FPS Counter:");
|
||||
|
||||
UI_CornerRadius(4)
|
||||
UI_Size(UI_TextContent(20, 1), UI_TextContent(10, 1))
|
||||
UI_ButtonF("Hello Line Paint Color Design Address Brightness");
|
||||
|
||||
UI_Spacer(UI_Pixels(50, 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UI_Spacer(UI_Pixels(50, 1));
|
||||
}
|
||||
|
||||
static void Workspace_BuildView(workspace *Workspace, workspace_view *View)
|
||||
{
|
||||
r32 ViewHighlightTransition =
|
||||
AnimationCurve_AnimateValueF(Workspace_ViewIsCurrent(Workspace, View), 0, 0.25, "Workspace View Highlight %p", View);
|
||||
UI_SetNextBorderColor(LinearBlend(Theme_BorderColor, Theme_HighlightBorderColor, ViewHighlightTransition));
|
||||
UI_SetNextCornerRadius(3);
|
||||
|
||||
ui_box *ViewBox = UI_MakeBoxF(UI_BoxFlag_Clickable |
|
||||
UI_BoxFlag_DrawBackground |
|
||||
UI_BoxFlag_DrawBorder |
|
||||
UI_BoxFlag_Clip,
|
||||
"Workspace View %p", View);
|
||||
|
||||
UI_Parent(ViewBox)
|
||||
UI_Size(UI_Percent(1, 0), UI_Percent(1, 0))
|
||||
{
|
||||
if(View->Type == Workspace_View_Startup)
|
||||
{
|
||||
UI_Row UI_Padding(UI_Pixels(50, 0))
|
||||
UI_Width(UI_ChildrenSum(1, 1)) UI_Column UI_Padding(UI_Pixels(50, 0))
|
||||
{
|
||||
UI_Size(UI_TextContent(0, 1), UI_TextContent(10, 1))
|
||||
{
|
||||
UI_Font(Font_Bold) UI_FontSize(36)
|
||||
UI_LabelF("Welcome to VN");
|
||||
UI_TextColor(Theme_BorderColor) UI_LabelF("An impractical way to make a game");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(View->Type == Workspace_View_CommandPalette)
|
||||
{
|
||||
Workspace_BuildViewTypeLister(Workspace, View);
|
||||
}
|
||||
else if(View->Type == Workspace_View_Editor)
|
||||
{
|
||||
Workspace_BuildEditor(Workspace, View);
|
||||
}
|
||||
else if(View->Type == Workspace_View_Settings)
|
||||
{
|
||||
Workspace_BuildSettings(Workspace, View);
|
||||
}
|
||||
}
|
||||
|
||||
UI_SignalFromBox(ViewBox);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* date = June 11th 2023 1:20 pm */
|
||||
|
||||
#ifndef VN_WORKSPACE_VIEW_H
|
||||
#define VN_WORKSPACE_VIEW_H
|
||||
|
||||
struct workspace_view
|
||||
{
|
||||
memory_arena Arena;
|
||||
enum workspace_view_type Type;
|
||||
|
||||
workspace_panel *Parent;
|
||||
workspace_view *Next;
|
||||
workspace_view *Prev;
|
||||
|
||||
void *Data;
|
||||
};
|
||||
|
||||
enum workspace_view_type
|
||||
{
|
||||
Workspace_View_Startup,
|
||||
Workspace_View_Editor,
|
||||
Workspace_View_CommandPalette,
|
||||
Workspace_View_Settings,
|
||||
};
|
||||
|
||||
struct workspace_view_editor
|
||||
{
|
||||
v2 Offset;
|
||||
r32 ZoomLevel;
|
||||
r32 Scale; // sixten(NOTE): Read-only, based on the zoom level
|
||||
workspace_editor_node *FirstNode;
|
||||
workspace_editor_node *LastNode;
|
||||
workspace_editor_node *FirstFreeNode;
|
||||
workspace_editor_node *LastFreeNode;
|
||||
};
|
||||
|
||||
struct workspace_view_command_palette
|
||||
{
|
||||
b32 ListerFieldSelected;
|
||||
char ListerInput[128];
|
||||
s32 ListerInputUsed;
|
||||
text_edit_state ListerInputEditState;
|
||||
};
|
||||
|
||||
enum workspace_settings_category
|
||||
{
|
||||
Workspace_Settings_All,
|
||||
Workspace_Settings_General,
|
||||
Workspace_Settings_Developer,
|
||||
};
|
||||
|
||||
struct workspace_view_settings
|
||||
{
|
||||
workspace_settings_category Category;
|
||||
};
|
||||
|
||||
//- sixten: Views
|
||||
inline workspace_view *Workspace_CreateNewView(workspace_view_type Type, workspace_panel *Parent);
|
||||
inline void Workspace_DestroyView(workspace_view *View);
|
||||
inline b32 Workspace_ViewIsCurrent(workspace *Workspace, workspace_view *View);
|
||||
inline string Workspace_GetViewName(workspace_view *View);
|
||||
|
||||
//- sixten: Builder code
|
||||
static void Workspace_ViewListerInputCallback(render_group *Group, glyph_atlas *Atlas, ui_box *Box, void *Data);
|
||||
static void Workspace_BuildViewTypeLister(workspace *Workspace, workspace_view *View);
|
||||
static void Workspace_BuildView(workspace *Workspace, workspace_view *View);
|
||||
|
||||
#endif //VN_WORKSPACE_VIEW_H
|
|
@ -0,0 +1,679 @@
|
|||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#include "timeapi.h"
|
||||
|
||||
#include "vn_platform.h"
|
||||
|
||||
#include "win32_main.h"
|
||||
#include "win32_opengl.cpp"
|
||||
|
||||
global b32 Global_Running;
|
||||
global win32_state Global_Win32State;
|
||||
global WINDOWPLACEMENT Global_WindowPosition = {sizeof(Global_WindowPosition)};;
|
||||
|
||||
static void Win32_PlatformError(char *Message, bool IsFatal)
|
||||
{
|
||||
MessageBoxA(0, Message, "nv - Platform Error", MB_OK|(IsFatal?MB_ICONSTOP:MB_ICONEXCLAMATION));
|
||||
|
||||
if(IsFatal)
|
||||
{
|
||||
ExitProcess((UINT)-1);
|
||||
}
|
||||
}
|
||||
|
||||
static PLATFORM_ALLOCATE_MEMORY(Win32_AllocateMemory)
|
||||
{
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
umm TotalSize = Size + sizeof(win32_memory_block);
|
||||
|
||||
win32_memory_block *Block =
|
||||
(win32_memory_block *)VirtualAlloc(0, TotalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
Assert(Block);
|
||||
Block->Block.Base = (u8 *)Block + sizeof(win32_memory_block);
|
||||
Block->Block.Size = Size;
|
||||
|
||||
win32_memory_block *Sentinel = &State->MemorySentinel;
|
||||
Block->Next = Sentinel;
|
||||
|
||||
BeginTicketMutex(&State->MemoryMutex);
|
||||
Block->Prev = Sentinel->Prev;
|
||||
Block->Prev->Next = Block;
|
||||
Block->Next->Prev = Block;
|
||||
EndTicketMutex(&State->MemoryMutex);
|
||||
|
||||
platform_memory_block *Result = &Block->Block;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static PLATFORM_DEALLOCATE_MEMORY(Win32_DeallocateMemory)
|
||||
{
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
win32_memory_block *Win32Block = (win32_memory_block *)Block;
|
||||
|
||||
if(Block)
|
||||
{
|
||||
BeginTicketMutex(&State->MemoryMutex);
|
||||
Win32Block->Prev->Next = Win32Block->Next;
|
||||
Win32Block->Next->Prev = Win32Block->Prev;
|
||||
EndTicketMutex(&State->MemoryMutex);
|
||||
}
|
||||
|
||||
BOOL Result = VirtualFree(Block, 0, MEM_RELEASE);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static PLATFORM_OPEN_FILE(Win32_OpenFile)
|
||||
{
|
||||
DWORD DesiredAccess = 0;
|
||||
if(FileAccess & PlatformAccess_Read)
|
||||
{
|
||||
DesiredAccess |= GENERIC_READ;
|
||||
}
|
||||
if(FileAccess & PlatformAccess_Write)
|
||||
{
|
||||
DesiredAccess |= GENERIC_WRITE;
|
||||
}
|
||||
|
||||
DWORD CreationAttributes = 0;
|
||||
if(FileAccess & PlatformAccess_Read)
|
||||
{
|
||||
CreationAttributes = OPEN_EXISTING;
|
||||
}
|
||||
|
||||
string FullPath = Path;
|
||||
|
||||
HANDLE File = CreateFileA((char *)Path.Data, DesiredAccess, 0, 0, CreationAttributes, 0, 0);
|
||||
|
||||
platform_file_handle Result = {};
|
||||
Result.Platform = (u64)File;
|
||||
Result.IsValid = (File != INVALID_HANDLE_VALUE);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static PLATFORM_CLOSE_FILE(Win32_CloseFile)
|
||||
{
|
||||
HANDLE File = (HANDLE)Handle.Platform;
|
||||
if(File != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(File);
|
||||
}
|
||||
}
|
||||
|
||||
static PLATFORM_READ_FILE(Win32_ReadFile)
|
||||
{
|
||||
HANDLE File = (HANDLE)Handle.Platform;
|
||||
if(File != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD BytesRead;
|
||||
ReadFile(File, Dest, Size, &BytesRead, 0);
|
||||
|
||||
Assert(BytesRead == Size);
|
||||
}
|
||||
}
|
||||
|
||||
static PLATFORM_GET_FILE_SIZE(Win32_GetFileSize)
|
||||
{
|
||||
u64 Result = 0;
|
||||
|
||||
HANDLE File = (HANDLE)Handle.Platform;
|
||||
if(File != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LARGE_INTEGER FileSize;
|
||||
GetFileSizeEx(File, &FileSize);
|
||||
|
||||
Result = FileSize.QuadPart;
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static PLATFORM_SET_CURSOR(Win32_SetCursor)
|
||||
{
|
||||
Global_Win32State.Cursor = Cursor;
|
||||
}
|
||||
|
||||
inline u64 Win32_GetWallClock(void)
|
||||
{
|
||||
LARGE_INTEGER Query;
|
||||
QueryPerformanceCounter(&Query);
|
||||
|
||||
u64 Result = Query.QuadPart;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline r64 Win32_GetSecondsElapsed(u64 Start, u64 End)
|
||||
{
|
||||
u64 Elapsed = End - Start;
|
||||
|
||||
r64 Result = (r64)Elapsed/(r64)Global_Win32State.PerformanceFrequency;
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline FILETIME Win32_GetLastWriteTime(char *Path)
|
||||
{
|
||||
FILETIME Result = {};
|
||||
|
||||
HANDLE File = CreateFileA(Path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
if(File)
|
||||
{
|
||||
FILETIME Creation, LastAccess, LastWrite;
|
||||
GetFileTime(File, &Creation, &LastAccess, &LastWrite);
|
||||
|
||||
Result = LastWrite;
|
||||
|
||||
CloseHandle(File);
|
||||
}
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static win32_loaded_code Win32_LoadCode(void)
|
||||
{
|
||||
win32_loaded_code Code = {};
|
||||
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
if(CopyFile(State->DLLPath, State->TempDLLPath, FALSE))
|
||||
{
|
||||
Code.LastWriteTime = Win32_GetLastWriteTime(State->DLLPath);
|
||||
|
||||
Code.DLL = LoadLibraryA(State->TempDLLPath);
|
||||
if(Code.DLL)
|
||||
{
|
||||
Code.UpdateAndRender = (vn_update_and_render *)GetProcAddress(Code.DLL, "VN_UpdateAndRender");
|
||||
if(Code.UpdateAndRender)
|
||||
{
|
||||
Code.IsValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(Code);
|
||||
}
|
||||
|
||||
static void Win32_UnloadCode(win32_loaded_code *Code)
|
||||
{
|
||||
if(Code->DLL)
|
||||
{
|
||||
FreeLibrary(Code->DLL);
|
||||
}
|
||||
|
||||
*Code = {};
|
||||
}
|
||||
|
||||
static void Win32_UpdateCode(win32_loaded_code *Code)
|
||||
{
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
FILETIME LastWriteTime = Win32_GetLastWriteTime(State->DLLPath);
|
||||
if(CompareFileTime(&Code->LastWriteTime, &LastWriteTime) != 0)
|
||||
{
|
||||
Win32_UnloadCode(Code);
|
||||
*Code = Win32_LoadCode();
|
||||
}
|
||||
}
|
||||
|
||||
static PLATFORM_TOGGLE_FULLSCREEN(Win32_ToggleFullscreen)
|
||||
{
|
||||
HWND Window = Global_Win32State.Window;
|
||||
|
||||
DWORD Style = GetWindowLong(Window, GWL_STYLE);
|
||||
if(Style & WS_OVERLAPPEDWINDOW)
|
||||
{
|
||||
MONITORINFO MonitorInfo = {sizeof(MonitorInfo)};
|
||||
if(GetWindowPlacement(Window, &Global_WindowPosition) &&
|
||||
GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo))
|
||||
{
|
||||
SetWindowPos(Window, HWND_TOP,
|
||||
MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
|
||||
MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left,
|
||||
MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowPlacement(Window, &Global_WindowPosition);
|
||||
SetWindowPos(Window, 0, 0, 0, 0, 0,
|
||||
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_FRAMECHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
inline v2 Win32_GetMouseP(HWND Window)
|
||||
{
|
||||
POINT Point;
|
||||
GetCursorPos(&Point);
|
||||
ScreenToClient(Window, &Point);
|
||||
|
||||
v2 Result = V2(Point.x, Point.y);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline v2 Win32_GetWindowDim(HWND Window)
|
||||
{
|
||||
RECT ClientRect;
|
||||
GetClientRect(Window, &ClientRect);
|
||||
|
||||
v2 Result = V2(ClientRect.right - ClientRect.left, ClientRect.bottom - ClientRect.top);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
inline platform_modifiers Win32_GetModifiers(void)
|
||||
{
|
||||
platform_modifiers Modifiers = 0;
|
||||
|
||||
if(GetKeyState(VK_CONTROL) & 0x8000)
|
||||
{
|
||||
Modifiers |= PlatformModifier_Ctrl;
|
||||
}
|
||||
if(GetKeyState(VK_SHIFT) & 0x8000)
|
||||
{
|
||||
Modifiers |= PlatformModifier_Shift;
|
||||
}
|
||||
if(GetKeyState(VK_MENU) & 0x8000)
|
||||
{
|
||||
Modifiers |= PlatformModifier_Alt;
|
||||
}
|
||||
|
||||
return(Modifiers);
|
||||
}
|
||||
|
||||
static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
|
||||
{
|
||||
LRESULT Result = 0;
|
||||
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
temporary_memory Scratch = GetScratch(0, 0);
|
||||
|
||||
platform_event *Event = 0;
|
||||
|
||||
b32 ButtonIsUp = false;
|
||||
axis2 ScrollAxis = Axis2_Y;
|
||||
|
||||
switch(Message)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
{
|
||||
Global_Running = false;
|
||||
} break;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
// TODO(casey): For now, we are setting the window styles in here
|
||||
// because sometimes Windows can reposition our window out of fullscreen
|
||||
// without going through our ToggleFullscreen(), and we want to put our
|
||||
// title bar and border back when it does!
|
||||
|
||||
WINDOWPOS *NewPos = (WINDOWPOS *)LParam;
|
||||
|
||||
b32 BecomingFullscreen = false;
|
||||
MONITORINFO MonitorInfo = {sizeof(MonitorInfo)};
|
||||
if(GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY),
|
||||
&MonitorInfo))
|
||||
{
|
||||
s32 MonWidth = (MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left);
|
||||
s32 MonHeight = (MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top);
|
||||
BecomingFullscreen = ((MonitorInfo.rcMonitor.left == NewPos->x) &&
|
||||
(MonitorInfo.rcMonitor.top == NewPos->y) &&
|
||||
(MonWidth == NewPos->cx) &&
|
||||
(MonHeight == NewPos->cy));
|
||||
}
|
||||
|
||||
DWORD OldStyle = GetWindowLong(Window, GWL_STYLE);
|
||||
DWORD FullscreenStyle = OldStyle & ~WS_OVERLAPPEDWINDOW;
|
||||
DWORD WindowedStyle = OldStyle | WS_OVERLAPPEDWINDOW;
|
||||
DWORD NewStyle = (BecomingFullscreen) ? FullscreenStyle : WindowedStyle;
|
||||
|
||||
if(NewStyle != OldStyle)
|
||||
{
|
||||
SetWindowLong(Window, GWL_STYLE, NewStyle);
|
||||
}
|
||||
|
||||
Result = DefWindowProcA(Window, Message, WParam, LParam);
|
||||
} break;
|
||||
|
||||
case WM_MOUSEHWHEEL:
|
||||
{
|
||||
ScrollAxis = Axis2_X;
|
||||
} fallthrough;
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
Event = PushStruct(&State->EventArena, platform_event);
|
||||
Event->Type = PlatformEvent_MouseScroll;
|
||||
Event->Scroll.E[ScrollAxis] = GET_WHEEL_DELTA_WPARAM(WParam) / 120.0;
|
||||
} break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
ButtonIsUp = true;
|
||||
} fallthrough;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
{
|
||||
platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press;
|
||||
|
||||
platform_key Key = Key_Invalid;
|
||||
switch(Message)
|
||||
{
|
||||
case WM_LBUTTONUP: case WM_LBUTTONDOWN: { Key = Key_MouseLeft; } break;
|
||||
case WM_MBUTTONUP: case WM_MBUTTONDOWN: { Key = Key_MouseMiddle; } break;
|
||||
case WM_RBUTTONUP: case WM_RBUTTONDOWN: { Key = Key_MouseRight; } break;
|
||||
}
|
||||
|
||||
Event = PushStruct(&State->EventArena, platform_event);
|
||||
Event->Type = Type;
|
||||
Event->Key = Key;
|
||||
Event->P = Win32_GetMouseP(Window);
|
||||
} break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYUP:
|
||||
{
|
||||
ButtonIsUp = true;
|
||||
} fallthrough;
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
platform_event_type Type = ButtonIsUp ? PlatformEvent_Release : PlatformEvent_Press;
|
||||
|
||||
u32 VKCode = (u32)WParam;
|
||||
platform_key Key = Key_Invalid;
|
||||
|
||||
if(VKCode >= 'A' && VKCode <= 'Z')
|
||||
{
|
||||
Key = (platform_key)(Key_A + (VKCode - 'A'));
|
||||
}
|
||||
else if(VKCode >= VK_F1 && VKCode <= VK_F12)
|
||||
{
|
||||
Key = (platform_key)(Key_F1 + (VKCode - VK_F1));
|
||||
}
|
||||
else if(VKCode == VK_LEFT) { Key = Key_Left; }
|
||||
else if(VKCode == VK_RIGHT) { Key = Key_Right; }
|
||||
else if(VKCode == VK_UP) { Key = Key_Up; }
|
||||
else if(VKCode == VK_DOWN) { Key = Key_Down; }
|
||||
else if(VKCode == VK_SPACE) { Key = Key_Space; }
|
||||
else if(VKCode == VK_PRIOR) { Key = Key_PageUp; }
|
||||
else if(VKCode == VK_NEXT) { Key = Key_PageDown; }
|
||||
else if(VKCode == VK_HOME) { Key = Key_Home; }
|
||||
else if(VKCode == VK_END) { Key = Key_End; }
|
||||
else if(VKCode == VK_BACK) { Key = Key_Backspace; }
|
||||
else if(VKCode == VK_DELETE) { Key = Key_Delete; }
|
||||
|
||||
if(Key != Key_Invalid)
|
||||
{
|
||||
Event = PushStruct(&State->EventArena, platform_event);
|
||||
Event->Type = Type;
|
||||
Event->Key = Key;
|
||||
}
|
||||
|
||||
if(!ButtonIsUp && (VKCode == VK_RETURN) && (LParam & (1 << 29)))
|
||||
{
|
||||
Win32_ToggleFullscreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = DefWindowProc(Window, Message, WParam, LParam);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case WM_CHAR:
|
||||
{
|
||||
u32 Codepoint = (u32)WParam;
|
||||
if(Codepoint == '\r')
|
||||
{
|
||||
Codepoint = '\n';
|
||||
}
|
||||
|
||||
if((Codepoint >= 32 && Codepoint != 127) || Codepoint == '\t' || Codepoint == '\n')
|
||||
{
|
||||
Event = PushStruct(&State->EventArena, platform_event);
|
||||
Event->Type = PlatformEvent_Text;
|
||||
Event->Codepoint = Codepoint;
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
range2_r32 WindowRect = {};
|
||||
WindowRect.Max = Win32_GetWindowDim(Window);
|
||||
if(InRange(WindowRect, Win32_GetMouseP(Window)))
|
||||
{
|
||||
persist HCURSOR CursorTable[PlatformCursor_Count];
|
||||
persist b32 CursorTableLoaded = false;
|
||||
if(!CursorTableLoaded)
|
||||
{
|
||||
CursorTable[PlatformCursor_Arrow] = LoadCursor(0, IDC_ARROW);
|
||||
CursorTable[PlatformCursor_Cross] = LoadCursor(0, IDC_CROSS);
|
||||
CursorTable[PlatformCursor_Hand] = LoadCursor(0, IDC_HAND);
|
||||
CursorTable[PlatformCursor_Help] = LoadCursor(0, IDC_HELP);
|
||||
CursorTable[PlatformCursor_IBeam] = LoadCursor(0, IDC_IBEAM);
|
||||
CursorTable[PlatformCursor_SlashedCircle] = LoadCursor(0, IDC_NO);
|
||||
CursorTable[PlatformCursor_ArrowAll] = LoadCursor(0, IDC_SIZEALL);
|
||||
CursorTable[PlatformCursor_ArrowNESW] = LoadCursor(0, IDC_SIZENESW);
|
||||
CursorTable[PlatformCursor_ArrowVertical] = LoadCursor(0, IDC_SIZENS);
|
||||
CursorTable[PlatformCursor_ArrowNWSE] = LoadCursor(0, IDC_SIZENWSE);
|
||||
CursorTable[PlatformCursor_ArrowHorizontal] = LoadCursor(0, IDC_SIZEWE);
|
||||
CursorTable[PlatformCursor_Wait] = LoadCursor(0, IDC_WAIT);
|
||||
|
||||
CursorTableLoaded = true;
|
||||
}
|
||||
|
||||
SetCursor(CursorTable[Global_Win32State.Cursor]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefWindowProc(Window, Message, WParam, LParam);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
Result = DefWindowProc(Window, Message, WParam, LParam);
|
||||
} break;
|
||||
}
|
||||
|
||||
if(Event)
|
||||
{
|
||||
Event->Modifiers = Win32_GetModifiers();
|
||||
DLLInsertLast(State->EventList.First, State->EventList.Last, Event);
|
||||
}
|
||||
|
||||
ReleaseScratch(Scratch);
|
||||
|
||||
return(Result);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
MSG Message;
|
||||
while(PeekMessage(&Message, Window, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&Message);
|
||||
DispatchMessageA(&Message);
|
||||
}
|
||||
|
||||
Input->EventList = &State->EventList;
|
||||
|
||||
v2 NewMouseP = Win32_GetMouseP(Window);
|
||||
v2 OldMouseP = Input->MouseP;
|
||||
|
||||
Input->dMouseP = NewMouseP - OldMouseP;
|
||||
Input->MouseP = NewMouseP;
|
||||
|
||||
Input->dtForFrame = dtForFrame;
|
||||
}
|
||||
|
||||
static void Win32_EnforceFrameRate(u64 FrameBegin, r32 TargetFrameRate)
|
||||
{
|
||||
win32_state *State = &Global_Win32State;
|
||||
|
||||
r64 TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock());
|
||||
r64 Target = 1.0 / TargetFrameRate;
|
||||
|
||||
r64 ToSleep = Target - TimeElapsed;
|
||||
if(ToSleep > 0)
|
||||
{
|
||||
u64 MSToSleep = (u64)Floor(ToSleep*1000);
|
||||
if(State->SleepIsGranular)
|
||||
{
|
||||
Sleep(MSToSleep);
|
||||
}
|
||||
|
||||
while(ToSleep > 0)
|
||||
{
|
||||
TimeElapsed = Win32_GetSecondsElapsed(FrameBegin, Win32_GetWallClock());
|
||||
ToSleep = Target - TimeElapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Win32_GetRelevantPaths(win32_state *State)
|
||||
{
|
||||
GetModuleFileName(0, State->EXEPath, ArrayCount(State->EXEPath));
|
||||
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
Win32_PlatformError("Path to executable is too long. Try running the game from another directory", true);
|
||||
}
|
||||
|
||||
s64 OnePastLastSlash = LastIndexOf(MakeStringFromCString(State->EXEPath), '\\') + 1;
|
||||
|
||||
string DLLName = StrLit("vn.dll");
|
||||
Copy(State->DLLPath, State->EXEPath, OnePastLastSlash);
|
||||
Copy(State->DLLPath+OnePastLastSlash, DLLName.Data, DLLName.Count);
|
||||
|
||||
string TempDLLName = StrLit("temp_vn.dll");
|
||||
Copy(State->TempDLLPath, State->EXEPath, OnePastLastSlash);
|
||||
Copy(State->TempDLLPath+OnePastLastSlash, TempDLLName.Data, TempDLLName.Count);
|
||||
}
|
||||
|
||||
int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, int ShowCommand)
|
||||
{
|
||||
thread_context ThreadContext = {};
|
||||
SetThreadContext(&ThreadContext);
|
||||
|
||||
// sixten: Setup Win32 platform state.
|
||||
{
|
||||
win32_state *State = &Global_Win32State;
|
||||
Win32_GetRelevantPaths(State);
|
||||
|
||||
LARGE_INTEGER FrequencyQuery;
|
||||
QueryPerformanceFrequency(&FrequencyQuery);
|
||||
State->PerformanceFrequency = FrequencyQuery.QuadPart;
|
||||
|
||||
State->MemorySentinel.Next = &State->MemorySentinel;
|
||||
State->MemorySentinel.Prev = &State->MemorySentinel;
|
||||
|
||||
State->SleepIsGranular = (timeBeginPeriod(1) != TIMERR_NOERROR);
|
||||
}
|
||||
|
||||
// sixten: Setup platform layer
|
||||
{
|
||||
Platform.AllocateMemory = Win32_AllocateMemory;
|
||||
Platform.DeallocateMemory = Win32_DeallocateMemory;
|
||||
Platform.OpenFile = Win32_OpenFile;
|
||||
Platform.CloseFile = Win32_CloseFile;
|
||||
Platform.ReadFile = Win32_ReadFile;
|
||||
Platform.GetFileSize = Win32_GetFileSize;
|
||||
Platform.SetCursor = Win32_SetCursor;
|
||||
Platform.ToggleFullscreen = Win32_ToggleFullscreen;
|
||||
}
|
||||
|
||||
WNDCLASS WindowClass = {};
|
||||
WindowClass.lpszClassName = "vn-window-class";
|
||||
WindowClass.lpfnWndProc = Win32_WindowCallback;
|
||||
WindowClass.hCursor = LoadCursorA(0, IDC_ARROW);
|
||||
WindowClass.style = CS_OWNDC;
|
||||
|
||||
if(RegisterClassA(&WindowClass))
|
||||
{
|
||||
HWND Window = CreateWindowEx(0,
|
||||
WindowClass.lpszClassName,
|
||||
"vn - June 2023 Build",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
0, 0, Instance, 0);
|
||||
if(Window)
|
||||
{
|
||||
Global_Win32State.Window = Window;
|
||||
|
||||
vn_input Input = {};
|
||||
|
||||
// sixten: Setup OpenGL
|
||||
vn_render_commands RenderCommands = {};
|
||||
HDC DeviceContext = GetDC(Window);
|
||||
Win32_CreateOpenGLContext(DeviceContext);
|
||||
opengl_context OpenGLContext = OpenGL_SetupContext(&RenderCommands, 16*1024);
|
||||
|
||||
vn_memory Memory = {};
|
||||
Memory.PlatformAPI = Platform;
|
||||
|
||||
win32_loaded_code LoadedCode = Win32_LoadCode();
|
||||
|
||||
ShowWindow(Window, SW_SHOWNORMAL);
|
||||
|
||||
u64 CurrentTime = Win32_GetWallClock();
|
||||
|
||||
Global_Running = true;
|
||||
while(Global_Running)
|
||||
{
|
||||
u64 NewTime = Win32_GetWallClock();
|
||||
r64 dtForFrame = Win32_GetSecondsElapsed(CurrentTime, NewTime);
|
||||
CurrentTime = NewTime;
|
||||
|
||||
Win32_ProcessInput(&Input, Window, dtForFrame);
|
||||
|
||||
Win32_SetCursor(PlatformCursor_Arrow);
|
||||
|
||||
// sixten: Update and render frame.
|
||||
{
|
||||
Win32_UpdateCode(&LoadedCode);
|
||||
|
||||
OpenGL_BeginFrame(&RenderCommands, Win32_GetWindowDim(Window));
|
||||
|
||||
if(LoadedCode.IsValid)
|
||||
{
|
||||
LoadedCode.UpdateAndRender(&ThreadContext, &Memory, &Input, &RenderCommands);
|
||||
}
|
||||
|
||||
OpenGL_EndFrame(&OpenGLContext, &RenderCommands);
|
||||
wglSwapLayerBuffers(DeviceContext, WGL_SWAP_MAIN_PLANE);
|
||||
}
|
||||
|
||||
Win32_EnforceFrameRate(CurrentTime, 144.0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Win32_PlatformError("Unable to create window.", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Win32_PlatformError("Unable to register window class.", true);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* date = May 7th 2023 9:54 am */
|
||||
|
||||
#ifndef WIN32_MAIN_H
|
||||
#define WIN32_MAIN_H
|
||||
|
||||
struct win32_memory_block
|
||||
{
|
||||
platform_memory_block Block;
|
||||
win32_memory_block *Next;
|
||||
win32_memory_block *Prev;
|
||||
u64 Padding[2];
|
||||
};
|
||||
|
||||
CTAssert(sizeof(win32_memory_block) == 64);
|
||||
|
||||
struct win32_state
|
||||
{
|
||||
win32_memory_block MemorySentinel;
|
||||
ticket_mutex MemoryMutex;
|
||||
|
||||
u64 PerformanceFrequency;
|
||||
b32 SleepIsGranular;
|
||||
|
||||
HWND Window;
|
||||
|
||||
memory_arena EventArena;
|
||||
temporary_memory EventArenaTemp;
|
||||
platform_event_list EventList;
|
||||
|
||||
char EXEPath[512];
|
||||
char DLLPath[512];
|
||||
char TempDLLPath[512];
|
||||
|
||||
platform_cursor Cursor;
|
||||
};
|
||||
|
||||
struct win32_loaded_code
|
||||
{
|
||||
HMODULE DLL;
|
||||
FILETIME LastWriteTime;
|
||||
|
||||
vn_update_and_render *UpdateAndRender;
|
||||
|
||||
b32 IsValid;
|
||||
};
|
||||
|
||||
#endif //WIN32_MAIN_H
|
|
@ -0,0 +1,120 @@
|
|||
inline void *OpenGL_LoadFunction(char *Name)
|
||||
{
|
||||
void *Result = (void *)wglGetProcAddress(Name);
|
||||
if((Result == 0) || (Result == (void *)1) || (Result == (void *)2) || (Result == (void *)3))
|
||||
{
|
||||
HMODULE Module = LoadLibraryA("opengl32.dll");
|
||||
Result = (void *)GetProcAddress(Module, Name);
|
||||
}
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void *OpenGL_AllocateMemory(umm Size)
|
||||
{
|
||||
void *Result = VirtualAlloc(0, Size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
static void OpenGL_DeallocateMemory(void *Memory)
|
||||
{
|
||||
VirtualFree(Memory, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
||||
#define WGL_SAMPLES_ARB 0x2042
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
|
||||
typedef BOOL wgl_choose_pixel_format_arb(HDC hdc,
|
||||
const int *piAttribIList,
|
||||
const FLOAT *pfAttribFList,
|
||||
UINT nMaxFormats,
|
||||
int *piFormats,
|
||||
UINT *nNumFormats);
|
||||
|
||||
typedef HGLRC wgl_create_context_attribs_arb(HDC hDC, HGLRC hShareContext,
|
||||
const int *attribList);
|
||||
|
||||
typedef BOOL wgl_make_context_current_arb(HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
|
||||
|
||||
typedef BOOL wgl_swap_interval_ext(int interval);
|
||||
|
||||
static wgl_choose_pixel_format_arb *wglChoosePixelFormatARB;
|
||||
static wgl_create_context_attribs_arb *wglCreateContextAttribsARB;
|
||||
static wgl_make_context_current_arb *wglMakeContextCurrentARB;
|
||||
static wgl_swap_interval_ext *wglSwapIntervalEXT;
|
||||
|
||||
#include "opengl_render.h"
|
||||
#include "opengl_render.cpp"
|
||||
|
||||
static void Win32_CreateOpenGLContext(HDC DeviceContext)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR PixelFormatDesc = {};
|
||||
PixelFormatDesc.nSize = sizeof(PixelFormatDesc);
|
||||
PixelFormatDesc.nVersion = 1;
|
||||
PixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
|
||||
PixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
|
||||
PixelFormatDesc.cColorBits = 32;
|
||||
PixelFormatDesc.cDepthBits = 24;
|
||||
PixelFormatDesc.cStencilBits = 8;
|
||||
PixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
int PixelFormat = ChoosePixelFormat(DeviceContext, &PixelFormatDesc);
|
||||
Assert(PixelFormat);
|
||||
|
||||
SetPixelFormat(DeviceContext, PixelFormat, &PixelFormatDesc);
|
||||
|
||||
HGLRC DummyContext = wglCreateContext(DeviceContext);
|
||||
wglMakeCurrent(DeviceContext, DummyContext);
|
||||
|
||||
wglChoosePixelFormatARB = (wgl_choose_pixel_format_arb *)OpenGL_LoadFunction("wglChoosePixelFormatARB");
|
||||
wglCreateContextAttribsARB = (wgl_create_context_attribs_arb *)OpenGL_LoadFunction("wglCreateContextAttribsARB");
|
||||
wglMakeContextCurrentARB = (wgl_make_context_current_arb *)OpenGL_LoadFunction("wglMakeContextCurrentARB");
|
||||
wglSwapIntervalEXT = (wgl_swap_interval_ext *)OpenGL_LoadFunction("wglSwapIntervalEXT");
|
||||
|
||||
int AttribList[] =
|
||||
{
|
||||
WGL_DRAW_TO_WINDOW_ARB, 1,
|
||||
WGL_SUPPORT_OPENGL_ARB, 1,
|
||||
WGL_DOUBLE_BUFFER_ARB, 1,
|
||||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
||||
WGL_COLOR_BITS_ARB, 32,
|
||||
WGL_DEPTH_BITS_ARB, 24,
|
||||
WGL_STENCIL_BITS_ARB, 8,
|
||||
WGL_SAMPLE_BUFFERS_ARB, true,
|
||||
WGL_SAMPLES_ARB, 16,
|
||||
0
|
||||
};
|
||||
|
||||
UINT NumFormats;
|
||||
wglChoosePixelFormatARB(DeviceContext, AttribList, 0, 1, &PixelFormat, &NumFormats);
|
||||
|
||||
int ContextAttribs[] =
|
||||
{
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
0
|
||||
};
|
||||
|
||||
HGLRC RenderContext = wglCreateContextAttribsARB(DeviceContext, DummyContext, ContextAttribs);
|
||||
|
||||
wglMakeCurrent(DeviceContext, RenderContext);
|
||||
wglDeleteContext(DummyContext);
|
||||
wglSwapIntervalEXT(1);
|
||||
|
||||
OpenGL_LoadAllFunctions();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
vn - release 1
|
||||
--------------
|
||||
|
||||
Right, so we need to have some tools to make a visual novel. In lieu of actual GOOD tools, we will deal with subpar ones instead. Thusly, this first release will only include the bearest tools to get you started, but it should be enough for some basic (text only) scenes.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,73 @@
|
|||
version(1);
|
||||
|
||||
project_name = "vn";
|
||||
|
||||
patterns =
|
||||
{
|
||||
"*.c",
|
||||
"*.cpp",
|
||||
"*.jai",
|
||||
"*.odin",
|
||||
"*.zig",
|
||||
"*.h",
|
||||
"*.inc",
|
||||
"*.bat",
|
||||
"*.sh",
|
||||
"*.4coder",
|
||||
"*.txt",
|
||||
};
|
||||
|
||||
blacklist_patterns =
|
||||
{
|
||||
".*",
|
||||
};
|
||||
|
||||
load_paths =
|
||||
{
|
||||
{
|
||||
{ {"."}, .recursive = true, .relative = true }, .os = "win"
|
||||
},
|
||||
};
|
||||
|
||||
command_list =
|
||||
{
|
||||
{
|
||||
.name = "build",
|
||||
.out = "*compilation*",
|
||||
.footer_panel = true,
|
||||
.save_dirty_files = true,
|
||||
.cursor_at_end = false,
|
||||
.cmd =
|
||||
{
|
||||
{ "build.bat", .os = "win" },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
.name = "run",
|
||||
.out = "*compilation*",
|
||||
.footer_panel = true,
|
||||
.save_dirty_files = true,
|
||||
.cursor_at_end = false,
|
||||
.cmd =
|
||||
{
|
||||
{ "build\\win32_main.exe", .os = "win" },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
.name = "cloc",
|
||||
.out = "*compilation*",
|
||||
.footer_panel = true,
|
||||
.save_dirty_files = true,
|
||||
.cursor_at_end = false,
|
||||
.cmd =
|
||||
{
|
||||
{ "cloc ./code/*.*", .os = "win" },
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
fkey_command[2] = "run";
|
||||
fkey_command[3] = "cloc";
|
|
@ -0,0 +1,11 @@
|
|||
This is a list of things that needs doing in a SUGGESTED order.
|
||||
|
||||
* UI
|
||||
- Draggable panels
|
||||
- Fix weird grey draggable arena between panels at the headers.
|
||||
- Settings / Preferences view. (Including saving and loading of these settings/preferences)
|
||||
|
||||
* Rendering
|
||||
- Fix texture clipping
|
||||
- Control over each corner when rounding
|
||||
|
Loading…
Reference in New Issue