Did an audit of the transient arena's usage, cleaned up the assembly parsing to control allocations, removed stb_truetype (again?) and fixed the memory problems the node system was having.
This commit is contained in:
parent
808453b867
commit
40d9e0b83e
|
@ -77,7 +77,7 @@ ParseAssemblyVector (char* String)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ParseAssemblyFileHeader (tokenizer* Tokenizer, assembly_definition* Definition)
|
ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer)
|
||||||
{
|
{
|
||||||
if (CharArraysEqualUpToLength(Tokenizer->At, LED_STRIP_COUNT_IDENTIFIER, CharArrayLength(LED_STRIP_COUNT_IDENTIFIER)))
|
if (CharArraysEqualUpToLength(Tokenizer->At, LED_STRIP_COUNT_IDENTIFIER, CharArrayLength(LED_STRIP_COUNT_IDENTIFIER)))
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ ParseAssemblyFileHeader (tokenizer* Tokenizer, assembly_definition* Definition)
|
||||||
assembly_token CountToken = ParseToken(Tokenizer);
|
assembly_token CountToken = ParseToken(Tokenizer);
|
||||||
if (CountToken.Type == AssemblyToken_Number)
|
if (CountToken.Type == AssemblyToken_Number)
|
||||||
{
|
{
|
||||||
Definition->LEDStripSize = ParseSignedIntUnsafe(CountToken.Token).SignedIntValue;
|
Assembly->LEDStripSize = ParseSignedIntUnsafe(CountToken.Token).SignedIntValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -103,9 +103,11 @@ ParseAssemblyFileHeader (tokenizer* Tokenizer, assembly_definition* Definition)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ParseLEDStrip (tokenizer* Tokenizer, assembly_definition* Assembly)
|
ParseLEDStrip (assembly_definition* Assembly, tokenizer* Tokenizer)
|
||||||
{
|
{
|
||||||
led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount;
|
led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount;
|
||||||
|
Assert(Assembly->LEDStripCount < Assembly->LEDStripSize);
|
||||||
|
|
||||||
Assembly->LEDStripCount++;
|
Assembly->LEDStripCount++;
|
||||||
|
|
||||||
// Control Box Index
|
// Control Box Index
|
||||||
|
@ -163,24 +165,15 @@ ParseLEDStrip (tokenizer* Tokenizer, assembly_definition* Assembly)
|
||||||
EatWhitespace(Tokenizer);
|
EatWhitespace(Tokenizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal assembly_definition
|
internal void
|
||||||
ParseAssemblyFile (char* File, memory_arena* Storage)
|
ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer)
|
||||||
{
|
{
|
||||||
assembly_definition Result = {};
|
EatWhitespace(Tokenizer);
|
||||||
|
|
||||||
tokenizer Tokenizer = {};
|
while(*Tokenizer->At)
|
||||||
Tokenizer.At = File;
|
|
||||||
|
|
||||||
ParseAssemblyFileHeader(&Tokenizer, &Result);
|
|
||||||
|
|
||||||
Result.LEDStrips = PushArray(Storage, led_strip_definition,
|
|
||||||
Result.LEDStripSize);
|
|
||||||
EatWhitespace(&Tokenizer);
|
|
||||||
|
|
||||||
while(*Tokenizer.At)
|
|
||||||
{
|
{
|
||||||
EatWhitespace(&Tokenizer);
|
EatWhitespace(Tokenizer);
|
||||||
assembly_token Token = ParseToken(&Tokenizer);
|
assembly_token Token = ParseToken(Tokenizer);
|
||||||
|
|
||||||
if (Token.Type != AssemblyToken_EndOfFile)
|
if (Token.Type != AssemblyToken_EndOfFile)
|
||||||
{
|
{
|
||||||
|
@ -188,13 +181,12 @@ ParseAssemblyFile (char* File, memory_arena* Storage)
|
||||||
{
|
{
|
||||||
case AssemblyToken_LEDStrip:
|
case AssemblyToken_LEDStrip:
|
||||||
{
|
{
|
||||||
ParseLEDStrip(&Tokenizer, &Result);
|
ParseLEDStrip(Assembly, Tokenizer);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
// TODO(Peter): Other cases? What else would need to be in the assembly body?
|
||||||
{
|
|
||||||
InvalidCodePath;
|
InvalidDefaultCase;
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -202,5 +194,9 @@ ParseAssemblyFile (char* File, memory_arena* Storage)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result;
|
|
||||||
|
// NOTE(Peter): Ensure the validity of the assembly file. We probably don't want an assert here,
|
||||||
|
// more likely we want to load a valid assembly anyways, and just raise this as an error to the user
|
||||||
|
// so they can fix it.
|
||||||
|
Assert(Assembly->LEDStripCount == Assembly->LEDStripSize);
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,12 +283,24 @@ SendSACNBufferData (s32 ThreadID, void* JobData)
|
||||||
internal void
|
internal void
|
||||||
LoadAssembly (app_state* State, context Context, char* Path)
|
LoadAssembly (app_state* State, context Context, char* Path)
|
||||||
{
|
{
|
||||||
|
assembly_definition AssemblyDefinition = {};
|
||||||
|
|
||||||
|
arena_snapshot TempMemorySnapshot = TakeSnapshotOfArena(*State->Transient);
|
||||||
|
|
||||||
platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path);
|
platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path);
|
||||||
if (TestAssemblyFile.Size <= 0)
|
Assert(TestAssemblyFile.Size > 0);
|
||||||
{
|
{
|
||||||
InvalidCodePath;
|
tokenizer AssemblyFileTokenizer = {};
|
||||||
|
AssemblyFileTokenizer.At = (char*)TestAssemblyFile.Base;
|
||||||
|
AssemblyFileTokenizer.Memory = (char*)TestAssemblyFile.Base;
|
||||||
|
AssemblyFileTokenizer.MemoryLength = TestAssemblyFile.Size;
|
||||||
|
|
||||||
|
ParseAssemblyFileHeader(&AssemblyDefinition, &AssemblyFileTokenizer);
|
||||||
|
|
||||||
|
AssemblyDefinition.LEDStrips = PushArray(State->Transient, led_strip_definition, AssemblyDefinition.LEDStripSize);
|
||||||
|
|
||||||
|
ParseAssemblyFileBody(&AssemblyDefinition, &AssemblyFileTokenizer);
|
||||||
}
|
}
|
||||||
assembly_definition AssemblyDefinition = ParseAssemblyFile((char*)TestAssemblyFile.Base, State->Transient);
|
|
||||||
Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size);
|
Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size);
|
||||||
|
|
||||||
string PathString = MakeStringLiteral(Path);
|
string PathString = MakeStringLiteral(Path);
|
||||||
|
@ -297,6 +309,8 @@ LoadAssembly (app_state* State, context Context, char* Path)
|
||||||
|
|
||||||
r32 Scale = 100;
|
r32 Scale = 100;
|
||||||
ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, v3{0, 0, 0}, Scale, Context, State);
|
ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, v3{0, 0, 0}, Scale, Context, State);
|
||||||
|
|
||||||
|
ClearArenaToSnapshot(State->Transient, TempMemorySnapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -517,7 +531,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
||||||
State->NodeRenderSettings.PortColors[MemberType_v4] = BlueV4;
|
State->NodeRenderSettings.PortColors[MemberType_v4] = BlueV4;
|
||||||
State->NodeRenderSettings.Font = State->Font;
|
State->NodeRenderSettings.Font = State->Font;
|
||||||
|
|
||||||
State->OutputNode = PushOutputNodeOnList(State->NodeList, v2{500, 250}, State->Transient);
|
State->OutputNode = PushOutputNodeOnList(State->NodeList, v2{500, 250}, State->Permanent);
|
||||||
|
|
||||||
ReloadStaticData(Context, GlobalDebugServices);
|
ReloadStaticData(Context, GlobalDebugServices);
|
||||||
}
|
}
|
||||||
|
@ -526,6 +540,12 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
{
|
{
|
||||||
app_state* State = (app_state*)Context.MemoryBase;
|
app_state* State = (app_state*)Context.MemoryBase;
|
||||||
|
|
||||||
|
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient,
|
||||||
|
// and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't
|
||||||
|
// zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically
|
||||||
|
// incorrect to clear the arena, and then access the memory later.
|
||||||
|
ClearArena(State->Transient);
|
||||||
|
|
||||||
ExecuteAllRegisteredCommands(&State->InputCommandRegistry, Input, State);
|
ExecuteAllRegisteredCommands(&State->InputCommandRegistry, Input, State);
|
||||||
|
|
||||||
UpdateOutputNodeCalculations(State->OutputNode, State->NodeList, State->Transient,
|
UpdateOutputNodeCalculations(State->OutputNode, State->NodeList, State->Transient,
|
||||||
|
@ -533,13 +553,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
State->LEDBufferList->Colors,
|
State->LEDBufferList->Colors,
|
||||||
State->LEDBufferList->Count);
|
State->LEDBufferList->Count);
|
||||||
|
|
||||||
/*
|
ClearTransientNodeColorBuffers(State->NodeList);
|
||||||
patterns_update_list Temp_PatternsNeedUpdate = UpdateAllChannels(&State->ChannelSystem,
|
|
||||||
Context.DeltaTime,
|
|
||||||
State->Transient);
|
|
||||||
|
|
||||||
UpdateAllPatterns(&Temp_PatternsNeedUpdate, &State->PatternSystem, State->LEDBufferList, Context.DeltaTime, State->Transient);
|
|
||||||
*/
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// NOTE(Peter): We know that these two lists should be maintained together. Each element in the list is one sculpture's worth of
|
// NOTE(Peter): We know that these two lists should be maintained together. Each element in the list is one sculpture's worth of
|
||||||
|
@ -907,7 +921,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
Context.DeltaTime, State->Camera, Input, State->Transient);
|
Context.DeltaTime, State->Camera, Input, State->Transient);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearArena(State->Transient);
|
|
||||||
EndDebugFrame(GlobalDebugServices);
|
EndDebugFrame(GlobalDebugServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,6 @@ struct assembly
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "assembly_parser.h"
|
#include "assembly_parser.h"
|
||||||
//#include "foldhaus_environment.h"
|
|
||||||
|
|
||||||
// TODO(Peter): remove this, and get pattern_system.h outta here!!
|
// TODO(Peter): remove this, and get pattern_system.h outta here!!
|
||||||
typedef struct led_pattern led_pattern;
|
typedef struct led_pattern led_pattern;
|
||||||
|
|
|
@ -187,6 +187,12 @@ AllocateNonGrowableArenaWithSpace(platform_alloc* PlatformAlloc, s32 SizeNeeded)
|
||||||
static void
|
static void
|
||||||
ClearMemoryRegion (memory_region* Region)
|
ClearMemoryRegion (memory_region* Region)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
// NOTE(Peter): Turn this on occasionally. This is a big time sink but it forces us into
|
||||||
|
// correct memory usage since there's no error reporting for accessing memory the arena thinks
|
||||||
|
// is unused. At least now, it'll be zero's.
|
||||||
|
GSMemSet(Region->Base, 0, Region->Size);
|
||||||
|
#endif
|
||||||
Region->Used = 0;
|
Region->Used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ PushOutputNodeOnList (node_list* List, v2 Min, memory_arena* Storage)
|
||||||
OutputNodeName.Length,
|
OutputNodeName.Length,
|
||||||
1,
|
1,
|
||||||
Min,
|
Min,
|
||||||
v2{125, 150},
|
DEFAULT_NODE_DIMENSION,
|
||||||
Storage);
|
Storage);
|
||||||
Node->Type = NodeType_OutputNode;
|
Node->Type = NodeType_OutputNode;
|
||||||
CopyStringTo(OutputNodeName, &Node->Name);
|
CopyStringTo(OutputNodeName, &Node->Name);
|
||||||
|
@ -841,45 +841,44 @@ UpdateNodeCalculation (interface_node* Node, node_list* NodeList, memory_arena*
|
||||||
|
|
||||||
for (s32 ConnectionIdx = 0; ConnectionIdx < Node->ConnectionsCount; ConnectionIdx++)
|
for (s32 ConnectionIdx = 0; ConnectionIdx < Node->ConnectionsCount; ConnectionIdx++)
|
||||||
{
|
{
|
||||||
node_connection* Connection = 0;
|
node_connection Connection = Node->Connections[ConnectionIdx];
|
||||||
|
|
||||||
// TODO(Peter): We're currently passing in a pointer to the leds array for every single
|
// TODO(Peter): We're currently passing in a pointer to the leds array for every single
|
||||||
// NODE_COLOR_BUFFER. We shouldn't do that, and just require each data structure that
|
// NODE_COLOR_BUFFER. We shouldn't do that, and just require each data structure that
|
||||||
// needs the leds to request that as its own member/parameter.
|
// needs the leds to request that as its own member/parameter.
|
||||||
if (ConnectionIsInput(Node->Connections[ConnectionIdx]) ||
|
if (Connection.Type == MemberType_NODE_COLOR_BUFFER)
|
||||||
Connection->Type == MemberType_NODE_COLOR_BUFFER)
|
|
||||||
{
|
{
|
||||||
Connection = Node->Connections + ConnectionIdx;
|
node_led_color_connection* ColorConnection = (node_led_color_connection*)(NodeData + MemberList[ConnectionIdx].Offset);
|
||||||
switch (Connection->Type)
|
|
||||||
|
ColorConnection->LEDs = LEDs;
|
||||||
|
ColorConnection->LEDCount = LEDCount;
|
||||||
|
ColorConnection->Colors = Connection.LEDsValue.Colors;
|
||||||
|
|
||||||
|
if (!ColorConnection->Colors)
|
||||||
|
{
|
||||||
|
sacn_pixel* ColorsCopy = PushArray(Transient, sacn_pixel, LEDCount);
|
||||||
|
GSMemSet((u8*)ColorsCopy, 0, sizeof(sacn_pixel) * LEDCount);
|
||||||
|
ColorConnection->Colors = ColorsCopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ConnectionIsInput(Connection))
|
||||||
|
{
|
||||||
|
Assert(Connection.Type != MemberType_NODE_COLOR_BUFFER);
|
||||||
|
switch (Connection.Type)
|
||||||
{
|
{
|
||||||
case MemberType_s32:
|
case MemberType_s32:
|
||||||
{
|
{
|
||||||
GSMemCopy(&Connection->S32Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(s32));
|
GSMemCopy(&Connection.S32Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(s32));
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case MemberType_r32:
|
case MemberType_r32:
|
||||||
{
|
{
|
||||||
GSMemCopy(&Connection->R32Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(r32));
|
GSMemCopy(&Connection.R32Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(r32));
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case MemberType_v4:
|
case MemberType_v4:
|
||||||
{
|
{
|
||||||
GSMemCopy(&Connection->V4Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(v4));
|
GSMemCopy(&Connection.V4Value, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(v4));
|
||||||
}break;
|
|
||||||
|
|
||||||
case MemberType_NODE_COLOR_BUFFER:
|
|
||||||
{
|
|
||||||
Connection->LEDsValue.LEDs = LEDs;
|
|
||||||
Connection->LEDsValue.LEDCount = LEDCount;
|
|
||||||
|
|
||||||
if (Connection->LEDsValue.Colors == 0)
|
|
||||||
{
|
|
||||||
sacn_pixel* ColorsCopy = PushArray(Transient, sacn_pixel, LEDCount);
|
|
||||||
GSMemCopy(ColorsInit, ColorsCopy, sizeof(sacn_pixel) * LEDCount);
|
|
||||||
Connection->LEDsValue.Colors = ColorsCopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
GSMemCopy(&Connection->LEDsValue, (NodeData + MemberList[ConnectionIdx].Offset), sizeof(node_led_color_connection));
|
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
|
@ -921,6 +920,7 @@ UpdateNodeCalculation (interface_node* Node, node_list* NodeList, memory_arena*
|
||||||
case MemberType_NODE_COLOR_BUFFER:
|
case MemberType_NODE_COLOR_BUFFER:
|
||||||
{
|
{
|
||||||
node_led_color_connection* Value = (node_led_color_connection*)(NodeData + MemberList[ConnectionIdx].Offset);
|
node_led_color_connection* Value = (node_led_color_connection*)(NodeData + MemberList[ConnectionIdx].Offset);
|
||||||
|
Connection->LEDsValue.Colors = Value->Colors;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
|
@ -937,7 +937,12 @@ UpdateOutputNodeCalculations (interface_node* OutputNode, node_list* NodeList, m
|
||||||
node_connection ColorsConnection = OutputNode->Connections[0];
|
node_connection ColorsConnection = OutputNode->Connections[0];
|
||||||
if (ColorsConnection.LEDsValue.Colors)
|
if (ColorsConnection.LEDsValue.Colors)
|
||||||
{
|
{
|
||||||
GSMemCopy(ColorsConnection.LEDsValue.Colors, Colors, sizeof(sacn_pixel) * LEDCount);
|
sacn_pixel* DestPixel = Colors;
|
||||||
|
sacn_pixel* SourcePixel = ColorsConnection.LEDsValue.Colors;
|
||||||
|
for (s32 i = 0; i < LEDCount; i++)
|
||||||
|
{
|
||||||
|
*DestPixel++ = *SourcePixel++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,6 +961,25 @@ UpdateAllNodeCalculations (node_list* NodeList, memory_arena* Transient, led* LE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ClearTransientNodeColorBuffers (node_list* NodeList)
|
||||||
|
{
|
||||||
|
node_list_iterator NodeIter = GetNodeListIterator(*NodeList);
|
||||||
|
while (NodeIteratorIsValid(NodeIter))
|
||||||
|
{
|
||||||
|
interface_node* Node = NodeIter.At;
|
||||||
|
for (s32 ConnectionIdx = 0; ConnectionIdx < Node->ConnectionsCount; ConnectionIdx++)
|
||||||
|
{
|
||||||
|
node_connection* Connection = Node->Connections + ConnectionIdx;
|
||||||
|
if (Connection->Type == MemberType_NODE_COLOR_BUFFER)
|
||||||
|
{
|
||||||
|
Connection->LEDsValue.Colors = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Next(&NodeIter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
DrawValueDisplay (render_command_buffer* RenderBuffer, rect Bounds, node_connection Value, bitmap_font* Font)
|
DrawValueDisplay (render_command_buffer* RenderBuffer, rect Bounds, node_connection Value, bitmap_font* Font)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,8 @@ typedef enum node_type node_type;
|
||||||
#define IsInputMember 1 << 0
|
#define IsInputMember 1 << 0
|
||||||
#define IsOutputMember 1 << 1
|
#define IsOutputMember 1 << 1
|
||||||
|
|
||||||
|
#define DEFAULT_NODE_DIMENSION v2{125, 150}
|
||||||
|
|
||||||
#define NODE_COLOR_BUFFER \
|
#define NODE_COLOR_BUFFER \
|
||||||
led* LEDs; \
|
led* LEDs; \
|
||||||
sacn_pixel* Colors; \
|
sacn_pixel* Colors; \
|
||||||
|
|
4853
stb/stb_truetype.h
4853
stb/stb_truetype.h
File diff suppressed because it is too large
Load Diff
|
@ -47,9 +47,22 @@ NODE_PROC(MultiplyPatterns, multiply_patterns_data)
|
||||||
{
|
{
|
||||||
Assert(LED->Index >= 0 && LED->Index < Data->ResultLEDCount);
|
Assert(LED->Index >= 0 && LED->Index < Data->ResultLEDCount);
|
||||||
|
|
||||||
Data->ResultColors[LED->Index].R = (Data->AColors[LED->Index].R + Data->BColors[LED->Index].R) / 2;
|
r32 AR = (r32)Data->AColors[LED->Index].R / 255.f;
|
||||||
Data->ResultColors[LED->Index].G = (Data->AColors[LED->Index].G + Data->BColors[LED->Index].G) / 2;
|
r32 AG = (r32)Data->AColors[LED->Index].G / 255.f;
|
||||||
Data->ResultColors[LED->Index].B = (Data->AColors[LED->Index].B + Data->BColors[LED->Index].B) / 2;
|
r32 AB = (r32)Data->AColors[LED->Index].B / 255.f;
|
||||||
|
|
||||||
|
r32 BR = (r32)Data->BColors[LED->Index].R / 255.f;
|
||||||
|
r32 BG = (r32)Data->BColors[LED->Index].G / 255.f;
|
||||||
|
r32 BB = (r32)Data->BColors[LED->Index].B / 255.f;
|
||||||
|
|
||||||
|
r32 RCombined = AR * BR;
|
||||||
|
r32 GCombined = AG * BG;
|
||||||
|
r32 BCombined = AB * BB;
|
||||||
|
|
||||||
|
Data->ResultColors[LED->Index].R = (u8)(GSClamp01(RCombined) * 255);
|
||||||
|
Data->ResultColors[LED->Index].G = (u8)(GSClamp01(GCombined) * 255);
|
||||||
|
Data->ResultColors[LED->Index].B = (u8)(GSClamp01(BCombined) * 255);
|
||||||
|
|
||||||
LED++;
|
LED++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue