Merge branch 'dev'

This commit is contained in:
PS 2021-02-28 15:37:02 -08:00
commit ea2eb0e469
61 changed files with 5998 additions and 1574 deletions

View File

@ -2,10 +2,19 @@
![Lumenarium Banner](./docs/images/splash.png)
## Build Lumenarium
Building Lumenarium requires having MSVC installed (sorry, Windows only for now!). At the moment, there are bunch of errors from the meta program but the program will still compile
1. Run build_meta.bat
2. Run build.bat
3. Launch win32_foldhaus.exe (locaated in the build folder)
Building Lumenarium requires having MSVC installed (sorry, Windows only for now!).
1. clone the repo onto your computer
2. Run the appropriate build batch file
- for Windows: use `build\build_app_msvc_win32_debug.bat`
- other platforms coming soon
## Run Lumenarium
Windows - Debug
1. Just run `win32_msvc\debug\win32_foldhaus.exe`
## Debug Lumenarium
###Windows
Building in debug mode outputs pdb file info that can be read by Visual Studio or RemedyBG (preferred debugging solution, but ymmv). You can just open the exe in either application and it'll find the pdb file in the same directory
## What Is Lumenarium?
Lumenarium is our custom build light and motion control software. It allows us to design light and motion patterns for our sculptures, visualize the output long before the sculpture is built, and iterate in real time to achieve the best visual results quickly.

View File

@ -2,8 +2,8 @@
IF NOT "%PrebuildCalled%"=="1" GOTO error
C:\apps\ctime\ctime.exe -end %StatsPath%\%StatsFile% %LastError%
C:\apps\ctime\ctime.exe -stats %StatsPath%\%StatsFile%
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -end %StatsPath%\%StatsFile% %LastError% )
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -stats %StatsPath%\%StatsFile% )
set PrebuildCalled=0
GOTO:eof

View File

@ -1,6 +1,6 @@
@echo off
REM This file takes two arguments
REM This file takes three arguments
REM 1 = "app" or "meta"
REM 2 = "debug" or "release"
REM 3 = "msvc" or "clang"
@ -22,7 +22,9 @@ set StatsFile=%1_win32_%3_%2_build_time.ctm
IF NOT EXIST %BuildPath% mkdir %BuildPath%
IF NOT EXIST %StatsPath% mkdir %StatsPath%
C:\apps\ctime\ctime.exe -begin %StatsPath%\%StatsFile%
set CTimePath=C:\apps\ctime
IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -begin %StatsPath%\%StatsFile% )
echo.
echo BUILDING TO %BuildPath%
echo STATS IN %StatsPath%\%StatsFile%

View File

@ -1,32 +1,26 @@
@echo off
set ProjectDevFolder=%~dp0
set ProjectDevPath=%ProjectDevFolder:~0,-1%
pushd %ProjectDevPath%
IF NOT EXIST .\build_clang\ mkdir .\build_clang
C:\programs\ctime\ctime.exe -begin %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm
SET MyPath=%~dp0
SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat app debug clang
set CommonCompilerFlags=-std=c++11 -Wno-writable-strings -Wno-unused-value -Wno-varargs -Wno-switch -Wno-microsoft-enum-forward-reference -DDEBUG=1
pushd .\build_clang\
pushd %BuildPath%
REM Run the Preprocessor
foldhaus_meta.exe ..\src\foldhaus_app.cpp
del *.pdb > NUL 2> NUL
echo WAITING FOR PDB TO WRITE > lock.tmp
clang %CommonCompilerFlags% ..\src\foldhaus_app.cpp -shared
clang++ %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp -shared -o
set LastError=%ERRORLEVEL%
del lock.tmp
clang %CommonCompilerFlags% ..\src\win32_foldhaus.cpp -o win32_foldhaus.exe user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib
clang++ -c %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp
link win32_foldhaus.o user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib
C:\programs\ctime\ctime.exe -end %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm %LastError%
REM C:\programs\ctime\ctime.exe -stats %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm
popd
call %MyPath%\_postbuild_win32.bat

View File

@ -2,32 +2,38 @@
SET MyPath=%~dp0
SET MyPath=%MyPath:~0,-1%
call %MyPath%\_prebuild_win32.bat app debug msvc
call %MyPath%\setup_cl.bat
set CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except-
set CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -O2 %CommonCompilerFlags%
set CommonLinkerFlags= -opt:ref -incremental:no
SET CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
set DLLExports=/EXPORT:InitializeApplication /EXPORT:UpdateAndRender /EXPORT:CleanupApplication /EXPORT:ReloadStaticData
SET CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -O2 %CommonCompilerFlags%
SET CommonLinkerFlags= -opt:ref -incremental:no
SET DLLExports=/EXPORT:InitializeApplication /EXPORT:UpdateAndRender /EXPORT:CleanupApplication /EXPORT:ReloadStaticData
pushd %BuildPath%
del *.pdb > NUL 2> NUL
REM Run the Preprocessor
REM %MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp
echo WAITING FOR PDB TO WRITE > lock.tmp
cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp /Fefoldhaus.dll /LD /link %CommonLinkerFlags% %DLLExports%
set LastError=%ERRORLEVEL%
SET LastError=%ERRORLEVEL%
del lock.tmp
cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib
REM COMPILE UTILITY EXES
cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib
cl %CommonCompilerFlags% %ProjectDevPath%\src\sculpture_gen\gen_blumen_lumen.cpp /Fegen_blumen_lumen.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib
popd
call %MyPath%\_postbuild_win32.bat

40
build/setup_cl.bat Normal file
View File

@ -0,0 +1,40 @@
@echo off
ECHO SETUP CL
SET "LIB="
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 13.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional
IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64))
ECHO SETUP CL COMPLETE

2
debug.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
call remedybg.bat ./app_run_tree/win32_msvc/debug/session.rdbg

4
run.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
pushd app_run_tree
start win32_msvc\debug\win32_foldhaus.exe
popd

280
src/app/blumen_lumen.cpp Normal file
View File

@ -0,0 +1,280 @@
//
// File: blumen_lumen.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-23
//
#ifndef BLUMEN_LUMEN_CPP
internal void
BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData)
{
mic_listen_job_data* Data = (mic_listen_job_data*)UserData;
gs_data Msg = {};
u8 WeathermanIPAddr[4] = {};
WeathermanIPAddr[0] = 127;
WeathermanIPAddr[1] = 0;
WeathermanIPAddr[2] = 0;
WeathermanIPAddr[3] = 1;
u32 WeathermanIPV4 = (u32)UpackB4(WeathermanIPAddr);
u32 WeathermanPort = 20185;
while (*Data->Running)
{
#if 1
if (SocketQueryStatus(Data->SocketManager, Data->ListenSocket))
{
// TODO(pjs): Removing this block for now - nothing is wrong with it except that SocketPeek is still blocking for some reason
if (SocketPeek(Data->SocketManager, Data->ListenSocket))
{
// TODO(pjs): Make this a peek operation
Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient);
if (Msg.Size > 0)
{
Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg;
if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX)
{
Data->MicPacketBuffer->WriteHead = 0;
}
}
}
#endif
while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead)
{
u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++;
if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
Data->OutgoingMsgQueue->ReadHead = 0;
}
Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex];
u32 Address = WeathermanIPV4;
u32 Port = WeathermanPort;
s32 Flags = 0;
SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags);
}
}
}
CloseSocket(Data->SocketManager, Data->ListenSocket);
}
internal void
BlumenLumen_LoadPatterns(app_state* State)
{
animation_pattern_array* Patterns = &State->Patterns;
if (Patterns->CountMax == 0)
{
*Patterns = Patterns_Create(&State->Permanent, 32);
}
Patterns->Count = 0;
Patterns_PushPattern(Patterns, TestPatternOne);
Patterns_PushPattern(Patterns, TestPatternTwo);
Patterns_PushPattern(Patterns, TestPatternThree);
Patterns_PushPattern(Patterns, Pattern_AllGreen);
Patterns_PushPattern(Patterns, Pattern_HueShift);
Patterns_PushPattern(Patterns, Pattern_HueFade);
Patterns_PushPattern(Patterns, Pattern_Spots);
Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow);
Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow);
Patterns_PushPattern(Patterns, Pattern_GrowAndFade);
Patterns_PushPattern(Patterns, Pattern_ColorToWhite);
Patterns_PushPattern(Patterns, Pattern_Blue);
Patterns_PushPattern(Patterns, Pattern_Green);
Patterns_PushPattern(Patterns, Pattern_FlowerColors);
Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite);
Patterns_PushPattern(Patterns, Pattern_BasicFlowers);
}
internal pixel
TEMP_Saturate(pixel P)
{
v4 CRGB = v4{ (r32)P.R / 255.f, (r32)P.G / 255.f, (r32)P.B / 255.f, 1.f };
v4 CHSV = RGBToHSV(CRGB);
if (CHSV.g > .3f)
{
CHSV.g = 1;
CRGB = HSVToRGB(CHSV);
}
return V4ToRGBPixel(CRGB);
}
internal gs_data
BlumenLumen_CustomInit(app_state* State, context Context)
{
// This is memory for any custom data that we want to use
// as a part of a particular sculpture.
// By returning it from here, it will be sent as an argument to
// the sculpture's CustomUpdate function;
gs_data Result = {};
Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state));
blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory;
BLState->Running = true;
BLState->MicListenJobData.Running = &BLState->Running;
BLState->MicListenJobData.SocketManager = Context.SocketManager;
BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer;
BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue;
BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185");
//BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData);
gs_const_string SculpturePath = ConstString("data/test_blumen.fold");
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
{ // Animation PLAYGROUND
animation Anim0 = {0};
Anim0.Name = PushStringF(&State->Permanent, 256, "test_anim_zero");
Anim0.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8);
Anim0.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8);
Anim0.PlayableRange.Min = 0;
Anim0.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim0, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(15), 0);
AnimationArray_Push(&State->AnimationSystem.Animations, Anim0);
animation Anim1 = {0};
Anim1.Name = PushStringF(&State->Permanent, 256, "test_anim_one");
Anim1.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8);
Anim1.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8);
Anim1.PlayableRange.Min = 0;
Anim1.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim1, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(12), 0);
AnimationArray_Push(&State->AnimationSystem.Animations, Anim1);
animation Anim2 = {0};
Anim2.Name = PushStringF(&State->Permanent, 256, "i_love_you");
Anim2.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8);
Anim2.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8);
Anim2.PlayableRange.Min = 0;
Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0);
AnimationArray_Push(&State->AnimationSystem.Animations, Anim2);
State->AnimationSystem.TimelineShouldAdvance = true;
} // End Animation Playground
for (u32 i = 0; i < FLOWER_COLORS_COUNT; i++)
{
FlowerAColors[i] = TEMP_Saturate(FlowerAColors[i]);
FlowerBColors[i] = TEMP_Saturate(FlowerBColors[i]);
FlowerCColors[i] = TEMP_Saturate(FlowerCColors[i]);
}
return Result;
}
internal void
BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory;
MotorTimeElapsed += Context->DeltaTime;
gs_string BlueString = MakeString("blue");
gs_string GreenString = MakeString("green");
gs_string ILoveYouString = MakeString("i_love_you");
while (BLState->MicPacketBuffer.ReadHead != BLState->MicPacketBuffer.WriteHead)
{
gs_data PacketData = BLState->MicPacketBuffer.Values[BLState->MicPacketBuffer.ReadHead++];
microphone_packet Packet = *(microphone_packet*)PacketData.Memory;
u32 NameLen = CStringLength(Packet.AnimationFileName);
if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen))
{
State->AnimationSystem.ActiveAnimationIndex = 0;
}
else if (StringEqualsCharArray(GreenString.ConstString, Packet.AnimationFileName, NameLen))
{
State->AnimationSystem.ActiveAnimationIndex = 1;
}
else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen))
{
State->AnimationSystem.ActiveAnimationIndex = 2;
}
if (BLState->MicPacketBuffer.ReadHead >= PACKETS_MAX)
{
BLState->MicPacketBuffer.ReadHead = 0;
}
}
if (MotorTimeElapsed > 60)
{
// NOTE(pjs):
MotorTimeElapsed = 0;
u8 Position = LastPosition;
if (LastPosition == 2)
{
LastPosition = 1;
}
else
{
LastPosition = 2;
}
if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) ||
(BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead))
{
u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead;
gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex;
if (Msg->Size == 0)
{
*Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet));
}
motor_packet* Packet = (motor_packet*)Msg->Memory;
Packet->FlowerPositions[0] = Position;
Packet->FlowerPositions[1] = Position;
Packet->FlowerPositions[2] = Position;
// NOTE(pjs): We increment the write head AFTER we've written so that
// the network thread doesn't think the buffer is ready to send before
// the data is set. We want to avoid the case of:
// 1. Main Thread increments write head to 1
// 2. Network Thread thinks theres a new message to send at 0
// 3. Network Thread sends the message at 0
// 4. Main Thread sets the message at 0
BLState->OutgoingMsgQueue.WriteHead += 1;
if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
BLState->OutgoingMsgQueue.WriteHead = 0;
}
}
}
}
US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory;
BLState->Running = false;
}
internal user_space_desc
BlumenLumen_UserSpaceCreate()
{
user_space_desc Result = {};
Result.LoadPatterns = BlumenLumen_LoadPatterns;
Result.CustomInit = BlumenLumen_CustomInit;
Result.CustomUpdate = BlumenLumen_CustomUpdate;
Result.CustomCleanup = BlumenLumen_CustomCleanup;
return Result;
}
#define BLUMEN_LUMEN_CPP
#endif // BLUMEN_LUMEN_CPP

119
src/app/blumen_lumen.h Normal file
View File

@ -0,0 +1,119 @@
//
// File: blumen_lumen.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef BLUMEN_LUMEN_H
typedef struct motor_packet
{
u8 FlowerPositions[3];
} motor_packet;
#pragma pack(push, 1)
struct microphone_packet
{
b8 ChangeAnimation;
char AnimationFileName[32];
b8 SetLayer;
char LayerName[32];
r32 LayerOpacity;
b8 SetLayerParamColor;
char LayerParamColor[7];
r32 OverrideDuration;
};
#pragma pack(pop)
#define BLUMEN_MESSAGE_QUEUE_COUNT 32
typedef struct blumen_network_msg_queue
{
gs_data Buffers[BLUMEN_MESSAGE_QUEUE_COUNT];
u32 WriteHead;
u32 ReadHead;
} blumen_network_msg_queue;
// TODO(pjs): Refactor this -> blumen_network_job_state
struct mic_listen_job_data
{
bool* Running;
platform_socket_manager* SocketManager;
packet_ringbuffer* MicPacketBuffer;
platform_socket_handle_ ListenSocket;
blumen_network_msg_queue* OutgoingMsgQueue;
};
struct blumen_lumen_state
{
bool Running;
packet_ringbuffer MicPacketBuffer;
blumen_network_msg_queue OutgoingMsgQueue;
temp_job_req JobReq;
platform_thread_handle MicListenThread;
mic_listen_job_data MicListenJobData;
};
// If you change anything, exit lumenarium if its running
// then in this application hit f1 to compile then
// go to remedybg (the debugger) and hit f5
// don't touch this
u8 LastPosition = 1;
u8 ClosedValue = 1;
u8 OpenValue = 2;
r64 MotorTimeElapsed = 0;
r64 OpenClosePeriod = 15.0f;
#define BLUMEN_LUMEN_H
#endif // BLUMEN_LUMEN_H

View File

@ -12,6 +12,8 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue
b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State);
gs_string TextInputString = PushString(State->Transient, 32);
panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos);
if (ActivePanel)
{
@ -47,7 +49,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue
// frame when the button was released, even if the command is registered to both events
if (KeyTransitionedDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue);
if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue))
{
char KeyASCII = KeyCodeToChar(Event.Key);
if (KeyASCII)
{
OutChar(&TextInputString, KeyASCII);
}
}
}
else if (KeyTransitionedUp(Event))
{
@ -55,7 +64,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue
}
else if (KeyHeldDown(Event))
{
FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue);
if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue))
{
char KeyASCII = KeyCodeToChar(Event.Key);
if (KeyASCII)
{
OutChar(&TextInputString, KeyASCII);
}
}
}
}
}
@ -74,6 +90,8 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue
}
}
State->Interface.TempInputString = TextInputString.ConstString;
ClearCommandQueue(&State->CommandQueue);
}
@ -84,6 +102,15 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue)
State->WindowBounds = Context->WindowBounds;
State->Interface.Mouse = Context->Mouse;
State->Interface.HotWidgetFramesSinceUpdate += 1;
if (State->Interface.HotWidgetFramesSinceUpdate > 1)
{
State->Interface.HotWidget = {};
}
Assert(State->Interface.PerFrameMemory &&
(u64)State->Interface.PerFrameMemory != 0x5);
PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds);
Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context);
}
@ -91,15 +118,15 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue)
internal void
Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
{
State->Interface.WindowBounds = Context->WindowBounds;
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
PushRenderClearScreen(RenderBuffer);
ui_InterfaceReset(&State->Interface);
State->Interface.RenderBuffer = RenderBuffer;
ui_layout Layout = ui_CreateLayout(&State->Interface, Context->WindowBounds);
ui_PushLayout(&State->Interface, Layout);
ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout"));
{
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
@ -110,69 +137,19 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
}
}
}
ui_PopLayout(&State->Interface, MakeString("Editor Layout"));
ui_PopLayout(&State->Interface);
// Draw the Interface
for (u32 i = 0; i < State->Interface.WidgetsCount; i++)
if (State->Interface.DrawOrderRoot != 0)
{
ui_widget Widget = State->Interface.Widgets[i];
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
{
v4 Color = State->Interface.Style.ButtonColor_Inactive;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget))
{
Color = State->Interface.Style.ButtonColor_Active;
}
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = State->Interface.Style.ButtonColor_Selected;
}
PushRenderQuad2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Color);
}
if (Widget.String.Length > 0)
{
v4 Color = State->Interface.Style.TextColor;
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer,
Widget.String.Length,
State->Interface.Style.Font->BitmapMemory,
State->Interface.Style.Font->BitmapTextureHandle,
State->Interface.Style.Font->BitmapWidth,
State->Interface.Style.Font->BitmapHeight,
State->Interface.Style.Font->BitmapBytesPerPixel,
State->Interface.Style.Font->BitmapStride);
v2 RegisterPosition = Widget.Bounds.Min + State->Interface.Style.Margin;
switch (Widget.Alignment)
{
case Align_Left:
{
RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color);
}break;
case Align_Right:
{
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color);
}break;
InvalidDefaultCase;
}
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline))
{
// TODO(pjs): replace these with values from the style
r32 Thickness = 1.0f;
v4 Color = WhiteV4;
PushRenderBoundingBox2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Thickness, Color);
}
ui_widget Widget = *State->Interface.DrawOrderRoot;
Editor_DrawWidget(State, Context, RenderBuffer, Widget, Context->WindowBounds);
}
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);
ResetWorkQueue(Context->GeneralWorkQueue);
}

View File

@ -0,0 +1,151 @@
//
// File: foldhaus_editor_draw.h
// Author: Peter Slattery
// Creation Date: 2021-01-16
//
#ifndef FOLDHAUS_EDITOR_DRAW_H
internal void
Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color)
{
gs_string Temp = PushString(State->Transient, 256);
PrintF(&Temp, "%d", Widget.Id.Id);
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer,
Widget.String.Length,
State->Interface.Style.Font->BitmapMemory,
State->Interface.Style.Font->BitmapTextureHandle,
State->Interface.Style.Font->BitmapWidth,
State->Interface.Style.Font->BitmapHeight,
State->Interface.Style.Font->BitmapBytesPerPixel,
State->Interface.Style.Font->BitmapStride);
v2 RegisterPosition = Widget.Bounds.Min + State->Interface.Style.Margin;
switch (Widget.Alignment)
{
case Align_Left:
{
RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color);
}break;
case Align_Right:
{
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color);
}break;
InvalidDefaultCase;
}
}
enum widget_fill_dir
{
WidgetFill_Horizontal = 0,
WidgetFill_Vertical = 1,
};
internal rect2
Editor_GetWidgetFillBounds(ui_widget Widget)
{
Assert(ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill));
rect2 Result = {};
widget_fill_dir Dir = WidgetFill_Horizontal;
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) { Dir = WidgetFill_Vertical; }
widget_fill_dir OtherDir = (widget_fill_dir)(WidgetFill_Vertical - Dir);
Result.Min.E[Dir] = Widget.Bounds.Min.E[Dir];
Result.Max.E[Dir] = Widget.Bounds.Max.E[Dir];
r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.E[OtherDir], Widget.Bounds.Max.E[OtherDir]);
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed))
{
Result.Min.E[OtherDir] = FillToPoint;
Result.Max.E[OtherDir] = Widget.Bounds.Max.E[OtherDir];
}
else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle))
{
Result.Min.E[OtherDir] = FillToPoint - 5;
Result.Max.E[OtherDir] = FillToPoint + 5;
}
else
{
Result.Min.E[OtherDir] = Widget.Bounds.Min.E[OtherDir];
Result.Max.E[OtherDir] = FillToPoint;
}
return Result;
}
internal void
Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds)
{
rect2 WidgetParentUnion = Widget.Bounds;
WidgetParentUnion = Rect2Union(Widget.Bounds, ParentClipBounds);
if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0))
{
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
{
v4 Color = State->Interface.Style.ButtonColor_Inactive;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget))
{
Color = State->Interface.Style.ButtonColor_Active;
}
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = State->Interface.Style.ButtonColor_Selected;
}
PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color);
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
{
v4 Color = State->Interface.Style.TextColor;
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color);
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) ||
ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill))
{
v4 Color = State->Interface.Style.ButtonColor_Selected;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) ||
ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = WhiteV4;
}
rect2 FillBounds = Editor_GetWidgetFillBounds(Widget);
rect2 ClippedFillBounds = Rect2Union(FillBounds, WidgetParentUnion);
PushRenderQuad2D(RenderBuffer, ClippedFillBounds, Color);
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
{
// TODO(pjs): add this color to the style
v4 TextColor = BlackV4;
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, ClippedFillBounds, TextColor);
}
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline))
{
// TODO(pjs): replace these with values from the style
r32 Thickness = 1.0f;
v4 Color = WhiteV4;
PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color);
}
}
if (Widget.ChildrenRoot)
{
Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot, WidgetParentUnion);
}
if (Widget.Next)
{
Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next, ParentClipBounds);
}
}
#define FOLDHAUS_EDITOR_DRAW_H
#endif // FOLDHAUS_EDITOR_DRAW_H

View File

@ -98,38 +98,38 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
if (OpState->PanelEditMode == PanelEdit_Modify)
{
if (Panel->SplitDirection == PanelSplit_Horizontal)
if (OpState->Panel->SplitDirection == PanelSplit_Horizontal)
{
r32 NewSplitY = Mouse.Pos.y;
if (NewSplitY <= PanelBounds.Min.y)
{
ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem);
}
else if (NewSplitY >= PanelBounds.Max.y)
{
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem);
}
else
{
Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
Panel_UpdateLayout(Panel, PanelBounds);
OpState->Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds);
Panel_UpdateLayout(OpState->Panel, PanelBounds);
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
else if (OpState->Panel->SplitDirection == PanelSplit_Vertical)
{
r32 NewSplitX = Mouse.Pos.x;
if (NewSplitX <= PanelBounds.Min.x)
{
ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem);
}
else if (NewSplitX >= PanelBounds.Max.x)
{
ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem);
}
else
{
Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds);
Panel_UpdateLayout(Panel, PanelBounds);
OpState->Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds);
Panel_UpdateLayout(OpState->Panel, PanelBounds);
}
}
}
@ -140,11 +140,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y);
if (Mouse.Pos.y > SplitY)
{
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem);
}
else
{
ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem);
}
}
else if (OpState->PanelEdgeDirection == PanelSplit_Vertical)
@ -152,11 +152,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation)
r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x);
if (Mouse.Pos.x > SplitX)
{
ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem);
}
else
{
ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem);
ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem);
}
}
}
@ -338,14 +338,16 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse
}
internal void
DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mouse, render_command_buffer* RenderBuffer)
DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, mouse_state* Mouse, render_command_buffer* RenderBuffer)
{
r32 MouseLeftEdgeDistance = Abs(Mouse->Pos.x - PanelMin.x);
r32 MouseRightEdgeDistance = Abs(Mouse->Pos.x - PanelMax.x);
r32 MouseTopEdgeDistance = Abs(Mouse->Pos.y - PanelMax.y);
r32 MouseBottomEdgeDistance = Abs(Mouse->Pos.y - PanelMin.y);
v4 Color = BlackV4;
PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color);
v4 HighlightColor = v4{.3f, .3f, .3f, 1.f};
r32 HighlightThickness = 1;
if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
@ -353,28 +355,28 @@ DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mo
v2 LeftEdgeMin = PanelMin;
v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y};
PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_HorizontalArrows;
Mouse->CursorType = CursorType_HArrows;
}
else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y};
v2 RightEdgeMax = PanelMax;
PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_HorizontalArrows;
Mouse->CursorType = CursorType_HArrows;
}
else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness};
v2 TopEdgeMax = PanelMax;
PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_VerticalArrows;
Mouse->CursorType = CursorType_VArrows;
}
else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE)
{
v2 BottomEdgeMin = PanelMin;
v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness};
PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor);
Mouse->CursorType = CursorType_VerticalArrows;
Mouse->CursorType = CursorType_VArrows;
}
}
@ -386,7 +388,8 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB
rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23});
if (ui_BeginDropdown(&State->Interface, MakeString("Select"), PanelSelectBtnBounds))
panel_definition CurrentDef = State->PanelSystem.PanelDefs[Panel->TypeIndex];
if (ui_BeginDropdown(&State->Interface, MakeString(CurrentDef.PanelName, CurrentDef.PanelNameLength), PanelSelectBtnBounds))
{
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{
@ -427,6 +430,7 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_
internal void
DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context)
{
rect2 Bounds = Panel->Bounds;
switch (Panel->SplitDirection)
{
case PanelSplit_Horizontal:
@ -439,11 +443,9 @@ DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_stat
case PanelSplit_NoSplit:
{
panel* OverridePanel = Panel_GetModalOverride(Panel);
RenderPanel(OverridePanel, OverridePanel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
v4 BorderColor = v4{0, 0, 0, 1};
RenderPanel(OverridePanel, Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*OverridePanel, OverridePanel->Bounds.Min, OverridePanel->Bounds.Max, BorderColor, Mouse, RenderBuffer);
DrawPanelBorder(*OverridePanel, Bounds.Min, Bounds.Max, Mouse, RenderBuffer);
}break;
InvalidDefaultCase;

View File

@ -40,7 +40,7 @@ OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContex
// TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint?
Result.Arena.Allocator = ThreadContext.Allocator;
Result.ModeMemoryPagesFreeList.CountMax = 16; // TODO(Peter): Static number of modes that can be active simultaneously
Result.ModeMemoryPagesFreeList.CountMax = 32; // TODO(Peter): Static number of modes that can be active simultaneously
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
{

View File

@ -34,7 +34,7 @@ GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range
}
internal handle
AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animation_system* System)
AddAnimationBlockAtCurrentTime (animation_pattern_handle AnimationProcHandle, u32 LayerHandle, animation_system* System)
{
u32 NewBlockStart = System->CurrentFrame;
u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System);
@ -240,14 +240,13 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
operation_mode* DragAnimationBlockMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationBlockCommands, UpdateDragAnimationBlock);
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
drag_animation_block_state* OpState = CreateOperationState(DragAnimationBlockMode,
&State->Modes,
drag_animation_block_state);
OpState->TimelineBounds = TimelineBounds;
OpState->BlockHandle = BlockHandle;
OpState->VisibleRange = VisibleRange;
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
OpState->ClipRange = SelectedBlock->Range;
}
// -------------------
@ -261,7 +260,8 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
frame_range Range = ActiveAnim->PlayableRange;
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, Panel->Bounds, Range);
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, TimelineState->SelectedAnimationLayer);
animation_pattern_handle PatternHandle = Patterns_IndexToHandle(4);
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), PatternHandle, TimelineState->SelectedAnimationLayer);
TimelineState->SelectedBlockHandle = NewBlockHandle;
}
@ -303,10 +303,7 @@ DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_r
r32 BarWidth = Rect2Width(BarBounds);
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
// TODO(pjs): both of these functions can get wrapped in a MouseClickedRect
// and an alternate MouseIsDraggingRect
if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) &&
PointIsInRect(BarBounds, Interface.Mouse.DownPos))
if (ui_MouseClickedRect(Interface, BarBounds))
{
StartDragTimeMarker(BarBounds, VisibleFrames, State);
}
@ -579,8 +576,10 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
if (FileInfo.Path.Length > 0)
{
gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path);
gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size);
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationPatternsCount, GlobalAnimationPatterns);
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, State->Patterns);
NewAnim.FileInfo = AnimFile.FileInfo;
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
@ -588,20 +587,20 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
}
internal void
DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem)
DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem, animation_pattern_array Patterns)
{
ui_layout Layout = ui_CreateLayout(Interface, PanelBounds);
ui_PushLayout(Interface, Layout);
for (s32 i = 0; i < GlobalAnimationPatternsCount; i++)
ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("AnimClips Layout"));
for (u32 i = 0; i < Patterns.Count; i++)
{
animation_pattern Pattern = GlobalAnimationPatterns[i];
animation_pattern Pattern = Patterns.Values[i];
gs_string PatternName = MakeString(Pattern.Name, Pattern.NameLength);
if (ui_LayoutListEntry(Interface, &Layout, PatternName, i))
if (ui_Button(Interface, PatternName))
{
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem);
animation_pattern_handle PatternHandle = Patterns_IndexToHandle(i);
AddAnimationBlockAtCurrentTime(PatternHandle, SelectedAnimationLayerHandle, AnimationSystem);
}
}
ui_PopLayout(Interface);
ui_PopLayout(Interface, MakeString("AnimClips Layout"));
}
internal void
@ -609,11 +608,10 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
{
animation_system* AnimSystem = &State->AnimationSystem;
ui_interface* Interface = &State->Interface;
ui_layout Layout = ui_CreateLayout(Interface, Bounds);
ui_PushLayout(Interface, Layout);
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout"));
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_StartRow(&State->Interface, 4);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
ui_BeginRow(&State->Interface, 4);
{
if (ui_Button(Interface, MakeString("Pause")))
{
@ -630,15 +628,9 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
AnimSystem->TimelineShouldAdvance = false;
AnimSystem->CurrentFrame = 0;
}
if (ui_Button(Interface, MakeString("Load")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
}
}
ui_EndRow(&State->Interface);
ui_PopLayout(&State->Interface);
ui_PopLayout(&State->Interface, MakeString("PlayBar Layout"));
}
internal void
@ -646,10 +638,14 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_
{
ui_interface* Interface = &State->Interface;
gs_string TempString = PushString(State->Transient, 256);
frame_range VisibleFrames = TimelineState->VisibleRange;
// :FrameRange
// frame_range VisibleFrames = TimelineState->VisibleRange;
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
frame_range VisibleFrames = ActiveAnim.PlayableRange;
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
// Frame Ticks
u32 TickCount = 10;
@ -691,12 +687,12 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_
}
internal void
LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
v2 LayerDim = { Rect2Width(Bounds), LAYER_HEIGHT };
rect2 LayerBounds = {0};
@ -726,9 +722,15 @@ internal void
TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
frame_range ViewRange = TimelineState->VisibleRange;
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
// TODO(pjs): setting the timeline to show the entire range
// of the current animation until I reimplement the range
// slider bars
// :FrameRange
// frame_range ViewRange = TimelineState->VisibleRange;
frame_range ViewRange = ActiveAnim.PlayableRange;
handle SelectedBlockHandle = TimelineState->SelectedBlockHandle;
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
@ -791,21 +793,17 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
}
internal void
AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
animation_system* AnimSystem = &State->AnimationSystem;
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem);
ui_interface* Interface = &State->Interface;
ui_layout Layout = ui_CreateLayout(Interface, Bounds);
ui_PushLayout(Interface, Layout);
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"));
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG);
ui_StartRow(&State->Interface, 2);
{
ui_DrawString(Interface, MakeString("Active Animation"));
if (ui_BeginDropdown(Interface, ActiveAnim->Name))
if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), ActiveAnim->Name))
{
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
{
@ -816,10 +814,74 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende
}
}
}
ui_EndDropdown(Interface);
ui_EndLabeledDropdown(&State->Interface);
ui_BeginRow(Interface, 3);
{
if (ui_Button(Interface, MakeString("New")))
{
animation NewAnim = {};
NewAnim.Name = PushString(State->AnimationSystem.Storage, 256);
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
}
ui_EndRow(&State->Interface);
ui_PopLayout(Interface);
if (ui_Button(Interface, MakeString("Save")))
{
// Save Animation File
// TODO(pjs): If you created the animation via the "new" button, there won't be a file attached.
// need to use the file browser to create a file
u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex;
animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex];
gs_string FileText = AnimSerializer_Serialize(ActiveAnimation, State->Patterns, State->Transient);
if (WriteEntireFile(Context.ThreadContext.FileHandler, ActiveAnimation.FileInfo.Path, StringToData(FileText)))
{
InvalidCodePath;
}
}
if (ui_Button(Interface, MakeString("Load")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
}
}
ui_EndRow(Interface);
ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name);
ui_Label(Interface, MakeString("Frame Range"));
ui_BeginRow(Interface, 3);
{
ActiveAnim->PlayableRange.Min = ui_TextEntryU64(Interface, MakeString("StartFrame"), ActiveAnim->PlayableRange.Min);
ActiveAnim->PlayableRange.Max = ui_TextEntryU64(Interface, MakeString("EndFrame"), ActiveAnim->PlayableRange.Max);
}
ui_EndRow(Interface);
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, TimelineState->SelectedBlockHandle);
if (SelectedBlock)
{
animation_pattern BlockPattern = Patterns_GetPattern(State->Patterns, SelectedBlock->AnimationProcHandle);
ui_BeginRow(Interface, 3);
ui_Label(Interface, MakeString("Selected Pattern"));
//if (ui_BeginLabeledDropdown(Interface, MakeString("Selected Pattern"), MakeString(BlockPattern.Name, BlockPattern.NameLength)))
if (ui_BeginDropdown(Interface, MakeString(BlockPattern.Name, BlockPattern.NameLength)))
{
for (u32 i = 0; i < State->Patterns.Count; i++)
{
animation_pattern Pattern = State->Patterns.Values[i];
if (ui_Button(Interface, MakeString(Pattern.Name, Pattern.NameLength)))
{
SelectedBlock->AnimationProcHandle = Patterns_IndexToHandle(i);
}
}
}
ui_EndLabeledDropdown(Interface);
}
ui_PopLayout(Interface, MakeString("AnimInfo Layout"));
}
internal void
@ -835,13 +897,11 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
{
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f});
rect2 TimelineBounds, InfoBounds;
RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds);
RectVSplitAtDistanceFromLeft(PanelBounds, 300, &InfoBounds, &TimelineBounds);
rect2 AnimInfoBounds, SelectionInfoBounds;
RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds);
{ // Timeline
rect2 LayersPanelBounds, TimeRangePanelBounds;
RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds);
@ -854,12 +914,9 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
LayerList_Render(TimelineState, LayersBounds, RenderBuffer, State, Context);
LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context);
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
}
AnimInfoView_Render(TimelineState, AnimInfoBounds, RenderBuffer, State, Context);
SelectionInfoView_Render(TimelineState, SelectionInfoBounds, RenderBuffer, State, Context);
AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context);
}
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H

View File

@ -0,0 +1,116 @@
//
// File: foldhaus_panel_assembly_debug.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H
GSMetaTag(panel_init);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Cleanup(panel* Panel, app_state* State)
{
}
// TODO(pjs): This is really blumen specific
#define FSC(f,c) FlowerStripToChannel((f), (c))
internal u8
FlowerStripToChannel(u8 Flower, u8 Channel)
{
Assert(Flower < 3);
Assert(Channel < 8);
u8 Result = 0;
Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07);
return Result;
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_file_view);
internal void
AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Assembly Debug Layout"));
InterfaceAssert(Interface->PerFrameMemory);
gs_string OverrideStr = MakeString(OverrideTypeStrings[State->AssemblyDebugState.Override]);
if (ui_BeginLabeledDropdown(Interface, MakeString("Override"), OverrideStr))
{
for (u32 i = 0; i < ADS_Override_Count; i++)
{
if (ui_Button(Interface, MakeString(OverrideTypeStrings[i])))
{
State->AssemblyDebugState.Override = (override_type)i;
}
}
}
ui_EndLabeledDropdown(Interface);
InterfaceAssert(Interface->PerFrameMemory);
switch (State->AssemblyDebugState.Override)
{
case ADS_Override_TagWhite:
case ADS_Override_TagStripWhite:
{
ui_LabeledTextEntry(Interface, MakeString("Tag Name"), &State->AssemblyDebugState.TagName);
ui_LabeledTextEntry(Interface, MakeString("Tag Value"), &State->AssemblyDebugState.TagValue);
if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite)
{
State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly);
State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip);
}
}break;
case ADS_Override_ChannelWhite:
{
u64 Board = 0;
u64 Strip = 0;
Board = ui_LabeledTextEntryU64(Interface, MakeString("Board"), Board);
Strip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), Strip);
State->AssemblyDebugState.TargetChannel = FSC(Board, Strip);
}break;
case ADS_Override_AllRed:
case ADS_Override_AllGreen:
case ADS_Override_AllBlue:
case ADS_Override_AllWhite:
{
State->AssemblyDebugState.Brightness = (u8)ui_LabeledRangeSlider(Interface, MakeString("Brightness"), (r32)State->AssemblyDebugState.Brightness, 0, 255);
}break;
default:
{
InterfaceAssert(Interface->PerFrameMemory);
State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly);
InterfaceAssert(Interface->PerFrameMemory);
State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip);
InterfaceAssert(Interface->PerFrameMemory);
}break;
}
ui_RangeSlider(Interface, MakeString("Test"), .5f, 0, 1);
ui_PopLayout(Interface, MakeString("Assembly Debug Layout"));
}
#define FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H
#endif // FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H

View File

@ -5,8 +5,16 @@
//
#ifndef FOLDHAUS_PANEL_FILE_VIEW_H
enum file_view_mode
{
FileViewMode_Load,
FileViewMode_Save,
};
struct file_view_state
{
file_view_mode Mode;
gs_string WorkingDirectory;
gs_memory_arena FileNamesArena;
gs_file_info_array FileNames;
@ -14,9 +22,18 @@ struct file_view_state
gs_file_info SelectedFile;
};
internal void
FileView_SetMode(panel* Panel, file_view_mode Mode)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
FileViewState->Mode = Mode;
}
internal void
FileView_Exit_(panel* FileViewPanel, app_state* State, context Context)
{
// TODO(pjs): Free State->FileNamesArena
Assert(FileViewPanel->IsModalOverrideFor != 0);
panel* ReturnTo = FileViewPanel->IsModalOverrideFor;
if (ReturnTo->ModalOverrideCB)
@ -30,7 +47,7 @@ global input_command* FileView_Commands = 0;
s32 FileView_CommandsCount = 0;
internal void
FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context)
FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context)
{
ClearArena(&State->FileNamesArena);
@ -43,23 +60,20 @@ FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state
u32 SecondLastSlashIndex = FindLast(SanitizedDirectory, LastSlashIndex - 1, '\\');
SanitizedDirectory = Substring(SanitizedDirectory, 0, SecondLastSlashIndex);
}
else if (StringsEqual(LastDir, ConstString(".")))
else if (StringsEqual(LastDir, ConstString(".")) && LastDir.Length > 1)
{
SanitizedDirectory = Substring(SanitizedDirectory, 0, LastSlashIndex);
}
State->WorkingDirectory = PushString(&State->FileNamesArena, WorkingDirectory.Length + 2);
PrintF(&State->WorkingDirectory, "%S", SanitizedDirectory);
if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '\\')
gs_file_info NewWorkingDirectory = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDirectory);
if (NewWorkingDirectory.IsDirectory)
{
AppendPrintF(&State->WorkingDirectory, "\\");
}
if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '*')
{
AppendPrintF(&State->WorkingDirectory, "*");
}
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
// in some cases. Shouldn't be a problem but it is unnecessary
PrintF(&State->WorkingDirectory, "%S", WorkingDirectory);
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, State->WorkingDirectory.ConstString, EnumerateDirectory_IncludeDirectories);
}
}
GSMetaTag(panel_init);
@ -71,7 +85,10 @@ FileView_Init(panel* Panel, app_state* State, context Context)
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
Panel->StateMemory = StructToData(FileViewState, file_view_state);
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator);
FileViewUpdateWorkingDirectory(ConstString("."), FileViewState, Context);
// TODO(pjs): this shouldn't be stored in permanent
FileViewState->WorkingDirectory = PushString(&State->Permanent, 256);
FileView_UpdateWorkingDirectory(ConstString("."), FileViewState, Context);
}
GSMetaTag(panel_cleanup);
@ -88,18 +105,34 @@ internal void
FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds);
ui_PushLayout(&State->Interface, Layout);
Assert(FileViewState->Mode == FileViewMode_Save);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
{
if (ui_Button(&State->Interface, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
// Header
ui_DrawString(&State->Interface, FileViewState->WorkingDirectory);
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->WorkingDirectory))
{
// if last character is a slash, update pwd, and clear the filter string
// otherwise update the filter string
gs_string Pwd = FileViewState->WorkingDirectory;
char LastChar = Pwd.Str[Pwd.Length - 1];
if (LastChar == '\\' || LastChar == '/')
{
FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context);
}
else
{
}
}
// File Display
ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count);
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
{
gs_file_info File = FileViewState->FileNames.Values[i];
@ -108,11 +141,12 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length);
gs_string PathString = PushString(State->Transient, FileName.Length);
PrintF(&PathString, "%S", FileName);
if (ui_LayoutListButton(&State->Interface, &Layout, PathString, i))
if (ui_LayoutListButton(&State->Interface, PathString, i))
{
if (File.IsDirectory)
{
FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context);
FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context);
}
else
{
@ -121,11 +155,11 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
}
}
}
ui_PopLayout(&State->Interface);
ui_EndList(&State->Interface);
}
ui_PopLayout(&State->Interface, MakeString("FileView Layout"));
}
#define FOLDHAUS_PANEL_FILE_VIEW_H
#endif // FOLDHAUS_PANEL_FILE_VIEW_H

View File

@ -38,50 +38,44 @@ GSMetaTag(panel_type_hierarchy);
internal void
HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds);
ui_PushLayout(&State->Interface, Layout);
gs_string TempString = PushString(State->Transient, 256);
u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1;
u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count);
rect2* LineBounds = PushArray(State->Transient, rect2, LineCount);
// Fill in alternating color rows for the backgrounds
for (u32 Line = 0; Line < LineCount; Line++)
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout"));
ui_BeginList(&State->Interface, MakeString("Hierarchy List"), 10, State->Assemblies.Count + 1);
{
LineBounds[Line] = ui_ReserveElementBounds(&Layout);
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line);
ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor);
}
ui_column_spec Cols[2] = {
ui_column_spec{ UIColumnSize_Fill, 0 },
ui_column_spec{ UIColumnSize_MaxWidth, 128 }
};
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
ui_BeginRow(&State->Interface, 2, &Cols[0]);
for (u32 AssemblyIndex = 0; AssemblyIndex < AssembliesToDraw; AssemblyIndex++)
{
assembly Assembly = State->Assemblies.Values[AssemblyIndex];
assembly Assembly = State->Assemblies.Values[i];
PrintF(&TempString, "%S", Assembly.Name);
ui_StartRow(&State->Interface, 2);
ui_Label(&State->Interface, TempString);
if (ui_Button(&State->Interface, MakeString("X")))
{
ui_DrawString(&State->Interface, TempString);
if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex))
{
UnloadAssembly(AssemblyIndex, State, Context);
}
UnloadAssembly(i, State, Context);
}
ui_EndRow(&State->Interface);
}
if (AssembliesToDraw < LineCount)
{
// NOTE(Peter): Add assembly button
PrintF(&TempString, "+ Add Assembly");
if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw))
ui_BeginRow(&State->Interface, 2, &Cols[0]);
ui_Label(&State->Interface, MakeString(" "));
if (ui_Button(&State->Interface, MakeString("+ Add Assembly")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
FileView_SetMode(FileBrowser, FileViewMode_Save);
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
}
ui_EndRow(&State->Interface);
}
ui_PopLayout(&State->Interface);
ui_EndList(&State->Interface);
ui_PopLayout(&State->Interface, MakeString("Hierarchy Layout"));
}

View File

@ -25,53 +25,72 @@ ProfilerView_Cleanup(panel* Panel, app_state* State)
}
internal void
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient)
{
v4 ThreadColors[] = {
v4{.73f, .33f, .83f, 1},
v4{0, .50f, .50f, 1},
v4{.83f, 0, 0, 1},
v4{.33f, .49f, .83f, 1},
v4{.74f, .40f, .25f, 1},
};
rect2 Bounds = ui_LayoutRemaining(Layout);
rect2 Bounds = ui_LayoutRemaining(*Layout);
r32 Width = Rect2Width(Bounds);
r32 DepthHeight = 64;
r32 DepthHeight = 32;
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
r32 FrameTotalCycles = (r32)(VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles);
debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices,
VisibleFrame);
r32 NextThreadTop = Bounds.Max.y;
scope_record* HotRecord = 0;
scope_name* HotRecordName = 0;
char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
for (s32 i = 0; i < ThreadScopeCalls->Count; i++)
for (s32 t = 0; t < VisibleFrame->ThreadCount; t++)
{
scope_record* Record = ThreadScopeCalls->Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles;
r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles;
debug_scope_record_list ThreadCalls = VisibleFrame->ThreadCalls[t];
gs_string String = PushString(Transient, 256);
r32 ThreadScopeMin = Bounds.Max.y;
//PrintF(&String, "Thread %d", ThreadCalls.ThreadId);
//ui_Label(Interface, String, rect2{ThreadScopeMin);
r32 Hue = (r32)(t) / (r32)(VisibleFrame->ThreadCount);
Hue += (.5f * (t % 2));
v4 ThreadHSV = v4{ 360.0f * Hue, .5f, 1.0f, 1.0f };
v4 ThreadRGB = HSVToRGB(ThreadHSV);
for (s32 i = 0; i < ThreadCalls.Count; i++)
{
scope_record* Record = ThreadCalls.Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
s64 OffsetStart = Record->StartCycles - FrameStartCycles;
s64 OffsetEnd = Record->EndCycles - FrameStartCycles;
r32 PercentStart = (r32)(OffsetStart) / FrameTotalCycles;
r32 PercentEnd = (r32)(OffsetEnd) / FrameTotalCycles;
r32 PercentWidth = PercentEnd - PercentStart;
r32 PixelStart = Bounds.Min.x + (Width * PercentStart);
r32 PixelEnd = Bounds.Min.x + (Width * PercentEnd);
r32 MinY = Bounds.Max.y - ((Record->CallDepth + 1) * DepthHeight);
rect2 ScopeBounds = {
v2{ PixelStart, MinY },
v2{ PixelEnd, MinY + (DepthHeight - 4) }
v2{0, 0},
v2{PercentWidth * Width, DepthHeight - 4},
};
v2 Offset = {
Bounds.Min.x + (PercentStart * Width),
NextThreadTop - ((Record->CallDepth + 1) * DepthHeight)
};
ScopeBounds = Rect2Translate(ScopeBounds, Offset);
ThreadScopeMin = Min(ScopeBounds.Min.y, ThreadScopeMin);
if (Rect2Width(ScopeBounds) >= 1)
{
v4 Color = ThreadColors[0];
v4 Color = ThreadRGB;
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
{
Color = GreenV4;
HotRecord = Record;
HotRecordName = Name;
ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover"));
{
s64 Cycles = (Record->EndCycles - Record->StartCycles);
r32 PercentFrame = (r32)(Cycles) / FrameTotalCycles;
PrintF(&String, "%S : %.2f%% frame | %dcy",
Name->Name,
PercentFrame,
Cycles);
ui_Label(Interface, String);
}
ui_EndMousePopup(Interface);
}
ui_FillRect(Interface, ScopeBounds, Color);
@ -79,32 +98,44 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
}
}
if (HotRecord != 0)
{
PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles);
rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32});
ui_DrawString(Interface, String, TextBounds);
NextThreadTop = ThreadScopeMin;
}
}
internal void
RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
{
char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
r32 ColumnWidths[] = {256, 128, 128, 128, 128};
ui_StartRow(Interface, 5, &ColumnWidths[0]);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fixed, 256 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 }};
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
{
ui_DrawString(Interface, MakeString("Procedure"));
ui_DrawString(Interface, MakeString("% Frame"));
ui_DrawString(Interface, MakeString("Seconds"));
ui_DrawString(Interface, MakeString("Cycles"));
ui_DrawString(Interface, MakeString("Calls"));
ui_Label(Interface, MakeString("Procedure"));
ui_Label(Interface, MakeString("% Frame"));
ui_Label(Interface, MakeString("Seconds"));
ui_Label(Interface, MakeString("Cycles"));
ui_Label(Interface, MakeString("Calls"));
}
ui_EndRow(Interface);
s32 CountedScopes = 0;
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
CountedScopes += 1;
}
}
ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes);
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
@ -112,26 +143,24 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu
{
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
ui_StartRow(Interface, 5, &ColumnWidths[0]);
{
PrintF(&String, "%S", NameEntry.Name);
ui_DrawString(Interface, String);
ui_Label(Interface, String);
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
ui_DrawString(Interface, String);
ui_Label(Interface, String);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
ui_DrawString(Interface, String);
ui_Label(Interface, String);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
ui_DrawString(Interface, String);
ui_Label(Interface, String);
PrintF(&String, "%d", CollatedRecord->CallCount);
ui_DrawString(Interface, String);
ui_Label(Interface, String);
}
}
ui_EndRow(Interface);
}
}
ui_EndList(Interface);
}
GSMetaTag(panel_render);
@ -179,23 +208,22 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds);
ui_PushLayout(&State->Interface, Layout);
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
ui_StartRow(&State->Interface, 4);
ui_BeginRow(&State->Interface, 4);
{
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_DrawString(&State->Interface, String);
ui_Label(&State->Interface, String);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_DrawString(&State->Interface, String);
ui_Label(&State->Interface, String);
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
// be removed, or used for something else
ui_ReserveElementBounds(&Layout);
ui_ReserveBounds(&State->Interface, Layout, true);
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
{
@ -204,7 +232,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
}
ui_EndRow(&State->Interface);
ui_StartRow(&State->Interface, 8);
ui_BeginRow(&State->Interface, 8);
{
if (ui_Button(&State->Interface, MakeString("Scope View")))
{
@ -226,7 +254,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
ui_PopLayout(&State->Interface);
ui_PopLayout(&State->Interface, MakeString("Profiler Layout"));
}

View File

@ -5,6 +5,12 @@
//
#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H
// Definitions
#define PIXEL_TO_WORLD_SCALE 0.01f
//
struct sculpture_view_panel_state
{
camera Camera;
@ -24,8 +30,8 @@ OPERATION_RENDER_PROC(Update3DViewMouseRotate)
v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos;
m44 XRotation = M44RotationX(-TotalDeltaPos.y * State->PixelsToWorldScale);
m44 YRotation = M44RotationY(TotalDeltaPos.x * State->PixelsToWorldScale);
m44 XRotation = M44RotationX(-TotalDeltaPos.y * PIXEL_TO_WORLD_SCALE);
m44 YRotation = M44RotationY(TotalDeltaPos.x * PIXEL_TO_WORLD_SCALE);
m44 Combined = XRotation * YRotation;
OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz;
@ -226,14 +232,10 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, PanelState->Camera, PanelBounds);
gs_string Tempgs_string = PushString(State->Transient, 256);
PrintF(&Tempgs_string, "%f %f", LedOnScreenPosition.x, LedOnScreenPosition.y);
PrintF(&Tempgs_string, "Hot Id: %u, ZIndex: %u | Active Id: %u", State->Interface.HotWidget.Id,
State->Interface.HotWidget.ZIndex,State->Interface.ActiveWidget.Id);
DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4);
v2 BoxHalfDim = v2{ 25, 25 };
v2 BoxMin = LedOnScreenPosition - BoxHalfDim;
v2 BoxMax = LedOnScreenPosition + BoxHalfDim;
PushRenderBoundingBox2D(RenderBuffer, BoxMin, BoxMax, 2.0f, TealV4);
}
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}

View File

@ -4,7 +4,7 @@
// Creation Date: 2020-10-17
//
#ifndef FOLDHAUS_PANEL_TYPES_CPP
global s32 GlobalPanelDefsCount = 6;
global s32 GlobalPanelDefsCount = 7;
global panel_definition GlobalPanelDefs[] = {
{ "File View", 9, FileView_Init, FileView_Cleanup, FileView_Render, FileView_Commands, FileView_CommandsCount },
{ "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands, SculptureView_CommandsCount },
@ -12,6 +12,7 @@ global panel_definition GlobalPanelDefs[] = {
{ "Dmx View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, DMXView_Commands, DMXView_CommandsCount },
{ "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, HierarchyView_Commands, HierarchyView_CommandsCount },
{ "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, ProfilerView_Commands, ProfilerView_CommandsCount },
{ "Assembly Debug", 14, AssemblyDebug_Init, AssemblyDebug_Cleanup, AssemblyDebug_Render, 0, 0 },
};
#define FOLDHAUS_PANEL_TYPES_CPP
#endif // FOLDHAUS_PANEL_TYPES_CPP

View File

@ -10,8 +10,8 @@ enum panel_type {
PanelType_AnimationTimeline,
PanelType_DMXView,
PanelType_HierarchyView,
PanelType_NodeGraph,
PanelType_ProfilerView,
PanelType_AssemblyDebug,
};
#define FOLDHAUS_PANEL_TYPES_H
#endif // FOLDHAUS_PANEL_TYPES_H

View File

@ -5,7 +5,7 @@
//
#ifndef FOLDHAUS_ANIMATION
#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
typedef ANIMATION_PROC(animation_proc);
struct frame_range
@ -14,6 +14,11 @@ struct frame_range
s32 Max;
};
struct animation_pattern_handle
{
s32 IndexPlusOne;
};
// NOTE(pjs): An animation block is a time range paired with an
// animation_pattern (see below). While a timeline's current time
// is within the range of a block, that particular block's animation
@ -21,7 +26,7 @@ struct frame_range
struct animation_block
{
frame_range Range;
u32 AnimationProcHandle;
animation_pattern_handle AnimationProcHandle;
u32 Layer;
};
@ -76,6 +81,9 @@ struct animation
animation_block_array Blocks_;
frame_range PlayableRange;
// The information / path to the file where this animation is to be saved / where it is loaded from
gs_file_info FileInfo;
};
struct animation_array
@ -132,6 +140,13 @@ struct animation_pattern
animation_proc* Proc;
};
struct animation_pattern_array
{
animation_pattern* Values;
u32 Count;
u32 CountMax;
};
// Serialization
enum animation_field
@ -185,6 +200,55 @@ global gs_const_string AnimationFieldStrings[] = {
ConstString("animation_name"),// AnimField_BlockAnimName
};
//////////////////////////
//
// Patterns List
internal animation_pattern_array
Patterns_Create(gs_memory_arena* Arena, s32 CountMax)
{
animation_pattern_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Arena, animation_pattern, Result.CountMax);
return Result;
}
#define Patterns_PushPattern(array, proc) Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)))
internal void
Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength)
{
Assert(Array->Count < Array->CountMax);
animation_pattern Pattern = {0};
Pattern.Name = Name;
Pattern.NameLength = NameLength;
Pattern.Proc = Proc;
Array->Values[Array->Count++] = Pattern;
}
internal animation_pattern_handle
Patterns_IndexToHandle(s32 Index)
{
animation_pattern_handle Result = {};
Result.IndexPlusOne = Index + 1;
return Result;
}
internal animation_pattern
Patterns_GetPattern(animation_pattern_array Patterns, animation_pattern_handle Handle)
{
animation_pattern Result = {0};
if (Handle.IndexPlusOne > 0)
{
u32 Index = Handle.IndexPlusOne - 1;
Assert(Index < Patterns.Count);
Result = Patterns.Values[Index];
}
return Result;
}
//////////////////////////
//
// Anim Block Array
@ -291,7 +355,7 @@ AnimationArray_Push(animation_array* Array, animation Value)
// Animation
internal handle
Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, u32 AnimationProcHandle, u32 LayerIndex)
Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, animation_pattern_handle AnimationProcHandle, u32 LayerIndex)
{
Assert(LayerIndex < Animation->Layers.Count);
@ -420,6 +484,24 @@ ClampFrameToRange(s32 Frame, frame_range Range)
// System
struct animation_system_desc
{
gs_memory_arena* Storage;
u32 AnimArrayCount;
r32 SecondsPerFrame;
};
internal animation_system
AnimationSystem_Init(animation_system_desc Desc)
{
animation_system Result = {};
Result.Storage = Desc.Storage;
Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount);
Result.SecondsPerFrame = Desc.SecondsPerFrame;
return Result;
}
internal animation*
AnimationSystem_GetActiveAnimation(animation_system* System)
{

View File

@ -81,22 +81,22 @@ LedBlend_GetProc(blend_mode BlendMode)
}
internal void
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern* Patterns, gs_memory_arena* Transient)
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array Patterns, gs_memory_arena* Transient,
u8* UserData)
{
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
// :AnimProcHandle
u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc;
AnimationProc(Buffer, Assembly, SecondsIntoBlock, Transient);
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
Pattern.Proc(Buffer, Assembly, SecondsIntoBlock, Transient, UserData);
}
internal void
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
led_system* LedSystem,
animation_pattern* Patterns,
gs_memory_arena* Transient)
animation_pattern_array Patterns,
gs_memory_arena* Transient,
u8* UserData)
{
s32 CurrentFrame = System->CurrentFrame;
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
@ -150,14 +150,14 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
{
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
animation_block Block = LayerFrame.Hot;
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient);
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
}
if (LayerFrame.HasNextHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
animation_block Block = LayerFrame.NextHot;
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient);
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
}
}
@ -194,6 +194,8 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
}
}
}
System->LastUpdatedFrame = System->CurrentFrame;
}
#define FOLDHAUS_ANIMATION_RENDERER_CPP

View File

@ -6,7 +6,7 @@
#ifndef FOLDHAUS_ANIMATION_SERIALIZER_CPP
internal gs_string
AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memory_arena* Arena)
AnimSerializer_Serialize(animation Anim, animation_pattern_array Patterns, gs_memory_arena* Arena)
{
serializer Serializer = {0};
Serializer.String = PushString(Arena, 4096);
@ -45,10 +45,7 @@ AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memo
// TODO(pjs): Handle free'd animation blocks
animation_block AnimationBlockAt = Anim.Blocks_.Values[i];
// TODO(pjs): Systematize the AnimationProcHandle
// :AnimProcHandle
u32 AnimationProcIndex = AnimationBlockAt.AnimationProcHandle - 1;
animation_pattern Animation = GlobalClips[AnimationProcIndex];
animation_pattern Animation = Patterns_GetPattern(Patterns, AnimationBlockAt.AnimationProcHandle);
Serializer_OpenStruct(&Serializer, AnimField_Block);
{
@ -70,7 +67,7 @@ AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memo
}
internal animation
AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, animation_pattern* AnimClips)
AnimParser_Parse(gs_string File, gs_memory_arena* Arena, animation_pattern_array AnimPatterns)
{
animation Result = {0};
@ -162,12 +159,13 @@ AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, ani
// TODO(pjs): AnimName -> Animation Proc Handle
gs_string AnimName = Parser_ReadStringValue(&Parser, AnimField_BlockAnimName);
Block.AnimationProcHandle = 0;
for (u32 i = 0; i < AnimClipsCount; i++)
Block.AnimationProcHandle = {0};
for (u32 i = 0; i < AnimPatterns.Count; i++)
{
if (StringEqualsCharArray(AnimName.ConstString, AnimClips[i].Name, CStringLength(AnimClips[i].Name)))
animation_pattern Pattern = AnimPatterns.Values[i];
if (StringEqualsCharArray(AnimName.ConstString, Pattern.Name, Pattern.NameLength))
{
Block.AnimationProcHandle = i + 1;
Block.AnimationProcHandle = Patterns_IndexToHandle(i);
break;
}
}

View File

@ -72,7 +72,7 @@ AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, g
///////////////////////////
internal led_system
LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax)
LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
{
led_system Result = {};
Result.PlatformMemory = PlatformMemory;
@ -136,7 +136,7 @@ LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position)
}
internal u32
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex)
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex, u32 LedLUTStartIndex)
{
u32 LedsAdded = 0;
@ -154,7 +154,7 @@ Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* Str
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step] = LedIndex;
StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex;
}
}break;
@ -164,7 +164,7 @@ Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* Str
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded);
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded);
}
}break;
@ -190,7 +190,7 @@ ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
strip_gen_data GenData = StripAt->GenerationData;
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded);
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0);
}
}
@ -208,7 +208,8 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
assembly* NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch))
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
if (AssemblyParser.Success)
{
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
@ -217,6 +218,14 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
FreeMemoryArena(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
for (parser_error* ErrorAt = AssemblyParser.ErrorsRoot;
ErrorAt != 0;
ErrorAt = ErrorAt->Next)
{
OutputDebugString(ErrorAt->Message.Str);
}
}
else
{
@ -256,20 +265,11 @@ AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_con
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.TagsCount; j++)
{
v2_tag TagAt = StripAt.Tags[j];
if (TagAt.NameHash == NameHash)
{
// NOTE(pjs): We can pass an empty string to the Value parameter,
// and it will match all values of Tag
if (ValueHash == 0 || ValueHash == TagAt.ValueHash)
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
{
Result.StripIndices[Result.Count++] = StripIndex;
}
}
}
}
return Result;
}

View File

@ -160,7 +160,6 @@ struct assembly_array
assembly* Values;
};
internal led_buffer*
LedSystemGetBuffer(led_system* System, u32 Index)
{
@ -205,5 +204,34 @@ StripGenData_CountLeds(strip_gen_data Data)
return Result;
}
internal bool
AssemblyStrip_HasTagValue(v2_strip Strip, u64 NameHash, u64 ValueHash)
{
bool Result = false;
for (u32 i = 0; i < Strip.TagsCount; i++)
{
v2_tag TagAt = Strip.Tags[i];
if (TagAt.NameHash == NameHash)
{
// NOTE(pjs): We can pass an empty string to the Value parameter,
// and it will match all values of Tag
if (ValueHash == 0 || ValueHash == TagAt.ValueHash)
{
Result = true;
break;
}
}
}
return Result;
}
internal bool
AssemblyStrip_HasTagValueSLOW(v2_strip Strip, char* Name, char* Value)
{
u64 NameHash = HashDJB2ToU32(Name);
u64 ValueHash = HashDJB2ToU32(Value);
return AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash);
}
#define FOLDHAUS_ASSEMBLY_H
#endif // FOLDHAUS_ASSEMBLY_H

View File

@ -0,0 +1,213 @@
//
// File: foldhaus_assembly_debug.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef FOLDHAUS_ASSEMBLY_DEBUG_H
enum override_type
{
ADS_Override_None,
ADS_Override_Strip,
ADS_Override_SoloStrip,
ADS_Override_AllRed,
ADS_Override_AllGreen,
ADS_Override_AllBlue,
ADS_Override_AllOff,
ADS_Override_AllWhite,
ADS_Override_TagWhite,
ADS_Override_TagStripWhite,
ADS_Override_ChannelWhite,
ADS_Override_Count,
};
global gs_const_string OverrideTypeStrings[] = {
LitString("Override_None"),
LitString("Override_Strip"),
LitString("Override_SoloStrip" ),
LitString("Override_AllRed" ),
LitString("Override_AllGreen" ),
LitString("Override_AllBlue" ),
LitString("ADS_Override_AllOff" ),
LitString("ADS_Override_AllWhite" ),
LitString("ADS_Override_TagWhite" ),
LitString("ADS_Override_TagStripWhite" ),
LitString("ADS_Override_ChannelWhite," ),
LitString("Override_Count"),
};
struct assembly_debug_state
{
override_type Override;
u32 TargetAssembly;
u32 TargetStrip;
gs_string TagName;
gs_string TagValue;
pixel TargetColor;
u32 TargetChannel;
u8 Brightness;
};
internal assembly_debug_state
AssemblyDebug_Create(gs_memory_arena* Storage)
{
assembly_debug_state Result = {};
Result.TagName = PushString(Storage, 256);
Result.TagValue = PushString(Storage, 256);
return Result;
}
internal void
AssemblyDebug_OverrideStripWithColor(v2_strip Strip, led_buffer LedBuffer, pixel Color)
{
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIdx = Strip.LedLUT[i];
LedBuffer.Colors[LedIdx] = Color;
}
}
internal void
AssemblyDebug_OverrideWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color)
{
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}
internal void
AssemblyDebug_OverrideTagValueWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color, gs_string TagName, gs_string TagValue)
{
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = HashDJB2ToU32(StringExpand(TagValue));
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash))
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}
}
internal void
AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assemblies, led_system LedSystem)
{
if (State.Override == ADS_Override_None) return;
State.TargetColor = pixel{255,255,255};
assembly Assembly = Assemblies.Values[State.TargetAssembly];
led_buffer LedBuffer = LedSystem.Buffers[Assembly.LedBufferIndex];
u8 V = State.Brightness;
switch (State.Override)
{
case ADS_Override_Strip:
{
v2_strip Strip = Assembly.Strips[State.TargetStrip];
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, State.TargetColor);
}break;
case ADS_Override_SoloStrip:
{
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
pixel Color = pixel{0,0,0};
if (s == State.TargetStrip)
{
Color = State.TargetColor;
}
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color);
}
}break;
case ADS_Override_AllRed:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, 0, 0});
}break;
case ADS_Override_AllGreen:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, V, 0});
}break;
case ADS_Override_AllBlue:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, V});
}break;
case ADS_Override_AllOff:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
}break;
case ADS_Override_AllWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, V, V});
}break;
case ADS_Override_TagWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
AssemblyDebug_OverrideTagValueWithColor(Assembly, LedBuffer, pixel{255, 255, 255}, State.TagName, State.TagValue);
}break;
case ADS_Override_TagStripWhite:
{
u64 NameHash = HashDJB2ToU32(StringExpand(State.TagName));
u64 ValueHash = HashDJB2ToU32(StringExpand(State.TagValue));
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
v2_strip Strip = Assembly.Strips[State.TargetStrip];
if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash))
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer,
pixel{255, 255, 255});
}
}break;
case ADS_Override_ChannelWhite:
{
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
if (Strip.UARTAddr.Channel == State.TargetChannel)
{
AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, pixel{255, 255, 255});
}
}
}break;
case ADS_Override_None:
{
}break;
InvalidDefaultCase;
}
if (State.Override )
{
}
}
#define FOLDHAUS_ASSEMBLY_DEBUG_H
#endif // FOLDHAUS_ASSEMBLY_DEBUG_H

View File

@ -225,7 +225,7 @@ AssemblyParser_ReadSequence(parser* Parser, assembly* Assembly)
internal strip_gen_data
AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly)
{
strip_gen_data Result = {0};
strip_gen_data Result = {};
if (Parser_ReadOpenStruct(Parser, AssemblyField_Segment))
{
@ -258,12 +258,13 @@ AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly)
return Result;
}
internal bool
internal parser
ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient)
{
Assembly->LedCountTotal = 0;
parser Parser = {0};
Parser.FileName = FileName;
Parser.String = FileText;
Parser.Identifiers = &AssemblyFieldIdentifiers[0];
Parser.IdentifiersCount = AssemblyField_Count;
@ -271,6 +272,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
Parser.LineStart = Parser.At;
Parser.Arena = &Assembly->Arena;
Parser.Transient = Transient;
Parser.Success = true;
Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName);
Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale);
@ -298,6 +300,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
else
{
Parser_PushErrorF(&Parser, "Invalid output mode specified for assembly.");
Parser.Success = false;
}
for (u32 i = 0; i < Assembly->StripCount; i++)
@ -316,16 +319,17 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
if (!Parser_ReadCloseStruct(&Parser))
{
Parser_PushErrorF(&Parser, "Strip struct doesn't close where expected");
Parser.Success = false;
}
}
else
{
Parser_PushErrorF(&Parser, "Expected a strip struct but none was found");
Parser.Success = false;
}
}
// TODO(pjs): invalidate the file if its incorrect
return true; //Tokenizer.ParsingIsValid;
return Parser;
}
#define FOLDHAUS_ASSEMBLY_PARSER_CPP

View File

@ -95,5 +95,14 @@ AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string Co
Buffer->ComPort = ComPort;
}
internal addressed_data_buffer_list
AddressedDataBufferList_Create(gs_thread_context TC)
{
addressed_data_buffer_list Result = {};
Result.Arena = AllocatorAllocStruct(TC.Allocator, gs_memory_arena);
*Result.Arena = CreateMemoryArena(TC.Allocator);
return Result;
}
#define FOLDHAUS_ADDRESSED_DATA_H
#endif // FOLDHAUS_ADDRESSED_DATA_H

View File

@ -135,7 +135,7 @@ struct parser_error
{
gs_string Message;
gs_string FileName;
gs_const_string FileName;
u32 LineNumber;
parser_error* Next;
@ -143,7 +143,7 @@ struct parser_error
struct parser
{
gs_string FileName;
gs_const_string FileName;
gs_string String;
@ -160,6 +160,8 @@ struct parser
parser_error* ErrorsRoot;
parser_error* ErrorsHead;
bool Success;
};
internal void
@ -170,13 +172,17 @@ Parser_PushErrorF(parser* Parser, char* Format, ...)
Error->LineNumber = Parser->Line;
Error->Message = PushString(Parser->Transient, 1024);
PrintF(&Error->Message, "File: %S Line: %d - ", Error->FileName, Error->LineNumber);
PrintF(&Error->Message, "Error:\n");
va_list Args;
va_start(Args, Format);
PrintFArgsList(&Error->Message, Format, Args);
va_end(Args);
AppendPrintF(&Error->Message, "\n\tFile: %S\n\tLine: %d\n",
Error->FileName, Error->LineNumber);
NullTerminate(&Error->Message);
SLLPushOrInit(Parser->ErrorsRoot, Parser->ErrorsHead, Error);
}
@ -202,8 +208,27 @@ Parser_AdvanceChar(parser* P)
{
P->Line += 1;
P->LineStart = P->At + 1;
}
if ((P->At[0] == '\n' && P->At[1] == '\r') ||
(P->At[0] == '\r' && P->At[1] == '\n'))
{
P->At++;
P->At++;
}
else if (P->At[0] == '\n')
{
P->At++;
}
else
{
// TODO(pjs): Not sure this is actually invalid
InvalidCodePath;
}
}
else
{
P->At++;
}
}
internal void

View File

@ -27,10 +27,15 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask
#if 1
OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B;
#else
OutputPixel[0] = 255;
OutputPixel[1] = 255;
OutputPixel[2] = 255;
#endif
if (Channel->ElementsCount == 4)
{
// TODO(pjs): Calculate white from the RGB components?
@ -56,7 +61,7 @@ UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
}
internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient)
{
uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3;
@ -64,30 +69,103 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli
// NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will
// be bigger than this, but their size is based on the number of pixels in each channel
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel
struct strips_to_data_buffer
{
gs_const_string ComPort;
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
u32* StripIndices;
u32 StripIndicesCount;
u32 StripIndicesCountMax;
u64 LedCount;
u8** ChannelsStart;
strips_to_data_buffer* Next;
};
u32 BuffersNeededCount = 0;
strips_to_data_buffer* BuffersNeededHead = 0;
strips_to_data_buffer* BuffersNeededTail = 0;
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
// If there is a buffer for this com port already created
// we use that
strips_to_data_buffer* BufferSelected = 0;
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
if (StringsEqual(At->ComPort, StripAt.UARTAddr.ComPort.ConstString))
{
BufferSelected = At;
break;
}
}
// if no existing buffer for this com port
// create a new one
if (!BufferSelected)
{
BufferSelected = PushStruct(Transient, strips_to_data_buffer);
*BufferSelected = {};
BufferSelected->ComPort = StripAt.UARTAddr.ComPort.ConstString;
// we don't know at this point how many indices per
// com port so just make enough room to fit all the strips
// if necessary
BufferSelected->StripIndicesCountMax = Assembly.StripCount;
BufferSelected->StripIndices = PushArray(Transient, u32, BufferSelected->StripIndicesCountMax);
BufferSelected->LedCount = 0;
BufferSelected->Next = 0;
SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected);
BuffersNeededCount += 1;
}
Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax);
u32 Index = BufferSelected->StripIndicesCount++;
BufferSelected->StripIndices[Index] = StripIdx;
BufferSelected->LedCount += StripAt.LedCount;
}
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel
At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount);
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
gs_const_string ComPort = At->ComPort;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
for (u32 i = 0; i < At->StripIndicesCount; i++)
{
u32 StripIdx = At->StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIdx];
ChannelSettings.PixelsCount = StripAt.LedCount;
UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer);
}
UART_DrawAll_Create(&WriteCursor);
}
}
}

