Merge branch 'dev'
This commit is contained in:
commit
ea2eb0e469
25
README.md
25
README.md
|
@ -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.
|
||||
|
@ -26,7 +35,7 @@ The following features are under active development for integration in Lumenariu
|
|||
|
||||
***
|
||||
### Sculpture File Format
|
||||
Sculptures are specified via a structured text file so that it is easy to represent new sculptures, simply as strips of LEDs.
|
||||
Sculptures are specified via a structured text file so that it is easy to represent new sculptures, simply as strips of LEDs.
|
||||
|
||||
Documentation coming soon.
|
||||
|
||||
|
@ -36,13 +45,13 @@ Lumenarium supports SACN output, and ArtNet is in development, via a DMX system
|
|||
|
||||
***
|
||||
### Live Visualization
|
||||
We don't always have access to our physical sculptures while working on the lights and motion for them. Having a visualization of the sculpture lets us see what the patterns we develop will look like when running on the actual sculpture.
|
||||
We don't always have access to our physical sculptures while working on the lights and motion for them. Having a visualization of the sculpture lets us see what the patterns we develop will look like when running on the actual sculpture.
|
||||
|
||||
The visualization runs in real time, and mirrors the DMX output the sculptures will receive, so any changes made in the software are immediately reflected, both in the visualization and in the data sent over the network.
|
||||
|
||||
***
|
||||
### Animation Timeline
|
||||
One goal of Lumenarium is to enable fine-grained control over procedural light and motion patterns. Patterns can be arranged on a timeline for manual sequencing.
|
||||
One goal of Lumenarium is to enable fine-grained control over procedural light and motion patterns. Patterns can be arranged on a timeline for manual sequencing.
|
||||
|
||||
Coming Soon
|
||||
* Pattern Fading/Cross fading
|
||||
|
@ -58,6 +67,6 @@ Coming Soon
|
|||
|
||||
***
|
||||
### Live Compilation Reload
|
||||
One of the most fulfilling parts of working on these sculptures is getting to iterate live on the lights and motion in front of the physical sculpture while on active display. While Lumenarium is designed to enable everyone to shape the visual identity of our sculptures, it also allows for low-level, fine grained control over the visual output as well. The software is split into a platform layer (currently Windows only, though there are plans to support Mac, and possibly Raspberry Pi), and an application library. The application library can be recompiled and hot loaded while the software is running to facilitate the fastest possible iteration time.
|
||||
One of the most fulfilling parts of working on these sculptures is getting to iterate live on the lights and motion in front of the physical sculpture while on active display. While Lumenarium is designed to enable everyone to shape the visual identity of our sculptures, it also allows for low-level, fine grained control over the visual output as well. The software is split into a platform layer (currently Windows only, though there are plans to support Mac, and possibly Raspberry Pi), and an application library. The application library can be recompiled and hot loaded while the software is running to facilitate the fastest possible iteration time.
|
||||
|
||||
To see how this works in detail see [Handmade Hero](https://guide.handmadehero.org/code/day022/)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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%
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
call remedybg.bat ./app_run_tree/win32_msvc/debug/session.rdbg
|
|
@ -0,0 +1,4 @@
|
|||
@echo off
|
||||
pushd app_run_tree
|
||||
start win32_msvc\debug\win32_foldhaus.exe
|
||||
popd
|
|
@ -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
|
|
@ -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
|
|
@ -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,88 +118,38 @@ 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);
|
||||
|
||||
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
|
||||
|
||||
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
|
||||
ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout"));
|
||||
{
|
||||
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
||||
if (OperationMode.Render != 0)
|
||||
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
|
||||
|
||||
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
|
||||
{
|
||||
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
|
||||
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
||||
if (OperationMode.Render != 0)
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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,35 +793,95 @@ 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);
|
||||
if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), ActiveAnim->Name))
|
||||
{
|
||||
ui_DrawString(Interface, MakeString("Active Animation"));
|
||||
if (ui_BeginDropdown(Interface, ActiveAnim->Name))
|
||||
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
|
||||
{
|
||||
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
|
||||
animation Animation = AnimSystem->Animations.Values[i];
|
||||
if (ui_Button(Interface, Animation.Name))
|
||||
{
|
||||
animation Animation = AnimSystem->Animations.Values[i];
|
||||
if (ui_Button(Interface, Animation.Name))
|
||||
AnimSystem->ActiveAnimationIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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)))
|
||||
{
|
||||
AnimSystem->ActiveAnimationIndex = i;
|
||||
SelectedBlock->AnimationProcHandle = Patterns_IndexToHandle(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_EndDropdown(Interface);
|
||||
ui_EndLabeledDropdown(Interface);
|
||||
}
|
||||
ui_EndRow(&State->Interface);
|
||||
ui_PopLayout(Interface);
|
||||
|
||||
ui_PopLayout(Interface, MakeString("AnimInfo Layout"));
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -835,31 +897,26 @@ 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);
|
||||
rect2 LayersPanelBounds, TimeRangePanelBounds;
|
||||
RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds);
|
||||
|
||||
{ // Timeline
|
||||
rect2 LayersPanelBounds, TimeRangePanelBounds;
|
||||
RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds);
|
||||
|
||||
r32 TitleBarHeight = State->Interface.Style.RowHeight;
|
||||
// These are the actual rects we will draw in
|
||||
rect2 PlayBarBounds, FrameCountBounds;
|
||||
rect2 LayersBounds, TimeRangeBounds;
|
||||
RectHSplitAtDistanceFromTop(LayersPanelBounds, TitleBarHeight, &PlayBarBounds, &LayersBounds);
|
||||
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
|
||||
|
||||
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
|
||||
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
|
||||
LayerList_Render(TimelineState, LayersBounds, RenderBuffer, State, Context);
|
||||
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
|
||||
}
|
||||
r32 TitleBarHeight = State->Interface.Style.RowHeight;
|
||||
// These are the actual rects we will draw in
|
||||
rect2 PlayBarBounds, FrameCountBounds;
|
||||
rect2 LayersBounds, TimeRangeBounds;
|
||||
RectHSplitAtDistanceFromTop(LayersPanelBounds, TitleBarHeight, &PlayBarBounds, &LayersBounds);
|
||||
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
|
||||
|
||||
AnimInfoView_Render(TimelineState, AnimInfoBounds, RenderBuffer, State, Context);
|
||||
SelectionInfoView_Render(TimelineState, SelectionInfoBounds, RenderBuffer, State, Context);
|
||||
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
|
||||
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
|
||||
LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context);
|
||||
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
|
||||
AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context);
|
||||
}
|
||||
|
||||
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
|
||||
|
|
|
@ -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
|
|
@ -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, "\\");
|
||||
// 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);
|
||||
}
|
||||
if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '*')
|
||||
{
|
||||
AppendPrintF(&State->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,44 +105,61 @@ 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);
|
||||
|
||||
if (ui_Button(&State->Interface, MakeString("Exit")))
|
||||
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
|
||||
{
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
}
|
||||
|
||||
// Header
|
||||
ui_DrawString(&State->Interface, FileViewState->WorkingDirectory);
|
||||
|
||||
// File Display
|
||||
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
|
||||
{
|
||||
gs_file_info File = FileViewState->FileNames.Values[i];
|
||||
|
||||
u32 LastSlashIndex = FindLast(File.Path, '\\');
|
||||
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_Button(&State->Interface, MakeString("Exit")))
|
||||
{
|
||||
if (File.IsDirectory)
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
}
|
||||
|
||||
// Header
|
||||
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 == '/')
|
||||
{
|
||||
FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context);
|
||||
FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileViewState->SelectedFile = File;
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
u32 LastSlashIndex = FindLast(File.Path, '\\');
|
||||
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, PathString, i))
|
||||
{
|
||||
if (File.IsDirectory)
|
||||
{
|
||||
FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileViewState->SelectedFile = File;
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_EndList(&State->Interface);
|
||||
}
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
ui_PopLayout(&State->Interface, MakeString("FileView Layout"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FOLDHAUS_PANEL_FILE_VIEW_H
|
||||
#endif // FOLDHAUS_PANEL_FILE_VIEW_H
|
|
@ -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);
|
||||
}
|
||||
|
||||
for (u32 AssemblyIndex = 0; AssemblyIndex < AssembliesToDraw; AssemblyIndex++)
|
||||
{
|
||||
assembly Assembly = State->Assemblies.Values[AssemblyIndex];
|
||||
PrintF(&TempString, "%S", Assembly.Name);
|
||||
|
||||
ui_StartRow(&State->Interface, 2);
|
||||
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_DrawString(&State->Interface, TempString);
|
||||
if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex))
|
||||
ui_BeginRow(&State->Interface, 2, &Cols[0]);
|
||||
|
||||
assembly Assembly = State->Assemblies.Values[i];
|
||||
PrintF(&TempString, "%S", Assembly.Name);
|
||||
|
||||
ui_Label(&State->Interface, TempString);
|
||||
if (ui_Button(&State->Interface, MakeString("X")))
|
||||
{
|
||||
UnloadAssembly(AssemblyIndex, State, Context);
|
||||
UnloadAssembly(i, State, Context);
|
||||
}
|
||||
|
||||
ui_EndRow(&State->Interface);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (AssembliesToDraw < LineCount)
|
||||
{
|
||||
// NOTE(Peter): Add assembly button
|
||||
PrintF(&TempString, "+ Add Assembly");
|
||||
if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw))
|
||||
{
|
||||
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
|
||||
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
|
||||
}
|
||||
}
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
ui_EndList(&State->Interface);
|
||||
ui_PopLayout(&State->Interface, MakeString("Hierarchy Layout"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,86 +25,117 @@ 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];
|
||||
|
||||
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) }
|
||||
};
|
||||
if (Rect2Width(ScopeBounds) >= 1)
|
||||
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++)
|
||||
{
|
||||
v4 Color = ThreadColors[0];
|
||||
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
|
||||
{
|
||||
Color = GreenV4;
|
||||
HotRecord = Record;
|
||||
HotRecordName = Name;
|
||||
}
|
||||
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;
|
||||
|
||||
ui_FillRect(Interface, ScopeBounds, Color);
|
||||
ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4);
|
||||
rect2 ScopeBounds = {
|
||||
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 = ThreadRGB;
|
||||
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
|
||||
{
|
||||
Color = GreenV4;
|
||||
|
||||
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);
|
||||
ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%d", CollatedRecord->CallCount);
|
||||
ui_DrawString(Interface, String);
|
||||
}
|
||||
ui_EndRow(Interface);
|
||||
PrintF(&String, "%S", NameEntry.Name);
|
||||
ui_Label(Interface, String);
|
||||
|
||||
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
|
||||
ui_Label(Interface, String);
|
||||
|
||||
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
|
||||
ui_Label(Interface, String);
|
||||
|
||||
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
|
||||
ui_Label(Interface, String);
|
||||
|
||||
PrintF(&String, "%d", CollatedRecord->CallCount);
|
||||
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"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,18 +265,9 @@ 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++)
|
||||
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
|
||||
{
|
||||
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)
|
||||
{
|
||||
Result.StripIndices[Result.Count++] = StripIndex;
|
||||
}
|
||||
}
|
||||
Result.StripIndices[Result.Count++] = StripIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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++;
|
||||
}
|
||||
P->At++;
|
||||
}
|
||||
|
||||
internal void
|
||||
|
|
|
@ -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,29 +69,102 @@ 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;
|
||||
|
||||
u32* StripIndices;
|
||||
u32 StripIndicesCount;
|
||||
u32 StripIndicesCountMax;
|
||||
|
||||
u64 LedCount;
|
||||
|
||||
u8** ChannelsStart;
|
||||
|
||||
strips_to_data_buffer* Next;
|
||||
};
|
||||
|
||||
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
|
||||
AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString);
|
||||
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
|
||||
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];
|
||||
ChannelSettings.PixelsCount = StripAt.LedCount;
|
||||
UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
UART_DrawAll_Create(&WriteCursor);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
animation_system_desc AnimSysDesc = {};
|
||||
AnimSysDesc.Storage = &State->Permanent;
|
||||
AnimSysDesc.AnimArrayCount = 32;
|
||||
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
|
||||
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
|
||||
|
||||
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->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
|
||||
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
US_CustomUpdate(&State->UserSpaceDesc, State, Context);
|
||||
|
||||
AssemblyDebug_OverrideOutput(State->AssemblyDebugState,
|
||||
State->Assemblies,
|
||||
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
|
||||
// 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, State->Transient);
|
||||
}
|
||||
|
||||
CLEANUP_APPLICATION(CleanupApplication)
|
||||
{
|
||||
app_state* State = (app_state*)Context.MemoryBase;
|
||||
US_CustomCleanup(&State->UserSpaceDesc, State, Context);
|
||||
SACN_Cleanup(&State->SACN, Context);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
#include "engine/user_space.cpp"
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
1574
src/app/interface.h
1574
src/app/interface.h
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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,100 +372,155 @@ 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)
|
||||
{
|
||||
switch(BufferAt->AddressType)
|
||||
case AddressType_NetworkIP:
|
||||
{
|
||||
case AddressType_NetworkIP:
|
||||
Win32Socket_SendTo(BufferAt->SendSocket,
|
||||
BufferAt->V4SendAddress,
|
||||
BufferAt->SendPort,
|
||||
(const char*)BufferAt->Memory,
|
||||
BufferAt->MemorySize,
|
||||
0);
|
||||
}break;
|
||||
|
||||
case AddressType_ComPort:
|
||||
{
|
||||
if (BufferAt->ComPort.Length > 0)
|
||||
{
|
||||
Win32Socket_SendTo(BufferAt->SendSocket,
|
||||
BufferAt->V4SendAddress,
|
||||
BufferAt->SendPort,
|
||||
(const char*)BufferAt->Memory,
|
||||
BufferAt->MemorySize,
|
||||
0);
|
||||
}break;
|
||||
|
||||
case AddressType_ComPort:
|
||||
{
|
||||
if (BufferAt->ComPort.Length > 0)
|
||||
HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1);
|
||||
if (SerialPort != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1);
|
||||
if (SerialPort != INVALID_HANDLE_VALUE)
|
||||
if (Win32SerialPort_Write(SerialPort, BufferAt->Data))
|
||||
{
|
||||
if (Win32SerialPort_Write(SerialPort, BufferAt->Data))
|
||||
{
|
||||
BuffersSent += 1;
|
||||
}
|
||||
BuffersSent += 1;
|
||||
DataSizeSent += BufferAt->Data.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
Win32SerialArray_Close(BufferAt->ComPort);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugStringA("Skipping data buffer because its COM Port isn't set");
|
||||
}
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -15,32 +15,32 @@ enum key_code
|
|||
KeyCode_CapsLock,
|
||||
KeyCode_LeftShift, KeyCode_RightShift,
|
||||
KeyCode_LeftCtrl, KeyCode_RightCtrl,
|
||||
KeyCode_Fn,
|
||||
KeyCode_Alt,
|
||||
KeyCode_Fn,
|
||||
KeyCode_Alt,
|
||||
KeyCode_PageUp, KeyCode_PageDown,
|
||||
KeyCode_Backspace, KeyCode_Delete,
|
||||
KeyCode_Enter,
|
||||
|
||||
// Function Keys
|
||||
KeyCode_F0, KeyCode_F1, KeyCode_F2, KeyCode_F3, KeyCode_F4, KeyCode_F5, KeyCode_F6, KeyCode_F7,
|
||||
KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12,
|
||||
KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12,
|
||||
|
||||
// Letters
|
||||
KeyCode_a, KeyCode_b, KeyCode_c, KeyCode_d, KeyCode_e, KeyCode_f, KeyCode_g, KeyCode_h,
|
||||
KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p,
|
||||
KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x,
|
||||
KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p,
|
||||
KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x,
|
||||
KeyCode_y, KeyCode_z,
|
||||
|
||||
KeyCode_A, KeyCode_B, KeyCode_C, KeyCode_D, KeyCode_E, KeyCode_F, KeyCode_G, KeyCode_H,
|
||||
KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P,
|
||||
KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X,
|
||||
KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P,
|
||||
KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X,
|
||||
KeyCode_Y, KeyCode_Z,
|
||||
|
||||
// Numbers
|
||||
KeyCode_0, KeyCode_1, KeyCode_2, KeyCode_3, KeyCode_4, KeyCode_5, KeyCode_6, KeyCode_7,
|
||||
KeyCode_8, KeyCode_9,
|
||||
|
||||
KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5,
|
||||
KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5,
|
||||
KeyCode_Num6, KeyCode_Num7, KeyCode_Num8, KeyCode_Num9,
|
||||
|
||||
// Symbols
|
||||
|
@ -48,7 +48,7 @@ enum key_code
|
|||
KeyCode_Ampersand, KeyCode_Star, KeyCode_LeftParen, KeyCode_RightParen, KeyCode_Minus, KeyCode_Plus,
|
||||
KeyCode_Equals, KeyCode_Underscore, KeyCode_LeftBrace, KeyCode_RightBrace, KeyCode_LeftBracket,
|
||||
KeyCode_RightBracket, KeyCode_Colon, KeyCode_SemiColon, KeyCode_SingleQuote, KeyCode_DoubleQuote,
|
||||
KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period,
|
||||
KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period,
|
||||
KeyCode_QuestionMark, KeyCode_LessThan, KeyCode_GreaterThan, KeyCode_Tilde, KeyCode_BackQuote,
|
||||
|
||||
// Arrows
|
||||
|
@ -77,9 +77,9 @@ CharacterFromKeyCode (key_code Code)
|
|||
case KeyCode_Tab: { Result = '\t'; }break;
|
||||
|
||||
// Letters
|
||||
case KeyCode_a: { Result = 'a'; }break;
|
||||
case KeyCode_b: { Result = 'b'; }break;
|
||||
case KeyCode_c: { Result = 'c'; }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;
|
||||
|
@ -92,7 +92,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
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_p: { Result = 'p'; }break;
|
||||
case KeyCode_q: { Result = 'q'; }break;
|
||||
case KeyCode_r: { Result = 'r'; }break;
|
||||
case KeyCode_s: { Result = 's'; }break;
|
||||
|
@ -100,7 +100,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
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_x: { Result = 'x'; }break;
|
||||
case KeyCode_y: { Result = 'y'; }break;
|
||||
case KeyCode_z: { Result = 'z'; }break;
|
||||
|
||||
|
@ -119,7 +119,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
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_P: { Result = 'P'; }break;
|
||||
case KeyCode_Q: { Result = 'Q'; }break;
|
||||
case KeyCode_R: { Result = 'R'; }break;
|
||||
case KeyCode_S: { Result = 'S'; }break;
|
||||
|
@ -127,7 +127,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
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_X: { Result = 'X'; }break;
|
||||
case KeyCode_Y: { Result = 'Y'; }break;
|
||||
case KeyCode_Z: { Result = 'Z'; }break;
|
||||
|
||||
|
@ -148,7 +148,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
case KeyCode_Num2: { Result = '2'; }break;
|
||||
case KeyCode_Num3: { Result = '3'; }break;
|
||||
case KeyCode_Num4: { Result = '4'; }break;
|
||||
case KeyCode_Num5: { Result = '5'; }break;
|
||||
case KeyCode_Num5: { Result = '5'; }break;
|
||||
case KeyCode_Num6: { Result = '6'; }break;
|
||||
case KeyCode_Num7: { Result = '7'; }break;
|
||||
case KeyCode_Num8: { Result = '8'; }break;
|
||||
|
@ -181,7 +181,7 @@ CharacterFromKeyCode (key_code Code)
|
|||
case KeyCode_Backslash: { Result = '\\'; }break;
|
||||
case KeyCode_Pipe: { Result = '|'; }break;
|
||||
case KeyCode_Comma: { Result = ','; }break;
|
||||
case KeyCode_Period: { Result = '.'; }break;
|
||||
case KeyCode_Period: { Result = '.'; }break;
|
||||
case KeyCode_QuestionMark: { Result = '?'; }break;
|
||||
case KeyCode_LessThan: { Result = '<'; }break;
|
||||
case KeyCode_GreaterThan: { Result = '>'; }break;
|
||||
|
@ -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)
|
||||
|
@ -327,7 +346,7 @@ KeyTransitionedUp (input Input, key_code Key)
|
|||
}
|
||||
|
||||
internal void
|
||||
AddInputEventEntry (input_queue* Queue, key_code Key,
|
||||
AddInputEventEntry (input_queue* Queue, key_code Key,
|
||||
b32 WasDown, b32 IsDown, b32 ShiftDown, b32 AltDown, b32 CtrlDown, b32 SysDown)
|
||||
{
|
||||
Assert(Queue->QueueUsed < Queue->QueueSize);
|
||||
|
@ -392,11 +411,259 @@ GetMouseButtonStateAdvanced (b32 ButtonState)
|
|||
!((ButtonState & KeyState_IsDown) > 0))
|
||||
{
|
||||
Result= 0;
|
||||
}
|
||||
else if (ButtonState & KeyState_IsDown)
|
||||
{
|
||||
Result |= KeyState_WasDown;
|
||||
}
|
||||
else if (ButtonState & KeyState_IsDown)
|
||||
{
|
||||
Result |= KeyState_WasDown;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
u64 i = 0;
|
||||
for (; i < String.Length; i++)
|
||||
|
||||
bool StringIsValid = true;
|
||||
for (u32 i = 0; i < String.Length; i++)
|
||||
{
|
||||
u64 CharIndex = FindFirst(CharSet, String.Str[i]);
|
||||
if (CharIndex < CharSet.Length)
|
||||
{
|
||||
Result = CharToUInt(String.Str[i], CharSet) + (Result * Base);
|
||||
}
|
||||
else
|
||||
if (!StringContains(CharSet, String.Str[i]))
|
||||
{
|
||||
StringIsValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ParsedLength != 0)
|
||||
|
||||
if (StringIsValid)
|
||||
{
|
||||
*ParsedLength = i;
|
||||
u64 Acc = 0;
|
||||
u64 i = 0;
|
||||
for (; i < String.Length; i++)
|
||||
{
|
||||
u64 CharIndex = FindFirst(CharSet, String.Str[i]);
|
||||
if (CharIndex < CharSet.Length)
|
||||
{
|
||||
Acc = CharToUInt(String.Str[i], CharSet) + (Acc * Base);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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,39 +1812,75 @@ ParseInt(char* String, u64 Base = 10, u64* ParsedLength = 0)
|
|||
return ParseInt(LitString(String), Base, ParsedLength);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
gs_const_string IntegerString = GetStringBefore(String, DecimalIndex);
|
||||
gs_const_string DecimalString = GetStringAfter(String, DecimalIndex + 1);
|
||||
|
||||
r32 Polarity = 1;
|
||||
if (IntegerString.Str[0] == '-')
|
||||
{
|
||||
IntegerString = GetStringAfter(IntegerString, 1);
|
||||
Polarity = -1;
|
||||
}
|
||||
|
||||
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.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)
|
||||
{
|
||||
|
||||
u64 DecimalIndex = FindFirst(String, '.');
|
||||
u64 TempParsedLength = 0;
|
||||
u64 PlacesAfterPoint = 0;
|
||||
|
||||
gs_const_string IntegerString = GetStringBefore(String, DecimalIndex);
|
||||
gs_const_string DecimalString = GetStringAfter(String, DecimalIndex + 1);
|
||||
|
||||
r32 Polarity = 1;
|
||||
if (IntegerString.Str[0] == '-')
|
||||
{
|
||||
IntegerString = GetStringAfter(IntegerString, 1);
|
||||
Polarity = -1;
|
||||
}
|
||||
r64 Result = (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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -43,7 +43,6 @@ STREAM #1: 3D Overhaul
|
|||
- :ErrorLogging
|
||||
|
||||
- Animation System
|
||||
- blending between animation
|
||||
- layers
|
||||
- layer masks by sculpture
|
||||
- layer masks by tag / value
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue