scratch memory, sculpture rendering, wasm updates

This commit is contained in:
PS 2022-04-12 07:53:32 +02:00
parent 0e7a1b5536
commit 09db50e3d4
30 changed files with 3874 additions and 426 deletions

View File

@ -92,20 +92,69 @@ var lumenarium_wasm_imports = {
}, },
wasm_mem_grow: (new_size) => { wasm_mem_grow: (new_size) => {
let pages = new_size / WASM_PAGE_SIZE; let new_size_ = new_size >>> 0;
let pages = new_size_ / WASM_PAGE_SIZE;
let pages_rem = fract(pages); let pages_rem = fract(pages);
if (pages_rem > 0) pages = Math.floor(pages) + 1; if (pages_rem > 0) pages = Math.floor(pages) + 1;
let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength; let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength;
let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages); let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages);
console.log("mem_grow\n", console.log("mem_grow\n",
"req size: ", new_size, "\n", "req size: ", new_size_, "\n",
"old size: ", (old_page_count * WASM_PAGE_SIZE), "\n", "old size: ", (old_page_count * WASM_PAGE_SIZE), "\n",
"old size: ", size_before, "\n", "old size: ", size_before, "\n",
"grew by: ", (pages * WASM_PAGE_SIZE), "\n", "grew by: ", (pages * WASM_PAGE_SIZE), "\n",
"new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, ""); "new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, "");
}, },
malloc: (size) => {
},
free: (base) => {
},
sin: Math.sin,
sinf: Math.sin,
cos: Math.cos,
cosf: Math.cos,
tan: Math.tan,
tanf: Math.tan,
asin: Math.asin,
asinf: Math.asin,
acos: Math.acos,
acosf: Math.acos,
atan: Math.atan,
atanf: Math.atan,
pow: Math.pow,
powf: Math.pow,
fmodf: (f,d) => { return f % d; },
strlen: (ptr) => {
let len = 0;
let len_checked = 0;
let len_to_check = 256;
let found_end = false;
while (true)
{
let string = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, len_checked);
for (let i = len_checked; i < len_to_check; i++)
{
if (string[i] == 0)
{
len = i;
break;
}
}
len_checked *= 2;
}
return len_checked;
},
wasm_platform_file_async_work_on_job: (path, path_len, data, data_size, read, write) => {
},
wasm_performance_now: () => { wasm_performance_now: () => {
return performance.now(); return performance.now();
}, },
@ -260,6 +309,14 @@ function glBufferData(target, size, ptr, usage)
return r; return r;
} }
function glBufferSubData(target, offset, size, ptr)
{
let data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, size);
const r = gl.bufferSubData(target, offset, data, 0, size);
glErrorReport(arguments);
return r;
}
function glCreateShader(kind) function glCreateShader(kind)
{ {
let shader = gl.createShader(kind); let shader = gl.createShader(kind);
@ -395,6 +452,17 @@ function glTexSubImage2D(target, level, offsetx, offsety, width, height, format,
return r; return r;
} }
function glGetUniformLocation(program, name, name_len)
{
// TODO(PS): complete
return 0;
}
function glUniformMatrix4fv()
{
// TODO(PS):
}
function webgl_add_imports (canvas_selector, imports) { function webgl_add_imports (canvas_selector, imports) {
const canvas = document.querySelector(canvas_selector); const canvas = document.querySelector(canvas_selector);
if (!canvas) return console.error("no canvas"); if (!canvas) return console.error("no canvas");
@ -414,6 +482,7 @@ function webgl_add_imports (canvas_selector, imports) {
imports.glCreateBuffer = glCreateBuffer; imports.glCreateBuffer = glCreateBuffer;
imports.glBindBuffer = glBindBuffer; imports.glBindBuffer = glBindBuffer;
imports.glBufferData = glBufferData; imports.glBufferData = glBufferData;
imports.glBufferSubData = glBufferSubData;
imports.glCreateShader = glCreateShader; imports.glCreateShader = glCreateShader;
imports.glShaderSource = glShaderSource; imports.glShaderSource = glShaderSource;
imports.glCompileShader = glCompileShader; imports.glCompileShader = glCompileShader;
@ -431,5 +500,8 @@ function webgl_add_imports (canvas_selector, imports) {
imports.glTexImage2D = glTexImage2D; imports.glTexImage2D = glTexImage2D;
imports.glTexSubImage2D = glTexSubImage2D; imports.glTexSubImage2D = glTexSubImage2D;
imports.glBindTexture = glBindTexture; imports.glBindTexture = glBindTexture;
imports.glGetUniformLocation = glGetUniformLocation;
imports.glUniformMatrix4fv = glUniformMatrix4fv;
return imports; return imports;
} }

View File

@ -11,11 +11,11 @@
enum panel_split_direction enum panel_split_direction
{ {
PanelSplit_NoSplit, PanelSplit_NoSplit,
PanelSplit_Horizontal, PanelSplit_Horizontal,
PanelSplit_Vertical, PanelSplit_Vertical,
PanelSplit_Count, PanelSplit_Count,
}; };
typedef struct panel panel; typedef struct panel panel;
@ -25,32 +25,32 @@ typedef PANEL_MODAL_OVERRIDE_CALLBACK(panel_modal_override_callback);
struct panel struct panel
{ {
s32 TypeIndex; s32 TypeIndex;
gs_data StateMemory; gs_data StateMemory;
panel* ModalOverride; panel* ModalOverride;
panel* IsModalOverrideFor; panel* IsModalOverrideFor;
panel_modal_override_callback* ModalOverrideCB; panel_modal_override_callback* ModalOverrideCB;
rect2 Bounds; rect2 Bounds;
panel_split_direction SplitDirection; panel_split_direction SplitDirection;
r32 SplitPercent; r32 SplitPercent;
panel* Parent; panel* Parent;
union{ union{
panel* Left; panel* Left;
panel* Top; panel* Top;
}; };
union{ union{
panel* Right; panel* Right;
panel* Bottom; panel* Bottom;
}; };
}; };
struct free_panel struct free_panel
{ {
free_panel* Next; free_panel* Next;
}; };
#define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context) #define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context)
@ -65,25 +65,25 @@ typedef PANEL_RENDER_PROC(panel_render_proc);
// NOTE(Peter): This is used by the meta system to generate panel type info // NOTE(Peter): This is used by the meta system to generate panel type info
struct panel_definition struct panel_definition
{ {
char* PanelName; char* PanelName;
s32 PanelNameLength; s32 PanelNameLength;
panel_init_proc* Init; panel_init_proc* Init;
panel_cleanup_proc* Cleanup; panel_cleanup_proc* Cleanup;
panel_render_proc* Render; panel_render_proc* Render;
input_command* InputCommands; input_command* InputCommands;
s32 InputCommandsCount; s32 InputCommandsCount;
}; };
#define PANELS_MAX 16 #define PANELS_MAX 16
struct panel_system struct panel_system
{ {
panel_definition* PanelDefs; panel_definition* PanelDefs;
u32 PanelDefsCount; u32 PanelDefsCount;
panel* Panels; panel* Panels;
u32 PanelsUsed; u32 PanelsUsed;
free_panel* FreeList; free_panel* FreeList;
}; };
///////////////////////////////// /////////////////////////////////
@ -95,164 +95,164 @@ struct panel_system
internal void internal void
PanelSystem_Init(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount, gs_memory_arena* Storage) PanelSystem_Init(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount, gs_memory_arena* Storage)
{ {
PanelSystem->FreeList = 0; PanelSystem->FreeList = 0;
PanelSystem->PanelDefs = PanelDefs; PanelSystem->PanelDefs = PanelDefs;
PanelSystem->PanelDefsCount = PanelDefsCount; PanelSystem->PanelDefsCount = PanelDefsCount;
PanelSystem->Panels = PushArray(Storage, panel, PANELS_MAX); PanelSystem->Panels = PushArray(Storage, panel, PANELS_MAX);
} }
internal panel* internal panel*
PanelSystem_TakePanel(panel_system* PanelSystem) PanelSystem_TakePanel(panel_system* PanelSystem)
{ {
panel* FreeEntry = 0; panel* FreeEntry = 0;
if (PanelSystem->FreeList != 0) if (PanelSystem->FreeList != 0)
{ {
free_panel* FreePanel = PanelSystem->FreeList; free_panel* FreePanel = PanelSystem->FreeList;
PanelSystem->FreeList = FreePanel->Next; PanelSystem->FreeList = FreePanel->Next;
FreeEntry = (panel*)FreePanel; FreeEntry = (panel*)FreePanel;
} }
else else
{ {
Assert(PanelSystem->PanelsUsed < PANELS_MAX); Assert(PanelSystem->PanelsUsed < PANELS_MAX);
FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++; FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++;
} }
return FreeEntry; return FreeEntry;
} }
internal void internal void
PanelSystem_FreePanel(panel* Panel, panel_system* PanelSystem) PanelSystem_FreePanel(panel* Panel, panel_system* PanelSystem)
{ {
Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX); Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX);
free_panel* FreeEntry = (free_panel*)Panel; free_panel* FreeEntry = (free_panel*)Panel;
FreeEntry->Next = PanelSystem->FreeList; FreeEntry->Next = PanelSystem->FreeList;
PanelSystem->FreeList = FreeEntry; PanelSystem->FreeList = FreeEntry;
} }
internal void internal void
PanelSystem_FreePanelRecursive(panel* Panel, panel_system* PanelSystem) PanelSystem_FreePanelRecursive(panel* Panel, panel_system* PanelSystem)
{ {
if (Panel->SplitDirection != PanelSplit_NoSplit) if (Panel->SplitDirection != PanelSplit_NoSplit)
{ {
PanelSystem_FreePanelRecursive(Panel->Left, PanelSystem); PanelSystem_FreePanelRecursive(Panel->Left, PanelSystem);
PanelSystem_FreePanelRecursive(Panel->Right, PanelSystem); PanelSystem_FreePanelRecursive(Panel->Right, PanelSystem);
} }
PanelSystem_FreePanel(Panel, PanelSystem); PanelSystem_FreePanel(Panel, PanelSystem);
} }
internal panel* internal panel*
Panel_GetModalOverride(panel* Panel) Panel_GetModalOverride(panel* Panel)
{ {
panel* Result = Panel; panel* Result = Panel;
if (Panel->ModalOverride != 0) if (Panel->ModalOverride != 0)
{ {
Result = Panel_GetModalOverride(Panel->ModalOverride); Result = Panel_GetModalOverride(Panel->ModalOverride);
} }
return Result; return Result;
} }
internal void internal void
Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callback* Callback) Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callback* Callback)
{ {
Root->ModalOverride = Override; Root->ModalOverride = Override;
Root->ModalOverrideCB = Callback; Root->ModalOverrideCB = Callback;
Override->IsModalOverrideFor = Root; Override->IsModalOverrideFor = Root;
Override->Bounds = Root->Bounds; Override->Bounds = Root->Bounds;
} }
internal void internal void
Panel_PopModalOverride(panel* Parent, panel_system* System) Panel_PopModalOverride(panel* Parent, panel_system* System)
{ {
// TODO(pjs): Free the overrided panel // TODO(pjs): Free the overrided panel
PanelSystem_FreePanel(Parent->ModalOverride, System); PanelSystem_FreePanel(Parent->ModalOverride, System);
Parent->ModalOverride = 0; Parent->ModalOverride = 0;
} }
internal void internal void
Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_data TypeStateMemory, app_state* State, context Context) Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_data TypeStateMemory, app_state* State, context Context)
{ {
s32 OldTypeIndex = Panel->TypeIndex; s32 OldTypeIndex = Panel->TypeIndex;
Panel->TypeIndex = NewPanelType; Panel->TypeIndex = NewPanelType;
Panel->StateMemory = TypeStateMemory; Panel->StateMemory = TypeStateMemory;
if(OldTypeIndex >= 0) if(OldTypeIndex >= 0)
{ {
System->PanelDefs[OldTypeIndex].Cleanup(Panel, State); System->PanelDefs[OldTypeIndex].Cleanup(Panel, State);
} }
} }
internal void internal void
Panel_SetType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context) Panel_SetType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context)
{ {
gs_data EmptyStateData = {0}; gs_data EmptyStateData = {0};
Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context); Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context);
System->PanelDefs[NewPanelTypeIndex].Init(Panel, State, Context); System->PanelDefs[NewPanelTypeIndex].Init(Panel, State, Context);
} }
#define Panel_GetStateStruct(p, type) (type*)Panel_GetStateMemory((p), sizeof(type)).Memory #define Panel_GetStateStruct(p, type) (type*)Panel_GetStateMemory((p), sizeof(type)).Memory
internal gs_data internal gs_data
Panel_GetStateMemory(panel* Panel, u64 Size) Panel_GetStateMemory(panel* Panel, u64 Size)
{ {
Assert(Panel->StateMemory.Size == Size); Assert(Panel->StateMemory.Size == Size);
gs_data Result = Panel->StateMemory; gs_data Result = Panel->StateMemory;
return Result; return Result;
} }
internal panel* internal panel*
PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context) PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context)
{ {
panel* Panel = PanelSystem_TakePanel(PanelSystem); panel* Panel = PanelSystem_TakePanel(PanelSystem);
Panel_SetType(Panel, PanelSystem, PanelTypeIndex, State, Context); Panel_SetType(Panel, PanelSystem, PanelTypeIndex, State, Context);
return Panel; return Panel;
} }
internal void internal void
SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, panel_system* PanelSystem, app_state* State, context Context) SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, panel_system* PanelSystem, app_state* State, context Context)
{ {
if (Percent >= 0.0f && Percent <= 1.0f) if (Percent >= 0.0f && Percent <= 1.0f)
{ {
Parent->SplitDirection = SplitDirection; Parent->SplitDirection = SplitDirection;
Parent->SplitPercent = Percent; Parent->SplitPercent = Percent;
s32 ParentTypeIndex = Parent->TypeIndex; s32 ParentTypeIndex = Parent->TypeIndex;
gs_data ParentStateMemory = Parent->StateMemory; gs_data ParentStateMemory = Parent->StateMemory;
Parent->Left = PanelSystem_TakePanel(PanelSystem); Parent->Left = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Left->Parent = Parent; Parent->Left->Parent = Parent;
Parent->Right = PanelSystem_TakePanel(PanelSystem); Parent->Right = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Right->Parent = Parent; Parent->Right->Parent = Parent;
} }
} }
internal void internal void
SplitPanelVertically(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context) SplitPanelVertically(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context)
{ {
SplitPanel(Parent, Percent, PanelSplit_Vertical, PanelSystem, State, Context); SplitPanel(Parent, Percent, PanelSplit_Vertical, PanelSystem, State, Context);
} }
internal void internal void
SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context) SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context)
{ {
SplitPanel(Parent, Percent, PanelSplit_Horizontal, PanelSystem, State, Context); SplitPanel(Parent, Percent, PanelSplit_Horizontal, PanelSystem, State, Context);
} }
internal void internal void
ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelSystem) ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelSystem)
{ {
panel* LeftChild = Parent->Left; panel* LeftChild = Parent->Left;
panel* RightChild = Parent->Right; panel* RightChild = Parent->Right;
panel* PanelToDestroy = PanelToKeep == LeftChild ? RightChild : LeftChild; panel* PanelToDestroy = PanelToKeep == LeftChild ? RightChild : LeftChild;
*Parent = *PanelToKeep; *Parent = *PanelToKeep;
PanelSystem_FreePanel(PanelToKeep, PanelSystem); PanelSystem_FreePanel(PanelToKeep, PanelSystem);
PanelSystem_FreePanelRecursive(PanelToDestroy, PanelSystem); PanelSystem_FreePanelRecursive(PanelToDestroy, PanelSystem);
} }
///////////////////////////////// /////////////////////////////////
@ -264,178 +264,178 @@ ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelS
internal rect2 internal rect2
GetTopPanelBounds(panel* Panel) GetTopPanelBounds(panel* Panel)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = v2{ Result.Min = v2{
Panel->Bounds.Min.x, Panel->Bounds.Min.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y) LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
}; };
Result.Max = Panel->Bounds.Max; Result.Max = Panel->Bounds.Max;
return Result; return Result;
} }
internal rect2 internal rect2
GetBottomPanelBounds(panel* Panel) GetBottomPanelBounds(panel* Panel)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = Panel->Bounds.Min; Result.Min = Panel->Bounds.Min;
Result.Max = v2{ Result.Max = v2{
Panel->Bounds.Max.x, Panel->Bounds.Max.x,
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y) LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y)
}; };
return Result; return Result;
} }
internal rect2 internal rect2
GetRightPanelBounds(panel* Panel) GetRightPanelBounds(panel* Panel)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = v2{ Result.Min = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x), LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Min.y Panel->Bounds.Min.y
}; };
Result.Max = Panel->Bounds.Max; Result.Max = Panel->Bounds.Max;
return Result; return Result;
} }
internal rect2 internal rect2
GetLeftPanelBounds(panel* Panel) GetLeftPanelBounds(panel* Panel)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = Panel->Bounds.Min; Result.Min = Panel->Bounds.Min;
Result.Max = v2{ Result.Max = v2{
LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x), LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x),
Panel->Bounds.Max.y Panel->Bounds.Max.y
}; };
return Result; return Result;
} }
internal rect2 internal rect2
GetTopPanelBounds(panel* Panel, rect2 PanelBounds) GetTopPanelBounds(panel* Panel, rect2 PanelBounds)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = v2{ Result.Min = v2{
PanelBounds.Min.x, PanelBounds.Min.x,
LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y) LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y)
}; };
Result.Max = PanelBounds.Max; Result.Max = PanelBounds.Max;
return Result; return Result;
} }
internal rect2 internal rect2
GetBottomPanelBounds(panel* Panel, rect2 PanelBounds) GetBottomPanelBounds(panel* Panel, rect2 PanelBounds)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = PanelBounds.Min; Result.Min = PanelBounds.Min;
Result.Max = v2{ Result.Max = v2{
PanelBounds.Max.x, PanelBounds.Max.x,
LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y) LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y)
}; };
return Result; return Result;
} }
internal rect2 internal rect2
GetRightPanelBounds(panel* Panel, rect2 PanelBounds) GetRightPanelBounds(panel* Panel, rect2 PanelBounds)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = v2{ Result.Min = v2{
LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x), LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x),
PanelBounds.Min.y PanelBounds.Min.y
}; };
Result.Max = PanelBounds.Max; Result.Max = PanelBounds.Max;
return Result; return Result;
} }
internal rect2 internal rect2
GetLeftPanelBounds(panel* Panel, rect2 PanelBounds) GetLeftPanelBounds(panel* Panel, rect2 PanelBounds)
{ {
rect2 Result = {}; rect2 Result = {};
Result.Min = PanelBounds.Min; Result.Min = PanelBounds.Min;
Result.Max = v2{ Result.Max = v2{
LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x), LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x),
PanelBounds.Max.y PanelBounds.Max.y
}; };
return Result; return Result;
} }
internal void internal void
Panel_UpdateLayout(panel* Panel, rect2 Bounds) Panel_UpdateLayout(panel* Panel, rect2 Bounds)
{ {
Panel->Bounds = Bounds; Panel->Bounds = Bounds;
if (Panel->SplitDirection != PanelSplit_NoSplit) if (Panel->SplitDirection != PanelSplit_NoSplit)
{
rect2 LeftOrTopBounds = {};
rect2 RightOrBottomBounds = {};
switch (Panel->SplitDirection)
{ {
rect2 LeftOrTopBounds = {}; case PanelSplit_Horizontal:
rect2 RightOrBottomBounds = {}; {
switch (Panel->SplitDirection) LeftOrTopBounds = GetTopPanelBounds(Panel);
{ RightOrBottomBounds = GetBottomPanelBounds(Panel);
case PanelSplit_Horizontal: } break;
{
LeftOrTopBounds = GetTopPanelBounds(Panel);
RightOrBottomBounds = GetBottomPanelBounds(Panel);
} break;
case PanelSplit_Vertical: case PanelSplit_Vertical:
{ {
LeftOrTopBounds = GetLeftPanelBounds(Panel); LeftOrTopBounds = GetLeftPanelBounds(Panel);
RightOrBottomBounds = GetRightPanelBounds(Panel); RightOrBottomBounds = GetRightPanelBounds(Panel);
} break; } break;
InvalidDefaultCase; InvalidDefaultCase;
}
Panel_UpdateLayout(Panel->Left, LeftOrTopBounds);
Panel_UpdateLayout(Panel->Right, RightOrBottomBounds);
} }
Panel_UpdateLayout(Panel->Left, LeftOrTopBounds);
Panel_UpdateLayout(Panel->Right, RightOrBottomBounds);
}
} }
internal void internal void
PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds) PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds)
{ {
panel* Root = System->Panels; panel* Root = System->Panels;
Panel_UpdateLayout(Root, WindowBounds); Panel_UpdateLayout(Root, WindowBounds);
} }
internal panel* internal panel*
GetPanelContainingPoint(panel* Panel, v2 Point) GetPanelContainingPoint(panel* Panel, v2 Point)
{ {
panel* Result = 0; panel* Result = 0;
if (PointIsInRect(Panel->Bounds, Point)) if (PointIsInRect(Panel->Bounds, Point))
{
switch (Panel->SplitDirection)
{ {
switch (Panel->SplitDirection) case PanelSplit_NoSplit:
{
Result = Panel;
}break;
case PanelSplit_Vertical:
case PanelSplit_Horizontal:
{asdfasdfasdfasdfasdf
if (PointIsInRect(Panel->Left->Bounds, Point))
{ {
case PanelSplit_NoSplit: Result = GetPanelContainingPoint(Panel->Left, Point);
{
Result = Panel;
}break;
case PanelSplit_Vertical:
case PanelSplit_Horizontal:
{
if (PointIsInRect(Panel->Left->Bounds, Point))
{
Result = GetPanelContainingPoint(Panel->Left, Point);
}
else if (PointIsInRect(Panel->Right->Bounds, Point))
{
Result = GetPanelContainingPoint(Panel->Right, Point);
}
}break;
InvalidDefaultCase;
} }
} else if (PointIsInRect(Panel->Right->Bounds, Point))
{
Result = GetPanelContainingPoint(Panel->Right, Point);
}
}break;
return Result; InvalidDefaultCase;
}
}
return Result;
} }
internal panel* internal panel*
PanelSystem_GetPanelContainingPoint(panel_system* System, v2 Point) PanelSystem_GetPanelContainingPoint(panel_system* System, v2 Point)
{ {
panel* Result = 0; panel* Result = 0;
panel* Root = System->Panels; panel* Root = System->Panels;
Result = GetPanelContainingPoint(Root, Point); Result = GetPanelContainingPoint(Root, Point);
return Result; return Result;
} }
#define FOLDHAUS_PANEL_H #define FOLDHAUS_PANEL_H

View File

@ -131,12 +131,72 @@ ed_load_font_cb(Platform_File_Async_Job_Args result, u8* user_data)
platform_texture_update(ui->atlas_texture, ui->atlas.pixels, 1024, 1024, 1024); platform_texture_update(ui->atlas_texture, ui->atlas.pixels, 1024, 1024, 1024);
} }
internal void
ed_draw_panel(u8* user_data, BSP_Node_Id id, BSP_Node node, BSP_Area area)
{
App_State* state = (App_State*)user_data;
UI* ui = &state->editor->ui;
scratch_get(scratch);
UI_Layout title_layout = {};
ui_layout_set_row_info(ui, &title_layout);
title_layout.bounds_min = v2{ area.min.x, area.max.y - title_layout.row_height };
title_layout.bounds_max = area.max;
title_layout.at = title_layout.bounds_min;
UI_Layout panel_layout = {};
ui_layout_set_row_info(ui, &panel_layout);
panel_layout.bounds_min = area.min;
panel_layout.bounds_max = v2{ area.max.x, title_layout.bounds_max.y };
panel_layout.at = panel_layout.bounds_min;
ui_layout_push(ui, &panel_layout);
String title = {};
switch (node.user_data)
{
case 0:
{
title = lit_str("None");
} break;
case 1:
{
ed_sculpture_visualizer(state);
title = lit_str("Sculpture");
} break;
invalid_default_case;
}
ui_layout_pop(ui);
ui_layout_push(ui, &title_layout);
UI_Widget_Desc bg = {};
bg.style.flags = UIWidgetStyle_Bg;
bg.style.color_bg = v4{.4f,.4f,.4f,1};
bg.style.sprite = WHITE_SPRITE_ID;
bg.string = string_f(scratch.a, "%.*s_%u_title_bg", str_varg(title), id.value);
bg.p_min = title_layout.bounds_min;
bg.p_max = title_layout.bounds_max;
UI_Widget_Result r = ui_widget_push(ui, bg);
ui_layout_row_begin(&title_layout, 4);
{
ui_text(ui, title, BLACK_V4);
}
ui_layout_row_end(&title_layout);
ui_widget_pop(ui, r.id);
ui_layout_pop(ui);
}
internal void internal void
ed_init(App_State* state) ed_init(App_State* state)
{ {
Editor* editor = allocator_alloc_struct(permanent, Editor); Editor* editor = allocator_alloc_struct(permanent, Editor);
state->editor = editor; state->editor = editor;
state->editor->ui = ui_create(4096, 4096, state->input_state, permanent); editor->ui = ui_create(4096, 4096, state->input_state, permanent);
editor->ui.draw_panel_cb = ed_draw_panel;
editor->ui.draw_panel_cb_data = (u8*)state;
//bsp_split(&editor->ui.panels, editor->ui.panels.root, 700, BSPSplit_YAxis, 0, 1);
// make the default quad for us to draw with // make the default quad for us to draw with
// TODO(PS): this might be unnecessary with the per-frame buffer we use now // TODO(PS): this might be unnecessary with the per-frame buffer we use now
@ -144,6 +204,119 @@ ed_init(App_State* state)
platform_file_async_read(lit_str("data/font.ttf"), ed_load_font_cb); platform_file_async_read(lit_str("data/font.ttf"), ed_load_font_cb);
ed_sculpture_visualizer_init(state);
}
internal void
ed_sculpture_updated(App_State* state, r32 scale, r32 led_size)
{
Editor* ed = state->editor;
if (!ed) return;
scratch_get(scratch);
// NOTE(PS): we need to know the total number of leds in order to give them
// texture coordinates
u32 leds_count = 0;
for (u32 a = 0; a < state->assemblies.len; a++)
{
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
leds_count += pixels.len;
}
// round up to a texture whose sides are powers of two
u32 pixels_dim = (u32)floorf(sqrtf((r32)leds_count));
pixels_dim = round_up_to_pow2(pixels_dim);
u32 pixels_count = pixels_dim * pixels_dim;
r32 texel_dim = 1 / (r32)pixels_dim;
// NOTE(PS): Rebuild the sculpture geometry to point to the new
// sculpture.
Geo_Vertex_Buffer_Storage storage = (
GeoVertexBufferStorage_Position |
GeoVertexBufferStorage_TexCoord
);
u32 verts_cap = leds_count * 4;
u32 indices_cap = leds_count * 6;
Geo_Quad_Buffer_Builder geo = geo_quad_buffer_builder_create(scratch.a, verts_cap, storage, indices_cap);
r32 r = led_size;
u32 pixels_created = 0;
for (u32 a = 0; a < state->assemblies.len; a++)
{
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
for (u32 p = 0; p < pixels.len; p++)
{
v3 c = pixels.positions[p].xyz;
c *= scale;
u32 pixel_count = pixels_created++;
u32 pixel_x = pixel_count % pixels_dim;
u32 pixel_y = pixel_count / pixels_dim;
r32 texel_x_min = (r32)pixel_x / (r32)pixels_dim;
r32 texel_y_min = (r32)pixel_y / (r32)pixels_dim;
r32 texel_x_max = texel_x_min + texel_dim;
r32 texel_y_max = texel_y_min + texel_dim;
v2 t0 = v2{texel_x_min, texel_y_min};
v2 t1 = v2{texel_x_max, texel_y_min};
v2 t2 = v2{texel_x_max, texel_y_max};
v2 t3 = v2{texel_x_min, texel_y_max};
v3 p0 = c + v3{ -r, -r, 0 };
v3 p1 = c + v3{ r, -r, 0 };
v3 p2 = c + v3{ r, r, 0 };
v3 p3 = c + v3{ -r, r, 0 };
geo_quad_buffer_builder_push(&geo, p0, p1, p2, p3, t0, t1, t2, t3);
}
}
if (ed->sculpture_geo.indices_len != 0)
{
invalid_code_path;
// TODO(PS): destroy the old geometry buffer or update it
}
ed->sculpture_geo = platform_geometry_buffer_create(
geo.buffer_vertex.values,
geo.buffer_vertex.len,
geo.buffer_index.values,
geo.buffer_index.len
);
platform_vertex_attrib_pointer(
ed->sculpture_geo, ed->sculpture_shd, 3, ed->sculpture_shd.attrs[0], 5, 0
);
platform_vertex_attrib_pointer(
ed->sculpture_geo, ed->sculpture_shd, 2, ed->sculpture_shd.attrs[1], 5, 3
);
// TODO(PS): make this have enough pixels for the sculpture
// TODO(PS): map leds to pixels
if (ed->sculpture_tex.w != 0)
{
invalid_code_path;
// TODO(PS): destroy the old texture
}
u32* pixels = allocator_alloc_array(scratch.a, u32, pixels_count);
for (u32 y = 0; y < pixels_dim; y++)
{
for (u32 x = 0; x < pixels_dim; x++)
{
r32 rp = (r32)y / (r32)pixels_dim;
r32 bp = (r32)x / (r32)pixels_dim;
u8 rb = (u8)(255 * rp);
u8 bb = (u8)(255 * bp);
u32 c = (
0xFF0000FF |
(rb << 8) |
(bb << 16)
);
pixels[(y * pixels_dim) + x] = c;
}
}
ed->sculpture_tex = platform_texture_create((u8*)pixels, pixels_dim, pixels_dim, pixels_dim);
} }
internal void internal void
@ -152,59 +325,11 @@ ed_frame_prepare(App_State* state)
ui_frame_prepare(&state->editor->ui, state->editor->window_dim); ui_frame_prepare(&state->editor->ui, state->editor->window_dim);
} }
global r32 p = 0.3f;
internal void internal void
ed_frame(App_State* state) ed_frame(App_State* state)
{ {
UI* ui = &state->editor->ui; UI* ui = &state->editor->ui;
UI_Layout layout = {};
layout.bounds_min = v2{ 500, 200 };
layout.bounds_max = v2{ 700, 500 };
ui_layout_set_row_info(ui, &layout);
layout.at = layout.bounds_min;
ui_layout_push(ui, &layout);
ui_text_f(ui, "Hi there! %d", 1000);
show = ui_toggle(ui, lit_str("my toggle"), show);
if (show)
{
ui_layout_row_begin(ui, 2);
{
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
}
ui_layout_row_end(ui);
}
ui_button(ui, lit_str("Hi there my good sir"));
ui_scroll_view_begin(ui, lit_str("scroll area"), v2{800, 200}, v2{1000,500}, 8);
{
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("you there"));
ui_button(ui, lit_str("Sup"));
ui_button(ui, lit_str("I'm lastf;"));
}
ui_scroll_view_end(ui);
ui_layout_pop(ui);
edr_render_begin(state); edr_render_begin(state);
ui_draw(&state->editor->ui); ui_draw(&state->editor->ui);
edr_render(state); edr_render(state);

View File

@ -8,6 +8,16 @@ struct Editor
v2 window_dim; v2 window_dim;
Editor_Renderer renderer; Editor_Renderer renderer;
UI ui; UI ui;
v3 camera_pos;
Platform_Geometry_Buffer sculpture_geo;
Platform_Shader sculpture_shd;
Platform_Texture sculpture_tex;
}; };
// NOTE(PS): call this any time sculpture data is updated if
// you want to see the sculpture in the visualizer
internal void ed_sculpture_updated(App_State* state);
#endif //LUMENARIUM_EDITOR_H #endif //LUMENARIUM_EDITOR_H

View File

@ -0,0 +1,100 @@
static String sculpture_shd_vert_win32 = lit_str(
"#version 330 core\n"
"layout (location = 0) in vec3 a_pos;\n"
"layout (location = 1) in vec2 a_uv;\n"
"out vec2 uv;\n"
"uniform mat4 proj;\n"
"void main(void) {\n"
" gl_Position = proj * vec4(a_pos, 1.0);\n"
" uv = a_uv;\n"
"}"
);
static String sculpture_shd_vert_wasm = lit_str(
"precision highp float;\n"
"attribute vec3 a_pos;\n"
"attribute vec2 a_uv;\n"
"varying vec2 uv;\n"
"uniform mat4 proj;\n"
"void main(void) {\n"
" gl_Position = proj * vec4(a_pos, 1.0);\n"
" uv = a_uv;\n"
"}"
);
static String sculpture_shd_frag_win32 = lit_str(
"#version 330 core\n"
"in vec2 uv;\n"
"out vec4 FragColor;\n"
"uniform sampler2D texture;\n"
"void main(void) {\n"
" FragColor = texture(texture, uv);\n"
"}"
);
static String sculpture_shd_frag_wasm = lit_str(
"precision highp float;\n"
"varying vec2 uv;\n"
"uniform sampler2D texture;\n"
"void main(void) {\n"
" //gl_FragColor = texture2D(texture, uv) * color;\n"
" gl_FragColor = vec4(uv.x,1,uv.y,1);\n"
"}"
);
internal void
ed_sculpture_visualizer_init(App_State* state)
{
Editor* editor = state->editor;
#if defined(PLATFORM_win32)
String vert = sculpture_shd_vert_win32;
String frag = sculpture_shd_frag_win32;
#elif defined(PLATFORM_wasm)
String vert = sculpture_shd_vert_wasm;
String frag = sculpture_shd_frag_wasm;
#endif
String attrs[] = { lit_str("a_pos"), lit_str("a_uv") };
String uniforms[] = { lit_str("proj") };
editor->sculpture_shd = platform_shader_create(
vert, frag, attrs, 2, uniforms, 1
);
}
r32 cam_theta = 0;
internal void
ed_sculpture_visualizer(App_State* state)
{
Editor* ed = state->editor;
// Set the viewport to the current layout's region so that the sculpture
// never overlaps any other ui elements
UI_Layout l = *ed->ui.layout;
v2 view_dim = l.bounds_max - l.bounds_min;
glViewport(
(s32)l.bounds_min.x,
(s32)l.bounds_min.y,
(s32)view_dim.x,
(s32)view_dim.y
);
// TODO(PS): TEMPORARY CAMERA CODE
cam_theta += 0.05f;
v3 camera_pos = v3{sinf(cam_theta) * 50, 0, cosf(cam_theta) * 50};
r32 aspect = view_dim.x / view_dim.y;
m44 proj = HMM_Perspective(45.0, aspect, 0.01f, 500);
m44 view = HMM_LookAt(camera_pos, v3{0,0,0}, v3{0,1,0});
platform_shader_bind(ed->sculpture_shd);
platform_set_uniform(ed->sculpture_shd, 0, proj * view);
platform_texture_bind(ed->sculpture_tex);
platform_geometry_bind(ed->sculpture_geo);
platform_geometry_draw(ed->sculpture_geo, ed->sculpture_geo.indices_len);
// reset the viewport for all other rendering
glViewport(0, 0, (s32)ed->window_dim.x, (s32)ed->window_dim.y);
}

View File

