source: trunk/Packages/bgrabitmap/bgragradients.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 43.9 KB
Line 
1unit BGRAGradients;
2
3{$mode objfpc}{$H+}
4{$i bgrabitmap.inc}
5{$i bgrasse.inc}
6
7interface
8
9{ Here are various functions that draw gradients, shadow and lighting }
10
11uses
12 Classes, BGRAGraphics, BGRABitmapTypes, BGRABitmap, BGRABlend, BGRAPhongTypes, BGRASSE;
13
14{$IFDEF BGRABITMAP_USE_LCL}{ Creates a bitmap with the specified text horizontally centered and with a shadow }
15function TextShadow(AWidth,AHeight: Integer; AText: String; AFontHeight: Integer; ATextColor,AShadowColor: TBGRAPixel;
16 AOffSetX,AOffSetY: Integer; ARadius: Integer = 0; AFontStyle: TFontStyles = []; AFontName: String = 'Default'; AShowText: Boolean = True): TBGRABitmap;
17{$ENDIF}
18
19{----------------------------------------------------------------------}
20{ Functions to draw multiple gradients.
21 See : http://wiki.lazarus.freepascal.org/Double_Gradient#nGradient }
22type
23 TnGradientInfo = record
24 StartColor,StopColor: TBGRAPixel;
25 Direction: TGradientDirection;
26 EndPercent : single; // Position from 0 to 1
27 end;
28
29function nGradientInfo(StartColor, StopColor: TBGRAPixel; Direction: TGradientDirection; EndPercent: Single): TnGradientInfo;
30
31function nGradientAlphaFill(ARect: TRect; ADir: TGradientDirection; const AGradient: array of TnGradientInfo): TBGRABitmap; overload;
32function nGradientAlphaFill(AWidth, AHeight: Integer; ADir: TGradientDirection; const AGradient: array of TnGradientInfo): TBGRABitmap; overload;
33procedure nGradientAlphaFill(ACanvas: TCanvas; ARect: TRect; ADir: TGradientDirection; const AGradient: array of TnGradientInfo); overload;
34procedure nGradientAlphaFill(ABitmap: TBGRABitmap; ARect: TRect; ADir: TGradientDirection; const AGradient: array of TnGradientInfo); overload;
35
36function DoubleGradientAlphaFill(ARect: TRect; AStart1,AStop1,AStart2,AStop2: TBGRAPixel;
37 ADirection1,ADirection2,ADir: TGradientDirection; AValue: Single): TBGRABitmap; overload;
38function DoubleGradientAlphaFill(AWidth,AHeight: Integer; AStart1,AStop1,AStart2,AStop2: TBGRAPixel;
39 ADirection1,ADirection2,ADir: TGradientDirection; AValue: Single): TBGRABitmap; overload;
40procedure DoubleGradientAlphaFill(ACanvas: TCanvas; ARect: TRect; AStart1,AStop1,AStart2,AStop2: TBGRAPixel;
41 ADirection1,ADirection2,ADir: TGradientDirection; AValue: Single); overload;
42procedure DoubleGradientAlphaFill(ABitmap: TBGRABitmap; ARect: TRect; AStart1,AStop1,AStart2,AStop2: TBGRAPixel;
43 ADirection1,ADirection2,ADir: TGradientDirection; AValue: Single); overload;
44
45{----------------------------------------------------------------------}
46{ Phong shading functions. Use a height map (grayscale image or a precise map filled with MapHeightToBGRA)
47 to determine orientation and position of the surface.
48
49 Phong shading consist in adding an ambiant light, a diffuse light (angle between light and object),
50 and a specular light (angle between light, object and observer, i.e. reflected light) }
51
52type
53 TRectangleMapOption = (rmoNoLeftBorder,rmoNoTopBorder,rmoNoRightBorder,rmoNoBottomBorder,rmoLinearBorder);
54 TRectangleMapOptions = set of TRectangleMapOption;
55
56 { TPhongShading }
57
58 TPhongShading = class(TCustomPhongShading)
59 LightSourceIntensity : Single; //global intensity of the light
60
61 LightSourceDistanceTerm, //minimum distance always added (positive value)
62 LightSourceDistanceFactor, //how much actual distance is taken into account (usually 0 or 1)
63 LightDestFactor : Single; //how much the location of the lightened pixel is taken into account (usually 0 or 1)
64
65 LightPositionZ : Integer;
66 LightColor: TBGRAPixel; //color of the light reflection
67
68 SpecularFactor, //how much light is reflected (0..1)
69 SpecularIndex : Single; //how concentrated reflected light is (positive value)
70
71 AmbientFactor, //ambiant lighting whereever the point is (0..1)
72 DiffusionFactor, //diffusion, i.e. how much pixels are lightened by light source (0..1)
73 NegativeDiffusionFactor : Single; //how much hidden surface are darkened (0..1)
74 DiffuseSaturation: Boolean; //when diffusion saturates, use light color to show it
75
76 constructor Create;
77
78 { Render the specified map on the destination bitmap with one solid color. Map altitude
79 indicate the global height of the map. }
80 procedure Draw(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
81 Color : TBGRAPixel); override;
82
83 { Render with a color map of the same size as the height map. Map altitude
84 indicate the global height of the map. }
85 procedure Draw(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
86 ColorMap : TBGRACustomBitmap); override;
87
88 { Render with a color scanner. Map altitude
89 indicate the global height of the map. }
90 procedure DrawScan(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
91 ColorScan : IBGRAScanner); override;
92
93 { Draw a cone of the specified color }
94 procedure DrawCone(dest: TBGRACustomBitmap; X,Y,Size,Altitude: Integer; Color: TBGRAPixel); overload;
95 procedure DrawCone(dest: TBGRACustomBitmap; bounds: TRect; Altitude: Integer; Color: TBGRAPixel); overload;
96
97 { Draw a vertical cone of the specified color }
98 procedure DrawVerticalCone(dest: TBGRACustomBitmap; bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
99
100 { Draw an horizontal cylinder of the specified color }
101 procedure DrawHorizontalCylinder(dest: TBGRACustomBitmap; bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
102
103 { Draw a vertical cylinder of the specified color }
104 procedure DrawVerticalCylinder(dest: TBGRACustomBitmap; bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
105
106 { Draw a hemisphere of the specified color }
107 procedure DrawSphere(dest: TBGRACustomBitmap; bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
108
109 { Draw a rectangle of the specified color }
110 procedure DrawRectangle(dest: TBGRACustomBitmap; bounds: TRect; Border,Altitude: Integer; Color: TBGRAPixel; RoundCorners: Boolean; Options: TRectangleMapOptions);
111 protected
112
113 procedure DrawMapNormal(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
114 ColorMap : TBGRACustomBitmap);
115 procedure DrawScannerNormal(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
116 ColorScan : IBGRAScanner);
117 procedure DrawColorNormal(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
118 Color : TBGRAPixel);
119
120 {$ifdef BGRASSE_AVAILABLE}
121 procedure DrawMapSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
122 ColorMap : TBGRACustomBitmap);
123 procedure DrawScannerSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
124 ColorScan : IBGRAScanner);
125 procedure DrawColorSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
126 Color : TBGRAPixel);
127 {$endif}
128
129 end;
130
131{ Create a grayscale height map for a cone (may not be precise enough) }
132function CreateConeMap(size: integer): TBGRABitmap;
133
134{ Create a precise height map for a cone (not grayscale anymore but more precise) }
135function CreateConePreciseMap(width,height: integer): TBGRABitmap;
136
137{ Create a precise height map for a vertical cone (not grayscale anymore but more precise) }
138function CreateVerticalConePreciseMap(width,height: integer): TBGRABitmap;
139
140{ Create a precise height map for a vertical cylinder (not grayscale anymore but more precise) }
141function CreateVerticalCylinderPreciseMap(width,height: integer): TBGRABitmap;
142
143{ Create a precise height map for an horizontal cylinder (not grayscale anymore but more precise) }
144function CreateHorizontalCylinderPreciseMap(width,height: integer): TBGRABitmap;
145
146{ Create a grayscale height map for a sphere (may not be precise enough) }
147function CreateSphereMap(width,height: integer): TBGRABitmap;
148
149{ Create a precise height map for a sphere (not grayscale anymore but more precise) }
150function CreateSpherePreciseMap(width,height: integer): TBGRABitmap;
151
152{ Create a rectangle height map with a border }
153function CreateRectangleMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
154
155{ Create a precise height map for a rectangle height map with a border (not grayscale anymore but more precise) }
156function CreateRectanglePreciseMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
157function CreateRectanglePreciseMap(width, height, borderWidth, borderHeight: integer; options: TRectangleMapOptions): TBGRABitmap;
158
159{ Create a round rectangle height map with a border }
160function CreateRoundRectangleMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
161
162{ Create a precise height map for a round rectangle height map with a border (not grayscale anymore but more precise) }
163function CreateRoundRectanglePreciseMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
164function CreateRoundRectanglePreciseMap(width,height,borderWidth,borderHeight: integer; options: TRectangleMapOptions = []): TBGRABitmap;
165
166{---------- Perlin Noise -------------}
167{ Random image using a superposition of interpolated random values.
168 See : http://wiki.lazarus.freepascal.org/Perlin_Noise
169 http://freespace.virgin.net/hugo.elias/models/m_perlin.htm }
170
171{ Creates a non-tilable random grayscale image }
172function CreatePerlinNoiseMap(AWidth, AHeight: integer; HorizontalPeriod: Single = 1;
173 VerticalPeriod: Single = 1; Exponent: Double = 1; ResampleFilter: TResampleFilter = rfCosine): TBGRABitmap;
174
175{ Creates a tilable random grayscale image }
176function CreateCyclicPerlinNoiseMap(AWidth, AHeight: integer; HorizontalPeriod: Single = 1;
177 VerticalPeriod: Single = 1; Exponent: Double = 1; ResampleFilter: TResampleFilter = rfCosine): TBGRABitmap;
178
179implementation
180
181uses Types, Math, SysUtils{$IFDEF BGRABITMAP_USE_LCL}, BGRATextFX{$ENDIF}; {GraphType unit used by phongdraw.inc}
182
183{$IFDEF BGRABITMAP_USE_LCL}function TextShadow(AWidth, AHeight: Integer; AText: String;
184 AFontHeight: Integer; ATextColor, AShadowColor: TBGRAPixel; AOffSetX,
185 AOffSetY: Integer; ARadius: Integer; AFontStyle: TFontStyles;
186 AFontName: String; AShowText: Boolean): TBGRABitmap;
187begin
188 result := BGRATextFX.TextShadow(AWidth,AHeight,AText,AFontHeight,ATextColor,AShadowColor,AOffsetX,AOffsetY,ARadius,AFontStyle,AFontName,AShowText) as TBGRABitmap;
189end;{$ENDIF}
190
191function nGradientInfo(StartColor, StopColor: TBGRAPixel;
192 Direction: TGradientDirection; EndPercent: Single): TnGradientInfo;
193begin
194 result.StartColor := StartColor;
195 result.StopColor := StopColor;
196 result.Direction := Direction;
197 result.EndPercent := EndPercent;
198end;
199
200function DoubleGradientAlphaFill(ARect: TRect; AStart1,AStop1,AStart2,AStop2: TBGRAPixel;
201 ADirection1,ADirection2,ADir: TGradientDirection; AValue: Single): TBGRABitmap;
202var
203 ABitmap: TBGRABitmap;
204 ARect1,ARect2: TRect;
205 APoint1,APoint2,APoint3,APoint4: TPointF;
206begin
207 Dec(ARect.Right, ARect.Left);
208 ARect.Left := 0;
209 Dec(ARect.Bottom,ARect.Top);
210 ARect.Top := 0;
211
212 ABitmap := TBGRABitmap.Create(ARect.Right,ARect.Bottom);
213
214 if AValue <> 0 then ARect1:=ARect;
215 if AValue <> 1 then ARect2:=ARect;
216
217 if ADir = gdVertical then begin
218 ARect1.Bottom:=Round(ARect1.Bottom * AValue);
219 ARect2.Top:=ARect1.Bottom;
220 end
221 else if ADir = gdHorizontal then begin
222 ARect1.Right:=Round(ARect1.Right * AValue);
223 ARect2.Left:=ARect1.Right;
224 end;
225 if ADirection1 = gdVertical then begin
226 APoint1:=PointF(ARect1.Left,ARect1.Top);
227 APoint2:=PointF(ARect1.Left,ARect1.Bottom);
228 end
229 else if ADirection1 = gdHorizontal then begin
230 APoint1:=PointF(ARect1.Left,ARect1.Top);
231 APoint2:=PointF(ARect1.Right,ARect1.Top);
232 end;
233 if ADirection2 = gdVertical then begin
234 APoint3:=PointF(ARect2.Left,ARect2.Top);
235 APoint4:=PointF(ARect2.Left,ARect2.Bottom);
236 end
237 else if ADirection2 = gdHorizontal then begin
238 APoint3:=PointF(ARect2.Left,ARect2.Top);
239 APoint4:=PointF(ARect2.Right,ARect2.Top);
240 end;
241
242 if AValue <> 0 then
243 ABitmap.GradientFill(ARect1.Left,ARect1.Top,ARect1.Right,ARect1.Bottom,
244 AStart1,AStop1,gtLinear,APoint1,APoint2,dmSet,True);
245 if AValue <> 1 then
246 ABitmap.GradientFill( ARect2.Left,ARect2.Top,ARect2.Right,ARect2.Bottom,
247 AStart2,AStop2,gtLinear,APoint3,APoint4,dmSet,True);
248
249 Result:=ABitmap;
250end;
251
252function DoubleGradientAlphaFill(AWidth, AHeight: Integer; AStart1, AStop1,
253 AStart2, AStop2: TBGRAPixel; ADirection1, ADirection2,
254 ADir: TGradientDirection; AValue: Single): TBGRABitmap;
255begin
256 result := DoubleGradientAlphaFill(Rect(0,0,AWidth,AHeight),
257 AStart1,AStop1,AStart2,AStop2,
258 ADirection1,ADirection2, ADir, AValue);
259end;
260
261procedure DoubleGradientAlphaFill(ACanvas: TCanvas; ARect: TRect; AStart1,
262 AStop1, AStart2, AStop2: TBGRAPixel; ADirection1, ADirection2,
263 ADir: TGradientDirection; AValue: Single);
264var
265 bmp: TBGRABitmap;
266begin
267 bmp := DoubleGradientAlphaFill(ARect,AStart1,AStop1,AStart2,AStop2,ADirection1,ADirection2,ADir,AValue);
268 bmp.Draw(ACanvas,ARect.Left,ARect.Top,not bmp.HasTransparentPixels);
269 bmp.Free;
270end;
271
272procedure DoubleGradientAlphaFill(ABitmap: TBGRABitmap; ARect: TRect; AStart1,
273 AStop1, AStart2, AStop2: TBGRAPixel; ADirection1, ADirection2,
274 ADir: TGradientDirection; AValue: Single);
275var
276 bmp: TBGRABitmap;
277begin
278 bmp := DoubleGradientAlphaFill(ARect,AStart1,AStop1,AStart2,AStop2,ADirection1,ADirection2,ADir,AValue);
279 ABitmap.PutImage(ARect.Left,ARect.Top,bmp,dmDrawWithTransparency);
280 bmp.Free;
281end;
282
283function nGradientAlphaFill(ARect: TRect; ADir: TGradientDirection;
284 const AGradient: array of TnGradientInfo): TBGRABitmap;
285var
286 i:integer;
287 AnRect, OldRect: TRect;
288 Point1, Point2: TPointF;
289begin
290 Result := TBGRABitmap.Create(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top);
291 Dec(ARect.Right, ARect.Left);
292 ARect.Left := 0;
293 Dec(ARect.Bottom,ARect.Top);
294 ARect.Top := 0;
295
296 OldRect := ARect;
297
298 if ADir = gdVertical then
299 OldRect.Bottom := ARect.Top
300 else
301 OldRect.Right := ARect.Left;
302
303 for i := 0 to high(AGradient) do
304 begin
305 AnRect:=OldRect;
306 if ADir = gdVertical then
307 begin
308 AnRect.Bottom:=Round((ARect.Bottom-ARect.Top) * AGradient[i].endPercent + ARect.Top);
309 AnRect.Top:=OldRect.Bottom;
310 Point1:=PointF(AnRect.Left,AnRect.Top);
311 Point2:=PointF(AnRect.Left,AnRect.Bottom);
312 end
313 else
314 begin
315 AnRect.Right:=Round((ARect.Right-ARect.Left) * AGradient[i].endPercent + ARect.Left);
316 AnRect.Left:=OldRect.Right;
317 Point1:=PointF(AnRect.Left,AnRect.Top);
318 Point2:=PointF(AnRect.Right,AnRect.Top);
319 end;
320 Result.GradientFill(AnRect.Left,AnRect.Top,AnRect.Right,AnRect.Bottom,
321 AGradient[i].StartColor,AGradient[i].StopColor,gtLinear,Point1,Point2,dmSet,True);
322 OldRect := AnRect;
323 end;
324end;
325
326function nGradientAlphaFill(AWidth, AHeight: Integer; ADir: TGradientDirection;
327 const AGradient: array of TnGradientInfo): TBGRABitmap;
328begin
329 result := nGradientAlphaFill(Rect(0,0,AWidth,AHeight),ADir,AGradient);
330end;
331
332procedure nGradientAlphaFill(ACanvas: TCanvas; ARect: TRect;
333 ADir: TGradientDirection; const AGradient: array of TnGradientInfo);
334var
335 bmp: TBGRABitmap;
336begin
337 bmp := nGradientAlphaFill(ARect, ADir, AGradient);
338 bmp.Draw(ACanvas,ARect.Left,ARect.Top,not bmp.HasTransparentPixels);
339 bmp.Free;
340end;
341
342procedure nGradientAlphaFill(ABitmap: TBGRABitmap; ARect: TRect;
343 ADir: TGradientDirection; const AGradient: array of TnGradientInfo);
344var
345 bmp: TBGRABitmap;
346begin
347 bmp := nGradientAlphaFill(ARect, ADir, AGradient);
348 ABitmap.PutImage(ARect.Left,ARect.Top,bmp,dmDrawWithTransparency);
349 bmp.Free;
350end;
351
352{ TPhongShading }
353
354constructor TPhongShading.Create;
355begin
356 //set default values
357 LightSourceIntensity := 500;
358 LightSourceDistanceTerm := 150;
359 LightSourceDistanceFactor := 1;
360 LightDestFactor := 1;
361 LightColor := BGRAWhite;
362 AmbientFactor := 0.3;
363 DiffusionFactor := 0.9;
364 DiffuseSaturation:= False;
365 NegativeDiffusionFactor := 0.1;
366 SpecularFactor := 0.6;
367 SpecularIndex := 10;
368 LightPosition := Point(-100,-100);
369 LightPositionZ := 100;
370end;
371
372Const
373 PhongLightPrecisionSh = 12;
374 PhongLightPrecision = 1 shl PhongLightPrecisionSh;
375 PhongLightPrecisionDiv2 = PhongLightPrecision shr 1;
376
377{------------------ Phong drawing ----------------}
378{ Look for the fastest method available }
379procedure TPhongShading.Draw(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer;
380 Color : TBGRAPixel);
381begin
382 {$ifdef BGRASSE_AVAILABLE}
383 if UseSSE then
384 DrawColorSSE(dest,map,mapAltitude,ofsX,ofsY,Color)
385 else
386 {$endif}
387 DrawColorNormal(dest,map,mapAltitude,ofsX,ofsY,Color);
388end;
389
390procedure TPhongShading.Draw(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
391 mapAltitude: integer; ofsX, ofsY: integer; ColorMap: TBGRACustomBitmap);
392begin
393 {$ifdef BGRASSE_AVAILABLE}
394 if UseSSE then
395 DrawMapSSE(dest,map,mapAltitude,ofsX,ofsY,ColorMap)
396 else
397 {$endif}
398 DrawMapNormal(dest,map,mapAltitude,ofsX,ofsY,ColorMap);
399end;
400
401procedure TPhongShading.DrawScan(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
402 mapAltitude: integer; ofsX, ofsY: integer; ColorScan: IBGRAScanner);
403begin
404 {$ifdef BGRASSE_AVAILABLE}
405 if UseSSE then
406 DrawScannerSSE(dest,map,mapAltitude,ofsX,ofsY,ColorScan)
407 else
408 {$endif}
409 DrawScannerNormal(dest,map,mapAltitude,ofsX,ofsY,ColorScan);
410end;
411
412 {------------------ End of phong drawing ----------------}
413
414procedure TPhongShading.DrawCone(dest: TBGRACustomBitmap; X, Y, Size,
415 Altitude: Integer; Color: TBGRAPixel);
416var map: TBGRABitmap;
417begin
418 map := CreateConePreciseMap(Size,Size);
419 Draw(dest,map,Altitude,X,Y,Color);
420 map.Free;
421end;
422
423procedure TPhongShading.DrawCone(dest: TBGRACustomBitmap; bounds: TRect;
424 Altitude: Integer; Color: TBGRAPixel);
425var map: TBGRABitmap;
426 temp: integer;
427begin
428 if Bounds.Right < Bounds.Left then
429 begin
430 temp := Bounds.Left;
431 bounds.Left := bounds.Right;
432 Bounds.Right := temp;
433 end;
434 if Bounds.Bottom < Bounds.Top then
435 begin
436 temp := Bounds.Bottom;
437 bounds.Bottom := bounds.Top;
438 Bounds.Top := temp;
439 end;
440 map := CreateConePreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top);
441 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
442 map.Free;
443end;
444
445procedure TPhongShading.DrawVerticalCone(dest: TBGRACustomBitmap;
446 bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
447var map: TBGRABitmap;
448 temp: integer;
449begin
450 if Bounds.Right < Bounds.Left then
451 begin
452 temp := Bounds.Left;
453 bounds.Left := bounds.Right;
454 Bounds.Right := temp;
455 end;
456 if Bounds.Bottom < Bounds.Top then
457 begin
458 temp := Bounds.Bottom;
459 bounds.Bottom := bounds.Top;
460 Bounds.Top := temp;
461 end;
462 map := CreateVerticalConePreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top);
463 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
464 map.Free;
465end;
466
467procedure TPhongShading.DrawHorizontalCylinder(dest: TBGRACustomBitmap;
468 bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
469var map: TBGRABitmap;
470 temp: integer;
471begin
472 if Bounds.Right < Bounds.Left then
473 begin
474 temp := Bounds.Left;
475 bounds.Left := bounds.Right;
476 Bounds.Right := temp;
477 end;
478 if Bounds.Bottom < Bounds.Top then
479 begin
480 temp := Bounds.Bottom;
481 bounds.Bottom := bounds.Top;
482 Bounds.Top := temp;
483 end;
484 map := CreateHorizontalCylinderPreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top);
485 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
486 map.Free;
487end;
488
489procedure TPhongShading.DrawVerticalCylinder(dest: TBGRACustomBitmap;
490 bounds: TRect; Altitude: Integer; Color: TBGRAPixel);
491var map: TBGRABitmap;
492 temp: integer;
493begin
494 if Bounds.Right < Bounds.Left then
495 begin
496 temp := Bounds.Left;
497 bounds.Left := bounds.Right;
498 Bounds.Right := temp;
499 end;
500 if Bounds.Bottom < Bounds.Top then
501 begin
502 temp := Bounds.Bottom;
503 bounds.Bottom := bounds.Top;
504 Bounds.Top := temp;
505 end;
506 map := CreateVerticalCylinderPreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top);
507 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
508 map.Free;
509end;
510
511procedure TPhongShading.DrawSphere(dest: TBGRACustomBitmap; bounds: TRect;
512 Altitude: Integer; Color: TBGRAPixel);
513var map: TBGRABitmap;
514 temp: integer;
515begin
516 if Bounds.Right < Bounds.Left then
517 begin
518 temp := Bounds.Left;
519 bounds.Left := bounds.Right;
520 Bounds.Right := temp;
521 end;
522 if Bounds.Bottom < Bounds.Top then
523 begin
524 temp := Bounds.Bottom;
525 bounds.Bottom := bounds.Top;
526 Bounds.Top := temp;
527 end;
528 map := CreateSpherePreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top);
529 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
530 map.Free;
531end;
532
533procedure TPhongShading.DrawRectangle(dest: TBGRACustomBitmap; bounds: TRect;
534 Border,Altitude: Integer; Color: TBGRAPixel; RoundCorners: Boolean; Options: TRectangleMapOptions);
535var map: TBGRABitmap;
536 temp: integer;
537begin
538 if Bounds.Right < Bounds.Left then
539 begin
540 temp := Bounds.Left;
541 bounds.Left := bounds.Right;
542 Bounds.Right := temp;
543 end;
544 if Bounds.Bottom < Bounds.Top then
545 begin
546 temp := Bounds.Bottom;
547 bounds.Bottom := bounds.Top;
548 Bounds.Top := temp;
549 end;
550 if border > 10 then
551 begin
552 if RoundCorners then
553 map := CreateRoundRectanglePreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top,Border,Options)
554 else
555 map := CreateRectanglePreciseMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top,Border,Options);
556 end else
557 begin
558 if RoundCorners then
559 map := CreateRoundRectangleMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top,Border,Options)
560 else
561 map := CreateRectangleMap(Bounds.Right-Bounds.Left,Bounds.Bottom-Bounds.Top,Border,Options);
562 end;
563 Draw(dest,map,Altitude,bounds.Left,bounds.Top,Color);
564 map.Free;
565end;
566
567procedure TPhongShading.DrawMapNormal(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
568 mapAltitude: integer; ofsX, ofsY: integer; ColorMap: TBGRACustomBitmap);
569 {$I phongdraw.inc }
570
571procedure TPhongShading.DrawColorNormal(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
572 mapAltitude: integer; ofsX, ofsY: integer; Color: TBGRAPixel);
573 {$define PARAM_SIMPLECOLOR}
574 {$I phongdraw.inc }
575
576procedure TPhongShading.DrawScannerNormal(dest: TBGRACustomBitmap;
577 map: TBGRACustomBitmap; mapAltitude: integer; ofsX, ofsY: integer;
578 ColorScan: IBGRAScanner);
579 {$define PARAM_SCANNER}
580 {$I phongdraw.inc }
581
582{$ifdef BGRASSE_AVAILABLE}
583procedure TPhongShading.DrawMapSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
584 mapAltitude: integer; ofsX, ofsY: integer; ColorMap: TBGRACustomBitmap);
585 {$define PARAM_PHONGSSE}
586 {$I phongdraw.inc }
587
588procedure TPhongShading.DrawColorSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap;
589 mapAltitude: integer; ofsX, ofsY: integer; Color: TBGRAPixel);
590 {$define PARAM_PHONGSSE}
591 {$define PARAM_SIMPLECOLOR}
592 {$I phongdraw.inc }
593
594procedure TPhongShading.DrawScannerSSE(dest: TBGRACustomBitmap;
595 map: TBGRACustomBitmap; mapAltitude: integer; ofsX, ofsY: integer;
596 ColorScan: IBGRAScanner);
597 {$define PARAM_PHONGSSE}
598 {$define PARAM_SCANNER}
599 {$I phongdraw.inc }
600
601{$endif}
602
603{************************ maps ***********************************}
604
605function CreateConeMap(size: integer): TBGRABitmap;
606var cx,cy,r: single;
607 mask: TBGRABitmap;
608begin
609 cx := (size-1)/2;
610 cy := (size-1)/2;
611 r := (size-1)/2;
612 result := TBGRABitmap.Create(size,size);
613 result.GradientFill(0,0,size,size,BGRAWhite,BGRABlack,gtRadial,PointF(cx,cy),PointF(cx+r,cy),dmSet,False);
614
615 mask := TBGRABitmap.Create(size,size,BGRABlack);
616 mask.FillEllipseAntialias(cx,cy,r,r,BGRAWhite);
617 result.ApplyMask(mask);
618 mask.Free;
619end;
620
621function CreateConePreciseMap(width,height: integer): TBGRABitmap;
622var cx,cy,rx,ry,d: single;
623 xb,yb: integer;
624 p: PBGRAPixel;
625 mask: TBGRABitmap;
626begin
627 result := TBGRABitmap.Create(width,height);
628 cx := (width-1)/2;
629 cy := (height-1)/2;
630 rx := (width-1)/2;
631 ry := (height-1)/2;
632 for yb := 0 to height-1 do
633 begin
634 p := result.scanline[yb];
635 for xb := 0 to width-1 do
636 begin
637 d := sqr((xb-cx)/(rx+1))+sqr((yb-cy)/(ry+1));
638 if d >= 1 then
639 p^ := BGRAPixelTransparent else
640 p^ := MapHeightToBGRA(1-sqrt(d),255);
641 inc(p);
642 end;
643 end;
644 //antialiased border
645 mask := TBGRABitmap.Create(width,height,BGRABlack);
646 mask.FillEllipseAntialias(cx,cy,rx,ry,BGRAWhite);
647 result.ApplyMask(mask);
648 mask.Free;
649end;
650
651function CreateVerticalConePreciseMap(width, height: integer): TBGRABitmap;
652var cx,rx,d,vpos: single;
653 xb,yb: integer;
654 p: PBGRAPixel;
655 mask: TBGRABitmap;
656begin
657 result := TBGRABitmap.Create(width,height);
658 if (height=0) or (width=0) then exit;
659 cx := (width-1)/2;
660 for yb := 0 to height-1 do
661 begin
662 p := result.scanline[yb];
663 vpos := (yb+1)/height;
664 rx := width/2*vpos;
665 for xb := 0 to width-1 do
666 begin
667 d := sqr((xb-cx)/(rx+1));
668 if d >= 1 then
669 p^ := BGRAPixelTransparent else
670 p^ := MapHeightToBGRA(sqrt(1-d)*vpos,255);
671 inc(p);
672 end;
673 end;
674 //antialiased border
675 mask := TBGRABitmap.Create(width,height,BGRABlack);
676 mask.FillPolyAntialias([PointF(width/2,-0.5),PointF(0,height-0.5),PointF(width-0.5,height-0.5)],BGRAWhite);
677 result.ApplyMask(mask);
678 mask.Free;
679end;
680
681function CreateVerticalCylinderPreciseMap(width, height: integer): TBGRABitmap;
682var cx,rx,d: single;
683 xb: integer;
684begin
685 result := TBGRABitmap.Create(width,height);
686 if (height=0) or (width=0) then exit;
687 rx := width/2;
688 cx := (width-1)/2;
689 for xb := 0 to width-1 do
690 begin
691 d := sqr((xb-cx)/(rx+1));
692 result.SetVertLine(xb,0,height-1,MapHeightToBGRA(sqrt(1-d),255));
693 end;
694end;
695
696function CreateHorizontalCylinderPreciseMap(width, height: integer
697 ): TBGRABitmap;
698var cy,ry,d: single;
699 xb,yb: integer;
700 p: PBGRAPixel;
701 c: TBGRAPixel;
702begin
703 result := TBGRABitmap.Create(width,height);
704 if (height=0) or (width=0) then exit;
705 ry := height/2;
706 cy := (height-1)/2;
707 for yb := 0 to height-1 do
708 begin
709 p := result.scanline[yb];
710 d := sqr((yb-cy)/(ry+1));
711 c := MapHeightToBGRA(sqrt(1-d),255);
712 for xb := 0 to width-1 do
713 begin
714 p^ := c;
715 inc(p);
716 end;
717 end;
718end;
719
720function CreateSphereMap(width,height: integer): TBGRABitmap;
721var cx,cy,rx,ry,d: single;
722 xb,yb: integer;
723 p: PBGRAPixel;
724 h: integer;
725 mask: TBGRABitmap;
726begin
727 result := TBGRABitmap.Create(width,height);
728 cx := (width-1)/2;
729 cy := (height-1)/2;
730 rx := (width-1)/2;
731 ry := (height-1)/2;
732 for yb := 0 to height-1 do
733 begin
734 p := result.scanline[yb];
735 for xb := 0 to width-1 do
736 begin
737 d := sqr((xb-cx)/(rx+1))+sqr((yb-cy)/(ry+1));
738 if d >= 1 then
739 p^ := BGRAPixelTransparent else
740 begin
741 h := round(sqrt(1-d)*255);
742 p^.red := h;
743 p^.green := h;
744 p^.blue := h;
745 p^.alpha := 255;
746 end;
747 inc(p);
748 end;
749 end;
750 //antialiased border
751 mask := TBGRABitmap.Create(width,height,BGRABlack);
752 mask.FillEllipseAntialias(cx,cy,rx,ry,BGRAWhite);
753 result.ApplyMask(mask);
754 mask.Free;
755end;
756
757procedure MapBorderLimit(width,height: integer; options: TRectangleMapOptions; var border: integer);
758var maxHoriz,maxVert: integer;
759begin
760 if [rmoNoLeftBorder,rmoNoRightBorder] <= options then maxHoriz := border else
761 if [rmoNoLeftBorder,rmoNoRightBorder] * options = [] then maxHoriz := width div 2 else
762 maxHoriz := width;
763 if border > maxHoriz then border := maxHoriz;
764
765 if [rmoNoTopBorder,rmoNoBottomBorder] <= options then maxVert := border else
766 if [rmoNoTopBorder,rmoNoBottomBorder] * options = [] then maxVert := height div 2 else
767 maxVert := height;
768 if border > maxVert then border := maxVert;
769end;
770
771procedure MapBorderLimit(width,height: integer; options: TRectangleMapOptions; var borderHoriz,borderVert: integer);
772var maxHoriz,maxVert: integer;
773begin
774 if [rmoNoLeftBorder,rmoNoRightBorder] <= options then maxHoriz := borderHoriz else
775 if [rmoNoLeftBorder,rmoNoRightBorder] * options = [] then maxHoriz := width div 2 else
776 maxHoriz := width;
777 if borderHoriz > maxHoriz then borderHoriz := maxHoriz;
778
779 if [rmoNoTopBorder,rmoNoBottomBorder] <= options then maxVert := borderVert else
780 if [rmoNoTopBorder,rmoNoBottomBorder] * options = [] then maxVert := height div 2 else
781 maxVert := height;
782 if borderVert > maxVert then borderVert := maxVert;
783end;
784
785function CreateSpherePreciseMap(width, height: integer): TBGRABitmap;
786var cx,cy,rx,ry,d: single;
787 xb,yb: integer;
788 p: PBGRAPixel;
789 mask: TBGRABitmap;
790begin
791 result := TBGRABitmap.Create(width,height);
792 cx := (width-1)/2;
793 cy := (height-1)/2;
794 rx := (width-1)/2;
795 ry := (height-1)/2;
796 for yb := 0 to height-1 do
797 begin
798 p := result.scanline[yb];
799 for xb := 0 to width-1 do
800 begin
801 d := sqr((xb-cx)/(rx+1))+sqr((yb-cy)/(ry+1));
802 if d >= 1 then
803 p^ := BGRAPixelTransparent else
804 p^ := MapHeightToBGRA(sqrt(1-d),255);
805 inc(p);
806 end;
807 end;
808 //antialiased border
809 mask := TBGRABitmap.Create(width,height,BGRABlack);
810 mask.FillEllipseAntialias(cx,cy,rx,ry,BGRAWhite);
811 result.ApplyMask(mask);
812 mask.Free;
813end;
814
815procedure RectangleMapRemoveCorners(dest: TBGRABitmap; options: TRectangleMapOptions);
816begin
817 if [rmoNoLeftBorder,rmoNoTopBorder]*Options = [] then
818 begin
819 dest.SetPixel(0,0,BGRAPixelTransparent);
820 dest.ErasePixel(1,0,128);
821 dest.ErasePixel(0,1,128);
822 end;
823
824 if [rmoNoRightBorder,rmoNoTopBorder]*Options = [] then
825 begin
826 dest.SetPixel(dest.width-1,0,BGRAPixelTransparent);
827 dest.ErasePixel(dest.width-2,0,128);
828 dest.ErasePixel(dest.width-1,1,128);
829 end;
830
831 if [rmoNoRightBorder,rmoNoBottomBorder]*Options = [] then
832 begin
833 dest.SetPixel(dest.width-1,dest.height-1,BGRAPixelTransparent);
834 dest.ErasePixel(dest.width-2,dest.height-1,128);
835 dest.ErasePixel(dest.width-1,dest.height-2,128);
836 end;
837
838 if [rmoNoLeftBorder,rmoNoBottomBorder]*Options = [] then
839 begin
840 dest.SetPixel(0,dest.height-1,BGRAPixelTransparent);
841 dest.ErasePixel(1,dest.height-1,128);
842 dest.ErasePixel(0,dest.height-2,128);
843 end;
844end;
845
846function CreateRectangleMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
847var xb,yb: integer;
848 p: PBGRAPixel;
849 h: integer;
850begin
851 MapBorderLimit(width,height,options,border);
852
853 result := TBGRABitmap.Create(width,height);
854 for yb := 0 to height-1 do
855 begin
856 p := result.scanline[yb];
857 for xb := 0 to width-1 do
858 begin
859 if not (rmoNoLeftBorder in options) and (xb < border) and (yb > xb) and (yb < height-1-xb) then h := xb else
860 if not (rmoNoRightBorder in options) and (xb > width-1-border) and (yb > width-1-xb) and (yb < height-1-(width-1-xb)) then h := width-1-xb else
861 if not (rmoNoTopBorder in options) and (yb < border) and (xb > yb) and (xb < width-1-yb) then h := yb else
862 if not (rmoNoBottomBorder in options) and (yb > height-1-border) and (xb > height-1-yb) and (xb < width-1-(height-1-yb)) then h := height-1-yb else
863 if not (rmoNoLeftBorder in options) and (xb < border) then h := xb else
864 if not (rmoNoRightBorder in options) and (xb > width-1-border) then h := width-1-xb else
865 if not (rmoNoTopBorder in options) and (yb < border) then h := yb else
866 if not (rmoNoBottomBorder in options) and (yb > height-1-border) then h := height-1-yb else
867 begin
868 p^ := BGRAWhite;
869 inc(p);
870 Continue;
871 end;
872
873 if rmoLinearBorder in options then h := h*256 div border else
874 h := round(sin((h+1/2)/border*Pi/2)*255);
875 p^.red := h;
876 p^.green := h;
877 p^.blue := h;
878 p^.alpha := 255;
879 inc(p);
880 end;
881 end;
882
883 RectangleMapRemoveCorners(result,options);
884end;
885
886function CreateRectanglePreciseMap(width, height, border: integer;
887 options: TRectangleMapOptions): TBGRABitmap;
888var xb,yb: integer;
889 p: PBGRAPixel;
890 h: single;
891begin
892 MapBorderLimit(width,height,options,border);
893
894 result := TBGRABitmap.Create(width,height);
895 for yb := 0 to height-1 do
896 begin
897 p := result.scanline[yb];
898 for xb := 0 to width-1 do
899 begin
900 if not (rmoNoLeftBorder in options) and (xb < border) and (yb > xb) and (yb < height-1-xb) then h := xb else
901 if not (rmoNoRightBorder in options) and (xb > width-1-border) and (yb > width-1-xb) and (yb < height-1-(width-1-xb)) then h := width-1-xb else
902 if not (rmoNoTopBorder in options) and (yb < border) and (xb > yb) and (xb < width-1-yb) then h := yb else
903 if not (rmoNoBottomBorder in options) and (yb > height-1-border) and (xb > height-1-yb) and (xb < width-1-(height-1-yb)) then h := height-1-yb else
904 if not (rmoNoLeftBorder in options) and (xb < border) then h := xb else
905 if not (rmoNoRightBorder in options) and (xb > width-1-border) then h := width-1-xb else
906 if not (rmoNoTopBorder in options) and (yb < border) then h := yb else
907 if not (rmoNoBottomBorder in options) and (yb > height-1-border) then h := height-1-yb else
908 begin
909 p^ := BGRAWhite;
910 inc(p);
911 Continue;
912 end;
913
914 if rmoLinearBorder in options then h := h/border else
915 h := sin((h+1/2)/border*Pi/2);
916
917 p^ := MapHeightToBGRA(h,255);
918
919 inc(p);
920 end;
921 end;
922
923 RectangleMapRemoveCorners(result,options);
924end;
925
926function CreateRectanglePreciseMap(width, height, borderWidth, borderHeight: integer;
927 options: TRectangleMapOptions): TBGRABitmap;
928var xb,yb, minBorder: integer;
929 p: PBGRAPixel;
930 h: single;
931 smallStep: single;
932begin
933 MapBorderLimit(width,height,options,borderWidth,borderHeight);
934
935 minBorder := min(borderWidth,borderHeight);
936 if minBorder > 0 then smallStep := 1/minBorder else smallStep:= 0;
937
938 result := TBGRABitmap.Create(width,height);
939 for yb := 0 to height-1 do
940 begin
941 p := result.scanline[yb];
942 for xb := 0 to width-1 do
943 begin
944 if not (rmoNoLeftBorder in options) and (xb < borderWidth) and (yb < borderHeight) then
945 h := min(xb/borderWidth, yb/borderHeight) else
946 if not (rmoNoRightBorder in options) and (xb > width-1-borderWidth) and (yb < borderHeight) then
947 h := min((width-1-xb)/borderWidth, yb/borderHeight) else
948 if not (rmoNoTopBorder in options) and (xb < borderWidth) and (yb > height-1-borderHeight) then
949 h := min(xb/borderWidth, (height-1-yb)/borderHeight) else
950 if not (rmoNoBottomBorder in options) and (xb > width-1-borderWidth) and (yb > height-1-borderHeight) then
951 h := min((width-1-xb)/borderWidth, (height-1-yb)/borderHeight) else
952 if not (rmoNoLeftBorder in options) and (xb < borderWidth) then h := xb/borderWidth else
953 if not (rmoNoRightBorder in options) and (xb > width-1-borderWidth) then h := (width-1-xb)/borderWidth else
954 if not (rmoNoTopBorder in options) and (yb < borderHeight) then h := yb/borderHeight else
955 if not (rmoNoBottomBorder in options) and (yb > height-1-borderHeight) then h := (height-1-yb)/borderHeight else
956 begin
957 p^ := BGRAWhite;
958 inc(p);
959 Continue;
960 end;
961
962 if not (rmoLinearBorder in options) then
963 h := sin((h+smallStep*0.5)*Pi*0.5);
964
965 p^ := MapHeightToBGRA(h,255);
966
967 inc(p);
968 end;
969 end;
970
971 RectangleMapRemoveCorners(result,options);
972end;
973
974function CreateRoundRectangleMap(width,height,border: integer; options: TRectangleMapOptions = []): TBGRABitmap;
975var d: single;
976 xb,yb: integer;
977 p: PBGRAPixel;
978 h: integer;
979begin
980 MapBorderLimit(width,height,options,border);
981
982 result := TBGRABitmap.Create(width,height);
983 for yb := 0 to height-1 do
984 begin
985 p := result.scanline[yb];
986 for xb := 0 to width-1 do
987 begin
988 if not (rmoNoLeftBorder in options) and not (rmoNoTopBorder in options) and (xb < border) and (yb < border) then d := border-sqrt(sqr(border-xb)+sqr(border-yb)) else
989 if not (rmoNoLeftBorder in options) and not (rmoNoBottomBorder in options) and (xb < border) and (yb > height-1-border) then d := border-sqrt(sqr(border-xb)+sqr(border-(height-1-yb))) else
990 if not (rmoNoRightBorder in options) and not (rmoNoTopBorder in options) and (xb > width-1-border) and (yb < border) then d := border-sqrt(sqr(border-(width-1-xb))+sqr(border-yb)) else
991 if not (rmoNoRightBorder in options) and not (rmoNoBottomBorder in options) and (xb > width-1-border) and (yb > height-1-border) then d := border-sqrt(sqr(border-(width-1-xb))+sqr(border-(height-1-yb))) else
992 if not (rmoNoLeftBorder in options) and (xb < border) then d := xb else
993 if not (rmoNoRightBorder in options) and (xb > width-1-border) then d := width-1-xb else
994 if not (rmoNoTopBorder in options) and (yb < border) then d := yb else
995 if not (rmoNoBottomBorder in options) and (yb > height-1-border) then d := height-1-yb else
996 begin
997 p^ := BGRAWhite;
998 inc(p);
999 Continue;
1000 end;
1001
1002 d := (d+1)*border/(border+1);
1003
1004 if d < 0 then
1005 p^ := BGRAPixelTransparent else
1006 begin
1007 if rmoLinearBorder in options then h := trunc(d*256/border) else
1008 h := round(sin((d+1/2)/border*Pi/2)*255);
1009
1010 p^.red := h;
1011 p^.green := h;
1012 p^.blue := h;
1013 if d < 1 then p^.alpha := round(d*255) else
1014 p^.alpha := 255;
1015 end;
1016 inc(p);
1017 end;
1018 end;
1019end;
1020
1021function CreatePerlinNoiseMap(AWidth, AHeight: integer; HorizontalPeriod: Single;
1022 VerticalPeriod: Single; Exponent: Double = 1; ResampleFilter: TResampleFilter = rfCosine): TBGRABitmap;
1023
1024 procedure AddNoise(frequencyH, frequencyV: integer; amplitude: byte; dest: TBGRABitmap);
1025 var small,resampled: TBGRABitmap;
1026 p: PBGRAPixel;
1027 i: Integer;
1028 begin
1029 if (frequencyH = 0) or (frequencyV = 0) then exit;
1030 small := TBGRABitmap.Create(frequencyH,frequencyV);
1031 p := small.data;
1032 for i := 0 to small.NbPixels-1 do
1033 begin
1034 p^.red := random(amplitude);
1035 p^.green := p^.red;
1036 p^.blue := p^.green;
1037 p^.alpha := 255;
1038 inc(p);
1039 end;
1040 small.ResampleFilter := ResampleFilter;
1041 resampled := small.Resample(dest.Width,dest.Height) as TBGRABitmap;
1042 dest.BlendImage(0,0,resampled,boAdditive);
1043 resampled.Free;
1044 small.Free;
1045 end;
1046
1047var
1048 i: Integer;
1049 temp: TBGRABitmap;
1050
1051begin
1052 result := TBGRABitmap.Create(AWidth,AHeight);
1053 for i := 0 to 5 do
1054 AddNoise(round(AWidth / HorizontalPeriod / (32 shr i)),round(AHeight / VerticalPeriod / (32 shr i)), round(exp(ln((128 shr i)/128)*Exponent)*128),result);
1055
1056 temp := result.FilterNormalize(False) as TBGRABitmap;
1057 result.Free;
1058 result := temp;
1059
1060 temp := result.FilterBlurRadial(1,rbNormal) as TBGRABitmap;
1061 result.Free;
1062 result := temp;
1063end;
1064
1065function CreateCyclicPerlinNoiseMap(AWidth, AHeight: integer; HorizontalPeriod: Single = 1;
1066 VerticalPeriod: Single = 1; Exponent: Double = 1; ResampleFilter: TResampleFilter = rfCosine): TBGRABitmap;
1067
1068 procedure AddNoise(frequencyH, frequencyV: integer; amplitude: byte; dest: TBGRABitmap);
1069 var small,cycled,resampled: TBGRABitmap;
1070 p: PBGRAPixel;
1071 i: Integer;
1072 begin
1073 if (frequencyH = 0) or (frequencyV = 0) then exit;
1074 small := TBGRABitmap.Create(frequencyH,frequencyV);
1075 p := small.data;
1076 for i := 0 to small.NbPixels-1 do
1077 begin
1078 p^.red := random(amplitude);
1079 p^.green := p^.red;
1080 p^.blue := p^.green;
1081 p^.alpha := 255;
1082 inc(p);
1083 end;
1084 cycled := small.GetPart(rect(-2,-2,small.Width+2,small.Height+2)) as TBGRABitmap;
1085 cycled.ResampleFilter := ResampleFilter;
1086 resampled := cycled.Resample(round((cycled.Width-1)*(dest.Width/frequencyH)),round((cycled.Height-1)*(dest.Height/frequencyV))) as TBGRABitmap;
1087 dest.BlendImage(round(-2*(dest.Width/frequencyH)),round(-2*(dest.Height/frequencyV)),resampled,boAdditive);
1088 resampled.Free;
1089 cycled.Free;
1090 small.Free;
1091 end;
1092
1093var
1094 i: Integer;
1095 temp: TBGRABitmap;
1096
1097begin
1098 result := TBGRABitmap.Create(AWidth,AHeight);
1099 for i := 0 to 5 do
1100 AddNoise(round(AWidth / HorizontalPeriod / (32 shr i)),round(AHeight / VerticalPeriod / (32 shr i)), round(exp(ln((128 shr i)/128)*Exponent)*128),result);
1101
1102 temp := result.FilterNormalize(False) as TBGRABitmap;
1103 result.Free;
1104 result := temp;
1105
1106 temp := result.FilterBlurRadial(1,rbNormal) as TBGRABitmap;
1107 result.Free;
1108 result := temp;
1109end;
1110
1111function CreateRoundRectanglePreciseMap(width, height, border: integer;
1112 options: TRectangleMapOptions): TBGRABitmap;
1113var d: single;
1114 xb,yb: integer;
1115 p: PBGRAPixel;
1116 h: single;
1117begin
1118 MapBorderLimit(width,height,options,border);
1119
1120 result := TBGRABitmap.Create(width,height);
1121 for yb := 0 to height-1 do
1122 begin
1123 p := result.scanline[yb];
1124 for xb := 0 to width-1 do
1125 begin
1126 if not (rmoNoLeftBorder in options) and not (rmoNoTopBorder in options) and (xb < border) and (yb < border) then d := border-sqrt(sqr(border-xb)+sqr(border-yb)) else
1127 if not (rmoNoLeftBorder in options) and not (rmoNoBottomBorder in options) and (xb < border) and (yb > height-1-border) then d := border-sqrt(sqr(border-xb)+sqr(border-(height-1-yb))) else
1128 if not (rmoNoRightBorder in options) and not (rmoNoTopBorder in options) and (xb > width-1-border) and (yb < border) then d := border-sqrt(sqr(border-(width-1-xb))+sqr(border-yb)) else
1129 if not (rmoNoRightBorder in options) and not (rmoNoBottomBorder in options) and (xb > width-1-border) and (yb > height-1-border) then d := border-sqrt(sqr(border-(width-1-xb))+sqr(border-(height-1-yb))) else
1130 if not (rmoNoLeftBorder in options) and (xb < border) then d := xb else
1131 if not (rmoNoRightBorder in options) and (xb > width-1-border) then d := width-1-xb else
1132 if not (rmoNoTopBorder in options) and (yb < border) then d := yb else
1133 if not (rmoNoBottomBorder in options) and (yb > height-1-border) then d := height-1-yb else
1134 begin
1135 p^ := BGRAWhite;
1136 inc(p);
1137 Continue;
1138 end;
1139
1140 d := (d+1)*border/(border+1);
1141
1142 if d < 0 then
1143 p^ := BGRAPixelTransparent else
1144 begin
1145 if rmoLinearBorder in options then h := d/border else
1146 h := sin((d+1/2)/border*Pi/2);
1147
1148 if d < 1 then p^:= MapHeightToBGRA(h,round(d*255)) else
1149 p^ := MapHeightToBGRA(h,255);
1150 end;
1151 inc(p);
1152 end;
1153 end;
1154end;
1155
1156function CreateRoundRectanglePreciseMap(width, height, borderWidth,
1157 borderHeight: integer; options: TRectangleMapOptions): TBGRABitmap;
1158var d: single;
1159 xb,yb: integer;
1160 p: PBGRAPixel;
1161 h,smallStep,factor: single;
1162 minBorder: integer;
1163begin
1164 MapBorderLimit(width,height,options,borderWidth,borderHeight);
1165
1166 minBorder := min(borderWidth,borderHeight);
1167 if minBorder > 0 then smallStep := 1/minBorder else smallStep:= 0;
1168 factor := minBorder/(minBorder+1);
1169 result := TBGRABitmap.Create(width,height);
1170 for yb := 0 to height-1 do
1171 begin
1172 p := result.scanline[yb];
1173 for xb := 0 to width-1 do
1174 begin
1175 if not (rmoNoLeftBorder in options) and not (rmoNoTopBorder in options) and (xb < borderWidth) and (yb < borderHeight) then
1176 d := 1-sqrt(sqr((borderWidth-xb)/borderWidth)+sqr((borderHeight-yb)/borderHeight)) else
1177 if not (rmoNoLeftBorder in options) and not (rmoNoBottomBorder in options) and (xb < borderWidth) and (yb > height-1-borderHeight) then
1178 d := 1-sqrt(sqr((borderWidth-xb)/borderWidth)+sqr((borderHeight-(height-1-yb))/borderHeight)) else
1179 if not (rmoNoRightBorder in options) and not (rmoNoTopBorder in options) and (xb > width-1-borderWidth) and (yb < borderHeight) then
1180 d := 1-sqrt(sqr((borderWidth-(width-1-xb))/borderWidth)+sqr((borderHeight-yb)/borderHeight)) else
1181 if not (rmoNoRightBorder in options) and not (rmoNoBottomBorder in options) and (xb > width-1-borderWidth) and (yb > height-1-borderHeight) then
1182 d := 1-sqrt(sqr((borderWidth-(width-1-xb))/borderWidth)+sqr((borderHeight-(height-1-yb))/borderHeight)) else
1183 if not (rmoNoLeftBorder in options) and (xb < borderWidth) then d := xb/borderWidth else
1184 if not (rmoNoRightBorder in options) and (xb > width-1-borderWidth) then d := (width-1-xb)/borderWidth else
1185 if not (rmoNoTopBorder in options) and (yb < borderHeight) then d := yb/borderHeight else
1186 if not (rmoNoBottomBorder in options) and (yb > height-1-borderHeight) then d := (height-1-yb)/borderHeight else
1187 begin
1188 p^ := BGRAWhite;
1189 inc(p);
1190 Continue;
1191 end;
1192
1193 d := (d + smallStep)*factor;
1194
1195 if d < 0 then
1196 p^ := BGRAPixelTransparent else
1197 begin
1198 if rmoLinearBorder in options then h := d else
1199 h := sin((d+smallStep*0.5)*Pi*0.5);
1200
1201 if d < smallStep then p^:= MapHeightToBGRA(h,round(d/smallStep*255)) else
1202 p^ := MapHeightToBGRA(h,255);
1203 end;
1204 inc(p);
1205 end;
1206 end;
1207end;
1208
1209initialization
1210
1211 Randomize;
1212
1213end.
1214
Note: See TracBrowser for help on using the repository browser.