View File

@ -35,6 +35,8 @@ struct uart_footer
#pragma pack(pop)
#define UART_MESSAGE_MIN_SIZE sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer)
global u32 UART_CRCTable[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d

View File

@ -0,0 +1,46 @@
//
// File: userspace.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-30
//
#ifndef USERSPACE_CPP
internal void
US_LoadPatterns(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->LoadPatterns)
{
Desc->LoadPatterns(State);
}
}
internal void
US_CustomInit(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->CustomInit)
{
Desc->UserData = Desc->CustomInit(State, Context);
}
}
internal void
US_CustomUpdate(user_space_desc* Desc, app_state* State, context* Context)
{
if (Desc->CustomUpdate)
{
Desc->CustomUpdate(Desc->UserData, State, Context);
}
}
internal void
US_CustomCleanup(user_space_desc* Desc, app_state* State, context Context)
{
if (Desc->CustomCleanup)
{
Desc->CustomCleanup(Desc->UserData, State, Context);
}
}
#define USERSPACE_CPP
#endif // USERSPACE_CPP

View File

@ -0,0 +1,31 @@
//
// File: userspace.h
// Author: Peter Slattery
// Creation Date: 2021-01-30
//
#ifndef USERSPACE_H
#define US_LOAD_PATTERNS(name) void name(app_state* State)
typedef US_LOAD_PATTERNS(us_load_patterns_proc);
#define US_CUSTOM_INIT(name) gs_data name (app_state* State, context Context)
typedef US_CUSTOM_INIT(us_custom_init_proc);
#define US_CUSTOM_UPDATE(name) void name(gs_data UserData, app_state* State, context* Context)
typedef US_CUSTOM_UPDATE(us_custom_update_proc);
#define US_CUSTOM_CLEANUP(name) void name(gs_data UserData, app_state* State, context Context)
typedef US_CUSTOM_CLEANUP(us_custom_cleanup_proc);
typedef struct user_space_desc
{
us_load_patterns_proc* LoadPatterns;
us_custom_init_proc* CustomInit;
us_custom_update_proc* CustomUpdate;
us_custom_cleanup_proc* CustomCleanup;
gs_data UserData;
} user_space_desc;
#define USERSPACE_H
#endif // USERSPACE_H

View File

@ -8,8 +8,6 @@
#include "foldhaus_platform.h"
#include "foldhaus_app.h"
////////////////////////////////////////////////////////////////////////
RELOAD_STATIC_DATA(ReloadStaticData)
{
app_state* State = (app_state*)Context.MemoryBase;
@ -17,6 +15,8 @@ RELOAD_STATIC_DATA(ReloadStaticData)
GlobalDebugServices = DebugServices;
State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
}
INITIALIZE_APPLICATION(InitializeApplication)
@ -26,133 +26,69 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator);
State->Transient = Context.ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
State->GlobalLog = PushStruct(State->Transient, event_log);
*State->GlobalLog = {0};
State->GlobalLog = PushStruct(&State->Permanent, event_log);
State->CommandQueue = CommandQueue_Create(&State->Permanent, 32);
// TODO(Peter): put in InitializeInterface?
r32 FontSize = 14;
{
gs_file FontFile = ReadEntireFile(Context.ThreadContext.FileHandler, ConstString("data/Anonymous Pro.ttf"));
if (FileNoError(FontFile))
{
bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font);
animation_system_desc AnimSysDesc = {};
AnimSysDesc.Storage = &State->Permanent;
AnimSysDesc.AnimArrayCount = 32;
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
Font->BitmapWidth = 512;
Font->BitmapHeight = 512;
Font->BitmapBytesPerPixel = 4;
Font->BitmapMemory = PushArray(&State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel);
Font->BitmapStride = Font->BitmapWidth * Font->BitmapBytesPerPixel;
ZeroMemoryBlock(Font->BitmapMemory, Font->BitmapStride * Font->BitmapHeight);
platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false);
Font->PixelHeight = FontInfo.PixelHeight;
Font->Ascent = FontInfo.Ascent;
Font->Descent = FontInfo.Descent;
Font->Leading = FontInfo.Leading;
Font->MaxCharWidth = FontInfo.MaxCharWidth;
Font->CodepointDictionarySize = (FontInfo.CodepointOnePastLast - FontInfo.CodepointStart);
Font->CodepointDictionaryCount = 0;
Font->CodepointKeys = PushArray(&State->Permanent, char, Font->CodepointDictionarySize);
Font->CodepointValues = PushArray(&State->Permanent, codepoint_bitmap, Font->CodepointDictionarySize);
for (s32 Codepoint = FontInfo.CodepointStart;
Codepoint < FontInfo.CodepointOnePastLast;
Codepoint++)
{
u32 CodepointX, CodepointY;
GetNextCodepointOffset(Font, &CodepointX, &CodepointY);
u32 CodepointW, CodepointH;
Context.PlatformDrawFontCodepoint(
Font->BitmapMemory,
Font->BitmapWidth,
Font->BitmapHeight,
CodepointX, CodepointY,
Codepoint, FontInfo,
&CodepointW, &CodepointH);
AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY);
}
State->Interface.Style.Font = Font;
Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory,
Font->BitmapWidth, Font->BitmapHeight);
}
else
{
LogError(State->GlobalLog, "Unable to load font");
}
}
State->Interface.Style.FontSize = FontSize;
State->Interface.Style.PanelBGColors[0] = v4{.3f, .3f, .3f, 1};
State->Interface.Style.PanelBGColors[1] = v4{.4f, .4f, .4f, 1};
State->Interface.Style.PanelBGColors[2] = v4{.5f, .5f, .5f, 1};
State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1};
State->Interface.Style.ButtonColor_Inactive = BlackV4;
State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1};
State->Interface.Style.ButtonColor_Selected = v4{.3f, .3f, .3f, 1};
State->Interface.Style.TextColor = WhiteV4;
State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f };
State->Interface.Style.Margin = v2{5, 5};
State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface);
State->Interface.WidgetsCountMax = 4096;
State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax);
interface_config IConfig = {0};
IConfig.FontSize = 14;
IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f };
IConfig.ButtonColor_Inactive = BlackV4;
IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f };
IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f };
IConfig.TextColor = WhiteV4;
IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f };
IConfig.Margin = v2{5, 5};
State->Interface = ui_InterfaceCreate(Context, IConfig, &State->Permanent);
State->SACN = SACN_Initialize(Context);
State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128);
#if 1
gs_const_string SculpturePath = ConstString("data/blumen_lumen_silver_spring.fold");
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
#endif
State->PixelsToWorldScale = .01f;
State->LedSystem = LedSystem_Create(Context.ThreadContext.Allocator, 128);
State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent);
State->AssemblyDebugState.Brightness = 255;
State->AssemblyDebugState.Override = ADS_Override_AllRed;
GlobalDebugServices->Interface.RenderSculpture = true;
ReloadStaticData(Context, GlobalDebugServices);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
{
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, Context);
panel* AnimPanel = RootPanel->Bottom;
Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, Context);
panel* TopPanel = RootPanel->Top;
SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, Context);
panel* LeftPanel = TopPanel->Left;
SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, Context);
panel* Profiler = LeftPanel->Right;
Panel_SetType(Profiler, &State->PanelSystem, PanelType_ProfilerView, State, Context);
panel* Hierarchy = LeftPanel->Left;
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_HierarchyView, State, Context);
}
State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext);
{ // Animation PLAYGROUND
State->AnimationSystem = {};
State->AnimationSystem.Storage = &State->Permanent;
State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32);
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
State->AnimationSystem.SecondsPerFrame = 1.f / 24.f;
animation Anim = {0};
Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one");
Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8);
Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8);
Anim.PlayableRange.Min = 0;
Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem);
Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem);
Animation_AddBlock(&Anim, 22, 123, 2, 0);
AnimationArray_Push(&State->AnimationSystem.Animations, Anim);
} // End Animation Playground
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
ReloadStaticData(Context, GlobalDebugServices);
US_CustomInit(&State->UserSpaceDesc, State, Context);
}
UPDATE_AND_RENDER(UpdateAndRender)
@ -171,42 +107,34 @@ UPDATE_AND_RENDER(UpdateAndRender)
AnimationSystem_Update(&State->AnimationSystem);
if (AnimationSystem_NeedsRender(State->AnimationSystem))
{
State->AnimationSystem.LastUpdatedFrame = State->AnimationSystem.CurrentFrame;
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
State->Assemblies,
&State->LedSystem,
GlobalAnimationPatterns,
State->Transient);
State->Patterns,
State->Transient,
State->UserSpaceDesc.UserData.Memory);
}
{
US_CustomUpdate(&State->UserSpaceDesc, State, Context);
AssemblyDebug_OverrideOutput(State->AssemblyDebugState,
State->Assemblies,
State->LedSystem);
Editor_Render(State, Context, RenderBuffer);
// NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information
assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem);
}
Editor_Render(State, Context, RenderBuffer);
// Checking for overflows
#if 0
{
DEBUG_TRACK_SCOPE(OverflowChecks);
AssertAllocationsNoOverflow(State->Permanent);
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
assembly* Assembly = &State->Assemblies.Values[i];
AssertAllocationsNoOverflow(Assembly->Arena);
}
}
#endif
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
}
CLEANUP_APPLICATION(CleanupApplication)
{
app_state* State = (app_state*)Context.MemoryBase;
US_CustomCleanup(&State->UserSpaceDesc, State, Context);
SACN_Cleanup(&State->SACN, Context);
}

View File

@ -19,6 +19,7 @@
#include "engine/assembly/foldhaus_assembly.h"
#include "engine/assembly/foldhaus_assembly_parser.cpp"
#include "engine/assembly/foldhaus_assembly_debug.h"
#include "engine/sacn/foldhaus_sacn.h"
#include "engine/uart/foldhaus_uart.h"
@ -40,6 +41,9 @@ typedef struct panel panel;
#include "engine/animation/foldhaus_animation_serializer.cpp"
#include "engine/animation/foldhaus_animation_renderer.cpp"
#include "engine/user_space.h"
#include "blumen_lumen.h"
struct app_state
{
gs_memory_arena Permanent;
@ -51,8 +55,10 @@ struct app_state
streaming_acn SACN;
led_system LedSystem;
assembly_array Assemblies;
assembly_debug_state AssemblyDebugState;
animation_system AnimationSystem;
event_log* GlobalLog;
animation_pattern_array Patterns;
// Interface
//
@ -65,155 +71,17 @@ struct app_state
panel_system PanelSystem;
panel* HotPanel;
r32 PixelsToWorldScale;
user_space_desc UserSpaceDesc;
};
internal void OpenColorPicker(app_state* State, v4* Address);
#include "engine/assembly/foldhaus_assembly.cpp"
// BEGIN TEMPORARY PATTERNS
internal void
TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{
led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient);
led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient);
#include "engine/user_space.cpp"
for (u32 i = 0; i < BlumenStrips.Count; i++)
{
u32 StripIndex = BlumenStrips.StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{
u32 LedIndex = StripAt.LedLUT[j];
Leds->Colors[LedIndex] = { 255, 0, 0 };
}
}
for (u32 i = 0; i < RadiaStrips.Count; i++)
{
u32 StripIndex = RadiaStrips.StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{
u32 LedIndex = StripAt.LedLUT[j];
Leds->Colors[LedIndex] = { 0, 255, 0 };
}
}
#if 0
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 LedPosition = Leds->Positions[LedIndex];
float PercentX = RemapClampedR32(LedPosition.x, -150.0f, 150.0f, 0.0f, 1.0f);
float PercentY = RemapClampedR32(LedPosition.y, -150.0f, 150.0f, 0.0f, 1.0f);
Leds->Colors[LedIndex].R = (u8)(PercentX * 255);
Leds->Colors[LedIndex].G = (u8)(PercentY * 255);
}
#endif
}
internal void
TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{
r32 PeriodicTime = (Time / PiR32) * 2;
r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f;
r32 ZeroOneCos = (CosR32(PeriodicTime) * .5f) + .5f;
pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) };
v4 Center = v4{0, 0, 0, 1};
r32 ThetaZ = Time / 2;
v4 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
v4 Right = V4Cross(Normal, v4{0, 1, 0, 0});
v4 FrontCenter = Center + (Normal * 25);
v4 BackCenter = Center - (Normal * 25);
r32 OuterRadiusSquared = 1000000;
r32 InnerRadiusSquared = 0;
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 Position = Leds->Positions[LedIndex];
v4 ToFront = Position + FrontCenter;
v4 ToBack = Position + BackCenter;
r32 ToFrontDotNormal = V4Dot(ToFront, Normal);
r32 ToBackDotNormal = V4Dot(ToBack, Normal);
ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000);
ToBackDotNormal = Clamp01(ToBackDotNormal * 1000);
r32 SqDistToCenter = V4MagSquared(Position);
if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared)
{
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
{
Leds->Colors[LedIndex] = Color;
}
else
{
//Leds->Colors[LedIndex] = {};
}
}
else
{
//Leds->Colors[LedIndex] = {};
}
}
}
internal void
TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{
v4 GreenCenter = v4{0, 0, 150, 1};
r32 GreenRadius = Abs(SinR32(Time)) * 200;
v4 TealCenter = v4{0, 0, 150, 1};
r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200;
r32 FadeDist = 35;
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 LedPosition = Leds->Positions[LedIndex];
u8 Red = 0;
u8 Green = 0;
u8 Blue = 0;
r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius);
r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist);
Green = (u8)(GreenBrightness * 255);
r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius);
r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist);
Red = (u8)(TealBrightness * 255);
Blue = (u8)(TealBrightness * 255);
Leds->Colors[LedIndex].R = Red;
Leds->Colors[LedIndex].B = Green;
Leds->Colors[LedIndex].G = Green;
}
}
internal void
Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient)
{
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
Leds->Colors[LedIndex].R = 0;
Leds->Colors[LedIndex].B = 255;
Leds->Colors[LedIndex].G = 255;
}
}
// END TEMPORARY PATTERNS
#include "patterns/blumen_patterns.h"
#include "blumen_lumen.cpp"
internal void
EndCurrentOperationMode(app_state* State)
@ -221,14 +89,6 @@ EndCurrentOperationMode(app_state* State)
DeactivateCurrentOperationMode(&State->Modes);
}
s32 GlobalAnimationPatternsCount = 4;
animation_pattern GlobalAnimationPatterns[] = {
{ "Test Pattern One", 16, TestPatternOne },
{ "Test Pattern Two", 16, TestPatternTwo },
{ "Test Pattern Three", 18, TestPatternThree },
{ "Pattern_AllGreen", 16, Pattern_AllGreen },
};
#include "editor/panels/foldhaus_panel_types.h"
#include "editor/panels/foldhaus_panel_file_view.h"
@ -237,15 +97,12 @@ animation_pattern GlobalAnimationPatterns[] = {
#include "editor/panels/foldhaus_panel_dmx_view.h"
#include "editor/panels/foldhaus_panel_animation_timeline.h"
#include "editor/panels/foldhaus_panel_hierarchy.h"
#include "editor/panels/foldhaus_panel_assembly_debug.h"
#include "editor/panels/foldhaus_panel_types.cpp"
//#include "generated/foldhaus_panels_generated.h"
#include "editor/foldhaus_interface.cpp"
#include "../meta/gs_meta_include.cpp"
#include "editor/foldhaus_editor_draw.h"
#include "editor/foldhaus_editor.cpp"
#define FOLDHAUS_APP_H

View File

@ -54,6 +54,7 @@ struct debug_frame
s64 FrameEndCycles;
s32 ScopeNamesMax;
s32 ScopeNamesCount;
scope_name* ScopeNamesHash;
s32 ThreadCount;
@ -302,6 +303,7 @@ EndDebugFrame (debug_services* Services)
CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame);
}
s32 ScopeNamesCount = 0;
for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++)
{
if (ClosingFrame->ScopeNamesHash[n].Hash != 0)
@ -310,8 +312,10 @@ EndDebugFrame (debug_services* Services)
CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency;
CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles;
CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount;
ScopeNamesCount += 1;
}
}
ClosingFrame->ScopeNamesCount = ScopeNamesCount;
Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % DEBUG_FRAME_COUNT;
StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services);

View File

@ -5,10 +5,10 @@
//
#ifndef FOLDHAUS_PLATFORM_H
// TODO Remove
#include <math.h>
#include <windows.h>
#include <math.h> // TODO Remove
#include "..\gs_libs\gs_types.h"
#include "..\gs_libs\gs_types.cpp"
@ -50,6 +50,22 @@ typedef struct context context;
// Application Functions
// TODO(pjs): TEMP
typedef void temp_job_req_proc(gs_thread_context* Ctx, u8* Memory);
struct temp_job_req
{
temp_job_req_proc* Proc;
u8* Memory;
};
// This isn't necessarily temp but I'm not sure it goes here
#define PACKETS_MAX 32
struct packet_ringbuffer
{
gs_data Values[PACKETS_MAX];
u32 ReadHead;
u32 WriteHead;
};
#define INITIALIZE_APPLICATION(name) void name(context Context)
typedef INITIALIZE_APPLICATION(initialize_application);
@ -148,7 +164,7 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint);
// Worker Threads
#define PLATFORM_THREAD_COUNT 0
#define PLATFORM_THREAD_COUNT 3
RESET_WORK_QUEUE(ResetWorkQueue)
{
@ -190,6 +206,9 @@ struct context
update_and_render* UpdateAndRender;
cleanup_application* CleanupApplication;
platform_thread_manager* ThreadManager;
platform_socket_manager* SocketManager;
// Platform Services
gs_work_queue* GeneralWorkQueue;
@ -200,6 +219,5 @@ struct context
platform_get_socket_handle* PlatformGetSocketHandle;
};
#define FOLDHAUS_PLATFORM_H
#endif // FOLDHAUS_PLATFORM_H

View File

@ -15,6 +15,14 @@ AllocateRenderCommandBuffer (u8* Memory, s32 Size, renderer_realloc* Realloc)
Result.Realloc = Realloc;
return Result;
}
internal render_command_buffer
AllocateRenderCommandBuffer(u32 MemorySize,
gs_memory_arena* Arena,
renderer_realloc* Realloc)
{
u8* Memory = PushSize(Arena, MemorySize);
return AllocateRenderCommandBuffer(Memory, MemorySize, Realloc);
}
internal void
Render3DQuadBatch (u8* CommandData, s32 TriCount)

View File

@ -589,6 +589,21 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color)
PushQuad2DOnBatch(&Batch, Min, Max, Color);
}
internal void
PushRenderQuad2D (render_command_buffer* Buffer, rect2 Rect, v4 Color)
{
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, Rect.Min, Rect.Max, Color);
}
internal void
PushRenderQuad2DClipped (render_command_buffer* Buffer, rect2 Rect, rect2 ClippingBox, v4 Color)
{
rect2 Clipped = Rect2Union(Rect, ClippingBox);
render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1);
PushQuad2DOnBatch(&Batch, Clipped.Min, Clipped.Max, Color);
}
internal void
PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color)
{

File diff suppressed because it is too large Load Diff

107
src/app/interface_test.cpp Normal file
View File

@ -0,0 +1,107 @@
//
// File: interface_test.cpp
// Author: Peter Slattery
// Creation Date: 2020-11-15
//
#ifndef INTERFACE_TEST_CPP
global r32 TestSlider_Value = 5;
global r32 TestSlider_Min = 0;
global r32 TestSlider_Max = 10;
global bool TestToggle = true;
global r64 TestTextEntry = 3.1415f;
internal void
InterfaceTest_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
{
ui_InterfaceReset(&State->Interface);
State->Interface.RenderBuffer = RenderBuffer;
State->Interface.WindowBounds = Context->WindowBounds;
gs_string A = MakeString("TestRender Layout");
#if 0
ui_PushLayout(&State->Interface, A);
{
#if 1
TestTextEntry = ui_TextEntryR64(&State->Interface, MakeString("Spacer"), TestTextEntry);
ui_Button(&State->Interface, MakeString("A"));
TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max);
#elif 0
ui_PushLayout(&State->Interface, MakeString("Outer"));
{
for (u32 i = 0; i < 3; i++)
{
ui_Button(&State->Interface, MakeString("A"));
}
}
ui_PopLayout(&State->Interface);
ui_BeginRow(&State->Interface, 2);
{
ui_PushLayout(&State->Interface, MakeString("TestLayout"));
{
for (u32 i = 0; i < 5; i++)
{
ui_Button(&State->Interface, MakeString("TestButon"));
}
}
ui_PopLayout(&State->Interface);
ui_PushLayout(&State->Interface, MakeString("TestLayout"));
{
ui_Button(&State->Interface, MakeString("TestButon"));
TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle);
TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max);
if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown")))
{
ui_Button(&State->Interface, MakeString("TestButon"));
ui_Button(&State->Interface, MakeString("TestButon"));
ui_Button(&State->Interface, MakeString("TestButon"));
}
ui_EndDropdown(&State->Interface);
}
ui_PopLayout(&State->Interface);
}
ui_EndRow(&State->Interface);
ui_PushLayout(&State->Interface, MakeString("Outer"));
{
for (u32 i = 0; i < 3; i++)
{
ui_Button(&State->Interface, MakeString("B"));
}
}
ui_PopLayout(&State->Interface);
#else
ui_BeginList(&State->Interface, MakeString("Test List"), 10);
{
for (u32 i = 0; i < 32; i++)
{
ui_Button(&State->Interface, MakeString("Option"));
}
}
ui_EndList(&State->Interface);
#endif
ui_PushOverlayLayout(&State->Interface, rect2{25, 25, 400, 200}, LayoutDirection_TopDown, MakeString("t"));
{
ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Mouse Pos - %f %f", State->Interface.Mouse.Pos.x, State->Interface.Mouse.Pos.y));
Assert(State->Interface.PerFrameMemory->CursorList);
ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Hot - %lld | Active - %lld",
State->Interface.HotWidget.Id, State->Interface.ActiveWidget.Id));
Assert(State->Interface.PerFrameMemory->CursorList);
ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Last Active - %lld",
State->Interface.LastActiveWidget.Id));
Assert(State->Interface.PerFrameMemory->CursorList);
}
ui_PopLayout(&State->Interface);
}
ui_PopLayout(&State->Interface);
#endif
}
#define INTERFACE_TEST_CPP
#endif // INTERFACE_TEST_CPP

View File

@ -0,0 +1,730 @@
//
// File: blumen_patterns.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef BLUMEN_PATTERNS_H
#define FLOWER_COLORS_COUNT 12
pixel FlowerAColors[FLOWER_COLORS_COUNT] = {
{ 232,219,88 },
{ 232,219,88 },
{ 232,219,88 },
{ 147,75,176 },
{ 193,187,197 },
{ 223,190,49 },
{ 198,76,65 },
{ 198,76,65 },
{ 198,76,65 },
{ 226,200,17 },
{ 116,126,39 },
{ 61,62,31 }
};
pixel FlowerBColors[FLOWER_COLORS_COUNT] = {
{ 62,56,139 },
{ 93,87,164 },
{ 93,87,164 },
{ 93,87,164 },
{ 155,140,184 },
{ 191,201,204 },
{ 45,31,116 },
{ 201,196,156 },
{ 191,175,109 },
{ 186,176,107 },
{ 89,77,17 },
{ 47,49,18 },
};
pixel FlowerCColors[FLOWER_COLORS_COUNT] = {
{ 220,217,210 },
{ 220,217,210 },
{ 220,217,210 },
{ 225,193,110 },
{ 225,193,110 },
{ 227,221,214 },
{ 227,221,214 },
{ 230,218,187 },
{ 230,218,187 },
{ 172,190,211 },
{ 172,190,211 },
{ 172,190,211 },
};
internal pixel
PixelMix(r32 T, pixel A, pixel B)
{
pixel Result = {
LerpU8(T, A.R, B.R),
LerpU8(T, A.G, B.G),
LerpU8(T, A.B, B.B),
};
return Result;
}
internal pixel
GetColor(pixel* Colors, u32 ColorsCount, r32 Percent)
{
Percent = Clamp01(Percent);
u32 LowerIndex = Percent * ColorsCount;
u32 HigherIndex = LowerIndex + 1;
if (HigherIndex >= ColorsCount) HigherIndex = 0;
r32 LowerPercent = (r32)LowerIndex / (r32)ColorsCount;
r32 StepPercent = 1.f / (r32)ColorsCount;
r32 PercentLower = (Percent - LowerPercent) / StepPercent;
pixel Result = PixelMix(PercentLower, Colors[LowerIndex], Colors[HigherIndex]);
return Result;
}
internal void
SolidColorPattern(led_buffer* Leds, pixel Color)
{
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
Leds->Colors[LedIndex] = Color;
}
}
internal void
Pattern_Blue(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
pixel Blue = pixel{0, 0, 255};
SolidColorPattern(Leds, Blue);
}
internal void
Pattern_Green(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
pixel Green = pixel{0, 255, 0};
SolidColorPattern(Leds, Green);
}
internal void
Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 CycleTime = 10;
r32 CyclePercent = ModR32(Time, CycleTime) / CycleTime;
pixel CA = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, CyclePercent);
pixel CB = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, 1.0f - CyclePercent);
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
r32 Pct = (Abs(ModR32(P.y, 150) / 150) + CycleTime) * PiR32;
r32 APct = RemapR32(SinR32(Pct), -1, 1, 0, 1);
Leds->Colors[LedIndex] = PixelMix(APct, CA, CB);
}
}
internal void
TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient);
led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient);
for (u32 i = 0; i < BlumenStrips.Count; i++)
{
u32 StripIndex = BlumenStrips.StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{
u32 LedIndex = StripAt.LedLUT[j];
Leds->Colors[LedIndex] = { 255, 0, 0 };
}
}
for (u32 i = 0; i < RadiaStrips.Count; i++)
{
u32 StripIndex = RadiaStrips.StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIndex];
for (u32 j = 0; j < StripAt.LedCount; j++)
{
u32 LedIndex = StripAt.LedLUT[j];
Leds->Colors[LedIndex] = { 0, 255, 0 };
}
}
}
internal void
TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 PeriodicTime = (Time / PiR32) * 2;
r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f;
r32 ZeroOneCos = (CosR32(PeriodicTime) * .5f) + .5f;
pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) };
v4 Center = v4{0, 0, 0, 1};
r32 ThetaZ = Time / 2;
v4 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
v4 Right = V4Cross(Normal, v4{0, 1, 0, 0});
v4 FrontCenter = Center + (Normal * 25);
v4 BackCenter = Center - (Normal * 25);
r32 OuterRadiusSquared = 1000000;
r32 InnerRadiusSquared = 0;
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 Position = Leds->Positions[LedIndex];
v4 ToFront = Position + FrontCenter;
v4 ToBack = Position + BackCenter;
r32 ToFrontDotNormal = V4Dot(ToFront, Normal);
r32 ToBackDotNormal = V4Dot(ToBack, Normal);
ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000);
ToBackDotNormal = Clamp01(ToBackDotNormal * 1000);
r32 SqDistToCenter = V4MagSquared(Position);
if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared)
{
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
{
Leds->Colors[LedIndex] = Color;
}
else
{
//Leds->Colors[LedIndex] = {};
}
}
else
{
//Leds->Colors[LedIndex] = {};
}
}
}
internal void
TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
v4 GreenCenter = v4{0, 0, 150, 1};
r32 GreenRadius = Abs(SinR32(Time)) * 200;
v4 TealCenter = v4{0, 0, 150, 1};
r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200;
r32 FadeDist = 35;
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 LedPosition = Leds->Positions[LedIndex];
u8 Red = 0;
u8 Green = 0;
u8 Blue = 0;
r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius);
r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist);
Green = (u8)(GreenBrightness * 255);
r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius);
r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist);
Red = (u8)(TealBrightness * 255);
Blue = (u8)(TealBrightness * 255);
Leds->Colors[LedIndex].R = Red;
Leds->Colors[LedIndex].B = Green;
Leds->Colors[LedIndex].G = Green;
}
}
v4 RGBToHSV(v4 In)
{
v4 Result = {};
r32 Min = Min(In.r, Min(In.g, In.b));
r32 Max = Max(In.r, Max(In.g, In.b));
r32 V = Max;
r32 Delta = Max - Min;
r32 S = 0;
r32 H = 0;
if( Max != 0 )
{
S = Delta / Max;
if( In.r == Max )
{
H = ( In.g - In.b ) / Delta; // between yellow & magenta
}
else if( In.g == Max )
{
H = 2 + ( In.b - In.r ) / Delta; // between cyan & yellow
}
else
{
H = 4 + ( In.r - In.g ) / Delta; // between magenta & cyan
}
H *= 60; // degrees
if( H < 0 )
H += 360;
Assert(H);
//if ( isNaN(h) )
//H = 0;
Result = v4{H, S, V, 1};
}
else
{
// r = g = b = 0
// s = 0, v is undefined
S = 0;
H = -1;
Result = v4{H, S, 1, 1};
}
return Result;
}
v4 HSVToRGB (v4 In)
{
float Hue = In.x;
/*
while (Hue > 360.0f) { Hue -= 360.0f; }
while (Hue < 0.0f) { Hue += 360.0f; }
*/
Hue = ModR32(Hue, 360.0f);
if (Hue < 0) { Hue += 360.0f; }
if (Hue == MinR32) { Hue = 0; }
if (Hue == MaxR32) { Hue = 360; }
Assert(Hue >= 0 && Hue < 360);
float Sat = In.y;
float Value = In.z;
float hh, p, q, t, ff;
long i;
v4 Result = {};
Result.a = In.a;
if(Sat <= 0.0f) { // < is bogus, just shuts up warnings
Result.r = Value;
Result.g = Value;
Result.b = Value;
return Result;
}
hh = Hue;
if(hh >= 360.0f) hh = 0.0f;
hh /= 60.0f;
i = (long)hh;
ff = hh - i;
p = Value * (1.0f - Sat);
q = Value * (1.0f - (Sat * ff));
t = Value * (1.0f - (Sat * (1.0f - ff)));
switch(i) {
case 0:
{Result.r = Value;
Result.g = t;
Result.b = p;
}break;
case 1:
{
Result.r = q;
Result.g = Value;
Result.b = p;
}break;
case 2:
{
Result.r = p;
Result.g = Value;
Result.b = t;
}break;
case 3:
{
Result.r = p;
Result.g = q;
Result.b = Value;
}break;
case 4:
{
Result.r = t;
Result.g = p;
Result.b = Value;
}break;
case 5:
default:
{
Result.r = Value;
Result.g = p;
Result.b = q;
}break;
}
return Result;
}
internal void
Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 Height = SinR32(Time) * 25;
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
v4 HSV = { CycleProgress * 360, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Dist = Pos.y - Height;
//v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 };
//v4 RGB = HSVToRGB(HSV);
u8 R = (u8)(RGB.x * 255);
u8 G = (u8)(RGB.y * 255);
u8 B = (u8)(RGB.z * 255);
Leds->Colors[LedIndex].R = R;
Leds->Colors[LedIndex].G = G;
Leds->Colors[LedIndex].B = B;
}
}
internal pixel
V4ToRGBPixel(v4 C)
{
pixel Result = {};
Result.R = (u8)(C.x * 255);
Result.G = (u8)(C.y * 255);
Result.B = (u8)(C.z * 255);
return Result;
}
internal void
Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 HueBase = ModR32(Time * 50, 360);
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Hue = HueBase + Pos.y + Pos.x;
v4 HSV = { Hue, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal void
Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
u32 I = LedIndex + 1;
Leds->Colors[LedIndex] = {};
if (I % 3 == 0)
{
Leds->Colors[LedIndex].R = 255;
}
else if (I % 3 == 1)
{
Leds->Colors[LedIndex].G = 255;
}
else if (I % 3 == 2)
{
Leds->Colors[LedIndex].B = 255;
}
}
}
internal r32
PatternHash(r32 Seed)
{
return FractR32(Seed * 17.0 * FractR32(Seed * 0.3183099));
}
internal void
Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
pixel ColorA = { 0, 255, 255 };
pixel ColorB = { 255, 0, 255 };
r32 Speed = .5f;
Time *= Speed;
r32 ScaleA = 2 * SinR32(Time / 5);
r32 ScaleB = 2.4f * CosR32(Time / 2.5f);
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
r32 V = P.y;
r32 Noise = .3f * PatternHash(V);
r32 ThetaY = (Leds->Positions[LedIndex].y / 10) + Time + Noise;
r32 ThetaX = (Leds->Positions[LedIndex].x / 13) + Time + Noise;
r32 Fade = (ScaleA * SinR32(ThetaY)) + (ScaleB * CosR32(3 * ThetaX));
Fade = RemapClampedR32(Fade, -1, 1, 0, 1);
Leds->Colors[LedIndex].R = (u8)LerpR32(Fade, ColorA.R, ColorB.R);
Leds->Colors[LedIndex].G = (u8)LerpR32(Fade, ColorA.G, ColorB.G);
Leds->Colors[LedIndex].B = (u8)LerpR32(Fade, ColorA.B, ColorB.B);
}
}
internal void
Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) });
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v2 Vector = v2{
Leds->Positions[LedIndex].x,
Leds->Positions[LedIndex].z
};
Vector = V2Normalize(Vector);
r32 Angle = V2Dot(RefVector, Vector);
v4 HSV = { (Angle * 30) + (Time * 10) + Leds->Positions[LedIndex].y, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal r32
Smoothstep(r32 T)
{
r32 Result = (T * T * (3 - (2 * T)));
return Result;
}
internal void
Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 FillCycleTime = ModR32(Time, 7.0f) / 7.0f;
r32 ColorCycleTime = ModR32(Time, 21.0f) / 21.0f;
v4 HSV = { 0, 1, 1, 1 };
for (u32 s = 0; s < Assembly.StripCount; s++)
{
v2_strip Strip = Assembly.Strips[s];
v4 RGB0 = HSVToRGB(HSV);
for (u32 l = 0; l < Strip.LedCount; l++)
{
u32 LedIndex = Strip.LedLUT[l];
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0);
}
HSV.x += 15;
}
}
internal void
Pattern_GrowAndFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 PercentCycle = ModR32(Time, 10) / 10;
v4 HSV = { PercentCycle * 360, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
r32 RefHeight = -100 + (Smoothstep(PercentCycle * 1.4f) * 400);
r32 RefBrightness = 1.0f - Smoothstep(PercentCycle);
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
v4 P = Leds->Positions[LedIndex];
v4 RgbFaded = v4{};
if (P.y < RefHeight)
{
RgbFaded = RGB * RefBrightness;
}
Leds->Colors[LedIndex] = V4ToRGBPixel(RgbFaded);
}
}
internal void
Pattern_ColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 FadeBottomBase = 50;
r32 FadeTop = 125;
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
r32 FlowerSpread = .8f;
r32 FlowerOffset = 0;
if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center"))
{
FlowerOffset = 1;
}
else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right"))
{
FlowerOffset = 2;
}
FlowerOffset *= FlowerSpread;
r32 PercentCycle = ModR32(Time + FlowerOffset, 10) / 10;
r32 FadeBottom = FadeBottomBase + RemapR32(SinR32((PercentCycle * 4) * TauR32), -1, 1, -50, 50);
v4 TopRGB = WhiteV4;
pixel TopColor = V4ToRGBPixel(TopRGB);
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
v4 P = Leds->Positions[LedIndex];
pixel FinalColor = {};
if (P.y > FadeTop)
{
FinalColor = TopColor;
}
else
{
r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f);
r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, -32.f, 32.f);
v4 BottomRGB = HSVToRGB(v4{ (PercentCycle * 360) + HNoise, 1, B, 1 });
if (P.y < FadeBottom)
{
FinalColor = V4ToRGBPixel(BottomRGB);
}
else if (P.y >= FadeBottom && P.y <= FadeTop)
{
r32 FadePct = RemapR32(P.y, FadeBottom, FadeTop, 0, 1);
v4 MixRGB = V4Lerp(FadePct, BottomRGB, TopRGB);
FinalColor = V4ToRGBPixel(MixRGB);
}
}
Leds->Colors[LedIndex] = FinalColor;
}
}
}
internal void
Pattern_FlowerColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
r32 FadeBottomBase = 50;
r32 FadeTop = 125;
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
#if 0
// All flowers same flower type
pixel* Colors = &FlowerAColors[0];
r32 FlowerSpread = .8f;
r32 FlowerOffset = 0;
if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center"))
{
FlowerOffset = 1;
}
else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right"))
{
FlowerOffset = 2;
}
FlowerOffset *= FlowerSpread;
#else
// Each flower different
pixel* Colors = &FlowerAColors[0];
r32 FlowerOffset = 0;
if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center"))
{
Colors = &FlowerBColors[0];
}
else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right"))
{
Colors = &FlowerCColors[0];
}
#endif
r32 PercentCycle = ModR32(Time + FlowerOffset, 10) / 10;
r32 FadeBottom = FadeBottomBase + RemapR32(SinR32((PercentCycle * 4) * TauR32), -1, 1, -50, 50);
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
v4 P = Leds->Positions[LedIndex];
pixel FinalColor = {};
r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f);
r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, 0.f, 1.f);
pixel BottomColor = GetColor(Colors, FLOWER_COLORS_COUNT, (PercentCycle + HNoise) / 2);
FinalColor = BottomColor;
Leds->Colors[LedIndex] = FinalColor;
}
}
}
r32 TLastFrame = 0;
pixel* FAC = &FlowerAColors[0];
pixel* FBC = &FlowerBColors[0];
pixel* FCC = &FlowerCColors[0];
internal void
Pattern_BasicFlowers(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData)
{
if (TLastFrame > Time)
{
pixel* Temp = FAC;
FAC = FBC;
FBC = FCC;
FCC = Temp;
}
TLastFrame = Time;
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
// Each flower different
pixel* Colors = FAC;
if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center"))
{
Colors = FBC;
}
else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right"))
{
Colors = FCC;
}
r32 CycleT = ModR32(Time, 10) * 20;
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
v4 P = Leds->Positions[LedIndex];
r32 T = ModR32(P.y + CycleT, 200) / 200.f;
T = Clamp01(T);
Leds->Colors[LedIndex] = GetColor(Colors, FLOWER_COLORS_COUNT, T);
}
}
}
#define BLUMEN_PATTERNS_H
#endif // BLUMEN_PATTERNS_H

View File

@ -23,9 +23,12 @@
#include "win32_foldhaus_work_queue.h"
#include "win32_foldhaus_serial.h"
#include "win32_foldhaus_socket.h"
#include "win32_foldhaus_mouse.h"
#include "../foldhaus_renderer.cpp"
#include "win32_test_code.cpp"
global b32 Running = false;
global b32 WindowIsActive = false;
@ -187,7 +190,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true,
ShiftDown, AltDown, CtrlDown, false);
Mouse->LeftButtonState = KeyState_IsDown & ~KeyState_WasDown;
Mouse->LeftButtonState |= KeyState_IsDown;
Mouse->DownPos = Mouse->Pos;
// :Win32MouseEventCapture
@ -237,7 +240,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false,
ShiftDown, AltDown, CtrlDown, false);
Mouse->LeftButtonState = ~KeyState_IsDown & KeyState_WasDown;
Mouse->LeftButtonState &= ~KeyState_IsDown;
// :Win32MouseEventCapture
ReleaseCapture();
@ -276,6 +279,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
case WM_KEYDOWN:
case WM_KEYUP:
{
#if 0
int VirtualKey = (int)Message.wParam;
key_code Key = Win32GetKeyCode(VirtualKey, true, false);
s32 KeyIndex = (int)Key;
@ -287,6 +291,27 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
// New Input Queue
AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown,
ShiftDown, AltDown, CtrlDown, false);
#endif
TranslateMessage(&Message);
DispatchMessage(&Message);
}break;
case WM_CHAR:
{
char VirtualKey = (char)Message.wParam;
key_code Key = CharToKeyCode(VirtualKey);
s32 KeyIndex = (int)Key;
b32 KeyWasDown = (Message.lParam & (1 << 30)) != 0;
b32 KeyIsDown = (Message.lParam & (1 << 31)) == 0;
b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000;
b32 AltDown = GetKeyState(VK_MENU) & 0x8000;
b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000;
// New Input Queue
AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown,
ShiftDown, AltDown, CtrlDown, false);
@ -347,34 +372,14 @@ Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize)
return NewMemory;
}
// NOTE(Peter): Only meant to take one of the values specified below:
// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM,
// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE,
// IDC_SIZEWE, IDC_UPARROW, IDC_WAIT
internal HCURSOR
Win32LoadSystemCursor(char* CursorIdentifier)
{
u32 Error = 0;
HCURSOR Result = LoadCursorA(NULL, CursorIdentifier);
if (Result == NULL)
{
Error = GetLastError();
InvalidCodePath;
}
return Result;
}
internal void
Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData)
Win32_SendAddressedDataBuffer(gs_thread_context Context, addressed_data_buffer* BufferAt)
{
DEBUG_TRACK_FUNCTION;
u32 BuffersSent = 0;
u32 DataSizeSent = 0;
for (addressed_data_buffer* BufferAt = OutputData.Root;
BufferAt != 0;
BufferAt = BufferAt->Next)
{
switch(BufferAt->AddressType)
{
case AddressType_NetworkIP:
@ -397,50 +402,125 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_
if (Win32SerialPort_Write(SerialPort, BufferAt->Data))
{
BuffersSent += 1;
DataSizeSent += BufferAt->Data.Size;
}
else
{
Win32SerialArray_Close(BufferAt->ComPort);
}
}
}
else
{
#if 0
OutputDebugStringA("Skipping data buffer because its COM Port isn't set");
#endif
}
}break;
InvalidDefaultCase;
}
}
gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256);
PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent);
NullTerminate(&OutputStr);
OutputDebugStringA(OutputStr.Str);
}
internal void
Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg)
Win32_SendAddressedDataBuffer_Job(gs_thread_context Context, gs_data Arg)
{
addressed_data_buffer_list* OutputData = (addressed_data_buffer_list*)Arg.Memory;
Win32_SendAddressedDataBuffers(Context, *OutputData);
addressed_data_buffer* OutputData = (addressed_data_buffer*)Arg.Memory;
Win32_SendAddressedDataBuffer(Context, OutputData);
}
#pragma pack(push, 1)
struct test_microphone_packet
internal bool
ReloadAndLinkDLL(win32_dll_refresh* DLL, context* Context, gs_work_queue* WorkQueue, bool ShouldError)
{
b8 ChangeAnimation;
char AnimationFileName[32];
b8 SetLayer;
char LayerName[32];
r32 LayerOpacity;
b8 SetLayerParamColor;
char LayerParamColor[7];
r32 OverrideDuration;
};
#pragma pack(pop)
bool Success = false;
if (HotLoadDLL(DLL))
{
SetApplicationLinks(Context, *DLL, WorkQueue);
Context->ReloadStaticData(*Context, GlobalDebugServices);
Success = true;
}
else if(ShouldError)
{
OutputDebugStringA("Unable to load application DLL at startup.\nAborting\n");
}
return Success;
}
inline u32
UpackB4(const u8* ptr)
internal gs_const_string
GetExePath(HINSTANCE HInstance, gs_thread_context ThreadContext)
{
return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24));
gs_const_string Result = {};
u32 Error = 0;
u32 PathSize = MAX_PATH;
char* Path = PushArray(ThreadContext.Transient, char, PathSize);
DWORD Length = GetModuleFileNameA(HInstance, Path, PathSize);
if (Length)
{
Error = GetLastError();
if (Error == ERROR_INSUFFICIENT_BUFFER) {
// PathSize wasn't long enough
// TODO(pjs): handle this case
InvalidCodePath;
}
Result.Str = Path;
Result.Length = (u64)Length;
}
else
{
Error = GetLastError();
InvalidCodePath;
}
return Result;
}
internal bool
SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext)
{
bool Result = false;
gs_const_string ExePath = GetExePath(HInstance, ThreadContext);
gs_string ScratchPath = PushString(ThreadContext.Transient, ExePath.Length + 128);
gs_string WorkingDirectory = PushString(ThreadContext.Transient, ExePath.Length + 128);
while (WorkingDirectory.Length == 0)
{
s64 LastSlash = FindLastFromSet(ExePath, "\\/");
if (LastSlash < 0) break;
ExePath = Substring(ExePath, 0, LastSlash);
PrintF(&ScratchPath, "%S\\data", ExePath);
NullTerminate(&ScratchPath);
gs_file_info PathInfo = GetFileInfo(ThreadContext.FileHandler, ScratchPath.ConstString);
if (PathInfo.Path.Length > 0 &&
PathInfo.IsDirectory) {
PrintF(&WorkingDirectory, "%S", ExePath);
NullTerminate(&WorkingDirectory);
}
}
if (WorkingDirectory.Length > 0)
{
OutputDebugStringA("Setting Working Directory\n");
OutputDebugStringA(WorkingDirectory.Str);
Result = SetCurrentDirectory(WorkingDirectory.Str);
if (!Result)
{
u32 Error = GetLastError();
InvalidCodePath;
}
}
else
{
OutputDebugStringA("Error, no data folder found\n");
}
return Result;
}
int WINAPI
@ -453,35 +533,7 @@ WinMain (
{
gs_thread_context ThreadContext = Win32CreateThreadContext();
#if 0
// NOTE(pjs): UART TEST CODE
// NOTE(pjs): UART TEST CODE
// NOTE(pjs): UART TEST CODE
u32 LedCount = 48;
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
MessageBaseSize += sizeof(u8) * 3 * LedCount;
gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient);
gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer);
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < LedCount; i++)
{
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
OutputPixel[Channel->RedIndex] = (u8)(i);
OutputPixel[Channel->GreenIndex] = 0;
OutputPixel[Channel->BlueIndex] = 0;
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
#endif
if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1;
MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents);
Win32UpdateWindowDimension(&MainWindow);
@ -492,14 +544,10 @@ WinMain (
OpenGLWindowInfo.DepthBits = 0;
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
s32 InitialMemorySize = MB(64);
u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0);
context Context = {};
Context.ThreadContext = ThreadContext;
Context.MemorySize = InitialMemorySize;
Context.MemoryBase = InitialMemory;
Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
Context.Mouse = {0};
Context.MemorySize = MB(64);
Context.MemoryBase = (u8*)Win32Alloc(Context.MemorySize, 0);
gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator);
@ -509,109 +557,43 @@ WinMain (
r32 LastFrameSecondsElapsed = 0.0f;
GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services);
s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1;
InitDebugServices(GlobalDebugServices,
PerformanceCountFrequency,
DEBUGAlloc,
Win32Realloc,
GetWallClock,
Win32GetThreadId,
DebugThreadCount);
PLATFORM_THREAD_COUNT + 1);
input_queue InputQueue;
{
s32 InputQueueMemorySize = sizeof(input_entry) * 32;
u8* InputQueueMemory = (u8*)Win32Alloc(InputQueueMemorySize, 0);
InputQueue = InitializeInputQueue(InputQueueMemory, InputQueueMemorySize);
}
input_queue InputQueue = InputQueue_Create(&PlatformPermanent, 32);
//
// Set up worker threads
const s32 WorkerThreadCount = PLATFORM_THREAD_COUNT;
worker_thread_info* WorkerThreads = 0;
if (PLATFORM_THREAD_COUNT > 0)
{
WorkerThreads = PushArray(&PlatformPermanent, worker_thread_info, PLATFORM_THREAD_COUNT);
}
HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
gs_work_queue WorkQueue = {};
WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle;
WorkQueue.JobsMax = 512;
WorkQueue.Jobs = PushArray(&PlatformPermanent, gs_threaded_job, WorkQueue.JobsMax);
WorkQueue.NextJobIndex = 0;
WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue;
WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone;
WorkQueue.ResetWorkQueue = ResetWorkQueue;
for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++)
{
// ID = 0 is reserved for this thread
WorkerThreads[i].Queue = &WorkQueue;
WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0);
}
// Cursors
HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND);
HCURSOR CursorLoading = Win32LoadSystemCursor(IDC_WAIT);
HCURSOR CursorHorizontalArrows = Win32LoadSystemCursor(IDC_SIZEWE);
HCURSOR CursorVerticalArrows = Win32LoadSystemCursor(IDC_SIZENS);
HCURSOR CursorDiagonalTopLeftArrows = Win32LoadSystemCursor(IDC_SIZENWSE);
HCURSOR CursorDiagonalTopRightArrows = Win32LoadSystemCursor(IDC_SIZENESW);
Win32WorkQueue_Init(&PlatformPermanent, PLATFORM_THREAD_COUNT);
// Platform functions
Context.GeneralWorkQueue = &WorkQueue;
Context.GeneralWorkQueue = &Win32WorkQueue.WorkQueue;
Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle;
Context.PlatformGetSocketHandle = Win32GetSocketHandle;
Context.PlatformGetFontInfo = Win32GetFontInfo;
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
Context.ThreadManager = PushStruct(&PlatformPermanent, platform_thread_manager);
*Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread);
Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager);
*Context.SocketManager = CreatePlatformSocketManager(Win32ConnectSocket, Win32CloseSocket, Win32SocketQueryStatus, Win32SocketPeek, Win32SocketReceive, Win32SocketSend);
win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName);
if (HotLoadDLL(&DLLRefresh))
{
SetApplicationLinks(&Context, DLLRefresh, &WorkQueue);
Context.ReloadStaticData(Context, GlobalDebugServices);
}
else
{
MessageBox(MainWindow.Handle, "Unable to load application DLL at startup.\nAborting\n", "Set Up Error", MB_OK);
return -1;
}
if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; }
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
Mouse_Init();
#if 0
// NOTE(pjs): SOCKET READING TEST CODE
// NOTE(pjs): SOCKET READING TEST CODE
// NOTE(pjs): SOCKET READING TEST CODE
win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185");
test_microphone_packet* Recv = 0;
while (true)
{
gs_data Data = Win32Socket_Receive(&TestSocket, ThreadContext.Transient);
if (Data.Size > 0)
{
OutputDebugStringA("Received\n");
Recv = (test_microphone_packet*)Data.Memory;
}
ClearArena(ThreadContext.Transient);
}
#endif
Win32SocketSystem_Init(&PlatformPermanent);
Win32SerialArray_Create(ThreadContext);
s32 RenderMemorySize = MB(12);
u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize);
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc);
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(MB(12), &PlatformPermanent, Win32Realloc);
addressed_data_buffer_list OutputData = {};
OutputData.Arena = AllocatorAllocStruct(Context.ThreadContext.Allocator, gs_memory_arena);
*OutputData.Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext);
Context.InitializeApplication(Context);
@ -626,24 +608,12 @@ WinMain (
DEBUG_TRACK_SCOPE(MainLoop);
ResetInputQueue(&InputQueue);
if (HotLoadDLL(&DLLRefresh))
{
SetApplicationLinks(&Context, DLLRefresh, &WorkQueue);
Context.ReloadStaticData(Context, GlobalDebugServices);
}
ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false);
AddressedDataBufferList_Clear(&OutputData);
{ // Mouse Position
POINT MousePos;
GetCursorPos (&MousePos);
ScreenToClient(MainWindow.Handle, &MousePos);
Context.Mouse.Scroll = 0;
Context.Mouse.OldPos = Context.Mouse.Pos;
Context.Mouse.Pos = v2{(r32)MousePos.x, (r32)MainWindow.Height - MousePos.y};
Context.Mouse.DeltaPos = Context.Mouse.Pos - Context.Mouse.OldPos;
}
Mouse_Update(MainWindow, &Context);
MSG Message;
while (PeekMessageA(&Message, MainWindow.Handle, 0, 0, PM_REMOVE))
@ -659,59 +629,42 @@ WinMain (
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData);
bool Multithread = false;
if (Multithread)
{
for (addressed_data_buffer* At = OutputData.Root;
At != 0;
At = At->Next)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)At;
ProcArg.Size = sizeof(addressed_data_buffer);
Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffer_Job, ProcArg, ConstString("Send UART Data"));
}
}
else
{
for (addressed_data_buffer* At = OutputData.Root;
At != 0;
At = At->Next)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)At;
ProcArg.Size = sizeof(addressed_data_buffer);
Win32_SendAddressedDataBuffer_Job(ThreadContext, ProcArg);
}
}
RenderCommandBuffer(RenderBuffer);
ClearRenderBuffer(&RenderBuffer);
if (true)
{
gs_data ProcArg = {};
ProcArg.Memory = (u8*)&OutputData;
ProcArg.Size = sizeof(OutputData);
Win32PushWorkOnQueue(&WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data"));
}
Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState);
Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState);
Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState);
switch (Context.Mouse.CursorType)
{
case CursorType_Arrow:
{
SetCursor(CursorArrow);
}break;
case CursorType_Pointer:
{
SetCursor(CursorPointer);
}break;
case CursorType_Loading:
{
SetCursor(CursorLoading);
}break;
case CursorType_HorizontalArrows:
{
SetCursor(CursorHorizontalArrows);
}break;
case CursorType_VerticalArrows:
{
SetCursor(CursorVerticalArrows);
}break;
case CursorType_DiagonalTopLeftArrows:
{
SetCursor(CursorDiagonalTopLeftArrows);
}break;
case CursorType_DiagonalTopRightArrows:
{
SetCursor(CursorDiagonalTopRightArrows);
}break;
InvalidDefaultCase;
}
Mouse_Advance(&Context);
HDC DeviceContext = GetDC(MainWindow.Handle);
SwapBuffers(DeviceContext);
ReleaseDC(MainWindow.Handle, DeviceContext);
//Win32DoQueueWorkUntilDone(&WorkQueue, Context.ThreadContext);
Win32DoQueueWorkUntilDone(&Win32WorkQueue.WorkQueue, Context.ThreadContext);
s64 FinishedWorkTime = GetWallClock();
r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency);
@ -730,20 +683,10 @@ WinMain (
Context.CleanupApplication(Context);
for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++)
{
Win32Socket_Close(Win32Sockets.Values + SocketIdx);
}
Win32WorkQueue_Cleanup();
//Win32_TestCode_SocketReading_Cleanup();
s32 CleanupResult = 0;
do {
CleanupResult = WSACleanup();
}while(CleanupResult == SOCKET_ERROR);
for (s32 Thread = 0; Thread < PLATFORM_THREAD_COUNT; Thread++)
{
TerminateThread(WorkerThreads[Thread].Handle, 0);
}
Win32SocketSystem_Cleanup();
return 0;
}

View File

@ -46,6 +46,20 @@ GET_FILE_INFO(Win32GetFileInfo)
}
CloseHandle(FileHandle);
}
else
{
DWORD FileAttr = GetFileAttributes(Path.Str);
if (FileAttr != INVALID_FILE_ATTRIBUTES &&
(FileAttr & FILE_ATTRIBUTE_DIRECTORY))
{
Result.Path = Path;
Result.IsDirectory = true;
}
else
{
// Path is not a file or directory
}
}
return Result;
}
@ -183,7 +197,8 @@ Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list*
{
u32 FilesCount = 0;
u32 IndexOfLastSlash = FindLastFromSet(Path, "\\/");
s64 IndexOfLastSlash = FindLastFromSet(Path, "\\/");
Assert(IndexOfLastSlash >= 0);
gs_const_string SearchPath = Substring(Path, 0, IndexOfLastSlash + 1);
WIN32_FIND_DATA FindFileData;

View File

@ -0,0 +1,118 @@
//
// File: win32_mouse.h
// Author: Peter Slattery
// Creation Date: 2021-01-10
//
#ifndef WIN32_MOUSE_H
HCURSOR CursorArrow;
HCURSOR CursorPointer;
HCURSOR CursorLoading;
HCURSOR CursorHArrows;
HCURSOR CursorVArrows;
HCURSOR CursorDTopLeftArrows;
HCURSOR CursorDTopRightArrows;
HCURSOR CurrentCursor;
// NOTE(Peter): Only meant to take one of the values specified below:
// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM,
// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE,
// IDC_SIZEWE, IDC_UPARROW, IDC_WAIT
internal HCURSOR
Win32LoadSystemCursor(char* CursorIdentifier)
{
u32 Error = 0;
HCURSOR Result = LoadCursorA(NULL, CursorIdentifier);
if (Result == NULL)
{
Error = GetLastError();
InvalidCodePath;
}
return Result;
}
internal void
Mouse_Init()
{
CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
CursorPointer = Win32LoadSystemCursor(IDC_HAND);
CursorLoading = Win32LoadSystemCursor(IDC_WAIT);
CursorHArrows = Win32LoadSystemCursor(IDC_SIZEWE);
CursorVArrows = Win32LoadSystemCursor(IDC_SIZENS);
CursorDTopLeftArrows = Win32LoadSystemCursor(IDC_SIZENWSE);
CursorDTopRightArrows = Win32LoadSystemCursor(IDC_SIZENESW);
}
internal void
Mouse_Update(window Window, context* Context)
{
POINT Pos;
GetCursorPos (&Pos);
ScreenToClient(Window.Handle, &Pos);
Context->Mouse.Scroll = 0;
Context->Mouse.OldPos = Context->Mouse.Pos;
Context->Mouse.Pos = v2{(r32)Pos.x, (r32)Window.Height - Pos.y};
Context->Mouse.DeltaPos = Context->Mouse.Pos - Context->Mouse.OldPos;
if (KeyIsDown(Context->Mouse.LeftButtonState))
{
SetKeyWasDown(Context->Mouse.LeftButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.LeftButtonState);
}
if (KeyIsDown(Context->Mouse.MiddleButtonState))
{
SetKeyWasDown(Context->Mouse.MiddleButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.MiddleButtonState);
}
if (KeyIsDown(Context->Mouse.RightButtonState))
{
SetKeyWasDown(Context->Mouse.RightButtonState);
}
else
{
SetKeyWasUp(Context->Mouse.RightButtonState);
}
}
internal void
Mouse_Advance(context* Context)
{
Context->Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context->Mouse.LeftButtonState);
Context->Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context->Mouse.MiddleButtonState);
Context->Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context->Mouse.RightButtonState);
HCURSOR NewCursor = 0;
switch (Context->Mouse.CursorType)
{
case CursorType_Arrow: { NewCursor = CursorArrow; } break;
case CursorType_Pointer: { NewCursor = CursorPointer; }break;
case CursorType_Loading: { NewCursor = CursorLoading; }break;
case CursorType_HArrows: { NewCursor = CursorHArrows; }break;
case CursorType_VArrows: { NewCursor = CursorVArrows; }break;
case CursorType_DTopLeftArrows: { NewCursor = CursorDTopLeftArrows; }break;
case CursorType_DTopRightArrows: { NewCursor = CursorDTopRightArrows; }break;
InvalidDefaultCase;
}
if (NewCursor != CurrentCursor)
{
CurrentCursor = NewCursor;
SetCursor(NewCursor);
}
}
#define WIN32_MOUSE_H
#endif // WIN32_MOUSE_H

View File

@ -6,9 +6,9 @@
#ifndef WIN32_SERIAL_H
global u32 Win32SerialHandlesCountMax;
global u32 Win32SerialHandlesCount;
global HANDLE* Win32SerialHandles;
global gs_string* Win32SerialPortNames;
global s32* Win32SerialPortFilled;
DCB
Win32SerialPort_GetState(HANDLE ComPortHandle)
@ -137,7 +137,18 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
{
OutputDebugStringA("Error: Unable to write to port\n");
s32 Error = GetLastError();
//InvalidCodePath;
switch (Error)
{
case ERROR_OPERATION_ABORTED:
case ERROR_GEN_FAILURE:
{
// NOTE(pjs): Probably means that the serial port became invalid
// ie. the usb stick was removed
}break;
case ERROR_INVALID_HANDLE:
InvalidDefaultCase;
}
}
return Success;
@ -183,12 +194,15 @@ Win32SerialArray_Create(gs_thread_context Context)
DEBUG_TRACK_FUNCTION;
Win32SerialHandlesCountMax = 32;
Win32SerialHandlesCount = 0;
Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax);
Win32SerialPortFilled = AllocatorAllocArray(Context.Allocator, s32, Win32SerialHandlesCountMax);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
Win32SerialPortNames[i] = AllocatorAllocString(Context.Allocator, 256);
Win32SerialPortFilled[i] = 0;
}
}
@ -197,10 +211,28 @@ Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax);
u32 Index = Win32SerialHandlesCount++;
Win32SerialHandles[Index] = SerialHandle;
PrintF(&Win32SerialPortNames[Index], "%S", PortName);
bool Found = false;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + i, 1, 0);
if (!WasFilled)
{
Win32SerialHandles[i] = SerialHandle;
PrintF(&Win32SerialPortNames[i], "%S", PortName);
Found = true;
break;
}
}
Assert(Found);
}
void
Win32SerialArray_Pop(u32 Index)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + Index, 0, 1);
Assert(WasFilled);
Win32SerialPortFilled[Index] = false;
Win32SerialHandles[Index] = INVALID_HANDLE_VALUE;
}
HANDLE
@ -209,9 +241,10 @@ Win32SerialArray_Get(gs_const_string PortName)
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCount; i++)
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
if (Win32SerialPortFilled[i] &&
StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
PortHandle = Win32SerialHandles[i];
break;
@ -239,5 +272,19 @@ Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize,
return PortHandle;
}
void
Win32SerialArray_Close(gs_const_string PortName)
{
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (Win32SerialPortFilled[i] && StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
Win32SerialPort_Close(Win32SerialHandles[i]);
Win32SerialArray_Pop(i);
break;
}
}
}
#define WIN32_SERIAL_H
#endif // WIN32_SERIAL_H

View File

@ -17,6 +17,9 @@ struct win32_socket_array
s32 Count;
};
global WSADATA WSAData;
global win32_socket_array Win32Sockets;
//////////////////////
//
// Win32 Socket Array
@ -50,9 +53,7 @@ Win32SocketArray_Get(win32_socket_array Array, s32 Index)
//////////////////////
//
// Win32 Socket System
global win32_socket_array Win32Sockets;
// Win32 Sockets
internal win32_socket
Win32Socket_Create(s32 AddressFamily, s32 Type, s32 Protocol)
@ -130,6 +131,206 @@ Win32Socket_ConnectToAddress(char* Address, char* DefaultPort)
return Result;
}
internal bool
Win32ConnectSocket(platform_socket* Socket)
{
bool Result = false;
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Socket->Addr, Socket->Port, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
SOCKET SocketHandle = socket(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (SocketHandle == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
// If iMode == 0, blocking is enabled
// if iMode != 0, non-blocking mode is enabled
u_long iMode = 1;
Error = ioctlsocket(SocketHandle, FIONBIO, &iMode);
if (Error != NO_ERROR)
{
InvalidCodePath;
}
Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
u32 Status = WSAGetLastError();
if (Status == WSAEWOULDBLOCK)
{
#if 0
TIMEVAL Timeout = { 0, 500 };
fd_set SocketSet = {};
FD_ZERO(&SocketSet);
FD_SET(SocketHandle, &SocketSet);
Assert(FD_ISSET(SocketHandle, &SocketSet));
Status = select(0, &SocketSet, 0, 0, (const TIMEVAL*)&Timeout);
if (Status == SOCKET_ERROR)
{
}
else if (Status == 0)
{
}
else
{
}
#endif
}
else
{
closesocket(SocketHandle);
continue;
}
}
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0);
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
Result = true;
break;
}
}
else
{
Error = WSAGetLastError();
InvalidCodePath;
}
if (!Result)
{
Assert(Socket->PlatformHandle == 0);
}
freeaddrinfo(PotentialConnections);
return Result;
}
internal bool
Win32CloseSocket(platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
closesocket(*Win32Sock);
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET));
*Socket = {};
return true;
}
internal bool
Win32SocketQueryStatus(platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
bool Result = (*Win32Sock != INVALID_SOCKET);
return Result;
}
internal u32
Win32SocketPeek(platform_socket* Socket)
{
u32 Result = 0;
s32 Flags = MSG_PEEK;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
char Temp[4];
u32 TempSize = 4;
s32 BytesQueued = recv(*Win32Sock, Temp, TempSize, Flags);
if (BytesQueued != SOCKET_ERROR)
{
Result = (u32)BytesQueued;
}
else
{
// TODO(pjs): Error handling
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAEWOULDBLOCK:
case WSAENOTCONN:
{
}break;
InvalidDefaultCase;
}
}
return Result;
}
internal gs_data
Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage)
{
// TODO(pjs): Test this first code path when you have data running - it should
// get the actual size of the data packet being sent
#if 0
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSizeToData(Storage, 1024);
s32 Flags = 0;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
Result.Size = BytesReceived;
return Result;
#endif
}
internal s32
Win32SocketSend(platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(*Win32Sock, (char*)Data.Memory, Data.Size, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
if (Error == 10051)
{
}
if (Error == 10053)
{
// TODO(pjs): WSAECONNABORTED
InvalidCodePath;
}
else
{
// TODO(Peter): :ErrorLogging
InvalidCodePath;
}
}
return LengthSent;
}
internal s32
Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
@ -227,7 +428,18 @@ Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
switch (Error)
{
case WSAECONNABORTED:
case WSANOTINITIALISED:
break;
case WSAENOTCONN:
{
}break;
InvalidDefaultCase;
}
}
Result.Size = BytesReceived;
return Result;
@ -241,6 +453,38 @@ Win32Socket_Close(win32_socket* Socket)
Socket->Socket = INVALID_SOCKET;
}
internal void
Win32Socket_CloseArray(win32_socket_array Array)
{
for (s32 i = 0; i < Array.Count; i++)
{
win32_socket* Socket = Array.Values + i;
Win32Socket_Close(Socket);
}
}
//////////////////////
//
// Win32 Socket System
internal void
Win32SocketSystem_Init(gs_memory_arena* Arena)
{
WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, Arena);
}
internal void
Win32SocketSystem_Cleanup()
{
Win32Socket_CloseArray(Win32Sockets);
s32 CleanupResult = 0;
do {
CleanupResult = WSACleanup();
}while(CleanupResult == SOCKET_ERROR);
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
s32 Result = Win32SocketArray_Take(&Win32Sockets);

View File

@ -18,6 +18,16 @@ struct worker_thread_info
gs_work_queue* Queue;
};
struct win32_work_queue
{
u32 ThreadCount;
worker_thread_info* Threads;
gs_work_queue WorkQueue;
};
worker_thread_info* WorkerThreads;
win32_work_queue Win32WorkQueue;
internal s32
Win32GetThreadId()
{
@ -46,6 +56,8 @@ Win32CreateThreadContext(gs_memory_arena* Transient = 0)
Win32EnumerateDirectory,
Result.Transient);
Result.DebugOutput.Print = Win32DebugPrint;
return Result;
}
@ -151,5 +163,90 @@ WorkerThreadProc (LPVOID InputThreadInfo)
return 0;
}
DWORD WINAPI
Win32ThreadProcWrapper(LPVOID ThreadInfo)
{
platform_thread* Thread = (platform_thread*)ThreadInfo;
gs_thread_context Ctx = Win32CreateThreadContext();
Thread->Proc(&Ctx, Thread->UserData);
// TODO(pjs): Destroy Thread Context
// TODO(pjs): How do we notify the thread manager this thread belongs to that it is free?
// Probaby put a pointer to the thread manager in the platform_thread struct
// so we can update the tracking structure?
return 0;
}
CREATE_THREAD(Win32CreateThread)
{
Thread->Proc = Proc;
Thread->UserData = UserData;
// TODO(pjs): ugh, allocation out in the middle of nowhere
HANDLE* ThreadHandle = (HANDLE*)Win32Alloc(sizeof(HANDLE), 0);
*ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0);
// TODO(pjs): Error checking on the created thread
Thread->PlatformHandle = (u8*)ThreadHandle;
return true;
}
KILL_THREAD(Win32KillThread)
{
HANDLE* ThreadHandle = (HANDLE*)Thread->PlatformHandle;
TerminateThread(ThreadHandle, 0);
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE));
// TODO(pjs): Error checking
return true;
}
internal void
Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount)
{
if (ThreadCount > 0)
{
Win32WorkQueue.ThreadCount = ThreadCount;
Win32WorkQueue.Threads = PushArray(Arena, worker_thread_info, ThreadCount);
}
gs_work_queue WQ = {};
WQ.SemaphoreHandle = CreateSemaphoreEx(0, 0, ThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);;
WQ.JobsMax = 512;
WQ.Jobs = PushArray(Arena, gs_threaded_job, WQ.JobsMax);
WQ.NextJobIndex = 0;
WQ.PushWorkOnQueue = Win32PushWorkOnQueue;
WQ.CompleteQueueWork = Win32DoQueueWorkUntilDone;
Win32WorkQueue.WorkQueue = WQ;
// ID = 0 is reserved for this thread
for (u32 i = 0; i < ThreadCount; i++)
{
worker_thread_info* T = Win32WorkQueue.Threads + i;
T->Queue = &Win32WorkQueue.WorkQueue;
T->Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)T, 0, 0);
}
}
internal void
Win32WorkQueue_Cleanup()
{
u32 Error = 0;
for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++)
{
u32 Success = TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0);
if (!Success)
{
Error = GetLastError();
InvalidCodePath;
}
}
}
#define WIN32_FOLDHAUS_WORK_QUEUE_H
#endif // WIN32_FOLDHAUS_WORK_QUEUE_H

View File

@ -0,0 +1,86 @@
//
// File: win32_test_code.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-10
//
#ifndef WIN32_TEST_CODE_CPP
#if 0
internal void
Win32_TestCode_UART(gs_thread_context ThreadContext)
{
u32 LedCount = 48;
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
MessageBaseSize += sizeof(u8) * 3 * LedCount;
gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient);
gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer);
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < LedCount; i++)
{
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
OutputPixel[Channel->RedIndex] = (u8)(i);
OutputPixel[Channel->GreenIndex] = 0;
OutputPixel[Channel->BlueIndex] = 0;
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
#endif
win32_socket ListenSocket;
HANDLE ListenThread;
DWORD WINAPI
Win32_TestCode_ListenThreadProc(LPVOID ThreadData)
{
gs_thread_context Ctx = Win32CreateThreadContext();
temp_job_req* Req = (temp_job_req*)ThreadData;
while (true)
{
Req->Proc(&Ctx, Req->Memory);
}
}
internal void
Win32_TestCode_SocketReading(gs_thread_context ThreadContext, temp_job_req* Req)
{
ListenSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185");
u8* Arg = (u8*)Req;
ListenThread = CreateThread(0, 0, &Win32_TestCode_ListenThreadProc, Arg, 0, 0);
}
internal void
BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData)
{
packet_ringbuffer* MicPacketBuffer = (packet_ringbuffer*)UserData;
gs_data Data = Win32Socket_Receive(&ListenSocket, Ctx->Transient);
if (Data.Size > 0)
{
OutputDebugStringA("Listened");
MicPacketBuffer->Values[MicPacketBuffer->WriteHead++] = Data;
if (MicPacketBuffer->WriteHead >= PACKETS_MAX)
{
MicPacketBuffer->WriteHead = 0;
}
}
}
internal void
Win32_TestCode_SocketReading_Cleanup()
{
TerminateThread(ListenThread, 0);
Win32Socket_Close(&ListenSocket);
}
#define WIN32_TEST_CODE_CPP
#endif // WIN32_TEST_CODE_CPP

View File

@ -5,8 +5,6 @@
//
#ifndef GS_FONT_H
#ifndef GS_FONT_H
struct codepoint_bitmap
{
s32 XOffset, YOffset;
@ -37,20 +35,6 @@ struct bitmap_font
s32 BitmapTextureHandle;
};
internal bitmap_font
InitializeTextFont (s32 CodepointCount, u8* CodepointMemory, s32 CodepointMemorySize)
{
bitmap_font Result = {};
Result.CodepointDictionarySize = CodepointCount;
Result.CodepointDictionaryCount = 0;
Assert(CodepointMemorySize >= (sizeof(char) + sizeof(codepoint_bitmap)) * CodepointCount);
Result.CodepointKeys = (char*)CodepointMemory;
Result.CodepointValues = (codepoint_bitmap*)(CodepointMemory + (sizeof(char) * CodepointCount));
return Result;
}
#define GLYPH_SKIRT 1
internal void
GetNextCodepointOffset (bitmap_font* Font, u32* X, u32* Y)
@ -126,8 +110,58 @@ NewLineYOffset (bitmap_font Font)
return Result;
}
#define GS_FONT_H
#endif
internal bitmap_font
TextFont_Create(gs_file FontFile, u32 BitmapDim, u32 FontSize, context Context, gs_memory_arena* Arena)
{
bitmap_font Result = {};
Assert(FileNoError(FontFile));
Result.BitmapWidth = BitmapDim;
Result.BitmapHeight = BitmapDim;
Result.BitmapBytesPerPixel = 4;
Result.BitmapStride = Result.BitmapWidth * Result.BitmapBytesPerPixel;
u32 BitmapSize = Result.BitmapWidth * Result.BitmapHeight * Result.BitmapBytesPerPixel;
Result.BitmapMemory = PushArray(Arena, u8, BitmapSize);
ZeroMemoryBlock(Result.BitmapMemory, BitmapSize);
platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false);
Result.PixelHeight = FontInfo.PixelHeight;
Result.Ascent = FontInfo.Ascent;
Result.Descent = FontInfo.Descent;
Result.Leading = FontInfo.Leading;
Result.MaxCharWidth = FontInfo.MaxCharWidth;
Result.CodepointDictionarySize = (FontInfo.CodepointOnePastLast - FontInfo.CodepointStart);
Result.CodepointDictionaryCount = 0;
Result.CodepointKeys = PushArray(Arena, char, Result.CodepointDictionarySize);
Result.CodepointValues = PushArray(Arena, codepoint_bitmap, Result.CodepointDictionarySize);
for (s32 Codepoint = FontInfo.CodepointStart;
Codepoint < FontInfo.CodepointOnePastLast;
Codepoint++)
{
u32 CodepointX, CodepointY;
GetNextCodepointOffset(&Result, &CodepointX, &CodepointY);
u32 CodepointW, CodepointH;
Context.PlatformDrawFontCodepoint(
Result.BitmapMemory,
Result.BitmapWidth,
Result.BitmapHeight,
CodepointX, CodepointY,
Codepoint, FontInfo,
&CodepointW, &CodepointH);
AddCodepointToFont(&Result, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY);
}
Result.BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Result.BitmapMemory,
Result.BitmapWidth, Result.BitmapHeight);
return Result;
}
#define GS_FONT_H
#endif // GS_FONT_H

View File

@ -227,6 +227,11 @@ enum key_state_flags
#define KeyWasDown(event) ((event & KeyState_WasDown) > 0)
#define KeyIsDown(event) ((event & KeyState_IsDown) > 0)
#define SetKeyDown(key) (key |= KeyState_IsDown)
#define SetKeyWasDown(key) (key |= KeyState_WasDown)
#define SetKeyUp(key) (key &= ~KeyState_IsDown)
#define SetKeyWasUp(key) (key &= ~KeyState_WasDown)
struct input_entry
{
key_code Key;
@ -246,10 +251,10 @@ enum cursor_type
CursorType_Arrow,
CursorType_Pointer,
CursorType_Loading,
CursorType_HorizontalArrows,
CursorType_VerticalArrows,
CursorType_DiagonalTopLeftArrows,
CursorType_DiagonalTopRightArrows,
CursorType_HArrows,
CursorType_VArrows,
CursorType_DTopLeftArrows,
CursorType_DTopRightArrows,
CursorType_Count,
};
@ -266,11 +271,13 @@ struct mouse_state
b32 MiddleButtonState;
b32 RightButtonState;
cursor_type CursorType;
};
internal input_queue
InitializeInputQueue (u8* Memory, s32 MemorySize)
InputQueue_Create (u8* Memory, s32 MemorySize)
{
input_queue Result = {};
s32 EntriesCount = MemorySize / sizeof(input_entry);
@ -279,6 +286,18 @@ InitializeInputQueue (u8* Memory, s32 MemorySize)
Result.Entries = (input_entry*)Memory;
return Result;
}
internal input_queue
InputQueue_Create(gs_memory_arena* Arena, u32 CountMax)
{
input_queue Result = {0};
if (CountMax > 0)
{
s32 Size = sizeof(input_entry) * 32;
u8* Memory = PushSize(Arena, Size);
Result = InputQueue_Create(Memory, Size);
}
return Result;
}
internal void
ResetInputQueue (input_queue* Queue)
@ -400,5 +419,253 @@ GetMouseButtonStateAdvanced (b32 ButtonState)
return Result;
}
internal char
KeyCodeToChar(key_code Code)
{
char Result = 0;
switch (Code)
{
case KeyCode_Space: { Result = ' '; } break;
case KeyCode_Tab: { Result = '\t'; } break;
case KeyCode_Enter: { Result = '\n'; } break;
case KeyCode_Backspace: { Result = '\b'; } break;
case KeyCode_a: { Result = 'a'; } break;
case KeyCode_b: { Result = 'b'; } break;
case KeyCode_c: { Result = 'c'; } break;
case KeyCode_d: { Result = 'd'; } break;
case KeyCode_e: { Result = 'e'; } break;
case KeyCode_f: { Result = 'f'; } break;
case KeyCode_g: { Result = 'g'; } break;
case KeyCode_h: { Result = 'h'; } break;
case KeyCode_i: { Result = 'i'; } break;
case KeyCode_j: { Result = 'j'; } break;
case KeyCode_k: { Result = 'k'; } break;
case KeyCode_l: { Result = 'l'; } break;
case KeyCode_m: { Result = 'm'; } break;
case KeyCode_n: { Result = 'n'; } break;
case KeyCode_o: { Result = 'o'; } break;
case KeyCode_p: { Result = 'p'; } break;
case KeyCode_q: { Result = 'q'; } break;
case KeyCode_r: { Result = 'r'; } break;
case KeyCode_s: { Result = 's'; } break;
case KeyCode_t: { Result = 't'; } break;
case KeyCode_u: { Result = 'u'; } break;
case KeyCode_v: { Result = 'v'; } break;
case KeyCode_w: { Result = 'w'; } break;
case KeyCode_x: { Result = 'x'; } break;
case KeyCode_y: { Result = 'y'; } break;
case KeyCode_z: { Result = 'z'; } break;
case KeyCode_A: { Result = 'A'; } break;
case KeyCode_B: { Result = 'B'; } break;
case KeyCode_C: { Result = 'C'; } break;
case KeyCode_D: { Result = 'D'; } break;
case KeyCode_E: { Result = 'E'; } break;
case KeyCode_F: { Result = 'F'; } break;
case KeyCode_G: { Result = 'G'; } break;
case KeyCode_H: { Result = 'H'; } break;
case KeyCode_I: { Result = 'I'; } break;
case KeyCode_J: { Result = 'J'; } break;
case KeyCode_K: { Result = 'K'; } break;
case KeyCode_L: { Result = 'L'; } break;
case KeyCode_M: { Result = 'M'; } break;
case KeyCode_N: { Result = 'N'; } break;
case KeyCode_O: { Result = 'O'; } break;
case KeyCode_P: { Result = 'P'; } break;
case KeyCode_Q: { Result = 'Q'; } break;
case KeyCode_R: { Result = 'R'; } break;
case KeyCode_S: { Result = 'S'; } break;
case KeyCode_T: { Result = 'T'; } break;
case KeyCode_U: { Result = 'U'; } break;
case KeyCode_V: { Result = 'V'; } break;
case KeyCode_W: { Result = 'W'; } break;
case KeyCode_X: { Result = 'X'; } break;
case KeyCode_Y: { Result = 'Y'; } break;
case KeyCode_Z: { Result = 'Z'; } break;
case KeyCode_Num0:
case KeyCode_0: { Result = '0'; } break;
case KeyCode_Num1:
case KeyCode_1: { Result = '1'; } break;
case KeyCode_Num2:
case KeyCode_2: { Result = '2'; } break;
case KeyCode_Num3:
case KeyCode_3: { Result = '3'; } break;
case KeyCode_Num4:
case KeyCode_4: { Result = '4'; } break;
case KeyCode_Num5:
case KeyCode_5: { Result = '5'; } break;
case KeyCode_Num6:
case KeyCode_6: { Result = '6'; } break;
case KeyCode_Num7:
case KeyCode_7: { Result = '7'; } break;
case KeyCode_Num8:
case KeyCode_8: { Result = '8'; } break;
case KeyCode_Num9:
case KeyCode_9: { Result = '9'; } break;
case KeyCode_Bang: { Result = '!'; } break;
case KeyCode_At: { Result = '@'; } break;
case KeyCode_Pound: { Result = '#'; } break;
case KeyCode_Dollar: { Result = '$'; } break;
case KeyCode_Percent: { Result = '%'; } break;
case KeyCode_Carrot: { Result = '^'; } break;
case KeyCode_Ampersand: { Result = '&'; } break;
case KeyCode_Star: { Result = '*'; } break;
case KeyCode_LeftParen: { Result = '('; } break;
case KeyCode_RightParen: { Result = ')'; } break;
case KeyCode_Minus: { Result = '-'; } break;
case KeyCode_Plus: { Result = '+'; } break;
case KeyCode_Equals: { Result = '='; } break;
case KeyCode_Underscore: { Result = '_'; } break;
case KeyCode_LeftBrace: { Result = '{'; } break;
case KeyCode_RightBrace: { Result = '}'; } break;
case KeyCode_LeftBracket: { Result = '['; } break;
case KeyCode_RightBracket: { Result = ']'; } break;
case KeyCode_Colon: { Result = ':'; } break;
case KeyCode_SemiColon: { Result = ';'; } break;
case KeyCode_SingleQuote: { Result = '\''; } break;
case KeyCode_DoubleQuote: { Result = '"'; } break;
case KeyCode_ForwardSlash: { Result = '/'; } break;
case KeyCode_Backslash: { Result = '\\'; } break;
case KeyCode_Pipe: { Result = '|'; } break;
case KeyCode_Comma: { Result = ','; } break;
case KeyCode_Period: { Result = '.'; } break;
case KeyCode_QuestionMark: { Result = '?'; } break;
case KeyCode_LessThan: { Result = '<'; } break;
case KeyCode_GreaterThan: { Result = '>'; } break;
case KeyCode_Tilde: { Result = '~'; } break;
case KeyCode_BackQuote: { Result = '`'; } break;
default: { Result = 0; } break;
}
return Result;
}
internal bool
KeyCodeHasChar(key_code Code)
{
bool Result = KeyCodeToChar(Code) != 0;
return Result;
}
internal key_code
CharToKeyCode(char C)
{
key_code Result = KeyCode_Invalid;
switch (C)
{
case ' ': { Result = KeyCode_Space; } break;
case '\t': { Result = KeyCode_Tab; } break;
case '\n': { Result = KeyCode_Enter; } break;
case '\b': { Result = KeyCode_Backspace; } break;
case 'a': { Result = KeyCode_a; } break;
case 'b': { Result = KeyCode_b; } break;
case 'c': { Result = KeyCode_c; } break;
case 'd': { Result = KeyCode_d; } break;
case 'e': { Result = KeyCode_e; } break;
case 'f': { Result = KeyCode_f; } break;
case 'g': { Result = KeyCode_g; } break;
case 'h': { Result = KeyCode_h; } break;
case 'i': { Result = KeyCode_i; } break;
case 'j': { Result = KeyCode_j; } break;
case 'k': { Result = KeyCode_k; } break;
case 'l': { Result = KeyCode_l; } break;
case 'm': { Result = KeyCode_m; } break;
case 'n': { Result = KeyCode_n; } break;
case 'o': { Result = KeyCode_o; } break;
case 'p': { Result = KeyCode_p; } break;
case 'q': { Result = KeyCode_q; } break;
case 'r': { Result = KeyCode_r; } break;
case 's': { Result = KeyCode_s; } break;
case 't': { Result = KeyCode_t; } break;
case 'u': { Result = KeyCode_u; } break;
case 'v': { Result = KeyCode_v; } break;
case 'w': { Result = KeyCode_w; } break;
case 'x': { Result = KeyCode_x; } break;
case 'y': { Result = KeyCode_y; } break;
case 'z': { Result = KeyCode_z; } break;
case 'A': { Result = KeyCode_A; } break;
case 'B': { Result = KeyCode_B; } break;
case 'C': { Result = KeyCode_C; } break;
case 'D': { Result = KeyCode_D; } break;
case 'E': { Result = KeyCode_E; } break;
case 'F': { Result = KeyCode_F; } break;
case 'G': { Result = KeyCode_G; } break;
case 'H': { Result = KeyCode_H; } break;
case 'I': { Result = KeyCode_I; } break;
case 'J': { Result = KeyCode_J; } break;
case 'K': { Result = KeyCode_K; } break;
case 'L': { Result = KeyCode_L; } break;
case 'M': { Result = KeyCode_M; } break;
case 'N': { Result = KeyCode_N; } break;
case 'O': { Result = KeyCode_O; } break;
case 'P': { Result = KeyCode_P; } break;
case 'Q': { Result = KeyCode_Q; } break;
case 'R': { Result = KeyCode_R; } break;
case 'S': { Result = KeyCode_S; } break;
case 'T': { Result = KeyCode_T; } break;
case 'U': { Result = KeyCode_U; } break;
case 'V': { Result = KeyCode_V; } break;
case 'W': { Result = KeyCode_W; } break;
case 'X': { Result = KeyCode_X; } break;
case 'Y': { Result = KeyCode_Y; } break;
case 'Z': { Result = KeyCode_Z; } break;
case '0': { Result = KeyCode_0; } break;
case '1': { Result = KeyCode_1; } break;
case '2': { Result = KeyCode_2; } break;
case '3': { Result = KeyCode_3; } break;
case '4': { Result = KeyCode_4; } break;
case '5': { Result = KeyCode_5; } break;
case '6': { Result = KeyCode_6; } break;
case '7': { Result = KeyCode_7; } break;
case '8': { Result = KeyCode_8; } break;
case '9': { Result = KeyCode_9; } break;
case '!': { Result = KeyCode_Bang; } break;
case '@': { Result = KeyCode_At; } break;
case '#': { Result = KeyCode_Pound; } break;
case '$': { Result = KeyCode_Dollar; } break;
case '%': { Result = KeyCode_Percent; } break;
case '^': { Result = KeyCode_Carrot; } break;
case '&': { Result = KeyCode_Ampersand; } break;
case '*': { Result = KeyCode_Star; } break;
case '(': { Result = KeyCode_LeftParen; } break;
case ')': { Result = KeyCode_RightParen; } break;
case '-': { Result = KeyCode_Minus; } break;
case '+': { Result = KeyCode_Plus; } break;
case '=': { Result = KeyCode_Equals; } break;
case '_': { Result = KeyCode_Underscore; } break;
case '{': { Result = KeyCode_LeftBrace; } break;
case '}': { Result = KeyCode_RightBrace; } break;
case '[': { Result = KeyCode_LeftBracket; } break;
case ']': { Result = KeyCode_RightBracket; } break;
case ':': { Result = KeyCode_Colon; } break;
case ';': { Result = KeyCode_SemiColon; } break;
case '\'': { Result = KeyCode_SingleQuote; } break;
case '"': { Result = KeyCode_DoubleQuote; } break;
case '/': { Result = KeyCode_ForwardSlash; } break;
case '\\': { Result = KeyCode_Backslash; } break;
case '|': { Result = KeyCode_Pipe; } break;
case ',': { Result = KeyCode_Comma; } break;
case '.': { Result = KeyCode_Period; } break;
case '?': { Result = KeyCode_QuestionMark; } break;
case '<': { Result = KeyCode_LessThan; } break;
case '>': { Result = KeyCode_GreaterThan; } break;
case '~': { Result = KeyCode_Tilde; } break;
case '`': { Result = KeyCode_BackQuote; } break;
default: { Result = KeyCode_Invalid; } break;
}
return Result;
}
#define GS_INPUT_H
#endif // GS_INPUT_H

View File

@ -441,6 +441,21 @@ SqrtU32(u32 V)
return sqrt(V);
}
internal r32
ModR32(r32 Value, r32 Int)
{
r32 Div = Value / Int;
r32 Fract = Abs(FractR32(Div));
return Int * Fract;
}
internal r64
ModR64(r64 Value, r64 Int)
{
r64 Div = Value / Int;
r64 Fract = Abs(FractR64(Div));
return Int * Fract;
}
internal r32
SinR32(r32 Rad)
{
@ -670,34 +685,34 @@ V4Cross(v4 A, v4 B)
}
internal v2
V2Lerp(v2 A, v2 B, r32 T)
V2Lerp(r32 T, v2 A, v2 B)
{
v2 Result = v2{
LerpR32(A.x, B.x, T),
LerpR32(A.y, B.y, T),
LerpR32(T, A.x, B.x),
LerpR32(T, A.y, B.y),
};
return Result;
}
internal v3
V3Lerp(v3 A, v3 B, r32 T)
V3Lerp(r32 T, v3 A, v3 B)
{
v3 Result = v3{
LerpR32(A.x, B.x, T),
LerpR32(A.y, B.y, T),
LerpR32(A.z, B.z, T),
LerpR32(T, A.x, B.x),
LerpR32(T, A.y, B.y),
LerpR32(T, A.z, B.z),
};
return Result;
}
internal v4
V4Lerp(v4 A, v4 B, r32 T)
V4Lerp(r32 T, v4 A, v4 B)
{
v4 Result = v4{
LerpR32(A.x, B.x, T),
LerpR32(A.y, B.y, T),
LerpR32(A.z, B.z, T),
LerpR32(A.w, B.w, T),
LerpR32(T, A.x, B.x),
LerpR32(T, A.y, B.y),
LerpR32(T, A.z, B.z),
LerpR32(T, A.w, B.w),
};
return Result;
}
@ -927,6 +942,10 @@ Range2Union(range2 A, range2 B)
Result.Min.y = Max(A.Min.y, B.Min.y);
Result.Max.x = Min(A.Max.x, B.Max.x);
Result.Max.y = Min(A.Max.y, B.Max.y);
if (Rect2Width(Result) < 0) { Result.Min.x = Result.Max.x; }
if (Rect2Height(Result) < 0) { Result.Min.y = Result.Max.y; }
return Result;
}
internal range3
@ -949,6 +968,41 @@ Rect2GetRectLocalPoint(rect2 Rect, v2 Point)
return Result;
}
internal r32
Rect2Area(rect2 Rect)
{
r32 Result = Rect2Width(Rect) * Rect2Height(Rect);
return Result;
}
internal v2
Rect2BottomLeft(rect2 Rect)
{
v2 Result = Rect.Min;
return Result;
}
internal v2
Rect2BottomRight(rect2 Rect)
{
v2 Result = v2{ Rect.Max.x, Rect.Min.y };
return Result;
}
internal v2
Rect2TopRight(rect2 Rect)
{
v2 Result = Rect.Max;
return Result;
}
internal v2
Rect2TopLeft(rect2 Rect)
{
v2 Result = v2{ Rect.Min.x, Rect.Max.y };
return Result;
}
///////////////////////////
//
// Ray
@ -1386,7 +1440,12 @@ CharArrayLength (char* CS)
internal bool
IsNullTerminated(gs_const_string String)
{
return (String.Str[String.Length] == 0);
bool Result = false;
if (String.Str)
{
Result = (String.Str[String.Length] == 0);
}
return Result;
}
internal bool
IsNullTerminated(gs_string String)
@ -1514,12 +1573,12 @@ FindFirstFromSet(gs_const_string String, char* SetArray)
return Result;
}
internal u64
internal s64
FindLastFromSet(gs_const_string String, char* SetArray)
{
gs_const_string Set = ConstString(SetArray);
u64 Result = String.Length - 1;
for(s64 At = Result; At >= 0; At--)
s64 Result = -1;
for(s64 At = String.Length - 1; At >= 0; At--)
{
char CharAt = String.Str[At];
for (u64 SetAt = 0; SetAt < Set.Length; SetAt++)
@ -1538,6 +1597,21 @@ FindLastFromSet(gs_const_string String, char* SetArray)
return Result;
}
internal bool
StringContains(gs_const_string Str, char C)
{
bool Result = false;
for (u32 i = 0; i < Str.Length; i++)
{
if (Str.Str[i] == C)
{
Result = true;
break;
}
}
return Result;
}
internal bool
StringsEqualUpToLength(gs_const_string A, gs_const_string B, u64 Length)
{
@ -1641,30 +1715,66 @@ CharToUInt(char C, u64 Base)
return CharToUInt(C, GetCharSetForBase(Base));
}
internal u64
ParseUInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0)
struct parse_uint_result
{
u64 Result = 0;
b8 Success;
u64 Value;
u32 ParsedLength;
};
internal parse_uint_result
ValidateAndParseUInt(gs_const_string String, u64 Base = 10)
{
parse_uint_result Result = {0};
gs_const_string CharSet = GetCharSetForBase(Base);
bool StringIsValid = true;
for (u32 i = 0; i < String.Length; i++)
{
if (!StringContains(CharSet, String.Str[i]))
{
StringIsValid = false;
break;
}
}
if (StringIsValid)
{
u64 Acc = 0;
u64 i = 0;
for (; i < String.Length; i++)
{
u64 CharIndex = FindFirst(CharSet, String.Str[i]);
if (CharIndex < CharSet.Length)
{
Result = CharToUInt(String.Str[i], CharSet) + (Result * Base);
Acc = CharToUInt(String.Str[i], CharSet) + (Acc * Base);
}
else
{
break;
}
}
if (ParsedLength != 0)
{
*ParsedLength = i;
Result.Success = true;
Result.Value = Acc;
Result.ParsedLength = i;
}
return Result;
}
internal u64
ParseUInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0)
{
parse_uint_result ParseResult = ValidateAndParseUInt(String, Base);
Assert(ParseResult.Success);
if (ParsedLength)
{
*ParsedLength = ParseResult.ParsedLength;
}
return ParseResult.Value;
}
internal u64
ParseUInt(u64 Length, char* String, u64 Base = 10, u64* ParsedLength = 0)
{
@ -1702,10 +1812,32 @@ ParseInt(char* String, u64 Base = 10, u64* ParsedLength = 0)
return ParseInt(LitString(String), Base, ParsedLength);
}
internal r64
ParseFloat(gs_const_string String, u64* ParsedLength = 0)
struct parse_float_result
{
b8 Success;
r64 Value;
u64 ParsedLength;
};
internal parse_float_result
ValidateAndParseFloat(gs_const_string String)
{
parse_float_result Result = {0};
Result.Success = false;
// Validate
bool StringIsValid = true;
for (u64 i = 0; i < String.Length; i++)
{
if (!IsNumericDecimal(String.Str[i]) && String.Str[i] != '-')
{
StringIsValid = false;
break;
}
}
if (StringIsValid)
{
u64 DecimalIndex = FindFirst(String, '.');
u64 TempParsedLength = 0;
u64 PlacesAfterPoint = 0;
@ -1719,22 +1851,36 @@ ParseFloat(gs_const_string String, u64* ParsedLength = 0)
IntegerString = GetStringAfter(IntegerString, 1);
Polarity = -1;
}
r64 Result = (r64)ParseInt(IntegerString, 10, &TempParsedLength);
Result.Value = (r64)ParseInt(IntegerString, 10, &TempParsedLength);
if (TempParsedLength == IntegerString.Length)
{
r64 AfterPoint = (r64)ParseUInt(DecimalString, 10, &PlacesAfterPoint);
r64 Decimal = (AfterPoint / PowR64(10, PlacesAfterPoint));
Result = Result + Decimal;
Result *= Polarity;
Result.Value = Result.Value + Decimal;
Result.Value *= Polarity;
}
Result.ParsedLength = TempParsedLength + PlacesAfterPoint;
if (DecimalIndex < String.Length) { Result.ParsedLength += 1; }
Result.Success = true;
}
return Result;
}
internal r64
ParseFloat(gs_const_string String, u64* ParsedLength = 0)
{
parse_float_result Result = ValidateAndParseFloat(String);
Assert(Result.Success);
if (ParsedLength != 0)
{
*ParsedLength = TempParsedLength + PlacesAfterPoint;
if (DecimalIndex < String.Length) { *ParsedLength += 1; }
*ParsedLength = Result.ParsedLength;
}
return Result;
return Result.Value;
}
internal r64
ParseFloat(char* String, u64* ParsedLength = 0)
@ -1956,11 +2102,16 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args)
FormatAt++;
if (IsBase10(FormatAt[0]))
{
PrecisionSpecified = true;
gs_const_string PrecisionStr = {};
PrecisionStr.Str = FormatAt;
for (char* C = FormatAt; *FormatAt && IsBase10(*C); C++)
{
PrecisionStr.Length++;
}
u64 Parsed = 0;
AssertMessage("ParseInt assumes whole string is an integer");
Precision = (s32)ParseInt(FormatAt, 10, &Parsed);
Precision = (s32)ParseInt(PrecisionStr, 10, &Parsed);
FormatAt += Parsed;
}
else if (FormatAt[0] == '*')
@ -1979,31 +2130,31 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args)
if (FormatAt[0] == 'h' && FormatAt[1] == 'h')
{
LengthSpecified = true;
LengthSpecified = 1;
Length = 1;
FormatAt += 2;
}
else if (FormatAt[0] == 'h')
{
LengthSpecified = true;
LengthSpecified = 2;
Length = 2;
FormatAt++;
}
else if (FormatAt[0] == 'l' && FormatAt[1] == 'l')
{
LengthSpecified = true;
LengthSpecified = 8;
Length = 8;
FormatAt += 2;
}
else if (FormatAt[0] == 'l')
{
LengthSpecified = true;
LengthSpecified = 4;
Length = 4;
FormatAt++;
}
else if (FormatAt[0] == 'j')
{
LengthSpecified = true;
LengthSpecified = 8;
Length = 8;
FormatAt++;
}
else if (FormatAt[0] == 'z')
@ -2034,7 +2185,7 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args)
}
else if (FormatAt[0] == 'u')
{
u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args);
u64 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args);
U64ToASCII(&StringRemaining, UnsignedInt, 10, Base10Chars);
}
else if (FormatAt[0] == 'o')
@ -2475,6 +2626,19 @@ PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...)
return Result;
}
internal gs_string
PushStringCopy(gs_memory_arena* Arena, gs_const_string String)
{
gs_string Result = PushString(Arena, String.Length);
Result.Size = String.Length;
Result.Length = String.Length;
for (u32 i = 0; i < String.Length; i++)
{
Result.Str[i] = String.Str[i];
}
return Result;
}
internal void
ClearArena(gs_memory_arena* Arena)
{
@ -3107,10 +3271,299 @@ TimeHandlerGetSecondsElapsed(gs_time_handler TimeHandler, s64 StartCycles, s64 E
return Result;
}
//////////////////////////
//
// Thread Manager
CREATE_THREAD(CreateThreadStub)
{
return {};
}
KILL_THREAD(KillThreadStub)
{
return false;
}
internal platform_thread_manager
CreatePlatformThreadManager(platform_create_thread* CreateThreadProc,
platform_kill_thread* KillThreadProc)
{
platform_thread_manager Result = {};
Result.CreateThreadProc = CreateThreadProc;
Result.KillThreadProc = KillThreadProc;
if (!CreateThreadProc)
{
Result.CreateThreadProc = CreateThreadStub;
}
if (!KillThreadProc)
{
Result.KillThreadProc = KillThreadStub;
}
return Result;
}
internal platform_thread_handle
CreateThread(platform_thread_manager* Manager, thread_proc_* Proc, u8* Arg)
{
platform_thread_handle Result = {};
for (u32 i = 1; i < THREADS_MAX; i++)
{
if (!Manager->ThreadsUsed[i])
{
Result.Index = i;
break;
}
}
Assert(Result.Index != 0);
Manager->ThreadsUsed[Result.Index] = true;
Manager->CreateThreadProc(&Manager->Threads[Result.Index], Proc, Arg);
return Result;
}
internal bool
KillThread(platform_thread_manager* Manager, platform_thread_handle Handle)
{
Assert(Manager->ThreadsUsed[Handle.Index]);
platform_thread* Thread = &Manager->Threads[Handle.Index];
bool Result = Manager->KillThreadProc(Thread);
if (Result)
{
Manager->ThreadsUsed[Handle.Index] = false;
Manager->Threads[Handle.Index] = {};
}
return Result;
}
//////////////////////////
//
// Socket Manager
CONNECT_SOCKET(PlatformConnectSocket_Stub)
{
return false;
}
CLOSE_SOCKET(PlatformCloseSocket_Stub)
{
return false;
}
SOCKET_QUERY_STATUS(PlatformSocketQueryStatus_Stub)
{
return false;
}
SOCKET_PEEK(PlatformSocketPeek_Stub)
{
return 0;
}
SOCKET_RECEIVE(PlatformSocketRecieve_Stub)
{
return {};
}
SOCKET_SEND(PlatformSocketSend_Stub)
{
return false;
}
internal platform_socket_manager
CreatePlatformSocketManager(platform_connect_socket* ConnectSocketProc,
platform_close_socket* CloseSocketProc,
platform_socket_query_status* SocketQueryStatusProc,
platform_socket_peek* SocketPeekProc,
platform_socket_receive* SocketRecieveProc,
platform_socket_send* SocketSendProc)
{
platform_socket_manager Result = {};
Result.ConnectSocketProc = ConnectSocketProc;
Result.CloseSocketProc = CloseSocketProc;
Result.SocketQueryStatusProc = SocketQueryStatusProc;
Result.SocketPeekProc = SocketPeekProc;
Result.SocketRecieveProc = SocketRecieveProc;
Result.SocketSendProc = SocketSendProc;
if (!ConnectSocketProc)
{
Result.ConnectSocketProc = PlatformConnectSocket_Stub;
}
if (!CloseSocketProc)
{
Result.CloseSocketProc = PlatformCloseSocket_Stub;
}
if (!SocketQueryStatusProc)
{
Result.SocketQueryStatusProc = PlatformSocketQueryStatus_Stub;
}
if (!SocketPeekProc)
{
Result.SocketPeekProc = PlatformSocketPeek_Stub;
}
if (!SocketRecieveProc)
{
Result.SocketRecieveProc = PlatformSocketRecieve_Stub;
}
if (!SocketSendProc)
{
Result.SocketSendProc = PlatformSocketSend_Stub;
}
return Result;
}
internal platform_socket*
SocketManagerGetSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle)
{
platform_socket* Result = 0;
if (Manager->SocketsUsed[Handle.Index])
{
platform_socket* Socket = &Manager->Sockets[Handle.Index];
if (Socket->PlatformHandle != 0)
{
Result = Socket;
}
}
return Result;
}
internal bool
ConnectSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle)
{
bool Result = false;
platform_socket* Socket = SocketManagerGetSocket(Manager, Handle);
if (Socket)
{
Result = Manager->ConnectSocketProc(Socket);
}
return Result;
}
internal platform_socket_handle_
CreateSocket(platform_socket_manager* Manager, char* Addr, char* Port)
{
platform_socket_handle_ Result = {};
for (u32 i = 1; i < SOCKETS_COUNT_MAX; i++)
{
if (!Manager->SocketsUsed[i])
{
Result.Index = i;
Manager->SocketsUsed[i] = true;
break;
}
}
Assert(Result.Index != 0);
platform_socket* Socket = &Manager->Sockets[Result.Index];
CopyArray(Addr, Socket->Addr, char, CStringLength(Addr) + 1);
CopyArray(Port, Socket->Port, char, CStringLength(Port) + 1);
bool Success = Manager->ConnectSocketProc(Socket);
Assert(Success);
return Result;
}
internal bool
CloseSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle)
{
bool Result = false;
platform_socket* Socket = SocketManagerGetSocket(Manager, Handle);
if (Socket)
{
if (Manager->CloseSocketProc(Socket))
{
Manager->SocketsUsed[Handle.Index] = false;
*Socket = {};
Result = true;
}
}
return Result;
}
// NOTE(pjs): returns true if the socket is connected
// TODO(pjs): make this more descriptive?
internal bool
SocketQueryStatus(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle)
{
bool Result = false;
platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle);
if (Socket)
{
Result = Manager->SocketQueryStatusProc(Socket);
}
return Result;
}
internal u32
SocketPeek(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle)
{
u32 Result = 0;
platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle);
if (Socket)
{
Result = Manager->SocketPeekProc(Socket);
}
return Result;
}
internal gs_data
SocketRecieve(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, gs_memory_arena* Storage)
{
gs_data Result = {};
platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle);
if (Socket)
{
Result = Manager->SocketRecieveProc(Socket, Storage);
}
return Result;
}
internal bool
SocketSend(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, u32 Address, u32 Port, gs_data Data, s32 Flags)
{
bool Result = false;
platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle);
if (Socket)
{
s32 SizeSent = Manager->SocketSendProc(Socket, Address, Port, Data, Flags);
Result = (SizeSent == Data.Size);
}
return Result;
}
///////////////////////////
//
// Hashes
internal u32
HashAppendDJB2ToU32(u32 Hash, u8 Byte)
{
u32 Result = Hash;
if (Result == 0) { Result = 5381; }
Result = ((Result << 5) + Result) + Byte;
return Result;
}
internal u64
HashAppendDJB2ToU32(u64 Hash, u8 Byte)
{
u64 Result = Hash;
if (Result == 0) { Result = 5381; }
Result = ((Result << 5) + Result) + Byte;
return Result;
}
internal u32
HashDJB2ToU32(char* String)
{

View File

@ -9,6 +9,7 @@
# pragma GCC diagnostic ignored "-Wunused-value"
# pragma GCC diagnostic ignored "-Wvarargs"
# pragma GCC diagnostic ignored "-Wwritable-strings"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#if defined(_MSC_VER)
@ -574,7 +575,8 @@ CStringLength(char* Str)
{
char* At = Str;
while (*At) { At++; }
return PointerDifference(At, Str);
u64 Result = PointerDifference(At, Str);
return Result;
}
#define StringExpand(str) (int)(str).Length, (str).Str
@ -1004,16 +1006,52 @@ struct gs_thread_context
gs_memory_arena* Transient;
};
// Threads & Work Queue
// Threads
typedef struct platform_thread_handle
{
u32 Index;
} platform_thread_handle;
typedef struct platform_thread_manager platform_thread_manager;
#define THREAD_PROC_(name) void name(gs_thread_context* Ctx, u8* UserData)
typedef THREAD_PROC_(thread_proc_);
typedef struct platform_thread
{
u8* PlatformHandle;
thread_proc_* Proc;
u8* UserData;
// TODO(pjs): Some kind of platform thread handle
} platform_thread;
#define CREATE_THREAD(name) bool name(platform_thread* Thread, thread_proc_* Proc, u8* UserData)
typedef CREATE_THREAD(platform_create_thread);
#define KILL_THREAD(name) bool name(platform_thread* Thread)
typedef KILL_THREAD(platform_kill_thread);
#define THREADS_MAX 32
typedef struct platform_thread_manager
{
b8 ThreadsUsed[THREADS_MAX];
platform_thread Threads[THREADS_MAX];
platform_create_thread* CreateThreadProc;
platform_kill_thread* KillThreadProc;
} platform_thread_manager;
// Work Queue
typedef struct gs_work_queue gs_work_queue;
struct gs_worker_thread
typedef struct gs_worker_thread
{
gs_thread_context Context;
gs_work_queue* Queue;
b32 ShouldExit;
};
} gs_worker_thread;
#define THREAD_PROC(name) void name(gs_thread_context Context, gs_data Data)
typedef THREAD_PROC(thread_proc);
@ -1047,8 +1085,57 @@ struct gs_work_queue
// Work Queue
push_work_on_queue* PushWorkOnQueue;
complete_queue_work* CompleteQueueWork;
reset_work_queue* ResetWorkQueue;
};
// Sockets
typedef struct platform_socket_handle_
{
u32 Index;
} platform_socket_handle_;
typedef struct platform_socket
{
char Addr[128];
char Port[32];
u8* PlatformHandle;
} platform_socket;
#define CONNECT_SOCKET(name) bool name(platform_socket* Socket)
typedef CONNECT_SOCKET(platform_connect_socket);
#define CLOSE_SOCKET(name) bool name(platform_socket* Socket)
typedef CLOSE_SOCKET(platform_close_socket);
#define SOCKET_QUERY_STATUS(name) bool name(platform_socket* Socket)
typedef SOCKET_QUERY_STATUS(platform_socket_query_status);
#define SOCKET_PEEK(name) u32 name(platform_socket* Socket)
typedef SOCKET_PEEK(platform_socket_peek);
// TODO(pjs): allow for a size parameter that can be zero
// if provided, that is how big the message it expects to be
// if it equals zero, the proc will peek at the message first to determine
// the needed size
#define SOCKET_RECEIVE(name) gs_data name(platform_socket* Socket, gs_memory_arena* Storage)
typedef SOCKET_RECEIVE(platform_socket_receive);
#define SOCKET_SEND(name) s32 name(platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags)
typedef SOCKET_SEND(platform_socket_send);
#define SOCKETS_COUNT_MAX 32
typedef struct platform_socket_manager
{
b8 SocketsUsed[SOCKETS_COUNT_MAX];
platform_socket Sockets[SOCKETS_COUNT_MAX];
platform_connect_socket* ConnectSocketProc;
platform_close_socket* CloseSocketProc;
platform_socket_query_status* SocketQueryStatusProc;
platform_socket_peek* SocketPeekProc;
platform_socket_receive* SocketRecieveProc;
platform_socket_send* SocketSendProc;
} platform_socket_manager;
#define GS_TYPES_H
#endif // GS_TYPES_H

View File

@ -0,0 +1,227 @@
//
// File: gen_blumen_lumen.cpp
// Author: Peter Slattery
// Creation Date: 2021-01-06
//
#ifndef GEN_BLUMEN_LUMEN_CPP
#include <stdio.h>
#include <windows.h>
#include "../gs_libs/gs_types.h"
#include "../gs_libs/gs_types.cpp"
#include "../app/platform_win32/win32_foldhaus_utils.h"
#include "../app/platform_win32/win32_foldhaus_memory.h"
#include "../app/platform_win32/win32_foldhaus_fileio.h"
#include "../app/platform_win32/win32_foldhaus_work_queue.h"
#include "sculpture_gen.h"
typedef struct
{
v3 CenterStart;
v3 CenterEnd;
r32 Radius;
u32 SegmentsCount;
u32 SubsegmentsCount;
u32 SubsegmentLeds;
// Only one of these two values is needed.
// If ChannelsArray != 0, then it will be used, and assumed to
// have SegmentsCount values
// Otherwise, each segment will increment from ChannelStart
u32 ChannelStart;
u32* ChannelsArray;
char* ComPort;
char* SectionTagValue;
char* FlowerTagValue;
} loop_desc;
internal void
BuildLoop(gs_string* OutputBuffer, loop_desc Desc)
{
r32 SegmentsArc = TauR32 / Desc.SegmentsCount;
r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount;
for (u32 i = 0; i < Desc.SegmentsCount; i++)
{
r32 ArcBase = SegmentsArc * i;
u32 Channel = 0;
if (Desc.ChannelsArray != 0)
{
Channel = Desc.ChannelsArray[i];
}
else
{
Channel = Desc.ChannelStart + i;
}
WriteLedStripOpen(OutputBuffer, Channel, Desc.ComPort);
WriteSegmentSequenceOpen(OutputBuffer, Desc.SubsegmentsCount);
for (u32 j = 0; j < Desc.SubsegmentsCount; j++)
{
r32 Arc = ArcBase + (SubsegmentsArc * j);
v3 Offset = v3{ SinR32(Arc), 0, CosR32(Arc) } * Desc.Radius;
v3 P0 = Desc.CenterStart + Offset;
v3 P1 = Desc.CenterEnd + Offset;
// Swap directions on the middle strip
if (j%2 != 0)
{
v3 Temp = P0;
P0 = P1;
P1 = Temp;
}
WriteSegmentSequenceSegment(OutputBuffer, P0, P1, Desc.SubsegmentLeds);
}
WriteSegmentSequenceClose(OutputBuffer);
WriteSegmentTagsOpen(OutputBuffer, 2);
WriteSegmentTag(OutputBuffer, "section", Desc.SectionTagValue);
WriteSegmentTag(OutputBuffer, "flower", Desc.FlowerTagValue);
WriteSegmentTagsClose(OutputBuffer);
WriteLedStripClose(OutputBuffer);
}
}
typedef struct
{
v3 Pos;
char* ComPort;
char* FlowerTagValue;
u32* StemChannels;
u32* BloomOuterChannels;
u32* BloomInnerChannels;
} flower_desc;
internal u32
BuildFlower(gs_string* OutputBuffer, flower_desc Desc)
{
#if 1
// the bloom stem inner
loop_desc BloomStemInner = {};
BloomStemInner.CenterStart = v3{0, 1.4f, 0} + Desc.Pos;
BloomStemInner.CenterEnd = v3{0, .9f, 0} + Desc.Pos;
BloomStemInner.Radius = .05f;
BloomStemInner.SegmentsCount = 6;
BloomStemInner.SubsegmentsCount = 3;
BloomStemInner.SubsegmentLeds = 35;
BloomStemInner.ChannelsArray = Desc.BloomInnerChannels;
BloomStemInner.ComPort = Desc.ComPort;
BloomStemInner.SectionTagValue = "inner_bloom";
BloomStemInner.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemInner);
// the bloom stem outer
loop_desc BloomStemOuter = {};
BloomStemOuter.CenterStart = v3{0, .5f, 0} + Desc.Pos;
BloomStemOuter.CenterEnd = v3{0, .9f, 0} + Desc.Pos;
BloomStemOuter.Radius = .07f;
BloomStemOuter.SegmentsCount = 9;
BloomStemOuter.SubsegmentsCount = 3;
BloomStemOuter.SubsegmentLeds = 41;
BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels;
BloomStemOuter.ComPort = Desc.ComPort;
BloomStemOuter.SectionTagValue = "outer_bloom";
BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemOuter);
#endif
#if 1
// the flower stem
loop_desc FlowerStem = {};
FlowerStem.CenterStart = v3{0, -1.5f, 0} + Desc.Pos;
FlowerStem.CenterEnd = v3{0, .5f, 0} + Desc.Pos;
FlowerStem.Radius = .05f;
FlowerStem.SegmentsCount = 6;
FlowerStem.SubsegmentsCount = 1;
FlowerStem.SubsegmentLeds = 300;
FlowerStem.ChannelsArray = Desc.StemChannels;
FlowerStem.ComPort = Desc.ComPort;
FlowerStem.SectionTagValue = "stem";
FlowerStem.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, FlowerStem);
#endif
u32 StripsCount = BloomStemInner.SegmentsCount;
StripsCount += BloomStemOuter.SegmentsCount;
StripsCount += FlowerStem.SegmentsCount;
return StripsCount;
}
// Just for brevity, no real function provided
#define FSC(f,c) FlowerStripToChannel((f), (c))
internal u8
FlowerStripToChannel(u8 Flower, u8 Channel)
{
Assert(Flower < 3);
Assert(Channel < 8);
u8 Result = 0;
Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07);
return Result;
}
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
gs_string OutputBuffer = PushString(Ctx.Transient, MB(4));
WriteAssemblyUARTOpen(&OutputBuffer,
"Blumen Lumen - Silver Spring",
100,
v3{0, 0, 0},
63,
"");
u32 StripCount = 0;
u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) };
u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) };
u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) };
flower_desc F0 = {};
F0.Pos = v3{-1, 0, 0};
F0.ComPort = "\\\\.\\COM4";
F0.FlowerTagValue = "left";
F0.StemChannels = StemChannels;
F0.BloomOuterChannels = BloomOuterChannels;
F0.BloomInnerChannels = BloomInnerChannels;
StripCount += BuildFlower(&OutputBuffer, F0);
flower_desc F1 = {};
F1.Pos = v3{0, 0, 0};
F1.ComPort = "\\\\.\\COM5";
F1.FlowerTagValue = "center";
F1.StemChannels = StemChannels;
F1.BloomInnerChannels = BloomInnerChannels;
F1.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer, F1);
flower_desc F2 = {};
F2.Pos = v3{1, 0, 0};
F2.ComPort = "\\\\.\\COM6";
F2.FlowerTagValue = "right";
F2.StemChannels = StemChannels;
F2.BloomInnerChannels = BloomInnerChannels;
F2.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer, F2);
printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str);
//printf("%d\n", StripCount);
return 0;
}
#define GEN_BLUMEN_LUMEN_CPP
#endif // GEN_BLUMEN_LUMEN_CPP

View File

@ -0,0 +1,106 @@
//
// File: sculpture_gen.h
// Author: Peter Slattery
// Creation Date: 2021-01-06
//
#ifndef SCULPTURE_GEN_H
internal void
WriteIndented(gs_string* Buffer, u32 Indent, char* Format, ...)
{
va_list Args;
va_start(Args, Format);
for (u32 i = 0; i < Indent; i++)
{
OutChar(Buffer, '\t');
}
PrintFArgsList(Buffer, Format, Args);
va_end(Args);
}
internal void
WriteAssemblyUARTOpen(gs_string* Buffer, char* Name, u32 Scale, v3 Center, u32 StripCount, char* ComPort)
{
WriteIndented(Buffer, 0, "assembly_name: \"%s\";\n", Name);
WriteIndented(Buffer, 0, "assembly_scale: %d;\n", Scale);
WriteIndented(Buffer, 0, "assembly_center: (%f, %f, %f);\n", Center.x, Center.y, Center.z);
WriteIndented(Buffer, 0, "led_strip_count: %d;\n", StripCount);
WriteIndented(Buffer, 0, "output_mode: \"UART\";\n");
if (ComPort)
{
WriteIndented(Buffer, 0, "com_port: \"%s\";\n", ComPort);
}
}
internal void
WriteLedStripOpen(gs_string* Buffer, u32 Channel, char* ComPort)
{
WriteIndented(Buffer, 0, "led_strip:\n{\n");
WriteIndented(Buffer, 1, "output_uart: {\n");
WriteIndented(Buffer, 2, "channel: %d;\n", Channel);
WriteIndented(Buffer, 2, "com_port: \"%s\";\n", ComPort);
WriteIndented(Buffer, 1, "};\n\n");
}
internal void
WriteSegmentSequenceOpen(gs_string* Buffer, u32 SegmentCount)
{
WriteIndented(Buffer, 1, "segment: {\n");
WriteIndented(Buffer, 2, "point_placement_type: \"SegmentSequence\";\n");
WriteIndented(Buffer, 2, "segment_sequence:\n");
WriteIndented(Buffer, 2, "{\n");
WriteIndented(Buffer, 3, "segment_count: %d;\n", SegmentCount);
}
internal void
WriteSegmentSequenceSegment(gs_string* Buffer, v3 P0, v3 P1, u32 LedCount)
{
WriteIndented(Buffer, 3, "segment: {\n");
WriteIndented(Buffer, 4, "point_placement_type: \"InterpolatePoints\";\n");
WriteIndented(Buffer, 4, "interpolate_points: {\n");
WriteIndented(Buffer, 5, "start: (%f, %f, %f);\n", P0.x, P0.y, P0.z);
WriteIndented(Buffer, 5, "end: (%f, %f, %f);\n", P1.x, P1.y, P1.z);
WriteIndented(Buffer, 5, "led_count: %d;\n", LedCount);
WriteIndented(Buffer, 4, "};\n");
WriteIndented(Buffer, 3, "};\n");
}
internal void
WriteSegmentSequenceClose(gs_string* Buffer)
{
WriteIndented(Buffer, 2, "};\n");
WriteIndented(Buffer, 1, "};\n");
}
internal void
WriteSegmentTagsOpen(gs_string* Buffer, u32 TagCount)
{
WriteIndented(Buffer, 1, "tags_count: %d;\n", TagCount);
}
internal void
WriteSegmentTag(gs_string* Buffer, char* TagName, char* TagValue)
{
WriteIndented(Buffer, 1, "tag: {\n");
WriteIndented(Buffer, 2, "name: \"%s\";\n", TagName);
WriteIndented(Buffer, 2, "value: \"%s\";\n", TagValue);
WriteIndented(Buffer, 1, "};\n");
}
internal void
WriteSegmentTagsClose(gs_string* Buffer)
{
}
internal void
WriteLedStripClose(gs_string* Buffer)
{
WriteIndented(Buffer, 0, "};\n");
}
#define SCULPTURE_GEN_H
#endif // SCULPTURE_GEN_H

View File

@ -43,7 +43,6 @@ STREAM #1: 3D Overhaul
- :ErrorLogging
- Animation System
- blending between animation
- layers
- layer masks by sculpture
- layer masks by tag / value

View File

@ -1,3 +1,5 @@
x blending between animation
x saving animation timelines
x Buckets & Lists
x On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place

19
test_motor_header.h Normal file
View File

@ -0,0 +1,19 @@
//
// File: test_motor_header.h
// Author: Peter Slattery
// Creation Date: 2021-01-14
//
#ifndef TEST_MOTOR_HEADER_H
struct
{
u8 MotorOnePos;
u8 MotorTwoPos;
u8 MotorThreePos;
} typedef packet;
static packet
UnpackPacket
#define TEST_MOTOR_HEADER_H
#endif // TEST_MOTOR_HEADER_H

View File

@ -0,0 +1,29 @@
//
// File: test_sound_interface_packet.h
// Author: Peter Slattery
// Creation Date: 2021-01-14
//
#ifndef TEST_SOUND_INTERFACE_PACKET_H
enum selectable_patterns
{
};
typedef struct
{
u8 PrimaryColor[3];
u8 SecondaryColor[3];
u32 PatternIndex; // Set via selectable_patterns
u8 Speed; //
} sound_interface_packet;
// expects V to be in the range -1:1
u8 FloatToSpeed (float V)
{
u8 Result = (u8)(((V + 1) / 2) * 255);
return Result;
}
#define TEST_SOUND_INTERFACE_PACKET_H
#endif // TEST_SOUND_INTERFACE_PACKET_H