@ -2,19 +2,34 @@
static String ui_shader_vert_win32 = lit_str( static String ui_shader_vert_win32 = lit_str(
"#version 330 core\n" "#version 330 core\n"
"layout (location = 0) in vec4 a_pos;\n" "layout (location = 0) in vec3 a_pos;\n"
"layout (location = 1) in vec2 a_uv;\n" "layout (location = 1) in vec2 a_uv;\n"
"layout (location = 2) in vec4 a_color;\n" "layout (location = 2) in vec4 a_color;\n"
"out vec2 uv;\n" "out vec2 uv;\n"
"out vec4 color;\n" "out vec4 color;\n"
"uniform mat4 proj;\n" "uniform mat4 proj;\n"
"void main(void) {\n" "void main(void) {\n"
" gl_Position = proj * a_pos;\n" " gl_Position = proj * vec4(a_pos, 1.0);\n"
" uv = a_uv;\n" " uv = a_uv;\n"
" color = a_color;\n" " color = a_color;\n"
"}" "}"
); );
static String ui_shader_vert_wasm = lit_str(
"precision highp float;\n"
"attribute vec3 a_pos;\n"
"attribute vec2 a_uv;\n"
"attribute vec4 a_color;\n"
"varying vec2 uv;\n"
"varying vec4 color;\n"
"uniform mat4 proj;\n"
"void main(void) {\n"
" gl_Position = proj * vec4(a_pos, 1.0);\n"
" uv = a_uv;\n"
" color = a_color;\n"
"}"
);
static String ui_shader_frag_win32 = lit_str( static String ui_shader_frag_win32 = lit_str(
"#version 330 core\n" "#version 330 core\n"
"in vec2 uv;\n" "in vec2 uv;\n"
@ -26,10 +41,21 @@ static String ui_shader_frag_win32 = lit_str(
"}" "}"
); );
static String ui_shader_frag_wasm = lit_str(
"precision highp float;\n"
"varying vec2 uv;\n"
"varying vec4 color;\n"
"uniform sampler2D texture;\n"
"void main(void) {\n"
" gl_FragColor = texture2D(texture, uv) * color;\n"
"}"
);
internal UI internal UI
ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a) ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
{ {
UI result = {}; UI result = {};
zero_struct(result);
result.input = input; result.input = input;
// Widgets // Widgets
@ -39,36 +65,46 @@ ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
result.widgets.states = allocator_alloc_array(a, UI_Widget_State, result.widgets.states_cap); result.widgets.states = allocator_alloc_array(a, UI_Widget_State, result.widgets.states_cap);
result.widgets.states_hash = allocator_alloc_array(a, u32, result.widgets.states_cap); result.widgets.states_hash = allocator_alloc_array(a, u32, result.widgets.states_cap);
result.panels = bsp_create(a, 32);
result.panels.root = bsp_push(&result.panels, {0}, {v2{},v2{1400, 800}}, 1);
// Per Frame Vertex Buffer // Per Frame Vertex Buffer
result.verts_cap = verts_cap; Geo_Vertex_Buffer_Storage storage = (
result.verts = allocator_alloc_array(a, UI_Vertex, verts_cap); GeoVertexBufferStorage_Position |
result.indices_cap = verts_cap * 2; GeoVertexBufferStorage_TexCoord |
result.indices = allocator_alloc_array(a, u32, result.indices_cap); GeoVertexBufferStorage_Color
);
result.geo = geo_quad_buffer_builder_create(a, verts_cap, storage, verts_cap * 2);
result.per_frame_buffer = platform_geometry_buffer_create( result.per_frame_buffer = platform_geometry_buffer_create(
(r32*)result.verts, result.geo.buffer_vertex.values,
result.verts_cap, result.geo.buffer_vertex.cap,
result.indices, result.geo.buffer_index.values,
result.indices_cap result.geo.buffer_index.cap
); );
#if defined(PLATFORM_win32)
String vert = ui_shader_vert_win32;
String frag = ui_shader_frag_win32;
#elif defined(PLATFORM_wasm)
String vert = ui_shader_vert_wasm;
String frag = ui_shader_frag_wasm;
#endif
String attrs[] = { lit_str("a_pos"), lit_str("a_uv"), lit_str("a_color") }; String attrs[] = { lit_str("a_pos"), lit_str("a_uv"), lit_str("a_color") };
String uniforms[] = { lit_str("proj") }; String uniforms[] = { lit_str("proj") };
result.shader = platform_shader_create( result.shader = platform_shader_create(
ui_shader_vert_win32, vert, frag, attrs, 3, uniforms, 1
ui_shader_frag_win32,
attrs, 3,
uniforms, 1
); );
platform_vertex_attrib_pointer( platform_vertex_attrib_pointer(
result.per_frame_buffer, result.shader, 4, result.shader.attrs[0], 10, 0 result.per_frame_buffer, result.shader, 3, result.shader.attrs[0], 9, 0
); );
platform_vertex_attrib_pointer( platform_vertex_attrib_pointer(
result.per_frame_buffer, result.shader, 2, result.shader.attrs[1], 10, 4 result.per_frame_buffer, result.shader, 2, result.shader.attrs[1], 9, 3
); );
platform_vertex_attrib_pointer( platform_vertex_attrib_pointer(
result.per_frame_buffer, result.shader, 4, result.shader.attrs[2], 10, 6 result.per_frame_buffer, result.shader, 4, result.shader.attrs[2], 9, 5
); );
// Texture Atlas // Texture Atlas
@ -87,41 +123,18 @@ ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
return result; return result;
} }
internal u32
ui_vert_push(UI* ui, v3 p, v2 t, v4 c)
{
assert(ui->verts_len < ui->verts_cap);
u32 index = ui->verts_len++;
ui->verts[index].pos = {p.x, p.y, p.z, 1};
ui->verts[index].uv = t;
ui->verts[index].color = c;
return index;
}
internal void
ui_index_push(UI* ui, u32 i)
{
assert(ui->indices_len < ui->indices_cap);
ui->indices[ui->indices_len++] = i;
}
internal void internal void
ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c) ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c)
{ {
u32 bl = ui_vert_push(ui, pmin, tmin, c); v3 p0 = pmin;
u32 br = ui_vert_push(ui, v3{pmax.x, pmin.y, pmin.z}, v2{tmax.x,tmin.y}, c); v3 p1 = v3{pmax.x, pmin.y, pmin.z};
u32 tr = ui_vert_push(ui, pmax, tmax, c); v3 p2 = pmax;
u32 tl = ui_vert_push(ui, v3{pmin.x, pmax.y, pmin.z}, v2{tmin.x,tmax.y}, c); v3 p3 = v3{pmin.x, pmax.y, pmin.z};
v2 t0 = tmin;
ui_index_push(ui, bl); v2 t1 = v2{tmax.x,tmin.y};
ui_index_push(ui, br); v2 t2 = tmax;
ui_index_push(ui, tr); v2 t3 = v2{tmin.x,tmax.y};
geo_quad_buffer_builder_push(&ui->geo, p0, p1, p2, p3, t0, t1, t2, t3, c);
ui_index_push(ui, bl);
ui_index_push(ui, tr);
ui_index_push(ui, tl);
} }
internal void internal void
@ -159,6 +172,7 @@ internal UI_Char_Draw_Cmd
ui_sprite_char_get_draw_cmd(UI* ui, v3 at, u32 codepoint) ui_sprite_char_get_draw_cmd(UI* ui, v3 at, u32 codepoint)
{ {
UI_Char_Draw_Cmd result = {}; UI_Char_Draw_Cmd result = {};
zero_struct(result);
Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(&ui->atlas, codepoint); Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(&ui->atlas, codepoint);
result.uv = texture_atlas_sprite_get_uvs(&ui->atlas, sprite); result.uv = texture_atlas_sprite_get_uvs(&ui->atlas, sprite);
@ -181,14 +195,23 @@ ui_sprite_char_get_draw_cmd(UI* ui, v3 at, u32 codepoint)
internal void internal void
ui_frame_prepare(UI* ui, v2 window_dim) ui_frame_prepare(UI* ui, v2 window_dim)
{ {
ui->verts_len = 0; ui->geo.buffer_vertex.len = 0;
ui->indices_len = 0; ui->geo.buffer_index.len = 0;
ui->widgets.free_len = 0; ui->widgets.free_len = 0;
ui->widgets.active_parent = 0; ui->widgets.active_parent = 0;
ui->widgets.root = ui_widget_pool_push(&ui->widgets, lit_str("root")); ui->widgets.root = ui_widget_pool_push(&ui->widgets, lit_str("root"));
ui->widgets.active_parent = ui->widgets.root; ui->widgets.active_parent = ui->widgets.root;
BSP_Node* panel_root = bsp_get(&ui->panels, ui->panels.root);
if (window_dim.x != 0 && window_dim.y != 0 && window_dim != panel_root->area.max)
{
BSP_Area area = {};
area.min = v2{0,0};
area.max = window_dim;
bsp_node_area_update(&ui->panels, ui->panels.root, area);
}
v2 half_d = window_dim * 0.5f; v2 half_d = window_dim * 0.5f;
ui->proj = HMM_Orthographic(0, window_dim.x, window_dim.y, 0, 0.01f, 100); ui->proj = HMM_Orthographic(0, window_dim.x, window_dim.y, 0, 0.01f, 100);
@ -206,9 +229,42 @@ ui_frame_prepare(UI* ui, v2 window_dim)
global bool show = false; global bool show = false;
internal void
ui_draw_panel(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data)
{
if (node->split.kind != BSPSplit_None) return;
UI* ui = (UI*)user_data;
BSP_Area area = node->area;
if (ui->draw_panel_cb) ui->draw_panel_cb(ui->draw_panel_cb_data, id, *node, area);
r32 z = -1;
v3 l0p0 = v3{ area.min.x, area.min.y, z }; // left side
v3 l0p1 = v3{ area.min.x + 1, area.max.y, z };
v3 l1p0 = v3{ area.max.x - 1, area.min.y, z }; // right side
v3 l1p1 = v3{ area.max.x, area.max.y, z };
v3 l2p0 = v3{ area.min.x, area.min.y , z }; // bottom side
v3 l2p1 = v3{ area.max.x, area.min.y + 1, z };
v3 l3p0 = v3{ area.min.x, area.max.y , z }; // top side
v3 l3p1 = v3{ area.max.x, area.max.y + 1, z };
u32 sid = WHITE_SPRITE_ID;
v4 c = WHITE_V4;
if (rect2_contains(area.min, area.max, ui->input->frame_hot->mouse_pos))
{
c = PINK_V4;
}
ui_sprite_push(ui, l0p0, l0p1, sid, c);
ui_sprite_push(ui, l1p0, l1p1, sid, c);
ui_sprite_push(ui, l2p0, l2p1, sid, c);
ui_sprite_push(ui, l3p0, l3p1, sid, c);
}
internal void internal void
ui_draw(UI* ui) ui_draw(UI* ui)
{ {
bsp_walk_inorder(&ui->panels, ui->panels.root, ui_draw_panel, (u8*)ui);
u32 widget_count = ui->widgets.free_len; u32 widget_count = ui->widgets.free_len;
r32 range_min = -10; r32 range_min = -10;
r32 range_max = -1; r32 range_max = -1;
@ -217,20 +273,18 @@ ui_draw(UI* ui)
platform_geometry_buffer_update( platform_geometry_buffer_update(
&ui->per_frame_buffer, &ui->per_frame_buffer,
(r32*)ui->verts, (r32*)ui->geo.buffer_vertex.values,
0, 0,
ui->verts_len * 10, ui->geo.buffer_vertex.len * ui->geo.buffer_vertex.stride,
ui->indices, ui->geo.buffer_index.values,
0, 0,
ui->indices_len ui->geo.buffer_index.len
); );
platform_shader_bind(ui->shader); platform_shader_bind(ui->shader);
platform_set_uniform(ui->shader, 0, ui->proj); platform_set_uniform(ui->shader, 0, ui->proj);
platform_texture_bind(ui->atlas_texture); platform_texture_bind(ui->atlas_texture);
platform_geometry_bind(ui->per_frame_buffer); platform_geometry_bind(ui->per_frame_buffer);
platform_geometry_draw(ui->per_frame_buffer, ui->indices_len); platform_geometry_draw(ui->per_frame_buffer, ui->geo.buffer_index.len);
OutputDebugStringA("Frame\n\n");
} }
//////////////////////////////////////////// ////////////////////////////////////////////
@ -241,6 +295,7 @@ ui_widget_id_create(String string, u32 index)
{ {
assert(string.len != 0 && string.str != 0); assert(string.len != 0 && string.str != 0);
UI_Widget_Id result = {}; UI_Widget_Id result = {};
zero_struct(result);
result.value = hash_djb2_to_u32(string); result.value = hash_djb2_to_u32(string);
result.index = index; result.index = index;
return result; return result;
@ -272,7 +327,11 @@ ui_widget_pool_push(UI_Widget_Pool* pool, String string)
result->child_first = 0; result->child_first = 0;
result->child_last = 0; result->child_last = 0;
u32 index = hash_table_register(pool->states_hash, pool->states_cap, result->id.value); u32 index = hash_table_find(pool->states_hash, pool->states_cap, result->id.value);
if (index == pool->states_cap)
{
index = hash_table_register(pool->states_hash, pool->states_cap, result->id.value);
}
assert(index != pool->states_cap); assert(index != pool->states_cap);
UI_Widget_State* state = pool->states + index; UI_Widget_State* state = pool->states + index;
zero_struct(*state); zero_struct(*state);
@ -286,6 +345,7 @@ ui_widget_pool_push(UI_Widget_Pool* pool, String string)
result result
); );
} }
pool->active_parent = result;
return result; return result;
} }
@ -337,6 +397,7 @@ internal UI_Widget_Result
ui_widget_push(UI* ui, UI_Widget_Desc desc) ui_widget_push(UI* ui, UI_Widget_Desc desc)
{ {
UI_Widget_Result result = {}; UI_Widget_Result result = {};
zero_struct(result);
v2 dim = desc.p_max - desc.p_min; v2 dim = desc.p_max - desc.p_min;
if (dim.x == 0 || dim.y == 0) return result; if (dim.x == 0 || dim.y == 0) return result;
@ -427,9 +488,10 @@ ui_widget_push(UI* ui, UI_Widget_Desc desc)
} }
internal void internal void
ui_widget_pop(UI* ui, UI_Widget* widget) ui_widget_pop(UI* ui, UI_Widget_Id widget_id)
{ {
assert(ui_widget_id_equals(widget->id, ui->widgets.active_parent->id)); if (!ui_widget_id_is_valid(widget_id)) return;
assert(ui_widget_id_equals(widget_id, ui->widgets.active_parent->id));
ui_widget_pool_pop(&ui->widgets); ui_widget_pool_pop(&ui->widgets);
} }
@ -475,7 +537,9 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s
if (has_flag(child->desc.style.flags, (UIWidgetStyle_FillH | UIWidgetStyle_FillV))) if (has_flag(child->desc.style.flags, (UIWidgetStyle_FillH | UIWidgetStyle_FillV)))
{ {
v3 fill_min = {}; v3 fill_min = {};
zero_struct(fill_min);
v3 fill_max = {}; v3 fill_max = {};
zero_struct(fill_max);
if (has_flag(child->desc.style.flags, UIWidgetStyle_FillH)) if (has_flag(child->desc.style.flags, UIWidgetStyle_FillH))
{ {
r32 fill_x = HMM_Lerp(bg_min.x, child->desc.fill_pct.x, bg_max.x); r32 fill_x = HMM_Lerp(bg_min.x, child->desc.fill_pct.x, bg_max.x);
@ -523,6 +587,7 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s
{ {
u8 at = child->desc.string.str[i]; u8 at = child->desc.string.str[i];
UI_Char_Draw_Cmd cmd = {}; UI_Char_Draw_Cmd cmd = {};
zero_struct(cmd);
if (!char_is_space(at)) if (!char_is_space(at))
{ {
cmd = ui_sprite_char_get_draw_cmd(ui, baseline, (u32)at); cmd = ui_sprite_char_get_draw_cmd(ui, baseline, (u32)at);
@ -616,8 +681,9 @@ internal UI_Layout_Bounds
ui_layout_get_next(UI_Layout* layout) ui_layout_get_next(UI_Layout* layout)
{ {
UI_Layout_Bounds result = {}; UI_Layout_Bounds result = {};
zero_struct(result);
if (layout->at.x >= layout->bounds_max.x || layout->at.y >= layout->bounds_max.y || if (layout->at.x >= layout->bounds_max.x || layout->at.y >= layout->bounds_max.y ||
layout->at.y + layout->row_height >= layout->bounds_max.y) layout->at.y + layout->row_height > layout->bounds_max.y)
{ {
return result; return result;
} }
@ -653,8 +719,8 @@ ui_layout_get_next(UI_Layout* layout)
if (result.min.x < layout->bounds_min.x || result.min.y < layout->bounds_min.y || if (result.min.x < layout->bounds_min.x || result.min.y < layout->bounds_min.y ||
result.max.x < layout->bounds_min.x || result.max.y < layout->bounds_min.y) result.max.x < layout->bounds_min.x || result.max.y < layout->bounds_min.y)
{ {
result.min = {}; zero_struct(result.min);
result.max = {}; zero_struct(result.max);
} }
return result; return result;
@ -716,26 +782,40 @@ ui_layout_next_widget(UI* ui, UI_Widget_Kind kind)
{ {
UI_Layout_Bounds b = ui_layout_get_next(ui); UI_Layout_Bounds b = ui_layout_get_next(ui);
UI_Widget_Desc d = {}; UI_Widget_Desc d = {};
zero_struct(d);
d.p_min = b.min; d.p_min = b.min;
d.p_max = b.max; d.p_max = b.max;
d.style = ui_get_style(ui, kind); d.style = ui_get_style(ui, kind);
return d; return d;
} }
internal void
ui_text(UI* ui, String string, v4 color)
{
UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Text);
d.string = string;
d.style.color_fg = color;
UI_Widget_Result r = ui_widget_push(ui, d);
ui_widget_pop(ui, r.id);
}
internal void internal void
ui_text(UI* ui, String string) ui_text(UI* ui, String string)
{ {
UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Text); UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Text);
d.string = string; d.string = string;
ui_widget_push(ui, d); UI_Widget_Result r = ui_widget_push(ui, d);
ui_widget_pop(ui, r.id);
} }
internal void internal void
ui_text_f(UI* ui, char* fmt, ...) ui_text_f(UI* ui, char* fmt, ...)
{ {
scratch_get(scratch);
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
String string = string_fv(scratch, fmt, args); String string = string_fv(scratch.a, fmt, args);
va_end(args); va_end(args);
return ui_text(ui, string); return ui_text(ui, string);
@ -747,6 +827,7 @@ ui_button(UI* ui, String string)
UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Button); UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Button);
d.string = string; d.string = string;
UI_Widget_Result r = ui_widget_push(ui, d); UI_Widget_Result r = ui_widget_push(ui, d);
ui_widget_pop(ui, r.id);
return has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp); return has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp);
} }
@ -761,6 +842,7 @@ ui_toggle(UI* ui, String string, bool value)
} }
d.string = string; d.string = string;
UI_Widget_Result r = ui_widget_push(ui, d); UI_Widget_Result r = ui_widget_push(ui, d);
ui_widget_pop(ui, r.id);
bool result = value; bool result = value;
if (has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp)) result = !result; if (has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp)) result = !result;
return result; return result;
@ -769,6 +851,8 @@ ui_toggle(UI* ui, String string, bool value)
internal UI_Layout* internal UI_Layout*
ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 rows) ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 rows)
{ {
scratch_get(scratch);
r32 scroll_bar_dim = 15; r32 scroll_bar_dim = 15;
v2 scroll_bars_area = v2{0, 0}; v2 scroll_bars_area = v2{0, 0};
v2 scroll_area_min = bounds_min; v2 scroll_area_min = bounds_min;
@ -776,6 +860,7 @@ ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 ro
v2 scroll_area_dim = scroll_area_max - scroll_area_min; v2 scroll_area_dim = scroll_area_max - scroll_area_min;
v2 scroll_offset = {}; v2 scroll_offset = {};
zero_struct(scroll_offset);
r32 rows_avail = floorf(scroll_area_dim.y / ui->layout->row_height); r32 rows_avail = floorf(scroll_area_dim.y / ui->layout->row_height);
if (rows > rows_avail) if (rows > rows_avail)
{ {
@ -785,11 +870,13 @@ ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 ro
scroll_area_dim = scroll_area_max - scroll_area_min; scroll_area_dim = scroll_area_max - scroll_area_min;
UI_Widget_Desc vscroll_d = {}; UI_Widget_Desc vscroll_d = {};
zero_struct(vscroll_d);
vscroll_d.p_min = { bounds_max.x - scroll_bar_dim, bounds_min.y }; vscroll_d.p_min = { bounds_max.x - scroll_bar_dim, bounds_min.y };
vscroll_d.p_max = { bounds_max.x, bounds_max.y }; vscroll_d.p_max = { bounds_max.x, bounds_max.y };
vscroll_d.style = ui_get_style(ui, UIWidget_VScroll); vscroll_d.style = ui_get_style(ui, UIWidget_VScroll);
vscroll_d.string = string_f(scratch, "%.*s_vscroll", str_varg(string)); vscroll_d.string = string_f(scratch.a, "%.*s_vscroll", str_varg(string));
UI_Widget_Result r = ui_widget_push(ui, vscroll_d); UI_Widget_Result r = ui_widget_push(ui, vscroll_d);
ui_widget_pop(ui, r.id);
UI_Widget_State* vscroll_state = ui_widget_state_get(ui, r.id); UI_Widget_State* vscroll_state = ui_widget_state_get(ui, r.id);
scroll_offset.y = vscroll_state->scroll.y; scroll_offset.y = vscroll_state->scroll.y;
@ -800,7 +887,7 @@ ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 ro
scroll_offset *= v2{ 0, y_scroll_dist }; scroll_offset *= v2{ 0, y_scroll_dist };
UI_Layout* layout = allocator_alloc_struct(scratch, UI_Layout); UI_Layout* layout = allocator_alloc_struct(scratch.a, UI_Layout);
layout->mode = UILayout_Columns; layout->mode = UILayout_Columns;
layout->bounds_min = scroll_area_min; layout->bounds_min = scroll_area_min;
layout->bounds_max = scroll_area_max; layout->bounds_max = scroll_area_max;

View File

@ -165,15 +165,11 @@ struct UI_Layout_Bounds
v2 max; v2 max;
}; };
typedef void UI_Draw_Panel_Cb(u8* user_data, BSP_Node_Id id, BSP_Node node, BSP_Area area);
struct UI struct UI
{ {
UI_Vertex* verts; Geo_Quad_Buffer_Builder geo;
u32 verts_len;
u32 verts_cap;
u32* indices;
u32 indices_len;
u32 indices_cap;
Texture_Atlas atlas; Texture_Atlas atlas;
r32 font_ascent, font_descent, font_line_gap, font_space_width; r32 font_ascent, font_descent, font_line_gap, font_space_width;
@ -186,6 +182,10 @@ struct UI
UI_Layout* layout; UI_Layout* layout;
BSP panels;
UI_Draw_Panel_Cb* draw_panel_cb;
u8* draw_panel_cb_data;
// frames since these values were set // frames since these values were set
u16 widget_next_hot_frames; u16 widget_next_hot_frames;
u16 widget_hot_frames; u16 widget_hot_frames;
@ -206,7 +206,7 @@ internal void ui_sprite_register(UI* ui, u8* pixels, u32 w, u32 h, u32 id);
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color); internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color);
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id); internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id);
internal v3 ui_sprite_char_push(UI* ui, v2 at, u32 codepoint, v4 color); internal v3 ui_sprite_char_push(UI* ui, v2 at, u32 codepoint, v4 color);
internal void ui_draw(UI* ui); internal void ui_draw(App_State* state);
// Widgets // Widgets
@ -223,7 +223,7 @@ internal UI_Widget* ui_widget_pool_push(UI_Widget_Pool* pool, String string);
internal void ui_widget_pool_pop(UI_Widget_Pool* pool); internal void ui_widget_pool_pop(UI_Widget_Pool* pool);
internal UI_Widget_Result ui_widget_push(UI* ui, UI_Widget_Desc desc); internal UI_Widget_Result ui_widget_push(UI* ui, UI_Widget_Desc desc);
internal void ui_widget_pop(UI* ui, UI_Widget* widget); internal void ui_widget_pop(UI* ui, UI_Widget_Id widget_id);
internal r32 ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_step); internal r32 ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_step);

View File

@ -18,7 +18,7 @@ en_frame_prepare(App_State* state)
internal void internal void
en_frame(App_State* state) en_frame(App_State* state)
{ {
#if 0
/////////////////////////////////////// ///////////////////////////////////////
// Output Data // Output Data
@ -65,6 +65,7 @@ en_frame(App_State* state)
invalid_code_path; invalid_code_path;
} }
} }
#endif
} }
internal void internal void

View File

@ -100,3 +100,22 @@ assembly_add_led(
assert(strip->pixels_len < strip->pixels_cap); assert(strip->pixels_len < strip->pixels_cap);
strip->pixels[strip->pixels_len++] = pixel_index; strip->pixels[strip->pixels_len++] = pixel_index;
} }
void
assembly_strip_create_leds(
Assembly_Array* a,
Assembly_Handle h,
Assembly_Strip* strip,
v3 start, v3 end,
u32 led_count
){
v3 delta_total = end - start;
v3 delta_step = delta_total / (r32)led_count;
for (u32 i = 0; i < led_count; i++)
{
v4 pos = {0,0,0,1};
pos.XYZ = start + ((r32)i * delta_step);
assembly_add_led(a, h, strip, pos);
}
}

1906
src_v2/libs/stb_sprintf.h Normal file

File diff suppressed because it is too large Load Diff

492
src_v2/lumenarium_bsp.h Normal file
View File

@ -0,0 +1,492 @@
/* date = April 11th 2022 9:57 am */
#ifndef LUMENARIUM_BSP_H
#define LUMENARIUM_BSP_H
// NOTE(PS): Functionality Notes
// - there must always be a root node that contains the area of the tree as a whole
// - a node with no children has not been split
#define BTREE_NODE_ID_VALID_BIT (1 << 31)
struct BSP_Node_Id
{
u32 value;
};
enum BSP_Split_Kind
{
BSPSplit_XAxis = 1,
BSPSplit_YAxis = 0,
BSPSplit_ZAxis = 2,
BSPSplit_None = 3,
};
struct BSP_Split
{
BSP_Split_Kind kind;
r32 value;
};
enum BSP_Split_Update_Flags
{
BSPSplitUpdate_None = 0,
BSPSplitUpdate_FreeZeroAreaChildren = 1,
};
enum BSP_Child_Selector
{
// NOTE(PS): these values are intentionally overlapping since
// they access the data structure of the B-Tree in a particular
// way. ie. left and top are the same space in memory as are
// right and bottom
BSPChild_Left = 0,
BSPChild_Top = 0,
BSPChild_Right = 1,
BSPChild_Bottom = 1,
};
struct BSP_Area
{
v2 min;
v2 max;
};
struct BSP_Node
{
union
{
BSP_Node_Id parent;
BSP_Node_Id next_free;
};
BSP_Split split;
union
{
BSP_Node_Id children[2];
struct
{
union
{
BSP_Node_Id left;
BSP_Node_Id top;
};
union
{
BSP_Node_Id right;
BSP_Node_Id bottom;
};
};
};
u32 user_data;
BSP_Area area;
};
struct BSP
{
BSP_Node* nodes;
u32 nodes_cap;
u32 nodes_len;
BSP_Node_Id root;
BSP_Node_Id free_first;
};
typedef void BSP_Walk_Cb(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data);
internal BSP bsp_create(Allocator* allocator, u32 cap);
internal BSP_Node* bsp_get(BSP* tree, BSP_Node_Id id);
internal BSP_Node_Id bsp_push(BSP* tree, BSP_Node_Id parent, BSP_Area area, u32 user_data);
internal void bsp_free(BSP* tree, BSP_Node_Id id);
internal void bsp_free_cb(BSP* tree, BSP_Node_Id id, BSP* node, u8* user_data);
union BSP_Split_Result
{
BSP_Node_Id children[2];
struct
{
union
{
BSP_Node_Id left;
BSP_Node_Id top;
};
union
{
BSP_Node_Id right;
BSP_Node_Id bottom;
};
};
};
internal BSP_Split_Result bsp_split(BSP* tree, BSP_Node_Id id, r32 split, BSP_Split_Kind kind, u32 user_data_0, u32 user_data_1);
internal void bsp_join_recursive(BSP* tree, BSP_Node* parent, BSP_Child_Selector keep);
// left, parent, right
internal void bsp_walk_inorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* cb, u8* user_data);
// parent, left right
internal void bsp_walk_preorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* cb, u8* user_data);
// parent, right, parent
internal void bsp_walk_postorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* cb, u8* user_data);
internal void bsp_node_update_child_areas(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data);
internal void bsp_node_area_update(BSP* tree, BSP_Node_Id id, BSP_Area new_area);
internal void bsp_child_split_update(BSP* tree, BSP_Node_Id node, u32 new_split);
///////////////////////////////////////////////////
// IMPLEMENTATION
internal BSP
bsp_create(Allocator* allocator, u32 cap)
{
BSP result = {};
zero_struct(result);
result.nodes_cap = cap;
result.nodes = allocator_alloc_array(allocator, BSP_Node, cap);
return result;
}
#define bsp_node_id_is_valid(id) (has_flag(id.value, BTREE_NODE_ID_VALID_BIT))
#define bsp_node_id_equals(a,b) (a.value == b.value)
#define bsp_node_id_to_index(id) (id.value & (u32)(~BTREE_NODE_ID_VALID_BIT))
internal BSP_Node*
bsp_get(BSP* tree, BSP_Node_Id id)
{
if (!bsp_node_id_is_valid(id)) return 0;
u32 index = bsp_node_id_to_index(id);
if (index > tree->nodes_len) return 0;
return tree->nodes + index;
}
internal BSP_Node_Id
bsp_push(BSP* tree, BSP_Node_Id parent_id, BSP_Area area, u32 user_data)
{
BSP_Node_Id result = BSP_Node_Id{0};
BSP_Node* node = 0;
if (tree->nodes_len >= tree->nodes_cap)
{
if (bsp_node_id_is_valid(tree->free_first))
{
result = tree->free_first;
node = bsp_get(tree, result);
tree->free_first = node->next_free;
zero_struct(node->parent);
}
}
else
{
result.value = tree->nodes_len++;
assert(!has_flag(result.value, BTREE_NODE_ID_VALID_BIT));
add_flag(result.value, BTREE_NODE_ID_VALID_BIT);
node = tree->nodes + bsp_node_id_to_index(result);
}
if (bsp_node_id_is_valid(result))
{
node->split.kind = BSPSplit_None;
node->parent = parent_id;
node->area = area;
node->user_data = user_data;
}
return result;
}
internal void
bsp_free_(BSP* tree, BSP_Node_Id id, BSP_Node* now_free)
{
if (bsp_node_id_is_valid(now_free->parent))
{
BSP_Node* parent = bsp_get(tree, now_free->parent);
if (bsp_node_id_equals(parent->children[0], id))
{
zero_struct(parent->children[0]);
}
else if (bsp_node_id_equals(parent->children[1], id))
{
zero_struct(parent->children[1]);
}
else
{
// NOTE(PS): in this case, a child node had a reference to
// a parent that didn't have a reference back to the child
// this means the tree itself is messed up
invalid_code_path;
}
}
zero_struct(*now_free);
now_free->next_free = tree->free_first;
tree->free_first = id;
}
internal void
bsp_free(BSP* tree, BSP_Node_Id id)
{
BSP_Node* now_free = bsp_get(tree, id);
bsp_free_(tree, id, now_free);
}
internal void
bsp_free_cb(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data)
{
bsp_free_(tree, id, node);
}
internal BSP_Split_Result
bsp_split(BSP* tree, BSP_Node_Id node_id, r32 split, BSP_Split_Kind kind, u32 user_data_0, u32 user_data_1)
{
BSP_Node* node = bsp_get(tree, node_id);
split = clamp(node->area.min.Elements[kind], split, node->area.max.Elements[kind]);
node->split.value = split;
node->split.kind = kind;
node->children[0] = bsp_push(tree, node_id, {}, user_data_0);
node->children[1] = bsp_push(tree, node_id, {}, user_data_1);
bsp_node_update_child_areas(tree, node_id, node, 0);
BSP_Split_Result result = {};
result.children[0] = node->children[0];
result.children[1] = node->children[1];
return result;
}
internal void
bsp_join_recursive(BSP* tree, BSP_Node_Id parent_id, BSP_Child_Selector keep)
{
BSP_Node* parent = bsp_get(tree, parent_id);
BSP_Node keep_node = *bsp_get(tree, parent->children[keep]);
bsp_walk_preorder(tree, parent->children[0], bsp_free_cb, 0);
bsp_walk_preorder(tree, parent->children[1], bsp_free_cb, 0);
parent->user_data = keep_node.user_data;
zero_struct(parent->children[0]);
zero_struct(parent->children[1]);
}
// NOTE(PS): the other three walk functions all require allocation of a stack
// while this is fast with our scratch allocator, there are cases where, for
// correctness, we walk a tree that is very likely to be a single node. In
// those cases, we can avoid allocating anything by just visiting the single
// node and returning early.
// This function provides that functionality for all walk functions
internal bool
bsp_walk_single_node_check(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_data)
{
BSP_Node* node = bsp_get(tree, first);
if (node->split.kind == BSPSplit_None)
{
visit(tree, first, node, user_data);
return true;
}
return false;
}
// left, parent, right
internal void
bsp_walk_inorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_data)
{
if (!bsp_node_id_is_valid(first)) return;
if (bsp_walk_single_node_check(tree, first, visit, user_data)) return;
scratch_get(scratch);
BSP_Node_Id* stack = allocator_alloc_array(scratch.a, BSP_Node_Id, tree->nodes_len);
u32 stack_len = 0;
memory_zero_array(stack, BSP_Node_Id, tree->nodes_len);
BSP_Node_Id at = first;
while (true)
{
if (bsp_node_id_is_valid(at))
{
stack[stack_len++] = at;
BSP_Node* n = bsp_get(tree, at);
at = n->children[0];
}
else
{
if (stack_len == 0) break;
at = stack[--stack_len];
BSP_Node* n = bsp_get(tree, at);
visit(tree, at, n, user_data);
at = n->children[1];
}
}
}
// parent, left right
internal void
bsp_walk_preorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_data)
{
if (bsp_walk_single_node_check(tree, first, visit, user_data)) return;
scratch_get(scratch);
BSP_Node_Id* stack = allocator_alloc_array(scratch.a, BSP_Node_Id, tree->nodes_len);
u32 stack_len = 0;
memory_zero_array(stack, BSP_Node_Id, tree->nodes_len);
BSP_Node_Id at = first;
while (true)
{
while (bsp_node_id_is_valid(at))
{
BSP_Node* n = bsp_get(tree, at);
visit(tree, at, n, user_data);
stack[stack_len++] = at;
at = n->children[0];
}
if (!bsp_node_id_is_valid(at) && stack_len == 0) break;
at = stack[--stack_len];
BSP_Node* n = bsp_get(tree, at);
at = n->children[1];
}
}
// parent, right, parent
internal void
bsp_walk_postorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_data)
{
if (bsp_walk_single_node_check(tree, first, visit, user_data)) return;
scratch_get(scratch);
BSP_Node_Id* stack = allocator_alloc_array(scratch.a, BSP_Node_Id, tree->nodes_len);
u32 stack_len = 0;
memory_zero_array(stack, BSP_Node_Id, tree->nodes_len);
BSP_Node_Id at = first;
while (true)
{
if (bsp_node_id_is_valid(at))
{
BSP_Node* n = bsp_get(tree, at);
if (bsp_node_id_is_valid(n->children[1])) stack[stack_len++] = n->children[1];
stack[stack_len++] = at;
at = n->children[0];
}
else
{
if (stack_len == 0) break;
at = stack[--stack_len];
BSP_Node* n = bsp_get(tree, at);
assert(n != 0);
if (bsp_node_id_is_valid(n->children[1]) && bsp_node_id_equals(n->children[1], stack[stack_len - 1]))
{
BSP_Node_Id at_temp = stack[stack_len - 1];
stack[stack_len - 1] = at;
at = at_temp;
}
else
{
visit(tree, at, n, user_data);
zero_struct(at);
}
}
}
}
internal void
bsp_node_update_child_areas(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data)
{
// assume that node's area is correct. Using that, clamp its split as appropriate
// and then update its children. If a child has an area of zero, rely on flags
// to determine behavior
if (node->split.kind == BSPSplit_None) return;
BSP_Split_Update_Flags flags = (BSP_Split_Update_Flags)0;
if (user_data) flags = *(BSP_Split_Update_Flags*)user_data;
BSP_Split_Kind kind = node->split.kind;
BSP_Node* node_min = bsp_get(tree, node->children[0]);
BSP_Node* node_max = bsp_get(tree, node->children[1]);
node_min->area = node->area;
node_max->area = node->area;
node_min->area.max.Elements[kind] = node->split.value;
node_max->area.min.Elements[kind] = node->split.value;
if (has_flag(flags, BSPSplitUpdate_FreeZeroAreaChildren))
{
bool free_children = false;
if (node_min->area.max.Elements[kind] <= node_min->area.min.Elements[kind])
{
node->user_data = node_max->user_data;
free_children= true;
}
else if (node_max->area.max.Elements[kind] <= node_max->area.min.Elements[kind])
{
node->user_data = node_min->user_data;
free_children= true;
}
if (free_children)
{
bsp_walk_postorder(tree, node->children[0], bsp_free_cb, 0);
bsp_walk_postorder(tree, node->children[1], bsp_free_cb, 0);
}
}
// NOTE(PS): no need to recurse, this function assumes its either being
// called on a particular node or its the callback of one of the tree
// walk functions
}
internal void
bsp_node_area_update(BSP* tree, BSP_Node_Id node_id, BSP_Area area)
{
BSP_Node* node = bsp_get(tree, node_id);
node->area = area;
BSP_Split_Update_Flags flags = BSPSplitUpdate_FreeZeroAreaChildren;
bsp_walk_preorder(tree, node_id, bsp_node_update_child_areas, (u8*)&flags);
}
internal void
bsp_child_split_update(BSP* tree, BSP_Node_Id node_id, r32 new_split, BSP_Split_Update_Flags flags)
{
BSP_Node* node = bsp_get(tree, node_id);
node->split.value = new_split;
bsp_walk_preorder(tree, node_id, bsp_node_update_child_areas, (u8*)&flags);
}
#if defined(DEBUG)
internal void
bsp_tests()
{
scratch_get(scratch);
BSP tree = bsp_create(scratch.a, 256);
tree.root = bsp_push(&tree, {0}, {{0,0},{512,512}}, 0);
BSP_Split_Result r0 = bsp_split(&tree, tree.root, 256, BSPSplit_YAxis, 0, 0);
BSP_Node* root = bsp_get(&tree, tree.root);
BSP_Node* n0 = bsp_get(&tree, r0.children[0]);
BSP_Node* n1 = bsp_get(&tree, r0.children[1]);
assert(root != 0 && n0 != 0 && n1 != 0);
assert(n0->area.min == root->area.min);
assert(n0->area.max.x == 256 && n0->area.max.y == root->area.max.y);
assert(n1->area.max == root->area.max);
assert(n1->area.min.x == 256 && n0->area.min.y == root->area.min.y);
assert(n0->split.kind == BSPSplit_None);
assert(n1->split.kind == BSPSplit_None);
assert(root->split.kind == BSPSplit_YAxis);
BSP_Split_Result r1 = bsp_split(&tree, root->children[0], 32, BSPSplit_YAxis, 0, 0);
BSP_Split_Result r2 = bsp_split(&tree, r1.children[1], 64, BSPSplit_XAxis, 0, 0);
bsp_walk_postorder(&tree, root->children[0], bsp_free_cb, 0);
}
#else
#define bsp_tests()
#endif
#endif //LUMENARIUM_BSP_H

View File

@ -6,12 +6,12 @@ lumenarium_init()
{ {
App_State* state = 0; App_State* state = 0;
permanent = bump_allocator_create_reserve(GB(1)); permanent = bump_allocator_create_reserve(GB(2));
scratch = bump_allocator_create_reserve(KB(64)); scratch_ = bump_allocator_create_reserve(GB(8));
platform_file_jobs_init(); platform_file_jobs_init();
run_tests(); run_tests();
scratch_get(scratch);
App_Init_Desc desc = incenter_get_init_desc(); App_Init_Desc desc = incenter_get_init_desc();
// TODO(PS): make sure the values make sense in desc // TODO(PS): make sure the values make sense in desc
@ -21,6 +21,13 @@ lumenarium_init()
state->input_state = input_state_create(permanent); state->input_state = input_state_create(permanent);
String exe_file_path = platform_get_exe_path(scratch.a);
u64 run_tree_start = string_find_substring(exe_file_path, lit_str("run_tree"), 0, StringMatch_FindLast);
u64 run_tree_end = run_tree_start + lit_str("run_tree").len;
String run_tree_path = string_get_prefix(exe_file_path, run_tree_end);
String run_tree_path_nullterm = string_copy(run_tree_path, scratch.a);
platform_pwd_set(run_tree_path_nullterm);
en_init(state, desc); en_init(state, desc);
if (has_flag(state->flags, AppState_RunEditor)) if (has_flag(state->flags, AppState_RunEditor))
{ {
@ -33,7 +40,7 @@ lumenarium_init()
internal void internal void
lumenarium_frame_prepare(App_State* state) lumenarium_frame_prepare(App_State* state)
{ {
allocator_clear(scratch); allocator_clear(scratch_);
input_state_swap_frames(state->input_state); input_state_swap_frames(state->input_state);
@ -50,7 +57,7 @@ lumenarium_frame_prepare(App_State* state)
internal void internal void
lumenarium_frame(App_State* state) lumenarium_frame(App_State* state)
{ {
//en_frame(state); en_frame(state);
if (has_flag(state->flags, AppState_RunEditor)) if (has_flag(state->flags, AppState_RunEditor))
{ {
ed_frame(state); ed_frame(state);

View File

@ -8,9 +8,17 @@ typedef struct App_State App_State;
// Environment // Environment
#include "lumenarium_memory.cpp" #include "lumenarium_memory.cpp"
#include "lumenarium_string.cpp" #include "lumenarium_string.cpp"
#include "lumenarium_random.h"
#include "lumenarium_input.cpp" #include "lumenarium_input.cpp"
#include "lumenarium_texture_atlas.cpp" #include "lumenarium_texture_atlas.cpp"
#include "lumenarium_hash.cpp" #include "lumenarium_hash.cpp"
#include "lumenarium_geometry.h"
global Allocator* scratch_; // gets reset at frame boundaries
#define scratch_get(ident) Allocator_Scratch ident = Allocator_Scratch(scratch_)
#include "lumenarium_bsp.h"
// Engine // Engine
typedef struct Assembly_Strip Assembly_Strip; typedef struct Assembly_Strip Assembly_Strip;
@ -28,7 +36,6 @@ typedef struct Assembly_Strip Assembly_Strip;
// Lumenarium Runtime Environment // Lumenarium Runtime Environment
global Allocator* permanent; global Allocator* permanent;
global Allocator* scratch; // gets reset at frame boundaries
#if defined(DEBUG) #if defined(DEBUG)
# include "lumenarium_tests.cpp" # include "lumenarium_tests.cpp"
@ -72,6 +79,7 @@ struct App_State
#include "editor/lumenarium_editor_ui.cpp" #include "editor/lumenarium_editor_ui.cpp"
#include "editor/lumenarium_editor_renderer.cpp" #include "editor/lumenarium_editor_renderer.cpp"
#include "editor/lumenarium_editor_sculpture_visualizer.cpp"
#include "editor/lumenarium_editor.cpp" #include "editor/lumenarium_editor.cpp"

View File

@ -0,0 +1,268 @@
/* date = April 11th 2022 3:22 pm */
#ifndef LUMENARIUM_GEOMETRY_H
#define LUMENARIUM_GEOMETRY_H
// Utility functions for working with 3d geometry
// NOTE(PS): the Buffer vs Buffer_Builder distinction
// lets a static sized buffer exist, and be auto 'exported' or 'available'
// from a larger data structure that also stores enough data to incrementally
// build the buffer
// NOTE(PS): @IMPORTANT!!!
// at the moment this builder doesn't support allowing for the elements
// of a vertex to be in an order other than position tex color
// and in any other packing than tightly packed
typedef u32 Geo_Vertex_Buffer_Storage;
enum
{
GeoVertexBufferStorage_None = 0,
GeoVertexBufferStorage_Position = 1,
GeoVertexBufferStorage_TexCoord = 2,
GeoVertexBufferStorage_Color = 4
};
struct Geo_Vertex_Buffer
{
r32* values;
u32 len;
Geo_Vertex_Buffer_Storage storage;
u32 stride;
};
struct Geo_Vertex_Buffer_Builder
{
union
{
Geo_Vertex_Buffer buffer;
struct
{
// NOTE(PS): @Maintainence
// this must always match the layout of Geo_Vertex_Buffer
r32* values;
u32 len;
Geo_Vertex_Buffer_Storage storage;
u32 stride;
};
};
u32 cap;
};
struct Geo_Index_Buffer
{
u32* values;
u32 len;
};
struct Geo_Index_Buffer_Builder
{
union
{
Geo_Index_Buffer buffer;
struct
{
// NOTE(PS): @Maintainence
// this must always match the layout of Geo_Index_Buffer
u32* values;
u32 len;
};
};
u32 cap;
};
struct Geo_Quad_Buffer
{
Geo_Vertex_Buffer buffer_vertex;
Geo_Index_Buffer buffer_index;
};
struct Geo_Quad_Buffer_Builder
{
Geo_Vertex_Buffer_Builder buffer_vertex;
Geo_Index_Buffer_Builder buffer_index;
};
internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap);
internal Geo_Index_Buffer_Builder geo_index_buffer_builder_create(Allocator* a, u32 cap);
internal Geo_Quad_Buffer_Builder geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, u32 index_cap);
// Vertex Buffer
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c);
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t);
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v);
// Index Buffer
internal u32 geo_index_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, u32 i);
internal void geo_index_buffer_builder_push_tri(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2);
internal void geo_index_buffer_builder_push_quad(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3);
// Quad Buffer
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c);
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3);
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3);
internal Geo_Quad_Buffer geo_quad_buffer_builder_get_static_buffer(Geo_Quad_Buffer_Builder* b);
/////////////////////////////////////////////
// Implementation
internal u32
geo_vertex_buffer_builder_stride(Geo_Vertex_Buffer_Storage storage)
{
u32 result = 0;
result += has_flag(storage, GeoVertexBufferStorage_Position) ? 3 : 0;
result += has_flag(storage, GeoVertexBufferStorage_TexCoord) ? 2 : 0;
result += has_flag(storage, GeoVertexBufferStorage_Color) ? 4 : 0;
return result;
}
internal Geo_Vertex_Buffer_Builder
geo_vertex_buffer_builder_create(Allocator* a, u32 cap, Geo_Vertex_Buffer_Storage storage)
{
u32 stride = geo_vertex_buffer_builder_stride(storage);
u32 size = cap * stride;
Geo_Vertex_Buffer_Builder result = {};
zero_struct(result);
result.cap = cap;
result.storage = storage;
result.stride = stride;
result.values = allocator_alloc_array(a, r32, size);
return result;
}
internal Geo_Index_Buffer_Builder
geo_index_buffer_builder_create(Allocator* a, u32 cap)
{
Geo_Index_Buffer_Builder result = {};
zero_struct(result);
result.cap = cap;
result.values = allocator_alloc_array(a, u32, cap);
return result;
}
internal Geo_Quad_Buffer_Builder
geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, Geo_Vertex_Buffer_Storage storage, u32 index_cap)
{
Geo_Quad_Buffer_Builder result = {};
result.buffer_vertex = geo_vertex_buffer_builder_create(a, vertex_cap, storage);
result.buffer_index = geo_index_buffer_builder_create(a, index_cap);
return result;
}
// Vertex Buffer
internal u32
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c)
{
assert(b->len < b->cap);
u32 result = b->len++;
u32 offset = result * b->stride;
if (has_flag(b->storage, GeoVertexBufferStorage_Position))
{
b->values[offset++] = v.x;
b->values[offset++] = v.y;
b->values[offset++] = v.z;
}
if (has_flag(b->storage, GeoVertexBufferStorage_TexCoord))
{
b->values[offset++] = t.x;
b->values[offset++] = t.y;
}
if (has_flag(b->storage, GeoVertexBufferStorage_Color))
{
b->values[offset++] = c.x;
b->values[offset++] = c.y;
b->values[offset++] = c.z;
b->values[offset++] = c.w;
}
return result;
}
internal u32
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t)
{
return geo_vertex_buffer_builder_push(b, v, t, v4{0});
}
internal u32
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v)
{
return geo_vertex_buffer_builder_push(b, v, v2{0}, v4{0});
}
// Index Buffer
internal u32
geo_index_buffer_builder_push(Geo_Index_Buffer_Builder* b, u32 i)
{
assert(b->len < b->cap);
u32 result = b->len++;
b->values[result] = i;
return result;
}
internal void
geo_index_buffer_builder_push_tri(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2)
{
geo_index_buffer_builder_push(b, i0);
geo_index_buffer_builder_push(b, i1);
geo_index_buffer_builder_push(b, i2);
}
internal void
geo_index_buffer_builder_push_quad(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3)
{
geo_index_buffer_builder_push_tri(b, i0, i1, i2);
geo_index_buffer_builder_push_tri(b, i0, i2, i3);
}
// Quad Buffer
internal void
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c)
{
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, c);
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, c);
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, c);
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, c);
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
}
internal void
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3)
{
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, v4{});
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, v4{});
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, v4{});
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, v4{});
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
}
internal void
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3)
{
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, v2{}, v4{});
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, v2{}, v4{});
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, v2{}, v4{});
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, v2{}, v4{});
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
}
internal Geo_Quad_Buffer
geo_quad_buffer_builder_get_static_buffer(Geo_Quad_Buffer_Builder* b)
{
Geo_Quad_Buffer result = {};
result.buffer_vertex = b->buffer_vertex.buffer;
result.buffer_index = b->buffer_index.buffer;
return result;
}
#endif //LUMENARIUM_GEOMETRY_H

View File

@ -195,6 +195,16 @@ bump_allocator_destroy(Allocator* allocator)
allocator_destroy_(allocator, sizeof(Allocator_Bump)); allocator_destroy_(allocator, sizeof(Allocator_Bump));
} }
internal void
bump_allocator_rewind(Allocator* allocator, u64 to_point)
{
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
#if defined(DEBUG)
memory_zero(bump->base + to_point, bump->at - to_point);
#endif
bump->at = to_point;
}
internal Allocator* internal Allocator*
bump_allocator_create_() bump_allocator_create_()
{ {
@ -248,6 +258,28 @@ bump_allocator_create_child(Allocator* parent, u64 init_size)
return result; return result;
} }
/////////////////////////////////////////
// Scratch Allocator
struct Allocator_Scratch
{
Allocator* a;
u64 at_before;
Allocator_Scratch(Allocator* allocator)
{
this->a = allocator;
Allocator_Bump* bump = (Allocator_Bump*)this->a->allocator_data;
this->at_before = bump->at;
}
~Allocator_Scratch()
{
bump_allocator_rewind(this->a, this->at_before);
}
};
///////////////////////////////////////// /////////////////////////////////////////
// Paged Allocator // Paged Allocator

View File

@ -0,0 +1,47 @@
/* date = April 11th 2022 6:11 pm */
#ifndef LUMENARIUM_RANDOM_H
#define LUMENARIUM_RANDOM_H
struct Random_Series
{
u32 last_value;
};
internal Random_Series
random_series_create(u32 seed)
{
Random_Series result = {};
result.last_value = seed;
return result;
}
internal u32
random_series_next(Random_Series* s)
{
u32 result = s->last_value;
result ^= result << 13;
result ^= result >> 17;
result ^= result << 5;
s->last_value = result;
return result;
}
internal r32
random_series_next_unilateral(Random_Series* s)
{
r32 result = random_series_next(s) / (r32)(0xFFFFFFFF);
return result;
}
internal r32
random_series_next_bilateral(Random_Series* s)
{
r32 result = random_series_next(s) / (r32)(0xFFFFFFFF);
result = (result * 2.0f) - 1.0f;
return result;
}
#endif //LUMENARIUM_RANDOM_H

View File

@ -250,9 +250,9 @@ string_fv(Allocator* a, char* fmt, va_list args)
{ {
va_list args1; va_list args1;
va_copy(args1, args); va_copy(args1, args);
s32 needed = vsnprintf(0, 0, fmt, args); s32 needed = stbsp_vsnprintf(0, 0, fmt, args);
String result = allocator_alloc_string(a, needed + 1); String result = allocator_alloc_string(a, needed + 1);
result.len = vsnprintf((char*)result.str, result.cap, fmt, args1); result.len = stbsp_vsnprintf((char*)result.str, (int)result.cap, fmt, args1);
result.str[result.len] = 0; result.str[result.len] = 0;
va_end(args1); va_end(args1);
return result; return result;

View File

@ -70,7 +70,12 @@ memory_tests()
{ {
// TestGroup("Platform Allocation") // TestGroup("Platform Allocation")
{ {
u8* base = platform_mem_reserve(GB(32)); u64 size = GB(32);
#if defined(PLATFORM_wasm)
size = KB(4);
#endif
u8* base = platform_mem_reserve(size);
platform_mem_commit(base, KB(4)); platform_mem_commit(base, KB(4));
base[4095] = 200; base[4095] = 200;
assert(base[4095] == 200); assert(base[4095] == 200);
@ -85,18 +90,54 @@ memory_tests()
memory_allocator_tests(bump, false); memory_allocator_tests(bump, false);
allocator_destroy(bump); allocator_destroy(bump);
Allocator* paged = paged_allocator_create_reserve(KB(32)); Allocator* paged = paged_allocator_create_reserve(KB(32), KB(4));
memory_allocator_tests(paged, true); memory_allocator_tests(paged, true);
allocator_destroy(paged); allocator_destroy(paged);
} }
enum test_flags
{
TestNone = 0,
Test1 = 1,
Test2 = 2,
Test3 = 4,
Test4 = 8,
};
internal void internal void
run_tests() run_tests()
{ {
scratch_get(scratch);
// basic
u8 b = TestNone;
assert(!has_flag(b, TestNone));
assert(!has_flag(b, Test1));
add_flag(b, Test1);
assert(has_flag(b, Test1));
assert(!has_flag(b, Test2));
add_flag(b, Test2);
assert(has_flag(b, Test1));
assert(has_flag(b, Test2));
assert(has_flag(b, Test1 | Test2));
add_flag(b, Test4);
assert(has_flag(b, Test1));
assert(has_flag(b, Test2));
assert(has_flag(b, Test4));
assert(has_flag(b, Test1 | Test2 | Test4));
assert(!has_flag(b, Test3));
rem_flag(b, Test2);
assert(has_flag(b, Test1));
assert(!has_flag(b, Test2));
assert(has_flag(b, Test4));
assert(has_flag(b, Test1 | Test4));
assert(!has_flag(b, Test3));
// memory tests // memory tests
u8* a0 = allocator_alloc_array(scratch, u8, 32); u8* a0 = allocator_alloc_array(scratch.a, u8, 32);
u8* a1 = allocator_alloc_array(scratch, u8, 32); u8* a1 = allocator_alloc_array(scratch.a, u8, 32);
assert(a0 != a1); assert(a0 != a1);
assert((a0 + 32) <= a1); assert((a0 + 32) <= a1);
@ -113,7 +154,15 @@ run_tests()
assert(a1[i] == (100 + i)); assert(a1[i] == (100 + i));
} }
assert(round_up_to_pow2(1) == 1);
assert(round_up_to_pow2(3) == 4);
assert(round_up_to_pow2(29) == 32);
assert(round_up_to_pow2(32) == 32);
assert(round_up_to_pow2(120) == 128);
memory_tests(); memory_tests();
bsp_tests();
#if defined(PLATFORM_wasm) #if defined(PLATFORM_wasm)
// NOTE(PS): the tests below this point don't make sense on a web assembly // NOTE(PS): the tests below this point don't make sense on a web assembly
@ -123,21 +172,21 @@ run_tests()
// testing strings and exe path // testing strings and exe path
String exe_file_path = platform_get_exe_path(scratch); String exe_file_path = platform_get_exe_path(scratch.a);
assert(exe_file_path.str != 0); assert(exe_file_path.str != 0);
u64 run_tree_start = string_find_substring(exe_file_path, lit_str("run_tree"), 0, StringMatch_FindLast); u64 run_tree_start = string_find_substring(exe_file_path, lit_str("run_tree"), 0, StringMatch_FindLast);
u64 run_tree_end = run_tree_start + lit_str("run_tree").len; u64 run_tree_end = run_tree_start + lit_str("run_tree").len;
assert(run_tree_start < exe_file_path.len); assert(run_tree_start < exe_file_path.len);
String run_tree_path = string_get_prefix(exe_file_path, run_tree_end); String run_tree_path = string_get_prefix(exe_file_path, run_tree_end);
String run_tree_path_nullterm = string_copy(run_tree_path, scratch); String run_tree_path_nullterm = string_copy(run_tree_path, scratch.a);
assert(run_tree_path_nullterm.len > 0); assert(run_tree_path_nullterm.len > 0);
assert(platform_pwd_set(run_tree_path_nullterm)); assert(platform_pwd_set(run_tree_path_nullterm));
// testing file io // testing file io
Platform_File_Handle f = platform_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenExisting); Platform_File_Handle f = platform_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenExisting);
Platform_File_Info i = platform_file_get_info(f, scratch); Platform_File_Info i = platform_file_get_info(f, scratch.a);
Data d0 = platform_file_read_all(f, scratch); Data d0 = platform_file_read_all(f, scratch.a);
assert(d0.size > 0); assert(d0.size > 0);
String s = lit_str("foooooooooobbbbbbaaaarrrrrr"); String s = lit_str("foooooooooobbbbbbaaaarrrrrr");
@ -163,6 +212,4 @@ run_tests()
} }
#endif #endif
allocator_clear(scratch);
} }

View File

@ -37,6 +37,41 @@ typedef s64 b64;
typedef float r32; typedef float r32;
typedef double r64; typedef double r64;
#define u8_max 0xFF
#define u16_max 0xFFFF
#define u32_max 0xFFFFFFFF
#define u64_max 0xFFFFFFFFFFFFFFFF
#define s8_max 127
#define s16_max 32767
#define s32_max 2147483647
#define s64_max 9223372036854775807
#define s8_min -127 - 1
#define s16_min -32767 - 1
#define s32_min -2147483647 - 1
#define s64_min -9223372036854775807 - 1
#define r32_max 3.402823466e+38f
#define r32_min -3.402823466e+38f
#define r32_smallest_positive 1.1754943508e-38f
#define r32_epsilon 5.96046448e-8f
#define r32_pi 3.14159265359f
#define r32_half_pi 1.5707963267f
#define r32_tau 6.28318530717f
#define r64_max 1.79769313486231e+308
#define r64_min -1.79769313486231e+308
#define r64_smallest_positive 4.94065645841247e-324
#define r64_epsilon 1.11022302462515650e-16
#define r64_pi 3.14159265359
#define r64_half_pi 1.5707963267
#define r64_tau 6.28318530717
#define NanosToSeconds 1 / 10000000.0
#define SecondsToNanos 10000000.0
#define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF) #define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF)
struct Data struct Data
@ -54,12 +89,21 @@ data_create(u8* base, u64 size)
return result; return result;
} }
#define memory_zero_array(b,t,c) memory_zero((u8*)(b), sizeof(t) * (c))
internal void memory_zero(u8* base, u64 size); internal void memory_zero(u8* base, u64 size);
internal void memory_copy(u8* from, u8* to, u64 size); internal void memory_copy(u8* from, u8* to, u64 size);
////////////////////////////////////////////// //////////////////////////////////////////////
// Math // Math
#ifndef max
# define max(a,b) (a) > (b) ? (a) : (b)
#endif
#ifndef min
# define min(a,b) (a) > (b) ? (b) : (a)
#endif
#define lerp(a,t,b) (a) + ((1.0f - (t)) * (b)) #define lerp(a,t,b) (a) + ((1.0f - (t)) * (b))
#define clamp(r0,v,r1) min((r1),max((r0),(v))) #define clamp(r0,v,r1) min((r1),max((r0),(v)))
#define lerp_clamp(a,t,b) clamp((a),lerp((a),(t),(b)),(b)) #define lerp_clamp(a,t,b) clamp((a),lerp((a),(t),(b)),(b))
@ -247,6 +291,22 @@ hash_table_find(u32* ids, u32 cap, u32 value)
return result; return result;
} }
//////////////////////////////////////////////
// Math
internal u32
round_up_to_pow2(u32 v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
////////////////////////////////////////////// //////////////////////////////////////////////
// Vector Extensions // Vector Extensions
@ -254,6 +314,15 @@ hash_table_find(u32* ids, u32 cap, u32 value)
#define v2_floor(v) v2{ floorf(v.x), floorf(v.y) } #define v2_floor(v) v2{ floorf(v.x), floorf(v.y) }
#define v3_floor(v) v3{ floorf(v.x), floorf(v.y), floorf(v.z) } #define v3_floor(v) v3{ floorf(v.x), floorf(v.y), floorf(v.z) }
internal bool
rect2_contains(v2 min, v2 max, v2 point)
{
return (
min.x <= point.x && min.y <= point.y &&
max.x >= point.x && max.y >= point.y
);
}
////////////////////////////////////////////// //////////////////////////////////////////////
// Color Constants // Color Constants

View File

@ -85,12 +85,12 @@ bool platform_pwd_set(String path);
typedef u32 Platform_File_Async_Job_Flags; typedef u32 Platform_File_Async_Job_Flags;
enum enum
{ {
PlatformFileAsyncJob_Invalid = 0, PlatformFileAsyncJob_Invalid = 0,
PlatformFileAsyncJob_Read = 1, PlatformFileAsyncJob_Read = 1 << 0,
PlatformFileAsyncJob_Write = 2, PlatformFileAsyncJob_Write = 1 << 1,
PlatformFileAsyncJob_InFlight = 4, PlatformFileAsyncJob_InFlight = 1 << 2,
PlatformFileAsyncJob_Success = 8, PlatformFileAsyncJob_Success = 1 << 3,
PlatformFileAsyncJob_Failed = 16, PlatformFileAsyncJob_Failed = 1 << 4,
}; };
struct Platform_File_Async_Job_Args struct Platform_File_Async_Job_Args

View File

@ -17,6 +17,9 @@
#define STBTT_assert(x) assert(x) #define STBTT_assert(x) assert(x)
#include "../libs/stb_truetype.h" #include "../libs/stb_truetype.h"
#define STB_SPRINTF_IMPLEMENTATION
#include "../libs/stb_sprintf.h"
// NOTE(PS): only need the opengl extension headers // NOTE(PS): only need the opengl extension headers
// when running on a platform that is using opengl 3.3+ // when running on a platform that is using opengl 3.3+
#if !defined(PLATFORM_wasm) #if !defined(PLATFORM_wasm)

View File

@ -9,6 +9,7 @@
#include "../lumenarium_platform_common_includes.h" #include "../lumenarium_platform_common_includes.h"
#include "../../lumenarium_types.h" #include "../../lumenarium_types.h"
#include "../../lumenarium_memory.h"
#include "../lumenarium_platform.h" #include "../lumenarium_platform.h"
#include "../../lumenarium_first.cpp" #include "../../lumenarium_first.cpp"

View File

@ -1,5 +1,6 @@
WASM_EXTERN u32 wasm_fetch(char* file_path, u32 file_path_len, u8* dest, u32 size); WASM_EXTERN u32 wasm_fetch(char* file_path, u32 file_path_len, u8* dest, u32 size);
WASM_EXTERN void wasm_platform_file_async_work_on_job(char* path, u32 path_len, u8* data, u32 data_len, bool read, bool write);
Platform_File_Handle Platform_File_Handle
platform_file_open(String path, Platform_File_Access_Flags flags_access, Platform_File_Create_Flags flags_create) platform_file_open(String path, Platform_File_Access_Flags flags_access, Platform_File_Create_Flags flags_create)
@ -43,3 +44,13 @@ platform_pwd_set(String path)
return false; return false;
} }
void
platform_file_async_work_on_job(Platform_File_Async_Job* job)
{
wasm_platform_file_async_work_on_job(
(char*)job->args.path.str, job->args.path.len,
job->args.data.base, job->args.data.size,
has_flag(job->args.flags, PlatformFileAsyncJob_Read),
has_flag(job->args.flags, PlatformFileAsyncJob_Write)
);
}

View File

@ -92,20 +92,69 @@ var lumenarium_wasm_imports = {
}, },
wasm_mem_grow: (new_size) => { wasm_mem_grow: (new_size) => {
let pages = new_size / WASM_PAGE_SIZE; let new_size_ = new_size >>> 0;
let pages = new_size_ / WASM_PAGE_SIZE;
let pages_rem = fract(pages); let pages_rem = fract(pages);
if (pages_rem > 0) pages = Math.floor(pages) + 1; if (pages_rem > 0) pages = Math.floor(pages) + 1;
let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength; let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength;
let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages); let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages);
console.log("mem_grow\n", console.log("mem_grow\n",
"req size: ", new_size, "\n", "req size: ", new_size_, "\n",
"old size: ", (old_page_count * WASM_PAGE_SIZE), "\n", "old size: ", (old_page_count * WASM_PAGE_SIZE), "\n",
"old size: ", size_before, "\n", "old size: ", size_before, "\n",
"grew by: ", (pages * WASM_PAGE_SIZE), "\n", "grew by: ", (pages * WASM_PAGE_SIZE), "\n",
"new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, ""); "new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, "");
}, },
malloc: (size) => {
},
free: (base) => {
},
sin: Math.sin,
sinf: Math.sin,
cos: Math.cos,
cosf: Math.cos,
tan: Math.tan,
tanf: Math.tan,
asin: Math.asin,
asinf: Math.asin,
acos: Math.acos,
acosf: Math.acos,
atan: Math.atan,
atanf: Math.atan,
pow: Math.pow,
powf: Math.pow,
fmodf: (f,d) => { return f % d; },
strlen: (ptr) => {
let len = 0;
let len_checked = 0;
let len_to_check = 256;
let found_end = false;
while (true)
{
let string = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, len_checked);
for (let i = len_checked; i < len_to_check; i++)
{
if (string[i] == 0)
{
len = i;
break;
}
}
len_checked *= 2;
}
return len_checked;
},
wasm_platform_file_async_work_on_job: (path, path_len, data, data_size, read, write) => {
},
wasm_performance_now: () => { wasm_performance_now: () => {
return performance.now(); return performance.now();
}, },
@ -260,6 +309,14 @@ function glBufferData(target, size, ptr, usage)
return r; return r;
} }
function glBufferSubData(target, offset, size, ptr)
{
let data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, size);
const r = gl.bufferSubData(target, offset, data, 0, size);
glErrorReport(arguments);
return r;
}
function glCreateShader(kind) function glCreateShader(kind)
{ {
let shader = gl.createShader(kind); let shader = gl.createShader(kind);
@ -395,6 +452,17 @@ function glTexSubImage2D(target, level, offsetx, offsety, width, height, format,
return r; return r;
} }
function glGetUniformLocation(program, name, name_len)
{
// TODO(PS): complete
return 0;
}
function glUniformMatrix4fv()
{
// TODO(PS):
}
function webgl_add_imports (canvas_selector, imports) { function webgl_add_imports (canvas_selector, imports) {
const canvas = document.querySelector(canvas_selector); const canvas = document.querySelector(canvas_selector);
if (!canvas) return console.error("no canvas"); if (!canvas) return console.error("no canvas");
@ -414,6 +482,7 @@ function webgl_add_imports (canvas_selector, imports) {
imports.glCreateBuffer = glCreateBuffer; imports.glCreateBuffer = glCreateBuffer;
imports.glBindBuffer = glBindBuffer; imports.glBindBuffer = glBindBuffer;
imports.glBufferData = glBufferData; imports.glBufferData = glBufferData;
imports.glBufferSubData = glBufferSubData;
imports.glCreateShader = glCreateShader; imports.glCreateShader = glCreateShader;
imports.glShaderSource = glShaderSource; imports.glShaderSource = glShaderSource;
imports.glCompileShader = glCompileShader; imports.glCompileShader = glCompileShader;
@ -431,5 +500,8 @@ function webgl_add_imports (canvas_selector, imports) {
imports.glTexImage2D = glTexImage2D; imports.glTexImage2D = glTexImage2D;
imports.glTexSubImage2D = glTexSubImage2D; imports.glTexSubImage2D = glTexSubImage2D;
imports.glBindTexture = glBindTexture; imports.glBindTexture = glBindTexture;
imports.glGetUniformLocation = glGetUniformLocation;
imports.glUniformMatrix4fv = glUniformMatrix4fv;
return imports; return imports;
} }

View File

@ -48,6 +48,7 @@ typedef unsigned int GLsizei;
#define GL_RGB 0x1907 #define GL_RGB 0x1907
#define GL_RGBA 0x1908 #define GL_RGBA 0x1908
#define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_BYTE 0x1401
#define GL_CLAMP_TO_EDGE 0x812F
WASM_EXTERN bool glHadError(); WASM_EXTERN bool glHadError();
WASM_EXTERN void glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a); WASM_EXTERN void glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
@ -61,6 +62,7 @@ WASM_EXTERN void glClear(GLuint i);
WASM_EXTERN GLuint glCreateBuffer(); WASM_EXTERN GLuint glCreateBuffer();
WASM_EXTERN void glBindBuffer(GLenum buffer_kind, GLuint buffer_id); WASM_EXTERN void glBindBuffer(GLenum buffer_kind, GLuint buffer_id);
WASM_EXTERN void glBufferData(GLenum target, size_t size, const void* data, GLenum usage); WASM_EXTERN void glBufferData(GLenum target, size_t size, const void* data, GLenum usage);
WASM_EXTERN void glBufferSubData(GLenum target, size_t offset, size_t size, const void* data);
WASM_EXTERN GLuint glCreateShader(GLenum kind); WASM_EXTERN GLuint glCreateShader(GLenum kind);
WASM_EXTERN GLuint glShaderSource(GLuint shader_id, char* shader_code, GLuint shader_code_len); WASM_EXTERN GLuint glShaderSource(GLuint shader_id, char* shader_code, GLuint shader_code_len);
WASM_EXTERN void glCompileShader(GLuint shader_id); WASM_EXTERN void glCompileShader(GLuint shader_id);
@ -70,6 +72,7 @@ WASM_EXTERN void glLinkProgram(GLuint program);
WASM_EXTERN void glUseProgram(GLuint program); WASM_EXTERN void glUseProgram(GLuint program);
WASM_EXTERN GLuint glGetAttribLocation(GLuint program, const char* name, GLuint name_len); WASM_EXTERN GLuint glGetAttribLocation(GLuint program, const char* name, GLuint name_len);
WASM_EXTERN GLuint glGetUniformLocation(GLuint program, const char* name, u32 len); WASM_EXTERN GLuint glGetUniformLocation(GLuint program, const char* name, u32 len);
WASM_EXTERN void glUniformMatrix4fv(GLuint uniform, GLuint count, GLenum normalize, GLfloat* elements);
WASM_EXTERN void glVertexAttribPointer(GLuint attr, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); WASM_EXTERN void glVertexAttribPointer(GLuint attr, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
WASM_EXTERN void glEnableVertexAttribArray(GLuint index); WASM_EXTERN void glEnableVertexAttribArray(GLuint index);
WASM_EXTERN void glDrawElements(GLenum type, GLuint count, GLenum ele_type, void* indices); WASM_EXTERN void glDrawElements(GLenum type, GLuint count, GLenum ele_type, void* indices);
@ -109,6 +112,53 @@ platform_geometry_buffer_create(
return result; return result;
} }
void
platform_geometry_buffer_update(
Platform_Geometry_Buffer* buffer,
r32* verts,
u32 verts_offset,
u32 verts_len,
u32* indices,
u32 indices_offset,
u32 indices_len
){
glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices);
if (verts_len > buffer->vertices_len)
{
// NOTE(PS): this is because we're going to delete the old buffer and
// create a new one. In order to do that and not lose data, the update
// function needs to have been passed all the buffer's data
assert(verts_offset == 0);
glBufferData(
GL_ARRAY_BUFFER, verts_len * sizeof(r32), (void*)verts, GL_STATIC_DRAW
);
}
else
{
glBufferSubData(
GL_ARRAY_BUFFER, verts_offset * sizeof(r32), verts_len * sizeof(r32), (void*)verts
);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->buffer_id_indices);
if (indices_len > buffer->indices_len)
{
// NOTE(PS): this is because we're going to delete the old buffer and
// create a new one. In order to do that and not lose data, the update
// function needs to have been passed all the buffer's data
assert(indices_offset == 0);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER, indices_len * sizeof(u32), (void*)indices, GL_STATIC_DRAW
);
}
else
{
glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER, indices_offset * sizeof(u32), indices_len * sizeof(u32), (void*)indices
);
}
}
Platform_Shader Platform_Shader
platform_shader_create( platform_shader_create(
String code_vert, String code_frag, String* attrs, GLuint attrs_len, String* uniforms, GLuint uniforms_len String code_vert, String code_frag, String* attrs, GLuint attrs_len, String* uniforms, GLuint uniforms_len
@ -174,7 +224,7 @@ platform_shader_bind(Platform_Shader shader)
void void
platform_set_uniform(Platform_Shader shader, u32 index, m44 u) platform_set_uniform(Platform_Shader shader, u32 index, m44 u)
{ {
glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, &u.Elements[0]); glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements);
} }
void void

View File

@ -205,8 +205,8 @@ WinMain(
&win32_main_window, &win32_main_window,
hInstance, hInstance,
"Lumenariumtest0", "Lumenariumtest0",
1600, 1400,
900, 800,
win32_window_event_handler win32_window_event_handler
); );
win32_window_update_dim(&win32_main_window); win32_window_update_dim(&win32_main_window);

View File

@ -57,15 +57,16 @@ platform_geometry_buffer_create(
return result; return result;
} }
void platform_geometry_buffer_update( void
Platform_Geometry_Buffer* buffer, platform_geometry_buffer_update(
r32* verts, Platform_Geometry_Buffer* buffer,
u32 verts_offset, r32* verts,
u32 verts_len, u32 verts_offset,
u32* indices, u32 verts_len,
u32 indices_offset, u32* indices,
u32 indices_len u32 indices_offset,
){ u32 indices_len
){
gl.glBindVertexArray(buffer->buffer_id_vao); gl.glBindVertexArray(buffer->buffer_id_vao);
gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices); gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices);
win32_gl_no_error(); win32_gl_no_error();

View File

@ -7,33 +7,53 @@ incenter_get_init_desc()
return result; return result;
} }
#define INCENTER_METER 1.0f
#define INCENTER_FOOT 0.3048f
#define INCENTER_METERS(count) (count) * INCENTER_METER
#define INCENTER_FEET(count) (count) * INCENTER_FOOT
#define INCENTER_PER_METER(count) INCENTER_METER / (r32)(count)
internal void internal void
incenter_init(App_State* state) incenter_init(App_State* state)
{ {
// create a fake sculpture // create a fake sculpture
Assembly_Handle ah = assembly_add(&state->assemblies, lit_str("test"), 3000, 100); Assembly_Handle ah = assembly_add(&state->assemblies, lit_str("test"), 5043, 41);
r32 scale = 1; scratch_get(scratch);
Allocator* s = scratch.a;
// strips v3 start_p = v3{0, 0, 0};
for (int strip_x = 0; strip_x < 10; strip_x++)
Assembly_Strip* vertical_strip = assembly_add_strip(&state->assemblies, ah, 123);
assembly_strip_create_leds(
&state->assemblies,
ah,
vertical_strip,
start_p,
v3{0, INCENTER_FEET(-6.5f), 0},
123
);
r32 radius = INCENTER_FEET(10);
Random_Series rand = random_series_create(hash_djb2_to_u32("slkdjfalksdjf"));
for (u32 i = 0; i < 40; i++)
{ {
for (int strip_y = 0; strip_y < 10; strip_y++) Assembly_Strip* strip = assembly_add_strip(&state->assemblies, ah, 123);
{
if (strip_x == 5 && strip_y == 7)
{
int x= 5;
}
Assembly_Strip* strip = assembly_add_strip(&state->assemblies, ah, 30);
// leds go up r32 theta = random_series_next_unilateral(&rand) * r32_tau;
for (int led_z = 0; led_z < 30; led_z++) r32 phi = random_series_next_unilateral(&rand) * r32_tau;
{
v4 pos = { strip_x * scale, strip_y * scale, led_z * scale, 1 }; // spherical to cartesian conversion
assembly_add_led(&state->assemblies, ah, strip, pos); v3 end_p = {
} radius * sinf(phi) * cosf(theta),
} radius * sinf(phi) * sinf(theta),
radius * cosf(phi)
};
assembly_strip_create_leds(&state->assemblies, ah, strip, start_p, end_p, 123);
} }
ed_sculpture_updated(state, 5, 0.025f);
} }
internal void internal void