Created a hierarchy view
This commit is contained in:
parent
b83d718d37
commit
d9af0c6a36
|
@ -74,6 +74,8 @@ v2 FooterMin = PanelMin;
|
||||||
v2 PanelViewMax = PanelMax;
|
v2 PanelViewMax = PanelMax;
|
||||||
|
|
||||||
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
|
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
|
||||||
|
|
||||||
|
|
||||||
Definition.Render(*Panel, PanelMin, PanelMax, RenderBuffer, State, Context, Mouse);
|
Definition.Render(*Panel, PanelMin, PanelMax, RenderBuffer, State, Context, Mouse);
|
||||||
|
|
||||||
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
||||||
|
@ -136,55 +138,6 @@ SACNSendDMXBufferListJob (s32 ThreadID, void* JobData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
LoadAssembly (app_state* State, context Context, char* Path)
|
|
||||||
{
|
|
||||||
platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path);
|
|
||||||
Assert(TestAssemblyFile.Size > 0);
|
|
||||||
|
|
||||||
assembly_definition AssemblyDefinition = ParseAssemblyFile(TestAssemblyFile.Base, TestAssemblyFile.Size, &State->Transient);
|
|
||||||
|
|
||||||
Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size);
|
|
||||||
|
|
||||||
string PathString = MakeStringLiteral(Path);
|
|
||||||
s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\');
|
|
||||||
string FileName = Substring(PathString, IndexOfLastSlash + 1);
|
|
||||||
|
|
||||||
r32 Scale = 100;
|
|
||||||
memory_arena AssemblyArena = {};
|
|
||||||
AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
|
|
||||||
AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
|
|
||||||
|
|
||||||
assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition,
|
|
||||||
FileName,
|
|
||||||
v3{0, 0, 0},
|
|
||||||
Scale,
|
|
||||||
AssemblyArena);
|
|
||||||
array_entry_handle NewAssemblyHandle = PushElement(NewAssembly, &State->AssemblyList);
|
|
||||||
PushElement(NewAssemblyHandle, &State->ActiveAssemblyIndecies);
|
|
||||||
|
|
||||||
State->TotalLEDsCount += NewAssembly.LEDCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context)
|
|
||||||
{
|
|
||||||
assembly* Assembly = GetElementAtIndex(AssemblyIndex, State->AssemblyList);
|
|
||||||
State->TotalLEDsCount -= Assembly->LEDCount;
|
|
||||||
FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree);
|
|
||||||
|
|
||||||
RemoveElementAtIndex(AssemblyIndex, &State->AssemblyList);
|
|
||||||
for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
|
|
||||||
{
|
|
||||||
array_entry_handle Handle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
|
||||||
if (Handle.Index == AssemblyIndex)
|
|
||||||
{
|
|
||||||
RemoveElementAtIndex(i, &State->ActiveAssemblyIndecies);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
RELOAD_STATIC_DATA(ReloadStaticData)
|
RELOAD_STATIC_DATA(ReloadStaticData)
|
||||||
|
@ -197,8 +150,6 @@ RELOAD_STATIC_DATA(ReloadStaticData)
|
||||||
|
|
||||||
if (State->DefaultInputCommandRegistry.Size > 0)
|
if (State->DefaultInputCommandRegistry.Size > 0)
|
||||||
{
|
{
|
||||||
RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_MouseLeftButton, Command_Began, KeyCode_Invalid,
|
|
||||||
Begin3DViewMouseRotate);
|
|
||||||
RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_U, Command_Began, KeyCode_Invalid, OpenUniverseView);
|
RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_U, Command_Began, KeyCode_Invalid, OpenUniverseView);
|
||||||
RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_X, Command_Ended, KeyCode_Invalid, DeleteAnimationBlock);
|
RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_X, Command_Ended, KeyCode_Invalid, DeleteAnimationBlock);
|
||||||
}
|
}
|
||||||
|
@ -534,56 +485,6 @@ PushRenderOrthographic(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHe
|
||||||
if (Context.WindowIsVisible)
|
if (Context.WindowIsVisible)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight;
|
|
||||||
|
|
||||||
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
|
|
||||||
m44 ProjectionMatrix = GetCameraPerspectiveProjectionMatrix(State->Camera);
|
|
||||||
|
|
||||||
r32 LEDHalfWidth = .5f;
|
|
||||||
|
|
||||||
PushRenderPerspective(RenderBuffer, 0, 0, Context.WindowWidth / 2, Context.WindowHeight, State->Camera);
|
|
||||||
PushRenderClearScreen(RenderBuffer);
|
|
||||||
|
|
||||||
// TODO(Peter): Pretty sure this isn't working right now
|
|
||||||
m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1));
|
|
||||||
FaceCameraMatrix = FaceCameraMatrix;
|
|
||||||
|
|
||||||
DEBUG_IF(GlobalDebugServices->Interface.RenderSculpture) // DebugServices RenderSculpture Toggle
|
|
||||||
{
|
|
||||||
DEBUG_TRACK_SCOPE(RenderSculpture);
|
|
||||||
|
|
||||||
s32 MaxLEDsPerJob = 2048;
|
|
||||||
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount);
|
|
||||||
|
|
||||||
for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
|
|
||||||
{
|
|
||||||
array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
|
||||||
assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList);
|
|
||||||
s32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDCount, MaxLEDsPerJob);
|
|
||||||
|
|
||||||
for (s32 Job = 0; Job < JobsNeeded; Job++)
|
|
||||||
{
|
|
||||||
draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data);
|
|
||||||
JobData->LEDs = Assembly.LEDs;
|
|
||||||
JobData->Colors = Assembly.Colors;
|
|
||||||
JobData->StartIndex = Job * MaxLEDsPerJob;
|
|
||||||
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDCount);
|
|
||||||
JobData->Batch = &RenderLEDsBatch;
|
|
||||||
JobData->FaceCameraMatrix;
|
|
||||||
JobData->ModelViewMatrix = ModelViewMatrix;
|
|
||||||
JobData->LEDHalfWidth = LEDHalfWidth;
|
|
||||||
|
|
||||||
Context.GeneralWorkQueue->PushWorkOnQueue(
|
|
||||||
Context.GeneralWorkQueue,
|
|
||||||
DrawLEDsInBufferRangeJob,
|
|
||||||
JobData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0);
|
|
||||||
Context.GeneralWorkQueue->ResetWorkQueue(Context.GeneralWorkQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// Interface
|
// Interface
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
|
@ -181,18 +181,10 @@ typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
|
||||||
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
||||||
typedef PANEL_RENDER_PROC(panel_render_proc);
|
typedef PANEL_RENDER_PROC(panel_render_proc);
|
||||||
|
|
||||||
struct panel_definition
|
|
||||||
{
|
|
||||||
char* PanelName;
|
|
||||||
s32 PanelNameLength;
|
|
||||||
panel_init_proc* Init;
|
|
||||||
panel_cleanup_proc* Cleanup;
|
|
||||||
panel_render_proc* Render;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "panels/foldhaus_panel_sculpture_view.h"
|
#include "panels/foldhaus_panel_sculpture_view.h"
|
||||||
#include "panels/foldhaus_panel_profiler.h"
|
#include "panels/foldhaus_panel_profiler.h"
|
||||||
#include "panels/foldhaus_panel_dmx_view.h"
|
#include "panels/foldhaus_panel_dmx_view.h"
|
||||||
#include "panels/foldhaus_panel_animation_timeline.h"
|
#include "panels/foldhaus_panel_animation_timeline.h"
|
||||||
|
#include "panels/foldhaus_panel_hierarchy.h"
|
||||||
|
|
||||||
#include "generated/foldhaus_panels_generated.h"
|
#include "generated/foldhaus_panels_generated.h"
|
||||||
|
|
|
@ -62,3 +62,52 @@ ConstructAssemblyFromDefinition (assembly_definition Definition,
|
||||||
Assert(Assembly.LEDCount == Definition.TotalLEDCount);
|
Assert(Assembly.LEDCount == Definition.TotalLEDCount);
|
||||||
return Assembly;
|
return Assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
LoadAssembly (app_state* State, context Context, char* Path)
|
||||||
|
{
|
||||||
|
platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path);
|
||||||
|
Assert(TestAssemblyFile.Size > 0);
|
||||||
|
|
||||||
|
assembly_definition AssemblyDefinition = ParseAssemblyFile(TestAssemblyFile.Base, TestAssemblyFile.Size, &State->Transient);
|
||||||
|
|
||||||
|
Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size);
|
||||||
|
|
||||||
|
string PathString = MakeStringLiteral(Path);
|
||||||
|
s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\');
|
||||||
|
string FileName = Substring(PathString, IndexOfLastSlash + 1);
|
||||||
|
|
||||||
|
r32 Scale = 100;
|
||||||
|
memory_arena AssemblyArena = {};
|
||||||
|
AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
|
||||||
|
AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
|
||||||
|
|
||||||
|
assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition,
|
||||||
|
FileName,
|
||||||
|
v3{0, 0, 0},
|
||||||
|
Scale,
|
||||||
|
AssemblyArena);
|
||||||
|
array_entry_handle NewAssemblyHandle = PushElement(NewAssembly, &State->AssemblyList);
|
||||||
|
PushElement(NewAssemblyHandle, &State->ActiveAssemblyIndecies);
|
||||||
|
|
||||||
|
State->TotalLEDsCount += NewAssembly.LEDCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context)
|
||||||
|
{
|
||||||
|
assembly* Assembly = GetElementAtIndex(AssemblyIndex, State->AssemblyList);
|
||||||
|
State->TotalLEDsCount -= Assembly->LEDCount;
|
||||||
|
FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree);
|
||||||
|
|
||||||
|
RemoveElementAtIndex(AssemblyIndex, &State->AssemblyList);
|
||||||
|
for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
|
||||||
|
{
|
||||||
|
array_entry_handle Handle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
||||||
|
if (Handle.Index == AssemblyIndex)
|
||||||
|
{
|
||||||
|
RemoveElementAtIndex(i, &State->ActiveAssemblyIndecies);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -290,11 +290,14 @@ DrawPanelOrRecurse(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 Wind
|
||||||
if (Panel->SplitDirection == PanelSplit_NoSplit)
|
if (Panel->SplitDirection == PanelSplit_NoSplit)
|
||||||
{
|
{
|
||||||
RenderPanel(Panel, PanelMin, PanelMax, WindowMin, WindowMax, RenderBuffer, State, Context, Mouse);
|
RenderPanel(Panel, PanelMin, PanelMax, WindowMin, WindowMax, RenderBuffer, State, Context, Mouse);
|
||||||
v4 BorderColor = v4{0, 1, 1, 1};
|
v4 BorderColor = v4{0, 0, 0, 1};
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
||||||
{
|
{
|
||||||
BorderColor = v4{1, 0, 1, 1};
|
BorderColor = v4{1, 0, 1, 1};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
||||||
DrawPanelBorder(*Panel, PanelMin, PanelMax, BorderColor, RenderBuffer);
|
DrawPanelBorder(*Panel, PanelMin, PanelMax, BorderColor, RenderBuffer);
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
global_variable s32 GlobalPanelDefsCount = 4;
|
struct panel_definition
|
||||||
global_variable panel_definition GlobalPanelDefs[] = {
|
{
|
||||||
{ "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render },
|
char* PanelName;
|
||||||
{ "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render },
|
s32 PanelNameLength;
|
||||||
{ "DMX View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render },
|
panel_init_proc* Init;
|
||||||
{ "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render },
|
panel_cleanup_proc* Cleanup;
|
||||||
|
panel_render_proc* Render;
|
||||||
|
input_command* InputCommands;
|
||||||
|
};
|
||||||
|
|
||||||
|
global_variable s32 GlobalPanelDefsCount = 5;
|
||||||
|
global_variable panel_definition GlobalPanelDefs[] = {
|
||||||
|
{ "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands},
|
||||||
|
{ "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render, 0 },
|
||||||
|
{ "DMX View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, 0 },
|
||||||
|
{ "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, 0 },
|
||||||
|
{ "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, 0 },
|
||||||
};
|
};
|
|
@ -1,423 +0,0 @@
|
||||||
#ifndef GS_LANGUAGE_H
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__)
|
|
||||||
#include <windows.h>
|
|
||||||
#include <intrin.h>
|
|
||||||
|
|
||||||
// TODO(Peter): Get rid of stdio and math.h
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#elif defined(__APPLE__) && defined(__MAC__)
|
|
||||||
// TODO(Peter):
|
|
||||||
|
|
||||||
#else // Std lib
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define internal static
|
|
||||||
#define local_persist static
|
|
||||||
#define global_variable static
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(GS_TYPES)
|
|
||||||
|
|
||||||
#define GSINT64(s) (s) ## L
|
|
||||||
#define GSUINT64(s) (s) ## UL
|
|
||||||
|
|
||||||
typedef signed char b8;
|
|
||||||
typedef short int b16;
|
|
||||||
typedef int b32;
|
|
||||||
typedef long long int b64;
|
|
||||||
|
|
||||||
typedef unsigned char u8;
|
|
||||||
typedef unsigned short int u16;
|
|
||||||
typedef unsigned int u32;
|
|
||||||
typedef unsigned long long int u64;
|
|
||||||
|
|
||||||
typedef signed char s8;
|
|
||||||
typedef short int s16;
|
|
||||||
typedef int s32;
|
|
||||||
typedef long long int s64;
|
|
||||||
|
|
||||||
typedef float r32;
|
|
||||||
typedef double r64;
|
|
||||||
|
|
||||||
#define INT8_MIN (-128)
|
|
||||||
#define INT16_MIN (-32767-1)
|
|
||||||
#define INT32_MIN (-2147483647-1)
|
|
||||||
#define INT64_MIN (-GSINT64(9223372036854775807)-1)
|
|
||||||
|
|
||||||
#define INT8_MAX (127)
|
|
||||||
#define INT16_MAX (32767)
|
|
||||||
#define INT32_MAX (2147483647)
|
|
||||||
#define INT64_MAX (GSINT64(9223372036854775807))
|
|
||||||
|
|
||||||
#define UINT8_MAX (255)
|
|
||||||
#define UINT16_MAX (65535)
|
|
||||||
#define UINT32_MAX (4294967295U)
|
|
||||||
#define UINT64_MAX (GSUINT64(18446744073709551615))
|
|
||||||
|
|
||||||
#define FLOAT_MIN (1.175494351e-38F)
|
|
||||||
#define FLOAT_MAX (3.402823466e+38F)
|
|
||||||
#define DOUBLE_MIN (2.2250738585072014e-308)
|
|
||||||
#define DOUBLE_MAX (1.7976931348623158e+308)
|
|
||||||
|
|
||||||
#define Kilobytes(Value) ((Value) * 1024)
|
|
||||||
#define Megabytes(Value) (Kilobytes(Value) * 1024)
|
|
||||||
#define Gigabytes(Value) (Megabytes(Value) * 1024)
|
|
||||||
#define Terabytes(Value) (Gigabytes(Value) * 1024)
|
|
||||||
|
|
||||||
#define PI 3.14159265359
|
|
||||||
#define PI_OVER_180 0.01745329251f
|
|
||||||
|
|
||||||
#define GS_TYPES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
|
|
||||||
static void DebugPrint(char* Format, ...);
|
|
||||||
|
|
||||||
#if !defined(Assert)
|
|
||||||
// NOTE(peter): this writes to address 0 which is always illegal and will cause a crash
|
|
||||||
#define Assert(expression) if(!(expression)){ *((int *)0) = 5; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEBUG_IF(condition) if (condition)
|
|
||||||
|
|
||||||
#define InvalidCodePath Assert(0)
|
|
||||||
#define InvalidDefaultCase default: { Assert(0); }
|
|
||||||
#define DebugBreak __debugbreak()
|
|
||||||
|
|
||||||
#define STBI_ASSERT(x) Assert(x)
|
|
||||||
|
|
||||||
#ifdef GS_TEST_SUTE
|
|
||||||
#define TestClean(v, c) SuccessCount += Test(v, c, &TestCount)
|
|
||||||
internal s32
|
|
||||||
Test(b32 Result, char* Description, s32* Count)
|
|
||||||
{
|
|
||||||
char* Passed = (Result ? "Success" : "Failed");
|
|
||||||
if (!Result)
|
|
||||||
DebugPrint("%s:\n................................................%s\n\n", Description, Passed);
|
|
||||||
|
|
||||||
*Count = *Count + 1;
|
|
||||||
return (Result ? 1 : 0);
|
|
||||||
}
|
|
||||||
#endif // GS_TEST_SUTE
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define Assert(expression)
|
|
||||||
#define InvalidCodePath
|
|
||||||
#define DEBUG_IF(condition)
|
|
||||||
|
|
||||||
//#define DEBUG_TRACK_SCOPE(a)
|
|
||||||
|
|
||||||
#endif // DEBUG
|
|
||||||
|
|
||||||
#ifndef GS_LANGUAGE_MATH
|
|
||||||
|
|
||||||
#define GSZeroStruct(data) GSZeroMemory_((u8*)(&(data)), sizeof(data))
|
|
||||||
#define GSZeroMemory(mem, size) GSZeroMemory_((u8*)(mem), (size))
|
|
||||||
static void
|
|
||||||
GSZeroMemory_ (u8* Memory, s32 Size)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Size; i++) { Memory[i] = 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GSMemCopy(from, to, size) GSMemCopy_((u8*)from, (u8*)to, size)
|
|
||||||
static void
|
|
||||||
GSMemCopy_ (u8* From, u8* To, s32 Size)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Size; i++) { To[i] = From[i]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GSMemSet(buffer, value, size) GSMemSet_((u8*)buffer, value, size)
|
|
||||||
internal void
|
|
||||||
GSMemSet_ (u8* Buffer, u8 Value, s32 Length)
|
|
||||||
{
|
|
||||||
u8* Cursor = Buffer;
|
|
||||||
for (s32 i = 0; i < Length; i++)
|
|
||||||
{
|
|
||||||
*Cursor++ = Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GSMinDef(type) static type GSMin(type A, type B) { return (A < B ? A : B); }
|
|
||||||
GSMinDef(s8)
|
|
||||||
GSMinDef(s16)
|
|
||||||
GSMinDef(s32)
|
|
||||||
GSMinDef(s64)
|
|
||||||
GSMinDef(u8)
|
|
||||||
GSMinDef(u16)
|
|
||||||
GSMinDef(u32)
|
|
||||||
GSMinDef(u64)
|
|
||||||
GSMinDef(r32)
|
|
||||||
GSMinDef(r64)
|
|
||||||
#undef GSMinDef
|
|
||||||
|
|
||||||
#define GSMaxDef(type) static type GSMax(type A, type B) { return (A > B ? A : B); }
|
|
||||||
GSMaxDef(s8)
|
|
||||||
GSMaxDef(s16)
|
|
||||||
GSMaxDef(s32)
|
|
||||||
GSMaxDef(s64)
|
|
||||||
GSMaxDef(u8)
|
|
||||||
GSMaxDef(u16)
|
|
||||||
GSMaxDef(u32)
|
|
||||||
GSMaxDef(u64)
|
|
||||||
GSMaxDef(r32)
|
|
||||||
GSMaxDef(r64)
|
|
||||||
#undef GSMaxDef
|
|
||||||
|
|
||||||
inline b32 XOR(b32 A, b32 B)
|
|
||||||
{
|
|
||||||
b32 Result = (A == !B);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
#define GSClampDef(type) static type GSClamp(type Min, type V, type Max) { \
|
|
||||||
type Result = V; \
|
|
||||||
if (V < Min) { Result = Min; } \
|
|
||||||
if (V > Max) { Result = Max; } \
|
|
||||||
return Result; \
|
|
||||||
}
|
|
||||||
GSClampDef(s8)
|
|
||||||
GSClampDef(s16)
|
|
||||||
GSClampDef(s32)
|
|
||||||
GSClampDef(s64)
|
|
||||||
GSClampDef(u8)
|
|
||||||
GSClampDef(u16)
|
|
||||||
GSClampDef(u32)
|
|
||||||
GSClampDef(u64)
|
|
||||||
GSClampDef(r32)
|
|
||||||
GSClampDef(r64)
|
|
||||||
#undef GSClampDef
|
|
||||||
|
|
||||||
#define GSClamp01Def(type) static type GSClamp01(type V) { \
|
|
||||||
type Min = 0; type Max = 1; \
|
|
||||||
type Result = V; \
|
|
||||||
if (V < Min) { Result = Min; } \
|
|
||||||
if (V > Max) { Result = Max; } \
|
|
||||||
return Result; \
|
|
||||||
}
|
|
||||||
GSClamp01Def(r32)
|
|
||||||
GSClamp01Def(r64)
|
|
||||||
#undef GSClamp01Def
|
|
||||||
|
|
||||||
#define GSAbsDef(type) static type GSAbs(type A) { return (A < 0 ? -A : A); }
|
|
||||||
GSAbsDef(s8)
|
|
||||||
GSAbsDef(s16)
|
|
||||||
GSAbsDef(s32)
|
|
||||||
GSAbsDef(s64)
|
|
||||||
GSAbsDef(r32)
|
|
||||||
GSAbsDef(r64)
|
|
||||||
#undef GSAbsDef
|
|
||||||
|
|
||||||
#define GSPowDef(type) static type GSPow(type N, s32 Power) { \
|
|
||||||
type Result = N; \
|
|
||||||
for(s32 i = 1; i < Power; i++) { Result *= N; } \
|
|
||||||
return Result; \
|
|
||||||
}
|
|
||||||
GSPowDef(s8)
|
|
||||||
GSPowDef(s16)
|
|
||||||
GSPowDef(s32)
|
|
||||||
GSPowDef(s64)
|
|
||||||
GSPowDef(u8)
|
|
||||||
GSPowDef(u16)
|
|
||||||
GSPowDef(u32)
|
|
||||||
GSPowDef(u64)
|
|
||||||
GSPowDef(r32)
|
|
||||||
GSPowDef(r64)
|
|
||||||
#undef GSPowDef
|
|
||||||
|
|
||||||
|
|
||||||
#define GSLerpDef(type) type GSLerp(type A, type B, type Percent) { return (A * (1.0f - Percent))+(B * Percent);}
|
|
||||||
GSLerpDef(r32)
|
|
||||||
GSLerpDef(r64)
|
|
||||||
#undef GSLerpDef
|
|
||||||
|
|
||||||
static r32 GSSqrt(r32 V)
|
|
||||||
{
|
|
||||||
r32 Result = _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V)));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
// TODO(Peter): Need a way to split the input into two f32's to supply to _mm_sqrt_sd
|
|
||||||
static r64 GSSqrt(r64 V)
|
|
||||||
{
|
|
||||||
r64 Result = _mm_cvtsd_f64(_mm_sqrt_sd(_mm_set_sd(V)));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static r32 DegreesToRadians (r32 Degrees) { return Degrees * PI_OVER_180; }
|
|
||||||
static r64 DegreesToRadians (r64 Degrees) { return Degrees * PI_OVER_180; }
|
|
||||||
|
|
||||||
#define GSIsPowerOfTwoDef(type) static type IsPowerOfTwo(type V) { return (V & (V - 1)) == 0; }
|
|
||||||
GSIsPowerOfTwoDef(u8);
|
|
||||||
GSIsPowerOfTwoDef(u16);
|
|
||||||
GSIsPowerOfTwoDef(u32);
|
|
||||||
GSIsPowerOfTwoDef(u64);
|
|
||||||
#undef GSIsPowerOfTwoDef
|
|
||||||
|
|
||||||
#define GSIsOddDef(type) inline type IsOdd(type V) { return (V & 1); }
|
|
||||||
GSIsOddDef(u8);
|
|
||||||
GSIsOddDef(u16);
|
|
||||||
GSIsOddDef(u32);
|
|
||||||
GSIsOddDef(u64);
|
|
||||||
GSIsOddDef(s8);
|
|
||||||
GSIsOddDef(s16);
|
|
||||||
GSIsOddDef(s32);
|
|
||||||
GSIsOddDef(s64);
|
|
||||||
#undef GSIsOddDef
|
|
||||||
|
|
||||||
#define GSIntDivideRoundUpDef(type) static type IntegerDivideRoundUp (type A, type B) { r32 Result = (r32)A / (r32)B; Result += .99999f; return (type)Result; }
|
|
||||||
GSIntDivideRoundUpDef(u8);
|
|
||||||
GSIntDivideRoundUpDef(u16);
|
|
||||||
GSIntDivideRoundUpDef(u32);
|
|
||||||
GSIntDivideRoundUpDef(u64);
|
|
||||||
GSIntDivideRoundUpDef(s8);
|
|
||||||
GSIntDivideRoundUpDef(s16);
|
|
||||||
GSIntDivideRoundUpDef(s32);
|
|
||||||
GSIntDivideRoundUpDef(s64);
|
|
||||||
#undef GSIntDivideRoundUpDef
|
|
||||||
|
|
||||||
#define GSRemapDef(type) \
|
|
||||||
static type GSRemap(type Value, type OldMin, type OldMax, type NewMin, type NewMax) { \
|
|
||||||
type Result = (Value - OldMin) / (OldMax - OldMin); \
|
|
||||||
Result = (Result * (NewMax - NewMin)) + NewMin; \
|
|
||||||
return Result; \
|
|
||||||
}
|
|
||||||
GSRemapDef(u8);
|
|
||||||
GSRemapDef(u16);
|
|
||||||
GSRemapDef(u32);
|
|
||||||
GSRemapDef(u64);
|
|
||||||
GSRemapDef(s8);
|
|
||||||
GSRemapDef(s16);
|
|
||||||
GSRemapDef(s32);
|
|
||||||
GSRemapDef(s64);
|
|
||||||
GSRemapDef(r32);
|
|
||||||
GSRemapDef(r64);
|
|
||||||
#undef GSRemapDef
|
|
||||||
|
|
||||||
#define GSTrigFunctionDef(name, type, func) static type name(type V) { return func(V); }
|
|
||||||
GSTrigFunctionDef(GSSin, r32, sinf);
|
|
||||||
GSTrigFunctionDef(GSSin, r64, sin);
|
|
||||||
GSTrigFunctionDef(GSCos, r32, cosf);
|
|
||||||
GSTrigFunctionDef(GSCos, r64, cos);
|
|
||||||
GSTrigFunctionDef(GSTan, r32, tanf);
|
|
||||||
GSTrigFunctionDef(GSTan, r64, tan);
|
|
||||||
#undef GSTrigFunctionDef
|
|
||||||
|
|
||||||
static u8
|
|
||||||
RoundToNearestPowerOfTwo (u8 V)
|
|
||||||
{
|
|
||||||
u8 Result = 0;
|
|
||||||
|
|
||||||
if (IsPowerOfTwo(V))
|
|
||||||
{
|
|
||||||
Result = V;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result = V - 1;
|
|
||||||
Result |= Result >> 1;
|
|
||||||
Result |= Result >> 2;
|
|
||||||
Result |= Result >> 4;
|
|
||||||
Result += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u16
|
|
||||||
RoundToNearestPowerOfTwo (u16 V)
|
|
||||||
{
|
|
||||||
u16 Result = 0;
|
|
||||||
|
|
||||||
if (IsPowerOfTwo(V))
|
|
||||||
{
|
|
||||||
Result = V;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result = V - 1;
|
|
||||||
Result |= Result >> 1;
|
|
||||||
Result |= Result >> 2;
|
|
||||||
Result |= Result >> 4;
|
|
||||||
Result |= Result >> 8;
|
|
||||||
Result += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32
|
|
||||||
RoundToNearestPowerOfTwo (u32 V)
|
|
||||||
{
|
|
||||||
u32 Result = 0;
|
|
||||||
|
|
||||||
if (IsPowerOfTwo(V))
|
|
||||||
{
|
|
||||||
Result = V;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result = V - 1;
|
|
||||||
Result |= Result >> 1;
|
|
||||||
Result |= Result >> 2;
|
|
||||||
Result |= Result >> 4;
|
|
||||||
Result |= Result >> 8;
|
|
||||||
Result |= Result >> 16;
|
|
||||||
Result += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64
|
|
||||||
RoundToNearestPowerOfTwo (u64 V)
|
|
||||||
{
|
|
||||||
u64 Result = 0;
|
|
||||||
|
|
||||||
if (IsPowerOfTwo(V))
|
|
||||||
{
|
|
||||||
Result = V;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result = V - 1;
|
|
||||||
Result |= Result >> 1;
|
|
||||||
Result |= Result >> 2;
|
|
||||||
Result |= Result >> 4;
|
|
||||||
Result |= Result >> 8;
|
|
||||||
Result |= Result >> 16;
|
|
||||||
Result |= Result >> 32;
|
|
||||||
Result += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GS_LANGUAGE_MATH
|
|
||||||
#endif // GS_LANGUAGE_MATH
|
|
||||||
|
|
||||||
static u32
|
|
||||||
HostToNetU32(u32 In)
|
|
||||||
{
|
|
||||||
unsigned char *s = (unsigned char *)&In;
|
|
||||||
u32 Result = (u32)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u16
|
|
||||||
HostToNetU16(u16 In)
|
|
||||||
{
|
|
||||||
unsigned char *s = (unsigned char *)&In;
|
|
||||||
u16 Result = (u16)(s[0] << 8 | s[1]);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GS_LANGUAGE_H
|
|
||||||
#endif
|
|
|
@ -1,613 +0,0 @@
|
||||||
// File: gs_memory_arena.h
|
|
||||||
// Description: Single header file library that defines a push-only memory arena
|
|
||||||
// Author: Peter Slattery
|
|
||||||
// Date Created: 2019-12-22
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -----------------
|
|
||||||
// Set Up
|
|
||||||
// -----------------
|
|
||||||
//
|
|
||||||
// Include 'gs_memory_arena.h' in a file and start using it! (Simple! Nice!)
|
|
||||||
//
|
|
||||||
// -----------------
|
|
||||||
// Usage
|
|
||||||
// -----------------
|
|
||||||
// Simply create a memory_arena and use PushSize, PushStruct, or PushArray
|
|
||||||
// to allocate out of it.
|
|
||||||
// See Example Program below.
|
|
||||||
//
|
|
||||||
// While there are options you can set (see Options below), the library adheres
|
|
||||||
// to a 'zero-is-initialization' policy, that is, a memory_arena initialized to
|
|
||||||
// zero, under all default options, will 'just work'.
|
|
||||||
//
|
|
||||||
// Alignment:
|
|
||||||
// By default, the Push functions use 4 byte alignment
|
|
||||||
// If you need to control the alignment of an allocation, there are variants of the
|
|
||||||
// Push functions that allow for this: PushSizeAligned, PushStructAligned, and PushArrayAligned
|
|
||||||
// These functions simply take a final parameter which specifies the alignment.
|
|
||||||
// Note: Alignment must be a power of two
|
|
||||||
//
|
|
||||||
// -----------------
|
|
||||||
// Options
|
|
||||||
// -----------------
|
|
||||||
//
|
|
||||||
// DEBUG:
|
|
||||||
// Define DEBUG for debug functionality.
|
|
||||||
//
|
|
||||||
// To override the default assert function define GSMem_Assert(expression)
|
|
||||||
// before inluding this file.
|
|
||||||
//
|
|
||||||
// GS_MEMORY_NO_STD_LIBS:
|
|
||||||
// if you don't want stdlib.h to be included, define GS_MEMORY_NO_STD_LIBS
|
|
||||||
// before including this file.
|
|
||||||
// Note that if you do this, zero-is-initialization will no longer work for
|
|
||||||
// memory_arenas. You must either:
|
|
||||||
// 1. Set each memory_arena's Alloc and Realloc so they can grow fields
|
|
||||||
// 2. Set each memory_arena's ExpansionRule to ExpansionRule_Disallowed
|
|
||||||
// If DEBUG is defined, the program will assert if one of the 2 rules above
|
|
||||||
// aren't followed.
|
|
||||||
//
|
|
||||||
// memory_arena.Alloc and memory_arena.Realloc
|
|
||||||
// By default, memory_arena's will use malloc and realloc to grow.
|
|
||||||
// You can override this by setting the Alloc and Realloc function pointers
|
|
||||||
// of a memory_arena. See the example program below for an implementation of this.
|
|
||||||
//
|
|
||||||
// GS_MEMORY_BUFFER_SIZE:
|
|
||||||
// This defines the minimum buffer size for memory_arena's. If an arena doesn't have
|
|
||||||
// room to fit an allocation, it will allocate a new buffer no smaller than GS_MEMORY_BUFFER_SIZE
|
|
||||||
// and place the allocation in the new buffer.
|
|
||||||
// By default this is 4096 bytes. To override, define GS_MEMORY_BUFFER_SIZE before including
|
|
||||||
// this file
|
|
||||||
//
|
|
||||||
// GS_MEMORY_TRACK_ALLOCATIONS:
|
|
||||||
// If you want to keep records of each allocation performed in every arena, define
|
|
||||||
// GS_MEMORY_TRACK_ALLOCATIONS before including this file.
|
|
||||||
// When defined, memory arenas gain fields that allow them to keep a list of every
|
|
||||||
// allocation they contain. It also adds a footer on the end of each allocation that
|
|
||||||
// can be checked to ensure there are no writes to allocations that overflow their bounds
|
|
||||||
// Note that calling ClearArena also clears this list
|
|
||||||
// You can then call AssertAllocationsNoOverflow occasionally throughout your program
|
|
||||||
// to check that no allocations have been written beyond their boundaries
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Example Program
|
|
||||||
// (this compiles - copy it into its own file though)
|
|
||||||
#if 0
|
|
||||||
#include "gs_memory_arena.h"
|
|
||||||
|
|
||||||
// Places the characters 'gs' at the end of each allocation. This would allow for an external
|
|
||||||
// function to check that we haven't written past the end of an allocation
|
|
||||||
void* MallocWrapper(gs_mem_u32 Size)
|
|
||||||
{
|
|
||||||
int SizeWithFooter = Size + (sizeof(char) * 2);
|
|
||||||
void* Result = malloc(SizeWithFooter);
|
|
||||||
char* Footer = (char*)(Result + Size);
|
|
||||||
Footer[0] = 'g';
|
|
||||||
Footer[1] = 's';
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ReallocWrapper(void* Address, gs_mem_u32 Size)
|
|
||||||
{
|
|
||||||
return realloc(Address, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int ArgCount, char** Args)
|
|
||||||
{
|
|
||||||
memory_arena Arena = {};
|
|
||||||
// Uncomment these lines for an example of how you can implement custom allocation functions
|
|
||||||
// Arena.Alloc = MallocWrapper;
|
|
||||||
// Arena.Realloc = ReallocWrapper;
|
|
||||||
|
|
||||||
int ArrayLength = 10;
|
|
||||||
|
|
||||||
int* A = PushArray(&Arena, int, ArrayLength);
|
|
||||||
int* B = PushArray(&Arena, int, ArrayLength);
|
|
||||||
int* C = PushArray(&Arena, int, ArrayLength);
|
|
||||||
int* D = PushArrayAligned(&Arena, int, ArrayLength, 8);
|
|
||||||
int* E = PushArrayAligned(&Arena, int, ArrayLength, 16);
|
|
||||||
|
|
||||||
// Just ensure that we can actually write to each address of each array
|
|
||||||
for (s32 i = 0; i < ArrayLength; i++)
|
|
||||||
{
|
|
||||||
A[i] = i;
|
|
||||||
B[i] = i;
|
|
||||||
C[i] = i;
|
|
||||||
D[i] = i;
|
|
||||||
E[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearArena(&Arena);
|
|
||||||
|
|
||||||
A = PushArray(&Arena, int, ArrayLength);
|
|
||||||
for (s32 i = 0; i < ArrayLength; i++)
|
|
||||||
{
|
|
||||||
A[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -------------------
|
|
||||||
// Begin Library
|
|
||||||
// -------------------
|
|
||||||
#ifndef GS_MEMORY_ARENA_H
|
|
||||||
|
|
||||||
#ifndef GS_MEMORY_NO_STD_LIBS
|
|
||||||
|
|
||||||
// NOTE(Peter): We use this so that we can fall back on malloc and realloc
|
|
||||||
// in the event that a memory_arena needs to grow but doesn't have a
|
|
||||||
// alloc or realloc function pointer assigned to it.
|
|
||||||
//
|
|
||||||
// See GrowArena to see where this is used
|
|
||||||
//
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned char gs_mem_u8;
|
|
||||||
typedef unsigned int gs_mem_u32;
|
|
||||||
typedef unsigned long long int gs_mem_u64;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#if !defined(GSMem_Assert)
|
|
||||||
#define GSMem_Assert(expression) \
|
|
||||||
if(!(expression)) { \
|
|
||||||
*((int *)0) = 5; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define GSMem_Assert(expression)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum gs_memory_expansion_rule
|
|
||||||
{
|
|
||||||
MemoryExpansion_Allowed, // Zero is initialization lets the memory grow on its own
|
|
||||||
MemoryExpansion_OnlyIfFunctionsProvided,
|
|
||||||
MemoryExpansion_Disallowed,
|
|
||||||
MemoryExpansion_Count,
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE(Peter):
|
|
||||||
// This rule is only here to allow for taking arena snapshots. The problem this solves
|
|
||||||
// is if you take a snapshot while there are 'holes' in memory_buffers behind the
|
|
||||||
// most recently added memory_buffer, take a snapshot of that arena, then push something
|
|
||||||
// on that fits in one of those holes, we will fill the hole and be unable to track/free
|
|
||||||
// that addition via the snapshot construct.
|
|
||||||
//
|
|
||||||
// By requiring that allocations in a buffer only come from the most recent memory_buffer
|
|
||||||
// we can very easily rewind the buffer to the correct location.
|
|
||||||
// Hence FindAddress_InLastBufferOnly
|
|
||||||
enum gs_memory_find_address_rule
|
|
||||||
{
|
|
||||||
FindAddress_InAnyBuffer,
|
|
||||||
FindAddress_InLastBufferOnly,
|
|
||||||
FindAddress_Count,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void* gs_memory_alloc(gs_mem_u32 Size);
|
|
||||||
typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize);
|
|
||||||
typedef void gs_memory_free(void* Address, gs_mem_u32 Size);
|
|
||||||
|
|
||||||
#ifndef GS_MEMORY_BUFFER_SIZE
|
|
||||||
#define GS_MEMORY_BUFFER_SIZE 1024
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GS_MEMORY_FOOTER_SIZE 4
|
|
||||||
#define GS_MEMORY_FOOTER_0 'g'
|
|
||||||
#define GS_MEMORY_FOOTER_1 's'
|
|
||||||
#define GS_MEMORY_FOOTER_2 'p'
|
|
||||||
#define GS_MEMORY_FOOTER_3 's'
|
|
||||||
|
|
||||||
struct tracked_allocation
|
|
||||||
{
|
|
||||||
gs_mem_u8* Head;
|
|
||||||
gs_mem_u8* Footer;
|
|
||||||
char* File;
|
|
||||||
gs_mem_u32 LineNumber;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE 512
|
|
||||||
struct tracked_allocation_buffer
|
|
||||||
{
|
|
||||||
tracked_allocation Buffer[GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct memory_buffer
|
|
||||||
{
|
|
||||||
gs_mem_u8* Buffer;
|
|
||||||
gs_mem_u32 Size;
|
|
||||||
gs_mem_u32 Used;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct memory_arena
|
|
||||||
{
|
|
||||||
memory_buffer* Buffers;
|
|
||||||
gs_mem_u32 BuffersCount;
|
|
||||||
|
|
||||||
gs_mem_u32 TotalUsed;
|
|
||||||
gs_mem_u32 TotalSize;
|
|
||||||
|
|
||||||
gs_memory_find_address_rule FindAddressRule;
|
|
||||||
gs_memory_expansion_rule ExpansionRule;
|
|
||||||
gs_memory_alloc* Alloc;
|
|
||||||
gs_memory_realloc* Realloc;
|
|
||||||
|
|
||||||
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
|
|
||||||
tracked_allocation_buffer** AllocationBuffers;
|
|
||||||
gs_mem_u32 AllocationBuffersCount;
|
|
||||||
gs_mem_u32 AllocationsUsed;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct address_and_buffer
|
|
||||||
{
|
|
||||||
memory_buffer* Buffer;
|
|
||||||
gs_mem_u64 Address;
|
|
||||||
gs_mem_u32 SizeWithAlignment;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct arena_snapshot
|
|
||||||
{
|
|
||||||
gs_mem_u32 ArenaUsedAtSnapshot;
|
|
||||||
gs_mem_u32 HeadBufferUsedAtSnapshot;
|
|
||||||
gs_mem_u32 HeadBufferAtSnapshot;
|
|
||||||
memory_arena* Arena;
|
|
||||||
|
|
||||||
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
|
|
||||||
gs_mem_u32 AllocationsUsedAtSnapshot;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
FreeMemoryArena(memory_arena* Arena, gs_memory_free* Free)
|
|
||||||
{
|
|
||||||
if (Free)
|
|
||||||
{
|
|
||||||
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
|
|
||||||
{
|
|
||||||
memory_buffer* Buffer = Arena->Buffers + i;
|
|
||||||
Free(Buffer->Buffer, Buffer->Size);
|
|
||||||
}
|
|
||||||
Free(Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef GS_MEMORY_NO_STD_LIBS
|
|
||||||
GSMem_Assert(0);
|
|
||||||
#else
|
|
||||||
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
|
|
||||||
{
|
|
||||||
memory_buffer* Buffer = Arena->Buffers + i;
|
|
||||||
free(Buffer->Buffer);
|
|
||||||
}
|
|
||||||
free(Arena->Buffers);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IsPowerOfTwo(v) ((v != 0) && ((v & (v - 1)) == 0))
|
|
||||||
|
|
||||||
inline gs_mem_u32
|
|
||||||
GetAlignmentOffset (gs_mem_u64 Address, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
|
|
||||||
{
|
|
||||||
gs_mem_u32 AlignmentOffset = 0;
|
|
||||||
if (Address & AlignmentMask)
|
|
||||||
{
|
|
||||||
AlignmentOffset = Alignment - (Address & AlignmentMask);
|
|
||||||
}
|
|
||||||
return AlignmentOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static address_and_buffer
|
|
||||||
GetAlignedAddressInBuffer(memory_buffer* Buffer, gs_mem_u32 Size, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
|
|
||||||
{
|
|
||||||
address_and_buffer Result = {};
|
|
||||||
|
|
||||||
gs_mem_u64 HeadAddress = (gs_mem_u64)Buffer->Buffer + Buffer->Used;
|
|
||||||
gs_mem_u32 AlignmentOffset = GetAlignmentOffset(HeadAddress, Alignment, AlignmentMask);
|
|
||||||
gs_mem_u64 AlignedAddress = HeadAddress + AlignmentOffset;
|
|
||||||
|
|
||||||
if (Buffer->Used + AlignmentOffset + Size <= Buffer->Size)
|
|
||||||
{
|
|
||||||
Result.Buffer = Buffer;
|
|
||||||
Result.Address = AlignedAddress;
|
|
||||||
Result.SizeWithAlignment = Size + AlignmentOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static address_and_buffer
|
|
||||||
FindAlignedAddressInBufferWithRoom(memory_arena* Arena, gs_mem_u32 Size, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
|
|
||||||
{
|
|
||||||
address_and_buffer Result = {};
|
|
||||||
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
|
|
||||||
{
|
|
||||||
memory_buffer* At = Arena->Buffers + i;
|
|
||||||
GSMem_Assert(At);
|
|
||||||
|
|
||||||
address_and_buffer AddressInCurrentBuffer = GetAlignedAddressInBuffer(At, Size, Alignment, AlignmentMask);
|
|
||||||
if (AddressInCurrentBuffer.Address != 0)
|
|
||||||
{
|
|
||||||
Result = AddressInCurrentBuffer;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gs_mem_u8*
|
|
||||||
ArenaAlloc(memory_arena* Arena, gs_mem_u32 Size)
|
|
||||||
{
|
|
||||||
gs_mem_u8* Result = 0;
|
|
||||||
|
|
||||||
if (Arena->Alloc)
|
|
||||||
{
|
|
||||||
Result = (gs_mem_u8*)Arena->Alloc(sizeof(gs_mem_u8) * Size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef GS_MEMORY_NO_STD_LIBS
|
|
||||||
// NOTE(Peter): If you specify no std libs AND don't supply a allocation function
|
|
||||||
// we should assert as this is an invalid codepath
|
|
||||||
GSMem_Assert(0);
|
|
||||||
#else
|
|
||||||
Result = (gs_mem_u8*)malloc(sizeof(gs_mem_u8) * Size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gs_mem_u8*
|
|
||||||
ArenaRealloc(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize)
|
|
||||||
{
|
|
||||||
gs_mem_u8* Result = 0;
|
|
||||||
|
|
||||||
if (Arena->Realloc != 0)
|
|
||||||
{
|
|
||||||
Result = (gs_mem_u8*)Arena->Realloc(Head, OldSize, NewSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef GS_MEMORY_NO_STD_LIBS
|
|
||||||
// NOTE(Peter): If you specify no std libs AND don't supply a reallocation function
|
|
||||||
// we should assert as this is an invalid codepath
|
|
||||||
GSMem_Assert(0);
|
|
||||||
#else
|
|
||||||
Result = (gs_mem_u8*)realloc(Head, NewSize);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static memory_buffer*
|
|
||||||
GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded)
|
|
||||||
{
|
|
||||||
GSMem_Assert(Arena->ExpansionRule != MemoryExpansion_Disallowed);
|
|
||||||
if (Arena->ExpansionRule == MemoryExpansion_OnlyIfFunctionsProvided)
|
|
||||||
{
|
|
||||||
GSMem_Assert((Arena->Alloc != 0) && (Arena->Realloc != 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
gs_mem_u32 NewBuffersCount = (Arena->BuffersCount + 1);
|
|
||||||
gs_mem_u32 OldBuffersSize = sizeof(memory_buffer) * Arena->BuffersCount;
|
|
||||||
gs_mem_u32 NewBuffersSize = sizeof(memory_buffer) * NewBuffersCount;
|
|
||||||
Arena->Buffers = (memory_buffer*)ArenaRealloc(Arena, (gs_mem_u8*)Arena->Buffers, OldBuffersSize, NewBuffersSize);
|
|
||||||
Arena->BuffersCount = NewBuffersCount;
|
|
||||||
|
|
||||||
memory_buffer* NewBuffer = Arena->Buffers + (Arena->BuffersCount - 1);
|
|
||||||
NewBuffer->Size = GS_MEMORY_BUFFER_SIZE;
|
|
||||||
if (SizeNeeded > NewBuffer->Size)
|
|
||||||
{
|
|
||||||
NewBuffer->Size = SizeNeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
NewBuffer->Buffer = ArenaAlloc(Arena, sizeof(gs_mem_u8) * NewBuffer->Size);
|
|
||||||
NewBuffer->Used = 0;
|
|
||||||
|
|
||||||
Arena->TotalSize += NewBuffer->Size;
|
|
||||||
return NewBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
|
|
||||||
|
|
||||||
#define DetermineAllocationSize(size) (size) + GS_MEMORY_FOOTER_SIZE
|
|
||||||
#define ClearAllocationsUsed(arena) (arena)->AllocationsUsed = 0
|
|
||||||
#define ClearAllocationsUsedToSnapshot(arena, snapshot) \
|
|
||||||
(arena)->AllocationsUsed = (snapshot).AllocationsUsedAtSnapshot;
|
|
||||||
|
|
||||||
static void
|
|
||||||
TrackAllocation(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 Size, char* Filename, gs_mem_u32 LineNumber)
|
|
||||||
{
|
|
||||||
gs_mem_u32 AllocationsMax = Arena->AllocationBuffersCount * GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
|
|
||||||
if (Arena->AllocationsUsed >= AllocationsMax)
|
|
||||||
{
|
|
||||||
gs_mem_u32 NewAllocationBuffersCount = Arena->AllocationBuffersCount + 1;
|
|
||||||
Arena->AllocationBuffers = (tracked_allocation_buffer**)ArenaRealloc(Arena,
|
|
||||||
(gs_mem_u8*)Arena->AllocationBuffers,
|
|
||||||
Arena->AllocationBuffersCount * sizeof(void*),
|
|
||||||
NewAllocationBuffersCount * sizeof(void*));
|
|
||||||
Arena->AllocationBuffersCount = NewAllocationBuffersCount;
|
|
||||||
|
|
||||||
gs_mem_u32 NewBufferIndex = Arena->AllocationBuffersCount - 1;
|
|
||||||
Arena->AllocationBuffers[NewBufferIndex] = (tracked_allocation_buffer*)ArenaAlloc(Arena, sizeof(tracked_allocation_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
gs_mem_u32 AllocationIndex = Arena->AllocationsUsed++;
|
|
||||||
gs_mem_u32 BufferIndex = AllocationIndex / GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
|
|
||||||
gs_mem_u32 IndexInBuffer = AllocationIndex % GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
|
|
||||||
tracked_allocation_buffer* Buffer = Arena->AllocationBuffers[BufferIndex];
|
|
||||||
tracked_allocation* NewAllocationTracker = Buffer->Buffer + IndexInBuffer;
|
|
||||||
|
|
||||||
NewAllocationTracker->Head = Head;
|
|
||||||
|
|
||||||
NewAllocationTracker->Footer = Head + Size - GS_MEMORY_FOOTER_SIZE;
|
|
||||||
NewAllocationTracker->Footer[0] = GS_MEMORY_FOOTER_0;
|
|
||||||
NewAllocationTracker->Footer[1] = GS_MEMORY_FOOTER_1;
|
|
||||||
NewAllocationTracker->Footer[2] = GS_MEMORY_FOOTER_2;
|
|
||||||
NewAllocationTracker->Footer[3] = GS_MEMORY_FOOTER_3;
|
|
||||||
|
|
||||||
NewAllocationTracker->File = Filename;
|
|
||||||
NewAllocationTracker->LineNumber = LineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
VerifyAllocationNoOverflow (tracked_allocation Allocation)
|
|
||||||
{
|
|
||||||
bool Result = ((Allocation.Footer[0] == GS_MEMORY_FOOTER_0) &&
|
|
||||||
(Allocation.Footer[1] == GS_MEMORY_FOOTER_1) &&
|
|
||||||
(Allocation.Footer[2] == GS_MEMORY_FOOTER_2) &&
|
|
||||||
(Allocation.Footer[3] == GS_MEMORY_FOOTER_3));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AssertAllocationsNoOverflow (memory_arena Arena)
|
|
||||||
{
|
|
||||||
for (gs_mem_u32 AllocationIndex = 0;
|
|
||||||
AllocationIndex< Arena.AllocationsUsed;
|
|
||||||
AllocationIndex++)
|
|
||||||
{
|
|
||||||
gs_mem_u32 BufferIndex = AllocationIndex / GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
|
|
||||||
gs_mem_u32 IndexInBuffer = AllocationIndex % GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
|
|
||||||
|
|
||||||
tracked_allocation_buffer* Buffer = Arena.AllocationBuffers[BufferIndex];
|
|
||||||
tracked_allocation Allocation = Buffer->Buffer[IndexInBuffer];
|
|
||||||
|
|
||||||
GSMem_Assert(VerifyAllocationNoOverflow(Allocation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PushSize(arena, size) PushSize_((arena), (size), 4, __FILE__, __LINE__)
|
|
||||||
#define PushArray(arena, type, length) (type*)PushSize_((arena), sizeof(type) * length, 4, __FILE__, __LINE__)
|
|
||||||
#define PushStruct(arena, type) (type*)PushSize_((arena), sizeof(type), 4, __FILE__, __LINE__)
|
|
||||||
#define PushSizeAligned(arena, size, alignment) PushSize_((arena), (size), (alignment), __FILE__, __LINE__)
|
|
||||||
#define PushArrayAligned(arena, type, length, alignment) (type*)PushSize_((arena), sizeof(type) * length, (alignment), __FILE__, __LINE__)
|
|
||||||
#define PushStructAligned(arena, type, alignment) (type*)PushSize_((arena), sizeof(type), (alignment), __FILE__, __LINE__)
|
|
||||||
|
|
||||||
#else // GS_MEMORY_TRACK_ALLOCATIONS
|
|
||||||
|
|
||||||
#define AssertAllocationsNoOverflow(arena)
|
|
||||||
#define DetermineAllocationSize(size) size
|
|
||||||
#define ClearAllocationsUsed(arena)
|
|
||||||
#define ClearAllocationsUsedToSnapshot(arena, snapshot)
|
|
||||||
|
|
||||||
#define TrackAllocation(arena, head, size, filename, linenumber)
|
|
||||||
|
|
||||||
#define PushSize(arena, size) PushSize_((arena), (size))
|
|
||||||
#define PushArray(arena, type, length) (type*)PushSize_((arena), sizeof(type) * length)
|
|
||||||
#define PushStruct(arena, type) (type*)PushSize_((arena), sizeof(type))
|
|
||||||
#define PushSizeAligned(arena, size, alignment) PushSize_((arena), (size), (alignment))
|
|
||||||
#define PushArrayAligned(arena, type, length, alignment) (type*)PushSize_((arena), sizeof(type) * length, (alignment))
|
|
||||||
#define PushStructAligned(arena, type, alignment) (type*)PushSize_((arena), sizeof(type), (alignment))
|
|
||||||
|
|
||||||
#endif // GS_MEMORY_TRACK_ALLOCATIONS
|
|
||||||
|
|
||||||
static gs_mem_u8*
|
|
||||||
PushSize_(memory_arena* Arena, gs_mem_u32 Size, gs_mem_u32 Alignment = 4, char* Filename = 0, gs_mem_u32 LineNumber = 0)
|
|
||||||
{
|
|
||||||
// ie. Alignment = 4 = 100 (binary)
|
|
||||||
// 4 - 1 = 3
|
|
||||||
// 100 - 1 = 011 which is a mask of the bits we don't want set in the start address
|
|
||||||
GSMem_Assert(IsPowerOfTwo(Alignment));
|
|
||||||
gs_mem_u32 AlignmentMask = Alignment - 1;
|
|
||||||
|
|
||||||
gs_mem_u32 AllocationSize = DetermineAllocationSize(Size);
|
|
||||||
|
|
||||||
address_and_buffer ResultAddress = {};
|
|
||||||
if (Arena->FindAddressRule == FindAddress_InAnyBuffer)
|
|
||||||
{
|
|
||||||
ResultAddress = FindAlignedAddressInBufferWithRoom(Arena, AllocationSize, Alignment, AlignmentMask);
|
|
||||||
}
|
|
||||||
else if (Arena->FindAddressRule == FindAddress_InLastBufferOnly
|
|
||||||
&& Arena->BuffersCount > 0)
|
|
||||||
{
|
|
||||||
memory_buffer* LastBuffer = Arena->Buffers + Arena->BuffersCount - 1;
|
|
||||||
ResultAddress = GetAlignedAddressInBuffer(LastBuffer, Size, Alignment, AlignmentMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ResultAddress.Address == 0)
|
|
||||||
{
|
|
||||||
memory_buffer* Buffer = GrowArena(Arena, AllocationSize);
|
|
||||||
ResultAddress = GetAlignedAddressInBuffer(Buffer, AllocationSize, Alignment, AlignmentMask);
|
|
||||||
}
|
|
||||||
GSMem_Assert(ResultAddress.Address != 0);
|
|
||||||
GSMem_Assert((ResultAddress.Address & AlignmentMask) == 0);
|
|
||||||
|
|
||||||
gs_mem_u8* Result = (gs_mem_u8*)ResultAddress.Address;
|
|
||||||
ResultAddress.Buffer->Used += ResultAddress.SizeWithAlignment;
|
|
||||||
Arena->TotalUsed += ResultAddress.SizeWithAlignment;
|
|
||||||
|
|
||||||
TrackAllocation(Arena, Result, AllocationSize, Filename, LineNumber);
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ClearArena(memory_arena* Arena)
|
|
||||||
{
|
|
||||||
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
|
|
||||||
{
|
|
||||||
memory_buffer* At = Arena->Buffers + i;
|
|
||||||
At->Used = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Arena->TotalUsed = 0;
|
|
||||||
ClearAllocationsUsed(Arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
static arena_snapshot
|
|
||||||
TakeSnapshotOfArena(memory_arena* Arena)
|
|
||||||
{
|
|
||||||
Assert(Arena->FindAddressRule == FindAddress_InLastBufferOnly);
|
|
||||||
|
|
||||||
arena_snapshot Result = {};
|
|
||||||
Result.Arena = Arena;
|
|
||||||
Result.ArenaUsedAtSnapshot = Arena->TotalUsed;
|
|
||||||
if (Arena->BuffersCount > 0)
|
|
||||||
{
|
|
||||||
Result.HeadBufferAtSnapshot = Arena->BuffersCount - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result.HeadBufferAtSnapshot = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_buffer* HeadBuffer = Arena->Buffers + Result.HeadBufferAtSnapshot;
|
|
||||||
if (HeadBuffer)
|
|
||||||
{
|
|
||||||
Result.HeadBufferUsedAtSnapshot = HeadBuffer->Used;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ClearArenaToSnapshot(memory_arena* Arena, arena_snapshot Snapshot)
|
|
||||||
{
|
|
||||||
Assert(Arena == Snapshot.Arena);
|
|
||||||
|
|
||||||
memory_buffer* HeadBufferAtSnapshot = Arena->Buffers + Snapshot.HeadBufferAtSnapshot;
|
|
||||||
if (HeadBufferAtSnapshot)
|
|
||||||
{
|
|
||||||
HeadBufferAtSnapshot->Used = Snapshot.HeadBufferUsedAtSnapshot;
|
|
||||||
|
|
||||||
for (gs_mem_u32 i = Snapshot.HeadBufferAtSnapshot + 1; i < Arena->BuffersCount; i++)
|
|
||||||
{
|
|
||||||
memory_buffer* Buffer = Arena->Buffers + i;
|
|
||||||
Buffer->Used = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Arena->TotalUsed = Snapshot.ArenaUsedAtSnapshot;
|
|
||||||
ClearAllocationsUsedToSnapshot(Arena, Snapshot);
|
|
||||||
}
|
|
||||||
#define GS_MEMORY_ARENA_H
|
|
||||||
#endif // GS_MEMORY_ARENA_H
|
|
2206
src/gs_string.h
2206
src/gs_string.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,78 @@
|
||||||
|
PANEL_INIT_PROC(HierarchyView_Init)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PANEL_CLEANUP_PROC(HierarchyView_Cleanup)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PANEL_RENDER_PROC(HierarchyView_Render)
|
||||||
|
{
|
||||||
|
r32 PanelWidth = PanelMax.x - PanelMin.x;
|
||||||
|
r32 PanelHeight = PanelMax.y - PanelMin.y;
|
||||||
|
|
||||||
|
s32 LineBGColorsCount = 2;
|
||||||
|
v4 LineBGColors[] = {
|
||||||
|
{ .16f, .16f, .16f, 1.f },
|
||||||
|
{ .18f, .18f, .18f, 1.f },
|
||||||
|
};
|
||||||
|
v4 LineBGHoverColor = { .22f, .22f, .22f, 1.f };
|
||||||
|
|
||||||
|
r32 LineHeight = State->Interface.Font->PixelHeight + 8;
|
||||||
|
v2 LineMin = v2{PanelMin.x + State->Interface.Margin.x, PanelMax.y - LineHeight};
|
||||||
|
v2 LineMax = LineMin + v2{PanelWidth, LineHeight};
|
||||||
|
v2 TextOffset = v2{10, 4};
|
||||||
|
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
|
||||||
|
|
||||||
|
s32 LineCount = (s32)(PanelHeight / LineHeight) + 1;
|
||||||
|
for (s32 i = 0; i < LineCount; i++)
|
||||||
|
{
|
||||||
|
v4 Color = LineBGColors[i % LineBGColorsCount];
|
||||||
|
if (PointIsInRange(Mouse.Pos, LineMin, LineMax))
|
||||||
|
{
|
||||||
|
Color = LineBGHoverColor;
|
||||||
|
}
|
||||||
|
PushRenderQuad2D(RenderBuffer, LineMin, LineMax, Color);
|
||||||
|
if (i < State->ActiveAssemblyIndecies.Used)
|
||||||
|
{
|
||||||
|
array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
||||||
|
assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList);
|
||||||
|
PrintF(&TempString, "%S", Assembly.Name);
|
||||||
|
|
||||||
|
DrawString(RenderBuffer, TempString, State->Interface.Font, LineMin + TextOffset, WhiteV4);
|
||||||
|
|
||||||
|
PrintF(&TempString, "X");
|
||||||
|
|
||||||
|
v2 XLowerRight = v2{LineMax.x - 25, LineMin.y + TextOffset.y};
|
||||||
|
v2 XLowerLeft = DrawString(RenderBuffer, TempString, State->Interface.Font, XLowerRight, WhiteV4, Align_Right);
|
||||||
|
|
||||||
|
if (MouseButtonTransitionedUp(Mouse.LeftButtonState)
|
||||||
|
&& PointIsInRange(Mouse.Pos, XLowerLeft, LineMax))
|
||||||
|
{
|
||||||
|
UnloadAssembly(i, State, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i == State->ActiveAssemblyIndecies.Used)
|
||||||
|
{
|
||||||
|
PrintF(&TempString, "+ Add Assembly");
|
||||||
|
v2 TextMinX = LineMin + TextOffset;
|
||||||
|
DrawString(RenderBuffer, TempString, State->Interface.Font, TextMinX, WhiteV4);
|
||||||
|
|
||||||
|
if (MouseButtonTransitionedUp(Mouse.LeftButtonState)
|
||||||
|
&& PointIsInRange(Mouse.Pos, LineMin, LineMax))
|
||||||
|
{
|
||||||
|
char FilePath[256];
|
||||||
|
b32 Success = Context.PlatformGetFilePath(FilePath, 256, "Foldhaus Files\0*.fold\0\0");
|
||||||
|
if (Success)
|
||||||
|
{
|
||||||
|
LoadAssembly(State, Context, FilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineMin.y = GSMax(PanelMin.y, LineMin.y - LineHeight);
|
||||||
|
LineMax.y = GSMax(PanelMin.y, LineMax.y - LineHeight);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
input_command SculptureView_Commands[] = {
|
||||||
|
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate },
|
||||||
|
};
|
||||||
|
|
||||||
PANEL_INIT_PROC(SculptureView_Init)
|
PANEL_INIT_PROC(SculptureView_Init)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue