+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TglBitmapData.FillWithColorFloat(const aRed, aGreen, aBlue: Single; const aAlpha: Single);
+var
+ PixelData: TglBitmapPixelData;
+begin
+ TFormatDescriptor.Get(Format).PreparePixel(PixelData);
+ with PixelData do begin
+ Data.r := Max(0, Min(Range.r, Trunc(Range.r * aRed)));
+ Data.g := Max(0, Min(Range.g, Trunc(Range.g * aGreen)));
+ Data.b := Max(0, Min(Range.b, Trunc(Range.b * aBlue)));
+ Data.a := Max(0, Min(Range.a, Trunc(Range.a * aAlpha)));
+ end;
+ Convert(glBitmapFillWithColorFunc, false, @PixelData);
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TglBitmapData.SetData(const aData: PByte; const aFormat: TglBitmapFormat; const aWidth: Integer; const aHeight: Integer);
+begin
+ if (Data <> aData) then begin
+ if (Assigned(Data)) then
+ FreeMem(Data);
+ fData := aData;
+ end;
+
+ if Assigned(fData) then begin
+ FillChar(fDimension, SizeOf(fDimension), 0);
+ if aWidth <> -1 then begin
+ fDimension.Fields := fDimension.Fields + [ffX];
+ fDimension.X := aWidth;
+ end;
+
+ if aHeight <> -1 then begin
+ fDimension.Fields := fDimension.Fields + [ffY];
+ fDimension.Y := aHeight;
+ end;
+
+ fFormat := aFormat;
+ end else
+ fFormat := tfEmpty;
+
+ UpdateScanlines;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TglBitmapData.Clone: TglBitmapData;
+var
+ Temp: TglBitmapData;
+ TempPtr: PByte;
+ Size: Integer;
+begin
+ result := nil;
+ Temp := (ClassType.Create as TglBitmapData);
+ try
+ // copy texture data if assigned
+ if Assigned(Data) then begin
+ Size := TFormatDescriptor.Get(Format).GetSize(fDimension);
+ GetMem(TempPtr, Size);
+ try
+ Move(Data^, TempPtr^, Size);
+ Temp.SetData(TempPtr, Format, Width, Height);
+ except
+ if Assigned(TempPtr) then
+ FreeMem(TempPtr);
+ raise;
+ end;
+ end else begin
+ TempPtr := nil;
+ Temp.SetData(TempPtr, Format, Width, Height);
+ end;
+
+ // copy properties
+ Temp.fFormat := Format;
+ result := Temp;
+ except
+ FreeAndNil(Temp);
+ raise;
+ end;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TglBitmapData.Invert(const aRed, aGreen, aBlue, aAlpha: Boolean);
+var
+ mask: PtrInt;
+begin
+ mask :=
+ (Byte(aRed) and 1) or
+ ((Byte(aGreen) and 1) shl 1) or
+ ((Byte(aBlue) and 1) shl 2) or
+ ((Byte(aAlpha) and 1) shl 3);
+ if (mask > 0) then
+ Convert(glBitmapInvertFunc, false, {%H-}Pointer(mask));
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+type
+ TMatrixItem = record
+ X, Y: Integer;
+ W: Single;
+ end;
+
+ PglBitmapToNormalMapRec = ^TglBitmapToNormalMapRec;
+ TglBitmapToNormalMapRec = Record
+ Scale: Single;
+ Heights: array of Single;
+ MatrixU : array of TMatrixItem;
+ MatrixV : array of TMatrixItem;
+ end;
+
+const
+ ONE_OVER_255 = 1 / 255;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure glBitmapToNormalMapPrepareFunc(var FuncRec: TglBitmapFunctionRec);
+var
+ Val: Single;
+begin
+ with FuncRec do begin
+ Val :=
+ Source.Data.r * LUMINANCE_WEIGHT_R +
+ Source.Data.g * LUMINANCE_WEIGHT_G +
+ Source.Data.b * LUMINANCE_WEIGHT_B;
+ PglBitmapToNormalMapRec(Args)^.Heights[Position.Y * Size.X + Position.X] := Val * ONE_OVER_255;
+ end;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure glBitmapToNormalMapPrepareAlphaFunc(var FuncRec: TglBitmapFunctionRec);
+begin
+ with FuncRec do
+ PglBitmapToNormalMapRec(Args)^.Heights[Position.Y * Size.X + Position.X] := Source.Data.a * ONE_OVER_255;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure glBitmapToNormalMapFunc (var FuncRec: TglBitmapFunctionRec);
+type
+ TVec = Array[0..2] of Single;
+var
+ Idx: Integer;
+ du, dv: Double;
+ Len: Single;
+ Vec: TVec;
+
+ function GetHeight(X, Y: Integer): Single;
+ begin
+ with FuncRec do begin
+ X := Max(0, Min(Size.X -1, X));
+ Y := Max(0, Min(Size.Y -1, Y));
+ result := PglBitmapToNormalMapRec(Args)^.Heights[Y * Size.X + X];
+ end;
+ end;
+
+begin
+ with FuncRec do begin
+ with PglBitmapToNormalMapRec(Args)^ do begin
+ du := 0;
+ for Idx := Low(MatrixU) to High(MatrixU) do
+ du := du + GetHeight(Position.X + MatrixU[Idx].X, Position.Y + MatrixU[Idx].Y) * MatrixU[Idx].W;
+
+ dv := 0;
+ for Idx := Low(MatrixU) to High(MatrixU) do
+ dv := dv + GetHeight(Position.X + MatrixV[Idx].X, Position.Y + MatrixV[Idx].Y) * MatrixV[Idx].W;
+
+ Vec[0] := -du * Scale;
+ Vec[1] := -dv * Scale;
+ Vec[2] := 1;
+ end;
+
+ // Normalize
+ Len := 1 / Sqrt(Sqr(Vec[0]) + Sqr(Vec[1]) + Sqr(Vec[2]));
+ if Len <> 0 then begin
+ Vec[0] := Vec[0] * Len;
+ Vec[1] := Vec[1] * Len;
+ Vec[2] := Vec[2] * Len;
+ end;
+
+ // Farbe zuweisem
+ Dest.Data.r := Trunc((Vec[0] + 1) * 127.5);
+ Dest.Data.g := Trunc((Vec[1] + 1) * 127.5);
+ Dest.Data.b := Trunc((Vec[2] + 1) * 127.5);
+ end;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TglBitmapData.GenerateNormalMap(const aFunc: TglBitmapNormalMapFunc; const aScale: Single; const aUseAlpha: Boolean);
+var
+ Rec: TglBitmapToNormalMapRec;
+
+ procedure SetEntry (var Matrix: array of TMatrixItem; Index, X, Y: Integer; W: Single);
+ begin
+ if (Index >= Low(Matrix)) and (Index <= High(Matrix)) then begin
+ Matrix[Index].X := X;
+ Matrix[Index].Y := Y;
+ Matrix[Index].W := W;
+ end;
+ end;
+
+begin
+ if TFormatDescriptor.Get(Format).IsCompressed then
+ raise EglBitmapUnsupportedFormat.Create(Format);
+
+ if aScale > 100 then
+ Rec.Scale := 100
+ else if aScale < -100 then
+ Rec.Scale := -100
+ else
+ Rec.Scale := aScale;
+
+ SetLength(Rec.Heights, Width * Height);
+ try
+ case aFunc of
+ nm4Samples: begin
+ SetLength(Rec.MatrixU, 2);
+ SetEntry(Rec.MatrixU, 0, -1, 0, -0.5);
+ SetEntry(Rec.MatrixU, 1, 1, 0, 0.5);
+
+ SetLength(Rec.MatrixV, 2);
+ SetEntry(Rec.MatrixV, 0, 0, 1, 0.5);
+ SetEntry(Rec.MatrixV, 1, 0, -1, -0.5);
+ end;
+
+ nmSobel: begin
+ SetLength(Rec.MatrixU, 6);
+ SetEntry(Rec.MatrixU, 0, -1, 1, -1.0);
+ SetEntry(Rec.MatrixU, 1, -1, 0, -2.0);
+ SetEntry(Rec.MatrixU, 2, -1, -1, -1.0);
+ SetEntry(Rec.MatrixU, 3, 1, 1, 1.0);
+ SetEntry(Rec.MatrixU, 4, 1, 0, 2.0);
+ SetEntry(Rec.MatrixU, 5, 1, -1, 1.0);
+
+ SetLength(Rec.MatrixV, 6);
+ SetEntry(Rec.MatrixV, 0, -1, 1, 1.0);
+ SetEntry(Rec.MatrixV, 1, 0, 1, 2.0);
+ SetEntry(Rec.MatrixV, 2, 1, 1, 1.0);
+ SetEntry(Rec.MatrixV, 3, -1, -1, -1.0);
+ SetEntry(Rec.MatrixV, 4, 0, -1, -2.0);
+ SetEntry(Rec.MatrixV, 5, 1, -1, -1.0);
+ end;
+
+ nm3x3: begin
+ SetLength(Rec.MatrixU, 6);
+ SetEntry(Rec.MatrixU, 0, -1, 1, -1/6);
+ SetEntry(Rec.MatrixU, 1, -1, 0, -1/6);
+ SetEntry(Rec.MatrixU, 2, -1, -1, -1/6);
+ SetEntry(Rec.MatrixU, 3, 1, 1, 1/6);
+ SetEntry(Rec.MatrixU, 4, 1, 0, 1/6);
+ SetEntry(Rec.MatrixU, 5, 1, -1, 1/6);
+
+ SetLength(Rec.MatrixV, 6);
+ SetEntry(Rec.MatrixV, 0, -1, 1, 1/6);
+ SetEntry(Rec.MatrixV, 1, 0, 1, 1/6);
+ SetEntry(Rec.MatrixV, 2, 1, 1, 1/6);
+ SetEntry(Rec.MatrixV, 3, -1, -1, -1/6);
+ SetEntry(Rec.MatrixV, 4, 0, -1, -1/6);
+ SetEntry(Rec.MatrixV, 5, 1, -1, -1/6);
+ end;
+
+ nm5x5: begin
+ SetLength(Rec.MatrixU, 20);
+ SetEntry(Rec.MatrixU, 0, -2, 2, -1 / 16);
+ SetEntry(Rec.MatrixU, 1, -1, 2, -1 / 10);
+ SetEntry(Rec.MatrixU, 2, 1, 2, 1 / 10);
+ SetEntry(Rec.MatrixU, 3, 2, 2, 1 / 16);
+ SetEntry(Rec.MatrixU, 4, -2, 1, -1 / 10);
+ SetEntry(Rec.MatrixU, 5, -1, 1, -1 / 8);
+ SetEntry(Rec.MatrixU, 6, 1, 1, 1 / 8);
+ SetEntry(Rec.MatrixU, 7, 2, 1, 1 / 10);
+ SetEntry(Rec.MatrixU, 8, -2, 0, -1 / 2.8);
+ SetEntry(Rec.MatrixU, 9, -1, 0, -0.5);
+ SetEntry(Rec.MatrixU, 10, 1, 0, 0.5);
+ SetEntry(Rec.MatrixU, 11, 2, 0, 1 / 2.8);
+ SetEntry(Rec.MatrixU, 12, -2, -1, -1 / 10);
+ SetEntry(Rec.MatrixU, 13, -1, -1, -1 / 8);
+ SetEntry(Rec.MatrixU, 14, 1, -1, 1 / 8);
+ SetEntry(Rec.MatrixU, 15, 2, -1, 1 / 10);
+ SetEntry(Rec.MatrixU, 16, -2, -2, -1 / 16);
+ SetEntry(Rec.MatrixU, 17, -1, -2, -1 / 10);
+ SetEntry(Rec.MatrixU, 18, 1, -2, 1 / 10);
+ SetEntry(Rec.MatrixU, 19, 2, -2, 1 / 16);
+
+ SetLength(Rec.MatrixV, 20);
+ SetEntry(Rec.MatrixV, 0, -2, 2, 1 / 16);
+ SetEntry(Rec.MatrixV, 1, -1, 2, 1 / 10);
+ SetEntry(Rec.MatrixV, 2, 0, 2, 0.25);
+ SetEntry(Rec.MatrixV, 3, 1, 2, 1 / 10);
+ SetEntry(Rec.MatrixV, 4, 2, 2, 1 / 16);
+ SetEntry(Rec.MatrixV, 5, -2, 1, 1 / 10);
+ SetEntry(Rec.MatrixV, 6, -1, 1, 1 / 8);
+ SetEntry(Rec.MatrixV, 7, 0, 1, 0.5);
+ SetEntry(Rec.MatrixV, 8, 1, 1, 1 / 8);
+ SetEntry(Rec.MatrixV, 9, 2, 1, 1 / 16);
+ SetEntry(Rec.MatrixV, 10, -2, -1, -1 / 16);
+ SetEntry(Rec.MatrixV, 11, -1, -1, -1 / 8);
+ SetEntry(Rec.MatrixV, 12, 0, -1, -0.5);
+ SetEntry(Rec.MatrixV, 13, 1, -1, -1 / 8);
+ SetEntry(Rec.MatrixV, 14, 2, -1, -1 / 10);
+ SetEntry(Rec.MatrixV, 15, -2, -2, -1 / 16);
+ SetEntry(Rec.MatrixV, 16, -1, -2, -1 / 10);
+ SetEntry(Rec.MatrixV, 17, 0, -2, -0.25);
+ SetEntry(Rec.MatrixV, 18, 1, -2, -1 / 10);
+ SetEntry(Rec.MatrixV, 19, 2, -2, -1 / 16);
+ end;
+ end;
+
+ // Daten Sammeln
+ if aUseAlpha and TFormatDescriptor.Get(Format).HasAlpha then
+ Convert(glBitmapToNormalMapPrepareAlphaFunc, false, @Rec)
+ else
+ Convert(glBitmapToNormalMapPrepareFunc, false, @Rec);
+ Convert(glBitmapToNormalMapFunc, false, @Rec);
+ finally
+ SetLength(Rec.Heights, 0);
+ end;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+constructor TglBitmapData.Create;
+begin
+ inherited Create;
+ fFormat := glBitmapDefaultFormat;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+constructor TglBitmapData.Create(const aFileName: String);
+begin
+ Create;
+ LoadFromFile(aFileName);
+end;