diff options
author | Fox Caminiti <fox@foxcam.net> | 2022-12-16 20:16:43 -0500 |
---|---|---|
committer | Fox Caminiti <fox@foxcam.net> | 2022-12-16 20:16:43 -0500 |
commit | bedd6906eabdd513042d6a178d4dc56a3a41d1d3 (patch) | |
tree | 2bcbd3e46ae61e583707a2ccc5b3f5cfeacb61a8 /src/effects_software.cpp | |
parent | cdb9e1f7240cb0716b7d99df5e1fd7c3fc3407a8 (diff) |
v3, file/build organization
Diffstat (limited to 'src/effects_software.cpp')
-rw-r--r-- | src/effects_software.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/effects_software.cpp b/src/effects_software.cpp new file mode 100644 index 0000000..2fde6b9 --- /dev/null +++ b/src/effects_software.cpp @@ -0,0 +1,209 @@ + +static void +Effect_Software_DrawColor(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, v4 Color, blend_mode BlendMode) +{ + render_byte_info Bits = Bitmap_ByteInfo(BytesPerPixel); + rectangle RenderRegion = {0, 0, Width, Height}; + transform_info T; + T.BlendMode = BlendMode; + for (int32 Y = RenderRegion.Min.y; Y < RenderRegion.Max.y; Y++) { + for (int32 X = RenderRegion.Min.x; X < RenderRegion.Max.x; X++) { + uint32 Offset = Y*Width*BytesPerPixel + X*BytesPerPixel; + uint8 *LayerPixel = (uint8 *)EffectBitmapAddress + Offset; + + uint32 *R_DestAddress = (uint32 *)(LayerPixel + Bits.ByteOffset * 0); + uint32 *G_DestAddress = (uint32 *)(LayerPixel + Bits.ByteOffset * 1); + uint32 *B_DestAddress = (uint32 *)(LayerPixel + Bits.ByteOffset * 2); + uint32 *A_DestAddress = (uint32 *)(LayerPixel + Bits.ByteOffset * 3); + + real32 R_Dest = (real32)(*R_DestAddress & Bits.MaskPixel) * Bits.Normalized; + real32 G_Dest = (real32)(*G_DestAddress & Bits.MaskPixel) * Bits.Normalized; + real32 B_Dest = (real32)(*B_DestAddress & Bits.MaskPixel) * Bits.Normalized; + real32 A_Dest = (real32)(*A_DestAddress & Bits.MaskPixel) * Bits.Normalized; + + real32 R_Col = Color.r; + real32 G_Col = Color.g; + real32 B_Col = Color.b; + real32 A_Col = Color.a; + + real32 LayerAlpha = A_Col * 1; + + real32 R_Blend = R_Col; + real32 G_Blend = G_Col; + real32 B_Blend = B_Col; + real32 A_Blend = A_Col; + + Fallback_Blend(); + + uint32 R_Out = (uint32)(Normalize(R_Blend) * Bits.Bits); + uint32 G_Out = (uint32)(Normalize(G_Blend) * Bits.Bits); + uint32 B_Out = (uint32)(Normalize(B_Blend) * Bits.Bits); + uint32 A_Out = (uint32)(Normalize(A_Blend) * Bits.Bits); + + *R_DestAddress = (*R_DestAddress & ~Bits.MaskPixel) | R_Out; + *G_DestAddress = (*G_DestAddress & ~Bits.MaskPixel) | G_Out; + *B_DestAddress = (*B_DestAddress & ~Bits.MaskPixel) | B_Out; + *A_DestAddress = (*A_DestAddress & ~Bits.MaskPixel) | A_Out; + } + } +} +static void +CurvesSolver(real32 *LUT, v2 Point_P1, v2 Point_P2, v2 m1, v2 m2, int i) +{ + + real32 Precision = ((real32)1 / 256) * 0.1; + real32 Point_Span = Point_P2.x - Point_P1.x; + v2 Cache[256]; + + if (i == 0) { + // Don't know how to fix this, so I'm just gonna linear interpolate + // until I try quadratic solving. + real32 Count_Start = (Point_P1.x * 256); + real32 Count_End = (Point_P2.x * 256); + real32 Count_Total = Count_End - Count_Start; + real32 Width = Point_P2.x - Point_P1.x; + real32 Height = Point_P2.y - Point_P1.y; + real32 Count = Count_Start; + real32 t = 1; + while (Count < Count_End) { + LUT[(uint32)Count] = Normalize(Point_P1.y + (Height*((Count-Count_Start)/(Count_End - (Count_End - 256)))/Width)); + Count++; + } + } else { + real32 Count_Start = (Point_P1.x * 256); + real32 Count_End = (Point_P2.x * 256); + real32 Count_Total = Count_End - Count_Start; + real32 Count = Count_Start; + real32 t = 0; + int Timeout = 0; + + // This solver actually works kinda decently when the graph isn't that + // complex, taking less than 10 iterations per LUT value. It fails + // towards the edges and with harsh curves, going into the hundreds. The + // 1000 condition should only be hit when the solver is locked, which can + // happen when two points are close together on X. + + while (Count < Count_End) { + + real32 c = 2*t*t*t - 3*t*t; + real32 c0 = c + 1; + real32 c1 = t*t*t - 2*t*t + t; + real32 c2 = -c; + real32 c3 = t*t*t - t*t; + + v2 Point = (c0 * Point_P1) + (c1 * m1) + (c2 * Point_P2) + (c3 * m2); + + real32 TargetX = Count / 256; + + if (Timeout == 1000) { + Point.x = TargetX; + printf("Solve between %.1f and %.1f reached 1000 iterations at %.f!\n", Count_Start, Count_End, Count); + } + + // Only record the value if it's within a certain precision. + + if (Point.x <= TargetX - Precision || + Point.x >= TargetX + Precision) { + t = t * TargetX / Point.x; + Timeout++; + } else { + if (Point.y > 1.0f) { + LUT[(uint32)Count] = 1.0f; + } else if (Point.y < 0.0f) + LUT[(uint32)Count] = 0.0f; + else { + LUT[(uint32)Count] = Point.y; + } + t += (Point_Span / Count_Total); + Count++; + Timeout = 0; + } + } + } +} + +static void +Effect_Software_Curves(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, v2 *PointData, real32 PointCount, v4 PointCount_Col) +{ + real32 LUT[5][256] = {}; + + for (int a = 0; a < 5; a++) { + + int Num = (a == 0) ? (int)PointCount : (int)PointCount_Col.E[a-1]; + v2 *CurvePoint = PointData + (MAX_PROPERTIES_PER_EFFECT / 5 * a); + + for (int i = 0; i < Num; i++) { + v2 Point_P1 = CurvePoint[i]; + v2 Point_P2 = CurvePoint[i + 1]; + v2 Point_P0 = (i != 0) ? CurvePoint[i - 1] : V2(0, 0); + v2 Point_P3 = (i != (Num - 2)) ? CurvePoint[i + 2] : V2(1, 1); + + v2 m1 = (Point_P2 - Point_P0) / (2 * Tau); + v2 m2 = (Point_P3 - Point_P1) / (2 * Tau); + + CurvesSolver(LUT[a], Point_P1, Point_P2, m1, m2, i); + } + + if (CurvePoint[0].x > 0.0f) { + real32 Count_Start = 0; + real32 Count_End = (CurvePoint[0].x * 255); + real32 Count = Count_Start; + while (Count < Count_End) { + LUT[a][(uint32)Count] = LUT[a][(uint32)Count_End]; + Count++; + } + } + + if (CurvePoint[Num-1].x < 1.0f) { + real32 Count_Start = (CurvePoint[Num-1].x * 255) - 0.5; + real32 Count_End = 255; + real32 Count = Count_Start; + while (Count < Count_End) { + LUT[a][(uint32)Count] = LUT[a][(uint32)Count_Start]; + Count++; + } + } + + for (int i = 0; i < Num; i++) { + if (CurvePoint[i].y == 1.0f) + LUT[a][255] = 1.0f; + } + } + + + uint64 Size = Width*Height; + int i = 0; + Assert(BytesPerPixel == 4); + while (i < Size) { + uint32 *Pixel = (uint32 *)EffectBitmapAddress + i; + + uint8 A = (*Pixel >> 24); + uint8 B = (*Pixel >> 16); + uint8 G = (*Pixel >> 8); + uint8 R = (*Pixel >> 0); + +#if 1 + real32 R_Lookup = LUT[1][R]; + real32 G_Lookup = LUT[2][G]; + real32 B_Lookup = LUT[3][B]; + real32 A_Lookup = LUT[4][A]; + + real32 R_Lookup_All = LUT[0][(uint32)(R_Lookup*255)]; + real32 G_Lookup_All = LUT[0][(uint32)(G_Lookup*255)]; + real32 B_Lookup_All = LUT[0][(uint32)(B_Lookup*255)]; +#else + real32 R_Lookup_All = LUT[0][(uint32)(t.r)]; + real32 G_Lookup_All = LUT[0][(uint32)(t.g)]; + real32 B_Lookup_All = LUT[0][(uint32)(t.b)]; +#endif + + + uint32 Result = (((uint32)((A_Lookup * 255.0f) + 0.5) << 24) | + ((uint32)((B_Lookup_All * 255.0f) + 0.5) << 16) | + ((uint32)((G_Lookup_All * 255.0f) + 0.5) << 8) | + ((uint32)((R_Lookup_All * 255.0f) + 0.5) << 0)); + + *Pixel = Result; + i++; + } +} |