Changeset 472
- Timestamp:
- Apr 9, 2015, 9:58:36 PM (10 years ago)
- Location:
- GraphicTest
- Files:
-
- 36 added
- 1 deleted
- 60 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/GraphicTest.lpi
r470 r472 128 128 <Filename Value="Methods/ULazIntfImageColorsCopy.pas"/> 129 129 <IsPartOfProject Value="True"/> 130 <UnitName Value="ULazIntfImageColorsCopy"/> 130 131 </Unit8> 131 132 <Unit9> … … 163 164 <Filename Value="Methods/UOpenGLPBOMethod.pas"/> 164 165 <IsPartOfProject Value="True"/> 166 <UnitName Value="UOpenGLPBOMethod"/> 165 167 </Unit16> 166 168 <Unit17> … … 201 203 </CodeGeneration> 202 204 <Linking> 203 <Debugging>204 <UseExternalDbgSyms Value="True"/>205 </Debugging>206 205 <Options> 207 206 <Win32> -
GraphicTest/Packages/bgrabitmap/bgraanimatedgif.pas
r452 r472 34 34 FTimeAccumulator: double; 35 35 FCurrentImage, FWantedImage: integer; 36 FFullAnimationTime: double; 36 37 FPreviousDisposeMode: TDisposeMode; 37 38 … … 41 42 42 43 function GetCount: integer; 44 function GetTimeUntilNextImage: integer; 43 45 procedure Render(StretchWidth, StretchHeight: integer); 44 46 procedure UpdateSimple(Canvas: TCanvas; ARect: TRect; … … 70 72 BackgroundMode: TGifBackgroundMode; 71 73 72 constructor Create(filename : string);74 constructor Create(filenameUTF8: string); 73 75 constructor Create(stream: TStream); 74 76 constructor Create; override; … … 78 80 procedure LoadFromStream(Stream: TStream); override; 79 81 procedure SaveToStream(Stream: TStream); override; 82 procedure LoadFromFile(const AFilenameUTF8: string); override; 83 procedure SaveToFile(const AFilenameUTF8: string); override; 80 84 class function GetFileExtensions: string; override; 81 85 … … 97 101 property MemBitmap: TBGRABitmap Read GetMemBitmap; 98 102 property CurrentImage: integer Read FCurrentImage Write SetCurrentImage; 103 property TimeUntilNextImageMs: integer read GetTimeUntilNextImage; 99 104 end; 100 105 … … 114 119 implementation 115 120 116 uses BGRABlend ;121 uses BGRABlend, lazutf8classes; 117 122 118 123 const 124 {$IFDEF ENDIAN_LITTLE} 119 125 AlphaMask = $FF000000; 126 {$ELSE} 127 AlphaMask = $000000FF; 128 {$ENDIF} 120 129 121 130 type … … 188 197 if not FPaused then 189 198 FTimeAccumulator += (curDate - FPrevDate) * 24 * 60 * 60 * 1000; 199 if FFullAnimationTime > 0 then FTimeAccumulator:= frac(FTimeAccumulator/FFullAnimationTime)*FFullAnimationTime; 190 200 nextImage := FCurrentImage; 191 201 while FTimeAccumulator > FImages[nextImage].Delay do … … 279 289 end; 280 290 281 constructor TBGRAAnimatedGif.Create(filename: string);291 function TBGRAAnimatedGif.GetTimeUntilNextImage: integer; 282 292 var 283 Stream: TFileStream; 293 acc: double; 294 begin 295 if Count <= 1 then result := 60*1000 else 296 if (FWantedImage <> -1) or (FCurrentImage = -1) then 297 result := 0 298 else 299 begin 300 acc := FTimeAccumulator; 301 if not FPaused then acc += (Now- FPrevDate) * 24 * 60 * 60 * 1000; 302 if acc >= FImages[FCurrentImage].Delay then 303 result := 0 304 else 305 result := round(FImages[FCurrentImage].Delay-FTimeAccumulator); 306 end; 307 end; 308 309 constructor TBGRAAnimatedGif.Create(filenameUTF8: string); 310 var 311 Stream: TFileStreamUTF8; 284 312 begin 285 313 inherited Create; 286 314 Init; 287 Stream := TFileStream .Create(filename, fmOpenRead);315 Stream := TFileStreamUTF8.Create(filenameUTF8, fmOpenRead or fmShareDenyWrite); 288 316 LoadFromStream(Stream); 289 317 Stream.Free; … … 355 383 end; 356 384 385 procedure TBGRAAnimatedGif.LoadFromFile(const AFilenameUTF8: string); 386 var stream: TFileStreamUTF8; 387 begin 388 stream := TFileStreamUTF8.Create(AFilenameUTF8,fmOpenRead or fmShareDenyWrite); 389 try 390 LoadFromStream(Stream); 391 finally 392 Stream.Free; 393 end; 394 end; 395 396 procedure TBGRAAnimatedGif.SaveToFile(const AFilenameUTF8: string); 397 var 398 Stream: TFileStreamUTF8; 399 begin 400 Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate); 401 try 402 SaveToStream(Stream); 403 finally 404 Stream.Free; 405 end; 406 end; 407 357 408 {$HINTS OFF} 358 409 procedure TBGRAAnimatedGif.LoadImages(stream: TStream); … … 458 509 stridx: longint; 459 510 bitbuf, bitsinbuf: longint; 460 bytbuf: array[0..255] of byte;511 bytbuf: packed array[0..255] of byte; 461 512 bytinbuf, bytbufidx: byte; 462 513 endofsrc: boolean; … … 684 735 begin 685 736 stream.Read(GIFImageDescriptor, sizeof(GIFImageDescriptor)); 737 GIFImageDescriptor.Width := LEtoN(GIFImageDescriptor.Width); 738 GIFImageDescriptor.Height := LEtoN(GIFImageDescriptor.Height); 739 GIFImageDescriptor.x := LEtoN(GIFImageDescriptor.x); 740 GIFImageDescriptor.y := LEtoN(GIFImageDescriptor.y); 686 741 if (GIFImageDescriptor.flags and GIFImageDescriptor_LocalColorTableFlag = 687 742 GIFImageDescriptor_LocalColorTableFlag) then … … 724 779 Clear; 725 780 SetLength(FImages, NbImages); 781 FFullAnimationTime:= 0; 726 782 for i := 0 to Count - 1 do 783 begin 727 784 FImages[i] := NewImages[i]; 785 FFullAnimationTime += NewImages[i].Delay; 786 end; 728 787 end; 729 788 … … 746 805 mincount := sizeof(GIFGraphicControlExtension); 747 806 stream.Read(GIFGraphicControlExtension, mincount); 807 GIFGraphicControlExtension.delaytime := LEtoN(GIFGraphicControlExtension.delaytime); 748 808 749 809 if GIFGraphicControlExtension.flags and … … 781 841 begin 782 842 stream.Read(GIFScreenDescriptor, sizeof(GIFScreenDescriptor)); 843 GIFScreenDescriptor.Width := LEtoN(GIFScreenDescriptor.Width); 844 GIFScreenDescriptor.Height := LEtoN(GIFScreenDescriptor.Height); 783 845 FWidth := GIFScreenDescriptor.Width; 784 846 FHeight := GIFScreenDescriptor.Height; -
GraphicTest/Packages/bgrabitmap/bgrabitmap.pas
r452 r472 113 113 implementation 114 114 115 uses GraphType, BGRABitmapTypes; 115 uses GraphType, BGRABitmapTypes, BGRAReadBMP, BGRAReadGif, 116 BGRAReadIco, bgrareadjpeg, BGRAReadLzp, BGRAReadPCX, 117 BGRAReadPng, BGRAReadPSD, BGRAReadTGA, BGRAReadXPM, 118 BGRAWriteLzp; 116 119 117 120 var -
GraphicTest/Packages/bgrabitmap/bgrabitmappack.lpk
r452 r472 17 17 </SyntaxOptions> 18 18 </Parsing> 19 <CodeGeneration> 20 <Optimizations> 21 <VariablesInRegisters Value="True"/> 22 <OptimizationLevel Value="3"/> 23 </Optimizations> 24 </CodeGeneration> 19 25 <Linking> 20 26 <Debugging> 21 < DebugInfoType Value="dsStabs"/>27 <GenerateDebugInfo Value="False"/> 22 28 </Debugging> 23 29 </Linking> … … 31 37 <Description Value="Drawing routines with alpha blending and antialiasing"/> 32 38 <License Value="modified LGPL"/> 33 <Version Major=" 6" Minor="2"/>34 <Files Count=" 56">39 <Version Major="8" Minor="1"/> 40 <Files Count="91"> 35 41 <Item1> 36 42 <Filename Value="bgraanimatedgif.pas"/> … … 50 56 </Item4> 51 57 <Item5> 58 <Filename Value="bgracanvas.pas"/> 59 <UnitName Value="BGRACanvas"/> 60 </Item5> 61 <Item6> 62 <Filename Value="bgracanvas2d.pas"/> 63 <UnitName Value="BGRACanvas2D"/> 64 </Item6> 65 <Item7> 66 <Filename Value="bgracolorint.pas"/> 67 <UnitName Value="BGRAColorInt"/> 68 </Item7> 69 <Item8> 52 70 <Filename Value="bgracompressablebitmap.pas"/> 53 71 <UnitName Value="BGRACompressableBitmap"/> 54 </Item5> 55 <Item6> 72 </Item8> 73 <Item9> 74 <Filename Value="bgracoordpool3d.pas"/> 75 <UnitName Value="BGRACoordPool3D"/> 76 </Item9> 77 <Item10> 56 78 <Filename Value="bgradefaultbitmap.pas"/> 57 79 <UnitName Value="BGRADefaultBitmap"/> 58 </Item 6>59 <Item 7>80 </Item10> 81 <Item11> 60 82 <Filename Value="bgradnetdeserial.pas"/> 61 83 <UnitName Value="BGRADNetDeserial"/> 62 </Item7> 63 <Item8> 84 </Item11> 85 <Item12> 86 <Filename Value="bgrafillinfo.pas"/> 87 <UnitName Value="BGRAFillInfo"/> 88 </Item12> 89 <Item13> 64 90 <Filename Value="bgrafilters.pas"/> 65 91 <UnitName Value="BGRAFilters"/> 66 </Item8> 67 <Item9> 92 </Item13> 93 <Item14> 94 <Filename Value="bgrafreetype.pas"/> 95 <UnitName Value="BGRAFreeType"/> 96 </Item14> 97 <Item15> 98 <Filename Value="bgragradients.pas"/> 99 <UnitName Value="BGRAGradients"/> 100 </Item15> 101 <Item16> 102 <Filename Value="bgragradientscanner.pas"/> 103 <UnitName Value="BGRAGradientScanner"/> 104 </Item16> 105 <Item17> 106 <Filename Value="bgralayers.pas"/> 107 <UnitName Value="BGRALayers"/> 108 </Item17> 109 <Item18> 110 <Filename Value="bgramatrix3d.pas"/> 111 <UnitName Value="BGRAMatrix3D"/> 112 </Item18> 113 <Item19> 114 <Filename Value="bgraopenraster.pas"/> 115 <UnitName Value="BGRAOpenRaster"/> 116 </Item19> 117 <Item20> 68 118 <Filename Value="bgrapaintnet.pas"/> 69 119 <UnitName Value="BGRAPaintNet"/> 70 </Item9> 71 <Item10> 120 </Item20> 121 <Item21> 122 <Filename Value="bgrapath.pas"/> 123 <UnitName Value="BGRAPath"/> 124 </Item21> 125 <Item22> 126 <Filename Value="bgrapen.pas"/> 127 <UnitName Value="BGRAPen"/> 128 </Item22> 129 <Item23> 130 <Filename Value="bgraphongtypes.pas"/> 131 <UnitName Value="BGRAPhongTypes"/> 132 </Item23> 133 <Item24> 72 134 <Filename Value="bgrapolygon.pas"/> 73 135 <UnitName Value="BGRAPolygon"/> 74 </Item10> 75 <Item11> 136 </Item24> 137 <Item25> 138 <Filename Value="bgrapolygonaliased.pas"/> 139 <UnitName Value="BGRAPolygonAliased"/> 140 </Item25> 141 <Item26> 76 142 <Filename Value="bgraresample.pas"/> 77 143 <UnitName Value="BGRAResample"/> 78 </Item11> 79 <Item12> 80 <Filename Value="bgrapen.pas"/> 81 <UnitName Value="BGRAPen"/> 82 </Item12> 83 <Item13> 144 </Item26> 145 <Item27> 146 <Filename Value="bgrascene3d.pas"/> 147 <UnitName Value="BGRAScene3D"/> 148 </Item27> 149 <Item28> 150 <Filename Value="bgrascene3dinterface.inc"/> 151 <Type Value="Binary"/> 152 </Item28> 153 <Item29> 154 <Filename Value="bgraslicescaling.pas"/> 155 <UnitName Value="BGRASliceScaling"/> 156 </Item29> 157 <Item30> 158 <Filename Value="bgrasse.pas"/> 159 <UnitName Value="BGRASSE"/> 160 </Item30> 161 <Item31> 162 <Filename Value="bgrastreamlayers.pas"/> 163 <UnitName Value="BGRAStreamLayers"/> 164 </Item31> 165 <Item32> 166 <Filename Value="bgratext.pas"/> 167 <UnitName Value="BGRAText"/> 168 </Item32> 169 <Item33> 170 <Filename Value="bgratextfx.pas"/> 171 <UnitName Value="BGRATextFX"/> 172 </Item33> 173 <Item34> 84 174 <Filename Value="bgratransform.pas"/> 85 175 <UnitName Value="BGRATransform"/> 86 </Item13>87 <Item14>88 <Filename Value="bgragradientscanner.pas"/>89 <UnitName Value="BGRAGradientScanner"/>90 </Item14>91 <Item15>92 <Filename Value="bgratext.pas"/>93 <UnitName Value="BGRAText"/>94 </Item15>95 <Item16>96 <Filename Value="bgrapolygonaliased.pas"/>97 <UnitName Value="BGRAPolygonAliased"/>98 </Item16>99 <Item17>100 <Filename Value="blurfast.inc"/>101 <Type Value="Binary"/>102 </Item17>103 <Item18>104 <Filename Value="blurnormal.inc"/>105 <Type Value="Binary"/>106 </Item18>107 <Item19>108 <Filename Value="phongdraw.inc"/>109 <Type Value="Binary"/>110 </Item19>111 <Item20>112 <Filename Value="bgracanvas.pas"/>113 <UnitName Value="BGRACanvas"/>114 </Item20>115 <Item21>116 <Filename Value="filldensity256.inc"/>117 <Type Value="Binary"/>118 </Item21>119 <Item22>120 <Filename Value="perspectivescan.inc"/>121 <Type Value="Binary"/>122 </Item22>123 <Item23>124 <Filename Value="lineartexscan.inc"/>125 <Type Value="Binary"/>126 </Item23>127 <Item24>128 <Filename Value="bgrafillinfo.pas"/>129 <UnitName Value="BGRAFillInfo"/>130 </Item24>131 <Item25>132 <Filename Value="filldensitysegment256.inc"/>133 <Type Value="Binary"/>134 </Item25>135 <Item26>136 <Filename Value="renderdensity256.inc"/>137 <Type Value="Binary"/>138 </Item26>139 <Item27>140 <Filename Value="multishapeline.inc"/>141 <Type Value="Binary"/>142 </Item27>143 <Item28>144 <Filename Value="bgrapath.pas"/>145 <UnitName Value="BGRAPath"/>146 </Item28>147 <Item29>148 <Filename Value="bgracanvas2d.pas"/>149 <UnitName Value="BGRACanvas2D"/>150 </Item29>151 <Item30>152 <Filename Value="bgrascene3d.pas"/>153 <UnitName Value="BGRAScene3D"/>154 </Item30>155 <Item31>156 <Filename Value="bgratextfx.pas"/>157 <UnitName Value="BGRATextFX"/>158 </Item31>159 <Item32>160 <Filename Value="bgraphongtypes.pas"/>161 <UnitName Value="BGRAPhongTypes"/>162 </Item32>163 <Item33>164 <Filename Value="bgralayers.pas"/>165 <UnitName Value="BGRALayers"/>166 </Item33>167 <Item34>168 <Filename Value="bgrasse.pas"/>169 <UnitName Value="BGRASSE"/>170 176 </Item34> 171 177 <Item35> 172 <Filename Value=" perspectivescan2.inc"/>173 < Type Value="Binary"/>178 <Filename Value="bgratypewriter.pas"/> 179 <UnitName Value="BGRATypewriter"/> 174 180 </Item35> 175 181 <Item36> 176 <Filename Value=" shape3D.inc"/>177 < Type Value="Binary"/>182 <Filename Value="bgravectorize.pas"/> 183 <UnitName Value="BGRAVectorize"/> 178 184 </Item36> 179 185 <Item37> 180 <Filename Value="b grascene3dinterface.inc"/>186 <Filename Value="blendpixelinline.inc"/> 181 187 <Type Value="Binary"/> 182 188 </Item37> 183 189 <Item38> 184 <Filename Value="b gramatrix3d.pas"/>185 < UnitName Value="BGRAMatrix3D"/>190 <Filename Value="blendpixels.inc"/> 191 <Type Value="Binary"/> 186 192 </Item38> 187 193 <Item39> 188 <Filename Value=" csscolorconst.inc"/>194 <Filename Value="blendpixelsover.inc"/> 189 195 <Type Value="Binary"/> 190 196 </Item39> 191 197 <Item40> 192 <Filename Value=" lightingclasses3d.inc"/>198 <Filename Value="blurfast.inc"/> 193 199 <Type Value="Binary"/> 194 200 </Item40> 195 201 <Item41> 196 <Filename Value=" phonglight.inc"/>202 <Filename Value="blurnormal.inc"/> 197 203 <Type Value="Binary"/> 198 204 </Item41> 199 205 <Item42> 200 <Filename Value=" polyaliaspersp.inc"/>206 <Filename Value="csscolorconst.inc"/> 201 207 <Type Value="Binary"/> 202 208 </Item42> 203 209 <Item43> 204 <Filename Value=" lineartexscan2.inc"/>210 <Filename Value="filldensity256.inc"/> 205 211 <Type Value="Binary"/> 206 212 </Item43> 207 213 <Item44> 208 <Filename Value=" perspectivecolorscan.inc"/>214 <Filename Value="filldensitysegment256.inc"/> 209 215 <Type Value="Binary"/> 210 216 </Item44> 211 217 <Item45> 212 <Filename Value=" phongdrawsse.inc"/>218 <Filename Value="lightingclasses3d.inc"/> 213 219 <Type Value="Binary"/> 214 220 </Item45> 215 221 <Item46> 216 <Filename Value=" phonglightsse.inc"/>222 <Filename Value="lineartexscan.inc"/> 217 223 <Type Value="Binary"/> 218 224 </Item46> 219 225 <Item47> 220 <Filename Value=" bgracoordpool3d.pas"/>221 < UnitName Value="BGRACoordPool3D"/>226 <Filename Value="lineartexscan2.inc"/> 227 <Type Value="Binary"/> 222 228 </Item47> 223 229 <Item48> 224 <Filename Value=" bgraopenraster.pas"/>225 < UnitName Value="BGRAOpenRaster"/>230 <Filename Value="multishapeline.inc"/> 231 <Type Value="Binary"/> 226 232 </Item48> 227 233 <Item49> 228 <Filename Value=" blendpixels.inc"/>234 <Filename Value="perspectivecolorscan.inc"/> 229 235 <Type Value="Binary"/> 230 236 </Item49> 231 237 <Item50> 232 <Filename Value=" blendpixelinline.inc"/>238 <Filename Value="perspectivescan.inc"/> 233 239 <Type Value="Binary"/> 234 240 </Item50> 235 241 <Item51> 236 <Filename Value=" blendpixelsover.inc"/>242 <Filename Value="perspectivescan2.inc"/> 237 243 <Type Value="Binary"/> 238 244 </Item51> 239 245 <Item52> 240 <Filename Value=" bgrafreetype.pas"/>241 < UnitName Value="BGRAFreeType"/>246 <Filename Value="phongdraw.inc"/> 247 <Type Value="Binary"/> 242 248 </Item52> 243 249 <Item53> 244 <Filename Value=" bgragradients.pas"/>245 < UnitName Value="BGRAGradients"/>250 <Filename Value="phongdrawsse.inc"/> 251 <Type Value="Binary"/> 246 252 </Item53> 247 253 <Item54> 248 <Filename Value=" bgraslicescaling.pas"/>249 < UnitName Value="BGRASliceScaling"/>254 <Filename Value="phonglight.inc"/> 255 <Type Value="Binary"/> 250 256 </Item54> 251 257 <Item55> 252 <Filename Value=" bgravectorize.pas"/>253 < UnitName Value="BGRAVectorize"/>258 <Filename Value="phonglightsse.inc"/> 259 <Type Value="Binary"/> 254 260 </Item55> 255 261 <Item56> 256 <Filename Value=" bgratypewriter.pas"/>257 < UnitName Value="BGRATypewriter"/>262 <Filename Value="polyaliaspersp.inc"/> 263 <Type Value="Binary"/> 258 264 </Item56> 265 <Item57> 266 <Filename Value="renderdensity256.inc"/> 267 <Type Value="Binary"/> 268 </Item57> 269 <Item58> 270 <Filename Value="shapes3d.inc"/> 271 <Type Value="Binary"/> 272 </Item58> 273 <Item59> 274 <Filename Value="winstream.inc"/> 275 <Type Value="Binary"/> 276 </Item59> 277 <Item60> 278 <Filename Value="bgrasse.inc"/> 279 <UnitName Value="bgrasse"/> 280 </Item60> 281 <Item61> 282 <Filename Value="sseloadv.inc"/> 283 <UnitName Value="sseloadv"/> 284 </Item61> 285 <Item62> 286 <Filename Value="ssesavev.inc"/> 287 <UnitName Value="ssesavev"/> 288 </Item62> 289 <Item63> 290 <Filename Value="bgragrayscalemask.pas"/> 291 <UnitName Value="BGRAGrayscaleMask"/> 292 </Item63> 293 <Item64> 294 <Filename Value="bgrareadbmp.pas"/> 295 <UnitName Value="BGRAReadBMP"/> 296 </Item64> 297 <Item65> 298 <Filename Value="bgrareadgif.pas"/> 299 <UnitName Value="BGRAReadGif"/> 300 </Item65> 301 <Item66> 302 <Filename Value="bgrareadpcx.pas"/> 303 <UnitName Value="BGRAReadPCX"/> 304 </Item66> 305 <Item67> 306 <Filename Value="bgrareadpng.pas"/> 307 <UnitName Value="BGRAReadPng"/> 308 </Item67> 309 <Item68> 310 <Filename Value="bgrareadpsd.pas"/> 311 <UnitName Value="BGRAReadPSD"/> 312 </Item68> 313 <Item69> 314 <Filename Value="bgrathumbnail.pas"/> 315 <UnitName Value="BGRAThumbnail"/> 316 </Item69> 317 <Item70> 318 <Filename Value="bgrareadtga.pas"/> 319 <UnitName Value="BGRAReadTGA"/> 320 </Item70> 321 <Item71> 322 <Filename Value="bgrareadico.pas"/> 323 <UnitName Value="BGRAReadIco"/> 324 </Item71> 325 <Item72> 326 <Filename Value="bgrareadjpeg.pas"/> 327 <UnitName Value="bgrareadjpeg"/> 328 </Item72> 329 <Item73> 330 <Filename Value="bgrareadlzp.pas"/> 331 <UnitName Value="BGRAReadLzp"/> 332 </Item73> 333 <Item74> 334 <Filename Value="unzipperext.pas"/> 335 <UnitName Value="UnzipperExt"/> 336 </Item74> 337 <Item75> 338 <Filename Value="bgralzpcommon.pas"/> 339 <UnitName Value="BGRALzpCommon"/> 340 </Item75> 341 <Item76> 342 <Filename Value="bgrawritelzp.pas"/> 343 <UnitName Value="BGRAWriteLzp"/> 344 </Item76> 345 <Item77> 346 <Filename Value="bgrareadxpm.pas"/> 347 <UnitName Value="BGRAReadXPM"/> 348 </Item77> 349 <Item78> 350 <Filename Value="bgrasvg.pas"/> 351 <UnitName Value="BGRASVG"/> 352 </Item78> 353 <Item79> 354 <Filename Value="bgraunits.pas"/> 355 <UnitName Value="BGRAUnits"/> 356 </Item79> 357 <Item80> 358 <Filename Value="bgrasvgshapes.pas"/> 359 <UnitName Value="BGRASVGShapes"/> 360 </Item80> 361 <Item81> 362 <Filename Value="bgrasvgtype.pas"/> 363 <UnitName Value="BGRASVGType"/> 364 </Item81> 365 <Item82> 366 <Filename Value="bgrareadbmpmiomap.pas"/> 367 <UnitName Value="BGRAReadBmpMioMap"/> 368 </Item82> 369 <Item83> 370 <Filename Value="bgraarrow.pas"/> 371 <UnitName Value="BGRAArrow"/> 372 </Item83> 373 <Item84> 374 <Filename Value="vertex3d.inc"/> 375 <Type Value="Binary"/> 376 </Item84> 377 <Item85> 378 <Filename Value="face3d.inc"/> 379 <Type Value="Binary"/> 380 </Item85> 381 <Item86> 382 <Filename Value="part3d.inc"/> 383 <Type Value="Binary"/> 384 </Item86> 385 <Item87> 386 <Filename Value="object3d.inc"/> 387 <Type Value="Binary"/> 388 </Item87> 389 <Item88> 390 <Filename Value="bgrapalette.pas"/> 391 <UnitName Value="BGRAPalette"/> 392 </Item88> 393 <Item89> 394 <Filename Value="bgracolorquantization.pas"/> 395 <UnitName Value="BGRAColorQuantization"/> 396 </Item89> 397 <Item90> 398 <Filename Value="bgradithering.pas"/> 399 <UnitName Value="BGRADithering"/> 400 </Item90> 401 <Item91> 402 <Filename Value="paletteformats.inc"/> 403 <Type Value="Binary"/> 404 </Item91> 259 405 </Files> 260 <Type Value="RunAndDesignTime"/>261 406 <RequiredPkgs Count="2"> 262 407 <Item1> -
GraphicTest/Packages/bgrabitmap/bgrabitmappack.pas
r452 r472 8 8 9 9 uses 10 BGRAAnimatedGif, BGRABitmap, BGRABitmapTypes, BGRABlend, 11 BGRACompressableBitmap, BGRADefaultBitmap, BGRADNetDeserial, BGRAFilters, 12 BGRAPaintNet, BGRAPolygon, BGRAResample, BGRAPen, BGRATransform, 13 BGRAGradientScanner, BGRAText, BGRAPolygonAliased, BGRACanvas, BGRAFillInfo, 14 BGRAPath, BGRACanvas2D, BGRAScene3D, BGRATextFX, BGRAPhongTypes, BGRALayers, 15 BGRASSE, BGRAMatrix3D, BGRACoordPool3D, BGRAOpenRaster, BGRAFreeType, 16 BGRAGradients, BGRASliceScaling, BGRAVectorize, BGRATypewriter, 17 LazarusPackageIntf; 10 BGRAAnimatedGif, BGRABitmap, BGRABitmapTypes, BGRABlend, BGRACanvas, 11 BGRACanvas2D, BGRAColorInt, BGRACompressableBitmap, BGRACoordPool3D, 12 BGRADefaultBitmap, BGRADNetDeserial, BGRAFillInfo, BGRAFilters, 13 BGRAFreeType, BGRAGradients, BGRAGradientScanner, BGRALayers, BGRAMatrix3D, 14 BGRAOpenRaster, BGRAPaintNet, BGRAPath, BGRAPen, BGRAPhongTypes, 15 BGRAPolygon, BGRAPolygonAliased, BGRAResample, BGRAScene3D, 16 BGRASliceScaling, BGRASSE, BGRAStreamLayers, BGRAText, BGRATextFX, 17 BGRATransform, BGRATypewriter, BGRAVectorize, BGRAGrayscaleMask, 18 BGRAReadBMP, BGRAReadGif, BGRAReadPCX, BGRAReadPng, BGRAReadPSD, 19 BGRAThumbnail, BGRAReadTGA, BGRAReadIco, bgrareadjpeg, BGRAReadLzp, 20 UnzipperExt, BGRALzpCommon, BGRAWriteLzp, BGRAReadXPM, BGRASVG, BGRAUnits, 21 BGRASVGShapes, BGRASVGType, BGRAReadBmpMioMap, BGRAArrow, BGRAPalette, 22 BGRAColorQuantization, BGRADithering; 18 23 19 24 implementation 20 25 21 procedure Register;22 begin23 end;24 25 initialization26 RegisterPackage('BGRABitmapPack', @Register);27 26 end. -
GraphicTest/Packages/bgrabitmap/bgrabitmaptypes.pas
r452 r472 36 36 PBGRAPixel = ^TBGRAPixel; 37 37 38 //pixel structure 38 Int32or64 = {$IFDEF CPU64}Int64{$ELSE}LongInt{$ENDIF}; 39 UInt32or64 = {$IFDEF CPU64}UInt64{$ELSE}LongWord{$ENDIF}; 40 41 //Each pixel is a sequence of 4 bytes containing blue, green, red and alpha channel. 39 42 TBGRAPixel = packed record 40 43 blue, green, red, alpha: byte; 41 44 end; 45 46 ArrayOfTBGRAPixel = array of TBGRAPixel; 42 47 43 48 //gamma expanded values … … 50 55 hue, saturation, lightness, alpha: word; 51 56 end; 57 TGSBAPixel = THSLAPixel; 52 58 53 59 //general purpose color variable with floating point values … … 70 76 71 77 TResampleMode = (rmSimpleStretch, //low quality resample 72 rmFineResample); //use resample filters 73 TResampleFilter = (rfLinear, //linear interpolation 78 rmFineResample); //use resample filters and pixel-centered coordinates 79 TResampleFilter = (rfBox, //equivalent of stretch with high quality 80 rfLinear, //linear interpolation 74 81 rfHalfCosine, //mix of rfLinear and rfCosine 75 82 rfCosine, //cosine-like interpolation … … 77 84 rfMitchell, //downsizing interpolation 78 85 rfSpline, //upsizing interpolation 86 rfLanczos2, //Lanczos with radius 2 87 rfLanczos3, //Lanczos with radius 3 88 rfLanczos4, //Lanczos with radius 4 79 89 rfBestQuality); //mix of rfMitchell and rfSpline 80 90 91 TDitheringAlgorithm = (daNearestNeighbor, daFloydSteinberg); 92 TAlphaChannelPaletteOption = (acIgnore, acTransparentEntry, acFullChannelInPalette); 93 94 const 95 ResampleFilterStr : array[TResampleFilter] of string = 96 ('Box','Linear','HalfCosine','Cosine','Bicubic','Mitchell','Spline', 97 'Lanczos2','Lanczos3','Lanczos4','BestQuality'); 98 99 function StrToResampleFilter(str: string): TResampleFilter; 100 101 type 102 TBGRAImageFormat = (ifUnknown, ifJpeg, ifPng, ifGif, ifBmp, ifIco, ifPcx, ifPaintDotNet, ifLazPaint, ifOpenRaster, 103 ifPsd, ifTarga, ifTiff, ifXwd, ifXPixMap, ifBmpMioMap); 104 105 var 106 DefaultBGRAImageReader: array[TBGRAImageFormat] of TFPCustomImageReaderClass; 107 DefaultBGRAImageWriter: array[TBGRAImageFormat] of TFPCustomImageWriterClass; 108 109 type 81 110 TBGRAFontQuality = (fqSystem, fqSystemClearType, fqFineAntialiasing, fqFineClearTypeRGB, fqFineClearTypeBGR); 111 // fqSystem: use system rendering. It is fast however it may be not be smoothed. 112 // fqSystemClearType: use system rendering with ClearType. This quality is of course better than fqSystem however it may not be much smoother. 113 // fqFineAntialiasing: garanties a high quality antialiasing. This is slower. 114 // fqFineClearTypeRGB: garanties a high quality antialiasing with ClearType. The order of the color in the LCD screen is supposed to be un red/green/blue order. 115 // fqFineClearTypeBGR: same as above, except the color of the LCD screen is supposed to be in blue/green/red order. 82 116 83 117 TMedianOption = (moNone, moLowSmooth, moMediumSmooth, moHighSmooth); 84 TRadialBlurType = (rbNormal, rbDisk, rbCorona, rbPrecise, rbFast); 85 TSplineStyle = (ssInside, ssInsideWithEnds, ssCrossing, ssCrossingWithEnds, ssOutside, ssRoundOutside, ssVertexToSide); 118 TRadialBlurType = (rbNormal, rbDisk, rbCorona, rbPrecise, rbFast, rbBox); 119 TSplineStyle = (ssInside, ssInsideWithEnds, ssCrossing, ssCrossingWithEnds, 120 ssOutside, ssRoundOutside, ssVertexToSide); 86 121 87 //Advanced blending modes88 //see : http://www.brighthub.com/multimedia/photography/articles/18301.aspx89 //and : http://www.pegtop.net/delphi/articles/blendmodes/122 { Advanced blending modes 123 see : http://www.brighthub.com/multimedia/photography/articles/18301.aspx 124 and : http://www.pegtop.net/delphi/articles/blendmodes/ } 90 125 TBlendOperation = (boLinearBlend, boTransparent, //blending 91 126 boLighten, boScreen, boAdditive, boLinearAdd, boColorDodge, boDivide, boNiceGlow, boSoftLight, boHardLight, //lighting … … 146 181 end; 147 182 183 TArcDef = record 184 center: TPointF; 185 radius: TPointF; 186 xAngleRadCW, startAngleRadCW, endAngleRadCW: single; //see convention in BGRAPath 187 anticlockwise: boolean 188 end; 189 PArcDef = ^TArcDef; 190 148 191 TPoint3D = record 149 192 x,y,z: single; 150 193 end; 194 195 TBGRAArrowStyle = (asNone, asNormal, asCut, asTriangle, asHollowTriangle, asFlipped, asFlippedCut, asTail, asTailRepeat); 151 196 152 197 TBGRATypeWriterAlignment = (twaTopLeft, twaTop, twaTopRight, … … 169 214 function BezierCurve(origin, control1, control2, destination: TPointF) : TCubicBezierCurve; overload; 170 215 function BezierCurve(origin, control, destination: TPointF) : TQuadraticBezierCurve; overload; 216 function BezierCurve(origin, destination: TPointF) : TQuadraticBezierCurve; overload; 217 function ArcDef(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean) : TArcDef; 171 218 172 219 { Useful constants } … … 184 231 clBlackOpaque = TColor($010000); 185 232 233 {$DEFINE INCLUDE_COLOR_CONST} 186 234 {$i csscolorconst.inc} 187 235 … … 204 252 public 205 253 constructor Create; 206 procedure Add(Name: string; Color: TBGRAPixel);254 procedure Add(Name: string; const Color: TBGRAPixel); 207 255 procedure Finished; 208 256 function IndexOf(Name: string): integer; 257 function IndexOfColor(const AColor: TBGRAPixel; AMaxDiff: Word = 0): integer; 209 258 210 259 property ByName[Name: string]: TBGRAPixel read GetByName; … … 215 264 216 265 var 217 CSSColors: TBGRAColorList;266 VGAColors, CSSColors: TBGRAColorList; 218 267 219 268 function isEmptyPointF(pt: TPointF): boolean; … … 236 285 end; 237 286 287 { A path is the ability to define a contour with moveTo, lineTo... 288 It must not implement reference counting. } 289 IBGRAPath = interface 290 procedure closePath; 291 procedure moveTo(const pt: TPointF); 292 procedure lineTo(const pt: TPointF); 293 procedure polylineTo(const pts: array of TPointF); 294 procedure quadraticCurveTo(const cp,pt: TPointF); 295 procedure bezierCurveTo(const cp1,cp2,pt: TPointF); 296 procedure arc(const arcDef: TArcDef); 297 procedure copyTo(dest: IBGRAPath); 298 end; 299 238 300 TScanAtFunction = function (X,Y: Single): TBGRAPixel of object; 239 301 TScanAtIntegerFunction = function (X,Y: Integer): TBGRAPixel of object; 240 302 TScanNextPixelFunction = function: TBGRAPixel of object; 241 303 TBGRACustomGradient = class; 304 305 TBGRACustomFillInfo = class; 306 TBGRACustomFontRenderer = class; 242 307 243 308 { TBGRACustomBitmap } … … 249 314 protected 250 315 { accessors to properies } 316 function GetArrowEndRepeat: integer; virtual; abstract; 317 function GetArrowStartRepeat: integer; virtual; abstract; 318 procedure SetArrowEndRepeat(AValue: integer); virtual; abstract; 319 procedure SetArrowStartRepeat(AValue: integer); virtual; abstract; 320 function GetArrowEndOffset: single; virtual; abstract; 321 function GetArrowStartOffset: single; virtual; abstract; 322 procedure SetArrowEndOffset(AValue: single); virtual; abstract; 323 procedure SetArrowStartOffset(AValue: single); virtual; abstract; 324 function GetArrowEndSize: TPointF; virtual; abstract; 325 function GetArrowStartSize: TPointF; virtual; abstract; 326 procedure SetArrowEndSize(AValue: TPointF); virtual; abstract; 327 procedure SetArrowStartSize(AValue: TPointF); virtual; abstract; 328 function GetLineCap: TPenEndCap; virtual; abstract; 329 procedure SetLineCap(AValue: TPenEndCap); virtual; abstract; 330 function GetFontRenderer: TBGRACustomFontRenderer; virtual; abstract; 331 procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); virtual; abstract; 251 332 function GetHeight: integer; virtual; abstract; 252 333 function GetWidth: integer; virtual; abstract; … … 280 361 procedure SetClipRect(const AValue: TRect); virtual; abstract; 281 362 function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; 282 function LoadAsBmp32(Str: TStream): boolean; virtual; abstract; 363 procedure ClearTransparentPixels; virtual; abstract; 364 procedure SetArrowStart(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); virtual; abstract; 365 procedure SetArrowEnd(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); virtual; abstract; 283 366 284 367 public 285 368 Caption: string; //user defined caption 286 369 287 //font style 288 FontName: string; 289 FontStyle: TFontStyles; 290 FontQuality : TBGRAFontQuality; 291 FontOrientation: integer; 370 {-------------------font style------------------------} 371 FontName: string; //Specifies the font to use. Unless the font renderer accept otherwise, 372 //the name is in human readable form, like 'Arial', 'Times New Roman', ... 373 374 FontStyle: TFontStyles; //Specifies the set of styles to be applied to the font. 375 //These can be fsBold, fsItalic, fsStrikeOut, fsUnderline. 376 //So the value [fsBold,fsItalic] means that the font must be bold and italic. 377 378 FontQuality : TBGRAFontQuality;//Specifies the quality of rendering. Default value is fqSystem. 379 380 FontOrientation: integer; //Specifies the rotation of the text, for functions that support text rotation. 381 //It is expressed in tenth of degrees, positive values going counter-clockwise. 292 382 293 383 //line style 294 LineCap: TPenEndCap;295 384 JoinStyle: TPenJoinStyle; 296 385 JoinMiterLimit: single; 297 386 298 387 FillMode: TFillMode; //winding or alternate 388 LinearAntialiasing: boolean; 299 389 300 390 { The resample filter is used when resizing the bitmap, and … … 310 400 constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); virtual; abstract; overload; 311 401 constructor Create(AFilename: string); virtual; abstract; overload; 402 constructor Create(AFilename: string; AIsUtf8Filename: boolean); virtual; abstract; overload; 312 403 constructor Create(AStream: TStream); virtual; abstract; overload; 313 404 … … 315 406 function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; virtual; abstract; overload; 316 407 function NewBitmap(Filename: string): TBGRACustomBitmap; virtual; abstract; overload; 317 408 function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; virtual; abstract; overload; 409 410 //there are UTF8 functions that are different from standard function as those 411 //depend on TFPCustomImage that does not clearly handle UTF8 318 412 procedure LoadFromFile(const filename: string); virtual; 319 procedure LoadFromStream(Str: TStream); virtual; 320 procedure LoadFromStream(Str: TStream; Handler: TFPCustomImageReader); virtual; 321 procedure SaveToFile(const filename: string); virtual; 322 procedure SaveToFile(const filename: string; Handler:TFPCustomImageWriter); virtual; 413 procedure LoadFromFileUTF8(const filenameUTF8: string); virtual; 414 procedure LoadFromFileUTF8(const filenameUTF8: string; AHandler: TFPCustomImageReader); virtual; 415 procedure LoadFromStream(Str: TStream); virtual; overload; 416 procedure LoadFromStream(Str: TStream; Handler: TFPCustomImageReader); virtual; overload; 417 procedure SaveToFile(const filename: string); virtual; overload; 418 procedure SaveToFile(const filename: string; Handler:TFPCustomImageWriter); virtual; overload; 419 procedure SaveToFileUTF8(const filenameUTF8: string); virtual; overload; 420 procedure SaveToFileUTF8(const filenameUTF8: string; Handler:TFPCustomImageWriter); virtual; overload; 323 421 procedure SaveToStreamAsPng(Str: TStream); virtual; abstract; 324 procedure Assign(ABitmap: TBitmap); virtual; abstract; overload; 422 procedure SaveToStreamAs(Str: TStream; AFormat: TBGRAImageFormat); virtual; 423 procedure Assign(ARaster: TRasterImage); virtual; abstract; overload; 325 424 procedure Assign(MemBitmap: TBGRACustomBitmap); virtual; abstract; overload; 326 425 procedure Serialize(AStream: TStream); virtual; abstract; … … 328 427 329 428 {Pixel functions} 330 procedure SetPixel(x, y: integer; c: TColor); virtual; abstract; overload; 331 procedure XorPixel(x, y: integer; c: TBGRAPixel); virtual; abstract; overload; 332 procedure SetPixel(x, y: integer; c: TBGRAPixel); virtual; abstract; overload; 333 procedure DrawPixel(x, y: integer; c: TBGRAPixel); virtual; abstract; overload; 334 procedure DrawPixel(x, y: integer; ec: TExpandedPixel); virtual; abstract; overload; 335 procedure FastBlendPixel(x, y: integer; c: TBGRAPixel); virtual; abstract; 336 procedure ErasePixel(x, y: integer; alpha: byte); virtual; abstract; 337 procedure AlphaPixel(x, y: integer; alpha: byte); virtual; abstract; 338 function GetPixel(x, y: integer): TBGRAPixel; virtual; abstract; 339 function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; virtual; abstract; overload; 340 function GetPixelCycle(x, y: integer): TBGRAPixel; virtual; 429 procedure SetPixel(x, y: int32or64; c: TColor); virtual; abstract; overload; 430 procedure XorPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 431 procedure SetPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 432 procedure DrawPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; overload; 433 procedure DrawPixel(x, y: int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload; 434 procedure DrawPixel(x, y: int32or64; ec: TExpandedPixel); virtual; abstract; overload; 435 procedure FastBlendPixel(x, y: int32or64; c: TBGRAPixel); virtual; abstract; 436 procedure ErasePixel(x, y: int32or64; alpha: byte); virtual; abstract; 437 procedure AlphaPixel(x, y: int32or64; alpha: byte); virtual; abstract; 438 function GetPixel(x, y: int32or64): TBGRAPixel; virtual; abstract; overload; 439 function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract; 440 function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; virtual; abstract; overload; 441 function GetPixelCycle(x, y: int32or64): TBGRAPixel; virtual; overload; 341 442 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; virtual; abstract; overload; 342 443 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; virtual; abstract; overload; 444 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; virtual; abstract; overload; 445 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; virtual; abstract; overload; 343 446 344 447 {Line primitives} 345 procedure SetHorizLine(x, y, x2: integer; c: TBGRAPixel); virtual; abstract; 346 procedure XorHorizLine(x, y, x2: integer; c: TBGRAPixel); virtual; abstract; 347 procedure DrawHorizLine(x, y, x2: integer; c: TBGRAPixel); virtual; abstract; overload; 348 procedure DrawHorizLine(x, y, x2: integer; ec: TExpandedPixel); virtual; abstract; overload; 349 procedure DrawHorizLine(x, y, x2: integer; texture: IBGRAScanner); virtual; abstract; overload; 350 procedure FastBlendHorizLine(x, y, x2: integer; c: TBGRAPixel); virtual; abstract; 351 procedure AlphaHorizLine(x, y, x2: integer; alpha: byte); virtual; abstract; 352 procedure SetVertLine(x, y, y2: integer; c: TBGRAPixel); virtual; abstract; 353 procedure XorVertLine(x, y, y2: integer; c: TBGRAPixel); virtual; abstract; 354 procedure DrawVertLine(x, y, y2: integer; c: TBGRAPixel); virtual; abstract; 355 procedure AlphaVertLine(x, y, y2: integer; alpha: byte); virtual; abstract; 356 procedure FastBlendVertLine(x, y, y2: integer; c: TBGRAPixel); virtual; abstract; 357 procedure DrawHorizLineDiff(x, y, x2: integer; c, compare: TBGRAPixel; 358 maxDiff: byte); virtual; abstract; 448 procedure SetHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 449 procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 450 procedure DrawHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; overload; 451 procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); virtual; abstract; overload; 452 procedure DrawHorizLine(x, y, x2: int32or64; texture: IBGRAScanner); overload; 453 procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); virtual; abstract; 454 procedure AlphaHorizLine(x, y, x2: int32or64; alpha: byte); virtual; abstract; 455 procedure SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 456 procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 457 procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 458 procedure AlphaVertLine(x, y, y2: int32or64; alpha: byte); virtual; abstract; 459 procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); virtual; abstract; 460 procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel; maxDiff: byte); virtual; abstract; 461 procedure HorizLine(x,y,x2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); overload; 462 procedure VertLine(x,y,y2: Int32or64; c: TBGRAPixel; ADrawMode: TDrawMode); 463 procedure HorizLine(x,y,x2: Int32or64; texture: IBGRAScanner; ADrawMode: TDrawMode); virtual; abstract; overload; 359 464 360 465 {Shapes} 361 procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); virtual; abstract; 466 procedure DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single); virtual; abstract; 467 procedure DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single); virtual; abstract; 468 469 procedure ArrowStartAsNone; 470 procedure ArrowStartAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); 471 procedure ArrowStartAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); 472 procedure ArrowStartAsTail; 473 474 procedure ArrowEndAsNone; 475 procedure ArrowEndAsClassic(AFlipped: boolean = false; ACut: boolean = false; ARelativePenWidth: single = 1); 476 procedure ArrowEndAsTriangle(ABackOffset: single = 0; ARounded: boolean = false; AHollow: boolean = false; AHollowPenWidth: single = 0.5); 477 procedure ArrowEndAsTail; 478 479 procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode= dmDrawWithTransparency); virtual; abstract; 362 480 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); virtual; abstract; overload; 363 481 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); virtual; abstract; overload; … … 368 486 procedure DrawLineAntialias(x1, y1, x2, y2: single; texture: IBGRAScanner; w: single; Closed: boolean); virtual; abstract; overload; 369 487 488 procedure DrawPolyLine(const points: array of TPoint; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode=dmDrawWithTransparency); 370 489 procedure DrawPolyLineAntialias(const points: array of TPoint; c: TBGRAPixel; DrawLastPixel: boolean); virtual; overload; 371 490 procedure DrawPolyLineAntialias(const points: array of TPoint; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); virtual; overload; … … 373 492 procedure DrawPolyLineAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); virtual; abstract; overload; 374 493 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; Closed: boolean); virtual; abstract; overload; 494 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); virtual; abstract; overload; 495 procedure DrawPolygon(const points: array of TPoint; c: TBGRAPixel; ADrawMode: TDrawMode=dmDrawWithTransparency); 496 procedure DrawPolygonAntialias(const points: array of TPoint; c: TBGRAPixel); overload; 375 497 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); virtual; abstract; overload; 376 498 procedure DrawPolygonAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); virtual; abstract; overload; 499 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); virtual; abstract; overload; 377 500 378 501 procedure EraseLine(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); virtual; abstract; … … 380 503 procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single); virtual; abstract; overload; 381 504 procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single; Closed: boolean); virtual; abstract; overload; 505 procedure ErasePolyLine(const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); 506 procedure ErasePolyLineAntialias(const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); overload; 382 507 procedure ErasePolyLineAntialias(const points: array of TPointF; alpha: byte; w: single); virtual; abstract; overload; 508 procedure ErasePolygonOutline(const points: array of TPoint; alpha: byte); 509 procedure ErasePolygonOutlineAntialias(const points: array of TPoint; alpha: byte); 510 511 procedure FillPath(APath: IBGRAPath; c: TBGRAPixel); virtual; abstract; 512 procedure FillPath(APath: IBGRAPath; texture: IBGRAScanner); virtual; abstract; 383 513 384 514 procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); virtual; abstract; overload; … … 394 524 procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 395 525 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 526 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); virtual; abstract; overload; 396 527 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); virtual; abstract; overload; 528 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); virtual; abstract; overload; 397 529 398 530 procedure FillPolyLinearColor(const points: array of TPointF; AColors: array of TBGRAPixel); virtual; abstract; overload; … … 408 540 procedure ErasePoly(const points: array of TPointF; alpha: byte); virtual; abstract; 409 541 procedure ErasePolyAntialias(const points: array of TPointF; alpha: byte); virtual; abstract; 542 543 procedure FillShape(shape: TBGRACustomFillInfo; c: TBGRAPixel; drawmode: TDrawMode); virtual; abstract; 544 procedure FillShape(shape: TBGRACustomFillInfo; texture: IBGRAScanner; drawmode: TDrawMode); virtual; abstract; 545 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; c: TBGRAPixel); virtual; abstract; 546 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; texture: IBGRAScanner); virtual; abstract; 547 procedure EraseShape(shape: TBGRACustomFillInfo; alpha: byte); virtual; abstract; 548 procedure EraseShapeAntialias(shape: TBGRACustomFillInfo; alpha: byte); virtual; abstract; 410 549 411 550 procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single); virtual; abstract; … … 427 566 procedure RectangleAntialias(x, y, x2, y2: single; texture: IBGRAScanner; w: single); virtual; abstract; overload; 428 567 429 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor, FillColor: TBGRAPixel); virtual; abstract; 568 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; abstract; overload; 569 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; abstract; overload; 430 570 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; w: single; options: TRoundRectangleOptions = []); virtual; abstract; 431 571 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; pencolor: TBGRAPixel; w: single; fillcolor: TBGRAPixel; options: TRoundRectangleOptions = []); virtual; abstract; 432 572 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); virtual; abstract; 433 573 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; w: single; options: TRoundRectangleOptions = []); virtual; abstract; 574 procedure FillRoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; 434 575 procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; c: TBGRAPixel; options: TRoundRectangleOptions = []); virtual; abstract; 435 576 procedure FillRoundRectAntialias(x,y,x2,y2,rx,ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions = []); virtual; abstract; 436 577 procedure EraseRoundRectAntialias(x,y,x2,y2,rx,ry: single; alpha: byte; options: TRoundRectangleOptions = []); virtual; abstract; 437 578 579 procedure EllipseInRect(r: TRect; BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; overload; 580 procedure EllipseInRect(r: TRect; BorderColor,FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; overload; 581 procedure FillEllipseInRect(r: TRect; FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); virtual; 582 438 583 procedure FillRect(r: TRect; c: TColor); virtual; overload; 439 584 procedure FillRect(r: TRect; c: TBGRAPixel; mode: TDrawMode); virtual; overload; 585 procedure FillRect(r: TRect; texture: IBGRAScanner; mode: TDrawMode); virtual; overload; 440 586 procedure FillRect(x, y, x2, y2: integer; c: TColor); virtual; overload; 441 587 procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); virtual; abstract; overload; 442 procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); virtual; abstract; 588 procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); virtual; abstract; overload; 443 589 procedure FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel); virtual; abstract; 444 590 procedure FillRectAntialias(x, y, x2, y2: single; texture: IBGRAScanner); virtual; abstract; … … 446 592 procedure AlphaFillRect(x, y, x2, y2: integer; alpha: byte); virtual; abstract; 447 593 448 procedure TextOut(x, y: single; s: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; overload; 449 procedure TextOut(x, y: single; s: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; overload; 450 procedure TextOutAngle(x, y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 451 procedure TextOutAngle(x, y: single; orientation: integer; s: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 452 procedure TextOut(x, y: single; s: string; c: TBGRAPixel); virtual; overload; 453 procedure TextOut(x, y: single; s: string; c: TColor); virtual; overload; 454 procedure TextOut(x, y: single; s: string; texture: IBGRAScanner); virtual; overload; 455 procedure TextRect(ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; overload; 456 procedure TextRect(ARect: TRect; x, y: integer; s: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; overload; 457 procedure TextRect(ARect: TRect; s: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); virtual; overload; 458 procedure TextRect(ARect: TRect; s: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); virtual; overload; 459 function TextSize(s: string): TSize; virtual; abstract; 594 procedure TextOut(x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; overload; 595 procedure TextOut(x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; overload; 596 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 597 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 598 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; overload; 599 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; overload; 600 function TextSize(sUTF8: string): TSize; virtual; abstract; 601 602 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c or texture is used to fill the text. 603 The value of FontOrientation is taken into account, so that the text may be rotated. } 604 procedure TextOut(x, y: single; sUTF8: string; c: TBGRAPixel); virtual; overload; 605 procedure TextOut(x, y: single; sUTF8: string; c: TColor); virtual; overload; 606 procedure TextOut(x, y: single; sUTF8: string; texture: IBGRAScanner); virtual; overload; 607 608 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 609 The position depends on the specified horizontal alignment halign and vertical alignement valign. 610 The color c or texture is used to fill the text. No rotation is applied. } 611 procedure TextRect(ARect: TRect; sUTF8: string; halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); virtual; overload; 612 procedure TextRect(ARect: TRect; sUTF8: string; halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); virtual; overload; 460 613 461 614 {Spline} … … 494 647 procedure AlphaFill(alpha: byte); virtual; overload; 495 648 procedure AlphaFill(alpha: byte; start, Count: integer); virtual; abstract; overload; 496 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel); virtual; abstract; overload; 497 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner); virtual; abstract; overload; 649 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel); virtual; overload; 650 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner); virtual; overload; 651 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ADrawMode: TDrawMode); virtual; abstract; overload; 652 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ADrawMode: TDrawMode); virtual; abstract; overload; 498 653 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); virtual; abstract; overload; 499 654 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); virtual; abstract; overload; … … 529 684 530 685 {BGRA bitmap functions} 686 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); virtual; abstract; 687 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); virtual; abstract; 531 688 procedure PutImage(x, y: integer; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); virtual; abstract; 689 procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); virtual; abstract; 532 690 procedure PutImageSubpixel(x, y: single; Source: TBGRACustomBitmap); 533 691 procedure PutImagePart(x,y: integer; Source: TBGRACustomBitmap; SourceRect: TRect; mode: TDrawMode; AOpacity: byte = 255); 534 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255); virtual; abstract; 535 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); virtual; abstract; 692 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; 693 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255); overload; 694 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); virtual; abstract; overload; 695 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload; 696 function GetImageAffineBounds(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap): TRect; 697 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload; 698 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false; ACorrectBlur: Boolean = false); overload; 699 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload; 700 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); overload; 701 procedure ComputeImageAngleAxes(x,y,w,h,angle: single; imageCenterX,imageCenterY: single; ARestoreOffsetAfterRotation: boolean; 702 out Origin,HAxis,VAxis: TPointF); 703 function GetImageAngleBounds(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; ARestoreOffsetAfterRotation: boolean = false): TRect; 536 704 procedure BlendImage(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation); virtual; abstract; 537 705 procedure BlendImageOver(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation; AOpacity: byte = 255; … … 542 710 function Resample(newWidth, newHeight: integer; 543 711 mode: TResampleMode = rmFineResample): TBGRACustomBitmap; virtual; abstract; 544 procedure VerticalFlip; virtual; abstract; 545 procedure HorizontalFlip; virtual; abstract; 712 procedure VerticalFlip; virtual; overload; 713 procedure VerticalFlip(ARect: TRect); virtual; abstract; overload; 714 procedure HorizontalFlip; virtual; overload; 715 procedure HorizontalFlip(ARect: TRect); virtual; abstract; overload; 546 716 function RotateCW: TBGRACustomBitmap; virtual; abstract; 547 717 function RotateCCW: TBGRACustomBitmap; virtual; abstract; 548 718 procedure Negative; virtual; abstract; 719 procedure NegativeRect(ABounds: TRect); virtual; abstract; 549 720 procedure LinearNegative; virtual; abstract; 721 procedure LinearNegativeRect(ABounds: TRect); virtual; abstract; 722 procedure InplaceGrayscale; virtual; abstract; 723 procedure InplaceGrayscale(ABounds: TRect); virtual; abstract; 550 724 procedure ConvertToLinearRGB; virtual; abstract; 551 725 procedure ConvertFromLinearRGB; virtual; abstract; … … 553 727 procedure GrayscaleToAlpha; virtual; abstract; 554 728 procedure AlphaToGrayscale; virtual; abstract; 555 procedure ApplyMask(mask: TBGRACustomBitmap); virtual; abstract; 729 procedure ApplyMask(mask: TBGRACustomBitmap); overload; 730 procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect); overload; 731 procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); virtual; abstract; overload; 556 732 function GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; virtual; abstract; 557 function GetImageBounds(Channels: TChannels ): TRect; virtual; abstract;733 function GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect; virtual; abstract; 558 734 function GetDifferenceBounds(ABitmap: TBGRACustomBitmap): TRect; virtual; abstract; 559 735 function MakeBitmapCopy(BackgroundColor: TColor): TBitmap; virtual; abstract; … … 563 739 function FilterMedian(Option: TMedianOption): TBGRACustomBitmap; virtual; abstract; 564 740 function FilterSmooth: TBGRACustomBitmap; virtual; abstract; 565 function FilterSharpen: TBGRACustomBitmap; virtual; abstract; 741 function FilterSharpen(Amount: single = 1): TBGRACustomBitmap; virtual; abstract; 742 function FilterSharpen(ABounds: TRect; Amount: single = 1): TBGRACustomBitmap; virtual; abstract; 566 743 function FilterContour: TBGRACustomBitmap; virtual; abstract; 744 function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; virtual; abstract; 567 745 function FilterBlurRadial(radius: integer; 568 746 blurType: TRadialBlurType): TBGRACustomBitmap; virtual; abstract; 569 function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; virtual; abstract; 747 function FilterBlurRadial(ABounds: TRect; radius: integer; 748 blurType: TRadialBlurType): TBGRACustomBitmap; virtual; abstract; 570 749 function FilterBlurMotion(distance: integer; angle: single; 571 750 oriented: boolean): TBGRACustomBitmap; virtual; abstract; 751 function FilterBlurMotion(ABounds: TRect; distance: integer; angle: single; 752 oriented: boolean): TBGRACustomBitmap; virtual; abstract; 572 753 function FilterCustomBlur(mask: TBGRACustomBitmap): TBGRACustomBitmap; virtual; abstract; 754 function FilterCustomBlur(ABounds: TRect; mask: TBGRACustomBitmap): TBGRACustomBitmap; virtual; abstract; 573 755 function FilterEmboss(angle: single): TBGRACustomBitmap; virtual; abstract; 756 function FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap; virtual; abstract; 574 757 function FilterEmbossHighlight(FillSelection: boolean): TBGRACustomBitmap; virtual; abstract; 575 758 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel): TBGRACustomBitmap; virtual; abstract; 576 759 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; var Offset: TPoint): TBGRACustomBitmap; virtual; abstract; 577 760 function FilterGrayscale: TBGRACustomBitmap; virtual; abstract; 761 function FilterGrayscale(ABounds: TRect): TBGRACustomBitmap; virtual; abstract; 578 762 function FilterNormalize(eachChannel: boolean = True): TBGRACustomBitmap; virtual; abstract; 579 function FilterRotate(origin: TPointF; angle: single): TBGRACustomBitmap; virtual; abstract; 763 function FilterNormalize(ABounds: TRect; eachChannel: boolean = True): TBGRACustomBitmap; virtual; abstract; 764 function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false): TBGRACustomBitmap; virtual; abstract; 580 765 function FilterSphere: TBGRACustomBitmap; virtual; abstract; 581 766 function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; virtual; abstract; 767 function FilterTwirl(ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; virtual; abstract; 582 768 function FilterCylinder: TBGRACustomBitmap; virtual; abstract; 583 769 function FilterPlane: TBGRACustomBitmap; virtual; abstract; 584 770 585 property Data: PBGRAPixel Read GetDataPtr; 586 property Width: integer Read GetWidth; 587 property Height: integer Read GetHeight; 588 property NbPixels: integer Read GetNbPixels; 589 property Empty: boolean Read CheckEmpty; 590 591 property ScanLine[y: integer]: PBGRAPixel Read GetScanLine; 771 property Width: integer Read GetWidth; //width of the image in pixels 772 property Height: integer Read GetHeight; //height of the image in pixels 773 property NbPixels: integer Read GetNbPixels; //total number of pixels. It is always true that NbPixels = Width * Height 774 775 property ScanLine[y: integer]: PBGRAPixel Read GetScanLine; //Returns the address of the left-most pixel of any line. 776 //The parameter y ranges from 0 to Height-1. 777 778 property LineOrder: TRawImageLineOrder Read GetLineOrder; //Indicates the order in which lines are stored in memory. 779 //If it is equal to riloTopToBottom, the first line is the top line. 780 //If it is equal to riloBottomToTop, the first line is the bottom line. 781 782 property Data: PBGRAPixel Read GetDataPtr; //Provides a pointer to the first pixel in memory. 783 //Depending on the LineOrder property, this can be the top-left pixel or the bottom-left pixel. 784 //There is no padding between scanlines, so the start of the next line is at the address Data + Width. 785 786 property Empty: boolean Read CheckEmpty; //Returns True if the bitmap only contains transparent pixels or has a size of zero. 787 788 property HasTransparentPixels: boolean Read GetHasTransparentPixels; //Returns True if there are transparent or semitransparent pixels, 789 //and so if the image would be stored with an alpha channel. 790 592 791 property RefCount: integer Read GetRefCount; 593 792 property Bitmap: TBitmap Read GetBitmap; //don't forget to call InvalidateBitmap before if you changed something with Scanline 594 property HasTransparentPixels: boolean Read GetHasTransparentPixels;595 793 property AverageColor: TColor Read GetAverageColor; 596 794 property AveragePixel: TBGRAPixel Read GetAveragePixel; 597 property LineOrder: TRawImageLineOrder Read GetLineOrder;598 795 property CanvasFP: TFPImageCanvas read GetCanvasFP; 599 796 property CanvasDrawModeFP: TDrawMode read GetCanvasDrawModeFP write SetCanvasDrawModeFP; … … 603 800 Read GetCanvasAlphaCorrection Write SetCanvasAlphaCorrection; 604 801 605 property FontHeight: integer Read GetFontHeight Write SetFontHeight;606 802 property PenStyle: TPenStyle read GetPenStyle Write SetPenStyle; 607 803 property CustomPenStyle: TBGRAPenStyle read GetCustomPenStyle write SetCustomPenStyle; 608 804 property ClipRect: TRect read GetClipRect write SetClipRect; 609 property FontAntialias: Boolean read GetFontAntialias write SetFontAntialias; //antialiasing (it's different from TFont antialiasing mode) 805 806 { Specifies the height of the font without taking into account additional line spacing. 807 A negative value means that it is the full height instead (see below). } 808 property FontHeight: integer Read GetFontHeight Write SetFontHeight; 809 810 { Specifies the height of the font, taking into account the additional line spacing defined for the font. } 610 811 property FontFullHeight: integer read GetFontFullHeight write SetFontFullHeight; 611 property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric; 612 613 //interface 614 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 615 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 616 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 812 813 property FontAntialias: Boolean read GetFontAntialias write SetFontAntialias; //Simplified property to specify the quality. 814 property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric; //Returns measurement for the current font in pixels. 815 816 { Specifies the font renderer. By default it is an instance of TLCLFontRenderer of unit BGRAText. 817 Other renderers are provided in BGRATextFX unit and BGRAVectorize unit. 818 Once you assign a renderer, it will automatically be freed. 819 The renderers may provide additional styling for the font. } 820 property FontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer; 821 822 property LineCap: TPenEndCap read GetLineCap write SetLineCap; 823 property ArrowStartSize: TPointF read GetArrowStartSize write SetArrowStartSize; 824 property ArrowEndSize: TPointF read GetArrowEndSize write SetArrowEndSize; 825 property ArrowStartOffset: single read GetArrowStartOffset write SetArrowStartOffset; 826 property ArrowEndOffset: single read GetArrowEndOffset write SetArrowEndOffset; 827 property ArrowStartRepeat: integer read GetArrowStartRepeat write SetArrowStartRepeat; 828 property ArrowEndRepeat: integer read GetArrowEndRepeat write SetArrowEndRepeat; 617 829 618 830 //IBGRAScanner … … 623 835 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); virtual; 624 836 function IsScanPutPixelsDefined: boolean; virtual; 837 838 protected 839 //interface 840 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 841 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 842 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 843 625 844 end; 626 845 … … 637 856 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); virtual; 638 857 function IsScanPutPixelsDefined: boolean; virtual; 858 protected 639 859 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 640 860 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; … … 653 873 end; 654 874 875 { TIntersectionInfo } 876 877 TIntersectionInfo = class 878 interX: single; 879 winding: integer; 880 numSegment: integer; 881 procedure SetValues(AInterX: Single; AWinding, ANumSegment: integer); 882 end; 883 ArrayOfTIntersectionInfo = array of TIntersectionInfo; 884 885 TBGRACustomFillInfo = class 886 public 887 //returns true if the same segment number can be curved 888 function SegmentsCurved: boolean; virtual; abstract; 889 890 //returns integer bounds 891 function GetBounds: TRect; virtual; abstract; 892 893 //compute min-max to be drawn on destination bitmap according to cliprect. Returns false if 894 //there is nothing to draw 895 function ComputeMinMax(out minx,miny,maxx,maxy: integer; bmpDest: TBGRACustomBitmap): boolean; virtual; abstract; 896 897 //check if the point is inside the filling zone 898 function IsPointInside(x,y: single; windingMode: boolean): boolean; virtual; abstract; 899 900 //create an array that will contain computed intersections. 901 //you may augment, in this case, use CreateIntersectionInfo for new items 902 function CreateIntersectionArray: ArrayOfTIntersectionInfo; virtual; abstract; 903 function CreateIntersectionInfo: TIntersectionInfo; virtual; abstract; //creates a single info 904 procedure FreeIntersectionArray(var inter: ArrayOfTIntersectionInfo); virtual; abstract; 905 906 //fill a previously created array of intersections with actual intersections at the current y coordinate. 907 //nbInter gets the number of computed intersections 908 procedure ComputeAndSort(cury: single; var inter: ArrayOfTIntersectionInfo; out nbInter: integer; windingMode: boolean); virtual; abstract; 909 end; 910 911 { TBGRACustomFontRenderer } 912 913 TBGRACustomFontRenderer = class 914 FontName: string; //Specifies the font to use. Unless the font renderer accept otherwise, 915 //the name is in human readable form, like 'Arial', 'Times New Roman', ... 916 917 FontStyle: TFontStyles; //Specifies the set of styles to be applied to the font. 918 //These can be fsBold, fsItalic, fsStrikeOut, fsUnderline. 919 //So the value [fsBold,fsItalic] means that the font must be bold and italic. 920 921 FontQuality : TBGRAFontQuality;//Specifies the quality of rendering. Default value is fqSystem. 922 923 FontOrientation: integer; //Specifies the rotation of the text, for functions that support text rotation. 924 //It is expressed in tenth of degrees, positive values going counter-clockwise. 925 926 FontEmHeight: integer; // Specifies the height of the font without taking into account additional line spacing. 927 // A negative value means that it is the full height instead. 928 929 { Returns measurement for the current font in pixels. } 930 function GetFontPixelMetric: TFontPixelMetric; virtual; abstract; 931 932 { Returns the total size of the string provided using the current font. 933 Orientation is not taken into account, so that the width is along the text. } 934 function TextSize(sUTF8: string): TSize; virtual; abstract; 935 936 { Draws the UTF8 encoded string, with color c. 937 If align is taLeftJustify, (x,y) is the top-left corner. 938 If align is taCenter, (x,y) is at the top and middle of the text. 939 If align is taRightJustify, (x,y) is the top-right corner. 940 The value of FontOrientation is taken into account, so that the text may be rotated. } 941 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 942 943 { Same as above functions, except that the text is filled using texture. 944 The value of FontOrientation is taken into account, so that the text may be rotated. } 945 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 946 947 { Same as above, except that the orientation is specified, overriding the value of the property FontOrientation. } 948 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract; 949 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract; 950 951 { Draw the UTF8 encoded string at the coordinate (x,y), clipped inside the rectangle ARect. 952 Additional style information is provided by the style parameter. 953 The color c or texture is used to fill the text. No rotation is applied. } 954 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract; 955 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract; 956 957 { Copy the path for the UTF8 encoded string into ADest. 958 If align is taLeftJustify, (x,y) is the top-left corner. 959 If align is taCenter, (x,y) is at the top and middle of the text. 960 If align is taRightJustify, (x,y) is the top-right corner. } 961 procedure CopyTextPathTo({%H-}ADest: IBGRAPath; {%H-}x, {%H-}y: single; {%H-}s: string; {%H-}align: TAlignment); virtual; //optional 962 end; 963 655 964 type 656 965 TBGRABitmapAny = class of TBGRACustomBitmap; //used to create instances of the same type (see NewBitmap) 966 TBGRATextOutImproveReadabilityMode = (irMask, irNormal, irClearTypeRGB, irClearTypeBGR); 657 967 658 968 var 659 969 BGRABitmapFactory : TBGRABitmapAny; 970 BGRATextOutImproveReadabilityProc : procedure (bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; mode : TBGRATextOutImproveReadabilityMode); 971 972 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, maxyb, ignoreleft: integer; const cliprect: TRect): boolean; inline; 660 973 661 974 { Color functions } 662 function GetIntensity(c: TExpandedPixel): word; inline; 663 function SetIntensity(c: TExpandedPixel; intensity: word): TExpandedPixel; 664 function GetLightness(c: TExpandedPixel): word; inline; 665 function SetLightness(c: TExpandedPixel; lightness: word): TExpandedPixel; 975 function GetIntensity(const c: TExpandedPixel): word; inline; 976 function GetIntensity(c: TBGRAPixel): word; inline; 977 function SetIntensity(const c: TExpandedPixel; intensity: word): TExpandedPixel; 978 function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel; 979 function GetLightness(c: TBGRAPixel): word; 980 function GetLightness(const c: TExpandedPixel): word; inline; 981 function SetLightness(const c: TExpandedPixel; lightness: word): TExpandedPixel; 982 function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel; 983 function SetLightness(const c: TExpandedPixel; lightness: word; curLightness: word): TExpandedPixel; //if you already know the current lightness of the color 666 984 function ApplyLightnessFast(color: TBGRAPixel; lightness: word): TBGRAPixel; inline; 667 985 function ApplyIntensityFast(color: TBGRAPixel; lightness: longword): TBGRAPixel; 668 function CombineLightness(lightness1,lightness2: integer): integer;986 function CombineLightness(lightness1,lightness2: Int32or64): Int32or64; 669 987 function BGRAToHSLA(c: TBGRAPixel): THSLAPixel; 670 function ExpandedToHSLA(ec: TExpandedPixel): THSLAPixel; inline; 671 function BGRAToGSBA(c: TBGRAPixel): THSLAPixel; 672 function HSLAToExpanded(c: THSLAPixel): TExpandedPixel; 673 function HSLAToBGRA(c: THSLAPixel): TBGRAPixel; 988 function ExpandedToHSLA(const ec: TExpandedPixel): THSLAPixel; 989 function ExpandedToGSBA(ec: TExpandedPixel): TGSBAPixel; 990 function BGRAToGSBA(c: TBGRAPixel): TGSBAPixel; 991 function HSLAToExpanded(const c: THSLAPixel): TExpandedPixel; 992 function HSLAToBGRA(const c: THSLAPixel): TBGRAPixel; 674 993 function GtoH(ghue: word): word; 675 994 function HtoG(hue: word): word; … … 677 996 function GetHue(ec: TExpandedPixel): word; 678 997 function ColorImportance(ec: TExpandedPixel): word; 679 function GSBAToBGRA(c: THSLAPixel): TBGRAPixel; 680 function GSBAToHSLA(c: THSLAPixel): THSLAPixel; 998 function GSBAToBGRA(c: TGSBAPixel): TBGRAPixel; 999 function GSBAToExpanded(c: TGSBAPixel): TExpandedPixel; 1000 function GSBAToHSLA(c: TGSBAPixel): THSLAPixel; 681 1001 function GammaExpansion(c: TBGRAPixel): TExpandedPixel; inline; 682 function GammaCompression( ec: TExpandedPixel): TBGRAPixel; inline;1002 function GammaCompression(const ec: TExpandedPixel): TBGRAPixel; inline; 683 1003 function GammaCompression(red,green,blue,alpha: word): TBGRAPixel; inline; 684 1004 function BGRAToGrayscale(c: TBGRAPixel): TBGRAPixel; … … 707 1027 operator * (const c1: TColorF; factor: single): TColorF; inline; 708 1028 function ColorF(red,green,blue,alpha: single): TColorF; 709 function BGRAToStr(c: TBGRAPixel): string; 710 function StrToBGRA(str: string): TBGRAPixel; 711 function StrToBGRA(str: string; DefaultColor: TBGRAPixel): TBGRAPixel; 1029 function BGRAToStr(c: TBGRAPixel; AColorList: TBGRAColorList = nil; AMaxDiff: Word= 0): string; 1030 function StrToBGRA(str: string): TBGRAPixel; //full parse 1031 function StrToBGRA(str: string; const DefaultColor: TBGRAPixel): TBGRAPixel; //full parse with default when error or missing values 1032 function PartialStrToBGRA(str: string; const fallbackValues: TBGRAPixel; out error: boolean): TBGRAPixel; //partial parse allowed 1033 procedure TryStrToBGRA(str: string; var parsedValue: TBGRAPixel; out missingValues: boolean; out error: boolean); 712 1034 713 1035 { Get height [0..1] stored in a TBGRAPixel } … … 736 1058 operator * (const pt1: TPointF; factor: single): TPointF; inline; 737 1059 operator * (factor: single; const pt1: TPointF): TPointF; inline; 738 function PtInRect(pt: TPoint; r: TRect): boolean; 1060 function PtInRect(const pt: TPoint; r: TRect): boolean; overload; 1061 function RectWithSize(left,top,width,height: integer): TRect; 739 1062 function VectLen(dx,dy: single): single; overload; 740 1063 function VectLen(v: TPointF): single; overload; … … 753 1076 754 1077 { Cyclic functions } 755 function PositiveMod(value, cycle: integer): integer; inline;1078 function PositiveMod(value, cycle: Int32or64): Int32or64; inline; overload; 756 1079 757 1080 { Sin65536 and Cos65536 are fast routines to compute sine and cosine as integer values. … … 761 1084 without applying a modulo. } 762 1085 procedure PrecalcSin65536; // compute all values now 763 function Sin65536(value: word): integer; inline;764 function Cos65536(value: word): integer; inline;1086 function Sin65536(value: word): Int32or64; inline; 1087 function Cos65536(value: word): Int32or64; inline; 765 1088 function ByteSqrt(value: byte): byte; inline; 766 1089 1090 function DetectFileFormat(AFilenameUTF8: string): TBGRAImageFormat; 1091 function DetectFileFormat(AStream: TStream; ASuggestedExtensionUTF8: string = ''): TBGRAImageFormat; 1092 function SuggestImageFormat(AFilenameOrExtensionUTF8: string): TBGRAImageFormat; 1093 function CreateBGRAImageReader(AFormat: TBGRAImageFormat): TFPCustomImageReader; 1094 function CreateBGRAImageWriter(AFormat: TBGRAImageFormat; AHasTransparentPixels: boolean): TFPCustomImageWriter; 1095 767 1096 implementation 768 1097 769 uses Math, SysUtils; 1098 uses Math, SysUtils, FileUtil, lazutf8classes, LCLProc, 1099 FPReadTiff, FPReadXwd, FPReadXPM, 1100 FPWriteTiff, FPWriteJPEG, FPWritePNG, FPWriteBMP, FPWritePCX, 1101 FPWriteTGA, FPWriteXPM; 1102 1103 function StrToResampleFilter(str: string): TResampleFilter; 1104 var f: TResampleFilter; 1105 begin 1106 result := rfLinear; 1107 str := LowerCase(str); 1108 for f := low(TResampleFilter) to high(TResampleFilter) do 1109 if CompareText(str,ResampleFilterStr[f])=0 then 1110 begin 1111 result := f; 1112 exit; 1113 end; 1114 end; 770 1115 771 1116 function StrToBlendOperation(str: string): TBlendOperation; … … 937 1282 end; 938 1283 1284 //straight line 1285 function BezierCurve(origin, destination: TPointF): TQuadraticBezierCurve; 1286 begin 1287 result.p1 := origin; 1288 result.c := (origin+destination)*0.5; 1289 result.p2 := destination; 1290 end; 1291 1292 function ArcDef(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; 1293 anticlockwise: boolean): TArcDef; 1294 begin 1295 result.center := PointF(cx,cy); 1296 result.radius := PointF(rx,ry); 1297 result.xAngleRadCW:= xAngleRadCW; 1298 result.startAngleRadCW := startAngleRadCW; 1299 result.endAngleRadCW:= endAngleRadCW; 1300 result.anticlockwise:= anticlockwise; 1301 end; 1302 939 1303 { Check if a PointF structure is empty or should be treated as a list separator } 940 1304 function isEmptyPointF(pt: TPointF): boolean; 941 1305 begin 942 1306 Result := (pt.x = EmptySingle) and (pt.y = EmptySingle); 1307 end; 1308 1309 { TBGRACustomFontRenderer } 1310 1311 procedure TBGRACustomFontRenderer.CopyTextPathTo(ADest: IBGRAPath; x, y: single; s: string; align: TAlignment); 1312 begin 1313 end; 1314 1315 { TIntersectionInfo } 1316 1317 procedure TIntersectionInfo.SetValues(AInterX: Single; AWinding, 1318 ANumSegment: integer); 1319 begin 1320 interX := AInterX; 1321 winding := AWinding; 1322 numSegment := ANumSegment; 943 1323 end; 944 1324 … … 991 1371 end; 992 1372 993 procedure TBGRAColorList.Add(Name: string; Color: TBGRAPixel);1373 procedure TBGRAColorList.Add(Name: string; const Color: TBGRAPixel); 994 1374 begin 995 1375 if FFinished then … … 1021 1401 end; 1022 1402 1403 function TBGRAColorList.IndexOfColor(const AColor: TBGRAPixel; AMaxDiff: Word = 0): integer; 1404 var i: integer; 1405 MinDiff,CurDiff: Word; 1406 begin 1407 if AMaxDiff = 0 then 1408 begin 1409 for i := 0 to FNbColors-1 do 1410 if AColor = FColors[i].Color then 1411 begin 1412 result := i; 1413 exit; 1414 end; 1415 result := -1; 1416 end else 1417 begin 1418 MinDiff := AMaxDiff; 1419 result := -1; 1420 for i := 0 to FNbColors-1 do 1421 begin 1422 CurDiff := BGRAWordDiff(AColor,FColors[i].Color); 1423 if CurDiff <= MinDiff then 1424 begin 1425 result := i; 1426 MinDiff := CurDiff; 1427 if MinDiff = 0 then exit; 1428 end; 1429 end; 1430 end; 1431 end; 1432 1023 1433 { TBGRACustomBitmap } 1024 1434 … … 1039 1449 procedure TBGRACustomBitmap.LoadFromFile(const filename: string); 1040 1450 begin 1041 inherited LoadFromFile(filename); 1451 LoadFromFileUTF8(SysToUtf8(filename)); 1452 end; 1453 1454 procedure TBGRACustomBitmap.LoadFromFileUTF8(const filenameUTF8: string); 1455 var 1456 Stream: TStream; 1457 format: TBGRAImageFormat; 1458 reader: TFPCustomImageReader; 1459 begin 1460 stream := TFileStreamUTF8.Create(filenameUTF8,fmOpenRead or fmShareDenyWrite); 1461 try 1462 format := DetectFileFormat(Stream, ExtractFileExt(filenameUTF8)); 1463 reader := CreateBGRAImageReader(format); 1464 try 1465 LoadFromStream(stream, reader); 1466 finally 1467 reader.Free; 1468 end; 1469 finally 1470 ClearTransparentPixels; 1471 stream.Free; 1472 end; 1473 end; 1474 1475 procedure TBGRACustomBitmap.LoadFromFileUTF8(const filenameUTF8: string; 1476 AHandler: TFPCustomImageReader); 1477 var 1478 Stream: TStream; 1479 begin 1480 stream := TFileStreamUTF8.Create(filenameUTF8,fmOpenRead or fmShareDenyWrite); 1481 try 1482 LoadFromStream(stream, AHandler); 1483 finally 1484 ClearTransparentPixels; 1485 stream.Free; 1486 end; 1042 1487 end; 1043 1488 1044 1489 procedure TBGRACustomBitmap.SaveToFile(const filename: string); 1045 1490 begin 1046 inherited SaveToFile(filename); 1491 SaveToFileUTF8(SysToUtf8(filename)); 1492 end; 1493 1494 procedure TBGRACustomBitmap.SaveToFileUTF8(const filenameUTF8: string); 1495 var 1496 writer: TFPCustomImageWriter; 1497 format: TBGRAImageFormat; 1498 begin 1499 format := SuggestImageFormat(filenameUTF8); 1500 writer := CreateBGRAImageWriter(Format, HasTransparentPixels); 1501 try 1502 SaveToFileUTF8(filenameUTF8, writer); 1503 finally 1504 writer.free; 1505 end; 1047 1506 end; 1048 1507 … … 1050 1509 Handler: TFPCustomImageWriter); 1051 1510 begin 1052 inherited SaveToFile(filename, Handler); 1511 SaveToFileUTF8(SysToUtf8(filename),Handler); 1512 end; 1513 1514 procedure TBGRACustomBitmap.SaveToFileUTF8(const filenameUTF8: string; 1515 Handler: TFPCustomImageWriter); 1516 var 1517 stream: TFileStreamUTF8; 1518 begin 1519 stream := TFileStreamUTF8.Create(filenameUTF8,fmCreate); 1520 try 1521 SaveToStream(stream, Handler); 1522 finally 1523 stream.Free; 1524 end; 1525 end; 1526 1527 procedure TBGRACustomBitmap.SaveToStreamAs(Str: TStream; 1528 AFormat: TBGRAImageFormat); 1529 var handler: TFPCustomImageWriter; 1530 begin 1531 handler := CreateBGRAImageWriter(AFormat, HasTransparentPixels); 1532 try 1533 SaveToStream(Str, handler) 1534 finally 1535 handler.Free; 1536 end; 1537 end; 1538 1539 procedure TBGRACustomBitmap.DrawPixel(x, y: int32or64; c: TBGRAPixel; 1540 ADrawMode: TDrawMode); 1541 begin 1542 case ADrawMode of 1543 dmSet: SetPixel(x,y,c); 1544 dmSetExceptTransparent: if c.alpha = 255 then SetPixel(x,y,c); 1545 dmLinearBlend: FastBlendPixel(x,y,c); 1546 dmDrawWithTransparency: DrawPixel(x,y,c); 1547 dmXor: XorPixel(x,y,c); 1548 end; 1549 end; 1550 1551 procedure TBGRACustomBitmap.LoadFromStream(Str: TStream); 1552 var 1553 format: TBGRAImageFormat; 1554 reader: TFPCustomImageReader; 1555 begin 1556 format := DetectFileFormat(Str); 1557 reader := CreateBGRAImageReader(format); 1558 try 1559 LoadFromStream(Str,reader); 1560 finally 1561 reader.Free; 1562 end; 1053 1563 end; 1054 1564 … … 1057 1567 FP drawing mode is temporarily changed to load 1058 1568 bitmaps properly } 1059 procedure TBGRACustomBitmap.LoadFromStream(Str: TStream);1060 var1061 OldDrawMode: TDrawMode;1062 begin1063 OldDrawMode := CanvasDrawModeFP;1064 CanvasDrawModeFP := dmSet;1065 try1066 if not LoadAsBmp32(Str) then1067 inherited LoadFromStream(Str);1068 finally1069 CanvasDrawModeFP := OldDrawMode;1070 end;1071 end;1072 1073 { See above }1074 1569 procedure TBGRACustomBitmap.LoadFromStream(Str: TStream; 1075 1570 Handler: TFPCustomImageReader); … … 1087 1582 1088 1583 { Look for a pixel considering the bitmap is repeated in both directions } 1089 function TBGRACustomBitmap.GetPixelCycle(x, y: int eger): TBGRAPixel;1584 function TBGRACustomBitmap.GetPixelCycle(x, y: int32or64): TBGRAPixel; 1090 1585 begin 1091 1586 if (Width = 0) or (Height = 0) then … … 1093 1588 else 1094 1589 Result := (Scanline[PositiveMod(y,Height)] + PositiveMod(x,Width))^; 1590 end; 1591 1592 procedure TBGRACustomBitmap.DrawHorizLine(x, y, x2: int32or64; 1593 texture: IBGRAScanner); 1594 begin 1595 HorizLine(x,y,x2,texture,dmDrawWithTransparency); 1596 end; 1597 1598 procedure TBGRACustomBitmap.HorizLine(x, y, x2: Int32or64; c: TBGRAPixel; 1599 ADrawMode: TDrawMode); 1600 begin 1601 case ADrawMode of 1602 dmSet: SetHorizLine(x,y,x2,c); 1603 dmSetExceptTransparent: if c.alpha = 255 then SetHorizLine(x,y,x2,c); 1604 dmXor: XorHorizLine(x,y,x2,c); 1605 dmLinearBlend: FastBlendHorizLine(x,y,x2,c); 1606 dmDrawWithTransparency: DrawHorizLine(x,y,x2,c); 1607 end; 1608 end; 1609 1610 procedure TBGRACustomBitmap.VertLine(x, y, y2: Int32or64; c: TBGRAPixel; 1611 ADrawMode: TDrawMode); 1612 begin 1613 case ADrawMode of 1614 dmSet: SetVertLine(x,y,y2,c); 1615 dmSetExceptTransparent: if c.alpha = 255 then SetVertLine(x,y,y2,c); 1616 dmXor: XorVertLine(x,y,y2,c); 1617 dmLinearBlend: FastBlendVertLine(x,y,y2,c); 1618 dmDrawWithTransparency: DrawVertLine(x,y,y2,c); 1619 end; 1620 end; 1621 1622 procedure TBGRACustomBitmap.ArrowStartAsNone; 1623 begin 1624 SetArrowStart(asNone); 1625 end; 1626 1627 procedure TBGRACustomBitmap.ArrowStartAsClassic(AFlipped: boolean; ACut: boolean; ARelativePenWidth: single); 1628 var join: TPenJoinStyle; 1629 begin 1630 if (LineCap = pecRound) and not ACut then join := pjsRound else join := pjsMiter; 1631 if ACut then 1632 begin 1633 if AFlipped then 1634 SetArrowStart(asFlippedCut,join,ARelativePenWidth) 1635 else 1636 SetArrowStart(asCut,join,ARelativePenWidth) 1637 end 1638 else 1639 begin 1640 if AFlipped then 1641 SetArrowStart(asFlipped,join,ARelativePenWidth) 1642 else 1643 SetArrowStart(asNormal,join,ARelativePenWidth) 1644 end; 1645 end; 1646 1647 procedure TBGRACustomBitmap.ArrowStartAsTriangle(ABackOffset: single; ARounded: boolean; AHollow: boolean; 1648 AHollowPenWidth: single); 1649 var join: TPenJoinStyle; 1650 begin 1651 if ARounded then join := pjsRound else join := pjsMiter; 1652 if AHollow then 1653 SetArrowStart(asHollowTriangle, join,AHollowPenWidth, ABackOffset) 1654 else 1655 SetArrowStart(asTriangle, join,1,ABackOffset); 1656 end; 1657 1658 procedure TBGRACustomBitmap.ArrowStartAsTail; 1659 begin 1660 SetArrowStart(asTail); 1661 end; 1662 1663 procedure TBGRACustomBitmap.ArrowEndAsNone; 1664 begin 1665 SetArrowEnd(asNone); 1666 end; 1667 1668 procedure TBGRACustomBitmap.ArrowEndAsClassic(AFlipped: boolean; ACut: boolean; ARelativePenWidth: single); 1669 var join: TPenJoinStyle; 1670 begin 1671 if (LineCap = pecRound) and not ACut then join := pjsRound else join := pjsMiter; 1672 if ACut then 1673 begin 1674 if AFlipped then 1675 SetArrowEnd(asFlippedCut,join,ARelativePenWidth) 1676 else 1677 SetArrowEnd(asCut,join,ARelativePenWidth) 1678 end 1679 else 1680 begin 1681 if AFlipped then 1682 SetArrowEnd(asFlipped,join,ARelativePenWidth) 1683 else 1684 SetArrowEnd(asNormal,join,ARelativePenWidth) 1685 end; 1686 end; 1687 1688 procedure TBGRACustomBitmap.ArrowEndAsTriangle(ABackOffset: single; ARounded: boolean; AHollow: boolean; 1689 AHollowPenWidth: single); 1690 var join: TPenJoinStyle; 1691 begin 1692 if ARounded then join := pjsRound else join := pjsMiter; 1693 if AHollow then 1694 SetArrowEnd(asHollowTriangle, join,AHollowPenWidth, ABackOffset) 1695 else 1696 SetArrowEnd(asTriangle, join,1, ABackOffset); 1697 end; 1698 1699 procedure TBGRACustomBitmap.ArrowEndAsTail; 1700 begin 1701 SetArrowEnd(asTail); 1702 end; 1703 1704 procedure TBGRACustomBitmap.DrawPolyLine(const points: array of TPoint; 1705 c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode); 1706 var i: integer; 1707 begin 1708 if length(points) = 1 then 1709 begin 1710 if DrawLastPixel then DrawPixel(points[0].x,points[0].y,c,ADrawMode); 1711 end 1712 else 1713 for i := 0 to high(points)-1 do 1714 DrawLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,DrawLastPixel and (i=high(points)-1),ADrawMode); 1095 1715 end; 1096 1716 … … 1102 1722 if length(points) = 1 then 1103 1723 begin 1104 if DrawLastPixel then Draw Pixel(points[0].x,points[0].y,c);1724 if DrawLastPixel then DrawLineAntialias(points[0].x,points[0].y,points[0].x,points[0].y,c,true); 1105 1725 end 1106 1726 else … … 1124 1744 end; 1125 1745 1746 procedure TBGRACustomBitmap.DrawPolygon(const points: array of TPoint; 1747 c: TBGRAPixel; ADrawMode: TDrawMode); 1748 var i: integer; 1749 begin 1750 if length(points) = 1 then 1751 begin 1752 DrawPixel(points[0].x,points[0].y,c,ADrawMode); 1753 end 1754 else 1755 begin 1756 for i := 0 to high(points)-1 do 1757 DrawLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,false,ADrawMode); 1758 DrawLine(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,c,false,ADrawMode); 1759 end; 1760 end; 1761 1762 procedure TBGRACustomBitmap.DrawPolygonAntialias(const points: array of TPoint; 1763 c: TBGRAPixel); 1764 var i: integer; 1765 begin 1766 if length(points) = 1 then 1767 begin 1768 DrawLineAntialias(points[0].x,points[0].y,points[0].x,points[0].y,c,true); 1769 end 1770 else 1771 begin 1772 for i := 0 to high(points)-1 do 1773 DrawLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,c,false); 1774 DrawLineAntialias(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,c,false); 1775 end; 1776 end; 1777 1778 procedure TBGRACustomBitmap.ErasePolyLine(const points: array of TPoint; alpha: byte; 1779 DrawLastPixel: boolean); 1780 var i: integer; 1781 begin 1782 if length(points) = 1 then 1783 begin 1784 if DrawLastPixel then ErasePixel(points[0].x,points[0].y,alpha); 1785 end 1786 else 1787 for i := 0 to high(points)-1 do 1788 EraseLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,DrawLastPixel and (i=high(points)-1)); 1789 end; 1790 1791 procedure TBGRACustomBitmap.ErasePolyLineAntialias( 1792 const points: array of TPoint; alpha: byte; DrawLastPixel: boolean); 1793 var i: integer; 1794 begin 1795 if length(points) = 1 then 1796 begin 1797 if DrawLastPixel then ErasePixel(points[0].x,points[0].y,alpha); 1798 end 1799 else 1800 for i := 0 to high(points)-1 do 1801 EraseLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,DrawLastPixel and (i=high(points)-1)); 1802 end; 1803 1804 procedure TBGRACustomBitmap.ErasePolygonOutline(const points: array of TPoint; 1805 alpha: byte); 1806 var i: integer; 1807 begin 1808 if length(points) = 1 then 1809 begin 1810 ErasePixel(points[0].x,points[0].y,alpha); 1811 end 1812 else 1813 begin 1814 for i := 0 to high(points)-1 do 1815 EraseLine(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,false); 1816 EraseLine(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,alpha,false); 1817 end; 1818 end; 1819 1820 procedure TBGRACustomBitmap.ErasePolygonOutlineAntialias( 1821 const points: array of TPoint; alpha: byte); 1822 var i: integer; 1823 begin 1824 if length(points) = 1 then 1825 begin 1826 ErasePixel(points[0].x,points[0].y,alpha); 1827 end 1828 else 1829 begin 1830 for i := 0 to high(points)-1 do 1831 EraseLineAntialias(points[i].x,points[i].Y,points[i+1].x,points[i+1].y,alpha,false); 1832 EraseLineAntialias(points[high(points)].x,points[high(points)].Y,points[0].x,points[0].y,alpha,false); 1833 end; 1834 end; 1835 1126 1836 { Following functions are defined for convenience } 1127 1837 procedure TBGRACustomBitmap.Rectangle(x, y, x2, y2: integer; c: TColor); … … 1153 1863 end; 1154 1864 1865 procedure TBGRACustomBitmap.FillRoundRect(X1, Y1, X2, Y2: integer; DX, 1866 DY: integer; FillColor: TBGRAPixel; ADrawMode: TDrawMode); 1867 begin 1868 RoundRect(X1,Y1,X2,Y2,DX,DY,FillColor,FillColor,ADrawMode); 1869 end; 1870 1871 procedure TBGRACustomBitmap.EllipseInRect(r: TRect; BorderColor: TBGRAPixel; 1872 ADrawMode: TDrawMode); 1873 begin 1874 RoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),BorderColor,ADrawMode); 1875 end; 1876 1877 procedure TBGRACustomBitmap.EllipseInRect(r: TRect; BorderColor, 1878 FillColor: TBGRAPixel; ADrawMode: TDrawMode); 1879 begin 1880 RoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),BorderColor,FillColor,ADrawMode); 1881 end; 1882 1883 procedure TBGRACustomBitmap.FillEllipseInRect(r: TRect; FillColor: TBGRAPixel; 1884 ADrawMode: TDrawMode); 1885 begin 1886 FillRoundRect(r.left,r.top,r.right,r.bottom,abs(r.right-r.left),abs(r.bottom-r.top),FillColor,ADrawMode); 1887 end; 1888 1155 1889 procedure TBGRACustomBitmap.FillRect(r: TRect; c: TColor); 1156 1890 begin … … 1163 1897 end; 1164 1898 1899 procedure TBGRACustomBitmap.FillRect(r: TRect; texture: IBGRAScanner; 1900 mode: TDrawMode); 1901 begin 1902 FillRect(r.Left, r.top, r.right, r.bottom, texture, mode); 1903 end; 1904 1165 1905 procedure TBGRACustomBitmap.FillRect(x, y, x2, y2: integer; c: TColor); 1166 1906 begin … … 1168 1908 end; 1169 1909 1170 procedure TBGRACustomBitmap.TextOut(x, y: single; s: string; c: TBGRAPixel); 1171 begin 1172 TextOut(x, y, s, c, taLeftJustify); 1173 end; 1174 1175 procedure TBGRACustomBitmap.TextOut(x, y: single; s: string; c: TColor); 1176 begin 1177 TextOut(x, y, s, ColorToBGRA(c)); 1178 end; 1179 1180 procedure TBGRACustomBitmap.TextOut(x, y: single; s: string; 1910 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. 1911 The value of FontOrientation is taken into account, so that the text may be rotated. } 1912 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; c: TBGRAPixel); 1913 begin 1914 TextOut(x, y, sUTF8, c, taLeftJustify); 1915 end; 1916 1917 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The color c is used to fill the text. 1918 The value of FontOrientation is taken into account, so that the text may be rotated. } 1919 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; c: TColor); 1920 begin 1921 TextOut(x, y, sUTF8, ColorToBGRA(c)); 1922 end; 1923 1924 { Draw the UTF8 encoded string, (x,y) being the top-left corner. The texture is used to fill the text. 1925 The value of FontOrientation is taken into account, so that the text may be rotated. } 1926 procedure TBGRACustomBitmap.TextOut(x, y: single; sUTF8: string; 1181 1927 texture: IBGRAScanner); 1182 1928 begin 1183 TextOut(x, y, s, texture, taLeftJustify); 1184 end; 1185 1186 procedure TBGRACustomBitmap.TextRect(ARect: TRect; s: string; 1929 TextOut(x, y, sUTF8, texture, taLeftJustify); 1930 end; 1931 1932 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 1933 The position depends on the specified horizontal alignment halign and vertical alignement valign. 1934 The color c is used to fill the text. No rotation is applied. } 1935 procedure TBGRACustomBitmap.TextRect(ARect: TRect; sUTF8: string; 1187 1936 halign: TAlignment; valign: TTextLayout; c: TBGRAPixel); 1188 1937 var … … 1197 1946 style.ShowPrefix := false; 1198 1947 style.Clipping := false; 1199 TextRect(ARect,ARect.Left,ARect.Top,s,style,c); 1200 end; 1201 1202 procedure TBGRACustomBitmap.TextRect(ARect: TRect; s: string; 1948 TextRect(ARect,ARect.Left,ARect.Top,sUTF8,style,c); 1949 end; 1950 1951 { Draw the UTF8 encoded string in the rectangle ARect. Text is wrapped if necessary. 1952 The position depends on the specified horizontal alignment halign and vertical alignement valign. 1953 The texture is used to fill the text. No rotation is applied. } 1954 procedure TBGRACustomBitmap.TextRect(ARect: TRect; sUTF8: string; 1203 1955 halign: TAlignment; valign: TTextLayout; texture: IBGRAScanner); 1204 1956 var … … 1213 1965 style.ShowPrefix := false; 1214 1966 style.Clipping := false; 1215 TextRect(ARect,ARect.Left,ARect.Top,s ,style,texture);1967 TextRect(ARect,ARect.Left,ARect.Top,sUTF8,style,texture); 1216 1968 end; 1217 1969 … … 1245 1997 begin 1246 1998 AlphaFill(alpha, 0, NbPixels); 1999 end; 2000 2001 procedure TBGRACustomBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 2002 color: TBGRAPixel); 2003 begin 2004 FillMask(x,y, AMask, color, dmDrawWithTransparency); 2005 end; 2006 2007 procedure TBGRACustomBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 2008 texture: IBGRAScanner); 2009 begin 2010 FillMask(x,y, AMask, texture, dmDrawWithTransparency); 1247 2011 end; 1248 2012 … … 1276 2040 oldClip,newClip: TRect; 1277 2041 begin 1278 if Source = nilthen exit;2042 if (Source = nil) or (AOpacity = 0) then exit; 1279 2043 w := SourceRect.Right-SourceRect.Left; 1280 2044 h := SourceRect.Bottom-SourceRect.Top; … … 1304 2068 1305 2069 ClipRect := oldClip; 2070 end; 2071 2072 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2073 Source: TBGRACustomBitmap; AOpacity: Byte; ACorrectBlur: Boolean); 2074 begin 2075 if ACorrectBlur then 2076 PutImageAffine(Origin,HAxis,VAxis,Source,rfCosine,AOpacity) 2077 else 2078 PutImageAffine(Origin,HAxis,VAxis,Source,rfLinear,AOpacity); 2079 end; 2080 2081 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2082 Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte); 2083 var outputBounds: TRect; 2084 begin 2085 if (Source = nil) or (AOpacity = 0) then exit; 2086 if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and 2087 (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and 2088 (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then 2089 begin 2090 PutImage(round(origin.x),round(origin.y),Source,dmDrawWithTransparency,AOpacity); 2091 exit; 2092 end; 2093 outputBounds := GetImageAffineBounds(Origin,HAxis,VAxis,Source); 2094 PutImageAffine(Origin,HAxis,VAxis,Source,outputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity); 2095 end; 2096 2097 procedure TBGRACustomBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 2098 Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte; 2099 ACorrectBlur: Boolean); 2100 begin 2101 if ACorrectBlur then 2102 PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfCosine,dmDrawWithTransparency, AOpacity) 2103 else 2104 PutImageAffine(Origin,HAxis,VAxis,Source,AOutputBounds,rfLinear,dmDrawWithTransparency,AOpacity); 2105 end; 2106 2107 { Returns the area that contains the affine transformed image } 2108 function TBGRACustomBitmap.GetImageAffineBounds(Origin, HAxis, VAxis: TPointF; 2109 Source: TBGRACustomBitmap): TRect; 2110 var minx,miny,maxx,maxy: integer; 2111 vx,vy,pt1: TPointF; 2112 sourceBounds: TRect; 2113 2114 //include specified point in the bounds 2115 procedure Include(pt: TPointF); 2116 begin 2117 if floor(pt.X) < minx then minx := floor(pt.X); 2118 if floor(pt.Y) < miny then miny := floor(pt.Y); 2119 if ceil(pt.X) > maxx then maxx := ceil(pt.X); 2120 if ceil(pt.Y) > maxy then maxy := ceil(pt.Y); 2121 end; 2122 2123 begin 2124 result := EmptyRect; 2125 if (Source = nil) then exit; 2126 sourceBounds := source.GetImageBounds; 2127 if IsRectEmpty(sourceBounds) then exit; 2128 2129 if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and 2130 (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and 2131 (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then 2132 begin 2133 result := sourceBounds; 2134 OffsetRect(result,round(origin.x),round(origin.y)); 2135 IntersectRect(result,result,ClipRect); 2136 exit; 2137 end; 2138 2139 { Compute bounds } 2140 vx := (HAxis-Origin)*(1/source.Width); 2141 vy := (VAxis-Origin)*(1/source.Height); 2142 pt1 := Origin+vx*sourceBounds.Left+vy*sourceBounds.Top; 2143 minx := floor(pt1.X); 2144 miny := floor(pt1.Y); 2145 maxx := ceil(pt1.X); 2146 maxy := ceil(pt1.Y); 2147 Include(Origin+vx*sourceBounds.Right+vy*sourceBounds.Top); 2148 Include(Origin+vx*sourceBounds.Right+vy*sourceBounds.Bottom); 2149 Include(Origin+vx*sourceBounds.Left+vy*sourceBounds.Bottom); 2150 2151 result := rect(minx,miny,maxx+1,maxy+1); 2152 IntersectRect(result,result,ClipRect); 2153 end; 2154 2155 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2156 Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; 2157 imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2158 ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); 2159 begin 2160 if ACorrectBlur then 2161 PutImageAngle(x,y,Source,angle,AOutputBounds,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) 2162 else 2163 PutImageAngle(x,y,Source,angle,AOutputBounds,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); 2164 end; 2165 2166 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2167 Source: TBGRACustomBitmap; angle: single; imageCenterX: single; 2168 imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean; ACorrectBlur: Boolean); 2169 begin 2170 if ACorrectBlur then 2171 PutImageAngle(x,y,Source,angle,rfCosine,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation) 2172 else 2173 PutImageAngle(x,y,Source,angle,rfLinear,imageCenterX,imageCenterY,AOpacity,ARestoreOffsetAfterRotation); 2174 end; 2175 2176 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2177 Source: TBGRACustomBitmap; angle: single; AOutputBounds: TRect; 2178 AResampleFilter: TResampleFilter; imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2179 ARestoreOffsetAfterRotation: boolean); 2180 var 2181 Origin,HAxis,VAxis: TPointF; 2182 begin 2183 if (source = nil) or (AOpacity=0) then exit; 2184 ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, 2185 Origin,HAxis,VAxis); 2186 PutImageAffine(Origin,HAxis,VAxis,source,AOutputBounds,AResampleFilter,dmDrawWithTransparency,AOpacity); 2187 end; 2188 2189 procedure TBGRACustomBitmap.PutImageAngle(x, y: single; 2190 Source: TBGRACustomBitmap; angle: single; AResampleFilter: TResampleFilter; 2191 imageCenterX: single; imageCenterY: single; AOpacity: Byte; 2192 ARestoreOffsetAfterRotation: boolean); 2193 var 2194 Origin,HAxis,VAxis: TPointF; 2195 begin 2196 if (source = nil) or (AOpacity=0) then exit; 2197 ComputeImageAngleAxes(x,y,source.Width,source.Height,angle,imageCenterX,imageCenterY,ARestoreOffsetAfterRotation, 2198 Origin,HAxis,VAxis); 2199 PutImageAffine(Origin,HAxis,VAxis,source,AResampleFilter,AOpacity); 2200 end; 2201 2202 procedure TBGRACustomBitmap.ComputeImageAngleAxes(x, y, w, h, 2203 angle: single; imageCenterX, imageCenterY: single; 2204 ARestoreOffsetAfterRotation: boolean; out Origin, HAxis, VAxis: TPointF); 2205 var 2206 cosa,sina: single; 2207 2208 { Compute rotated coordinates } 2209 function Coord(relX,relY: single): TPointF; 2210 begin 2211 relX -= imageCenterX; 2212 relY -= imageCenterY; 2213 result.x := relX*cosa-relY*sina+x; 2214 result.y := relY*cosa+relX*sina+y; 2215 if ARestoreOffsetAfterRotation then 2216 begin 2217 result.x += imageCenterX; 2218 result.y += imageCenterY; 2219 end; 2220 end; 2221 2222 begin 2223 cosa := cos(-angle*Pi/180); 2224 sina := -sin(-angle*Pi/180); 2225 Origin := Coord(0,0); 2226 HAxis := Coord(w,0); 2227 VAxis := Coord(0,h); 2228 end; 2229 2230 function TBGRACustomBitmap.GetImageAngleBounds(x, y: single; 2231 Source: TBGRACustomBitmap; angle: single; imageCenterX: single; 2232 imageCenterY: single; ARestoreOffsetAfterRotation: boolean): TRect; 2233 var 2234 cosa,sina: single; 2235 2236 { Compute rotated coordinates } 2237 function Coord(relX,relY: single): TPointF; 2238 begin 2239 relX -= imageCenterX; 2240 relY -= imageCenterY; 2241 result.x := relX*cosa-relY*sina+x; 2242 result.y := relY*cosa+relX*sina+y; 2243 if ARestoreOffsetAfterRotation then 2244 begin 2245 result.x += imageCenterX; 2246 result.y += imageCenterY; 2247 end; 2248 end; 2249 2250 begin 2251 if (source = nil) then 2252 begin 2253 result := EmptyRect; 2254 exit; 2255 end; 2256 cosa := cos(-angle*Pi/180); 2257 sina := -sin(-angle*Pi/180); 2258 result := GetImageAffineBounds(Coord(0,0),Coord(source.Width,0),Coord(0,source.Height),source); 2259 end; 2260 2261 procedure TBGRACustomBitmap.VerticalFlip; 2262 begin 2263 VerticalFlip(rect(0,0,Width,Height)); 2264 end; 2265 2266 procedure TBGRACustomBitmap.HorizontalFlip; 2267 begin 2268 HorizontalFlip(rect(0,0,Width,Height)); 2269 end; 2270 2271 procedure TBGRACustomBitmap.ApplyMask(mask: TBGRACustomBitmap); 2272 begin 2273 ApplyMask(mask, Rect(0,0,Width,Height), Point(0,0)); 2274 end; 2275 2276 procedure TBGRACustomBitmap.ApplyMask(mask: TBGRACustomBitmap; ARect: TRect); 2277 begin 2278 ApplyMask(mask, ARect, ARect.TopLeft); 1306 2279 end; 1307 2280 … … 1448 2421 {************************** Color functions **************************} 1449 2422 2423 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, 2424 maxyb, ignoreleft: integer; const cliprect: TRect): boolean; 2425 var x2,y2: integer; 2426 begin 2427 if (x >= cliprect.Right) or (y >= cliprect.Bottom) or (x <= cliprect.Left-tx) or 2428 (y <= cliprect.Top-ty) or (ty <= 0) or (tx <= 0) then 2429 begin 2430 result := false; 2431 exit; 2432 end; 2433 2434 x2 := x + tx - 1; 2435 y2 := y + ty - 1; 2436 2437 if y < cliprect.Top then 2438 minyb := cliprect.Top 2439 else 2440 minyb := y; 2441 if y2 >= cliprect.Bottom then 2442 maxyb := cliprect.Bottom - 1 2443 else 2444 maxyb := y2; 2445 2446 if x < cliprect.Left then 2447 begin 2448 ignoreleft := cliprect.Left-x; 2449 minxb := cliprect.Left; 2450 end 2451 else 2452 begin 2453 ignoreleft := 0; 2454 minxb := x; 2455 end; 2456 if x2 >= cliprect.Right then 2457 maxxb := cliprect.Right - 1 2458 else 2459 maxxb := x2; 2460 2461 result := true; 2462 end; 2463 1450 2464 { The intensity is defined here as the maximum value of any color component } 1451 function GetIntensity(c : TExpandedPixel): word; inline;2465 function GetIntensity(const c: TExpandedPixel): word; inline; 1452 2466 begin 1453 2467 Result := c.red; … … 1458 2472 end; 1459 2473 1460 function SetIntensity(c: TExpandedPixel; intensity: word): TExpandedPixel; 2474 function GetIntensity(c: TBGRAPixel): word; 2475 begin 2476 Result := c.red; 2477 if c.green > Result then 2478 Result := c.green; 2479 if c.blue > Result then 2480 Result := c.blue; 2481 result := GammaExpansionTab[Result]; 2482 end; 2483 2484 function SetIntensity(const c: TExpandedPixel; intensity: word): TExpandedPixel; 1461 2485 var 1462 2486 curIntensity: word; … … 1464 2488 curIntensity := GetIntensity(c); 1465 2489 if curIntensity = 0 then //suppose it's gray if there is no color information 1466 Result := c 2490 begin 2491 Result.red := intensity; 2492 Result.green := intensity; 2493 Result.blue := intensity; 2494 result.alpha := c.alpha; 2495 end 1467 2496 else 1468 2497 begin … … 1475 2504 end; 1476 2505 2506 function SetIntensity(c: TBGRAPixel; intensity: word): TBGRAPixel; 2507 begin 2508 result := GammaCompression(SetIntensity(GammaExpansion(c),intensity)); 2509 end; 2510 2511 function GetLightness(c: TBGRAPixel): word; 2512 begin 2513 result := GetLightness(GammaExpansion(c)); 2514 end; 2515 1477 2516 { The lightness here is defined as the subjective sensation of luminosity, where 1478 2517 blue is the darkest component and green the lightest } 1479 function GetLightness(c : TExpandedPixel): word; inline;2518 function GetLightness(const c: TExpandedPixel): word; inline; 1480 2519 begin 1481 2520 Result := (c.red * redWeightShl10 + c.green * greenWeightShl10 + … … 1483 2522 end; 1484 2523 1485 function SetLightness(c : TExpandedPixel; lightness: word): TExpandedPixel;2524 function SetLightness(const c: TExpandedPixel; lightness: word): TExpandedPixel; 1486 2525 var 1487 2526 curLightness: word; 1488 AddedWhiteness, maxBeforeWhite: word;1489 clip: boolean;1490 2527 begin 1491 2528 curLightness := GetLightness(c); … … 1495 2532 exit; 1496 2533 end; 2534 result := SetLightness(c, lightness, curLightness); 2535 end; 2536 2537 function SetLightness(c: TBGRAPixel; lightness: word): TBGRAPixel; 2538 begin 2539 result := GammaCompression(SetLightness(GammaExpansion(c),lightness)); 2540 end; 2541 2542 function SetLightness(const c: TExpandedPixel; lightness: word; curLightness: word): TExpandedPixel; 2543 var 2544 AddedWhiteness, maxBeforeWhite: word; 2545 clip: boolean; 2546 begin 2547 if lightness = curLightness then 2548 begin //no change 2549 Result := c; 2550 exit; 2551 end; 1497 2552 if lightness = 65535 then //set to white 1498 2553 begin … … 1521 2576 if lightness < curLightness then //darker is easy 1522 2577 begin 1523 Result := SetIntensity(c, (GetIntensity(c) * lightness + (curLightness shr 1)) div 1524 curLightness); 2578 result.alpha:= c.alpha; 2579 result.red := (c.red * lightness + (curLightness shr 1)) div curLightness; 2580 result.green := (c.green * lightness + (curLightness shr 1)) div curLightness; 2581 result.blue := (c.blue * lightness + (curLightness shr 1)) div curLightness; 1525 2582 exit; 1526 2583 end; … … 1597 2654 end; 1598 2655 1599 function CombineLightness(lightness1,lightness2: integer): integer;2656 function CombineLightness(lightness1,lightness2: Int32or64): Int32or64; 1600 2657 {$ifdef CPUI386} {$asmmode intel} assembler; 1601 2658 asm … … 1663 2720 end; 1664 2721 1665 function ExpandedToHSLA(ec: TExpandedPixel): THSLAPixel;2722 procedure ExpandedToHSLAInline(r,g,b: Int32Or64; var dest: THSLAPixel); inline; 1666 2723 const 1667 deg60 = 8192; 1668 deg120 = deg60 * 2; 1669 deg240 = deg60 * 4; 1670 deg360 = deg60 * 6; 2724 deg60 = 10922; 2725 deg120 = 21845; 2726 deg240 = 43690; 1671 2727 var 1672 min, max, minMax: integer; 1673 twiceLightness: integer; 1674 r,g,b: integer; 1675 begin 1676 r := ec.red; 1677 g := ec.green; 1678 b := ec.blue; 1679 min := r; 1680 max := r; 1681 if g > max then 1682 max := g 1683 else 1684 if g < min then 2728 min, max, minMax: Int32or64; 2729 UMinMax,UTwiceLightness: UInt32or64; 2730 begin 2731 if g > r then 2732 begin 2733 max := g; 2734 min := r; 2735 end 2736 else 2737 begin 2738 max := r; 1685 2739 min := g; 2740 end; 1686 2741 if b > max then 1687 2742 max := b … … 1692 2747 1693 2748 if minMax = 0 then 1694 Result.hue := 02749 dest.hue := 0 1695 2750 else 1696 2751 if max = r then 1697 Result.hue := (((g - b) * deg60) div 1698 minMax + deg360) mod deg360 2752 {$PUSH}{$RANGECHECKS OFF} 2753 dest.hue := ((g - b) * deg60) div minMax 2754 {$POP} 1699 2755 else 1700 2756 if max = g then 1701 Result.hue := ((b - r) * deg60) div minMax + deg120 1702 else 1703 {max = b} Result.hue := 1704 ((r - g) * deg60) div minMax + deg240; 1705 twiceLightness := max + min; 2757 dest.hue := ((b - r) * deg60) div minMax + deg120 2758 else 2759 {max = b} dest.hue := ((r - g) * deg60) div minMax + deg240; 2760 UTwiceLightness := max + min; 1706 2761 if min = max then 1707 Result.saturation := 0 1708 else 1709 {$hints off} 1710 if twiceLightness < 65536 then 1711 Result.saturation := (int64(minMax) shl 16) div (twiceLightness + 1) 1712 else 1713 Result.saturation := (int64(minMax) shl 16) div (131072 - twiceLightness); 1714 {$hints on} 1715 Result.lightness := twiceLightness shr 1; 1716 Result.alpha := ec.alpha; 1717 Result.hue := (Result.hue shl 16) div deg360; 2762 dest.saturation := 0 2763 else 2764 begin 2765 UMinMax:= minMax; 2766 if UTwiceLightness < 65536 then 2767 dest.saturation := (UMinMax shl 16) div (UTwiceLightness + 1) 2768 else 2769 dest.saturation := (UMinMax shl 16) div (131072 - UTwiceLightness); 2770 end; 2771 dest.lightness := UTwiceLightness shr 1; 2772 end; 2773 2774 function ExpandedToHSLA(const ec: TExpandedPixel): THSLAPixel; 2775 begin 2776 result.alpha := ec.alpha; 2777 ExpandedToHSLAInline(ec.red,ec.green,ec.blue,result); 1718 2778 end; 1719 2779 1720 2780 function HtoG(hue: word): word; 1721 2781 const 1722 segmentDest: array[0..5] of word=2782 segmentDest: array[0..5] of NativeUInt = 1723 2783 (13653, 10923, 8192, 13653, 10923, 8192); 1724 segmentSrc: array[0..5] of word=2784 segmentSrc: array[0..5] of NativeUInt = 1725 2785 (10923, 10922, 10923, 10923, 10922, 10923); 1726 begin 1727 if hue < segmentSrc[0] then 1728 result := hue * segmentDest[0] div segmentSrc[0] 1729 else 1730 begin 1731 result := segmentDest[0]; 1732 hue -= segmentSrc[0]; 1733 if hue < segmentSrc[1] then 1734 result += hue * segmentDest[1] div segmentSrc[1] 2786 var 2787 h,g: NativeUInt; 2788 begin 2789 h := hue; 2790 if h < segmentSrc[0] then 2791 g := h * segmentDest[0] div segmentSrc[0] 2792 else 2793 begin 2794 g := segmentDest[0]; 2795 h -= segmentSrc[0]; 2796 if h < segmentSrc[1] then 2797 g += h * segmentDest[1] div segmentSrc[1] 1735 2798 else 1736 2799 begin 1737 result+= segmentDest[1];1738 h ue-= segmentSrc[1];1739 if h ue< segmentSrc[2] then1740 result += hue* segmentDest[2] div segmentSrc[2]2800 g += segmentDest[1]; 2801 h -= segmentSrc[1]; 2802 if h < segmentSrc[2] then 2803 g += h * segmentDest[2] div segmentSrc[2] 1741 2804 else 1742 2805 begin 1743 result+= segmentDest[2];1744 h ue-= segmentSrc[2];1745 if h ue< segmentSrc[3] then1746 result += hue* segmentDest[3] div segmentSrc[3]2806 g += segmentDest[2]; 2807 h -= segmentSrc[2]; 2808 if h < segmentSrc[3] then 2809 g += h * segmentDest[3] div segmentSrc[3] 1747 2810 else 1748 2811 begin 1749 result+= segmentDest[3];1750 h ue-= segmentSrc[3];1751 if h ue< segmentSrc[4] then1752 result += hue* segmentDest[4] div segmentSrc[4]2812 g += segmentDest[3]; 2813 h -= segmentSrc[3]; 2814 if h < segmentSrc[4] then 2815 g += h * segmentDest[4] div segmentSrc[4] 1753 2816 else 1754 2817 begin 1755 result+= segmentDest[4];1756 h ue-= segmentSrc[4];1757 result += hue* segmentDest[5] div segmentSrc[5];2818 g += segmentDest[4]; 2819 h -= segmentSrc[4]; 2820 g += h * segmentDest[5] div segmentSrc[5]; 1758 2821 end; 1759 2822 end; … … 1761 2824 end; 1762 2825 end; 2826 result := g; 1763 2827 end; 1764 2828 1765 2829 function GtoH(ghue: word): word; 1766 2830 const 1767 segment: array[0..5] of word=2831 segment: array[0..5] of NativeUInt = 1768 2832 (13653, 10923, 8192, 13653, 10923, 8192); 1769 begin 1770 if ghue < segment[0] then 1771 result := ghue * 10923 div segment[0] 1772 else 1773 begin 1774 ghue -= segment[0]; 1775 if ghue < segment[1] then 1776 result := ghue * (21845-10923) div segment[1] + 10923 2833 var g: NativeUint; 2834 begin 2835 g := ghue; 2836 if g < segment[0] then 2837 result := g * 10923 div segment[0] 2838 else 2839 begin 2840 g -= segment[0]; 2841 if g < segment[1] then 2842 result := g * (21845-10923) div segment[1] + 10923 1777 2843 else 1778 2844 begin 1779 g hue-= segment[1];1780 if g hue< segment[2] then1781 result := g hue* (32768-21845) div segment[2] + 218452845 g -= segment[1]; 2846 if g < segment[2] then 2847 result := g * (32768-21845) div segment[2] + 21845 1782 2848 else 1783 2849 begin 1784 g hue-= segment[2];1785 if g hue< segment[3] then1786 result := g hue* (43691-32768) div segment[3] + 327682850 g -= segment[2]; 2851 if g < segment[3] then 2852 result := g * (43691-32768) div segment[3] + 32768 1787 2853 else 1788 2854 begin 1789 g hue-= segment[3];1790 if g hue< segment[4] then1791 result := g hue* (54613-43691) div segment[4] + 436912855 g -= segment[3]; 2856 if g < segment[4] then 2857 result := g * (54613-43691) div segment[4] + 43691 1792 2858 else 1793 2859 begin 1794 g hue-= segment[4];1795 result := g hue* (65536-54613) div segment[5] + 54613;2860 g -= segment[4]; 2861 result := g * (65536-54613) div segment[5] + 54613; 1796 2862 end; 1797 2863 end; … … 1801 2867 end; 1802 2868 1803 function BGRAToGSBA(c: TBGRAPixel): THSLAPixel; 1804 var ec: TExpandedPixel; 1805 lightness: word; 1806 begin 1807 ec := GammaExpansion(c); 1808 lightness := GetLightness(ec); 1809 1810 result := ExpandedToHSLA(ec); 2869 function BGRAToGSBA(c: TBGRAPixel): TGSBAPixel; 2870 var lightness: UInt32Or64; 2871 red,green,blue: Int32or64; 2872 begin 2873 red := GammaExpansionTab[c.red]; 2874 green := GammaExpansionTab[c.green]; 2875 blue := GammaExpansionTab[c.blue]; 2876 result.alpha := c.alpha shl 8 + c.alpha; 2877 2878 lightness := (red * redWeightShl10 + green * greenWeightShl10 + 2879 blue * blueWeightShl10 + 512) shr 10; 2880 2881 ExpandedToHSLAInline(red,green,blue,result); 1811 2882 if result.lightness > 32768 then 1812 result.saturation := result.saturation* word(65535-result.lightness) div 32767;2883 result.saturation := result.saturation* UInt32or64(not result.lightness) div 32767; 1813 2884 result.lightness := lightness; 1814 2885 result.hue := HtoG(result.hue); 1815 2886 end; 1816 2887 1817 function HSLAToExpanded(c: THSLAPixel): TExpandedPixel; 2888 function ExpandedToGSBA(ec: TExpandedPixel): TGSBAPixel; 2889 var lightness: UInt32Or64; 2890 red,green,blue: Int32or64; 2891 begin 2892 red := ec.red; 2893 green := ec.green; 2894 blue := ec.blue; 2895 result.alpha := ec.alpha; 2896 2897 lightness := (red * redWeightShl10 + green * greenWeightShl10 + 2898 blue * blueWeightShl10 + 512) shr 10; 2899 2900 ExpandedToHSLAInline(red,green,blue,result); 2901 if result.lightness > 32768 then 2902 result.saturation := result.saturation* UInt32or64(not result.lightness) div 32767; 2903 result.lightness := lightness; 2904 result.hue := HtoG(result.hue); 2905 end; 2906 2907 function HSLAToExpanded(const c: THSLAPixel): TExpandedPixel; 1818 2908 const 1819 2909 deg30 = 4096; … … 1824 2914 deg360 = deg60 * 6; 1825 2915 1826 function ComputeColor(p, q: integer; h: integer): word; inline; 1827 begin 1828 if h > deg360 then 1829 Dec(h, deg360); 1830 if h < deg60 then 1831 Result := p + ((q - p) * h + deg30) div deg60 1832 else 2916 function ComputeColor(p, q: Int32or64; h: Int32or64): Int32or64; inline; 2917 begin 1833 2918 if h < deg180 then 1834 Result := q 1835 else 1836 if h < deg240 then 1837 Result := p + ((q - p) * (deg240 - h) + deg30) div deg60 1838 else 1839 Result := p; 2919 begin 2920 if h < deg60 then 2921 Result := p + ((q - p) * h + deg30) div deg60 2922 else 2923 Result := q 2924 end else 2925 begin 2926 if h < deg240 then 2927 Result := p + ((q - p) * (deg240 - h) + deg30) div deg60 2928 else 2929 Result := p; 2930 end; 1840 2931 end; 1841 2932 1842 2933 var 1843 q, p: integer; 1844 begin 1845 c.hue := c.hue * deg360 shr 16; 1846 if c.saturation = 0 then //gray 1847 begin 1848 result.red := c.lightness; 1849 result.green := c.lightness; 1850 result.blue := c.lightness; 2934 q, p, L, S, H: Int32or64; 2935 begin 2936 L := c.lightness; 2937 S := c.saturation; 2938 if S = 0 then //gray 2939 begin 2940 result.red := L; 2941 result.green := L; 2942 result.blue := L; 1851 2943 result.alpha := c.alpha; 1852 2944 exit; 1853 2945 end; 1854 2946 {$hints off} 1855 if c.lightness< 32768 then1856 q := ( c.lightness shr 1) * ((65535 + c.saturation) shr 1) shr 141857 else 1858 q := c.lightness + c.saturation - ((c.lightnessshr 1) *1859 ( c.saturationshr 1) shr 14);2947 if L < 32768 then 2948 q := (L shr 1) * ((65535 + S) shr 1) shr 14 2949 else 2950 q := L + S - ((L shr 1) * 2951 (S shr 1) shr 14); 1860 2952 {$hints on} 1861 if q > 65535 then 1862 q := 65535; 1863 p := c.lightness * 2 - q; 1864 if p > 65535 then 1865 p := 65535; 1866 result.red := ComputeColor(p, q, c.hue + deg120); 1867 result.green := ComputeColor(p, q, c.hue); 1868 result.blue := ComputeColor(p, q, c.hue + deg240); 2953 if q > 65535 then q := 65535; 2954 p := (L shl 1) - q; 2955 if p > 65535 then p := 65535; 2956 H := c.hue * deg360 shr 16; 2957 result.green := ComputeColor(p, q, H); 2958 inc(H, deg120); 2959 if H > deg360 then Dec(H, deg360); 2960 result.red := ComputeColor(p, q, H); 2961 inc(H, deg120); 2962 if H > deg360 then Dec(H, deg360); 2963 result.blue := ComputeColor(p, q, H); 1869 2964 result.alpha := c.alpha; 1870 2965 end; 1871 2966 1872 2967 { Conversion from HSL colorspace to RGB. See : http://en.wikipedia.org/wiki/HSL_color_space } 1873 function HSLAToBGRA(c : THSLAPixel): TBGRAPixel;2968 function HSLAToBGRA(const c: THSLAPixel): TBGRAPixel; 1874 2969 var ec: TExpandedPixel; 1875 2970 begin … … 1945 3040 end; 1946 3041 1947 function GSBAToBGRA(c: T HSLAPixel): TBGRAPixel;3042 function GSBAToBGRA(c: TGSBAPixel): TBGRAPixel; 1948 3043 var ec: TExpandedPixel; 1949 3044 lightness: word; … … 1956 3051 end; 1957 3052 1958 function GSBAToHSLA(c: THSLAPixel): THSLAPixel; 3053 function GSBAToExpanded(c: TGSBAPixel): TExpandedPixel; 3054 var lightness: word; 3055 begin 3056 c.hue := GtoH(c.hue); 3057 lightness := c.lightness; 3058 c.lightness := 32768; 3059 result := SetLightness(HSLAToExpanded(c),lightness); 3060 end; 3061 3062 function GSBAToHSLA(c: TGSBAPixel): THSLAPixel; 1959 3063 begin 1960 3064 result := BGRAToHSLA(GSBAToBGRA(c)); … … 1970 3074 end; 1971 3075 1972 function GammaCompression( ec: TExpandedPixel): TBGRAPixel;3076 function GammaCompression(const ec: TExpandedPixel): TBGRAPixel; 1973 3077 begin 1974 3078 Result.red := GammaCompressionTab[ec.red]; … … 1994 3098 cgray: byte; 1995 3099 begin 3100 if c.alpha = 0 then 3101 begin 3102 result := BGRAPixelTransparent; 3103 exit; 3104 end; 1996 3105 //gamma expansion 1997 3106 ec := GammaExpansion(c); … … 2017 3126 function MergeBGRA(const colors: array of TBGRAPixel): TBGRAPixel; 2018 3127 var 2019 sumR,sumG,sumB,sumA: longword;3128 sumR,sumG,sumB,sumA: NativeUInt; 2020 3129 i: integer; 2021 3130 begin … … 2107 3216 weight2: byte): TBGRAPixel; 2108 3217 var 2109 f1,f2: word; 2110 f12: longword; 2111 begin 2112 if (weight1 = 0) then 2113 begin 2114 if (weight2 = 0) then 3218 w1,w2,f1,f2,f12,a: UInt32or64; 3219 begin 3220 w1 := weight1; 3221 w2 := weight2; 3222 if (w1 = 0) then 3223 begin 3224 if (w2 = 0) then 2115 3225 result := BGRAPixelTransparent 2116 3226 else … … 2118 3228 end 2119 3229 else 2120 if (w eight2 = 0) then3230 if (w2 = 0) then 2121 3231 Result := c1 2122 3232 else 2123 3233 begin 2124 f1 := c1.alpha*weight1 shr 1; 2125 f2 := c2.alpha*weight2 shr 1; 3234 f1 := c1.alpha*w1; 3235 f2 := c2.alpha*w2; 3236 a := (f1+f2 + ((w1+w2) shr 1)) div (w1+w2); 3237 if a = 0 then 3238 begin 3239 result := BGRAPixelTransparent; 3240 exit; 3241 end else 3242 Result.alpha := a; 3243 {$IFNDEF CPU64} 3244 if (f1 >= 32768) or (f2 >= 32768) then 3245 begin 3246 f1 := f1 shr 1; 3247 f2 := f2 shr 1; 3248 end; 3249 {$ENDIF} 2126 3250 f12 := f1+f2; 2127 if f12 = 0 then 2128 result := BGRAPixelTransparent 2129 else 2130 begin 2131 Result.red := GammaCompressionTab[(GammaExpansionTab[c1.red] * f1 + GammaExpansionTab[c2.red] * f2) div f12]; 2132 Result.green := GammaCompressionTab[(GammaExpansionTab[c1.green] * f1 + GammaExpansionTab[c2.green] * f2) div f12]; 2133 Result.blue := GammaCompressionTab[(GammaExpansionTab[c1.blue] * f1 + GammaExpansionTab[c2.blue] * f2) div f12]; 2134 Result.alpha := (c1.alpha*weight1+c2.alpha*weight2 + ((weight1+weight2) shr 1)) div (weight1+weight2); 2135 end; 3251 Result.red := GammaCompressionTab[(GammaExpansionTab[c1.red] * f1 + GammaExpansionTab[c2.red] * f2) div f12]; 3252 Result.green := GammaCompressionTab[(GammaExpansionTab[c1.green] * f1 + GammaExpansionTab[c2.green] * f2) div f12]; 3253 Result.blue := GammaCompressionTab[(GammaExpansionTab[c1.blue] * f1 + GammaExpansionTab[c2.blue] * f2) div f12]; 2136 3254 end; 2137 3255 end; … … 2329 3447 end; 2330 3448 2331 { Write a color in hexadecimal format RRGGBBAA } 2332 function BGRAToStr(c: TBGRAPixel): string; 2333 begin 3449 { Write a color in hexadecimal format RRGGBBAA or using the name in a color list } 3450 function BGRAToStr(c: TBGRAPixel; AColorList: TBGRAColorList = nil; AMaxDiff: Word= 0): string; 3451 var idx: integer; 3452 begin 3453 if Assigned(AColorList) then 3454 begin 3455 idx := AColorList.IndexOfColor(c, AMaxDiff); 3456 if idx<> -1 then 3457 begin 3458 result := AColorList.Name[idx]; 3459 exit; 3460 end; 3461 end; 2334 3462 result := IntToHex(c.red,2)+IntToHex(c.green,2)+IntToHex(c.Blue,2)+IntToHex(c.Alpha,2); 2335 3463 end; … … 2338 3466 arrayOfString = array of string; 2339 3467 2340 function SimpleParseFuncParam(str: string ): arrayOfString;3468 function SimpleParseFuncParam(str: string; var flagError: boolean): arrayOfString; 2341 3469 var idxOpen,start,cur: integer; 2342 3470 begin 2343 3471 result := nil; 2344 3472 idxOpen := pos('(',str); 2345 if idxOpen = 0 then exit; 2346 start := idxOpen+1; 3473 if idxOpen = 0 then 3474 begin 3475 start := 1; 3476 //find first space 3477 while (start <= length(str)) and (str[start]<>' ') do inc(start); 3478 end else 3479 start := idxOpen+1; 2347 3480 cur := start; 2348 3481 while cur <= length(str) do … … 2351 3484 begin 2352 3485 setlength(result,length(result)+1); 2353 result[high(result)] := copy(str,start,cur-start);3486 result[high(result)] := trim(copy(str,start,cur-start)); 2354 3487 start := cur+1; 3488 if str[cur] = ')' then exit; 2355 3489 end; 2356 3490 inc(cur); 2357 3491 end; 3492 if idxOpen <> 0 then flagError := true; //should exit on ')' 2358 3493 if start <= length(str) then 2359 3494 begin … … 2363 3498 end; 2364 3499 2365 function ParseColorValue(str: string ): byte;3500 function ParseColorValue(str: string; var flagError: boolean): byte; 2366 3501 var pourcent,unclipped,{%H-}errPos: integer; 2367 3502 begin … … 2371 3506 begin 2372 3507 val(copy(str,1,length(str)-1),pourcent,errPos); 3508 if errPos <> 0 then flagError := true; 2373 3509 if pourcent < 0 then result := 0 else 2374 3510 if pourcent > 100 then result := 255 else … … 2377 3513 begin 2378 3514 val(str,unclipped,errPos); 3515 if errPos <> 0 then flagError := true; 2379 3516 if unclipped < 0 then result := 0 else 2380 3517 if unclipped > 255 then result := 255 else … … 2384 3521 end; 2385 3522 3523 //this function returns the parsed value only if it contains no error nor missing values, otherwise 3524 //it returns BGRAPixelTransparent 2386 3525 function StrToBGRA(str: string): TBGRAPixel; 2387 begin 2388 result := StrToBGRA(str, BGRAPixelTransparent); 2389 end; 2390 2391 { Read a color in hexadecimal format RRGGBB(AA) or RGB(A) } 2392 function StrToBGRA(str: string; DefaultColor: TBGRAPixel): TBGRAPixel; 3526 var missingValues, error: boolean; 3527 begin 3528 result := BGRABlack; 3529 TryStrToBGRA(str, result, missingValues, error); 3530 if missingValues or error then result := BGRAPixelTransparent; 3531 end; 3532 3533 //this function changes the content of parsedValue depending on available and parsable information. 3534 //set parsedValue to the fallback values before calling this function. 3535 //missing values are expressed by empty string or by '?', for example 'rgb(255,?,?,?)' will change only the red value. 3536 //note that if alpha is not expressed by the string format, it will be opaque. So 'rgb(255,?,?)' will change the red value and the alpha value. 3537 //the last parameter of rgba() is a floating point number where 1 is opaque and 0 is transparent. 3538 procedure TryStrToBGRA(str: string; var parsedValue: TBGRAPixel; out missingValues: boolean; out error: boolean); 2393 3539 var errPos: integer; 2394 3540 values: array of string; … … 2396 3542 idx: integer; 2397 3543 begin 2398 if str = '' then 2399 begin 2400 result := DefaultColor; 3544 str := Trim(str); 3545 error := false; 3546 if (str = '') or (str = '?') then 3547 begin 3548 missingValues := true; 2401 3549 exit; 2402 end; 2403 str := lowerCase(str); 3550 end else 3551 missingValues := false; 3552 str := StringReplace(lowerCase(str),'grey','gray',[]); 2404 3553 2405 3554 //VGA color names 2406 if str='black' then result := BGRA(0,0,0) else 2407 if str='silver' then result := BGRA(192,192,192) else 2408 if str='gray' then result := BGRA(128,128,128) else 2409 if str='grey' then result := BGRA(128,128,128) else 2410 if str='white' then result := BGRA(255,255,255) else 2411 if str='maroon' then result := BGRA(128,0,0) else 2412 if str='red' then result := BGRA(255,0,0) else 2413 if str='purple' then result := BGRA(128,0,128) else 2414 if str='fuchsia' then result := BGRA(255,0,255) else 2415 if str='green' then result := BGRA(0,128,0) else 2416 if str='lime' then result := BGRA(0,255,0) else 2417 if str='olive' then result := BGRA(128,128,0) else 2418 if str='yellow' then result := BGRA(255,255,0) else 2419 if str='navy' then result := BGRA(0,0,128) else 2420 if str='blue' then result := BGRA(0,0,255) else 2421 if str='teal' then result := BGRA(0,128,128) else 2422 if str='aqua' then result := BGRA(0,255,255) else 2423 if str='transparent' then result := DefaultColor else 3555 idx := VGAColors.IndexOf(str); 3556 if idx <> -1 then 3557 begin 3558 parsedValue := VGAColors[idx]; 3559 exit; 3560 end; 3561 if str='transparent' then parsedValue := BGRAPixelTransparent else 2424 3562 begin 2425 3563 //check CSS color … … 2427 3565 if idx <> -1 then 2428 3566 begin 2429 result:= CSSColors[idx];3567 parsedValue := CSSColors[idx]; 2430 3568 exit; 2431 3569 end; 2432 3570 2433 3571 //CSS RGB notation 2434 if (copy(str,1,4)='rgb(') or (copy(str,1,5)='rgba(') then 3572 if (copy(str,1,4)='rgb(') or (copy(str,1,5)='rgba(') or 3573 (copy(str,1,4)='rgb ') or (copy(str,1,5)='rgba ') then 2435 3574 begin 2436 values := SimpleParseFuncParam(str );3575 values := SimpleParseFuncParam(str,error); 2437 3576 if (length(values)=3) or (length(values)=4) then 2438 3577 begin 2439 result.red := ParseColorValue(values[0]); 2440 result.green := ParseColorValue(values[1]); 2441 result.blue := ParseColorValue(values[2]); 3578 if (values[0] <> '') and (values[0] <> '?') then 3579 parsedValue.red := ParseColorValue(values[0], error) 3580 else 3581 missingValues := true; 3582 if (values[1] <> '') and (values[1] <> '?') then 3583 parsedValue.green := ParseColorValue(values[1], error) 3584 else 3585 missingValues := true; 3586 if (values[2] <> '') and (values[2] <> '?') then 3587 parsedValue.blue := ParseColorValue(values[2], error) 3588 else 3589 missingValues := true; 2442 3590 if length(values)=4 then 2443 3591 begin 2444 val(values[3],alphaF,errPos); 2445 if alphaF < 0 then 2446 result.alpha := 0 else 2447 if alphaF > 1 then 2448 result.alpha := 255 2449 else 2450 result.alpha := round(alphaF*255); 3592 if (values[3] <> '') and (values[3] <> '?') then 3593 begin 3594 val(values[3],alphaF,errPos); 3595 if errPos <> 0 then 3596 begin 3597 parsedValue.alpha := 255; 3598 error := true; 3599 end 3600 else 3601 begin 3602 if alphaF < 0 then 3603 parsedValue.alpha := 0 else 3604 if alphaF > 1 then 3605 parsedValue.alpha := 255 3606 else 3607 parsedValue.alpha := round(alphaF*255); 3608 end; 3609 end else 3610 missingValues := true; 2451 3611 end else 2452 result.alpha := 255;3612 parsedValue.alpha := 255; 2453 3613 end else 2454 result := DefaultColor;3614 error := true; 2455 3615 exit; 2456 3616 end; … … 2459 3619 if str[1]='#' then delete(str,1,1); 2460 3620 2461 //add alpha if missing 3621 //add alpha if missing (if you want an undefined alpha use '??' or '?') 2462 3622 if length(str)=6 then str += 'FF'; 2463 3623 if length(str)=3 then str += 'F'; … … 2466 3626 if length(str)=8 then 2467 3627 begin 2468 val('$'+copy(str,1,2),result.red,errPos); 2469 if errPos <> 0 then 3628 if copy(str,1,2) <> '??' then 2470 3629 begin 2471 result := DefaultColor; 2472 exit; 2473 end; 2474 val('$'+copy(str,3,2),result.green,errPos); 2475 if errPos <> 0 then 3630 val('$'+copy(str,1,2),parsedValue.red,errPos); 3631 if errPos <> 0 then error := true; 3632 end else missingValues := true; 3633 if copy(str,3,2) <> '??' then 2476 3634 begin 2477 result := DefaultColor; 2478 exit; 2479 end; 2480 val('$'+copy(str,5,2),result.blue,errPos); 2481 if errPos <> 0 then 3635 val('$'+copy(str,3,2),parsedValue.green,errPos); 3636 if errPos <> 0 then error := true; 3637 end else missingValues := true; 3638 if copy(str,5,2) <> '??' then 2482 3639 begin 2483 result := DefaultColor; 2484 exit; 2485 end; 2486 val('$'+copy(str,7,2),result.alpha,errPos); 2487 if errPos <> 0 then 3640 val('$'+copy(str,5,2),parsedValue.blue,errPos); 3641 if errPos <> 0 then error := true; 3642 end else missingValues := true; 3643 if copy(str,7,2) <> '??' then 2488 3644 begin 2489 result := DefaultColor; 2490 exit; 2491 end; 3645 val('$'+copy(str,7,2),parsedValue.alpha,errPos); 3646 if errPos <> 0 then 3647 begin 3648 error := true; 3649 parsedValue.alpha := 255; 3650 end; 3651 end else missingValues := true; 2492 3652 end else 2493 3653 if length(str)=4 then 2494 3654 begin 2495 val('$'+copy(str,1,1),result.red,errPos); 2496 if errPos <> 0 then 3655 if str[1] <> '?' then 2497 3656 begin 2498 result := DefaultColor;2499 exit;2500 end;2501 val('$'+copy(str,2,1),result.green,errPos);2502 if errPos <> 0then3657 val('$'+str[1],parsedValue.red,errPos); 3658 if errPos <> 0 then error := true; 3659 parsedValue.red *= $11; 3660 end else missingValues := true; 3661 if str[2] <> '?' then 2503 3662 begin 2504 result := DefaultColor;2505 exit;2506 end;2507 val('$'+copy(str,3,1),result.blue,errPos);2508 if errPos <> 0then3663 val('$'+str[2],parsedValue.green,errPos); 3664 if errPos <> 0 then error := true; 3665 parsedValue.green *= $11; 3666 end else missingValues := true; 3667 if str[3] <> '?' then 2509 3668 begin 2510 result := DefaultColor;2511 exit;2512 end;2513 val('$'+copy(str,4,1),result.alpha,errPos);2514 if errPos <> 0then3669 val('$'+str[3],parsedValue.blue,errPos); 3670 if errPos <> 0 then error := true; 3671 parsedValue.blue *= $11; 3672 end else missingValues := true; 3673 if str[4] <> '?' then 2515 3674 begin 2516 result := DefaultColor; 2517 exit; 2518 end; 2519 result.red *= $11; 2520 result.green *= $11; 2521 result.blue *= $11; 2522 result.alpha *= $11; 3675 val('$'+str[4],parsedValue.alpha,errPos); 3676 if errPos <> 0 then 3677 begin 3678 error := true; 3679 parsedValue.alpha := 255; 3680 end else 3681 parsedValue.alpha *= $11; 3682 end else missingValues := true; 2523 3683 end else 2524 result := DefaultColor; 2525 end; 2526 3684 error := true; //string format not recognised 3685 end; 3686 3687 end; 3688 3689 //this function returns the values that can be read from the string, otherwise 3690 //it fills the gaps with the fallback values. The error boolean is True only 3691 //if there was invalid values, it is not set to True if there was missing values. 3692 function PartialStrToBGRA(str: string; const fallbackValues: TBGRAPixel; out 3693 error: boolean): TBGRAPixel; 3694 var missingValues: boolean; 3695 begin 3696 result := fallbackValues; 3697 TryStrToBGRA(str, result, missingValues, error); 3698 end; 3699 3700 { Read a color, for example in hexadecimal format RRGGBB(AA) or RGB(A). Partial colors are not accepted by this function. } 3701 function StrToBGRA(str: string; const DefaultColor: TBGRAPixel): TBGRAPixel; 3702 var missingValues, error: boolean; 3703 begin 3704 result := BGRABlack; 3705 TryStrToBGRA(str, result, missingValues, error); 3706 if missingValues or error then result := DefaultColor; 2527 3707 end; 2528 3708 … … 2531 3711 begin 2532 3712 intval := color.Green shl 16 + color.red shl 8 + color.blue; 2533 result := intval /16777215;3713 result := intval*5.960464832810452e-8; 2534 3714 end; 2535 3715 … … 2601 3781 end; 2602 3782 2603 function PtInRect( pt: TPoint; r: TRect): boolean;3783 function PtInRect(const pt: TPoint; r: TRect): boolean; 2604 3784 var 2605 3785 temp: integer; … … 2621 3801 end; 2622 3802 3803 function RectWithSize(left, top, width, height: integer): TRect; 3804 begin 3805 result.left := left; 3806 result.top := top; 3807 result.right := left+width; 3808 result.bottom := top+height; 3809 end; 3810 2623 3811 function VectLen(dx, dy: single): single; 2624 3812 begin … … 2630 3818 result := sqrt(v.x*v.x+v.y*v.y); 2631 3819 end; 2632 3820 {$OPTIMIZATION OFF} // Modif J.P 5/2013 2633 3821 function IntersectLine(line1, line2: TLineDef): TPointF; 2634 3822 var parallel: boolean; … … 2636 3824 result := IntersectLine(line1,line2,parallel); 2637 3825 end; 3826 {$OPTIMIZATION ON} 2638 3827 2639 3828 function IntersectLine(line1, line2: TLineDef; out parallel: boolean): TPointF; … … 2787 3976 2788 3977 // Get the cyclic value in the range [0..cycle-1] 2789 function PositiveMod(value, cycle: integer): integer; inline;3978 function PositiveMod(value, cycle: Int32or64): Int32or64; inline; 2790 3979 begin 2791 3980 result := value mod cycle; … … 2801 3990 byteSqrtTab: packed array of word; 2802 3991 2803 function Sin65536(value: word): integer;3992 function Sin65536(value: word): Int32or64; 2804 3993 var b: integer; 2805 3994 begin … … 2825 4014 end; 2826 4015 2827 function Cos65536(value: word): integer; 2828 begin 4016 function Cos65536(value: word): Int32or64; 4017 begin 4018 {$PUSH}{$R-} 2829 4019 result := Sin65536(value+16384); //cosine is translated 4020 {$POP} 2830 4021 end; 2831 4022 … … 2854 4045 end; 2855 4046 4047 function DetectFileFormat(AFilenameUTF8: string): TBGRAImageFormat; 4048 var stream: TFileStreamUTF8; 4049 begin 4050 try 4051 stream := TFileStreamUTF8.Create(AFilenameUTF8,fmOpenRead or fmShareDenyWrite); 4052 except 4053 result := ifUnknown; 4054 exit; 4055 end; 4056 try 4057 result := DetectFileFormat(stream, ExtractFileExt(AFilenameUTF8)); 4058 finally 4059 stream.Free; 4060 end; 4061 end; 4062 4063 function DetectFileFormat(AStream: TStream; ASuggestedExtensionUTF8: string 4064 ): TBGRAImageFormat; 4065 var 4066 scores: array[TBGRAImageFormat] of integer; 4067 imageFormat,bestImageFormat: TBGRAImageFormat; 4068 bestScore: integer; 4069 4070 procedure DetectFromStream; 4071 var 4072 {%H-}magic: packed array[0..7] of byte; 4073 {%H-}dwords: packed array[0..9] of DWORD; 4074 magicAsText: string; 4075 4076 streamStartPos, maxFileSize: Int64; 4077 expectedFileSize: DWord; 4078 4079 procedure DetectTarga; 4080 var 4081 paletteCount: integer; 4082 {%H-}targaPixelFormat: packed record pixelDepth: byte; imgDescriptor: byte; end; 4083 begin 4084 if (magic[1] in[$00,$01]) and (magic[2] in[0,1,2,3,9,10,11]) and (maxFileSize >= 18) then 4085 begin 4086 paletteCount:= magic[5] + magic[6] shl 8; 4087 if ((paletteCount = 0) and (magic[7] = 0)) or 4088 (magic[7] in [16,24,32]) then //check palette bit count 4089 begin 4090 AStream.Position:= streamStartPos+16; 4091 if AStream.Read({%H-}targaPixelFormat,2) = 2 then 4092 begin 4093 if (targaPixelFormat.pixelDepth in [8,16,24,32]) and 4094 (targaPixelFormat.imgDescriptor and 15 < targaPixelFormat.pixelDepth) then 4095 inc(scores[ifTarga],2); 4096 end; 4097 end; 4098 end; 4099 end; 4100 4101 procedure DetectLazPaint; 4102 var 4103 w,h: dword; 4104 i: integer; 4105 begin 4106 if (copy(magicAsText,1,8) = 'LazPaint') then //with header 4107 begin 4108 AStream.Position:= streamStartPos+8; 4109 if AStream.Read(dwords,10*4) = 10*4 then 4110 begin 4111 for i := 0 to 6 do dwords[i] := LEtoN(dwords[i]); 4112 if (dwords[0] = 0) and (dwords[1] <= expectedFileSize) and (dwords[5] <= expectedFileSize) and 4113 (dwords[9] <= expectedFileSize) and 4114 (dwords[6] = 0) then inc(scores[ifLazPaint],2); 4115 end; 4116 end else //without header 4117 if ((magic[0] <> 0) or (magic[1] <> 0)) and (magic[2] = 0) and (magic[3] = 0) and 4118 ((magic[4] <> 0) or (magic[5] <> 0)) and (magic[6] = 0) and (magic[7] = 0) then 4119 begin 4120 w := magic[0] + (magic[1] shl 8); 4121 h := magic[4] + (magic[5] shl 8); 4122 AStream.Position:= streamStartPos+8; 4123 if AStream.Read(dwords,4) = 4 then 4124 begin 4125 dwords[0] := LEtoN(dwords[0]); 4126 if (dwords[0] > 0) and (dwords[0] < 65536) then 4127 begin 4128 if 12+dwords[0] < expectedFileSize then 4129 begin 4130 AStream.Position:= streamStartPos+12+dwords[0]; 4131 if AStream.Read(dwords,6*4) = 6*4 then 4132 begin 4133 for i := 0 to 5 do dwords[i] := LEtoN(dwords[i]); 4134 if (dwords[0] <= w) and (dwords[1] <= h) and 4135 (dwords[2] <= w) and (dwords[3] <= h) and 4136 (dwords[2] >= dwords[0]) and (dwords[3] >= dwords[1]) and 4137 ((dwords[4] = 0) or (dwords[4] = 1)) and 4138 (dwords[5] > 0) then inc(scores[ifLazPaint],1); 4139 end; 4140 end; 4141 end; 4142 end; 4143 end; 4144 end; 4145 4146 begin 4147 fillchar({%H-}magic, sizeof(magic), 0); 4148 fillchar({%H-}dwords, sizeof(dwords), 0); 4149 4150 streamStartPos:= AStream.Position; 4151 maxFileSize:= AStream.Size - streamStartPos; 4152 if maxFileSize < 8 then exit; 4153 if AStream.Read(magic,sizeof(magic)) <> sizeof(magic) then 4154 begin 4155 fillchar(scores,sizeof(scores),0); 4156 exit; 4157 end; 4158 setlength(magicAsText,sizeof(magic)); 4159 move(magic[0],magicAsText[1],sizeof(magic)); 4160 4161 if (magic[0] = $ff) and (magic[1] = $d8) then 4162 begin 4163 inc(scores[ifJpeg]); 4164 if (magic[2] = $ff) and (magic[3] >= $c0) then inc(scores[ifJpeg]); 4165 end; 4166 4167 if (magic[0] = $89) and (magic[1] = $50) and (magic[2] = $4e) and 4168 (magic[3] = $47) and (magic[4] = $0d) and (magic[5] = $0a) and 4169 (magic[6] = $1a) and (magic[7] = $0a) then inc(scores[ifPng],2); 4170 4171 if (copy(magicAsText,1,6)='GIF87a') or (copy(magicAsText,1,6)='GIF89a') then inc(scores[ifGif],2); 4172 4173 if (magic[0] = $0a) and (magic[1] in [0,2,3,4,5]) and (magic[2] in[0,1]) and (magic[3] in[1,2,4,8]) then 4174 inc(scores[ifPcx],2); 4175 4176 if (copy(magicAsText,1,2)='BM') then 4177 begin 4178 inc(scores[ifBmp]); 4179 expectedFileSize:= magic[2] + (magic[3] shl 8) + (magic[4] shl 16) + (magic[5] shl 24); 4180 if expectedFileSize = maxFileSize then inc(scores[ifBmp]); 4181 end else 4182 if (copy(magicAsText,1,2)='RL') then 4183 begin 4184 inc(scores[ifBmpMioMap]); 4185 if (magic[2] in[0,1]) and (magic[3] = 0) then inc(scores[ifBmpMioMap]); 4186 end; 4187 4188 if (magic[0] = $00) and (magic[1] = $00) and (magic[2] in[$01,$02]) and (magic[3] = $00) and 4189 (magic[4] + (magic[5] shl 8) > 0) then inc(scores[ifIco]); 4190 4191 if (copy(magicAsText,1,4) = 'PDN3') then 4192 begin 4193 expectedFileSize:= 6 + (magic[4] + (magic[5] shl 8) + (magic[6] shl 16)) + 2; 4194 if expectedFileSize <= maxFileSize then 4195 begin 4196 inc(scores[ifPaintDotNet]); 4197 if magic[7] = $3c then inc(scores[ifPaintDotNet]); 4198 end; 4199 end; 4200 4201 DetectLazPaint; 4202 4203 if (magic[0] = $50) and (magic[1] = $4b) and (magic[2] = $03) and (magic[3] = $04) then 4204 begin 4205 if DefaultBGRAImageReader[ifOpenRaster] = nil then inc(scores[ifOpenRaster]) else 4206 with CreateBGRAImageReader(ifOpenRaster) do 4207 try 4208 if CheckContents(AStream) then inc(scores[ifOpenRaster],2); 4209 finally 4210 Free; 4211 end; 4212 end; 4213 4214 if (copy(magicAsText,1,4) = '8BPS') and (magic[4] = $00) and (magic[5] = $01) then inc(scores[ifPsd],2); 4215 4216 DetectTarga; 4217 4218 if (copy(magicAsText,1,2)='II') and (magic[2] = 42) and (magic[3]=0) then inc(scores[ifTiff]) else 4219 if (copy(magicAsText,1,2)='MM') and (magic[2] = 0) and (magic[3]=42) then inc(scores[ifTiff]); 4220 4221 if (copy(magicAsText,1,8) = '/* XPM *') or (copy(magicAsText,1,6) = '! XPM2') then inc(scores[ifXPixMap]); 4222 4223 AStream.Position := streamStartPos; 4224 end; 4225 4226 var 4227 extFormat: TBGRAImageFormat; 4228 4229 begin 4230 result := ifUnknown; 4231 for imageFormat:= low(TBGRAImageFormat) to high(TBGRAImageFormat) do 4232 scores[imageFormat] := 0; 4233 4234 ASuggestedExtensionUTF8:= UTF8LowerCase(ASuggestedExtensionUTF8); 4235 if (ASuggestedExtensionUTF8 <> '') and (UTF8Copy(ASuggestedExtensionUTF8,1,1) <> '.') then 4236 ASuggestedExtensionUTF8 := '.'+ASuggestedExtensionUTF8; 4237 4238 extFormat:= SuggestImageFormat(ASuggestedExtensionUTF8); 4239 if extFormat <> ifUnknown then inc(scores[extFormat]); 4240 4241 If AStream <> nil then DetectFromStream; 4242 4243 bestScore := 0; 4244 bestImageFormat:= ifUnknown; 4245 for imageFormat:=low(TBGRAImageFormat) to high(TBGRAImageFormat) do 4246 if scores[imageFormat] > bestScore then 4247 begin 4248 bestScore:= scores[imageFormat]; 4249 bestImageFormat:= imageFormat; 4250 end; 4251 result := bestImageFormat; 4252 end; 4253 4254 function SuggestImageFormat(AFilenameOrExtensionUTF8: string): TBGRAImageFormat; 4255 var ext: string; 4256 begin 4257 result := ifUnknown; 4258 4259 ext := ExtractFileName(AFilenameOrExtensionUTF8); 4260 if pos('.', ext) <> 0 then ext := ExtractFileExt(ext) else ext := '.'+ext; 4261 ext := UTF8LowerCase(ext); 4262 4263 if (ext = '.jpg') or (ext = '.jpeg') then result := ifJpeg else 4264 if (ext = '.png') then result := ifPng else 4265 if (ext = '.gif') then result := ifGif else 4266 if (ext = '.pcx') then result := ifPcx else 4267 if (ext = '.bmp') then result := ifBmp else 4268 if (ext = '.ico') or (ext = '.cur') then result := ifIco else 4269 if (ext = '.pdn') then result := ifPaintDotNet else 4270 if (ext = '.lzp') then result := ifLazPaint else 4271 if (ext = '.ora') then result := ifOpenRaster else 4272 if (ext = '.psd') then result := ifPsd else 4273 if (ext = '.tga') then result := ifTarga else 4274 if (ext = '.tif') or (ext = '.tiff') then result := ifTiff else 4275 if (ext = '.xwd') then result := ifXwd else 4276 if (ext = '.xpm') then result := ifXPixMap; 4277 end; 4278 4279 function CreateBGRAImageReader(AFormat: TBGRAImageFormat): TFPCustomImageReader; 4280 begin 4281 if DefaultBGRAImageReader[AFormat] = nil then 4282 begin 4283 case AFormat of 4284 ifUnknown: raise exception.Create('The image format is unknown.'); 4285 ifOpenRaster: raise exception.Create('You need to call BGRAOpenRaster.RegisterOpenRasterFormat to read this image.'); 4286 ifPaintDotNet: raise exception.Create('You need to call BGRAPaintNet.RegisterPaintNetFormat to read this image.'); 4287 else 4288 raise exception.Create('The image reader is not registered for this image format.'); 4289 end; 4290 end; 4291 result := DefaultBGRAImageReader[AFormat].Create; 4292 end; 4293 4294 function CreateBGRAImageWriter(AFormat: TBGRAImageFormat; AHasTransparentPixels: boolean): TFPCustomImageWriter; 4295 begin 4296 if DefaultBGRAImageWriter[AFormat] = nil then 4297 begin 4298 case AFormat of 4299 ifUnknown: raise exception.Create('The image format is unknown'); 4300 ifOpenRaster: raise exception.Create('You need to call BGRAOpenRaster.RegisterOpenRasterFormat to write with this image format.'); 4301 else 4302 raise exception.Create('The image writer is not registered for this image format.'); 4303 end; 4304 end; 4305 4306 if AFormat = ifPng then 4307 begin 4308 result := TFPWriterPNG.Create; 4309 TFPWriterPNG(result).Indexed := false; 4310 TFPWriterPNG(result).WordSized := false; 4311 TFPWriterPNG(result).UseAlpha := AHasTransparentPixels; 4312 end else 4313 if AFormat = ifBmp then 4314 begin 4315 result := TFPWriterBMP.Create; 4316 if AHasTransparentPixels then 4317 TFPWriterBMP(result).BitsPerPixel := 32 else 4318 TFPWriterBMP(result).BitsPerPixel := 24; 4319 end else 4320 if AFormat = ifXPixMap then 4321 begin 4322 result := TFPWriterXPM.Create; 4323 TFPWriterXPM(result).ColorCharSize := 2; 4324 end else 4325 result := DefaultBGRAImageWriter[AFormat].Create; 4326 end; 4327 2856 4328 initialization 2857 4329 2858 4330 InitGamma; 2859 CSSColors := TBGRAColorList.Create; 2860 CSSColors.Add('AliceBlue',CSSAliceBlue); 2861 CSSColors.Add('AntiqueWhite',CSSAntiqueWhite); 2862 CSSColors.Add('Aqua',CSSAqua); 2863 CSSColors.Add('Aquamarine',CSSAquamarine); 2864 CSSColors.Add('Azure',CSSAzure); 2865 CSSColors.Add('Beige',CSSBeige); 2866 CSSColors.Add('Bisque',CSSBisque); 2867 CSSColors.Add('Black',CSSBlack); 2868 CSSColors.Add('BlanchedAlmond',CSSBlanchedAlmond); 2869 CSSColors.Add('Blue',CSSBlue); 2870 CSSColors.Add('BlueViolet',CSSBlueViolet); 2871 CSSColors.Add('Brown',CSSBrown); 2872 CSSColors.Add('BurlyWood',CSSBurlyWood); 2873 CSSColors.Add('CadetBlue',CSSCadetBlue); 2874 CSSColors.Add('Chartreuse',CSSChartreuse); 2875 CSSColors.Add('Chocolate',CSSChocolate); 2876 CSSColors.Add('Coral',CSSCoral); 2877 CSSColors.Add('CornflowerBlue',CSSCornflowerBlue); 2878 CSSColors.Add('Cornsilk',CSSCornsilk); 2879 CSSColors.Add('Crimson',CSSCrimson); 2880 CSSColors.Add('Cyan',CSSCyan); 2881 CSSColors.Add('DarkBlue',CSSDarkBlue); 2882 CSSColors.Add('DarkCyan',CSSDarkCyan); 2883 CSSColors.Add('DarkGoldenrod',CSSDarkGoldenrod); 2884 CSSColors.Add('DarkGray',CSSDarkGray); 2885 CSSColors.Add('DarkGreen',CSSDarkGreen); 2886 CSSColors.Add('DarkKhaki',CSSDarkKhaki); 2887 CSSColors.Add('DarkMagenta',CSSDarkMagenta); 2888 CSSColors.Add('DarkOliveGreen',CSSDarkOliveGreen); 2889 CSSColors.Add('DarkOrange',CSSDarkOrange); 2890 CSSColors.Add('DarkOrchid',CSSDarkOrchid); 2891 CSSColors.Add('DarkRed',CSSDarkRed); 2892 CSSColors.Add('DarkSalmon',CSSDarkSalmon); 2893 CSSColors.Add('DarkSeaGreen',CSSDarkSeaGreen); 2894 CSSColors.Add('DarkSlateBlue',CSSDarkSlateBlue); 2895 CSSColors.Add('DarkSlateGray',CSSDarkSlateGray); 2896 CSSColors.Add('DarkTurquoise',CSSDarkTurquoise); 2897 CSSColors.Add('DarkViolet',CSSDarkViolet); 2898 CSSColors.Add('DeepPink',CSSDeepPink); 2899 CSSColors.Add('DeepSkyBlue',CSSDeepSkyBlue); 2900 CSSColors.Add('DimGray',CSSDimGray); 2901 CSSColors.Add('DodgerBlue',CSSDodgerBlue); 2902 CSSColors.Add('FireBrick',CSSFireBrick); 2903 CSSColors.Add('FloralWhite',CSSFloralWhite); 2904 CSSColors.Add('ForestGreen',CSSForestGreen); 2905 CSSColors.Add('Fuchsia',CSSFuchsia); 2906 CSSColors.Add('Gainsboro',CSSGainsboro); 2907 CSSColors.Add('GhostWhite',CSSGhostWhite); 2908 CSSColors.Add('Gold',CSSGold); 2909 CSSColors.Add('Goldenrod',CSSGoldenrod); 2910 CSSColors.Add('Gray',CSSGray); 2911 CSSColors.Add('Green',CSSGreen); 2912 CSSColors.Add('GreenYellow',CSSGreenYellow); 2913 CSSColors.Add('Honeydew',CSSHoneydew); 2914 CSSColors.Add('HotPink',CSSHotPink); 2915 CSSColors.Add('IndianRed',CSSIndianRed); 2916 CSSColors.Add('Indigo',CSSIndigo); 2917 CSSColors.Add('Ivory',CSSIvory); 2918 CSSColors.Add('Khaki',CSSKhaki); 2919 CSSColors.Add('Lavender',CSSLavender); 2920 CSSColors.Add('LavenderBlush',CSSLavenderBlush); 2921 CSSColors.Add('LawnGreen',CSSLawnGreen); 2922 CSSColors.Add('LemonChiffon',CSSLemonChiffon); 2923 CSSColors.Add('LightBlue',CSSLightBlue); 2924 CSSColors.Add('LightCoral',CSSLightCoral); 2925 CSSColors.Add('LightCyan',CSSLightCyan); 2926 CSSColors.Add('LightGoldenrodYellow',CSSLightGoldenrodYellow); 2927 CSSColors.Add('LightGray',CSSLightGray); 2928 CSSColors.Add('LightGreen',CSSLightGreen); 2929 CSSColors.Add('LightPink',CSSLightPink); 2930 CSSColors.Add('LightSalmon',CSSLightSalmon); 2931 CSSColors.Add('LightSeaGreen',CSSLightSeaGreen); 2932 CSSColors.Add('LightSkyBlue',CSSLightSkyBlue); 2933 CSSColors.Add('LightSlateGray',CSSLightSlateGray); 2934 CSSColors.Add('LightSteelBlue',CSSLightSteelBlue); 2935 CSSColors.Add('LightYellow',CSSLightYellow); 2936 CSSColors.Add('Lime',CSSLime); 2937 CSSColors.Add('LimeGreen',CSSLimeGreen); 2938 CSSColors.Add('Linen',CSSLinen); 2939 CSSColors.Add('Magenta',CSSMagenta); 2940 CSSColors.Add('Maroon',CSSMaroon); 2941 CSSColors.Add('MediumAquamarine',CSSMediumAquamarine); 2942 CSSColors.Add('MediumBlue',CSSMediumBlue); 2943 CSSColors.Add('MediumOrchid',CSSMediumOrchid); 2944 CSSColors.Add('MediumPurple',CSSMediumPurple); 2945 CSSColors.Add('MediumSeaGreen',CSSMediumSeaGreen); 2946 CSSColors.Add('MediumSlateBlue',CSSMediumSlateBlue); 2947 CSSColors.Add('MediumSpringGreen',CSSMediumSpringGreen); 2948 CSSColors.Add('MediumTurquoise',CSSMediumTurquoise); 2949 CSSColors.Add('MediumVioletRed',CSSMediumVioletRed); 2950 CSSColors.Add('MidnightBlue',CSSMidnightBlue); 2951 CSSColors.Add('MintCream',CSSMintCream); 2952 CSSColors.Add('MistyRose',CSSMistyRose); 2953 CSSColors.Add('Moccasin',CSSMoccasin); 2954 CSSColors.Add('NavajoWhite',CSSNavajoWhite); 2955 CSSColors.Add('Navy',CSSNavy); 2956 CSSColors.Add('OldLace',CSSOldLace); 2957 CSSColors.Add('Olive',CSSOlive); 2958 CSSColors.Add('OliveDrab',CSSOliveDrab); 2959 CSSColors.Add('Orange',CSSOrange); 2960 CSSColors.Add('OrangeRed',CSSOrangeRed); 2961 CSSColors.Add('Orchid',CSSOrchid); 2962 CSSColors.Add('PaleGoldenrod',CSSPaleGoldenrod); 2963 CSSColors.Add('PaleGreen',CSSPaleGreen); 2964 CSSColors.Add('PaleTurquoise',CSSPaleTurquoise); 2965 CSSColors.Add('PaleVioletRed',CSSPaleVioletRed); 2966 CSSColors.Add('PapayaWhip',CSSPapayaWhip); 2967 CSSColors.Add('PeachPuff',CSSPeachPuff); 2968 CSSColors.Add('Peru',CSSPeru); 2969 CSSColors.Add('Pink',CSSPink); 2970 CSSColors.Add('Plum',CSSPlum); 2971 CSSColors.Add('PowderBlue',CSSPowderBlue); 2972 CSSColors.Add('Purple',CSSPurple); 2973 CSSColors.Add('Red',CSSRed); 2974 CSSColors.Add('RosyBrown',CSSRosyBrown); 2975 CSSColors.Add('RoyalBlue',CSSRoyalBlue); 2976 CSSColors.Add('SaddleBrown',CSSSaddleBrown); 2977 CSSColors.Add('Salmon',CSSSalmon); 2978 CSSColors.Add('SandyBrown',CSSSandyBrown); 2979 CSSColors.Add('SeaGreen',CSSSeaGreen); 2980 CSSColors.Add('Seashell',CSSSeashell); 2981 CSSColors.Add('Sienna',CSSSienna); 2982 CSSColors.Add('Silver',CSSSilver); 2983 CSSColors.Add('SkyBlue',CSSSkyBlue); 2984 CSSColors.Add('SlateBlue',CSSSlateBlue); 2985 CSSColors.Add('SlateGray',CSSSlateGray); 2986 CSSColors.Add('Snow',CSSSnow); 2987 CSSColors.Add('SpringGreen',CSSSpringGreen); 2988 CSSColors.Add('SteelBlue',CSSSteelBlue); 2989 CSSColors.Add('Tan',CSSTan); 2990 CSSColors.Add('Teal',CSSTeal); 2991 CSSColors.Add('Thistle',CSSThistle); 2992 CSSColors.Add('Tomato',CSSTomato); 2993 CSSColors.Add('Turquoise',CSSTurquoise); 2994 CSSColors.Add('Violet',CSSViolet); 2995 CSSColors.Add('Wheat',CSSWheat); 2996 CSSColors.Add('White',CSSWhite); 2997 CSSColors.Add('WhiteSmoke',CSSWhiteSmoke); 2998 CSSColors.Add('Yellow',CSSYellow); 2999 CSSColors.Add('YellowGreen',CSSYellowGreen); 3000 CSSColors.Finished; 4331 {$DEFINE INCLUDE_COLOR_LIST} 4332 {$I csscolorconst.inc} 4333 DefaultBGRAImageWriter[ifJpeg] := TFPWriterJPEG; 4334 DefaultBGRAImageWriter[ifPng] := TFPWriterPNG; 4335 DefaultBGRAImageWriter[ifBmp] := TFPWriterBMP; 4336 DefaultBGRAImageWriter[ifPcx] := TFPWriterPCX; 4337 DefaultBGRAImageWriter[ifTarga] := TFPWriterTarga; 4338 DefaultBGRAImageWriter[ifXPixMap] := TFPWriterXPM; 4339 DefaultBGRAImageWriter[ifTiff] := TFPWriterTiff; 4340 //writing XWD not implemented 4341 4342 DefaultBGRAImageReader[ifTiff] := TFPReaderTiff; 4343 DefaultBGRAImageReader[ifXwd] := TFPReaderXWD; 4344 //the other readers are registered by their unit 3001 4345 3002 4346 finalization 3003 4347 3004 4348 CSSColors.Free; 4349 VGAColors.Free; 3005 4350 3006 4351 end. -
GraphicTest/Packages/bgrabitmap/bgrablend.pas
r452 r472 26 26 27 27 { Draw a series of pixels with alpha blending } 28 procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer; mode: TDrawMode; AOpacity:byte); 28 29 procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline; overload; 29 30 procedure DrawExpandedPixelsInline(dest: PBGRAPixel; ec: TExpandedPixel; Count: integer); inline; overload; … … 238 239 end; 239 240 241 procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer; 242 mode: TDrawMode; AOpacity: byte); 243 var i: integer; tempPixel: TBGRAPixel; 244 begin 245 case mode of 246 dmSet: 247 begin 248 if AOpacity <> 255 then 249 CopyPixelsWithOpacity(pdest, psource, AOpacity, copycount) 250 else 251 begin 252 copycount *= sizeof(TBGRAPixel); 253 move(psource^, pdest^, copycount); 254 end; 255 end; 256 dmSetExceptTransparent: 257 begin 258 if AOpacity <> 255 then 259 begin 260 for i := copycount - 1 downto 0 do 261 begin 262 if psource^.alpha = 255 then 263 begin 264 tempPixel := psource^; 265 tempPixel.alpha := ApplyOpacity(tempPixel.alpha,AOpacity); 266 FastBlendPixelInline(pdest,tempPixel); 267 end; 268 Inc(pdest); 269 Inc(psource); 270 end; 271 end else 272 for i := copycount - 1 downto 0 do 273 begin 274 if psource^.alpha = 255 then 275 pdest^ := psource^; 276 Inc(pdest); 277 Inc(psource); 278 end; 279 end; 280 dmDrawWithTransparency: 281 begin 282 if AOpacity <> 255 then 283 begin 284 for i := copycount - 1 downto 0 do 285 begin 286 DrawPixelInlineWithAlphaCheck(pdest, psource^, AOpacity); 287 Inc(pdest); 288 Inc(psource); 289 end; 290 end 291 else 292 for i := copycount - 1 downto 0 do 293 begin 294 DrawPixelInlineWithAlphaCheck(pdest, psource^); 295 Inc(pdest); 296 Inc(psource); 297 end; 298 end; 299 dmFastBlend: 300 begin 301 if AOpacity <> 255 then 302 begin 303 for i := copycount - 1 downto 0 do 304 begin 305 FastBlendPixelInline(pdest, psource^, AOpacity); 306 Inc(pdest); 307 Inc(psource); 308 end; 309 end else 310 for i := copycount - 1 downto 0 do 311 begin 312 FastBlendPixelInline(pdest, psource^); 313 Inc(pdest); 314 Inc(psource); 315 end; 316 end; 317 dmXor: 318 begin 319 if AOpacity <> 255 then 320 begin 321 for i := copycount - 1 downto 0 do 322 begin 323 FastBlendPixelInline(pdest, TBGRAPixel(PDWord(pdest)^ xor PDword(psource)^), AOpacity); 324 Inc(pdest); 325 Inc(psource); 326 end; 327 end else 328 XorPixels(pdest, psource, copycount); 329 end; 330 end; 331 end; 332 240 333 procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); 241 334 var … … 385 478 a1f, a2f, a12, a12m: cardinal; 386 479 begin 480 {$HINTS OFF} 387 481 a12 := 65025 - (not dest^.alpha) * (not c.alpha); 482 {$HINTS ON} 388 483 a12m := a12 shr 1; 389 484 … … 412 507 a1f, a2f, a12, a12m: cardinal; 413 508 begin 509 {$HINTS OFF} 414 510 a12 := 65025 - (not dest^.alpha) * (not calpha); 511 {$HINTS ON} 415 512 a12m := a12 shr 1; 416 513 … … 446 543 end; 447 544 545 {$HINTS OFF} 448 546 a12 := 65025 - (not dest^.alpha) * (not c.alpha); 547 {$HINTS ON} 449 548 a12m := a12 shr 1; 450 549 -
GraphicTest/Packages/bgrabitmap/bgracanvas.pas
r452 r472 6 6 7 7 uses 8 Classes, SysUtils, Graphics, GraphType, Types, FPImage, FPCanvas, BGRABitmapTypes;8 Classes, SysUtils, FPCanvas, Graphics, GraphType, Types, FPImage, BGRABitmapTypes; 9 9 10 10 type … … 229 229 procedure TBGRAFont.SetAntialiasing(const AValue: Boolean); 230 230 begin 231 if AValue and not Antialiasing then 232 Quality := fqFineAntialiasing; 231 if AValue = Antialiasing then exit; 232 if AValue then 233 Quality := fqFineAntialiasing 234 else 235 Quality := fqSystem; 233 236 end; 234 237 … … 279 282 if cf.Italic then Style += [fsItalic]; 280 283 if cf.Underline then Style += [fsUnderline]; 284 {$IF FPC_FULLVERSION>=20602} //changed in 2.6.2 and 2.7 285 if cf.StrikeThrough then Style += [fsStrikeOut]; 286 {$ELSE} 281 287 if cf.StrikeTrough then Style += [fsStrikeOut]; 288 {$ENDIF} 282 289 Name := cf.Name; 283 290 //Orientation := cf.Orientation; … … 916 923 dec(x2); 917 924 dec(y2); 925 926 if (Pen.Style = psSolid) and not Filled then 927 begin 928 ApplyPenStyle; 929 FBitmap.RectangleAntialias(x1,y1,x2,y2,Pen.ActualColor,Pen.ActualWidth); 930 exit; 931 end; 932 918 933 tex := Brush.BuildTexture(FBitmap); 919 934 -
GraphicTest/Packages/bgrabitmap/bgracanvas2d.pas
r452 r472 3 3 { To do : 4 4 5 draw text with a different precision if the matrix is scaled 6 drawImage(in image, in double sx, in double sy, in double sw, in double sh, in double dx, in double dy, in double dw, in double dh) 7 -> using FillPoly with texture coordinates 5 8 linear gradient any transformation 6 9 clearPath clipping 7 10 createRadialGradient 8 text functions9 11 globalCompositeOperation 10 drawImage(in image, in double sx, in double sy, in double sw, in double sh, in double dx, in double dy, in double dw, in double dh)11 12 image data functions 12 13 } … … 17 18 18 19 uses 19 Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATransform, BGRAGradientScanner ;20 Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATransform, BGRAGradientScanner, BGRAPath; 20 21 21 22 type … … 47 48 globalAlpha: byte; 48 49 50 fontName: string; 51 fontStyle: TFontStyles; 52 fontEmHeight: single; 53 textAlign: TAlignment; 54 textBaseline: string; 55 49 56 lineWidth: single; 50 57 lineCap: TPenEndCap; … … 55 62 shadowOffsetX,shadowOffsetY,shadowBlur: single; 56 63 shadowColor: TBGRAPixel; 64 shadowFastest: boolean; 57 65 58 66 matrix: TAffineMatrix; … … 63 71 end; 64 72 73 TCanvas2dTextSize = record 74 width,height: single; 75 end; 76 65 77 { TBGRACanvas2D } 66 78 67 TBGRACanvas2D = class 79 TBGRACanvas2D = class(IBGRAPath) 68 80 private 69 81 FSurface: TBGRACustomBitmap; … … 74 86 FPathPoints: array of TPointF; 75 87 FPathPointCount: integer; 88 FFontRenderer: TBGRACustomFontRenderer; 89 FLastCoord, FStartCoord: TPointF; 90 function GetCurrentPath: ArrayOfTPointF; 91 function GetFontName: string; 92 function GetFontRenderer: TBGRACustomFontRenderer; 93 function GetFontEmHeight: single; 94 function GetFontString: string; 95 function GetFontStyle: TFontStyles; 76 96 function GetGlobalAlpha: single; 77 97 function GetHasShadow: boolean; 78 98 function GetHeight: Integer; 79 99 function GetLineCap: string; 100 function GetLineCapLCL: TPenEndCap; 80 101 function GetlineJoin: string; 102 function GetlineJoinLCL: TPenJoinStyle; 81 103 function GetLineWidth: single; 104 function GetMatrix: TAffineMatrix; 82 105 function GetMiterLimit: single; 83 106 function GetPixelCenteredCoordinates: boolean; 84 107 function GetShadowBlur: single; 108 function GetShadowFastest: boolean; 85 109 function GetShadowOffset: TPointF; 86 110 function GetShadowOffsetX: single; 87 111 function GetShadowOffsetY: single; 112 function GetTextAlign: string; 113 function GetTextAlignLCL: TAlignment; 114 function GetTextBaseline: string; 88 115 function GetWidth: Integer; 116 procedure SetFontName(AValue: string); 117 procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); 118 procedure SetFontEmHeight(AValue: single); 119 procedure SetFontString(AValue: string); 120 procedure SetFontStyle(AValue: TFontStyles); 89 121 procedure SetGlobalAlpha(const AValue: single); 90 122 procedure SetLineCap(const AValue: string); 123 procedure SetLineCapLCL(AValue: TPenEndCap); 91 124 procedure SetLineJoin(const AValue: string); 92 125 procedure FillPoly(const points: array of TPointF); 93 126 procedure FillStrokePoly(const points: array of TPointF; fillOver: boolean); 127 procedure SetLineJoinLCL(AValue: TPenJoinStyle); 94 128 procedure SetLineWidth(const AValue: single); 129 procedure SetMatrix(AValue: TAffineMatrix); 95 130 procedure SetMiterLimit(const AValue: single); 96 131 procedure SetPixelCenteredCoordinates(const AValue: boolean); 97 132 procedure SetShadowBlur(const AValue: single); 133 procedure SetShadowFastest(AValue: boolean); 98 134 procedure SetShadowOffset(const AValue: TPointF); 99 135 procedure SetShadowOffsetX(const AValue: single); 100 136 procedure SetShadowOffsetY(const AValue: single); 137 procedure SetTextAlign(AValue: string); 138 procedure SetTextAlignLCL(AValue: TAlignment); 139 procedure SetTextBaseine(AValue: string); 101 140 procedure StrokePoly(const points: array of TPointF); 102 141 procedure DrawShadow(const points, points2: array of TPointF); … … 105 144 function ApplyTransform(const points: array of TPointF): ArrayOfTPointF; overload; 106 145 function ApplyTransform(point: TPointF): TPointF; overload; 107 function GetPenPos: TPointF; 146 function GetPenPos(defaultX, defaultY: single): TPointF; 147 function GetPenPos(defaultPt: TPointF): TPointF; 108 148 procedure AddPoint(point: TPointF); 109 149 procedure AddPoints(const points: array of TPointF); 110 150 procedure AddPointsRev(const points: array of TPointF); 111 151 function ApplyGlobalAlpha(color: TBGRAPixel): TBGRAPixel; 152 function GetDrawMode: TDrawMode; 153 procedure copyTo({%H-}dest: IBGRAPath); //IBGRAPath 112 154 public 155 antialiasing, linearBlend: boolean; 113 156 constructor Create(ASurface: TBGRACustomBitmap); 114 157 destructor Destroy; override; … … 118 161 procedure save; 119 162 procedure restore; 120 procedure scale(x,y: single); 121 procedure rotate(angleRad: single); 163 procedure scale(x,y: single); overload; 164 procedure scale(factor: single); overload; 165 procedure rotate(angleRadCW: single); 122 166 procedure translate(x,y: single); 123 procedure transform(a,b,c,d,e,f: single); 167 procedure transform(a,b,c,d,e,f: single); overload; 168 procedure transform(AMatrix: TAffineMatrix); overload; 124 169 procedure setTransform(a,b,c,d,e,f: single); 125 170 procedure resetTransform; … … 137 182 procedure shadowColor(color: TColor); overload; 138 183 procedure shadowColor(color: string); overload; 184 procedure shadowNone; 139 185 function getShadowColor: TBGRAPixel; 140 186 function createLinearGradient(x0,y0,x1,y1: single): IBGRACanvasGradient2D; overload; … … 149 195 procedure clearRect(x,y,w,h: single); 150 196 197 procedure addPath(APath: IBGRAPath); overload; 198 procedure addPath(ASvgPath: string); overload; 199 procedure path(APath: IBGRAPath); overload; 200 procedure path(ASvgPath: string); overload; 151 201 procedure beginPath; 152 202 procedure closePath; … … 154 204 procedure moveTo(x,y: single); overload; 155 205 procedure lineTo(x,y: single); overload; 156 procedure moveTo( pt: TPointF); overload;157 procedure lineTo( pt: TPointF); overload;206 procedure moveTo(const pt: TPointF); overload; 207 procedure lineTo(const pt: TPointF); overload; 158 208 procedure polylineTo(const pts: array of TPointF); 159 209 procedure quadraticCurveTo(cpx,cpy,x,y: single); overload; 160 procedure quadraticCurveTo(c p,pt: TPointF); overload;210 procedure quadraticCurveTo(const cp,pt: TPointF); overload; 161 211 procedure bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y: single); overload; 162 procedure bezierCurveTo(c p1,cp2,pt: TPointF); overload;212 procedure bezierCurveTo(const cp1,cp2,pt: TPointF); overload; 163 213 procedure rect(x,y,w,h: single); 164 procedure roundRect(x,y,w,h,radius: single); 214 procedure roundRect(x,y,w,h,radius: single); overload; 215 procedure roundRect(x,y,w,h,rx,ry: single); overload; 165 216 procedure spline(const pts: array of TPointF; style: TSplineStyle= ssOutside); 166 217 procedure splineTo(const pts: array of TPointF; style: TSplineStyle= ssOutside); 167 procedure arc(x, y, radius, startAngle, endAngle: single; anticlockwise: boolean); overload; 168 procedure arc(x, y, radius, startAngle, endAngle: single); overload; 218 procedure arc(x, y, radius, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload; 219 procedure arc(x, y, radius, startAngleRadCW, endAngleRadCW: single); overload; 220 procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload; 221 procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single); overload; 222 procedure arc(const arcDef: TArcDef); overload; 169 223 procedure arcTo(x1, y1, x2, y2, radius: single); overload; 170 224 procedure arcTo(p1,p2: TPointF; radius: single); overload; 225 procedure arcTo(rx, ry, xAngleRadCW: single; largeArc,anticlockwise: boolean; x, y: single); 226 procedure circle(x,y,r: single); 227 procedure ellipse(x,y,rx,ry: single); 228 procedure text(AText: string; x,y: single); 229 procedure fillText(AText: string; x,y: single); 230 procedure strokeText(AText: string; x,y: single); 231 function measureText(AText: string): TCanvas2dTextSize; 232 171 233 procedure fill; 172 234 procedure stroke; … … 183 245 184 246 function getLineStyle: TBGRAPenStyle; 185 procedure lineStyle(const AValue: array of single); 247 procedure lineStyle(const AValue: array of single); overload; 248 procedure lineStyle(AStyle: TPenStyle); overload; 186 249 187 250 property surface: TBGRACustomBitmap read FSurface; … … 190 253 property pixelCenteredCoordinates: boolean read GetPixelCenteredCoordinates write SetPixelCenteredCoordinates; 191 254 property globalAlpha: single read GetGlobalAlpha write SetGlobalAlpha; 255 property matrix: TAffineMatrix read GetMatrix write SetMatrix; 192 256 193 257 property lineWidth: single read GetLineWidth write SetLineWidth; 194 258 property lineCap: string read GetLineCap write SetLineCap; 259 property lineCapLCL: TPenEndCap read GetLineCapLCL write SetLineCapLCL; 195 260 property lineJoin: string read GetlineJoin write SetLineJoin; 261 property lineJoinLCL: TPenJoinStyle read GetlineJoinLCL write SetLineJoinLCL; 196 262 property miterLimit: single read GetMiterLimit write SetMiterLimit; 197 263 … … 200 266 property shadowOffset: TPointF read GetShadowOffset write SetShadowOffset; 201 267 property shadowBlur: single read GetShadowBlur write SetShadowBlur; 268 property shadowFastest: boolean read GetShadowFastest write SetShadowFastest; 202 269 property hasShadow: boolean read GetHasShadow; 270 271 property fontName: string read GetFontName write SetFontName; 272 property fontEmHeight: single read GetFontEmHeight write SetFontEmHeight; 273 property fontStyle: TFontStyles read GetFontStyle write SetFontStyle; 274 property font: string read GetFontString write SetFontString; 275 property textAlignLCL: TAlignment read GetTextAlignLCL write SetTextAlignLCL; 276 property textAlign: string read GetTextAlign write SetTextAlign; 277 property textBaseline: string read GetTextBaseline write SetTextBaseine; 278 279 property currentPath: ArrayOfTPointF read GetCurrentPath; 280 property fontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer; 281 282 protected 283 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 284 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 285 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 203 286 end; 204 287 205 288 implementation 206 289 207 uses Math, BGRAPen, BGRAFillInfo, BGRAPolygon, BGRABlend, FPWriteJPEG, FPWriteBMP, base64;290 uses Types, Math, BGRAPen, BGRAFillInfo, BGRAPolygon, BGRABlend, FPWriteJPEG, FPWriteBMP, base64; 208 291 209 292 type … … 446 529 globalAlpha := 255; 447 530 531 fontName := 'Arial'; 532 fontEmHeight := 10; 533 fontStyle := []; 534 textAlign:= taLeftJustify; 535 textBaseline := 'alphabetic'; 536 448 537 lineWidth := 1; 449 538 lineCap := pecFlat; … … 456 545 shadowBlur := 0; 457 546 shadowColor := BGRAPixelTransparent; 547 shadowFastest:= false; 458 548 459 549 matrix := AMatrix; … … 473 563 result.globalAlpha := globalAlpha; 474 564 565 result.fontName:= fontName; 566 result.fontEmHeight := fontEmHeight; 567 result.fontStyle := fontStyle; 568 475 569 result.lineWidth := lineWidth; 476 570 result.lineCap := lineCap; … … 483 577 result.shadowBlur := shadowBlur; 484 578 result.shadowColor := shadowColor; 579 result.shadowFastest := shadowFastest; 485 580 end; 486 581 … … 495 590 function TBGRACanvas2D.GetHeight: Integer; 496 591 begin 497 result := Surface.Height; 592 if Assigned(surface) then 593 result := Surface.Height 594 else 595 result := 0; 498 596 end; 499 597 … … 507 605 end; 508 606 607 function TBGRACanvas2D.GetLineCapLCL: TPenEndCap; 608 begin 609 result := currentState.lineCap; 610 end; 611 509 612 function TBGRACanvas2D.GetlineJoin: string; 510 613 begin … … 516 619 end; 517 620 621 function TBGRACanvas2D.GetlineJoinLCL: TPenJoinStyle; 622 begin 623 result := currentState.lineJoin; 624 end; 625 518 626 function TBGRACanvas2D.getLineStyle: TBGRAPenStyle; 519 627 begin … … 526 634 end; 527 635 636 function TBGRACanvas2D.GetMatrix: TAffineMatrix; 637 begin 638 result := currentState.matrix; 639 end; 640 528 641 function TBGRACanvas2D.GetMiterLimit: single; 529 642 begin … … 541 654 end; 542 655 656 function TBGRACanvas2D.GetShadowFastest: boolean; 657 begin 658 result := currentState.shadowFastest; 659 end; 660 543 661 function TBGRACanvas2D.GetShadowOffset: TPointF; 544 662 begin … … 556 674 end; 557 675 676 function TBGRACanvas2D.GetTextAlign: string; 677 begin 678 case currentState.textAlign of 679 taRightJustify: result := 'right'; 680 taCenter: result := 'center'; 681 else 682 result := 'left'; 683 end; 684 end; 685 686 function TBGRACanvas2D.GetTextAlignLCL: TAlignment; 687 begin 688 result := currentState.textAlign; 689 end; 690 691 function TBGRACanvas2D.GetTextBaseline: string; 692 begin 693 result := currentState.textBaseline; 694 end; 695 558 696 function TBGRACanvas2D.GetGlobalAlpha: single; 559 697 begin 560 698 result := currentState.globalAlpha/255; 699 end; 700 701 function TBGRACanvas2D.GetCurrentPath: ArrayOfTPointF; 702 var i: integer; 703 begin 704 setlength(result, FPathPointCount); 705 for i := 0 to high(result) do 706 result[i] := FPathPoints[i]; 707 end; 708 709 function TBGRACanvas2D.GetFontName: string; 710 begin 711 result := currentState.fontName; 712 end; 713 714 function TBGRACanvas2D.GetFontRenderer: TBGRACustomFontRenderer; 715 var zoom1,zoom2,zoom: single; 716 begin 717 if FFontRenderer = nil then 718 begin 719 if FSurface <> nil then 720 result := FSurface.FontRenderer 721 else 722 result := nil; 723 end else 724 result := FFontRenderer; 725 if Assigned(result) then 726 begin 727 result.FontName := currentState.fontName; 728 result.FontStyle := currentState.fontStyle; 729 if antialiasing then 730 result.FontQuality:= fqFineAntialiasing 731 else 732 result.FontQuality := fqSystem; 733 result.FontOrientation := 0; 734 zoom1 := VectLen(currentState.matrix[1,1],currentState.matrix[2,1]); 735 zoom2 := VectLen(currentState.matrix[1,2],currentState.matrix[2,2]); 736 if zoom1>zoom2 then zoom := zoom1 else zoom := zoom2; 737 result.FontEmHeight := round(currentState.fontEmHeight*zoom); 738 end; 739 end; 740 741 function TBGRACanvas2D.GetFontEmHeight: single; 742 begin 743 result := currentState.fontEmHeight; 744 end; 745 746 function TBGRACanvas2D.GetFontString: string; 747 var formats: TFormatSettings; 748 begin 749 formats := DefaultFormatSettings; 750 formats.DecimalSeparator := '.'; 751 752 result := ''; 753 if fsItalic in currentState.fontStyle then 754 result := result+'italic '; 755 if fsBold in currentState.fontStyle then 756 result += 'bold '; 757 result += FloatToStrF(currentState.fontEmHeight,ffGeneral,6,0,formats)+'px '; 758 result += currentState.fontName; 759 result := trim(result); 760 end; 761 762 function TBGRACanvas2D.GetFontStyle: TFontStyles; 763 begin 764 result := currentState.fontStyle; 561 765 end; 562 766 … … 570 774 function TBGRACanvas2D.GetWidth: Integer; 571 775 begin 572 result := Surface.Width; 776 if Assigned(Surface) then 777 result := Surface.Width 778 else 779 result := 0; 780 end; 781 782 procedure TBGRACanvas2D.SetFontName(AValue: string); 783 begin 784 currentState.fontName := AValue; 785 end; 786 787 procedure TBGRACanvas2D.SetFontRenderer(AValue: TBGRACustomFontRenderer); 788 begin 789 if AValue = FFontRenderer then exit; 790 FreeAndNil(FFontRenderer); 791 FFontRenderer := AValue; 792 end; 793 794 procedure TBGRACanvas2D.SetFontEmHeight(AValue: single); 795 begin 796 currentState.fontEmHeight := AValue; 797 end; 798 799 procedure TBGRACanvas2D.SetFontString(AValue: string); 800 var idxSpace,errPos: integer; 801 attrib,u: string; 802 value: single; 803 begin 804 currentState.fontStyle := []; 805 currentState.fontEmHeight := 10; 806 currentState.fontName := 'Arial'; 807 AValue := trim(AValue); 808 while AValue <> '' do 809 begin 810 while (AValue <> '') and (AValue[1]in [#0..#32]) do delete(AValue,1,1); 811 idxSpace := pos(' ',AValue); 812 if idxSpace = 0 then 813 attrib := AValue 814 else 815 attrib := copy(AValue,1,idxSpace-1); 816 attrib := lowerCase(attrib); 817 if attrib = '' then break; 818 if (attrib = 'normal') or (attrib = 'small-caps') or (attrib = 'lighter') then 819 begin 820 //nothing 821 end else 822 if (attrib = 'italic') or (attrib = 'oblique') then 823 begin 824 currentState.fontStyle += [fsItalic]; 825 end else 826 if (attrib = 'bold') or (attrib = 'bolder') then 827 begin 828 currentState.fontStyle += [fsBold]; 829 end else 830 if (attrib[1] in ['.','0'..'9']) then 831 begin 832 u := ''; 833 while (length(attrib)>0) and (attrib[length(attrib)] in['a'..'z']) do 834 begin 835 u := attrib[length(attrib)]+u; 836 delete(attrib,length(attrib),1); 837 end; 838 val(attrib,value,errPos); 839 if errPos = 0 then 840 begin 841 if u = '' then //weight 842 begin 843 if value >= 600 then currentState.fontStyle += [fsBold]; 844 end else 845 if u = 'px' then currentState.fontEmHeight := value else 846 if u = 'pt' then currentState.fontEmHeight:= value/72*96 else 847 if u = 'in' then currentState.fontEmHeight:= value*96 else 848 if u = 'mm' then currentState.fontEmHeight:= value/25.4*96 else 849 if u = 'cm' then currentState.fontEmHeight:= value/2.54*96; 850 end; 851 end else 852 break; 853 delete(AValue,1,length(attrib)+1); 854 end; 855 AValue := trim(AValue); 856 if AValue <> '' then currentState.fontName := AValue; 857 end; 858 859 procedure TBGRACanvas2D.SetFontStyle(AValue: TFontStyles); 860 begin 861 currentState.fontStyle:= AValue; 573 862 end; 574 863 … … 590 879 end; 591 880 881 procedure TBGRACanvas2D.SetLineCapLCL(AValue: TPenEndCap); 882 begin 883 currentState.lineCap := AValue; 884 end; 885 592 886 procedure TBGRACanvas2D.SetLineJoin(const AValue: string); 593 887 begin … … 604 898 tempScan: TBGRACustomScanner; 605 899 begin 606 if length(points) = 0then exit;900 if (length(points) = 0) or (surface = nil) then exit; 607 901 If hasShadow then DrawShadow(points,[]); 608 902 if currentState.clipMask <> nil then … … 612 906 else 613 907 tempScan := TBGRASolidColorMaskScanner.Create(currentState.clipMask,Point(0,0),ApplyGlobalAlpha(currentState.fillColor)); 614 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true); 908 if self.antialiasing then 909 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true, linearBlend) 910 else 911 BGRAPolygon.FillPolyAliasedWithTexture(surface, points, tempScan, true, GetDrawMode); 615 912 tempScan.free; 616 913 end else … … 621 918 begin 622 919 tempScan := TBGRAOpacityScanner.Create(currentState.fillTextureProvider.texture, currentState.globalAlpha); 623 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true); 920 if self.antialiasing then 921 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true, linearBlend) 922 else 923 BGRAPolygon.FillPolyAliasedWithTexture(surface, points, tempScan, true, GetDrawMode); 624 924 tempScan.Free; 625 925 end else 626 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, currentState.fillTextureProvider.texture, true) 926 begin 927 if self.antialiasing then 928 BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, currentState.fillTextureProvider.texture, true, linearBlend) 929 else 930 BGRAPolygon.FillPolyAliasedWithTexture(surface, points, currentState.fillTextureProvider.texture, true, GetDrawMode); 931 end 627 932 end 628 933 else 629 BGRAPolygon.FillPolyAntialias(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true); 934 begin 935 if self.antialiasing then 936 BGRAPolygon.FillPolyAntialias(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true, linearBlend) 937 else 938 BGRAPolygon.FillPolyAliased(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true, GetDrawMode) 939 end 630 940 end; 631 941 end; … … 639 949 texture: IBGRAScanner; 640 950 begin 641 if length(points) = 0then exit;951 if (length(points) = 0) or (surface = nil) then exit; 642 952 tempScan := nil; 643 953 tempScan2 := nil; … … 693 1003 694 1004 if fillOver then multi.PolygonOrder := poFirstOnTop else multi.PolygonOrder:= poLastOnTop; 1005 multi.Antialiasing := self.antialiasing; 695 1006 multi.Draw(surface); 696 1007 tempScan.free; … … 699 1010 end; 700 1011 1012 procedure TBGRACanvas2D.SetLineJoinLCL(AValue: TPenJoinStyle); 1013 begin 1014 currentState.lineJoin := AValue; 1015 end; 1016 701 1017 procedure TBGRACanvas2D.lineStyle(const AValue: array of single); 702 1018 begin … … 704 1020 end; 705 1021 1022 procedure TBGRACanvas2D.lineStyle(AStyle: TPenStyle); 1023 begin 1024 case AStyle of 1025 psSolid: lineStyle(SolidPenStyle); 1026 psDash: lineStyle(DashPenStyle); 1027 psDot: lineStyle(DotPenStyle); 1028 psDashDot: lineStyle(DashDotPenStyle); 1029 psDashDotDot: lineStyle(DashDotDotPenStyle); 1030 psClear: lineStyle(ClearPenStyle); 1031 end; 1032 end; 1033 1034 function TBGRACanvas2D.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1035 begin 1036 if GetInterface(iid, obj) then 1037 Result := S_OK 1038 else 1039 Result := longint(E_NOINTERFACE); 1040 end; 1041 1042 { There is no automatic reference counting, but it is compulsory to define these functions } 1043 function TBGRACanvas2D._AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1044 begin 1045 result := 0; 1046 end; 1047 1048 function TBGRACanvas2D._Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1049 begin 1050 result := 0; 1051 end; 1052 706 1053 procedure TBGRACanvas2D.SetLineWidth(const AValue: single); 707 1054 begin 708 1055 currentState.lineWidth := AValue; 1056 end; 1057 1058 procedure TBGRACanvas2D.SetMatrix(AValue: TAffineMatrix); 1059 begin 1060 currentState.matrix := AValue; 709 1061 end; 710 1062 … … 728 1080 end; 729 1081 1082 procedure TBGRACanvas2D.SetShadowFastest(AValue: boolean); 1083 begin 1084 currentState.shadowFastest := AValue; 1085 end; 1086 730 1087 procedure TBGRACanvas2D.SetShadowOffset(const AValue: TPointF); 731 1088 begin … … 742 1099 begin 743 1100 currentState.shadowOffsetY := AValue; 1101 end; 1102 1103 procedure TBGRACanvas2D.SetTextAlign(AValue: string); 1104 begin 1105 AValue := trim(LowerCase(AValue)); 1106 if (AValue = 'left') or (AValue = 'start') then 1107 textAlignLCL := taLeftJustify else 1108 if (AValue = 'right') or (AValue = 'end') then 1109 textAlignLCL := taRightJustify else 1110 if AValue = 'center' then 1111 textAlignLCL := taCenter; 1112 end; 1113 1114 procedure TBGRACanvas2D.SetTextAlignLCL(AValue: TAlignment); 1115 begin 1116 currentState.textAlign := AValue; 1117 end; 1118 1119 procedure TBGRACanvas2D.SetTextBaseine(AValue: string); 1120 begin 1121 currentState.textBaseline := trim(lowercase(AValue)); 744 1122 end; 745 1123 … … 750 1128 contour: array of TPointF; 751 1129 begin 752 if (length(points)= 0) or (currentState.lineWidth = 0) then exit;1130 if (length(points)= 0) or (currentState.lineWidth = 0) or (surface = nil) then exit; 753 1131 contour := ComputeWidePolylinePoints(points,currentState.lineWidth,BGRAPixelTransparent, 754 1132 currentState.lineCap,currentState.lineJoin,currentState.lineStyle,[plAutoCycle],miterLimit); … … 761 1139 else 762 1140 tempScan := TBGRASolidColorMaskScanner.Create(currentState.clipMask,Point(0,0),ApplyGlobalAlpha(currentState.strokeColor)); 763 BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,tempScan,True); 1141 if self.antialiasing then 1142 BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,tempScan,True, linearBlend) 1143 else 1144 BGRAPolygon.FillPolyAliasedWithTexture(Surface,contour,tempScan,True,GetDrawMode); 764 1145 tempScan.free; 765 1146 end else … … 769 1150 texture := nil; 770 1151 if texture = nil then 771 BGRAPolygon.FillPolyAntialias(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True) 1152 begin 1153 if self.antialiasing then 1154 BGRAPolygon.FillPolyAntialias(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True, linearBlend) 1155 else 1156 BGRAPolygon.FillPolyAliased(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True,GetDrawMode) 1157 end 772 1158 else 773 BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,texture,True); 1159 begin 1160 if self.antialiasing then 1161 BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,texture,True, linearBlend) 1162 else 1163 BGRAPolygon.FillPolyAliasedWithTexture(Surface,contour,texture,True,GetDrawMode) 1164 end; 774 1165 end; 775 1166 end; 776 1167 777 1168 procedure TBGRACanvas2D.DrawShadow(const points, points2: array of TPointF); 1169 const invSqrt2 = 1/sqrt(2); 778 1170 var ofsPts,ofsPts2: array of TPointF; 779 1171 offset: TPointF; 780 1172 i: Integer; 781 1173 tempBmp,blurred: TBGRACustomBitmap; 782 begin 783 if not hasShadow then exit; 1174 maxRect: TRect; 1175 foundRect: TRect; 1176 firstFound: boolean; 1177 1178 procedure AddPt(const coord: TPointF); 1179 var pixRect: TRect; 1180 begin 1181 if isEmptyPointF(coord) then exit; 1182 pixRect := Types.Rect(round(floor(coord.x)),round(floor(coord.y)),round(ceil(coord.x+0.999))+1,round(ceil(coord.y+0.999))+1); 1183 if firstFound then 1184 begin 1185 foundRect := pixRect; 1186 firstFound := false 1187 end 1188 else 1189 begin 1190 if pixRect.left < foundRect.left then foundRect.left := pixRect.Left; 1191 if pixRect.top < foundRect.top then foundRect.top := pixRect.top; 1192 if pixRect.right > foundRect.right then foundRect.right := pixRect.right; 1193 if pixRect.bottom > foundRect.bottom then foundRect.bottom := pixRect.bottom; 1194 end; 1195 end; 1196 1197 begin 1198 if not hasShadow or (surface = nil) then exit; 784 1199 offset := PointF(shadowOffsetX,shadowOffsetY); 785 1200 setlength(ofsPts, length(points)); … … 789 1204 for i := 0 to high(ofsPts2) do 790 1205 ofsPts2[i] := points2[i]+offset; 791 tempBmp := surface.NewBitmap(width,height,BGRAPixelTransparent); 1206 1207 maxRect := Types.Rect(0,0,width,height); 1208 if currentState.clipMask <> nil then 1209 foundRect := maxRect 1210 else 1211 begin 1212 firstFound := true; 1213 for i := 0 to high(ofsPts) do 1214 AddPt(ofsPts[i]); 1215 for i := 0 to high(ofsPts2) do 1216 AddPt(ofsPts2[i]); 1217 if firstFound then exit; 1218 InflateRect(foundRect, ceil(shadowBlur),ceil(shadowBlur)); 1219 if not IntersectRect(foundRect, foundRect,maxRect) then exit; 1220 offset := PointF(-foundRect.Left,-foundRect.Top); 1221 for i := 0 to high(ofsPts) do 1222 ofsPts[i] += offset; 1223 for i := 0 to high(ofsPts2) do 1224 ofsPts2[i] += offset; 1225 end; 1226 1227 tempBmp := surface.NewBitmap(foundRect.Right-foundRect.Left,foundRect.Bottom-foundRect.Top,BGRAPixelTransparent); 792 1228 tempBmp.FillMode := fmWinding; 793 1229 tempBmp.FillPolyAntialias(ofsPts, getShadowColor); … … 795 1231 if shadowBlur > 0 then 796 1232 begin 797 if (shadowBlur < 5) and (abs(shadowBlur-round(shadowBlur)) > 1e-6) then 798 blurred := tempBmp.FilterBlurRadial(round(shadowBlur*10),rbPrecise) 1233 if shadowFastest then 1234 begin 1235 if shadowBlur*invSqrt2 >= 0.5 then 1236 begin 1237 blurred := tempBmp.FilterBlurRadial(round(shadowBlur*invSqrt2),rbBox); 1238 tempBmp.Free; 1239 tempBmp := blurred; 1240 end; 1241 end 799 1242 else 800 blurred := tempBmp.FilterBlurRadial(round(shadowBlur),rbFast); 801 tempBmp.Free; 802 tempBmp := blurred; 1243 begin 1244 if (shadowBlur < 5) and (abs(shadowBlur-round(shadowBlur)) > 1e-6) then 1245 blurred := tempBmp.FilterBlurRadial(round(shadowBlur*10),rbPrecise) 1246 else 1247 blurred := tempBmp.FilterBlurRadial(round(shadowBlur),rbFast); 1248 tempBmp.Free; 1249 tempBmp := blurred; 1250 end; 803 1251 end; 804 1252 if currentState.clipMask <> nil then 805 1253 tempBmp.ApplyMask(currentState.clipMask); 806 surface.PutImage( 0,0,tempBmp,dmDrawWithTransparency,currentState.globalAlpha);1254 surface.PutImage(foundRect.Left,foundRect.Top,tempBmp,GetDrawMode,currentState.globalAlpha); 807 1255 tempBmp.Free; 808 1256 end; … … 810 1258 procedure TBGRACanvas2D.ClearPoly(const points: array of TPointF); 811 1259 begin 812 BGRAPolygon.FillPolyAntialias(surface, points, BGRA(0,0,0,255), true, true) 1260 if surface = nil then exit; 1261 if self.antialiasing then 1262 BGRAPolygon.FillPolyAntialias(surface, points, BGRA(0,0,0,255), true, true, linearBlend) 1263 else 1264 BGRAPolygon.FillPolyAliased(surface, points, BGRA(0,0,0,255), true, true, dmSet); 813 1265 end; 814 1266 … … 844 1296 end; 845 1297 846 function TBGRACanvas2D.GetPenPos : TPointF;847 begin 848 if FPathPointCount = 0then849 result := PointF( 0,0)1298 function TBGRACanvas2D.GetPenPos(defaultX,defaultY: single): TPointF; 1299 begin 1300 if isEmptyPointF(FLastCoord) then 1301 result := PointF(defaultX,defaultY) 850 1302 else 851 result := FPathPoints[FPathPointCount-1]; 1303 result := FLastCoord; 1304 end; 1305 1306 function TBGRACanvas2D.GetPenPos(defaultPt: TPointF): TPointF; 1307 begin 1308 result := GetPenPos(defaultPt.x,defaultPt.y); 852 1309 end; 853 1310 … … 889 1346 end; 890 1347 1348 function TBGRACanvas2D.GetDrawMode: TDrawMode; 1349 begin 1350 if linearBlend then result := dmLinearBlend else result := dmDrawWithTransparency; 1351 end; 1352 1353 procedure TBGRACanvas2D.copyTo(dest: IBGRAPath); 1354 begin 1355 //nothing 1356 end; 1357 891 1358 constructor TBGRACanvas2D.Create(ASurface: TBGRACustomBitmap); 892 1359 begin … … 894 1361 StateStack := TList.Create; 895 1362 FPathPointCount := 0; 1363 FLastCoord := EmptyPointF; 1364 FStartCoord := EmptyPointF; 896 1365 currentState := TBGRACanvasState2D.Create(AffineMatrixIdentity,nil); 897 1366 pixelCenteredCoordinates := false; 1367 antialiasing := true; 898 1368 end; 899 1369 … … 906 1376 StateStack.Free; 907 1377 currentState.Free; 1378 FreeAndNil(FFontRenderer); 908 1379 inherited Destroy; 909 1380 end; … … 917 1388 encode64: TBase64EncodingStream; 918 1389 begin 1390 if surface = nil then exit; 919 1391 stream := TMemoryStream.Create; 920 1392 if mimeType='image/jpeg' then … … 967 1439 end; 968 1440 969 procedure TBGRACanvas2D.rotate(angleRad: single); 970 begin 971 currentState.matrix *= AffineMatrixRotationRad(-angleRad); 1441 procedure TBGRACanvas2D.scale(factor: single); 1442 begin 1443 currentState.matrix *= AffineMatrixScale(factor,factor); 1444 end; 1445 1446 procedure TBGRACanvas2D.rotate(angleRadCW: single); 1447 begin 1448 currentState.matrix *= AffineMatrixRotationRad(-angleRadCW); 972 1449 end; 973 1450 … … 980 1457 begin 981 1458 currentState.matrix *= AffineMatrix(a,c,e,b,d,f); 1459 end; 1460 1461 procedure TBGRACanvas2D.transform(AMatrix: TAffineMatrix); 1462 begin 1463 currentState.matrix *= AMatrix; 982 1464 end; 983 1465 … … 1063 1545 begin 1064 1546 shadowColor(StrToBGRA(color)); 1547 end; 1548 1549 procedure TBGRACanvas2D.shadowNone; 1550 begin 1551 shadowColor(BGRAPixelTransparent); 1065 1552 end; 1066 1553 … … 1145 1632 end; 1146 1633 1634 procedure TBGRACanvas2D.addPath(APath: IBGRAPath); 1635 begin 1636 if (FPathPointCount <> 0) and not isEmptyPointF(FPathPoints[FPathPointCount-1]) then 1637 begin 1638 AddPoint(EmptyPointF); 1639 FLastCoord := EmptyPointF; 1640 FStartCoord := EmptyPointF; 1641 end; 1642 APath.copyTo(self); 1643 end; 1644 1645 procedure TBGRACanvas2D.addPath(ASvgPath: string); 1646 var p: TBGRAPath; 1647 begin 1648 p := TBGRAPath.Create(ASvgPath); 1649 addPath(p); 1650 p.Free; 1651 end; 1652 1653 procedure TBGRACanvas2D.path(APath: IBGRAPath); 1654 begin 1655 beginPath; 1656 addPath(APath); 1657 end; 1658 1659 procedure TBGRACanvas2D.path(ASvgPath: string); 1660 begin 1661 beginPath; 1662 addPath(ASvgPath); 1663 end; 1664 1147 1665 procedure TBGRACanvas2D.beginPath; 1148 1666 begin 1149 1667 FPathPointCount := 0; 1668 FLastCoord := EmptyPointF; 1669 FStartCoord := EmptyPointF; 1150 1670 end; 1151 1671 … … 1158 1678 while (i > 0) and not isEmptyPointF(FPathPoints[i-1]) do dec(i); 1159 1679 AddPoint(FPathPoints[i]); 1680 FLastCoord := FStartCoord; 1160 1681 end; 1161 1682 end; … … 1175 1696 pts[j] := FPathPoints[i+j]; 1176 1697 if closed then 1177 splinePts := surface.ComputeClosedSpline(pts,style)1698 splinePts := BGRAPath.ComputeClosedSpline(pts,style) 1178 1699 else 1179 splinePts := surface.ComputeOpenedSpline(pts,style);1700 splinePts := BGRAPath.ComputeOpenedSpline(pts,style); 1180 1701 dec(FPathPointCount,nb); 1181 1702 AddPoints(splinePts); … … 1193 1714 end; 1194 1715 1195 procedure TBGRACanvas2D.moveTo( pt: TPointF);1196 begin 1197 if FPathPointCount <> 0then1716 procedure TBGRACanvas2D.moveTo(const pt: TPointF); 1717 begin 1718 if (FPathPointCount <> 0) and not isEmptyPointF(FPathPoints[FPathPointCount-1]) then 1198 1719 AddPoint(EmptyPointF); 1199 1720 AddPoint(ApplyTransform(pt)); 1200 end; 1201 1202 procedure TBGRACanvas2D.lineTo(pt: TPointF); 1721 FStartCoord := pt; 1722 FLastCoord := pt; 1723 end; 1724 1725 procedure TBGRACanvas2D.lineTo(const pt: TPointF); 1203 1726 begin 1204 1727 AddPoint(ApplyTransform(pt)); 1728 FLastCoord := pt; 1205 1729 end; 1206 1730 1207 1731 procedure TBGRACanvas2D.polylineTo(const pts: array of TPointF); 1208 1732 begin 1209 AddPoints(ApplyTransform(pts)); 1733 if length(pts)> 0 then 1734 begin 1735 AddPoints(ApplyTransform(pts)); 1736 FLastCoord := pts[high(pts)]; 1737 end; 1210 1738 end; 1211 1739 … … 1215 1743 pts : array of TPointF; 1216 1744 begin 1217 curve := BezierCurve( GetPenPos,ApplyTransform(PointF(cpx,cpy)),ApplyTransform(PointF(x,y)));1218 pts := Surface.ComputeBezierCurve(curve);1745 curve := BezierCurve(ApplyTransform(GetPenPos(cpx,cpy)),ApplyTransform(PointF(cpx,cpy)),ApplyTransform(PointF(x,y))); 1746 pts := BGRAPath.ComputeBezierCurve(curve); 1219 1747 AddPoints(pts); 1220 end; 1221 1222 procedure TBGRACanvas2D.quadraticCurveTo(cp, pt: TPointF); 1748 FLastCoord := PointF(x,y); 1749 end; 1750 1751 procedure TBGRACanvas2D.quadraticCurveTo(const cp, pt: TPointF); 1223 1752 begin 1224 1753 quadraticCurveTo(cp.x,cp.y,pt.x,pt.y); … … 1230 1759 pts : array of TPointF; 1231 1760 begin 1232 curve := BezierCurve( GetPenPos,ApplyTransform(PointF(cp1x,cp1y)),1761 curve := BezierCurve(ApplyTransform(GetPenPos(cp1x,cp1y)),ApplyTransform(PointF(cp1x,cp1y)), 1233 1762 ApplyTransform(PointF(cp2x,cp2y)),ApplyTransform(PointF(x,y))); 1234 pts := Surface.ComputeBezierCurve(curve);1763 pts := BGRAPath.ComputeBezierCurve(curve); 1235 1764 AddPoints(pts); 1236 end; 1237 1238 procedure TBGRACanvas2D.bezierCurveTo(cp1, cp2, pt: TPointF); 1765 FLastCoord := PointF(x,y); 1766 end; 1767 1768 procedure TBGRACanvas2D.bezierCurveTo(const cp1, cp2, pt: TPointF); 1239 1769 begin 1240 1770 bezierCurveTo(cp1.x,cp1.y,cp2.x,cp2.y,pt.x,pt.y); … … 1247 1777 LineTo(x+w,y+h); 1248 1778 LineTo(x,y+h); 1249 LineTo(x,y);1779 closePath; 1250 1780 end; 1251 1781 … … 1265 1795 arcTo(PointF(x,y+h),PointF(x,y), radius); 1266 1796 arcTo(PointF(x,y),PointF(x+w,y), radius); 1797 closePath; 1798 end; 1799 1800 procedure TBGRACanvas2D.roundRect(x, y, w, h, rx, ry: single); 1801 begin 1802 if (w <= 0) or (h <= 0) then exit; 1803 if rx < 0 then rx := 0; 1804 if ry < 0 then ry := 0; 1805 if (rx = 0) and (ry = 0) then 1806 begin 1807 rect(x,y,w,h); 1808 exit; 1809 end; 1810 if rx*2 > w then rx := w/2; 1811 if ry*2 > h then ry := h/2; 1812 moveTo(x+rx,y); 1813 lineTo(x+w-rx,y); 1814 arcTo(rx,ry,0,false,false,x+w,y+ry); 1815 lineTo(x+w,y+h-ry); 1816 arcTo(rx,ry,0,false,false,x+w-rx,y+h); 1817 lineTo(x+rx,y+h); 1818 arcTo(rx,ry,0,false,false,x,y+h-ry); 1819 lineTo(x,y+ry); 1820 arcTo(rx,ry,0,false,false,x+rx,y); 1821 closePath; 1267 1822 end; 1268 1823 … … 1273 1828 transf := ApplyTransform(pts); 1274 1829 if (pts[0] = pts[high(pts)]) and (length(pts) > 1) then 1275 transf := surface.ComputeClosedSpline(slice(transf, length(transf)-1),style)1830 transf := BGRAPath.ComputeClosedSpline(slice(transf, length(transf)-1),style) 1276 1831 else 1277 transf := surface.ComputeOpenedSpline(transf,style);1832 transf := BGRAPath.ComputeOpenedSpline(transf,style); 1278 1833 AddPoints(transf); 1834 FLastCoord := pts[high(pts)]; 1279 1835 end; 1280 1836 … … 1284 1840 i: Integer; 1285 1841 begin 1842 if length(pts) = 0 then exit; 1286 1843 transf := ApplyTransform(pts); 1287 1844 if FPathPointCount <> 0 then … … 1290 1847 for i := high(transf) downto 1 do 1291 1848 transf[i]:= transf[i-1]; 1292 transf[0] := GetPenPos;1293 end; 1294 transf := surface.ComputeOpenedSpline(transf,style);1849 transf[0] := ApplyTransform(GetPenPos(pts[0].x,pts[0].y)); 1850 end; 1851 transf := BGRAPath.ComputeOpenedSpline(transf,style); 1295 1852 AddPoints(transf); 1296 end; 1297 1298 procedure TBGRACanvas2D.arc(x, y, radius, startAngle, endAngle: single; 1853 FLastCoord := pts[high(pts)]; 1854 end; 1855 1856 procedure TBGRACanvas2D.arc(x, y, radius, startAngleRadCW, endAngleRadCW: single; 1299 1857 anticlockwise: boolean); 1300 1858 var pts: array of TPointF; … … 1305 1863 unitAffine: TAffineMatrix; 1306 1864 v1orig,v2orig,v1ortho,v2ortho: TPointF; 1865 startRadCCW,endRadCCW: single; 1307 1866 begin 1308 1867 v1orig := PointF(currentState.matrix[1,1],currentState.matrix[2,1]); … … 1317 1876 unitAffine := AffineMatrix(v1ortho.x, v2ortho.x, pt.x, 1318 1877 v1ortho.y, v2ortho.y, pt.y); 1319 start Angle := -startAngle;1320 end Angle := -endAngle;1878 startRadCCW := -startAngleRadCW; 1879 endRadCCW := -endAngleRadCW; 1321 1880 if not anticlockwise then 1322 1881 begin 1323 temp := start Angle;1324 start Angle := endAngle;1325 end Angle:= temp;1326 pts := surface.ComputeArcRad(0,0,rx,ry,startAngle,endAngle);1882 temp := startRadCCW; 1883 startRadCCW := endRadCCW; 1884 endRadCCW:= temp; 1885 pts := BGRAPath.ComputeArcRad(0,0,rx,ry,startRadCCW,endRadCCW); 1327 1886 pts := ApplyTransform(pts,unitAffine); 1328 1887 AddPointsRev(pts); 1329 1888 end else 1330 1889 begin 1331 pts := surface.ComputeArcRad(0,0,rx,ry,startAngle,endAngle);1890 pts := BGRAPath.ComputeArcRad(0,0,rx,ry,startRadCCW,endRadCCW); 1332 1891 pts := ApplyTransform(pts,unitAffine); 1333 1892 AddPoints(pts); 1334 1893 end; 1335 end; 1336 1337 procedure TBGRACanvas2D.arc(x, y, radius, startAngle, endAngle: single); 1338 begin 1339 arc(x,y,radius,startAngle,endAngle,false); 1894 FLastCoord := ArcEndPoint(ArcDef(x,y,radius,radius,0,startAngleRadCW,endAngleRadCW,anticlockwise)); 1895 end; 1896 1897 procedure TBGRACanvas2D.arc(x, y, radius, startAngleRadCW, endAngleRadCW: single); 1898 begin 1899 arc(x,y,radius,startAngleRadCW,endAngleRadCW,false); 1900 end; 1901 1902 procedure TBGRACanvas2D.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; 1903 anticlockwise: boolean); 1904 begin 1905 arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,anticlockwise)) 1906 end; 1907 1908 procedure TBGRACanvas2D.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single); 1909 begin 1910 arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,false)) 1911 end; 1912 1913 procedure TBGRACanvas2D.arc(const arcDef: TArcDef); 1914 var previousMatrix: TAffineMatrix; 1915 begin 1916 if (arcDef.radius.x = 0) and (arcDef.radius.y = 0) then 1917 lineTo(arcDef.center) else 1918 begin 1919 previousMatrix := currentState.matrix; 1920 translate(arcDef.center.x,arcDef.center.y); 1921 rotate(arcDef.xAngleRadCW); 1922 scale(arcDef.radius.x,arcDef.radius.y); 1923 arc(0,0,1,arcDef.startAngleRadCW,arcDef.endAngleRadCW,arcDef.anticlockwise); 1924 currentState.matrix := previousMatrix; 1925 FLastCoord := ArcEndPoint(arcDef); 1926 end; 1340 1927 end; 1341 1928 1342 1929 procedure TBGRACanvas2D.arcTo(x1, y1, x2, y2, radius: single); 1343 var p0,p1,p2,p3,p4,an,bn,cn,c: TPointF; 1344 dir, a2, b2, c2, cosx, sinx, d, 1345 angle0, angle1: single; 1346 anticlockwise: boolean; 1347 begin 1348 if FPathPointCount = 0 then 1349 moveTo(x1,y1); 1350 radius := abs(radius); 1351 p0 := GetPenPos; 1352 p1 := PointF(x1,y1); 1353 p2 := PointF(x2,y2); 1354 1355 if (p0 = p1) or (p1 = p2) or (radius = 0) then 1356 begin 1357 lineto(x1,y1); 1358 exit; 1359 end; 1360 1361 dir := (x2-x1)*(p0.y-y1) + (y2-y1)*(x1-p0.x); 1362 if dir = 0 then 1363 begin 1364 lineto(x1,y1); 1365 exit; 1366 end; 1367 1368 a2 := (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1); 1369 b2 := (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); 1370 c2 := (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2); 1371 cosx := (a2+b2-c2)/(2*sqrt(a2*b2)); 1372 1373 sinx := sqrt(1 - cosx*cosx); 1374 if (sinx = 0) or (cosx = 1) then 1375 begin 1376 lineto(x1,y1); 1377 exit; 1378 end; 1379 d := radius / ((1 - cosx) / sinx); 1380 1381 an := (p1-p0)*(1/sqrt(a2)); 1382 bn := (p1-p2)*(1/sqrt(b2)); 1383 p3 := p1 - an*d; 1384 p4 := p1 - bn*d; 1385 anticlockwise := (dir < 0); 1386 1387 cn := PointF(an.y,-an.x)*radius; 1388 if not anticlockwise then cn := -cn; 1389 c := p3 + cn; 1390 angle0 := arctan2((p3.y-c.y), (p3.x-c.x)); 1391 angle1 := arctan2((p4.y-c.y), (p4.x-c.x)); 1392 1393 lineTo(p3.x,p3.y); 1394 arc(c.x,c.y, radius, angle0, angle1, anticlockwise); 1930 var p0: TPointF; 1931 begin 1932 p0 := GetPenPos(x1,y1); 1933 arc(Html5ArcTo(p0,PointF(x1,y1),PointF(x2,y2),radius)); 1395 1934 end; 1396 1935 … … 1398 1937 begin 1399 1938 arcTo(p1.x,p1.y,p2.x,p2.y,radius); 1939 end; 1940 1941 procedure TBGRACanvas2D.arcTo(rx, ry, xAngleRadCW: single; largeArc, 1942 anticlockwise: boolean; x, y: single); 1943 begin 1944 arc(SvgArcTo(GetPenPos(x,y), rx,ry, xAngleRadCW, largeArc, anticlockwise, PointF(x,y))); 1945 FLastCoord := PointF(x,y); 1946 end; 1947 1948 procedure TBGRACanvas2D.circle(x, y, r: single); 1949 begin 1950 arc(x,y,r,0,0); 1951 end; 1952 1953 procedure TBGRACanvas2D.ellipse(x, y, rx, ry: single); 1954 begin 1955 arc(x,y,rx,ry,0,0,0); 1956 end; 1957 1958 procedure TBGRACanvas2D.text(AText: string; x, y: single); 1959 var renderer : TBGRACustomFontRenderer; 1960 previousMatrix: TAffineMatrix; 1961 begin 1962 renderer := fontRenderer; 1963 if renderer.FontEmHeight <= 0 then exit; 1964 previousMatrix := currentState.matrix; 1965 1966 scale(currentState.fontEmHeight/renderer.FontEmHeight); 1967 if (currentState.textBaseline <> 'top') and 1968 (currentState.textBaseline <> 'hanging') then 1969 with renderer.GetFontPixelMetric do 1970 begin 1971 if currentState.textBaseline = 'bottom' then 1972 translate(0,-Lineheight) 1973 else if currentState.textBaseline = 'middle' then 1974 translate(0,-Lineheight/2) 1975 else if currentState.textBaseline = 'alphabetic' then 1976 translate(0,-baseline); 1977 end; 1978 1979 if renderer <> nil then 1980 renderer.CopyTextPathTo(self, x,y, AText, taLeftJustify); 1981 1982 currentState.matrix := previousMatrix; 1983 FLastCoord := EmptyPointF; 1984 FStartCoord := EmptyPointF; 1985 end; 1986 1987 procedure TBGRACanvas2D.fillText(AText: string; x, y: single); 1988 begin 1989 beginPath; 1990 text(AText,x,y); 1991 fill; 1992 beginPath; 1993 end; 1994 1995 procedure TBGRACanvas2D.strokeText(AText: string; x, y: single); 1996 begin 1997 beginPath; 1998 text(AText,x,y); 1999 stroke; 2000 beginPath; 2001 end; 2002 2003 function TBGRACanvas2D.measureText(AText: string): TCanvas2dTextSize; 2004 var renderer: TBGRACustomFontRenderer; 2005 begin 2006 renderer := fontRenderer; 2007 if renderer <> nil then 2008 begin 2009 with renderer.TextSize(AText) do 2010 begin 2011 result.width := cx; 2012 result.height:= cy; 2013 end; 2014 end 2015 else 2016 begin 2017 result.width := 0; 2018 result.height := 0; 2019 end; 1400 2020 end; 1401 2021 … … 1442 2062 currentState.clipMask := surface.NewBitmap(width,height,BGRAWhite); 1443 2063 tempBmp := surface.NewBitmap(width,height,BGRABlack); 1444 tempBmp.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite); 2064 if antialiasing then 2065 tempBmp.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite) 2066 else 2067 tempBmp.FillPoly(slice(FPathPoints,FPathPointCount),BGRAWhite,dmSet); 1445 2068 currentState.clipMask.BlendImage(0,0,tempBmp,boDarken); 1446 2069 tempBmp.Free; … … 1451 2074 if FPathPointCount = 0 then exit; 1452 2075 if currentState.clipMask = nil then exit; 1453 currentState.clipMask.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite); 2076 if antialiasing then 2077 currentState.clipMask.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite) 2078 else 2079 currentState.clipMask.FillPoly(slice(FPathPoints,FPathPointCount),BGRAWhite,dmSet); 1454 2080 if currentState.clipMask.Equals(BGRAWhite) then 1455 2081 FreeAndNil(currentState.clipMask); -
GraphicTest/Packages/bgrabitmap/bgracolorint.pas
r452 r472 167 167 end; 168 168 {$else} 169 begin 170 result.r := int64(color1.r)*factor65536 shr 16; 171 result.g := int64(color1.g)*factor65536 shr 16; 172 result.b := int64(color1.b)*factor65536 shr 16; 173 result.a := int64(color1.a)*factor65536 shr 16; 169 var prod: int64; 170 begin 171 prod := int64(color1.r)*factor65536; 172 if prod >= 0 then result.r := prod shr 16 173 else result.r := -((-prod) shr 16); 174 prod := int64(color1.g)*factor65536; 175 if prod >= 0 then result.g := prod shr 16 176 else result.g := -((-prod) shr 16); 177 prod := int64(color1.b)*factor65536; 178 if prod >= 0 then result.b := prod shr 16 179 else result.b := -((-prod) shr 16); 180 prod := int64(color1.a)*factor65536; 181 if prod >= 0 then result.a := prod shr 16 182 else result.a := -((-prod) shr 16); 174 183 end; 175 184 {$endif} -
GraphicTest/Packages/bgrabitmap/bgracompressablebitmap.pas
r452 r472 44 44 procedure Decompress; 45 45 procedure FreeData; 46 procedure Init; 46 47 public 47 48 CompressionLevel: Tcompressionlevel; … … 62 63 property Width : Integer read FWidth; 63 64 property Height: Integer read FHeight; 64 property Caption : string read FCaption ;65 property Caption : string read FCaption write FCaption; 65 66 66 67 end; … … 77 78 constructor TBGRACompressableBitmap.Create; 78 79 begin 79 FUncompressedData := nil; 80 FCompressedDataArray := nil; 81 FWidth := 0; 82 FHeight := 0; 83 FCaption := ''; 84 FCompressionProgress := 0; 85 CompressionLevel := clfastest; 80 Init; 86 81 end; 87 82 88 83 constructor TBGRACompressableBitmap.Create(Source: TBGRABitmap); 89 84 begin 90 FUncompressedData := nil; 91 FCompressedDataArray := nil; 92 FWidth := 0; 93 FHeight := 0; 94 FCaption := ''; 95 FCompressionProgress := 0; 85 Init; 96 86 Assign(Source); 97 87 end; … … 219 209 setlength(FCaption,WinReadLongint(AStream)); 220 210 AStream.Read(FCaption[1],length(FCaption)); 221 if (FWidth=0) or (FHeight = 0) then exit; 211 if (FWidth=0) or (FHeight = 0) then 212 begin 213 FUncompressedData := TMemoryStream.Create; 214 exit; 215 end; 222 216 223 217 FBounds.Left := WinReadLongint(AStream); … … 234 228 FCompressedDataArray[i].CopyFrom(AStream,size); 235 229 end; 230 231 if FCompressedDataArray = nil then 232 FUncompressedData := TMemoryStream.Create; 236 233 end; 237 234 … … 270 267 end; 271 268 269 procedure TBGRACompressableBitmap.Init; 270 begin 271 FUncompressedData := nil; 272 FCompressedDataArray := nil; 273 FWidth := 0; 274 FHeight := 0; 275 FCaption := ''; 276 FCompressionProgress := 0; 277 CompressionLevel := clfastest; 278 end; 279 272 280 { Copy a bitmap into this object. As it is copied, you need not 273 281 keep a copy of the source } -
GraphicTest/Packages/bgrabitmap/bgracoordpool3d.pas
r452 r472 6 6 7 7 uses 8 Classes, SysUtils, BGRABitmapTypes, BGRASSE ;8 Classes, SysUtils, BGRABitmapTypes, BGRASSE, BGRAMatrix3D; 9 9 10 10 type … … 15 15 {32} projectedCoord: TPointF; 16 16 {40} InvZ: single; 17 {44} used: longbool;17 {44} used: wordbool; customNormalUsed: wordbool; 18 18 {48} viewNormal: TPoint3D_128; 19 end; {64} 20 21 { TBGRACoordPool3D } 22 23 TBGRACoordPool3D = class 19 {64} customNormal: TPoint3D_128; 20 end; {80} 21 22 PBGRANormalData3D = ^TBGRANormalData3D; 23 TBGRANormalData3D = packed record 24 {0} customNormal: TPoint3D_128; 25 {16} viewNormal: TPoint3D_128; 26 {32} used: longbool; 27 {36} filler1,filler2,filler3: longword; 28 end; {48} 29 30 { TBGRAGenericPool } 31 32 TBGRAGenericPool = class 24 33 private 25 34 FFirstFree: integer; 26 FNbCoord,FCapacity: integer; 35 FNbElements,FCapacity: integer; 36 FElementSize: PtrInt; 37 FUsedCapacity : integer; 38 function GetElement(AIndex: integer): Pointer; 39 procedure SetCapacity(ACapacity: integer); 40 protected 27 41 FPoolData: TMemoryBlockAlign128; 28 FUsedCapacity : integer;29 function GetCoordData(AIndex: integer): PBGRACoordData3D;30 procedure SetCapacity(ACapacity: integer);42 function GetUsed({%H-}AElement: integer): boolean; virtual; 43 procedure SetUsed({%H-}AElement: integer; {%H-}AUsed: boolean); virtual; 44 procedure Remove(AIndex: integer); //does not work if GetUsed/SetUsed are not implemented 31 45 public 32 constructor Create(ACapacity: integer );46 constructor Create(ACapacity: integer; AElementSize: integer); 33 47 destructor Destroy; override; 34 procedure Remove(AIndex: integer);35 48 function Add: integer; 36 property CoordData[AIndex: integer]: PBGRACoordData3D read GetCoordData;49 property Element[AIndex: integer]: Pointer read GetElement; 37 50 property Capacity: integer read FCapacity; 38 51 property UsedCapacity: integer read FUsedCapacity; 39 52 end; 40 53 54 { TBGRACoordPool3D } 55 56 TBGRACoordPool3D = class(TBGRAGenericPool) 57 private 58 function GetCoordData(AIndex: integer): PBGRACoordData3D; 59 protected 60 function GetUsed(AElement: integer): boolean; override; 61 procedure SetUsed(AElement: integer; AUsed: boolean); override; 62 public 63 procedure Remove(AIndex: integer); 64 constructor Create(ACapacity: integer); 65 procedure ComputeWithMatrix(const AMatrix: TMatrix3D; const AProjection: TProjection3D); 66 property CoordData[AIndex: integer]: PBGRACoordData3D read GetCoordData; 67 end; 68 69 { TBGRANormalPool3D } 70 71 TBGRANormalPool3D = class(TBGRAGenericPool) 72 private 73 function GetNormalData(AIndex: integer): PBGRANormalData3D; 74 protected 75 function GetUsed(AElement: integer): boolean; override; 76 procedure SetUsed(AElement: integer; AUsed: boolean); override; 77 public 78 procedure Remove(AIndex: integer); 79 constructor Create(ACapacity: integer); 80 procedure ComputeWithMatrix(const AMatrix: TMatrix3D); 81 property NormalData[AIndex: integer]: PBGRANormalData3D read GetNormalData; 82 end; 83 41 84 implementation 42 85 43 { TBGRACoordPool3D } 44 45 procedure TBGRACoordPool3D.SetCapacity(ACapacity: integer); 86 { TBGRAGenericPool } 87 88 function TBGRAGenericPool.GetElement(AIndex: integer): Pointer; 89 begin 90 result := Pointer(PByte(FPoolData.Data)+AIndex*FElementSize); 91 end; 92 93 procedure TBGRAGenericPool.SetCapacity(ACapacity: integer); 46 94 var NewPoolData: TMemoryBlockAlign128; 47 95 begin … … 52 100 else 53 101 begin 54 NewPoolData := TMemoryBlockAlign128.Create(ACapacity* sizeof(TBGRACoordData3D));102 NewPoolData := TMemoryBlockAlign128.Create(ACapacity*FElementSize); 55 103 if FCapacity <> 0 then 56 104 begin … … 58 106 if FCapacity < ACapacity then 59 107 begin 60 move(FPoolData.Data^, NewPoolData.Data^, FCapacity* sizeof(TBGRACoordData3D));108 move(FPoolData.Data^, NewPoolData.Data^, FCapacity*FElementSize); 61 109 //pad with zeros 62 fillchar((pbyte(NewPoolData.Data)+FCapacity* sizeof(TBGRACoordData3D))^,(ACapacity-FCapacity)*sizeof(TBGRACoordData3D),0);110 fillchar((pbyte(NewPoolData.Data)+FCapacity*FElementSize)^,(ACapacity-FCapacity)*FElementSize,0); 63 111 end 64 112 else //previous block is greater or equal 65 move(FPoolData.Data^, NewPoolData.Data^, ACapacity* sizeof(TBGRACoordData3D));113 move(FPoolData.Data^, NewPoolData.Data^, ACapacity*FElementSize); 66 114 FreeAndNil(FPoolData); 67 115 end else 68 116 //clear new block 69 fillchar(pbyte(NewPoolData.Data)^,ACapacity* sizeof(TBGRACoordData3D),0);117 fillchar(pbyte(NewPoolData.Data)^,ACapacity*FElementSize,0); 70 118 71 119 FPoolData := NewPoolData; … … 75 123 end; 76 124 77 constructor TBGRACoordPool3D.Create(ACapacity: integer); 125 function TBGRAGenericPool.GetUsed(AElement: integer): boolean; 126 begin 127 result := false; 128 end; 129 130 procedure TBGRAGenericPool.SetUsed(AElement: integer; AUsed: boolean); 131 begin 132 //nothing 133 end; 134 135 constructor TBGRAGenericPool.Create(ACapacity: integer; AElementSize: integer); 78 136 begin 79 137 FCapacity := 0; 80 138 FPoolData := nil; 81 FNb Coord:= 0;139 FNbElements:= 0; 82 140 FFirstFree := 0; 83 141 FUsedCapacity := 0; 142 FElementSize:= AElementSize; 84 143 SetCapacity(ACapacity); 85 144 end; 86 145 87 destructor TBGRACoordPool3D.Destroy; 88 begin 89 FPoolData.Free; 146 destructor TBGRAGenericPool.Destroy; 147 begin 148 FreeAndNil(FPoolData); 149 FCapacity := 0; 150 FNbElements:= 0; 151 FFirstFree := 0; 152 FUsedCapacity := 0; 90 153 inherited Destroy; 91 154 end; 92 155 93 procedure TBGRACoordPool3D.Remove(AIndex: integer); 94 begin 95 if CoordData[AIndex]^.used then 96 begin 97 CoordData[AIndex]^.used := false; 156 procedure TBGRAGenericPool.Remove(AIndex: integer); 157 begin 158 if (AIndex < 0) or (AIndex >= FUsedCapacity) then 159 raise ERangeError.Create('Index out of bounds'); 160 if GetUsed(AIndex) then 161 begin 162 SetUsed(AIndex, false); 98 163 if AIndex < FFirstFree then FFirstFree := AIndex; 99 164 if AIndex = FUsedCapacity-1 then 100 165 begin 101 while (FUsedCapacity > 0) and not CoordData[FUsedCapacity-1]^.useddo166 while (FUsedCapacity > 0) and not GetUsed(FUsedCapacity-1) do 102 167 dec(FUsedCapacity); 103 168 end; … … 105 170 end; 106 171 107 function TBGRA CoordPool3D.Add: integer;172 function TBGRAGenericPool.Add: integer; 108 173 begin 109 174 //check for free space 110 175 while FFirstFree < FCapacity do 111 176 begin 112 if not CoordData[FFirstFree]^.usedthen113 begin 114 CoordData[FFirstFree]^.used := false;177 if not GetUsed(FFirstFree) then 178 begin 179 SetUsed(FFirstFree,True); 115 180 result := FFirstFree; 116 181 inc(FFirstFree); … … 124 189 //no free space 125 190 SetCapacity(FCapacity*2+8); 126 CoordData[FFirstFree]^.used := false;191 SetUsed(FFirstFree, true); 127 192 result := FFirstFree; 128 193 inc(FFirstFree); … … 131 196 end; 132 197 198 { TBGRACoordPool3D } 199 200 constructor TBGRACoordPool3D.Create(ACapacity: integer); 201 begin 202 inherited Create(ACapacity,SizeOf(TBGRACoordData3D)); 203 end; 204 205 procedure TBGRACoordPool3D.ComputeWithMatrix(const AMatrix: TMatrix3D; 206 const AProjection: TProjection3D); 207 var 208 P: PBGRACoordData3D; 209 I: NativeInt; 210 begin 211 if UsedCapacity = 0 then exit; 212 P := PBGRACoordData3D(FPoolData.Data); 213 {$IFDEF CPUI386} 214 {$asmmode intel} 215 if UseSSE then 216 begin 217 Matrix3D_SSE_Load(AMatrix); 218 asm 219 mov eax,[AProjection] 220 movups xmm4,[eax] 221 xorps xmm1,xmm1 222 end; 223 i := UsedCapacity; 224 if UseSSE3 then 225 begin 226 while i > 0 do 227 with P^ do 228 begin 229 if used then 230 begin 231 MatrixMultiplyVect3D_SSE3_Aligned(sceneCoord,viewCoord); 232 if viewCoord.z > 0 then 233 begin 234 asm 235 mov eax, P 236 movaps xmm3, [eax+16] //viewCoord 237 movaps xmm2,xmm3 238 shufps xmm2,xmm3,2+8+32+128 239 rcpps xmm2,xmm2 //xmm2 = InvZ 240 movss [eax+40],xmm2 //-> InvZ 241 242 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom 243 mulps xmm3,xmm2 //xmm3 *= InvZ 244 245 movhlps xmm0,xmm4 //xmm0 = Projection.Center 246 addps xmm3,xmm0 //xmm3 += Projection.Center 247 248 movlps [eax+32],xmm3 //->projectedCoord 249 movaps [eax+48],xmm1 //->normal 250 end; 251 end else 252 asm 253 mov eax, P 254 movlps [eax+32],xmm1 //0->projectedCoord 255 movaps [eax+48],xmm1 //->normal 256 end; 257 if customNormalUsed then 258 MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned(customNormal,viewNormal); 259 end; 260 dec(i); 261 inc(p); 262 end; 263 end else 264 begin 265 while i > 0 do 266 with P^ do 267 begin 268 if used then 269 begin 270 MatrixMultiplyVect3D_SSE_Aligned(sceneCoord,viewCoord); 271 if viewCoord.z > 0 then 272 begin 273 asm 274 mov eax, P 275 movaps xmm3, [eax+16] //viewCoord 276 movaps xmm2,xmm3 277 shufps xmm2,xmm3,2+8+32+128 278 rcpps xmm2,xmm2 //xmm2 = InvZ 279 movss [eax+40],xmm2 //-> InvZ 280 281 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom 282 mulps xmm3,xmm2 //xmm3 *= InvZ 283 284 movhlps xmm0,xmm4 //xmm0 = Projection.Center 285 addps xmm3,xmm0 //xmm3 += Projection.Center 286 287 movlps [eax+32],xmm3 //->projectedCoord 288 movaps [eax+48],xmm1 //->normal 289 end; 290 end else 291 asm 292 mov eax, P 293 movlps [eax+32],xmm1 //0 ->projectedCoord 294 movaps [eax+48],xmm1 //->normal 295 end; 296 if customNormalUsed then 297 MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned(customNormal,viewNormal); 298 end; 299 dec(i); 300 inc(p); 301 end; 302 end; 303 end 304 else 305 {$ENDIF} 306 begin 307 i := UsedCapacity; 308 while i > 0 do 309 with P^ do 310 begin 311 if used then 312 begin 313 viewCoord := AMatrix*sceneCoord; 314 if customNormalUsed then 315 viewNormal := MultiplyVect3DWithoutTranslation(AMatrix,customNormal) 316 else 317 ClearPoint3D_128(viewNormal); 318 if viewCoord.z > 0 then 319 begin 320 InvZ := 1/viewCoord.z; 321 projectedCoord := PointF(viewCoord.x*InvZ*AProjection.Zoom.x + AProjection.Center.x, 322 viewCoord.y*InvZ*AProjection.Zoom.Y + AProjection.Center.y); 323 end else 324 projectedCoord := PointF(0,0); 325 end; 326 dec(i); 327 inc(p); 328 end; 329 end; 330 end; 331 133 332 function TBGRACoordPool3D.GetCoordData(AIndex: integer): PBGRACoordData3D; 134 333 begin … … 136 335 end; 137 336 337 function TBGRACoordPool3D.GetUsed(AElement: integer): boolean; 338 begin 339 Result:= CoordData[AElement]^.used; 340 end; 341 342 procedure TBGRACoordPool3D.SetUsed(AElement: integer; AUsed: boolean); 343 begin 344 CoordData[AElement]^.used := AUsed; 345 end; 346 347 procedure TBGRACoordPool3D.Remove(AIndex: integer); 348 begin 349 inherited Remove(AIndex); 350 end; 351 352 { TBGRANormalPool3D } 353 354 function TBGRANormalPool3D.GetNormalData(AIndex: integer): PBGRANormalData3D; 355 begin 356 result := PBGRANormalData3D(FPoolData.Data)+AIndex; 357 end; 358 359 function TBGRANormalPool3D.GetUsed(AElement: integer): boolean; 360 begin 361 Result:= NormalData[AElement]^.used; 362 end; 363 364 procedure TBGRANormalPool3D.SetUsed(AElement: integer; AUsed: boolean); 365 begin 366 NormalData[AElement]^.used := AUsed; 367 end; 368 369 procedure TBGRANormalPool3D.Remove(AIndex: integer); 370 begin 371 inherited Remove(AIndex); 372 end; 373 374 constructor TBGRANormalPool3D.Create(ACapacity: integer); 375 begin 376 inherited Create(ACapacity,SizeOf(TBGRANormalData3D)); 377 end; 378 379 procedure TBGRANormalPool3D.ComputeWithMatrix(const AMatrix: TMatrix3D); 380 var 381 P: PBGRANormalData3D; 382 I: NativeInt; 383 begin 384 if UsedCapacity = 0 then exit; 385 P := PBGRANormalData3D(FPoolData.Data); 386 {$IFDEF CPUI386} 387 {$asmmode intel} 388 if UseSSE then 389 begin 390 Matrix3D_SSE_Load(AMatrix); 391 i := UsedCapacity; 392 if UseSSE3 then 393 begin 394 while i > 0 do 395 with P^ do 396 begin 397 if used then 398 MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned(customNormal,viewNormal); 399 dec(i); 400 inc(p); 401 end; 402 end else 403 begin 404 while i > 0 do 405 with P^ do 406 begin 407 if used then 408 MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned(customNormal,viewNormal); 409 dec(i); 410 inc(p); 411 end; 412 end; 413 end 414 else 415 {$ENDIF} 416 begin 417 i := UsedCapacity; 418 while i > 0 do 419 with P^ do 420 begin 421 if used then 422 viewNormal := MultiplyVect3DWithoutTranslation(AMatrix,customNormal); 423 dec(i); 424 inc(p); 425 end; 426 end; 427 end; 428 138 429 end. 139 430 -
GraphicTest/Packages/bgrabitmap/bgradefaultbitmap.pas
r452 r472 33 33 34 34 uses 35 Classes, SysUtils, Types, FPImage, Graphics, BGRABitmapTypes, GraphType, FPImgCanv, BGRACanvas, BGRACanvas2D, FPWritePng; 35 Classes, SysUtils, Types, FPImage, Graphics, BGRABitmapTypes, GraphType, FPImgCanv, 36 BGRACanvas, BGRACanvas2D, FPWritePng, BGRAArrow, BGRAPen; 36 37 37 38 type … … 43 44 if the coordinates are visible and return true if it is the case, swap 44 45 coordinates if necessary and make them fit into the clipping rectangle } 45 function CheckHorizLineBounds(var x, y, x2: int eger): boolean; inline;46 function CheckVertLineBounds(var x, y, y2: int eger; out delta: integer): boolean; inline;46 function CheckHorizLineBounds(var x, y, x2: int32or64): boolean; inline; 47 function CheckVertLineBounds(var x, y, y2: int32or64; out delta: int32or64): boolean; inline; 47 48 function CheckRectBounds(var x,y,x2,y2: integer; minsize: integer): boolean; inline; 48 49 function CheckClippedRectBounds(var x,y,x2,y2: integer): boolean; inline; 49 function CheckPutImageBounds(x, y, tx, ty: integer; out minxb, minyb, maxxb, maxyb, ignoreleft: integer): boolean; inline;50 50 function CheckAntialiasRectBounds(var x,y,x2,y2: single; w: single): boolean; 51 51 function GetCanvasBGRA: TBGRACanvas; … … 75 75 FCanvasFP: TFPImageCanvas; 76 76 FCanvasDrawModeFP: TDrawMode; 77 FCanvasPixelProcFP: procedure(x, y: int eger; col: TBGRAPixel) of object;77 FCanvasPixelProcFP: procedure(x, y: int32or64; col: TBGRAPixel) of object; 78 78 79 79 //canvas-like with antialiasing and texturing … … 83 83 //drawing options 84 84 FEraseMode: boolean; //when polygons are erased instead of drawn 85 FFont: TFont; //font parameters86 85 FFontHeight: integer; 87 FFont HeightSign: integer; //sign correction86 FFontRenderer: TBGRACustomFontRenderer; 88 87 89 88 { Pen style can be defined by PenStyle property of by CustomPenStyle property. … … 92 91 FCustomPenStyle: TBGRAPenStyle; 93 92 FPenStyle: TPenStyle; 93 FArrow: TBGRAArrow; 94 FLineCap: TPenEndCap; 94 95 95 96 //Pixel data … … 99 100 AlwaysReplaceAlpha: boolean = False; RaiseErrorOnInvalidPixelFormat: boolean = True): boolean; 100 101 function GetDataPtr: PBGRAPixel; override; 101 procedure ClearTransparentPixels; 102 procedure ClearTransparentPixels; override; 102 103 function GetScanlineFast(y: integer): PBGRAPixel; inline; 103 104 function GetLineOrder: TRawImageLineOrder; override; … … 144 145 function GetAveragePixel: TBGRAPixel; override; 145 146 function CreateAdaptedPngWriter: TFPWriterPNG; 146 function LoadAsBmp32(Str: TStream): boolean; override;147 147 148 148 //drawing … … 151 151 procedure SetPenStyle(const AValue: TPenStyle); override; 152 152 function GetPenStyle: TPenStyle; override; 153 154 procedure UpdateFont; 153 function GetLineCap: TPenEndCap; override; 154 procedure SetLineCap(AValue: TPenEndCap); override; 155 function GetArrowEndSize: TPointF; override; 156 function GetArrowStartSize: TPointF; override; 157 procedure SetArrowEndSize(AValue: TPointF); override; 158 procedure SetArrowStartSize(AValue: TPointF); override; 159 function GetArrowEndOffset: single; override; 160 function GetArrowStartOffset: single; override; 161 procedure SetArrowEndOffset(AValue: single); override; 162 procedure SetArrowStartOffset(AValue: single); override; 163 function GetArrowEndRepeat: integer; override; 164 function GetArrowStartRepeat: integer; override; 165 procedure SetArrowEndRepeat(AValue: integer); override; 166 procedure SetArrowStartRepeat(AValue: integer); override; 167 155 168 function GetFontHeight: integer; override; 156 169 procedure SetFontHeight(AHeight: integer); override; … … 158 171 procedure SetFontFullHeight(AHeight: integer); override; 159 172 function GetFontPixelMetric: TFontPixelMetric; override; 173 function GetFontRenderer: TBGRACustomFontRenderer; override; 174 procedure SetFontRenderer(AValue: TBGRACustomFontRenderer); override; 160 175 161 176 function GetClipRect: TRect; override; 162 177 procedure SetClipRect(const AValue: TRect); override; 163 178 164 function GetPixelCycleInline(ix,iy: integer; iFactX,iFactY: integer): TBGRAPixel; inline; 179 function InternalGetPixelCycle256(ix,iy: int32or64; iFactX,iFactY: int32or64): TBGRAPixel; 180 function InternalGetPixel256(ix,iy: int32or64; iFactX,iFactY: int32or64; smoothBorder: boolean): TBGRAPixel; 181 function GetPolyLineOption: TBGRAPolyLineOptions; 182 function GetArrow: TBGRAArrow; 183 procedure SetArrowStart(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); override; 184 procedure SetArrowEnd(AStyle: TBGRAArrowStyle; ATipStyle: TPenJoinStyle = pjsMiter; ARelativePenWidth: single = 1; ATriangleBackOffset: single = 0); override; 165 185 166 186 public … … 170 190 function GetUnique: TBGRACustomBitmap; 171 191 172 {TFPCustomImage override} 173 constructor Create(AWidth, AHeight: integer); override; 174 procedure SetSize(AWidth, AHeight: integer); override; 175 176 {Constructors} 177 constructor Create; override; 178 constructor Create(ABitmap: TBitmap); override; 179 constructor Create(AWidth, AHeight: integer; Color: TColor); override; 180 constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); override; 181 constructor Create(AFilename: string); override; 182 constructor Create(AStream: TStream); override; 183 destructor Destroy; override; 184 185 {Loading functions} 186 function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; override; 187 function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; override; 188 function NewBitmap(Filename: string): TBGRACustomBitmap; override; 189 190 procedure LoadFromFile(const filename: string); override; 192 {------------------------- Constructors from TFPCustomImage----------------} 193 constructor Create(AWidth, AHeight: integer); override; //Creates a new bitmap, initialize properties and bitmap data 194 procedure SetSize(AWidth, AHeight: integer); override; //Can only be called with an existing instance of TBGRABitmap. 195 //Sets the dimensions of an existing TBGRABitmap instance. 196 197 {------------------------- Constructors from TBGRACustomBitmap-------------} 198 constructor Create; override; //Creates an image of width and height equal to zero. 199 constructor Create(ABitmap: TBitmap); override; //Creates an image of dimensions AWidth and AHeight and filled with transparent pixels. 200 constructor Create(AWidth, AHeight: integer; Color: TColor); override; //Creates an image of dimensions AWidth and AHeight and fills it with the opaque color Color. 201 constructor Create(AWidth, AHeight: integer; Color: TBGRAPixel); override; //Creates an image of dimensions AWidth and AHeight and fills it with Color. 202 203 constructor Create(AFilename: string); override; // Creates an image by loading its content from the file AFilename. 204 // The encoding of the string is the default one for the operating system. 205 // It is recommended to use the next constructor and UTF8 encoding. 206 207 constructor Create(AFilename: string; AIsUtf8: boolean); override; //Creates an image by loading its content from the file AFilename. 208 //The boolean AIsUtf8Filename specifies if UTF8 encoding is assumed for the filename. 209 210 constructor Create(AStream: TStream); override; // Creates an image by loading its content from the stream AStream. 211 destructor Destroy; override; // Free the object and all its resources 212 213 {------------------------- Quasi-constructors -----------------------------} 214 function NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; override; //Can only be called from an existing instance of TBGRABitmap. 215 //Creates a new instance with dimensions AWidth and AHeight, 216 //containing transparent pixels. 217 218 function NewBitmap(AWidth, AHeight: integer; Color: TBGRAPixel): TBGRACustomBitmap; override; //Can only be called from an existing instance of TBGRABitmap. 219 //Creates a new instance with dimensions AWidth and AHeight, 220 //and fills it with Color. 221 222 function NewBitmap(Filename: string): TBGRACustomBitmap; override; //Can only be called from an existing instance of TBGRABitmap. 223 //Creates a new instance with by loading its content 224 //from the file Filename. The encoding of the string 225 //is the default one for the operating system. 226 227 function NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; override; //Can only be called from an existing instance of TBGRABitmap. 228 //Creates a new instance with by loading its content 229 //from the file Filename. 230 191 231 procedure SaveToFile(const filename: string); override; 192 232 procedure SaveToStreamAsPng(Str: TStream); override; 193 procedure Assign(A Bitmap: TBitmap); override; overload;233 procedure Assign(ARaster: TRasterImage); override; overload; 194 234 procedure Assign(MemBitmap: TBGRACustomBitmap);override; overload; 195 235 procedure Serialize(AStream: TStream); override; … … 198 238 199 239 {Pixel functions} 200 function PtInClipRect(x, y: integer): boolean; inline; 201 procedure SetPixel(x, y: integer; c: TColor); override; 202 procedure SetPixel(x, y: integer; c: TBGRAPixel); override; 203 procedure XorPixel(x, y: integer; c: TBGRAPixel); override; 204 procedure DrawPixel(x, y: integer; c: TBGRAPixel); override; 205 procedure DrawPixel(x, y: integer; ec: TExpandedPixel); override; 206 procedure FastBlendPixel(x, y: integer; c: TBGRAPixel); override; 207 procedure ErasePixel(x, y: integer; alpha: byte); override; 208 procedure AlphaPixel(x, y: integer; alpha: byte); override; 209 function GetPixel(x, y: integer): TBGRAPixel; override; 210 function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override; 240 function PtInClipRect(x, y: int32or64): boolean; inline; 241 procedure SetPixel(x, y: int32or64; c: TColor); override; 242 procedure SetPixel(x, y: int32or64; c: TBGRAPixel); override; 243 procedure XorPixel(x, y: int32or64; c: TBGRAPixel); override; 244 procedure DrawPixel(x, y: int32or64; c: TBGRAPixel); override; 245 procedure DrawPixel(x, y: int32or64; ec: TExpandedPixel); override; 246 procedure FastBlendPixel(x, y: int32or64; c: TBGRAPixel); override; 247 procedure ErasePixel(x, y: int32or64; alpha: byte); override; 248 procedure AlphaPixel(x, y: int32or64; alpha: byte); override; 249 function GetPixel(x, y: int32or64): TBGRAPixel; override; 250 function GetPixel256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; override; 251 function GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; override; 211 252 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override; 212 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; 213 repeatX: boolean; repeatY: boolean): TBGRAPixel; override; overload; 253 function GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; override; 254 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; override; 255 function GetPixelCycle256(x, y, fracX256,fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; repeatY: boolean): TBGRAPixel; override; 214 256 215 257 {Line primitives} 216 procedure SetHorizLine(x, y, x2: integer; c: TBGRAPixel); override; 217 procedure XorHorizLine(x, y, x2: integer; c: TBGRAPixel); override; 218 procedure DrawHorizLine(x, y, x2: integer; c: TBGRAPixel); override; 219 procedure DrawHorizLine(x, y, x2: integer; ec: TExpandedPixel); override; 220 procedure DrawHorizLine(x, y, x2: integer; texture: IBGRAScanner); override; 221 procedure FastBlendHorizLine(x, y, x2: integer; c: TBGRAPixel); override; 222 procedure AlphaHorizLine(x, y, x2: integer; alpha: byte); override; 223 procedure SetVertLine(x, y, y2: integer; c: TBGRAPixel); override; 224 procedure XorVertLine(x, y, y2: integer; c: TBGRAPixel); override; 225 procedure DrawVertLine(x, y, y2: integer; c: TBGRAPixel); override; 226 procedure AlphaVertLine(x, y, y2: integer; alpha: byte); override; 227 procedure FastBlendVertLine(x, y, y2: integer; c: TBGRAPixel); override; 228 procedure DrawHorizLineDiff(x, y, x2: integer; c, compare: TBGRAPixel; 258 procedure SetHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override; 259 procedure XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override; 260 procedure DrawHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override; 261 procedure DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel); override; 262 procedure HorizLine(x, y, x2: int32or64; texture: IBGRAScanner; ADrawMode : TDrawMode); override; 263 264 procedure FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); override; 265 procedure AlphaHorizLine(x, y, x2: int32or64; alpha: byte); override; 266 procedure SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); override; 267 procedure XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); override; 268 procedure DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); override; 269 procedure AlphaVertLine(x, y, y2: int32or64; alpha: byte); override; 270 procedure FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); override; 271 procedure DrawHorizLineDiff(x, y, x2: int32or64; c, compare: TBGRAPixel; 229 272 maxDiff: byte); override; 230 273 231 274 {Shapes} 232 procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); override; 275 procedure DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single); override; 276 procedure DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single); override; 277 278 procedure DrawLine(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode = dmDrawWithTransparency); override; 233 279 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean); override; 234 280 procedure DrawLineAntialias(x1, y1, x2, y2: integer; c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean); override; … … 242 288 procedure DrawPolyLineAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); override; 243 289 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; Closed: boolean); override; 290 procedure DrawPolyLineAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); override; 244 291 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single); override; 245 292 procedure DrawPolygonAntialias(const points: array of TPointF; texture: IBGRAScanner; w: single); override; 293 procedure DrawPolygonAntialias(const points: array of TPointF; c: TBGRAPixel; w: single; fillcolor: TBGRAPixel); override; 246 294 247 295 procedure EraseLine(x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); override; … … 250 298 procedure EraseLineAntialias(x1, y1, x2, y2: single; alpha: byte; w: single; Closed: boolean); override; 251 299 procedure ErasePolyLineAntialias(const points: array of TPointF; alpha: byte; w: single); override; 300 301 procedure FillPath(APath: IBGRAPath; c: TBGRAPixel); override; 302 procedure FillPath(APath: IBGRAPath; texture: IBGRAScanner); override; 252 303 253 304 procedure FillTriangleLinearColor(pt1,pt2,pt3: TPointF; c1,c2,c3: TBGRAPixel); override; … … 263 314 procedure FillQuadLinearMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override; 264 315 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override; 316 procedure FillQuadPerspectiveMapping(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); override; 265 317 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); override; 318 procedure FillQuadPerspectiveMappingAntialias(pt1,pt2,pt3,pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; ACleanBorders: TRect); override; 266 319 267 320 procedure FillPolyLinearMapping(const points: array of TPointF; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean); override; … … 270 323 procedure FillPolyPerspectiveMapping(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; TextureInterpolation: Boolean; zbuffer: psingle = nil); override; 271 324 procedure FillPolyPerspectiveMappingLightness(const points: array of TPointF; const pointsZ: array of single; texture: IBGRAScanner; texCoords: array of TPointF; lightnesses: array of word; TextureInterpolation: Boolean; zbuffer: psingle = nil); override; 325 272 326 procedure FillPoly(const points: array of TPointF; c: TBGRAPixel; drawmode: TDrawMode); override; 273 327 procedure FillPoly(const points: array of TPointF; texture: IBGRAScanner; drawmode: TDrawMode); override; … … 276 330 procedure ErasePoly(const points: array of TPointF; alpha: byte); override; 277 331 procedure ErasePolyAntialias(const points: array of TPointF; alpha: byte); override; 332 333 procedure FillShape(shape: TBGRACustomFillInfo; c: TBGRAPixel; drawmode: TDrawMode); override; 334 procedure FillShape(shape: TBGRACustomFillInfo; texture: IBGRAScanner; drawmode: TDrawMode); override; 335 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; c: TBGRAPixel); override; 336 procedure FillShapeAntialias(shape: TBGRACustomFillInfo; texture: IBGRAScanner); override; 337 procedure EraseShape(shape: TBGRACustomFillInfo; alpha: byte); override; 338 procedure EraseShapeAntialias(shape: TBGRACustomFillInfo; alpha: byte); override; 278 339 279 340 procedure EllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel; w: single); override; … … 295 356 procedure RoundRectAntialias(x,y,x2,y2,rx,ry: single; penTexture: IBGRAScanner; w: single; fillTexture: IBGRAScanner; options: TRoundRectangleOptions = []); override; 296 357 297 procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override; 298 procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); override; 358 procedure FillRect(x, y, x2, y2: integer; c: TBGRAPixel; mode: TDrawMode); override; overload; 359 procedure FillRect(x, y, x2, y2: integer; texture: IBGRAScanner; mode: TDrawMode); override; overload; 299 360 procedure FillRectAntialias(x, y, x2, y2: single; c: TBGRAPixel); override; 300 361 procedure EraseRectAntialias(x, y, x2, y2: single; alpha: byte); override; … … 305 366 procedure AlphaFillRect(x, y, x2, y2: integer; alpha: byte); override; 306 367 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; 307 BorderColor, FillColor: TBGRAPixel); override; 308 309 procedure TextOutAngle(x, y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); override; 310 procedure TextOutAngle(x, y: single; orientation: integer; s: string; texture: IBGRAScanner; align: TAlignment); override; 311 procedure TextOut(x, y: single; s: string; texture: IBGRAScanner; align: TAlignment); override; 312 procedure TextOut(x, y: single; s: string; c: TBGRAPixel; align: TAlignment); override; 313 procedure TextRect(ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); override; 314 procedure TextRect(ARect: TRect; x, y: integer; s: string; style: TTextStyle; texture: IBGRAScanner); override; 315 function TextSize(s: string): TSize; override; 368 BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override; 369 procedure RoundRect(X1, Y1, X2, Y2: integer; DX, DY: integer; 370 BorderColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); override; 371 372 { Draws the UTF8 encoded string, with color c. 373 If align is taLeftJustify, (x,y) is the top-left corner. 374 If align is taCenter, (x,y) is at the top and middle of the text. 375 If align is taRightJustify, (x,y) is the top-right corner. 376 The value of FontOrientation is taken into account, so that the text may be rotated. } 377 procedure TextOut(x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); override; overload; 378 379 { Same as above functions, except that the text is filled using texture. 380 The value of FontOrientation is taken into account, so that the text may be rotated. } 381 procedure TextOut(x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); override; overload; 382 383 { Same as above, except that the orientation is specified, overriding the value of the property FontOrientation. } 384 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); override; overload; 385 procedure TextOutAngle(x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); override; overload; 386 387 { Draw the UTF8 encoded string at the coordinate (x,y), clipped inside the rectangle ARect. 388 Additional style information is provided by the style parameter. 389 The color c or texture is used to fill the text. No rotation is applied. } 390 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); override; overload; 391 procedure TextRect(ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); override; overload; 392 393 { Returns the total size of the string provided using the current font. 394 Orientation is not taken into account, so that the width is along the text. } 395 function TextSize(sUTF8: string): TSize; override; 316 396 317 397 {Spline} … … 344 424 procedure DrawPixels(c: TBGRAPixel; start, Count: integer); override; 345 425 procedure AlphaFill(alpha: byte; start, Count: integer); override; 346 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel ); override;347 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner ); override;426 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ADrawMode: TDrawMode); override; 427 procedure FillMask(x,y: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ADrawMode: TDrawMode); override; 348 428 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; color: TBGRAPixel; ARGBOrder: boolean = true); override; 349 429 procedure FillClearTypeMask(x,y: integer; xThird: integer; AMask: TBGRACustomBitmap; texture: IBGRAScanner; ARGBOrder: boolean = true); override; … … 380 460 381 461 {BGRA bitmap functions} 462 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); override; 463 procedure CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); override; 382 464 procedure PutImage(x, y: integer; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); override; 383 procedure PutImageAngle(x,y: single; Source: TBGRACustomBitmap; angle: single; imageCenterX: single = 0; imageCenterY: single = 0; AOpacity: Byte=255; ARestoreOffsetAfterRotation: boolean = false); override; 384 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte=255); override; 465 procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); override; 466 procedure StretchPutImage(ARect: TRect; Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte = 255); override; 467 385 468 procedure BlendImage(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation); override; 386 469 procedure BlendImageOver(x, y: integer; Source: TBGRACustomBitmap; operation: TBlendOperation; AOpacity: byte = 255; … … 394 477 function Equals(comp: TBGRAPixel): boolean; override; 395 478 function GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; override; 396 function GetImageBounds(Channels: TChannels ): TRect; override;479 function GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect; override; 397 480 function GetDifferenceBounds(ABitmap: TBGRACustomBitmap): TRect; override; 398 481 function MakeBitmapCopy(BackgroundColor: TColor): TBitmap; override; … … 400 483 function Resample(newWidth, newHeight: integer; 401 484 mode: TResampleMode = rmFineResample): TBGRACustomBitmap; override; 402 procedure VerticalFlip ; override;403 procedure HorizontalFlip ; override;485 procedure VerticalFlip(ARect: TRect); override; 486 procedure HorizontalFlip(ARect: TRect); override; 404 487 function RotateCW: TBGRACustomBitmap; override; 405 488 function RotateCCW: TBGRACustomBitmap; override; 406 489 procedure Negative; override; 490 procedure NegativeRect(ABounds: TRect); override; 407 491 procedure LinearNegative; override; 492 procedure LinearNegativeRect(ABounds: TRect); override; 493 procedure InplaceGrayscale; override; 494 procedure InplaceGrayscale(ABounds: TRect); override; 408 495 procedure SwapRedBlue; override; 409 496 procedure GrayscaleToAlpha; override; 410 497 procedure AlphaToGrayscale; override; 411 procedure ApplyMask(mask: TBGRACustomBitmap ); override;498 procedure ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); override; 412 499 procedure ApplyGlobalOpacity(alpha: byte); override; 413 500 procedure ConvertToLinearRGB; override; 414 501 procedure ConvertFromLinearRGB; override; 502 procedure DrawCheckers(ARect: TRect; AColorEven,AColorOdd: TBGRAPixel); 415 503 416 504 {Filters} … … 418 506 function FilterMedian(Option: TMedianOption): TBGRACustomBitmap; override; 419 507 function FilterSmooth: TBGRACustomBitmap; override; 420 function FilterSharpen: TBGRACustomBitmap; override; 508 function FilterSharpen(Amount: single = 1): TBGRACustomBitmap; override; 509 function FilterSharpen(ABounds: TRect; Amount: single = 1): TBGRACustomBitmap; override; 421 510 function FilterContour: TBGRACustomBitmap; override; 511 function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; override; 422 512 function FilterBlurRadial(radius: integer; 423 513 blurType: TRadialBlurType): TBGRACustomBitmap; override; 424 function FilterPixelate(pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; override; 514 function FilterBlurRadial(ABounds: TRect; radius: integer; 515 blurType: TRadialBlurType): TBGRACustomBitmap; override; 425 516 function FilterBlurMotion(distance: integer; angle: single; 426 517 oriented: boolean): TBGRACustomBitmap; override; 518 function FilterBlurMotion(ABounds: TRect; distance: integer; angle: single; 519 oriented: boolean): TBGRACustomBitmap; override; 427 520 function FilterCustomBlur(mask: TBGRACustomBitmap): TBGRACustomBitmap; override; 521 function FilterCustomBlur(ABounds: TRect; mask: TBGRACustomBitmap): TBGRACustomBitmap; override; 428 522 function FilterEmboss(angle: single): TBGRACustomBitmap; override; 523 function FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap; override; 429 524 function FilterEmbossHighlight(FillSelection: boolean): TBGRACustomBitmap; override; 430 525 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel): TBGRACustomBitmap; override; 431 526 function FilterEmbossHighlight(FillSelection: boolean; BorderColor: TBGRAPixel; var Offset: TPoint): TBGRACustomBitmap; override; 432 527 function FilterGrayscale: TBGRACustomBitmap; override; 528 function FilterGrayscale(ABounds: TRect): TBGRACustomBitmap; override; 433 529 function FilterNormalize(eachChannel: boolean = True): TBGRACustomBitmap; override; 434 function FilterRotate(origin: TPointF; angle: single): TBGRACustomBitmap; override; 530 function FilterNormalize(ABounds: TRect; eachChannel: boolean = True): TBGRACustomBitmap; override; 531 function FilterRotate(origin: TPointF; angle: single; correctBlur: boolean = false): TBGRACustomBitmap; override; 435 532 function FilterSphere: TBGRACustomBitmap; override; 436 533 function FilterTwirl(ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; override; 534 function FilterTwirl(ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; override; 437 535 function FilterCylinder: TBGRACustomBitmap; override; 438 536 function FilterPlane: TBGRACustomBitmap; override; … … 465 563 466 564 uses Math, LCLIntf, LCLType, 467 BGRABlend, BGRAFilters, BGRA Pen, BGRAText, BGRATextFX, BGRAGradientScanner,565 BGRABlend, BGRAFilters, BGRAText, BGRATextFX, BGRAGradientScanner, 468 566 BGRAResample, BGRATransform, BGRAPolygon, BGRAPolygonAliased, 469 567 BGRAPath, FPReadPcx, FPWritePcx, FPReadXPM, FPWriteXPM; … … 486 584 procedure TBitmapTracker.Changed(Sender: TObject); 487 585 begin 488 FUser.FBitmapModified := True; 586 if FUser <> nil then 587 FUser.FBitmapModified := True; 489 588 inherited Changed(Sender); 490 589 end; … … 570 669 end; 571 670 572 { Update font properties to internal TFont object } 573 procedure TBGRADefaultBitmap.UpdateFont; 574 begin 575 if FFont.Name <> FontName then 576 FFont.Name := FontName; 577 if FFont.Style <> FontStyle then 578 FFont.Style := FontStyle; 579 if FFont.Height <> FFontHeight * FFontHeightSign then 580 FFont.Height := FFontHeight * FFontHeightSign; 581 if FFont.Orientation <> FontOrientation then 582 FFont.Orientation := FontOrientation; 583 if FontQuality = fqSystemClearType then 584 FFont.Quality := fqCleartype 585 else 586 FFont.Quality := FontDefaultQuality; 671 function TBGRADefaultBitmap.GetLineCap: TPenEndCap; 672 begin 673 result := FLineCap; 674 end; 675 676 procedure TBGRADefaultBitmap.SetLineCap(AValue: TPenEndCap); 677 begin 678 if AValue <> FLineCap then 679 begin 680 FLineCap:= AValue; 681 if Assigned(FArrow) then FArrow.LineCap := AValue; 682 end; 683 end; 684 685 function TBGRADefaultBitmap.GetArrowEndSize: TPointF; 686 begin 687 result := GetArrow.EndSize; 688 end; 689 690 function TBGRADefaultBitmap.GetArrowStartSize: TPointF; 691 begin 692 result := GetArrow.StartSize; 693 end; 694 695 procedure TBGRADefaultBitmap.SetArrowEndSize(AValue: TPointF); 696 begin 697 GetArrow.EndSize := AValue; 698 end; 699 700 procedure TBGRADefaultBitmap.SetArrowStartSize(AValue: TPointF); 701 begin 702 GetArrow.StartSize := AValue; 703 end; 704 705 function TBGRADefaultBitmap.GetArrowEndOffset: single; 706 begin 707 result := GetArrow.EndOffsetX; 708 end; 709 710 function TBGRADefaultBitmap.GetArrowStartOffset: single; 711 begin 712 result := GetArrow.StartOffsetX; 713 end; 714 715 procedure TBGRADefaultBitmap.SetArrowEndOffset(AValue: single); 716 begin 717 GetArrow.EndOffsetX := AValue; 718 end; 719 720 procedure TBGRADefaultBitmap.SetArrowStartOffset(AValue: single); 721 begin 722 GetArrow.StartOffsetX := AValue; 723 end; 724 725 function TBGRADefaultBitmap.GetArrowEndRepeat: integer; 726 begin 727 result := GetArrow.EndRepeatCount; 728 end; 729 730 function TBGRADefaultBitmap.GetArrowStartRepeat: integer; 731 begin 732 result := GetArrow.StartRepeatCount; 733 end; 734 735 procedure TBGRADefaultBitmap.SetArrowEndRepeat(AValue: integer); 736 begin 737 GetArrow.EndRepeatCount := AValue; 738 end; 739 740 procedure TBGRADefaultBitmap.SetArrowStartRepeat(AValue: integer); 741 begin 742 GetArrow.StartRepeatCount := AValue; 587 743 end; 588 744 … … 609 765 610 766 function TBGRADefaultBitmap.GetFontPixelMetric: TFontPixelMetric; 611 var fxFont: TFont; 612 begin 613 UpdateFont; 614 if FontQuality = fqSystem then 615 result := BGRAText.GetFontPixelMetric(FFont) 616 else 617 begin 618 FxFont := TFont.Create; 619 FxFont.Assign(FFont); 620 FxFont.Height := fxFont.Height*FontAntialiasingLevel; 621 Result:= BGRAText.GetFontPixelMetric(FxFont); 622 if Result.Baseline <> -1 then Result.Baseline:= round((Result.Baseline-1)/FontAntialiasingLevel); 623 if Result.CapLine <> -1 then Result.CapLine:= round(Result.CapLine/FontAntialiasingLevel); 624 if Result.DescentLine <> -1 then Result.DescentLine:= round((Result.DescentLine-1)/FontAntialiasingLevel); 625 if Result.Lineheight <> -1 then Result.Lineheight:= round(Result.Lineheight/FontAntialiasingLevel); 626 if Result.xLine <> -1 then Result.xLine:= round(Result.xLine/FontAntialiasingLevel); 627 end; 767 begin 768 result := FontRenderer.GetFontPixelMetric; 769 end; 770 771 function TBGRADefaultBitmap.GetFontRenderer: TBGRACustomFontRenderer; 772 begin 773 if FFontRenderer = nil then FFontRenderer := TLCLFontRenderer.Create; 774 result := FFontRenderer; 775 result.FontName := FontName; 776 result.FontStyle := FontStyle; 777 result.FontQuality := FontQuality; 778 result.FontOrientation := FontOrientation; 779 result.FontEmHeight := FFontHeight; 780 end; 781 782 procedure TBGRADefaultBitmap.SetFontRenderer(AValue: TBGRACustomFontRenderer); 783 begin 784 if AValue = FFontRenderer then exit; 785 FFontRenderer.Free; 786 FFontRenderer := AValue 628 787 end; 629 788 … … 689 848 end; 690 849 691 { Creates a new bitmap. Internally, it uses the same type so that if you 850 { Creates a new bitmap with dimensions AWidth and AHeight and filled with 851 transparent pixels. Internally, it uses the same type so that if you 692 852 use an optimized version, you get a new bitmap with the same optimizations } 693 853 function TBGRADefaultBitmap.NewBitmap(AWidth, AHeight: integer): TBGRACustomBitmap; … … 701 861 end; 702 862 863 { Can only be called from an existing instance of TBGRABitmap. 864 Creates a new instance with dimensions AWidth and AHeight, 865 and fills it with Color. } 703 866 function TBGRADefaultBitmap.NewBitmap(AWidth, AHeight: integer; 704 867 Color: TBGRAPixel): TBGRACustomBitmap; … … 712 875 end; 713 876 714 { Creates a new bitmap and loads it contents from a file } 877 { Creates a new bitmap and loads it contents from a file. 878 The encoding of the string is the default one for the operating system. 879 It is recommended to use the next function and UTF8 encoding } 715 880 function TBGRADefaultBitmap.NewBitmap(Filename: string): TBGRACustomBitmap; 716 881 var … … 719 884 BGRAClass := TBGRABitmapAny(self.ClassType); 720 885 Result := BGRAClass.Create(Filename); 886 end; 887 888 { Creates a new bitmap and loads it contents from a file. 889 It is recommended to use UTF8 encoding } 890 function TBGRADefaultBitmap.NewBitmap(Filename: string; AIsUtf8: boolean): TBGRACustomBitmap; 891 var 892 BGRAClass: TBGRABitmapAny; 893 begin 894 BGRAClass := TBGRABitmapAny(self.ClassType); 895 Result := BGRAClass.Create(Filename,AIsUtf8); 721 896 end; 722 897 … … 754 929 {---------------------- Constructors ---------------------------------} 755 930 931 { Creates an image of width and height equal to zero. } 756 932 constructor TBGRADefaultBitmap.Create; 757 933 begin … … 760 936 end; 761 937 938 { Creates an image of dimensions AWidth and AHeight and filled with transparent pixels. } 762 939 constructor TBGRADefaultBitmap.Create(ABitmap: TBitmap); 763 940 begin … … 767 944 end; 768 945 946 { Creates an image of dimensions AWidth and AHeight and fills it with the opaque color Color. } 769 947 constructor TBGRADefaultBitmap.Create(AWidth, AHeight: integer; Color: TColor); 770 948 begin … … 774 952 end; 775 953 954 { Creates an image of dimensions AWidth and AHeight and fills it with Color. } 776 955 constructor TBGRADefaultBitmap.Create(AWidth, AHeight: integer; Color: TBGRAPixel); 777 956 begin … … 781 960 end; 782 961 962 { Creates an image by loading its content from the file AFilename. 963 The encoding of the string is the default one for the operating system. 964 It is recommended to use the next constructor and UTF8 encoding. } 965 constructor TBGRADefaultBitmap.Create(AFilename: string); 966 begin 967 Init; 968 inherited Create(0, 0); 969 LoadFromFile(Afilename); 970 end; 971 972 { Free the object and all its resources } 783 973 destructor TBGRADefaultBitmap.Destroy; 784 974 begin 785 975 FreeData; 786 FFont .Free;976 FFontRenderer.Free; 787 977 FBitmap.Free; 788 978 FCanvasFP.Free; 789 979 FCanvasBGRA.Free; 790 980 FCanvas2D.Free; 981 FArrow.Free; 791 982 inherited Destroy; 792 983 end; … … 794 985 {------------------------- Loading functions ----------------------------------} 795 986 796 constructor TBGRADefaultBitmap.Create(AFilename: string); 987 { Creates an image by loading its content from the file AFilename. 988 The boolean AIsUtf8Filename specifies if UTF8 encoding is assumed for the filename. } 989 constructor TBGRADefaultBitmap.Create(AFilename: string; AIsUtf8: boolean); 797 990 begin 798 991 Init; 799 inherited Create(0, 0); 800 LoadFromFile(Afilename); 801 end; 802 992 inherited Create(0, 0); 993 if AIsUtf8 then 994 LoadFromFileUTF8(Afilename) 995 else 996 LoadFromFile(Afilename); 997 end; 998 999 { Creates an image by loading its content from the stream AStream. } 803 1000 constructor TBGRADefaultBitmap.Create(AStream: TStream); 804 1001 begin … … 808 1005 end; 809 1006 810 procedure TBGRADefaultBitmap.Assign(A Bitmap: TBitmap);1007 procedure TBGRADefaultBitmap.Assign(ARaster: TRasterImage); 811 1008 var TempBmp: TBitmap; 812 1009 ConvertOk: boolean; 813 1010 begin 814 1011 DiscardBitmapChange; 815 SetSize(ABitmap.Width, ABitmap.Height); 816 if not LoadFromRawImage(ABitmap.RawImage,0,False,False) then 1012 SetSize(ARaster.Width, ARaster.Height); 1013 if not LoadFromRawImage(ARaster.RawImage,0,False,False) then 1014 if ARaster is TBitmap then 817 1015 begin //try to convert 818 1016 TempBmp := TBitmap.Create; 819 TempBmp.Width := A Bitmap.Width;820 TempBmp.Height := A Bitmap.Height;821 TempBmp.Canvas.Draw(0,0,A Bitmap);1017 TempBmp.Width := ARaster.Width; 1018 TempBmp.Height := ARaster.Height; 1019 TempBmp.Canvas.Draw(0,0,ARaster); 822 1020 ConvertOk := LoadFromRawImage(TempBmp.RawImage,0,False,False); 823 1021 TempBmp.Free; 824 1022 if not ConvertOk then 825 1023 raise Exception.Create('Unable to convert image to 24 bit'); 826 end; 1024 end else 1025 raise Exception.Create('Unable to convert image to 24 bit'); 827 1026 If Empty then AlphaFill(255); // if bitmap seems to be empty, assume 828 1027 // it is an opaque bitmap without alpha channel … … 837 1036 838 1037 procedure TBGRADefaultBitmap.Serialize(AStream: TStream); 839 var lWidth,lHeight : integer;1038 var lWidth,lHeight,y: integer; 840 1039 begin 841 1040 lWidth := NtoLE(Width); … … 843 1042 AStream.Write(lWidth,sizeof(lWidth)); 844 1043 AStream.Write(lHeight,sizeof(lHeight)); 845 AStream.Write(Data^, NbPixels*sizeof(TBGRAPixel)); 1044 for y := 0 to Height-1 do 1045 AStream.Write(ScanLine[y]^, Width*sizeof(TBGRAPixel)); 846 1046 end; 847 1047 848 1048 {$hints off} 849 1049 procedure TBGRADefaultBitmap.Deserialize(AStream: TStream); 850 var lWidth,lHeight : integer;1050 var lWidth,lHeight,y: integer; 851 1051 begin 852 1052 AStream.Read(lWidth,sizeof(lWidth)); … … 855 1055 lHeight := LEtoN(lHeight); 856 1056 SetSize(lWidth,lHeight); 857 AStream.Read(Data^, NbPixels*sizeof(TBGRAPixel)); 1057 for y := 0 to Height-1 do 1058 AStream.Read(ScanLine[y]^, Width*sizeof(TBGRAPixel)); 858 1059 end; 859 1060 {$hints on} … … 865 1066 AStream.Write(zero,sizeof(zero)); 866 1067 AStream.Write(zero,sizeof(zero)); 867 end;868 869 procedure TBGRADefaultBitmap.LoadFromFile(const filename: string);870 var871 OldDrawMode: TDrawMode;872 begin873 OldDrawMode := CanvasDrawModeFP;874 CanvasDrawModeFP := dmSet;875 ClipRect := rect(0,0,Width,Height);876 try877 inherited LoadFromfile(filename);878 finally879 CanvasDrawModeFP := OldDrawMode;880 ClearTransparentPixels;881 end;882 1068 end; 883 1069 … … 918 1104 919 1105 { Check if a point is in the clipping rectangle } 920 function TBGRADefaultBitmap.PtInClipRect(x, y: int eger): boolean;1106 function TBGRADefaultBitmap.PtInClipRect(x, y: int32or64): boolean; 921 1107 begin 922 1108 result := (x >= FClipRect.Left) and (y >= FClipRect.Top) and (x < FClipRect.Right) and (y < FClipRect.Bottom); … … 943 1129 end; 944 1130 945 function TBGRADefaultBitmap. GetPixelCycleInline(ix, iy: integer; iFactX,946 iFactY: int eger): TBGRAPixel;947 var 948 ixMod1,ixMod2: int eger;949 w1,w2,w3,w4,alphaW: cardinal;950 bSum, gSum, rSum: cardinal;951 aSum: cardinal;1131 function TBGRADefaultBitmap.InternalGetPixelCycle256(ix, iy: int32or64; iFactX, 1132 iFactY: int32or64): TBGRAPixel; 1133 var 1134 ixMod1,ixMod2: int32or64; 1135 w1,w2,w3,w4,alphaW: UInt32or64; 1136 bSum, gSum, rSum: UInt32or64; 1137 aSum: UInt32or64; 952 1138 953 1139 c: TBGRAPixel; … … 964 1150 aSum := 0; 965 1151 966 scan := GetScanlineFast( PositiveMod(iy,Height));967 968 ixMod1 := PositiveMod(ix,Width); //apply cycle969 c := (scan + ix Mod1)^;1152 scan := GetScanlineFast(iy); 1153 1154 ixMod1 := ix; 1155 c := (scan + ix)^; 970 1156 alphaW := c.alpha * w1; 971 1157 aSum += alphaW; … … 975 1161 bSum += c.blue * alphaW; 976 1162 977 Inc(ix);978 i xMod2 := PositiveMod(ix,Width); //apply cycle1163 ixMod2 := ix+1; 1164 if ixMod2=Width then ixMod2 := 0; 979 1165 c := (scan + ixMod2)^; 980 1166 alphaW := c.alpha * w2; … … 986 1172 987 1173 Inc(iy); 988 scan := GetScanlineFast(PositiveMod(iy,Height)); 1174 if iy = Height then iy := 0; 1175 scan := GetScanlineFast(iy); 989 1176 990 1177 c := (scan + ixMod2)^; … … 1014 1201 end; 1015 1202 end; 1203 1204 function TBGRADefaultBitmap.InternalGetPixel256(ix, iy: int32or64; iFactX, 1205 iFactY: int32or64; smoothBorder: boolean): TBGRAPixel; 1206 var 1207 w1,w2,w3,w4,alphaW: cardinal; 1208 rSum, gSum, bSum: cardinal; //rgbDiv = aSum 1209 aSum, aDiv: cardinal; 1210 c: TBGRAPixel; 1211 scan: PBGRAPixel; 1212 begin 1213 rSum := 0; 1214 gSum := 0; 1215 bSum := 0; 1216 aSum := 0; 1217 aDiv := 0; 1218 1219 w4 := (iFactX*iFactY+127) shr 8; 1220 w3 := iFactY-w4; 1221 {$PUSH}{$HINTS OFF} 1222 w1 := (256-iFactX)-w3; 1223 {$POP} 1224 w2 := iFactX-w4; 1225 1226 { For each pixel around the coordinate, compute 1227 the weight for it and multiply values by it before 1228 adding to the sum } 1229 if (iy >= 0) and (iy < Height) then 1230 begin 1231 scan := GetScanlineFast(iy); 1232 1233 if (ix >= 0) and (ix < Width) then 1234 begin 1235 c := (scan + ix)^; 1236 alphaW := c.alpha * w1; 1237 aDiv += w1; 1238 aSum += alphaW; 1239 rSum += c.red * alphaW; 1240 gSum += c.green * alphaW; 1241 bSum += c.blue * alphaW; 1242 end; 1243 1244 Inc(ix); 1245 if (ix >= 0) and (ix < Width) then 1246 begin 1247 c := (scan + ix)^; 1248 alphaW := c.alpha * w2; 1249 aDiv += w2; 1250 aSum += alphaW; 1251 rSum += c.red * alphaW; 1252 gSum += c.green * alphaW; 1253 bSum += c.blue * alphaW; 1254 end; 1255 end 1256 else 1257 begin 1258 Inc(ix); 1259 end; 1260 1261 Inc(iy); 1262 if (iy >= 0) and (iy < Height) then 1263 begin 1264 scan := GetScanlineFast(iy); 1265 1266 if (ix >= 0) and (ix < Width) then 1267 begin 1268 c := (scan + ix)^; 1269 alphaW := c.alpha * w4; 1270 aDiv += w4; 1271 aSum += alphaW; 1272 rSum += c.red * alphaW; 1273 gSum += c.green * alphaW; 1274 bSum += c.blue * alphaW; 1275 end; 1276 1277 Dec(ix); 1278 if (ix >= 0) and (ix < Width) then 1279 begin 1280 c := (scan + ix)^; 1281 alphaW := c.alpha * w3; 1282 aDiv += w3; 1283 aSum += alphaW; 1284 rSum += c.red * alphaW; 1285 gSum += c.green * alphaW; 1286 bSum += c.blue * alphaW; 1287 end; 1288 end; 1289 1290 if aSum < 128 then //if there is no alpha 1291 Result := BGRAPixelTransparent 1292 else 1293 begin 1294 Result.red := (rSum + aSum shr 1) div aSum; 1295 Result.green := (gSum + aSum shr 1) div aSum; 1296 Result.blue := (bSum + aSum shr 1) div aSum; 1297 if smoothBorder or (aDiv = 256) then 1298 Result.alpha := (aSum + 128) shr 8 1299 else 1300 Result.alpha := (aSum + aDiv shr 1) div aDiv; 1301 end; 1302 end; 1303 1304 function TBGRADefaultBitmap.GetPolyLineOption: TBGRAPolyLineOptions; 1305 begin 1306 result := []; 1307 if Assigned(FArrow) and FArrow.IsStartDefined then result += [plNoStartCap]; 1308 if Assigned(FArrow) and FArrow.IsEndDefined then result += [plNoEndCap]; 1309 end; 1310 1311 function TBGRADefaultBitmap.GetArrow: TBGRAArrow; 1312 begin 1313 if FArrow = nil then 1314 begin 1315 FArrow := TBGRAArrow.Create; 1316 FArrow.LineCap := LineCap; 1317 end; 1318 result := FArrow; 1319 end; 1320 1016 1321 {-------------------------- Pixel functions -----------------------------------} 1017 1322 1018 procedure TBGRADefaultBitmap.SetPixel(x, y: int eger; c: TBGRAPixel);1323 procedure TBGRADefaultBitmap.SetPixel(x, y: int32or64; c: TBGRAPixel); 1019 1324 begin 1020 1325 if not PtInClipRect(x,y) then exit; … … 1024 1329 end; 1025 1330 1026 procedure TBGRADefaultBitmap.XorPixel(x, y: int eger; c: TBGRAPixel);1331 procedure TBGRADefaultBitmap.XorPixel(x, y: int32or64; c: TBGRAPixel); 1027 1332 var 1028 1333 p : PDWord; … … 1035 1340 end; 1036 1341 1037 procedure TBGRADefaultBitmap.SetPixel(x, y: int eger; c: TColor);1342 procedure TBGRADefaultBitmap.SetPixel(x, y: int32or64; c: TColor); 1038 1343 var 1039 1344 p: PByte; … … 1052 1357 end; 1053 1358 1054 procedure TBGRADefaultBitmap.DrawPixel(x, y: int eger; c: TBGRAPixel);1359 procedure TBGRADefaultBitmap.DrawPixel(x, y: int32or64; c: TBGRAPixel); 1055 1360 begin 1056 1361 if not PtInClipRect(x,y) then exit; … … 1060 1365 end; 1061 1366 1062 procedure TBGRADefaultBitmap.DrawPixel(x, y: int eger; ec: TExpandedPixel);1367 procedure TBGRADefaultBitmap.DrawPixel(x, y: int32or64; ec: TExpandedPixel); 1063 1368 begin 1064 1369 if not PtInClipRect(x,y) then exit; … … 1068 1373 end; 1069 1374 1070 procedure TBGRADefaultBitmap.FastBlendPixel(x, y: int eger; c: TBGRAPixel);1375 procedure TBGRADefaultBitmap.FastBlendPixel(x, y: int32or64; c: TBGRAPixel); 1071 1376 begin 1072 1377 if not PtInClipRect(x,y) then exit; … … 1076 1381 end; 1077 1382 1078 procedure TBGRADefaultBitmap.ErasePixel(x, y: int eger; alpha: byte);1383 procedure TBGRADefaultBitmap.ErasePixel(x, y: int32or64; alpha: byte); 1079 1384 begin 1080 1385 if not PtInClipRect(x,y) then exit; … … 1084 1389 end; 1085 1390 1086 procedure TBGRADefaultBitmap.AlphaPixel(x, y: int eger; alpha: byte);1391 procedure TBGRADefaultBitmap.AlphaPixel(x, y: int32or64; alpha: byte); 1087 1392 begin 1088 1393 if not PtInClipRect(x,y) then exit; … … 1095 1400 end; 1096 1401 1097 function TBGRADefaultBitmap.GetPixel(x, y: int eger): TBGRAPixel;1402 function TBGRADefaultBitmap.GetPixel(x, y: int32or64): TBGRAPixel; 1098 1403 begin 1099 1404 if (x < 0) or (x >= Width) or (y < 0) or (y >= Height) then //it is possible to read pixels outside of the cliprect … … 1106 1411 end; 1107 1412 1413 function TBGRADefaultBitmap.GetPixel256(x, y, fracX256, fracY256: int32or64; 1414 AResampleFilter: TResampleFilter; smoothBorder: boolean = true): TBGRAPixel; 1415 begin 1416 if (fracX256 = 0) and (fracY256 = 0) then 1417 result := GetPixel(x,y) 1418 else if AResampleFilter = rfBox then 1419 begin 1420 if fracX256 >= 128 then inc(x); 1421 if fracY256 >= 128 then inc(y); 1422 result := GetPixel(x,y); 1423 end else 1424 begin 1425 LoadFromBitmapIfNeeded; 1426 result := InternalGetPixel256(x,y,FineInterpolation256(fracX256,AResampleFilter),FineInterpolation256(fracY256,AResampleFilter),smoothBorder); 1427 end; 1428 end; 1429 1108 1430 {$hints off} 1109 1431 { This function compute an interpolated pixel at floating point coordinates } 1110 function TBGRADefaultBitmap.GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; 1111 var 1112 ix, iy: integer; 1113 w1,w2,w3,w4,alphaW: cardinal; 1114 rSum, gSum, bSum: cardinal; //rgbDiv = aSum 1115 aSum: cardinal; 1116 c: TBGRAPixel; 1117 scan: PBGRAPixel; 1118 factX,factY: single; 1119 iFactX,iFactY: integer; 1120 begin 1121 ix := floor(x); 1122 iy := floor(y); 1123 factX := x-ix; //distance from integer coordinate 1124 factY := y-iy; 1432 function TBGRADefaultBitmap.GetPixel(x, y: single; AResampleFilter: TResampleFilter = rfLinear; smoothBorder: boolean = true): TBGRAPixel; 1433 var 1434 ix, iy: Int32or64; 1435 iFactX,iFactY: Int32or64; 1436 begin 1437 ix := round(x*256); 1438 if (ix<= -256) or (ix>=Width shl 8) then 1439 begin 1440 result := BGRAPixelTransparent; 1441 exit; 1442 end; 1443 iy := round(y*256); 1444 if (iy<= -256) or (iy>=Height shl 8) then 1445 begin 1446 result := BGRAPixelTransparent; 1447 exit; 1448 end; 1449 1450 iFactX := ix and 255; //distance from integer coordinate 1451 iFactY := iy and 255; 1452 if ix<0 then ix := -1 else ix := ix shr 8; 1453 if iy<0 then iy := -1 else iy := iy shr 8; 1125 1454 1126 1455 //if the coordinate is integer, then call standard GetPixel function 1127 if ( factX = 0) and (factY = 0) then1128 begin 1129 Result := GetPixel(ix, iy);1456 if (iFactX = 0) and (iFactY = 0) then 1457 begin 1458 Result := (GetScanlineFast(iy)+ix)^; 1130 1459 exit; 1131 1460 end; 1461 1132 1462 LoadFromBitmapIfNeeded; 1133 1134 rSum := 0; 1135 gSum := 0; 1136 bSum := 0; 1137 aSum := 0; 1138 1139 //apply interpolation filter 1140 factX := FineInterpolation( factX, AResampleFilter ); 1141 factY := FineInterpolation( factY, AResampleFilter ); 1142 1143 iFactX := round(factX*256); //integer values for fractionnal part 1144 iFactY := round(factY*256); 1145 1146 w4 := (iFactX*iFactY+127) shr 8; 1147 w3 := iFactY-w4; 1148 w1 := (256-iFactX)-w3; 1149 w2 := iFactX-w4; 1150 1151 { For each pixel around the coordinate, compute 1152 the weight for it and multiply values by it before 1153 adding to the sum } 1154 if (iy >= 0) and (iy < Height) then 1155 begin 1156 scan := GetScanlineFast(iy); 1157 1158 if (ix >= 0) and (ix < Width) then 1159 begin 1160 c := (scan + ix)^; 1161 alphaW := c.alpha * w1; 1162 aSum += alphaW; 1163 rSum += c.red * alphaW; 1164 gSum += c.green * alphaW; 1165 bSum += c.blue * alphaW; 1166 end; 1167 1168 Inc(ix); 1169 if (ix >= 0) and (ix < Width) then 1170 begin 1171 c := (scan + ix)^; 1172 alphaW := c.alpha * w2; 1173 aSum += alphaW; 1174 rSum += c.red * alphaW; 1175 gSum += c.green * alphaW; 1176 bSum += c.blue * alphaW; 1177 end; 1178 end 1179 else 1180 begin 1181 Inc(ix); 1182 end; 1183 1184 Inc(iy); 1185 if (iy >= 0) and (iy < Height) then 1186 begin 1187 scan := GetScanlineFast(iy); 1188 1189 if (ix >= 0) and (ix < Width) then 1190 begin 1191 c := (scan + ix)^; 1192 alphaW := c.alpha * w4; 1193 aSum += alphaW; 1194 rSum += c.red * alphaW; 1195 gSum += c.green * alphaW; 1196 bSum += c.blue * alphaW; 1197 end; 1198 1199 Dec(ix); 1200 if (ix >= 0) and (ix < Width) then 1201 begin 1202 c := (scan + ix)^; 1203 alphaW := c.alpha * w3; 1204 aSum += alphaW; 1205 rSum += c.red * alphaW; 1206 gSum += c.green * alphaW; 1207 bSum += c.blue * alphaW; 1208 end; 1209 end; 1210 1211 if aSum < 128 then //if there is no alpha 1212 Result := BGRAPixelTransparent 1213 else 1214 begin 1215 Result.red := (rSum + aSum shr 1) div aSum; 1216 Result.green := (gSum + aSum shr 1) div aSum; 1217 Result.blue := (bSum + aSum shr 1) div aSum; 1218 Result.alpha := (aSum + 128) shr 8; 1219 end; 1463 result := InternalGetPixel256(ix,iy,FineInterpolation256(iFactX,AResampleFilter),FineInterpolation256(iFactY,AResampleFilter),smoothBorder); 1220 1464 end; 1221 1465 … … 1223 1467 function TBGRADefaultBitmap.GetPixelCycle(x, y: single; AResampleFilter: TResampleFilter = rfLinear): TBGRAPixel; 1224 1468 var 1225 ix, iy: integer; 1226 iFactX,iFactY: integer; 1227 begin 1469 ix, iy: Int32or64; 1470 iFactX,iFactY: Int32or64; 1471 begin 1472 if FData = nil then 1473 begin 1474 result := BGRAPixelTransparent; 1475 exit; 1476 end; 1228 1477 LoadFromBitmapIfNeeded; 1229 iFactX := round(x*256); 1230 iFactY := round(y*256); 1231 ix := (iFactX shr 8)+ScanOffset.X; 1232 iy := (iFactY shr 8)+ScanOffset.Y; 1233 iFactX := iFactX and 255; 1234 iFactY := iFactY and 255; 1235 1478 ix := round(x*256); 1479 iy := round(y*256); 1480 iFactX := ix and 255; 1481 iFactY := iy and 255; 1482 ix := PositiveMod(ix, FWidth shl 8) shr 8; 1483 iy := PositiveMod(iy, FHeight shl 8) shr 8; 1236 1484 if (iFactX = 0) and (iFactY = 0) then 1237 1485 begin 1238 result := ( ScanLine[PositiveMod(iy, FHeight)]+PositiveMod(ix, FWidth))^;1486 result := (GetScanlineFast(iy)+ix)^; 1239 1487 exit; 1240 1488 end; 1241 1242 1489 if ScanInterpolationFilter <> rfLinear then 1243 1490 begin … … 1245 1492 iFactY := FineInterpolation256( iFactY, ScanInterpolationFilter ); 1246 1493 end; 1247 1248 result := GetPixelCycleInline(ix,iy, iFactX,iFactY); 1494 result := InternalGetPixelCycle256(ix,iy, iFactX,iFactY); 1249 1495 end; 1250 1496 … … 1253 1499 ): TBGRAPixel; 1254 1500 var 1255 alpha: byte; 1256 begin 1257 alpha := 255; 1258 if not repeatX then 1259 begin 1260 if (x < -0.5) or (x > Width-0.5) then 1261 begin 1262 result := BGRAPixelTransparent; 1263 exit; 1501 ix, iy: Int32or64; 1502 iFactX,iFactY: Int32or64; 1503 begin 1504 if FData = nil then 1505 begin 1506 result := BGRAPixelTransparent; 1507 exit; 1508 end; 1509 ix := round(x*256); 1510 iy := round(y*256); 1511 iFactX := ix and 255; 1512 iFactY := iy and 255; 1513 if ix < 0 then ix := -((iFactX-ix) shr 8) 1514 else ix := ix shr 8; 1515 if iy < 0 then iy := -((iFactY-iy) shr 8) 1516 else iy := iy shr 8; 1517 result := GetPixelCycle256(ix,iy,iFactX,iFactY,AResampleFilter,repeatX,repeatY); 1518 end; 1519 1520 function TBGRADefaultBitmap.GetPixelCycle256(x, y, fracX256, 1521 fracY256: int32or64; AResampleFilter: TResampleFilter): TBGRAPixel; 1522 begin 1523 if (fracX256 = 0) and (fracY256 = 0) then 1524 result := GetPixelCycle(x,y) 1525 else if AResampleFilter = rfBox then 1526 begin 1527 if fracX256 >= 128 then inc(x); 1528 if fracY256 >= 128 then inc(y); 1529 result := GetPixelCycle(x,y); 1530 end else 1531 begin 1532 LoadFromBitmapIfNeeded; 1533 result := InternalGetPixelCycle256(PositiveMod(x,FWidth),PositiveMod(y,FHeight),FineInterpolation256(fracX256,AResampleFilter),FineInterpolation256(fracY256,AResampleFilter)); 1534 end; 1535 end; 1536 1537 function TBGRADefaultBitmap.GetPixelCycle256(x, y, fracX256, 1538 fracY256: int32or64; AResampleFilter: TResampleFilter; repeatX: boolean; 1539 repeatY: boolean): TBGRAPixel; 1540 begin 1541 if not repeatX and not repeatY then 1542 result := GetPixel256(x,y,fracX256,fracY256,AResampleFilter) 1543 else if repeatX and repeatY then 1544 result := GetPixelCycle256(x,y,fracX256,fracY256,AResampleFilter) 1545 else 1546 begin 1547 if not repeatX then 1548 begin 1549 if x < 0 then 1550 begin 1551 if x < -1 then 1552 begin 1553 result := BGRAPixelTransparent; 1554 exit; 1555 end; 1556 result := GetPixelCycle256(0,y,0,fracY256,AResampleFilter); 1557 result.alpha:= result.alpha*fracX256 shr 8; 1558 if result.alpha = 0 then 1559 result := BGRAPixelTransparent; 1560 exit; 1561 end; 1562 if x >= FWidth-1 then 1563 begin 1564 if x >= FWidth then 1565 begin 1566 result := BGRAPixelTransparent; 1567 exit; 1568 end; 1569 result := GetPixelCycle256(FWidth-1,y,0,fracY256,AResampleFilter); 1570 result.alpha:= result.alpha*(256-fracX256) shr 8; 1571 if result.alpha = 0 then 1572 result := BGRAPixelTransparent; 1573 exit; 1574 end; 1575 end else 1576 begin 1577 if y < 0 then 1578 begin 1579 if y < -1 then 1580 begin 1581 result := BGRAPixelTransparent; 1582 exit; 1583 end; 1584 result := GetPixelCycle256(x,0,fracX256,0,AResampleFilter); 1585 result.alpha:= result.alpha*fracY256 shr 8; 1586 if result.alpha = 0 then 1587 result := BGRAPixelTransparent; 1588 exit; 1589 end; 1590 if y >= FHeight-1 then 1591 begin 1592 if y >= FHeight then 1593 begin 1594 result := BGRAPixelTransparent; 1595 exit; 1596 end; 1597 result := GetPixelCycle256(x,FHeight-1,fracX256,0,AResampleFilter); 1598 result.alpha:= result.alpha*(256-fracY256) shr 8; 1599 if result.alpha = 0 then 1600 result := BGRAPixelTransparent; 1601 exit; 1602 end; 1264 1603 end; 1265 if x < 0 then 1266 begin 1267 alpha := round((0.5+x)*510); 1268 x := 0; 1269 end 1270 else 1271 if x > Width-1 then 1272 begin 1273 alpha := round((Width-0.5-x)*510); 1274 x := Width-1; 1275 end; 1276 end; 1277 if not repeatY then 1278 begin 1279 if (y < -0.5) or (y > Height-0.5) then 1280 begin 1281 result := BGRAPixelTransparent; 1282 exit; 1283 end; 1284 if y < 0 then 1285 begin 1286 alpha := round((0.5+y)*2*alpha); 1287 y := 0; 1288 end 1289 else 1290 if y > Height-1 then 1291 begin 1292 alpha := round((Height-0.5-y)*2*alpha); 1293 y := Height-1; 1294 end; 1295 end; 1296 result := GetPixelCycle(x,y,AResampleFilter); 1297 if alpha<>255 then 1298 result.alpha := ApplyOpacity(result.alpha,alpha); 1604 result := GetPixelCycle256(x,y,fracX256,fracY256,AResampleFilter); 1605 end; 1299 1606 end; 1300 1607 … … 1540 1847 (ARawImage.Description.BlueShift = 8) and 1541 1848 (ARawImage.Description.ByteOrder = riboMSBFirst)) then 1542 mustSwapRedBlue:= true 1849 begin 1850 mustSwapRedBlue:= true; 1851 mustReverse32 := false; 1852 end 1543 1853 else 1544 1854 begin … … 1655 1965 end; 1656 1966 1967 procedure TBGRADefaultBitmap.CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadePosition: byte; mode: TDrawMode = dmDrawWithTransparency); 1968 var constScanner: TBGRAConstantScanner; 1969 begin 1970 if AFadePosition = 0 then 1971 FillRect(ARect, Source1, mode) else 1972 if AFadePosition = 255 then 1973 FillRect(ARect, Source2, mode) else 1974 begin 1975 constScanner := TBGRAConstantScanner.Create(BGRA(AFadePosition,AFadePosition,AFadePosition,255)); 1976 CrossFade(ARect, Source1,Source2, constScanner, mode); 1977 constScanner.Free; 1978 end; 1979 end; 1980 1981 procedure TBGRADefaultBitmap.CrossFade(ARect: TRect; Source1, Source2: IBGRAScanner; AFadeMask: IBGRAScanner; mode: TDrawMode = dmDrawWithTransparency); 1982 var xb,yb: NativeInt; 1983 pdest: PBGRAPixel; 1984 c: TBGRAPixel; 1985 fadePos: byte; 1986 begin 1987 if not IntersectRect(ARect,ARect,ClipRect) then exit; 1988 for yb := ARect.top to ARect.Bottom-1 do 1989 begin 1990 pdest := GetScanlineFast(yb)+ARect.Left; 1991 Source1.ScanMoveTo(ARect.left, yb); 1992 Source2.ScanMoveTo(ARect.left, yb); 1993 AFadeMask.ScanMoveTo(ARect.left, yb); 1994 for xb := ARect.left to ARect.Right-1 do 1995 begin 1996 fadePos := AFadeMask.ScanNextPixel.green; 1997 c := MergeBGRAWithGammaCorrection(Source1.ScanNextPixel,not fadePos,Source2.ScanNextPixel,fadePos); 1998 case mode of 1999 dmSet: pdest^ := c; 2000 dmDrawWithTransparency: DrawPixelInlineWithAlphaCheck(pdest, c); 2001 dmLinearBlend: FastBlendPixelInline(pdest,c); 2002 dmSetExceptTransparent: if c.alpha = 255 then pdest^ := c; 2003 end; 2004 inc(pdest); 2005 end; 2006 end; 2007 InvalidateBitmap; 2008 end; 2009 1657 2010 procedure TBGRADefaultBitmap.DiscardBitmapChange; inline; 1658 2011 begin … … 1677 2030 FillMode := fmWinding; 1678 2031 1679 FFont := TFont.Create;1680 2032 FontName := 'Arial'; 1681 2033 FontStyle := []; 1682 2034 FontAntialias := False; 1683 2035 FFontHeight := 20; 1684 FFontHeightSign := GetFontHeightSign(FFont);1685 2036 1686 2037 PenStyle := psSolid; … … 1756 2107 {---------------------------- Line primitives ---------------------------------} 1757 2108 1758 function TBGRADefaultBitmap.CheckHorizLineBounds(var x,y,x2: int eger): boolean; inline;1759 var 1760 temp: int eger;2109 function TBGRADefaultBitmap.CheckHorizLineBounds(var x,y,x2: int32or64): boolean; inline; 2110 var 2111 temp: int32or64; 1761 2112 begin 1762 2113 if (x2 < x) then … … 1778 2129 end; 1779 2130 1780 procedure TBGRADefaultBitmap.SetHorizLine(x, y, x2: int eger; c: TBGRAPixel);2131 procedure TBGRADefaultBitmap.SetHorizLine(x, y, x2: int32or64; c: TBGRAPixel); 1781 2132 begin 1782 2133 if not CheckHorizLineBounds(x,y,x2) then exit; … … 1785 2136 end; 1786 2137 1787 procedure TBGRADefaultBitmap.XorHorizLine(x, y, x2: int eger; c: TBGRAPixel);2138 procedure TBGRADefaultBitmap.XorHorizLine(x, y, x2: int32or64; c: TBGRAPixel); 1788 2139 begin 1789 2140 if not CheckHorizLineBounds(x,y,x2) then exit; … … 1792 2143 end; 1793 2144 1794 procedure TBGRADefaultBitmap.DrawHorizLine(x, y, x2: int eger; c: TBGRAPixel);2145 procedure TBGRADefaultBitmap.DrawHorizLine(x, y, x2: int32or64; c: TBGRAPixel); 1795 2146 begin 1796 2147 if not CheckHorizLineBounds(x,y,x2) then exit; … … 1799 2150 end; 1800 2151 1801 procedure TBGRADefaultBitmap.DrawHorizLine(x, y, x2: int eger; ec: TExpandedPixel2152 procedure TBGRADefaultBitmap.DrawHorizLine(x, y, x2: int32or64; ec: TExpandedPixel 1802 2153 ); 1803 2154 begin … … 1807 2158 end; 1808 2159 1809 procedure TBGRADefaultBitmap. DrawHorizLine(x, y, x2: integer;1810 texture: IBGRAScanner );2160 procedure TBGRADefaultBitmap.HorizLine(x, y, x2: int32or64; 2161 texture: IBGRAScanner; ADrawMode : TDrawMode); 1811 2162 begin 1812 2163 if not CheckHorizLineBounds(x,y,x2) then exit; 1813 2164 texture.ScanMoveTo(x,y); 1814 ScannerPutPixels(texture,scanline[y] + x, x2 - x + 1, dmDrawWithTransparency);2165 ScannerPutPixels(texture,scanline[y] + x, x2 - x + 1,ADrawMode); 1815 2166 InvalidateBitmap; 1816 2167 end; 1817 2168 1818 procedure TBGRADefaultBitmap.FastBlendHorizLine(x, y, x2: int eger; c: TBGRAPixel);2169 procedure TBGRADefaultBitmap.FastBlendHorizLine(x, y, x2: int32or64; c: TBGRAPixel); 1819 2170 begin 1820 2171 if not CheckHorizLineBounds(x,y,x2) then exit; … … 1823 2174 end; 1824 2175 1825 procedure TBGRADefaultBitmap.AlphaHorizLine(x, y, x2: int eger; alpha: byte);2176 procedure TBGRADefaultBitmap.AlphaHorizLine(x, y, x2: int32or64; alpha: byte); 1826 2177 begin 1827 2178 if alpha = 0 then … … 1835 2186 end; 1836 2187 1837 function TBGRADefaultBitmap.CheckVertLineBounds(var x,y,y2: int eger; out delta: integer): boolean; inline;1838 var 1839 temp: int eger;2188 function TBGRADefaultBitmap.CheckVertLineBounds(var x,y,y2: int32or64; out delta: int32or64): boolean; inline; 2189 var 2190 temp: int32or64; 1840 2191 begin 1841 2192 if FLineOrder = riloBottomToTop then … … 1865 2216 end; 1866 2217 1867 procedure TBGRADefaultBitmap.SetVertLine(x, y, y2: int eger; c: TBGRAPixel);1868 var 1869 n, delta: int eger;2218 procedure TBGRADefaultBitmap.SetVertLine(x, y, y2: int32or64; c: TBGRAPixel); 2219 var 2220 n, delta: int32or64; 1870 2221 p: PBGRAPixel; 1871 2222 begin … … 1880 2231 end; 1881 2232 1882 procedure TBGRADefaultBitmap.XorVertLine(x, y, y2: int eger; c: TBGRAPixel);1883 var 1884 n, delta: int eger;2233 procedure TBGRADefaultBitmap.XorVertLine(x, y, y2: int32or64; c: TBGRAPixel); 2234 var 2235 n, delta: int32or64; 1885 2236 p: PBGRAPixel; 1886 2237 begin … … 1895 2246 end; 1896 2247 1897 procedure TBGRADefaultBitmap.DrawVertLine(x, y, y2: int eger; c: TBGRAPixel);1898 var 1899 n, delta: int eger;2248 procedure TBGRADefaultBitmap.DrawVertLine(x, y, y2: int32or64; c: TBGRAPixel); 2249 var 2250 n, delta: int32or64; 1900 2251 p: PBGRAPixel; 1901 2252 begin … … 1915 2266 end; 1916 2267 1917 procedure TBGRADefaultBitmap.AlphaVertLine(x, y, y2: int eger; alpha: byte);1918 var 1919 n, delta: int eger;2268 procedure TBGRADefaultBitmap.AlphaVertLine(x, y, y2: int32or64; alpha: byte); 2269 var 2270 n, delta: int32or64; 1920 2271 p: PBGRAPixel; 1921 2272 begin … … 1935 2286 end; 1936 2287 1937 procedure TBGRADefaultBitmap.FastBlendVertLine(x, y, y2: int eger; c: TBGRAPixel);1938 var 1939 n, delta: int eger;2288 procedure TBGRADefaultBitmap.FastBlendVertLine(x, y, y2: int32or64; c: TBGRAPixel); 2289 var 2290 n, delta: int32or64; 1940 2291 p: PBGRAPixel; 1941 2292 begin … … 1950 2301 end; 1951 2302 1952 procedure TBGRADefaultBitmap.DrawHorizLineDiff(x, y, x2: int eger;2303 procedure TBGRADefaultBitmap.DrawHorizLineDiff(x, y, x2: int32or64; 1953 2304 c, compare: TBGRAPixel; maxDiff: byte); 1954 2305 begin … … 1958 2309 end; 1959 2310 2311 procedure TBGRADefaultBitmap.SetArrowStart(AStyle: TBGRAArrowStyle; 2312 ATipStyle: TPenJoinStyle; ARelativePenWidth: single; ATriangleBackOffset: single); 2313 begin 2314 GetArrow.SetStart(AStyle,ATipStyle,ARelativePenWidth,ATriangleBackOffset); 2315 end; 2316 2317 procedure TBGRADefaultBitmap.SetArrowEnd(AStyle: TBGRAArrowStyle; 2318 ATipStyle: TPenJoinStyle; ARelativePenWidth: single; ATriangleBackOffset: single); 2319 begin 2320 GetArrow.SetEnd(AStyle,ATipStyle,ARelativePenWidth,ATriangleBackOffset); 2321 end; 2322 2323 procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; c: TBGRAPixel; w: single); 2324 var tempCanvas: TBGRACanvas2D; 2325 begin 2326 tempCanvas:= TBGRACanvas2D.Create(self); 2327 tempCanvas.strokeStyle(c); 2328 tempCanvas.lineWidth := w; 2329 tempCanvas.lineStyle(CustomPenStyle); 2330 tempCanvas.lineCapLCL := LineCap; 2331 tempCanvas.lineJoinLCL := JoinStyle; 2332 tempCanvas.path(APath); 2333 tempCanvas.stroke; 2334 tempCanvas.Free; 2335 end; 2336 2337 procedure TBGRADefaultBitmap.DrawPath(APath: IBGRAPath; texture: IBGRAScanner; w: single); 2338 var tempCanvas: TBGRACanvas2D; 2339 begin 2340 tempCanvas:= TBGRACanvas2D.Create(self); 2341 tempCanvas.strokeStyle(texture); 2342 tempCanvas.lineWidth := w; 2343 tempCanvas.lineStyle(CustomPenStyle); 2344 tempCanvas.lineCapLCL := LineCap; 2345 tempCanvas.lineJoinLCL := JoinStyle; 2346 tempCanvas.path(APath); 2347 tempCanvas.stroke; 2348 tempCanvas.Free; 2349 end; 2350 1960 2351 {---------------------------- Lines ---------------------------------} 1961 2352 { Call appropriate functions } 1962 2353 1963 2354 procedure TBGRADefaultBitmap.DrawLine(x1, y1, x2, y2: integer; 1964 c: TBGRAPixel; DrawLastPixel: boolean );1965 begin 1966 BGRADrawLineAliased(self,x1,y1,x2,y2,c,DrawLastPixel );2355 c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode); 2356 begin 2357 BGRADrawLineAliased(self,x1,y1,x2,y2,c,DrawLastPixel,ADrawMode); 1967 2358 end; 1968 2359 … … 1970 2361 c: TBGRAPixel; DrawLastPixel: boolean); 1971 2362 begin 1972 BGRADrawLineAntialias(self,x1,y1,x2,y2,c,DrawLastPixel );2363 BGRADrawLineAntialias(self,x1,y1,x2,y2,c,DrawLastPixel,LinearAntialiasing); 1973 2364 end; 1974 2365 … … 1978 2369 begin 1979 2370 DashPos := 0; 1980 BGRADrawLineAntialias(self,x1,y1,x2,y2,c1,c2,dashLen,DrawLastPixel,DashPos );2371 BGRADrawLineAntialias(self,x1,y1,x2,y2,c1,c2,dashLen,DrawLastPixel,DashPos,LinearAntialiasing); 1981 2372 end; 1982 2373 … … 1984 2375 c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer); 1985 2376 begin 1986 BGRADrawLineAntialias(self,x1,y1,x2,y2,c1,c2,dashLen,DrawLastPixel,DashPos );2377 BGRADrawLineAntialias(self,x1,y1,x2,y2,c1,c2,dashLen,DrawLastPixel,DashPos,LinearAntialiasing); 1987 2378 end; 1988 2379 … … 1990 2381 c: TBGRAPixel; w: single); 1991 2382 begin 1992 BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,LineCap,JoinStyle,FCustomPenStyle,[],nil,JoinMiterLimit); 2383 if Assigned(FArrow) then 2384 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2385 else 2386 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit); 1993 2387 end; 1994 2388 … … 1996 2390 texture: IBGRAScanner; w: single); 1997 2391 begin 1998 BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,[],texture,JoinMiterLimit); 2392 if Assigned(FArrow) then 2393 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2394 else 2395 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit); 1999 2396 end; 2000 2397 2001 2398 procedure TBGRADefaultBitmap.DrawLineAntialias(x1, y1, x2, y2: single; 2002 c: TBGRAPixel; w: single; closed: boolean);2399 c: TBGRAPixel; w: single; Closed: boolean); 2003 2400 var 2004 2401 options: TBGRAPolyLineOptions; 2005 2402 begin 2006 2403 if not closed then options := [plRoundCapOpen] else options := []; 2007 BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,nil,JoinMiterLimit); 2404 options += GetPolyLineOption; 2405 if Assigned(FArrow) then 2406 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2407 else 2408 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,nil,JoinMiterLimit) 2008 2409 end; 2009 2410 … … 2023 2424 c := BGRAPixelTransparent; 2024 2425 end; 2025 BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,texture,JoinMiterLimit); 2426 options += GetPolyLineOption; 2427 if Assigned(FArrow) then 2428 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2429 else 2430 BGRAPen.BGRAPolyLine(self,[PointF(x1,y1),PointF(x2,y2)],w,c,pecRound,pjsRound,FCustomPenStyle,options,texture,JoinMiterLimit); 2026 2431 end; 2027 2432 … … 2029 2434 c: TBGRAPixel; w: single); 2030 2435 begin 2031 BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,[],nil,JoinMiterLimit); 2436 if Assigned(FArrow) then 2437 BGRAPen.BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2438 else 2439 BGRAPen.BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,nil,JoinMiterLimit) 2032 2440 end; 2033 2441 … … 2035 2443 const points: array of TPointF; texture: IBGRAScanner; w: single); 2036 2444 begin 2037 BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,[],texture,JoinMiterLimit); 2445 if Assigned(FArrow) then 2446 BGRAPen.BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2447 else 2448 BGRAPen.BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,texture,JoinMiterLimit); 2038 2449 end; 2039 2450 … … 2044 2455 begin 2045 2456 if not closed then options := [plRoundCapOpen] else options := []; 2046 BGRAPolyLine(self,points,w,c,pecRound,JoinStyle,FCustomPenStyle,options,nil,JoinMiterLimit); 2457 options += GetPolyLineOption; 2458 if Assigned(FArrow) then 2459 BGRAPen.BGRAPolyLine(self,points,w,c,pecRound,JoinStyle,FCustomPenStyle,options,nil,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 2460 else 2461 BGRAPen.BGRAPolyLine(self,points,w,c,pecRound,JoinStyle,FCustomPenStyle,options,nil,JoinMiterLimit); 2462 end; 2463 2464 procedure TBGRADefaultBitmap.DrawPolyLineAntialias( 2465 const points: array of TPointF; c: TBGRAPixel; w: single; 2466 fillcolor: TBGRAPixel); 2467 var multi: TBGRAMultishapeFiller; 2468 begin 2469 multi := TBGRAMultishapeFiller.Create; 2470 multi.PolygonOrder := poLastOnTop; 2471 multi.AddPolygon(points,fillcolor); 2472 multi.AddPolygon(ComputeWidePolyline(points,w),c); 2473 if LinearAntialiasing then 2474 multi.Draw(self,dmLinearBlend) 2475 else 2476 multi.Draw(self,dmDrawWithTransparency); 2477 multi.Free; 2047 2478 end; 2048 2479 … … 2050 2481 c: TBGRAPixel; w: single); 2051 2482 begin 2052 2483 BGRAPolyLine(self,points,w,c,LineCap,JoinStyle,FCustomPenStyle,[plCycle],nil,JoinMiterLimit); 2053 2484 end; 2054 2485 … … 2057 2488 begin 2058 2489 BGRAPolyLine(self,points,w,BGRAPixelTransparent,LineCap,JoinStyle,FCustomPenStyle,[plCycle],texture,JoinMiterLimit); 2490 end; 2491 2492 procedure TBGRADefaultBitmap.DrawPolygonAntialias( 2493 const points: array of TPointF; c: TBGRAPixel; w: single; 2494 fillcolor: TBGRAPixel); 2495 var multi: TBGRAMultishapeFiller; 2496 begin 2497 multi := TBGRAMultishapeFiller.Create; 2498 multi.PolygonOrder := poLastOnTop; 2499 multi.AddPolygon(points,fillcolor); 2500 multi.AddPolygon(ComputeWidePolygon(points,w),c); 2501 if LinearAntialiasing then 2502 multi.Draw(self,dmLinearBlend) 2503 else 2504 multi.Draw(self,dmDrawWithTransparency); 2505 multi.Free; 2059 2506 end; 2060 2507 … … 2085 2532 DrawPolyLineAntialias(points, BGRA(0,0,0,alpha),w); 2086 2533 FEraseMode := False; 2534 end; 2535 2536 procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; c: TBGRAPixel); 2537 var tempCanvas: TBGRACanvas2D; 2538 begin 2539 tempCanvas:= TBGRACanvas2D.Create(self); 2540 tempCanvas.fillStyle(c); 2541 tempCanvas.path(APath); 2542 tempCanvas.fill; 2543 tempCanvas.Free; 2544 end; 2545 2546 procedure TBGRADefaultBitmap.FillPath(APath: IBGRAPath; texture: IBGRAScanner); 2547 var tempCanvas: TBGRACanvas2D; 2548 begin 2549 tempCanvas:= TBGRACanvas2D.Create(self); 2550 tempCanvas.fillStyle(texture); 2551 tempCanvas.path(APath); 2552 tempCanvas.fill; 2553 tempCanvas.Free; 2087 2554 end; 2088 2555 … … 2215 2682 end; 2216 2683 2684 procedure TBGRADefaultBitmap.FillQuadPerspectiveMapping(pt1, pt2, pt3, 2685 pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; 2686 ACleanBorders: TRect); 2687 var 2688 persp: TBGRAPerspectiveScannerTransform; 2689 clean: TBGRAExtendedBorderScanner; 2690 begin 2691 clean := TBGRAExtendedBorderScanner.Create(texture,ACleanBorders); 2692 persp := TBGRAPerspectiveScannerTransform.Create(clean,[tex1,tex2,tex3,tex4],[pt1,pt2,pt3,pt4]); 2693 FillPoly([pt1,pt2,pt3,pt4],persp,dmDrawWithTransparency); 2694 persp.Free; 2695 clean.Free; 2696 end; 2697 2217 2698 procedure TBGRADefaultBitmap.FillQuadPerspectiveMappingAntialias(pt1, pt2, pt3, 2218 2699 pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF); … … 2223 2704 FillPolyAntialias([pt1,pt2,pt3,pt4],persp); 2224 2705 persp.Free; 2706 end; 2707 2708 procedure TBGRADefaultBitmap.FillQuadPerspectiveMappingAntialias(pt1, pt2, pt3, 2709 pt4: TPointF; texture: IBGRAScanner; tex1, tex2, tex3, tex4: TPointF; 2710 ACleanBorders: TRect); 2711 var 2712 persp: TBGRAPerspectiveScannerTransform; 2713 clean: TBGRAExtendedBorderScanner; 2714 begin 2715 clean := TBGRAExtendedBorderScanner.Create(texture,ACleanBorders); 2716 persp := TBGRAPerspectiveScannerTransform.Create(clean,[tex1,tex2,tex3,tex4],[pt1,pt2,pt3,pt4]); 2717 FillPolyAntialias([pt1,pt2,pt3,pt4],persp); 2718 persp.Free; 2719 clean.Free; 2225 2720 end; 2226 2721 … … 2284 2779 procedure TBGRADefaultBitmap.FillPolyAntialias(const points: array of TPointF; c: TBGRAPixel); 2285 2780 begin 2286 BGRAPolygon.FillPolyAntialias(self, points, c, FEraseMode, FillMode = fmWinding );2781 BGRAPolygon.FillPolyAntialias(self, points, c, FEraseMode, FillMode = fmWinding, LinearAntialiasing); 2287 2782 end; 2288 2783 … … 2290 2785 texture: IBGRAScanner); 2291 2786 begin 2292 BGRAPolygon.FillPolyAntialiasWithTexture(self, points, texture, FillMode = fmWinding );2787 BGRAPolygon.FillPolyAntialiasWithTexture(self, points, texture, FillMode = fmWinding, LinearAntialiasing); 2293 2788 end; 2294 2789 … … 2306 2801 end; 2307 2802 2803 procedure TBGRADefaultBitmap.FillShape(shape: TBGRACustomFillInfo; c: TBGRAPixel; 2804 drawmode: TDrawMode); 2805 begin 2806 BGRAPolygon.FillShapeAliased(self, shape, c, FEraseMode, nil, FillMode = fmWinding, drawmode); 2807 end; 2808 2809 procedure TBGRADefaultBitmap.FillShape(shape: TBGRACustomFillInfo; 2810 texture: IBGRAScanner; drawmode: TDrawMode); 2811 begin 2812 BGRAPolygon.FillShapeAliased(self, shape, BGRAPixelTransparent, false, texture, FillMode = fmWinding, drawmode); 2813 end; 2814 2815 procedure TBGRADefaultBitmap.FillShapeAntialias(shape: TBGRACustomFillInfo; 2816 c: TBGRAPixel); 2817 begin 2818 BGRAPolygon.FillShapeAntialias(self, shape, c, FEraseMode, nil, FillMode = fmWinding, LinearAntialiasing); 2819 end; 2820 2821 procedure TBGRADefaultBitmap.FillShapeAntialias(shape: TBGRACustomFillInfo; 2822 texture: IBGRAScanner); 2823 begin 2824 BGRAPolygon.FillShapeAntialiasWithTexture(self, shape, texture, FillMode = fmWinding, LinearAntialiasing); 2825 end; 2826 2827 procedure TBGRADefaultBitmap.EraseShape(shape: TBGRACustomFillInfo; alpha: byte); 2828 begin 2829 BGRAPolygon.FillShapeAliased(self, shape, BGRA(0, 0, 0, alpha), True, nil, FillMode = fmWinding, dmDrawWithTransparency); 2830 end; 2831 2832 procedure TBGRADefaultBitmap.EraseShapeAntialias(shape: TBGRACustomFillInfo; 2833 alpha: byte); 2834 begin 2835 FEraseMode := True; 2836 FillShapeAntialias(shape, BGRA(0, 0, 0, alpha)); 2837 FEraseMode := False; 2838 end; 2839 2308 2840 procedure TBGRADefaultBitmap.EllipseAntialias(x, y, rx, ry: single; 2309 2841 c: TBGRAPixel; w: single); … … 2311 2843 if IsClearPenStyle(FCustomPenStyle) or (c.alpha = 0) then exit; 2312 2844 if IsSolidPenStyle(FCustomPenStyle) then 2313 BGRAPolygon.BorderEllipseAntialias(self, x, y, rx, ry, w, c, FEraseMode )2845 BGRAPolygon.BorderEllipseAntialias(self, x, y, rx, ry, w, c, FEraseMode, LinearAntialiasing) 2314 2846 else 2315 2847 DrawPolygonAntialias(ComputeEllipseContour(x,y,rx,ry),c,w); … … 2321 2853 if IsClearPenStyle(FCustomPenStyle) then exit; 2322 2854 if IsSolidPenStyle(FCustomPenStyle) then 2323 BGRAPolygon.BorderEllipseAntialiasWithTexture(self, x, y, rx, ry, w, texture )2855 BGRAPolygon.BorderEllipseAntialiasWithTexture(self, x, y, rx, ry, w, texture, LinearAntialiasing) 2324 2856 else 2325 2857 DrawPolygonAntialias(ComputeEllipseContour(x,y,rx,ry),texture,w); … … 2362 2894 procedure TBGRADefaultBitmap.FillEllipseAntialias(x, y, rx, ry: single; c: TBGRAPixel); 2363 2895 begin 2364 BGRAPolygon.FillEllipseAntialias(self, x, y, rx, ry, c, FEraseMode );2896 BGRAPolygon.FillEllipseAntialias(self, x, y, rx, ry, c, FEraseMode, LinearAntialiasing); 2365 2897 end; 2366 2898 … … 2368 2900 texture: IBGRAScanner); 2369 2901 begin 2370 BGRAPolygon.FillEllipseAntialiasWithTexture(self, x, y, rx, ry, texture );2902 BGRAPolygon.FillEllipseAntialiasWithTexture(self, x, y, rx, ry, texture, LinearAntialiasing); 2371 2903 end; 2372 2904 … … 2486 3018 if IsClearPenStyle(FCustomPenStyle) or (c.alpha = 0) then exit; 2487 3019 if IsSolidPenStyle(FCustomPenStyle) then 2488 BGRAPolygon.BorderRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,w,options,c,False )3020 BGRAPolygon.BorderRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,w,options,c,False, LinearAntialiasing) 2489 3021 else 2490 3022 DrawPolygonAntialias(BGRAPath.ComputeRoundRect(x,y,x2,y2,rx,ry,options),c,w); … … 2544 3076 if IsClearPenStyle(FCustomPenStyle) then exit; 2545 3077 if IsSolidPenStyle(FCustomPenStyle) then 2546 BGRAPolygon.BorderRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,w,options,texture )3078 BGRAPolygon.BorderRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,w,options,texture, LinearAntialiasing) 2547 3079 else 2548 3080 DrawPolygonAntialias(BGRAPath.ComputeRoundRect(x,y,x2,y2,rx,ry,options),texture,w); … … 2686 3218 end else 2687 3219 begin 2688 if (mode <> dmSet) and ( c.alpha = 0) then exit;3220 if (mode <> dmSet) and (mode <> dmXor) and (c.alpha = 0) then exit; 2689 3221 2690 3222 p := Scanline[y] + x; … … 2714 3246 end; 2715 3247 dmXor: 3248 if DWord(c) = 0 then exit 3249 else 2716 3250 for yb := y2 - y downto 0 do 2717 3251 begin … … 2825 3359 c: TBGRAPixel; options: TRoundRectangleOptions); 2826 3360 begin 2827 BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,c,False );3361 BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,c,False, LinearAntialiasing); 2828 3362 end; 2829 3363 … … 2831 3365 ry: single; texture: IBGRAScanner; options: TRoundRectangleOptions); 2832 3366 begin 2833 BGRAPolygon.FillRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,options,texture );3367 BGRAPolygon.FillRoundRectangleAntialiasWithTexture(self,x,y,x2,y2,rx,ry,options,texture, LinearAntialiasing); 2834 3368 end; 2835 3369 … … 2837 3371 ry: single; alpha: byte; options: TRoundRectangleOptions); 2838 3372 begin 2839 BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,BGRA(0,0,0,alpha),True );3373 BGRAPolygon.FillRoundRectangleAntialias(self,x,y,x2,y2,rx,ry,options,BGRA(0,0,0,alpha),True, LinearAntialiasing); 2840 3374 end; 2841 3375 2842 3376 procedure TBGRADefaultBitmap.RoundRect(X1, Y1, X2, Y2: integer; 2843 DX, DY: integer; BorderColor, FillColor: TBGRAPixel); 2844 begin 2845 BGRARoundRectAliased(self,X1,Y1,X2,Y2,DX,DY,BorderColor,FillColor); 3377 DX, DY: integer; BorderColor, FillColor: TBGRAPixel; ADrawMode: TDrawMode = dmDrawWithTransparency); 3378 begin 3379 BGRARoundRectAliased(self,X1,Y1,X2,Y2,DX,DY,BorderColor,FillColor,nil,ADrawMode); 3380 end; 3381 3382 procedure TBGRADefaultBitmap.RoundRect(X1, Y1, X2, Y2: integer; DX, 3383 DY: integer; BorderColor: TBGRAPixel; ADrawMode: TDrawMode); 3384 begin 3385 BGRARoundRectAliased(self,X1,Y1,X2,Y2,DX,DY,BorderColor,BGRAPixelTransparent,nil,ADrawMode,true); 2846 3386 end; 2847 3387 2848 3388 {------------------------- Text functions ---------------------------------------} 2849 3389 2850 procedure TBGRADefaultBitmap.TextOutAngle(x, y: single; orientation: integer; 2851 s: string; c: TBGRAPixel; align: TAlignment); 2852 begin 2853 UpdateFont; 2854 BGRAText.BGRATextOutAngle(self,FFont,FontQuality,x,y,orientation,s,c,nil,align); 2855 end; 2856 2857 procedure TBGRADefaultBitmap.TextOutAngle(x, y: single; orientation: integer; 2858 s: string; texture: IBGRAScanner; align: TAlignment); 2859 begin 2860 UpdateFont; 2861 BGRAText.BGRATextOutAngle(self,FFont,FontQuality,x,y,orientation,s,BGRAPixelTransparent,texture,align); 2862 end; 2863 2864 procedure TBGRADefaultBitmap.TextOut(x, y: single; s: string; 3390 procedure TBGRADefaultBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; 3391 sUTF8: string; c: TBGRAPixel; align: TAlignment); 3392 begin 3393 FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),c,align); 3394 end; 3395 3396 procedure TBGRADefaultBitmap.TextOutAngle(x, y: single; orientationTenthDegCCW: integer; 3397 sUTF8: string; texture: IBGRAScanner; align: TAlignment); 3398 begin 3399 FontRenderer.TextOutAngle(self,x,y,orientationTenthDegCCW,CleanTextOutString(sUTF8),texture,align); 3400 end; 3401 3402 procedure TBGRADefaultBitmap.TextOut(x, y: single; sUTF8: string; 2865 3403 texture: IBGRAScanner; align: TAlignment); 2866 3404 begin 2867 UpdateFont; 2868 2869 if (FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) and (FFont.Orientation mod 3600 = 0) then 2870 BGRATextFX.BGRATextOutImproveReadability(self,FFont,x,y,s,BGRAPixelTransparent,texture,align, 2871 FontQuality in[fqFineClearTypeRGB,fqFineClearTypeBGR], FontQuality = fqFineClearTypeRGB) else 2872 2873 BGRAText.BGRATextOut(self,FFont,FontQuality,x,y,s,BGRAPixelTransparent,texture,align); 2874 end; 2875 2876 procedure TBGRADefaultBitmap.TextOut(x, y: single; s: string; 3405 FontRenderer.TextOut(self,x,y,CleanTextOutString(sUTF8),texture,align); 3406 end; 3407 3408 procedure TBGRADefaultBitmap.TextOut(x, y: single; sUTF8: string; 2877 3409 c: TBGRAPixel; align: TAlignment); 2878 3410 begin 2879 UpdateFont; 2880 2881 if (FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) and (FFont.Orientation mod 3600 = 0) then 2882 BGRATextFX.BGRATextOutImproveReadability(self,FFont,x,y,s,c,nil,align, 2883 FontQuality in[fqFineClearTypeRGB,fqFineClearTypeBGR], FontQuality = fqFineClearTypeRGB) else 2884 2885 BGRAText.BGRATextOut(self,FFont,FontQuality,x,y,s,c,nil,align); 3411 FontRenderer.TextOut(self,x,y,CleanTextOutString(sUTF8),c,align); 2886 3412 end; 2887 3413 2888 3414 procedure TBGRADefaultBitmap.TextRect(ARect: TRect; x, y: integer; 2889 s: string; style: TTextStyle; c: TBGRAPixel); 2890 begin 2891 UpdateFont; 2892 BGRAText.BGRATextRect(self,FFont,FontQuality,ARect,x,y,s,style,c,nil); 2893 end; 2894 2895 procedure TBGRADefaultBitmap.TextRect(ARect: TRect; x, y: integer; s: string; 3415 sUTF8: string; style: TTextStyle; c: TBGRAPixel); 3416 begin 3417 FontRenderer.TextRect(self,ARect,x,y,sUTF8,style,c); 3418 end; 3419 3420 procedure TBGRADefaultBitmap.TextRect(ARect: TRect; x, y: integer; sUTF8: string; 2896 3421 style: TTextStyle; texture: IBGRAScanner); 2897 3422 begin 2898 UpdateFont; 2899 BGRAText.BGRATextRect(self,FFont,FontQuality,ARect,x,y,s,style,BGRAPixelTransparent,texture); 2900 end; 2901 2902 function TBGRADefaultBitmap.TextSize(s: string): TSize; 2903 begin 2904 UpdateFont; 2905 result := BGRAText.BGRATextSize(FFont,FontQuality,s,FontAntialiasingLevel); 2906 if (result.cy >= 24) and FontAntialias then 2907 result := BGRAText.BGRATextSize(FFont,FontQuality,s,4); 3423 FontRenderer.TextRect(self,ARect,x,y,sUTF8,style,texture); 3424 end; 3425 3426 { Returns the total size of the string provided using the current font. 3427 Orientation is not taken into account, so that the width is along the text. } 3428 function TBGRADefaultBitmap.TextSize(sUTF8: string): TSize; 3429 begin 3430 result := FontRenderer.TextSize(sUTF8); 2908 3431 end; 2909 3432 … … 2947 3470 w: single): ArrayOfTPointF; 2948 3471 begin 2949 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,[],JoinMiterLimit); 3472 if Assigned(FArrow) then 3473 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 3474 else 3475 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption,JoinMiterLimit) 2950 3476 end; 2951 3477 … … 2956 3482 begin 2957 3483 if not closed then options := [plRoundCapOpen] else options := []; 2958 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,pecRound,pjsRound,FCustomPenStyle,options,JoinMiterLimit); 3484 options += GetPolyLineOption; 3485 if Assigned(FArrow) then 3486 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,pecRound,pjsRound,FCustomPenStyle,options,JoinMiterLimit,@FArrow.ComputeStartAt,FArrow.StartOffsetX,@FArrow.ComputeEndAt,FArrow.EndOffsetX) 3487 else 3488 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,pecRound,pjsRound,FCustomPenStyle,options,JoinMiterLimit); 2959 3489 end; 2960 3490 … … 2962 3492 w: single): ArrayOfTPointF; 2963 3493 begin 2964 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle, [plCycle],JoinMiterLimit);3494 Result:= BGRAPen.ComputeWidePolylinePoints(points,w,BGRAWhite,LineCap,JoinStyle,FCustomPenStyle,GetPolyLineOption+[plCycle],JoinMiterLimit); 2965 3495 end; 2966 3496 … … 2984 3514 endRad: single; quality: single): ArrayOfTPointF; 2985 3515 begin 2986 result := BGRAPath.ComputeArc 65536(x,y,rx,ry,round(startRad*32768/Pi),round(endRad*32768/Pi),quality);3516 result := BGRAPath.ComputeArcRad(x,y,rx,ry,startRad,endRad,quality); 2987 3517 end; 2988 3518 … … 3057 3587 3058 3588 procedure TBGRADefaultBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 3059 color: TBGRAPixel );3589 color: TBGRAPixel; ADrawMode: TDrawMode); 3060 3590 var 3061 3591 scan: TBGRACustomScanner; … … 3063 3593 if (AMask = nil) or (color.alpha = 0) then exit; 3064 3594 scan := TBGRASolidColorMaskScanner.Create(AMask,Point(-X,-Y),color); 3065 self.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan, dmDrawWithTransparency);3595 self.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan,ADrawMode); 3066 3596 scan.Free; 3067 3597 end; 3068 3598 3069 3599 procedure TBGRADefaultBitmap.FillMask(x, y: integer; AMask: TBGRACustomBitmap; 3070 texture: IBGRAScanner );3600 texture: IBGRAScanner; ADrawMode: TDrawMode); 3071 3601 var 3072 3602 scan: TBGRACustomScanner; … … 3074 3604 if AMask = nil then exit; 3075 3605 scan := TBGRATextureMaskScanner.Create(AMask,Point(-X,-Y),texture); 3076 self.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan, dmDrawWithTransparency);3606 self.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan,ADrawMode); 3077 3607 scan.Free; 3078 3608 end; … … 3351 3881 function TBGRADefaultBitmap.ScanAt(X, Y: Single): TBGRAPixel; 3352 3882 var 3353 ix, iy: integer;3354 iFactX,iFactY: integer;3883 ix, iy: Int32or64; 3884 iFactX,iFactY: Int32or64; 3355 3885 begin 3356 3886 if FData = nil then … … 3359 3889 exit; 3360 3890 end; 3361 iFactX := round(x*256);3362 i FactY := round(y*256);3363 i x := (iFactX shr 8)+ScanOffset.X;3364 i y := (iFactY shr 8)+ScanOffset.Y;3365 iFact X := iFactXand 255;3366 i FactY := iFactY and 255;3367 3891 LoadFromBitmapIfNeeded; 3892 ix := round(x*256); 3893 iy := round(y*256); 3894 iFactX := ix and 255; 3895 iFactY := iy and 255; 3896 ix := PositiveMod(ix+(ScanOffset.X shl 8), FWidth shl 8) shr 8; 3897 iy := PositiveMod(iy+(ScanOffset.Y shl 8), FHeight shl 8) shr 8; 3368 3898 if (iFactX = 0) and (iFactY = 0) then 3369 3899 begin 3370 result := (GetScanlineFast( PositiveMod(iy, FHeight))+PositiveMod(ix, FWidth))^;3900 result := (GetScanlineFast(iy)+ix)^; 3371 3901 exit; 3372 3902 end; 3373 3374 3903 if ScanInterpolationFilter <> rfLinear then 3375 3904 begin … … 3377 3906 iFactY := FineInterpolation256( iFactY, ScanInterpolationFilter ); 3378 3907 end; 3379 3380 result := GetPixelCycleInline(ix,iy, iFactX,iFactY); 3908 result := InternalGetPixelCycle256(ix,iy, iFactX,iFactY); 3381 3909 end; 3382 3910 … … 3497 4025 end; 3498 4026 3499 function TBGRADefaultBitmap.CheckPutImageBounds(x,y,tx,ty: integer; out minxb,minyb,maxxb,maxyb,ignoreleft: integer): boolean inline;3500 var x2,y2: integer;3501 begin3502 if (x >= FClipRect.Right) or (y >= FClipRect.Bottom) or (x <= FClipRect.Left-tx) or3503 (y <= FClipRect.Top-ty) or (Height = 0) or (ty = 0) or (tx = 0) then3504 begin3505 result := false;3506 exit;3507 end;3508 3509 x2 := x + tx - 1;3510 y2 := y + ty - 1;3511 3512 if y < FClipRect.Top then3513 minyb := FClipRect.Top3514 else3515 minyb := y;3516 if y2 >= FClipRect.Bottom then3517 maxyb := FClipRect.Bottom - 13518 else3519 maxyb := y2;3520 3521 if x < FClipRect.Left then3522 begin3523 ignoreleft := FClipRect.Left-x;3524 minxb := FClipRect.Left;3525 end3526 else3527 begin3528 ignoreleft := 0;3529 minxb := x;3530 end;3531 if x2 >= FClipRect.Right then3532 maxxb := FClipRect.Right - 13533 else3534 maxxb := x2;3535 3536 result := true;3537 end;3538 3539 4027 function TBGRADefaultBitmap.CheckAntialiasRectBounds(var x, y, x2, y2: single; 3540 4028 w: single): boolean; … … 3584 4072 sourcewidth := Source.Width; 3585 4073 3586 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft ) then exit;4074 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft,FClipRect) then exit; 3587 4075 3588 4076 copycount := maxxb - minxb + 1; … … 3749 4237 sourcewidth := Source.Width; 3750 4238 3751 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft ) then exit;4239 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft,FClipRect) then exit; 3752 4240 3753 4241 copycount := maxxb - minxb + 1; … … 3783 4271 sourcewidth := Source.Width; 3784 4272 3785 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft ) then exit;4273 if not CheckPutImageBounds(x,y,sourcewidth,source.height,minxb,minyb,maxxb,maxyb,ignoreleft,FClipRect) then exit; 3786 4274 3787 4275 copycount := maxxb - minxb + 1; … … 3808 4296 end; 3809 4297 3810 { Draw an image wih an angle. Use an affine transformation to do this. }3811 procedure TBGRADefaultBitmap.PutImageAngle(x, y: single;3812 Source: TBGRACustomBitmap; angle: single; imageCenterX: single;3813 imageCenterY: single; AOpacity: Byte; ARestoreOffsetAfterRotation: boolean);3814 var3815 cosa,sina: single;3816 3817 { Compute rotated coordinates }3818 function Coord(relX,relY: single): TPointF;3819 begin3820 relX -= imageCenterX;3821 relY -= imageCenterY;3822 result.x := relX*cosa-relY*sina+x;3823 result.y := relY*cosa+relX*sina+y;3824 if ARestoreOffsetAfterRotation then3825 begin3826 result.x += imageCenterX;3827 result.y += imageCenterY;3828 end;3829 end;3830 3831 begin3832 cosa := cos(-angle*Pi/180);3833 sina := -sin(-angle*Pi/180);3834 PutImageAffine(Coord(0,0),Coord(source.Width,0),Coord(0,source.Height),source,AOpacity);3835 end;3836 3837 4298 { Draw an image with an affine transformation (rotation, scale, translate). 3838 Parameters are the bitmap origin, the end of the horizontal axis and the end of the vertical axis. } 3839 procedure TBGRADefaultBitmap.PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOpacity: Byte); 4299 Parameters are the bitmap origin, the end of the horizontal axis and the end of the vertical axis. 4300 The output bounds correspond to the pixels that will be affected in the destination. } 4301 procedure TBGRADefaultBitmap.PutImageAffine(Origin, HAxis, VAxis: TPointF; 4302 Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte); 3840 4303 var affine: TBGRAAffineBitmapTransform; 3841 minx,miny,maxx,maxy: integer; 3842 pt4: TPointF; 3843 3844 //include specified point in the bounds 3845 procedure Include(pt: TPointF); 3846 begin 3847 if floor(pt.X) < minx then minx := floor(pt.X); 3848 if floor(pt.Y) < miny then miny := floor(pt.Y); 3849 if ceil(pt.X) > maxx then maxx := ceil(pt.X); 3850 if ceil(pt.Y) > maxy then maxy := ceil(pt.Y); 3851 end; 3852 3853 begin 4304 SourceBounds: TRect; 4305 begin 4306 if (Source = nil) or (AOpacity = 0) then exit; 4307 IntersectRect(AOutputBounds,AOutputBounds,ClipRect); 4308 if IsRectEmpty(AOutputBounds) then exit; 4309 3854 4310 if (abs(Origin.x-round(Origin.x))<1e-6) and (abs(Origin.y-round(Origin.Y))<1e-6) and 3855 4311 (abs(HAxis.x-(Origin.x+Source.Width))<1e-6) and (abs(HAxis.y-origin.y)<1e-6) and 3856 4312 (abs(VAxis.x-Origin.x)<1e-6) and (abs(VAxis.y-(Origin.y+Source.Height))<1e-6) then 3857 4313 begin 3858 PutImage(round(origin.x),round(origin.y),Source,dmDrawWithTransparency,AOpacity); 4314 SourceBounds := AOutputBounds; 4315 OffsetRect(SourceBounds, -round(origin.x),-round(origin.y)); 4316 IntersectRect(SourceBounds,SourceBounds,rect(0,0,Source.Width,Source.Height)); 4317 PutImagePart(round(origin.x)+SourceBounds.Left,round(origin.y)+SourceBounds.Top,Source,SourceBounds,AMode,AOpacity); 3859 4318 exit; 3860 4319 end; 3861 4320 3862 4321 { Create affine transformation } 3863 affine := TBGRAAffineBitmapTransform.Create(Source );4322 affine := TBGRAAffineBitmapTransform.Create(Source, false, AResampleFilter); 3864 4323 affine.GlobalOpacity := AOpacity; 3865 4324 affine.Fit(Origin,HAxis,VAxis); 3866 3867 { Compute bounds } 3868 pt4.x := VAxis.x+HAxis.x-Origin.x; 3869 pt4.y := VAxis.y+HAxis.y-Origin.y; 3870 minx := floor(Origin.X); 3871 miny := floor(Origin.Y); 3872 maxx := ceil(Origin.X); 3873 maxy := ceil(Origin.Y); 3874 Include(HAxis); 3875 Include(VAxis); 3876 Include(pt4); 3877 3878 { Use the affine transformation as a scanner } 3879 FillRect(minx,miny,maxx+1,maxy+1,affine,dmDrawWithTransparency); 4325 FillRect(AOutputBounds,affine,AMode); 3880 4326 affine.Free; 4327 end; 4328 4329 procedure TBGRADefaultBitmap.StretchPutImage(ARect: TRect; 4330 Source: TBGRACustomBitmap; mode: TDrawMode; AOpacity: byte); 4331 begin 4332 If (Source = nil) or (AOpacity = 0) then exit; 4333 if (ARect.Right-ARect.Left = Source.Width) and (ARect.Bottom-ARect.Top = Source.Height) then 4334 PutImage(ARect.Left,ARect.Top,Source,mode,AOpacity) 4335 else 4336 BGRAResample.StretchPutImage(Source, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top, self, ARect.left,ARect.Top, mode, AOpacity); 3881 4337 end; 3882 4338 … … 3991 4447 end; 3992 4448 4449 function TBGRADefaultBitmap.FilterTwirl(ABounds: TRect; ACenter: TPoint; 4450 ARadius: Single; ATurn: Single; AExponent: Single): TBGRACustomBitmap; 4451 begin 4452 result := BGRAFilters.FilterTwirl(self, ABounds, ACenter, ARadius, ATurn, AExponent); 4453 end; 4454 3993 4455 function TBGRADefaultBitmap.FilterCylinder: TBGRACustomBitmap; 3994 4456 begin … … 4001 4463 end; 4002 4464 4003 function TBGRADefaultBitmap.FilterSharpen: TBGRACustomBitmap; 4004 begin 4005 Result := BGRAFilters.FilterSharpen(self); 4465 function TBGRADefaultBitmap.FilterSharpen(Amount: single = 1): TBGRACustomBitmap; 4466 begin 4467 Result := BGRAFilters.FilterSharpen(self,round(Amount*256)); 4468 end; 4469 4470 function TBGRADefaultBitmap.FilterSharpen(ABounds: TRect; Amount: single 4471 ): TBGRACustomBitmap; 4472 begin 4473 Result := BGRAFilters.FilterSharpen(self,ABounds,round(Amount*256)); 4006 4474 end; 4007 4475 … … 4017 4485 end; 4018 4486 4487 function TBGRADefaultBitmap.FilterBlurRadial(ABounds: TRect; radius: integer; 4488 blurType: TRadialBlurType): TBGRACustomBitmap; 4489 var task: TFilterTask; 4490 begin 4491 task := BGRAFilters.CreateRadialBlurTask(self, ABounds, radius, blurType); 4492 try 4493 result := task.Execute; 4494 finally 4495 task.Free; 4496 end; 4497 end; 4498 4019 4499 function TBGRADefaultBitmap.FilterPixelate(pixelSize: integer; 4020 4500 useResample: boolean; filter: TResampleFilter): TBGRACustomBitmap; … … 4029 4509 end; 4030 4510 4511 function TBGRADefaultBitmap.FilterBlurMotion(ABounds: TRect; distance: integer; 4512 angle: single; oriented: boolean): TBGRACustomBitmap; 4513 var task: TFilterTask; 4514 begin 4515 task := BGRAFilters.CreateMotionBlurTask(self,ABounds,distance,angle,oriented); 4516 try 4517 Result := task.Execute; 4518 finally 4519 task.Free; 4520 end; 4521 end; 4522 4031 4523 function TBGRADefaultBitmap.FilterCustomBlur(mask: TBGRACustomBitmap): 4032 4524 TBGRACustomBitmap; … … 4035 4527 end; 4036 4528 4529 function TBGRADefaultBitmap.FilterCustomBlur(ABounds: TRect; 4530 mask: TBGRACustomBitmap): TBGRACustomBitmap; 4531 var task: TFilterTask; 4532 begin 4533 task := BGRAFilters.CreateBlurTask(self, ABounds, mask); 4534 try 4535 result := task.Execute; 4536 finally 4537 task.Free; 4538 end; 4539 end; 4540 4037 4541 function TBGRADefaultBitmap.FilterEmboss(angle: single): TBGRACustomBitmap; 4038 4542 begin 4039 4543 Result := BGRAFilters.FilterEmboss(self, angle); 4544 end; 4545 4546 function TBGRADefaultBitmap.FilterEmboss(angle: single; ABounds: TRect): TBGRACustomBitmap; 4547 begin 4548 Result := BGRAFilters.FilterEmboss(self, angle, ABounds); 4040 4549 end; 4041 4550 … … 4063 4572 end; 4064 4573 4574 function TBGRADefaultBitmap.FilterGrayscale(ABounds: TRect): TBGRACustomBitmap; 4575 begin 4576 Result := BGRAFilters.FilterGrayscale(self, ABounds); 4577 end; 4578 4065 4579 function TBGRADefaultBitmap.FilterNormalize(eachChannel: boolean = True): 4066 4580 TBGRACustomBitmap; … … 4069 4583 end; 4070 4584 4585 function TBGRADefaultBitmap.FilterNormalize(ABounds: TRect; eachChannel: boolean): TBGRACustomBitmap; 4586 begin 4587 Result := BGRAFilters.FilterNormalize(self, ABounds, eachChannel); 4588 end; 4589 4071 4590 function TBGRADefaultBitmap.FilterRotate(origin: TPointF; 4072 angle: single ): TBGRACustomBitmap;4073 begin 4074 Result := BGRAFilters.FilterRotate(self, origin, angle );4591 angle: single; correctBlur: boolean): TBGRACustomBitmap; 4592 begin 4593 Result := BGRAFilters.FilterRotate(self, origin, angle, correctBlur); 4075 4594 end; 4076 4595 … … 4140 4659 end; 4141 4660 4142 {$hints off}4143 function TBGRADefaultBitmap.LoadAsBmp32(Str: TStream): boolean;4144 var OldPos: int64;4145 fileHeader: TBitmapFileHeader;4146 infoHeader: TBitmapInfoHeader;4147 dataSize: integer;4148 begin4149 OldPos := Str.Position;4150 result := false;4151 try4152 if Str.Read(fileHeader,sizeof(fileHeader)) <> sizeof(fileHeader) then4153 raise exception.Create('Inuable to read file header');4154 if fileHeader.bfType = $4D42 then4155 begin4156 if Str.Read(infoHeader,sizeof(infoHeader)) <> sizeof(infoHeader) then4157 raise exception.Create('Inuable to read info header');4158 4159 if (infoHeader.biPlanes = 1) and (infoHeader.biBitCount = 32) and (infoHeader.biCompression = 0) then4160 begin4161 SetSize(infoHeader.biWidth,infoHeader.biHeight);4162 Str.Position := OldPos+fileHeader.bfOffBits;4163 dataSize := NbPixels*sizeof(TBGRAPixel);4164 if Str.Read(Data^, dataSize) <> dataSize then4165 Begin4166 SetSize(0,0);4167 raise exception.Create('Unable to read data');4168 end;4169 result := true;4170 end;4171 end;4172 4173 except4174 on ex:exception do4175 begin4176 4177 end;4178 end;4179 Str.Position := OldPos;4180 4181 end;4182 {$hints on}4183 4184 4661 procedure TBGRADefaultBitmap.SetCanvasOpacity(AValue: byte); 4185 4662 begin … … 4225 4702 4226 4703 It is an involution, i.e it does nothing when applied twice } 4227 procedure TBGRADefaultBitmap.VerticalFlip ;4228 var 4229 yb : integer;4704 procedure TBGRADefaultBitmap.VerticalFlip(ARect: TRect); 4705 var 4706 yb,h2: integer; 4230 4707 line: PBGRAPixel; 4231 linesize : integer;4708 linesize, delta: integer; 4232 4709 PStart: PBGRAPixel; 4233 4710 PEnd: PBGRAPixel; … … 4236 4713 exit; 4237 4714 4715 if (ARect.Right <= ARect.Left) or (ARect.Bottom <= ARect.Top) then exit; 4716 if not IntersectRect(ARect, ARect, rect(0,0,Width,Height)) then exit; 4238 4717 LoadFromBitmapIfNeeded; 4239 linesize := Width* sizeof(TBGRAPixel);4718 linesize := (ARect.Right-ARect.Left) * sizeof(TBGRAPixel); 4240 4719 line := nil; 4241 4720 getmem(line, linesize); 4242 PStart := Data; 4243 PEnd := Data + (Height - 1) * Width; 4244 for yb := 0 to (Height div 2) - 1 do 4721 PStart := GetScanlineFast(ARect.Top)+ARect.Left; 4722 PEnd := GetScanlineFast(ARect.Bottom-1)+ARect.Left; 4723 h2 := (ARect.Bottom-ARect.Top) div 2; 4724 if LineOrder = riloTopToBottom then delta := +Width else delta := -Width; 4725 for yb := h2-1 downto 0 do 4245 4726 begin 4246 4727 move(PStart^, line^, linesize); 4247 4728 move(PEnd^, PStart^, linesize); 4248 4729 move(line^, PEnd^, linesize); 4249 Inc(PStart, Width);4250 Dec(PEnd, Width);4730 Inc(PStart, delta); 4731 Dec(PEnd, delta); 4251 4732 end; 4252 4733 freemem(line); … … 4257 4738 4258 4739 It is an involution, i.e it does nothing when applied twice} 4259 procedure TBGRADefaultBitmap.HorizontalFlip ;4260 var 4261 yb, xb : integer;4740 procedure TBGRADefaultBitmap.HorizontalFlip(ARect: TRect); 4741 var 4742 yb, xb, w: integer; 4262 4743 PStart: PBGRAPixel; 4263 4744 PEnd: PBGRAPixel; … … 4267 4748 exit; 4268 4749 4750 if (ARect.Right <= ARect.Left) or (ARect.Bottom <= ARect.Top) then exit; 4751 if not IntersectRect(ARect, ARect, rect(0,0,Width,Height)) then exit; 4752 w := ARect.Right-ARect.Left; 4269 4753 LoadFromBitmapIfNeeded; 4270 for yb := 0 to Height -1 do4271 begin 4272 PStart := Scanline[yb];4273 PEnd := PStart + Width;4274 for xb := 0 to ( Widthdiv 2) - 1 do4754 for yb := ARect.Top to ARect.Bottom-1 do 4755 begin 4756 PStart := GetScanlineFast(yb)+ARect.Left; 4757 PEnd := PStart + w; 4758 for xb := 0 to (w div 2) - 1 do 4275 4759 begin 4276 4760 Dec(PEnd); … … 4339 4823 complentary colors (black becomes white etc.). 4340 4824 4341 It is an involution, i.e it does nothing when applied twice}4825 It is NOT EXACTLY an involution, when applied twice, some color information is lost } 4342 4826 procedure TBGRADefaultBitmap.Negative; 4343 4827 var … … 4360 4844 end; 4361 4845 4846 procedure TBGRADefaultBitmap.NegativeRect(ABounds: TRect); 4847 var p: PBGRAPixel; 4848 xb,yb,xcount: integer; 4849 begin 4850 if not IntersectRect(ABounds,ABounds,ClipRect) then exit; 4851 xcount := ABounds.Right-ABounds.Left; 4852 for yb := ABounds.Top to ABounds.Bottom-1 do 4853 begin 4854 p := ScanLine[yb]+ABounds.Left; 4855 for xb := xcount-1 downto 0 do 4856 begin 4857 if p^.alpha <> 0 then 4858 begin 4859 p^.red := GammaCompressionTab[not GammaExpansionTab[p^.red]]; 4860 p^.green := GammaCompressionTab[not GammaExpansionTab[p^.green]]; 4861 p^.blue := GammaCompressionTab[not GammaExpansionTab[p^.blue]]; 4862 end; 4863 Inc(p); 4864 end; 4865 end; 4866 end; 4867 4362 4868 { Compute negative without gamma correction. 4363 4869 … … 4381 4887 end; 4382 4888 InvalidateBitmap; 4889 end; 4890 4891 procedure TBGRADefaultBitmap.LinearNegativeRect(ABounds: TRect); 4892 var p: PBGRAPixel; 4893 xb,yb,xcount: integer; 4894 begin 4895 if not IntersectRect(ABounds,ABounds,ClipRect) then exit; 4896 xcount := ABounds.Right-ABounds.Left; 4897 for yb := ABounds.Top to ABounds.Bottom-1 do 4898 begin 4899 p := ScanLine[yb]+ABounds.Left; 4900 for xb := xcount-1 downto 0 do 4901 begin 4902 if p^.alpha <> 0 then 4903 begin 4904 p^.red := not p^.red; 4905 p^.green := not p^.green; 4906 p^.blue := not p^.blue; 4907 end; 4908 Inc(p); 4909 end; 4910 end; 4911 end; 4912 4913 procedure TBGRADefaultBitmap.InplaceGrayscale; 4914 begin 4915 InplaceGrayscale(rect(0,0,Width,Height)); 4916 end; 4917 4918 procedure TBGRADefaultBitmap.InplaceGrayscale(ABounds: TRect); 4919 var 4920 task: TFilterTask; 4921 begin 4922 task := CreateGrayscaleTask(self, ABounds); 4923 task.Destination := self; 4924 task.Execute; 4925 task.Free; 4383 4926 end; 4384 4927 … … 4452 4995 4453 4996 See : http://wiki.lazarus.freepascal.org/BGRABitmap_tutorial_5 } 4454 procedure TBGRADefaultBitmap.ApplyMask(mask: TBGRACustomBitmap );4997 procedure TBGRADefaultBitmap.ApplyMask(mask: TBGRACustomBitmap; ARect: TRect; AMaskRectTopLeft: TPoint); 4455 4998 var 4456 4999 p, pmask: PBGRAPixel; 4457 5000 yb, xb: integer; 4458 begin 4459 if (Mask.Width <> Width) or (Mask.Height <> Height) then 4460 exit; 5001 MaskOffsetX,MaskOffsetY,w: integer; 5002 opacity: NativeUint; 5003 begin 5004 if (ARect.Right <= ARect.Left) or (ARect.Bottom <= ARect.Top) then exit; 5005 IntersectRect(ARect, ARect, rect(0,0,Width,Height)); 5006 MaskOffsetX := AMaskRectTopLeft.x - ARect.Left; 5007 MaskOffsetY := AMaskRectTopLeft.y - ARect.Top; 5008 OffsetRect(ARect, MaskOffsetX, MaskOffsetY); 5009 IntersectRect(ARect, ARect, rect(0,0,mask.Width,mask.Height)); 5010 OffsetRect(ARect, -MaskOffsetX, -MaskOffsetY); 4461 5011 4462 5012 LoadFromBitmapIfNeeded; 4463 for yb := 0 to Height - 1 do 4464 begin 4465 p := Scanline[yb]; 4466 pmask := Mask.Scanline[yb]; 4467 for xb := Width - 1 downto 0 do 4468 begin 4469 p^.alpha := ApplyOpacity(p^.alpha, pmask^.red); 5013 w := ARect.Right-ARect.Left-1; 5014 for yb := ARect.Top to ARect.Bottom - 1 do 5015 begin 5016 p := Scanline[yb]+ARect.Left; 5017 pmask := Mask.Scanline[yb+MaskOffsetY]+ARect.Left+MaskOffsetX; 5018 for xb := w downto 0 do 5019 begin 5020 opacity := ApplyOpacity(p^.alpha, pmask^.red); 5021 if opacity = 0 then p^ := BGRAPixelTransparent 5022 else p^.alpha := opacity; 4470 5023 Inc(p); 4471 5024 Inc(pmask); … … 4522 5075 end; 4523 5076 5077 procedure TBGRADefaultBitmap.DrawCheckers(ARect: TRect; AColorEven, 5078 AColorOdd: TBGRAPixel); 5079 const tx = 8; ty = 8; //must be a power of 2 5080 xMask = tx*2-1; 5081 var xcount,patY,w,n,patY1,patY2m1,patX,patX1: NativeInt; 5082 pdest: PBGRAPixel; 5083 delta: PtrInt; 5084 actualRect: TRect; 5085 begin 5086 actualRect := ARect; 5087 IntersectRect(actualRect, ARect, self.ClipRect); 5088 w := actualRect.Right-actualRect.Left; 5089 if (w <= 0) or (actualRect.Bottom <= actualRect.Top) then exit; 5090 delta := self.Width; 5091 if self.LineOrder = riloBottomToTop then delta := -delta; 5092 delta := (delta-w)*SizeOf(TBGRAPixel); 5093 pdest := self.ScanLine[actualRect.Top]+actualRect.left; 5094 patY1 := actualRect.Top - ARect.Top; 5095 patY2m1 := actualRect.Bottom - ARect.Top-1; 5096 patX1 := (actualRect.Left - ARect.Left) and xMask; 5097 for patY := patY1 to patY2m1 do 5098 begin 5099 xcount := w; 5100 if patY and ty = 0 then 5101 patX := patX1 5102 else 5103 patX := (patX1+tx) and xMask; 5104 while xcount > 0 do 5105 begin 5106 if patX and tx = 0 then 5107 begin 5108 n := 8-patX; 5109 if n > xcount then n := xcount; 5110 FillDWord(pdest^,n,DWord(AColorEven)); 5111 dec(xcount,n); 5112 inc(pdest,n); 5113 patX := tx; 5114 end else 5115 begin 5116 n := 16-patX; 5117 if n > xcount then n := xcount; 5118 FillDWord(pdest^,n,DWord(AColorOdd)); 5119 dec(xcount,n); 5120 inc(pdest,n); 5121 patX := 0; 5122 end; 5123 end; 5124 inc(pbyte(pdest),delta); 5125 end; 5126 self.InvalidateBitmap; 5127 end; 5128 4524 5129 { Get bounds of non zero values of specified channel } 4525 5130 function TBGRADefaultBitmap.GetImageBounds(Channel: TChannel = cAlpha; ANothingValue: Byte = 0): TRect; 5131 begin 5132 result := GetImageBounds([Channel], ANothingValue); 5133 end; 5134 5135 function TBGRADefaultBitmap.GetImageBounds(Channels: TChannels; ANothingValue: Byte = 0): TRect; 4526 5136 var 4527 5137 minx, miny, maxx, maxy: integer; 4528 xb, yb: integer;4529 p: pbyte;4530 offset: integer;5138 xb, xb2, yb: integer; 5139 p: PDWord; 5140 colorMask, colorZeros: DWord; 4531 5141 begin 4532 5142 maxx := -1; … … 4534 5144 minx := self.Width; 4535 5145 miny := self.Height; 4536 case Channel of 4537 cBlue: offset := 0; 4538 cGreen: offset := 1; 4539 cRed: offset := 2; 4540 else 4541 offset := 3; 4542 end; 5146 colorMask := 0; 5147 colorZeros := 0; 5148 if cBlue in Channels then 5149 begin 5150 colorMask := colorMask or $ff; 5151 colorZeros:= colorZeros or ANothingValue; 5152 end; 5153 if cGreen in Channels then 5154 begin 5155 colorMask := colorMask or $ff00; 5156 colorZeros:= colorZeros or (ANothingValue shl 8); 5157 end; 5158 if cRed in Channels then 5159 begin 5160 colorMask := colorMask or $ff0000; 5161 colorZeros:= colorZeros or (ANothingValue shl 16); 5162 end; 5163 if cAlpha in Channels then 5164 begin 5165 colorMask := colorMask or $ff000000; 5166 colorZeros:= colorZeros or (ANothingValue shl 24); 5167 end; 5168 colorMask := NtoLE(colorMask); 5169 colorZeros := NtoLE(colorZeros); 4543 5170 for yb := 0 to self.Height - 1 do 4544 5171 begin 4545 p := P Byte(self.ScanLine[yb]) + offset;5172 p := PDWord(self.ScanLine[yb]); 4546 5173 for xb := 0 to self.Width - 1 do 4547 5174 begin 4548 if p^ <> ANothingValuethen5175 if (p^ and colorMask) <> colorZeros then 4549 5176 begin 4550 5177 if xb < minx then … … 4556 5183 if yb > maxy then 4557 5184 maxy := yb; 5185 5186 inc(p, self.width-1-xb); 5187 for xb2 := self.Width-1 downto xb+1 do 5188 begin 5189 if (p^ and colorMask) <> colorZeros then 5190 begin 5191 if xb2 > maxx then 5192 maxx := xb2; 5193 break; 5194 end; 5195 dec(p); 5196 end; 5197 break; 4558 5198 end; 4559 Inc(p , sizeof(TBGRAPixel));5199 Inc(p); 4560 5200 end; 4561 5201 end; … … 4574 5214 Result.bottom := maxy + 1; 4575 5215 end; 4576 end;4577 4578 function TBGRADefaultBitmap.GetImageBounds(Channels: TChannels): TRect;4579 var c: TChannel;4580 begin4581 result := rect(0,0,0,0);4582 for c := low(TChannel) to high(TChannel) do4583 if c in Channels then4584 UnionRect(result,result,GetImageBounds(c));4585 5216 end; 4586 5217 -
GraphicTest/Packages/bgrabitmap/bgradnetdeserial.pas
r452 r472 155 155 procedure LoadFromStream(Stream: TStream); 156 156 procedure LoadFromFile(filename: string); 157 procedure LoadFromFileUTF8(filenameUTF8: string); 157 158 function ToString: string; override; 158 159 constructor Create; … … 182 183 183 184 implementation 185 186 uses lazutf8classes; 184 187 185 188 const … … 859 862 begin 860 863 stream := TFileStream.Create(filename, fmOpenRead); 864 try 865 LoadFromStream(stream); 866 finally 867 stream.Free; 868 end; 869 end; 870 871 procedure TDotNetDeserialization.LoadFromFileUTF8(filenameUTF8: string); 872 var 873 stream: TFileStreamUTF8; 874 begin 875 stream := TFileStreamUTF8.Create(filenameUTF8, fmOpenRead); 861 876 try 862 877 LoadFromStream(stream); -
GraphicTest/Packages/bgrabitmap/bgrafillinfo.pas
r452 r472 17 17 18 18 type 19 20 { TIntersectionInfo }21 22 TIntersectionInfo = class23 interX: single;24 winding: integer;25 numSegment: integer;26 procedure SetValues(AInterX: Single; AWinding, ANumSegment: integer);27 end;28 ArrayOfTIntersectionInfo = array of TIntersectionInfo;29 30 19 { TFillShapeInfo } 31 20 32 TFillShapeInfo = class 21 TFillShapeInfo = class(TBGRACustomFillInfo) 33 22 protected 34 23 //compute intersections. the array must be big enough … … 43 32 public 44 33 //returns true if the same segment number can be curved 45 function SegmentsCurved: boolean; virtual;34 function SegmentsCurved: boolean; override; 46 35 47 36 //returns integer bounds 48 function GetBounds: TRect; virtual;37 function GetBounds: TRect; override; 49 38 50 39 //compute min-max to be drawn on destination bitmap according to cliprect. Returns false if 51 40 //there is nothing to draw 52 function ComputeMinMax(out minx,miny,maxx,maxy: integer; bmpDest: TBGRACustomBitmap): boolean; 41 function ComputeMinMax(out minx,miny,maxx,maxy: integer; bmpDest: TBGRACustomBitmap): boolean; override; 53 42 54 43 //check if the point is inside the filling zone 55 function IsPointInside(x,y: single; windingMode: boolean): boolean; 44 function IsPointInside(x,y: single; windingMode: boolean): boolean; override; 56 45 57 46 //create an array that will contain computed intersections. 58 47 //you may augment, in this case, use CreateIntersectionInfo for new items 59 function CreateIntersectionArray: ArrayOfTIntersectionInfo; 60 function CreateIntersectionInfo: TIntersectionInfo; virtual; //creates a single info61 procedure FreeIntersectionArray(var inter: ArrayOfTIntersectionInfo); 48 function CreateIntersectionArray: ArrayOfTIntersectionInfo; override; 49 function CreateIntersectionInfo: TIntersectionInfo; override; //creates a single info 50 procedure FreeIntersectionArray(var inter: ArrayOfTIntersectionInfo); override; 62 51 63 52 //fill a previously created array of intersections with actual intersections at the current y coordinate. 64 53 //nbInter gets the number of computed intersections 65 procedure ComputeAndSort(cury: single; var inter: ArrayOfTIntersectionInfo; out nbInter: integer; windingMode: boolean); 54 procedure ComputeAndSort(cury: single; var inter: ArrayOfTIntersectionInfo; out nbInter: integer; windingMode: boolean); override; 66 55 67 56 end; … … 157 146 end; 158 147 159 { T FillPolyInfo }160 161 T FillPolyInfo = class(TFillShapeInfo)148 { TCustomFillPolyInfo } 149 150 TCustomFillPolyInfo = class(TFillShapeInfo) 162 151 private 163 152 function GetNbPoints: integer; … … 167 156 FEmptyPt: array of boolean; 168 157 FNext, FPrev: array of integer; 169 158 function NbMaxIntersection: integer; override; 159 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; {%H-}dy: single; {%H-}AData: pointer); virtual; 160 public 161 constructor Create(const points: array of TPointF); 162 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; virtual; 163 procedure FreeSegmentData(data: pointer); virtual; 164 function GetBounds: TRect; override; 165 property NbPoints: integer read GetNbPoints; 166 end; 167 168 { TFillPolyInfo } 169 170 TFillPolyInfo = class(TCustomFillPolyInfo) 171 protected 170 172 FSlices: array of TPolySlice; 171 173 FCurSlice: integer; 172 174 FMaxIntersection: integer; 173 175 function NbMaxIntersection: integer; override; 174 176 procedure ComputeIntersection(cury: single; … … 177 179 constructor Create(const points: array of TPointF); 178 180 destructor Destroy; override; 179 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; virtual; 180 procedure FreeSegmentData(data: pointer); virtual; 181 function GetBounds: TRect; override; 182 property NbPoints: integer read GetNbPoints; 181 end; 182 183 POnePassRecord = ^TOnePassRecord; 184 TOnePassRecord = record 185 id: integer; 186 data: pointer; 187 slope: single; 188 winding: integer; 189 includeStartingPoint: boolean; 190 originalY1: single; 191 x1,y1,y2: single; 192 next: POnePassRecord; 193 nextWaiting: POnePassRecord; 194 nextDrawing: POnePassRecord; 195 end; 196 197 { TOnePassFillPolyInfo } 198 199 TOnePassFillPolyInfo = class(TCustomFillPolyInfo) 200 private 201 procedure InsertionSortByY; 202 function PartitionByY(left, right: integer): integer; 203 procedure QuickSortByY(left, right: integer); 204 procedure SortByY; 205 protected 206 FOnePass: array of TOnePassRecord; 207 FSortedByY: array of POnePassRecord; 208 FFirstWaiting, FFirstDrawing: POnePassRecord; 209 FShouldInitializeDrawing: boolean; 210 procedure ComputeIntersection(cury: single; 211 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override; 212 public 213 constructor Create(const points: array of TPointF); 214 function CreateIntersectionArray: ArrayOfTIntersectionInfo; override; 215 destructor Destroy; override; 216 end; 217 218 { TSimpleFillPolyInfo } 219 220 TSimpleFillPolyInfo = class(TCustomFillPolyInfo) 221 protected 222 FSimple: array of record 223 winding: integer; 224 includeStartingPoint: boolean; 225 data: pointer; 226 end; 227 procedure ComputeIntersection(cury: single; var inter: ArrayOfTIntersectionInfo; 228 var nbInter: integer); override; 229 public 230 constructor Create(const points: array of TPointF); 231 destructor Destroy; override; 183 232 end; 184 233 185 234 procedure AddDensity(dest: PDensity; start,count: integer; value : word); inline; 186 function DivByAntialiasPrecision(value: cardinal): cardinal; inline;187 function DivByAntialiasPrecision256(value: cardinal): cardinal; inline;188 function DivByAntialiasPrecision65536(value: cardinal): cardinal; inline;235 function DivByAntialiasPrecision(value: UInt32or64): UInt32or64; inline; 236 function DivByAntialiasPrecision256(value: UInt32or64): UInt32or64; inline; 237 function DivByAntialiasPrecision65536(value: UInt32or64): UInt32or64; inline; 189 238 procedure ComputeAliasedRowBounds(x1,x2: single; minx,maxx: integer; out ix1,ix2: integer); 190 239 … … 215 264 function IsPointInPolygon(const points: ArrayOfTPointF; point: TPointF 216 265 ; windingMode: boolean): boolean; 217 var info: T FillShapeInfo;218 begin 219 info := T FillPolyInfo.Create(points);266 var info: TBGRACustomFillInfo; 267 begin 268 info := TSimpleFillPolyInfo.Create(points); 220 269 result := info.IsPointInside(point.x+0.5,point.y+0.5,windingMode); 221 270 info.free; … … 223 272 224 273 function IsPointInEllipse(x, y, rx, ry: single; point: TPointF): boolean; 225 var info: T FillShapeInfo;274 var info: TBGRACustomFillInfo; 226 275 begin 227 276 info := TFillEllipseInfo.Create(x,y,rx,ry); … … 232 281 function IsPointInRoundRectangle(x1, y1, x2, y2, rx, ry: single; point: TPointF 233 282 ): boolean; 234 var info: T FillShapeInfo;283 var info: TBGRACustomFillInfo; 235 284 begin 236 285 info := TFillRoundRectangleInfo.Create(x1, y1, x2, y2, rx, ry,[]); … … 274 323 end; 275 324 276 function DivByAntialiasPrecision(value: cardinal): cardinal;325 function DivByAntialiasPrecision(value: UInt32or64): UInt32or64; 277 326 begin // 278 327 result := value shr AntialiasPrecisionShift;// div AntialiasPrecision; 279 328 end; 280 329 281 function DivByAntialiasPrecision256(value: cardinal): cardinal;330 function DivByAntialiasPrecision256(value: UInt32or64): UInt32or64; 282 331 begin // 283 332 result := value shr (AntialiasPrecisionShift+8);// div (256*AntialiasPrecision); 284 333 end; 285 334 286 function DivByAntialiasPrecision65536(value: cardinal): cardinal;335 function DivByAntialiasPrecision65536(value: UInt32or64): UInt32or64; 287 336 begin // 288 337 result := value shr (AntialiasPrecisionShift+16);//div (65536*AntialiasPrecision); 289 end;290 291 { TIntersectionInfo }292 293 procedure TIntersectionInfo.SetValues(AInterX: Single; AWinding, ANumSegment: integer);294 begin295 interX := AInterX;296 winding := AWinding;297 numSegment := ANumSegment;298 338 end; 299 339 … … 571 611 end; 572 612 573 { TFillPolyInfo } 574 575 constructor TFillPolyInfo.Create(const points: array of TPointF); 576 function AddSeg(numSlice: integer): integer; 577 begin 578 result := FSlices[numSlice].nbSegments; 579 if length(FSlices[numSlice].segments)=FSlices[numSlice].nbSegments then 580 setlength(FSlices[numSlice].segments,FSlices[numSlice].nbSegments*2+2); 581 inc(FSlices[numSlice].nbSegments); 582 end; 583 613 { TCustomFillPolyInfo } 614 615 constructor TCustomFillPolyInfo.Create(const points: array of TPointF); 584 616 var 585 i, j , k: integer;617 i, j: integer; 586 618 First, cur, nbP: integer; 587 yList: array of single;588 nbYList: integer;589 ya,yb,temp: single;590 sliceStart,sliceEnd,idxSeg: integer;591 idSeg: integer;592 593 619 begin 594 620 setlength(FPoints, length(points)); 595 621 nbP := 0; 622 first := -1; 596 623 for i := 0 to high(points) do 597 if (i=0) or (points[i]<>points[i-1]) then 598 begin 624 if isEmptyPointF(points[i]) then 625 begin 626 if first<>-1 then 627 begin 628 if nbP = first+1 then //is there only one point? 629 begin 630 dec(nbP); 631 first := -1; //remove subpolygon 632 end else 633 if (FPoints[nbP-1] = FPoints[first]) then 634 dec(nbP); //remove just last looping point 635 end; 636 if first<>-1 then 637 begin 638 FPoints[nbP] := points[i]; 639 inc(nbP); 640 first := -1; 641 end; 642 end else 643 if (first=-1) or (points[i]<>points[i-1]) then 644 begin 645 if first = -1 then first := nbP; 599 646 FPoints[nbP] := points[i]; 600 647 inc(nbP); 601 648 end; 602 if (nbP>0) and (FPoints[nbP-1] = FPoints[0]) then dec(NbP);603 649 setlength(FPoints, nbP); 604 650 … … 656 702 else 657 703 FSlopes[i] := EmptySingle; 704 end; 705 706 {$hints off} 707 function TCustomFillPolyInfo.CreateSegmentData(numPt,nextPt: integer; x, y: single 708 ): pointer; 709 begin 710 result := nil; 711 end; 712 {$hints on} 713 714 procedure TCustomFillPolyInfo.FreeSegmentData(data: pointer); 715 begin 716 freemem(data); 717 end; 718 719 function TCustomFillPolyInfo.GetBounds: TRect; 720 var 721 minx, miny, maxx, maxy, i: integer; 722 begin 723 if length(FPoints) = 0 then 724 begin 725 result := rect(0,0,0,0); 726 exit; 727 end; 728 miny := floor(FPoints[0].y); 729 maxy := ceil(FPoints[0].y); 730 minx := floor(FPoints[0].x); 731 maxx := ceil(FPoints[0].x); 732 for i := 1 to high(FPoints) do 733 if not FEmptyPt[i] then 734 begin 735 if floor(FPoints[i].y) < miny then 736 miny := floor(FPoints[i].y) 737 else 738 if ceil(FPoints[i].y) > maxy then 739 maxy := ceil(FPoints[i].y); 740 741 if floor(FPoints[i].x) < minx then 742 minx := floor(FPoints[i].x) 743 else 744 if ceil(FPoints[i].x) > maxx then 745 maxx := ceil(FPoints[i].x); 746 end; 747 Result := rect(minx, miny, maxx + 1, maxy + 1); 748 end; 749 750 function TCustomFillPolyInfo.GetNbPoints: integer; 751 begin 752 result := length(FPoints); 753 end; 754 755 function TCustomFillPolyInfo.NbMaxIntersection: integer; 756 begin 757 Result := length(FPoints); 758 end; 759 760 procedure TCustomFillPolyInfo.SetIntersectionValues(AInter: TIntersectionInfo; 761 AInterX: Single; AWinding, ANumSegment: integer; dy: single; AData: pointer); 762 begin 763 AInter.SetValues( AInterX, AWinding, ANumSegment ); 764 end; 765 766 { TFillPolyInfo } 767 768 function TFillPolyInfo.NbMaxIntersection: integer; 769 begin 770 Result:= FMaxIntersection; 771 end; 772 773 procedure TFillPolyInfo.ComputeIntersection(cury: single; 774 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); 775 var 776 j: integer; 777 begin 778 if length(FSlices)=0 then exit; 779 780 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice); 781 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice); 782 with FSlices[FCurSlice] do 783 if (cury >= y1) and (cury <= y2) then 784 begin 785 for j := 0 to nbSegments-1 do 786 begin 787 SetIntersectionValues(inter[nbinter], (cury - segments[j].y1) * segments[j].slope + segments[j].x1, 788 segments[j].winding, segments[j].id, cury - segments[j].y1, segments[j].data ); 789 Inc(nbinter); 790 end; 791 end; 792 end; 793 794 constructor TFillPolyInfo.Create(const points: array of TPointF); 795 function AddSeg(numSlice: integer): integer; 796 begin 797 result := FSlices[numSlice].nbSegments; 798 if length(FSlices[numSlice].segments)=FSlices[numSlice].nbSegments then 799 setlength(FSlices[numSlice].segments,FSlices[numSlice].nbSegments*2+2); 800 inc(FSlices[numSlice].nbSegments); 801 end; 802 803 var 804 yList: array of single; 805 nbYList: integer; 806 ya,yb,temp: single; 807 sliceStart,sliceEnd,idxSeg: integer; 808 i,j,k,idSeg: integer; 809 810 begin 811 inherited Create(points); 658 812 659 813 //slice … … 716 870 717 871 FCurSlice := 0; 872 FMaxIntersection:= 0; 873 for i := 0 to high(FSlices) do 874 if FSlices[i].nbSegments > FMaxIntersection then 875 FMaxIntersection:= FSlices[i].nbSegments; 718 876 end; 719 877 … … 728 886 end; 729 887 730 {$hints off} 731 function TFillPolyInfo.CreateSegmentData(numPt,nextPt: integer; x, y: single 732 ): pointer; 733 begin 734 result := nil; 735 end; 736 {$hints on} 737 738 procedure TFillPolyInfo.FreeSegmentData(data: pointer); 739 begin 740 freemem(data); 741 end; 742 743 function TFillPolyInfo.GetBounds: TRect; 888 { TOnePassFillPolyInfo } 889 890 function TOnePassFillPolyInfo.PartitionByY(left,right: integer): integer; 891 892 procedure Swap(idx1,idx2: integer); inline; 893 var temp: POnePassRecord; 894 begin 895 temp := FSortedByY[idx1]; 896 FSortedByY[idx1] := FSortedByY[idx2]; 897 FSortedByY[idx2] := temp; 898 end; 899 900 var pivotIndex: integer; 901 pivotValue: single; 902 storeIndex: integer; 903 i: integer; 904 905 begin 906 pivotIndex := left + random(right-left+1); 907 pivotValue := FSortedByY[pivotIndex]^.y1; 908 swap(pivotIndex,right); 909 storeIndex := left; 910 for i := left to right-1 do 911 if FSortedByY[i]^.y1 <= pivotValue then 912 begin 913 swap(i,storeIndex); 914 inc(storeIndex); 915 end; 916 swap(storeIndex,right); 917 result := storeIndex; 918 end; 919 920 procedure TOnePassFillPolyInfo.QuickSortByY(left,right: integer); 921 var pivotNewIndex: integer; 922 begin 923 if right > left+9 then 924 begin 925 pivotNewIndex := PartitionByY(left,right); 926 QuickSortByY(left,pivotNewIndex-1); 927 QuickSortByY(pivotNewIndex+1,right); 928 end; 929 end; 930 931 procedure TOnePassFillPolyInfo.InsertionSortByY; 932 var i,j: integer; 933 tempValue: single; 934 tempPtr: POnePassRecord; 935 begin 936 for i := 1 to high(FSortedByY) do 937 begin 938 tempPtr := FSortedByY[i]; 939 TempValue := tempPtr^.y1; 940 j := i; 941 while (j>0) and (FSortedByY[j-1]^.y1 > TempValue) do 942 begin 943 FSortedByY[j] := FSortedByY[j-1]; 944 dec(j); 945 end; 946 FSortedByY[j] := tempPtr; 947 end; 948 end; 949 950 procedure TOnePassFillPolyInfo.SortByY; 951 var i,nbSorted: integer; 952 begin 953 setlength(FSortedByY, length(FPoints)); 954 nbSorted := 0; 955 for i := 0 to high(FSortedByY) do 956 if not FEmptyPt[i] then 957 begin 958 FSortedByY[nbSorted] := @FOnePass[i]; 959 inc(nbSorted); 960 end; 961 setlength(FSortedByY,nbSorted); 962 if length(FSortedByY) < 10 then InsertionSortByY else 963 begin 964 QuickSortByY(0,high(FSortedByY)); 965 InsertionSortByY; 966 end; 967 end; 968 969 procedure TOnePassFillPolyInfo.ComputeIntersection(cury: single; 970 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); 744 971 var 745 minx, miny, maxx, maxy, i: integer; 746 begin 747 if length(FPoints) = 0 then 748 begin 749 result := rect(0,0,0,0); 750 exit; 751 end; 752 miny := floor(FPoints[0].y); 753 maxy := ceil(FPoints[0].y); 754 minx := floor(FPoints[0].x); 755 maxx := ceil(FPoints[0].x); 756 for i := 1 to high(FPoints) do 757 if not FEmptyPt[i] then 758 begin 759 if floor(FPoints[i].y) < miny then 760 miny := floor(FPoints[i].y) 972 p,pprev,pnext: POnePassRecord; 973 begin 974 FShouldInitializeDrawing := true; 975 976 p := FFirstWaiting; 977 while p <> nil do 978 begin 979 if (cury >= p^.y1) then 980 begin 981 if cury <= p^.y2+1 then 982 begin 983 p^.nextDrawing := FFirstDrawing; 984 FFirstDrawing := p; 985 end; 986 end 987 else break; 988 p := p^.nextWaiting; 989 end; 990 FFirstWaiting:= p; 991 992 p := FFirstDrawing; 993 pprev := nil; 994 while p <> nil do 995 begin 996 pnext := p^.nextDrawing; 997 { if p^.slope = EmptySingle then 998 raise exception.Create('Unexpected');} 999 if ((cury > p^.y1) and (cury <= p^.y2)) or 1000 (p^.includeStartingPoint and (cury = p^.y1)) then 1001 begin 1002 { if nbinter = length(inter) then 1003 raise exception.Create('too much'); } 1004 if inter[nbinter] = nil then inter[nbinter] := CreateIntersectionInfo; 1005 SetIntersectionValues(inter[nbinter], (cury - p^.y1)*p^.slope + p^.x1, p^.winding, p^.id, cury - p^.originalY1, p^.data); 1006 inc(nbinter); 1007 end else 1008 if (cury > p^.y2+1) then 1009 begin 1010 if pprev <> nil then 1011 pprev^.nextDrawing := pnext 761 1012 else 762 if ceil(FPoints[i].y) > maxy then 763 maxy := ceil(FPoints[i].y); 764 765 if floor(FPoints[i].x) < minx then 766 minx := floor(FPoints[i].x) 767 else 768 if ceil(FPoints[i].x) > maxx then 769 maxx := ceil(FPoints[i].x); 770 end; 771 Result := rect(minx, miny, maxx + 1, maxy + 1); 772 end; 773 774 function TFillPolyInfo.GetNbPoints: integer; 775 begin 776 result := length(FPoints); 777 end; 778 779 function TFillPolyInfo.NbMaxIntersection: integer; 780 begin 781 Result := length(FPoints); 782 end; 783 784 procedure TFillPolyInfo.ComputeIntersection(cury: single; 785 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); 786 var 787 j: integer; 788 begin 789 if length(FSlices)=0 then exit; 790 791 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice); 792 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice); 793 with FSlices[FCurSlice] do 794 if (cury >= y1) and (cury <= y2) then 795 begin 796 for j := 0 to nbSegments-1 do 797 begin 798 inter[nbinter].SetValues( (cury - segments[j].y1) * segments[j].slope + segments[j].x1, 799 segments[j].winding, segments[j].id ); 800 Inc(nbinter); 801 end; 802 end; 1013 FFirstDrawing:= pnext; 1014 p := pnext; 1015 continue; 1016 end; 1017 pprev := p; 1018 p := pnext; 1019 end; 1020 end; 1021 1022 constructor TOnePassFillPolyInfo.Create(const points: array of TPointF); 1023 var i,j: integer; 1024 p: POnePassRecord; 1025 temp: single; 1026 begin 1027 inherited create(points); 1028 1029 FShouldInitializeDrawing := true; 1030 setlength(FOnePass, length(FPoints)); 1031 for i := 0 to high(FPoints) do 1032 if not FEmptyPt[i] then 1033 begin 1034 p := @FOnePass[i]; 1035 j := FNext[i]; 1036 p^.next := @FOnePass[FNext[i]]; 1037 p^.id := i; 1038 p^.slope := FSlopes[i]; 1039 if p^.slope <> EmptySingle then 1040 p^.data := CreateSegmentData(i, j, FPoints[i].x, FPoints[i].y); 1041 p^.y1 := FPoints[i].y; 1042 p^.y2 := FPoints[j].y; 1043 p^.originalY1 := p^.y1; 1044 p^.winding:= ComputeWinding(p^.y1,p^.y2); 1045 if p^.y1 < p^.y2 then 1046 p^.x1 := FPoints[i].x 1047 else 1048 if p^.y1 > p^.y2 then 1049 begin 1050 temp := p^.y1; 1051 p^.y1 := p^.y2; 1052 p^.y2 := temp; 1053 p^.x1 := FPoints[j].x; 1054 end; 1055 end; 1056 1057 SortByY; 1058 end; 1059 1060 function TOnePassFillPolyInfo.CreateIntersectionArray: ArrayOfTIntersectionInfo; 1061 var i: integer; 1062 p,pprev: POnePassRecord; 1063 begin 1064 if FShouldInitializeDrawing then 1065 begin 1066 FShouldInitializeDrawing := false; 1067 FFirstWaiting:= nil; 1068 pprev := nil; 1069 for i := 0 to high(FSortedByY) do 1070 begin 1071 p := FSortedByY[i]; 1072 if p^.winding > 0 then 1073 p^.includeStartingPoint := p^.next^.winding <= 0 1074 else if p^.winding < 0 then 1075 p^.includeStartingPoint := p^.next^.winding >= 0; 1076 if p^.slope <> EmptySingle then 1077 begin 1078 if pprev <> nil then 1079 pprev^.nextWaiting:= p 1080 else 1081 FFirstWaiting := p; 1082 pprev := p; 1083 end; 1084 end; 1085 end; 1086 1087 setlength(result, NbMaxIntersection); 1088 end; 1089 1090 destructor TOnePassFillPolyInfo.Destroy; 1091 var i: integer; 1092 begin 1093 for i := 0 to high(FOnePass) do 1094 if FOnePass[i].data<>nil then FreeSegmentData(FOnePass[i].data); 1095 FOnePass := nil; 1096 inherited Destroy; 1097 end; 1098 1099 { TSimpleFillPolyInfo } 1100 1101 procedure TSimpleFillPolyInfo.ComputeIntersection(cury: single; 1102 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); 1103 var i,j: integer; 1104 begin 1105 for i := 0 to high(FPoints) do 1106 if FSlopes[i] <> EmptySingle then 1107 begin 1108 j := FNext[i]; 1109 if ((cury > FPoints[i].y) and (cury <= FPoints[j].y)) or 1110 ((cury < FPoints[i].y) and (cury >= FPoints[j].y)) or 1111 (FSimple[i].includeStartingPoint and (cury = FPoints[i].y)) then 1112 begin 1113 SetIntersectionValues(inter[nbinter], (cury - FPoints[i].y)*FSlopes[i] + FPoints[i].x, FSimple[i].winding, i, cury - FPoints[i].y, FSimple[i].data); 1114 inc(nbinter); 1115 end; 1116 end; 1117 end; 1118 1119 constructor TSimpleFillPolyInfo.Create(const points: array of TPointF); 1120 var i,j: integer; 1121 begin 1122 inherited Create(points); 1123 1124 setlength(FSimple, length(FPoints)); 1125 for i := 0 to high(FPoints) do 1126 begin 1127 j := FNext[i]; 1128 if j <> -1 then 1129 FSimple[i].winding:= ComputeWinding(FPoints[i].y,FPoints[j].y) 1130 else 1131 FSimple[i].winding:= 0; 1132 if FSlopes[i] <> EmptySingle then 1133 FSimple[i].data := CreateSegmentData(i, j, FPoints[i].x, FPoints[i].y); 1134 end; 1135 end; 1136 1137 destructor TSimpleFillPolyInfo.Destroy; 1138 var i: integer; 1139 begin 1140 for i := 0 to high(FSimple) do 1141 if FSimple[i].data <> nil then 1142 FreeSegmentData(FSimple[i].data); 1143 FSimple := nil; 1144 inherited Destroy; 803 1145 end; 804 1146 … … 1100 1442 end; 1101 1443 1444 initialization 1445 1446 Randomize; 1447 1102 1448 end. 1103 1449 -
GraphicTest/Packages/bgrabitmap/bgrafilters.pas
r452 r472 11 11 uses 12 12 Classes, BGRABitmapTypes; 13 14 type 15 TCheckShouldStopFunc = function(ACurrentY: integer) : boolean of object; 16 17 { TFilterTask } 18 19 TFilterTask = class 20 private 21 FCheckShouldStop: TCheckShouldStopFunc; 22 procedure SetDestination(AValue: TBGRACustomBitmap); 23 protected 24 FDestination: TBGRACustomBitmap; 25 FSource: TBGRACustomBitmap; 26 FCurrentY: integer; 27 function GetShouldStop(ACurrentY: integer): boolean; 28 procedure DoExecute; virtual; abstract; 29 public 30 function Execute: TBGRACustomBitmap; 31 property Destination: TBGRACustomBitmap read FDestination write SetDestination; 32 property CheckShouldStop: TCheckShouldStopFunc read FCheckShouldStop write FCheckShouldStop; 33 property CurrentY: integer read FCurrentY; 34 end; 13 35 14 36 { The median filter consist in calculating the median value of pixels. Here … … 25 47 26 48 { Sharpen filter add more contrast between pixels } 27 function FilterSharpen(bmp: TBGRACustomBitmap): TBGRACustomBitmap; 49 function FilterSharpen(bmp: TBGRACustomBitmap; AAmount: integer = 256): TBGRACustomBitmap; 50 function FilterSharpen(bmp: TBGRACustomBitmap; ABounds: TRect; AAmount: integer = 256): TBGRACustomBitmap; 28 51 29 52 { A radial blur applies a blur with a circular influence, i.e, each pixel … … 32 55 function FilterBlurRadial(bmp: TBGRACustomBitmap; radius: integer; 33 56 blurType: TRadialBlurType): TBGRACustomBitmap; 57 function CreateRadialBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; ARadius: integer; 58 ABlurType: TRadialBlurType): TFilterTask; 34 59 35 60 { The precise blur allow to specify the blur radius with subpixel accuracy } 36 function FilterBlurRadialPrecise(bmp: TBGRACustomBitmap; 37 radius: single): TBGRACustomBitmap;61 function FilterBlurRadialPrecise(bmp: TBGRACustomBitmap; radius: single): TBGRACustomBitmap; 62 function CreateRadialPreciseBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; ARadius: single): TFilterTask; 38 63 39 64 { Motion blur merge pixels in a direction. The oriented parameter specifies … … 41 66 function FilterBlurMotion(bmp: TBGRACustomBitmap; distance: single; 42 67 angle: single; oriented: boolean): TBGRACustomBitmap; 43 44 function FilterPixelate(bmp: TBGRACustomBitmap; pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; 68 function CreateMotionBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; ADistance,AAngle: single; AOriented: boolean): TFilterTask; 45 69 46 70 { General purpose blur filter, with a blur mask as parameter to describe 47 71 how pixels influence each other } 48 function FilterBlur(bmp: TBGRACustomBitmap; 49 blurMask: TBGRACustomBitmap): TBGRACustomBitmap; 72 function FilterBlur(bmp: TBGRACustomBitmap; blurMask: TBGRACustomBitmap): TBGRACustomBitmap; 73 function CreateBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; AMask: TBGRACustomBitmap; AMaskIsThreadSafe: boolean = false): TFilterTask; 74 75 function FilterPixelate(bmp: TBGRACustomBitmap; pixelSize: integer; useResample: boolean; filter: TResampleFilter = rfLinear): TBGRACustomBitmap; 50 76 51 77 { Emboss filter compute a color difference in the angle direction } 52 78 function FilterEmboss(bmp: TBGRACustomBitmap; angle: single): TBGRACustomBitmap; 79 function FilterEmboss(bmp: TBGRACustomBitmap; angle: single; ABounds: TRect): TBGRACustomBitmap; 53 80 54 81 { Emboss highlight computes a sort of emboss with 45 degrees angle and … … 63 90 function FilterNormalize(bmp: TBGRACustomBitmap; 64 91 eachChannel: boolean = True): TBGRACustomBitmap; 92 function FilterNormalize(bmp: TBGRACustomBitmap; ABounds: TRect; 93 eachChannel: boolean = True): TBGRACustomBitmap; 65 94 66 95 { Rotate filter rotate the image and clip it in the bounding rectangle } 67 96 function FilterRotate(bmp: TBGRACustomBitmap; origin: TPointF; 68 angle: single ): TBGRACustomBitmap;97 angle: single; correctBlur: boolean = false): TBGRACustomBitmap; 69 98 70 99 { Grayscale converts colored pixel into grayscale with same luminosity } 71 100 function FilterGrayscale(bmp: TBGRACustomBitmap): TBGRACustomBitmap; 101 function FilterGrayscale(bmp: TBGRACustomBitmap; ABounds: TRect): TBGRACustomBitmap; 102 function CreateGrayscaleTask(bmp: TBGRACustomBitmap; ABounds: TRect): TFilterTask; 72 103 73 104 { Compute a contour, as if the image was drawn with a 2 pixels-wide black pencil } … … 79 110 { Twirl distortion, i.e. a progressive rotation } 80 111 function FilterTwirl(bmp: TBGRACustomBitmap; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; 112 function FilterTwirl(bmp: TBGRACustomBitmap; ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; 81 113 82 114 { Distort the image as if it were on a vertical cylinder } … … 88 120 implementation 89 121 90 uses Math, GraphType, Dialogs, BGRATransform; 122 uses Math, GraphType, Dialogs, BGRATransform, Types, SysUtils; 123 124 type 125 { TGrayscaleTask } 126 127 TGrayscaleTask = class(TFilterTask) 128 private 129 FBounds: TRect; 130 public 131 constructor Create(bmp: TBGRACustomBitmap; ABounds: TRect); 132 protected 133 procedure DoExecute; override; 134 end; 135 136 { TBoxBlurTask } 137 138 TBoxBlurTask = class(TFilterTask) 139 private 140 FBounds: TRect; 141 FRadius: integer; 142 public 143 constructor Create(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer); 144 protected 145 procedure DoExecute; override; 146 end; 147 148 { TRadialBlurTask } 149 150 TRadialBlurTask = class(TFilterTask) 151 private 152 FBounds: TRect; 153 FRadius: integer; 154 FBlurType: TRadialBlurType; 155 public 156 constructor Create(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer; 157 blurType: TRadialBlurType); 158 protected 159 procedure DoExecute; override; 160 end; 161 162 { TCustomBlurTask } 163 164 TCustomBlurTask = class(TFilterTask) 165 private 166 FBounds: TRect; 167 FMask: TBGRACustomBitmap; 168 FMaskOwned: boolean; 169 public 170 constructor Create(bmp: TBGRACustomBitmap; ABounds: TRect; AMask: TBGRACustomBitmap; AMaskIsThreadSafe: boolean = false); 171 destructor Destroy; override; 172 protected 173 procedure DoExecute; override; 174 end; 175 176 { TRadialPreciseBlurTask } 177 178 TRadialPreciseBlurTask = class(TFilterTask) 179 private 180 FBounds: TRect; 181 FRadius: Single; 182 public 183 constructor Create(bmp: TBGRACustomBitmap; ABounds: TRect; radius: single); 184 protected 185 procedure DoExecute; override; 186 end; 187 188 { TMotionBlurTask } 189 190 TMotionBlurTask = class(TFilterTask) 191 private 192 FBounds: TRect; 193 FDistance,FAngle: single; 194 FOriented: boolean; 195 public 196 constructor Create(ABmp: TBGRACustomBitmap; ABounds: TRect; ADistance, AAngle: single; AOriented: boolean); 197 protected 198 procedure DoExecute; override; 199 end; 200 201 procedure FilterBlurRadial(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer; 202 blurType: TRadialBlurType; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 203 procedure FilterBlurRadialPrecise(bmp: TBGRACustomBitmap; ABounds: TRect; 204 radius: single; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 205 procedure FilterBlurMotion(bmp: TBGRACustomBitmap; ABounds: TRect; distance: single; 206 angle: single; oriented: boolean; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 207 procedure FilterBlur(bmp: TBGRACustomBitmap; ABounds: TRect; 208 blurMask: TBGRACustomBitmap; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 91 209 92 210 function FilterSmartZoom3(bmp: TBGRACustomBitmap; … … 98 216 99 217 var 100 xb, yb: integer;218 xb, yb: Int32or64; 101 219 diag1, diag2, h1, h2, v1, v2: TSmartDiff; 102 220 c,c1,c2: TBGRAPixel; … … 105 223 function ColorDiff(c1, c2: TBGRAPixel): single; 106 224 var 107 max1, max2: integer;225 max1, max2: Int32or64; 108 226 begin 109 227 if (c1.alpha = 0) and (c2.alpha = 0) then … … 156 274 end; 157 275 158 function smartDiff(x1, y1, x2, y2: integer): TSmartDiff;276 function smartDiff(x1, y1, x2, y2: Int32or64): TSmartDiff; 159 277 var 160 278 c1, c2, c1m, c2m: TBGRAPixel; … … 209 327 begin 210 328 c1 := bmp.GetPixel(xb, yb); 211 c2 := bmp.GetPixel( integer(xb + 1), integer(yb + 1));329 c2 := bmp.GetPixel(xb + 1, yb + 1); 212 330 c := MergeBGRA(c1, c2); 213 331 //restore 214 332 Result.SetPixel(xb * 3 + 2, yb * 3 + 2, bmp.GetPixel(xb, yb)); 215 Result.SetPixel(xb * 3 + 3, yb * 3 + 3, bmp.GetPixel( integer(xb + 1), integer(yb + 1)));333 Result.SetPixel(xb * 3 + 3, yb * 3 + 3, bmp.GetPixel(xb + 1, yb + 1)); 216 334 217 335 if (diag1.sd < h1.sd) and (diag1.sd < v2.sd) then … … 250 368 of the square. Finally the difference is added to the new pixel, exagerating 251 369 its difference with its neighbours. } 252 function FilterSharpen(bmp: TBGRACustomBitmap): TBGRACustomBitmap; 253 const 254 nbpix = 8; 370 function FilterSharpen(bmp: TBGRACustomBitmap; ABounds: TRect; AAmount: integer = 256): TBGRACustomBitmap; 255 371 var 256 yb, x b: integer;257 dx, dy , n, j: integer;258 a_pixels: array[ 0..nbpix - 1] of TBGRAPixel;259 sumR, sumG, sumB, sumA, RGBdiv, nbA: cardinal;260 tempPixel,refPixel: TBGRAPixel;261 pdest : PBGRAPixel;372 yb, xcount: Int32or64; 373 dx, dy: Int32or64; 374 a_pixels: array[-2..1,-2..1] of PBGRAPixel; 375 sumR, sumG, sumB, sumA, {RGBdiv, }nbA: UInt32or64; 376 refPixel: TBGRAPixel; 377 pdest,ptempPixel: PBGRAPixel; 262 378 bounds: TRect; 263 begin 379 Amount256: boolean; 380 lastXincluded: boolean; 381 alpha,rgbDivShr1: uint32or64; 382 begin 383 if IsRectEmpty(ABounds) then exit; 384 Amount256 := AAmount = 256; 264 385 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 265 386 266 387 //determine where pixels are in the bitmap 267 388 bounds := bmp.GetImageBounds; 268 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then 269 exit; 389 if not IntersectRect(bounds, bounds,ABounds) then exit; 270 390 bounds.Left := max(0, bounds.Left - 1); 271 391 bounds.Top := max(0, bounds.Top - 1); 272 392 bounds.Right := min(bmp.Width, bounds.Right + 1); 273 393 bounds.Bottom := min(bmp.Height, bounds.Bottom + 1); 394 lastXincluded:= bounds.Right < bmp.Width; 274 395 275 396 //loop through the destination bitmap … … 277 398 begin 278 399 pdest := Result.scanline[yb] + bounds.Left; 279 for xb := bounds.Left to bounds.Right - 1 do 280 begin 400 fillchar({%H-}a_pixels,sizeof(a_pixels),0); 401 for dy := -1 to 1 do 402 if (yb+dy >= bounds.Top) and (yb+dy < bounds.Bottom) then 403 a_pixels[dy,1] := bmp.ScanLine[yb+dy]+bounds.Left else 404 a_pixels[dy,1] := nil; 405 xcount := bounds.right-bounds.left; 406 while xcount > 0 do 407 begin 408 dec(xcount); 409 281 410 //for each pixel, read eight surrounding pixels in the source bitmap 282 n := 0;283 411 for dy := -1 to 1 do 284 for dx := -1 to 1 do 285 if (dx <> 0) or (dy <> 0) then 286 begin 287 a_pixels[n] := bmp.GetPixel(integer(xb + dx), integer(yb + dy)); 288 Inc(n); 289 end; 412 for dx := -1 to 0 do 413 a_pixels[dy,dx] := a_pixels[dy,dx+1]; 414 if (xcount > 0) or lastXincluded then 415 begin 416 for dy := -1 to 1 do 417 if a_pixels[dy,0] <> nil then a_pixels[dy,1] := a_pixels[dy,0]+1; 418 end; 290 419 291 420 //compute sum … … 294 423 sumB := 0; 295 424 sumA := 0; 296 RGBdiv := 0;425 //RGBdiv := 0; 297 426 nbA := 0; 298 427 299 428 {$hints off} 300 for j := 0 to n - 1 do 301 begin 302 tempPixel := a_pixels[j]; 303 sumR += tempPixel.red * tempPixel.alpha; 304 sumG += tempPixel.green * tempPixel.alpha; 305 sumB += tempPixel.blue * tempPixel.alpha; 306 RGBdiv += tempPixel.alpha; 307 sumA += tempPixel.alpha; 308 Inc(nbA); 309 end; 429 for dy := -1 to 1 do 430 for dx := -1 to 1 do 431 if (dx<>0) or (dy<>0) then 432 begin 433 ptempPixel := a_pixels[dy,dx]; 434 if ptempPixel <> nil then 435 begin 436 alpha := ptempPixel^.alpha; 437 sumR += ptempPixel^.red * alpha; 438 sumG += ptempPixel^.green * alpha; 439 sumB += ptempPixel^.blue * alpha; 440 //RGBdiv += alpha; 441 sumA += alpha; 442 Inc(nbA); 443 end; 444 end; 310 445 {$hints on} 311 446 312 447 //we finally have an average pixel 313 if ( RGBdiv= 0) then448 if ({RGBdiv}sumA = 0) then 314 449 refPixel := BGRAPixelTransparent 315 450 else 316 451 begin 317 refPixel.red := (sumR + RGBdiv shr 1) div RGBdiv; 318 refPixel.green := (sumG + RGBdiv shr 1) div RGBdiv; 319 refPixel.blue := (sumB + RGBdiv shr 1) div RGBdiv; 452 rgbDivShr1:= {RGBDiv}sumA shr 1; 453 refPixel.red := (sumR + rgbDivShr1) div {RGBdiv}sumA; 454 refPixel.green := (sumG + rgbDivShr1) div {RGBdiv}sumA; 455 refPixel.blue := (sumB + rgbDivShr1) div {RGBdiv}sumA; 320 456 refPixel.alpha := (sumA + nbA shr 1) div nbA; 321 457 end; 322 458 323 459 //read the pixel at the center of the square 324 tempPixel := bmp.GetPixel(xb, yb);460 ptempPixel := a_pixels[0,0]; 325 461 if refPixel <> BGRAPixelTransparent then 326 462 begin 327 463 //compute sharpened pixel by adding the difference 328 tempPixel.red := max(0, min(255, tempPixel.red + 329 integer(tempPixel.red - refPixel.red))); 330 tempPixel.green := max(0, min(255, tempPixel.green + 331 integer(tempPixel.green - refPixel.green))); 332 tempPixel.blue := max(0, min(255, tempPixel.blue + 333 integer(tempPixel.blue - refPixel.blue))); 334 tempPixel.alpha := max(0, min(255, tempPixel.alpha + 335 integer(tempPixel.alpha - refPixel.alpha))); 336 end; 337 pdest^ := tempPixel; 464 if not Amount256 then 465 pdest^ := BGRA( max(0, min($FFFF, Int32or64(ptempPixel^.red shl 8) + 466 AAmount*(ptempPixel^.red - refPixel.red))) shr 8, 467 max(0, min($FFFF, Int32or64(ptempPixel^.green shl 8) + 468 AAmount*(ptempPixel^.green - refPixel.green))) shr 8, 469 max(0, min($FFFF, Int32or64(ptempPixel^.blue shl 8) + 470 AAmount*(ptempPixel^.blue - refPixel.blue))) shr 8, 471 max(0, min($FFFF, Int32or64(ptempPixel^.alpha shl 8) + 472 AAmount*(ptempPixel^.alpha - refPixel.alpha))) shr 8 ) 473 else 474 pdest^ := BGRA( max(0, min(255, (ptempPixel^.red shl 1) - refPixel.red)), 475 max(0, min(255, (ptempPixel^.green shl 1) - refPixel.green)), 476 max(0, min(255, (ptempPixel^.blue shl 1) - refPixel.blue)), 477 max(0, min(255, (ptempPixel^.alpha shl 1) - refPixel.alpha))); 478 end else 479 pdest^ := ptempPixel^; 338 480 Inc(pdest); 339 481 end; 340 482 end; 341 483 Result.InvalidateBitmap; 484 end; 485 486 function FilterSharpen(bmp: TBGRACustomBitmap; AAmount: integer 487 ): TBGRACustomBitmap; 488 begin 489 result := FilterSharpen(bmp,rect(0,0,bmp.Width,bmp.Height),AAmount); 342 490 end; 343 491 344 492 { Precise blur builds a blur mask with a gradient fill and use 345 493 general purpose blur } 346 functionFilterBlurRadialPrecise(bmp: TBGRACustomBitmap;347 radius: single): TBGRACustomBitmap;494 procedure FilterBlurRadialPrecise(bmp: TBGRACustomBitmap; 495 ABounds: TRect; radius: single; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 348 496 var 349 497 blurShape: TBGRACustomBitmap; … … 352 500 if radius = 0 then 353 501 begin 354 result := bmp.Duplicate;502 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 355 503 exit; 356 504 end; … … 360 508 BGRABlack, gtRadial, pointF(intRadius, intRadius), pointF( 361 509 intRadius - radius - 1, intRadius), dmSet); 362 Result := FilterBlur(bmp, blurShape);510 FilterBlur(bmp, ABounds, blurShape, ADestination, ACheckShouldStop); 363 511 blurShape.Free; 512 end; 513 514 function FilterBlurRadialPrecise(bmp: TBGRACustomBitmap; radius: single 515 ): TBGRACustomBitmap; 516 begin 517 result := bmp.NewBitmap(bmp.Width,bmp.Height); 518 FilterBlurRadialPrecise(bmp, rect(0,0,bmp.Width,bmp.Height), radius, result, nil); 519 end; 520 521 function CreateRadialPreciseBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; 522 ARadius: single): TFilterTask; 523 begin 524 result := TRadialPreciseBlurTask.Create(ABmp,ABounds,ARadius); 364 525 end; 365 526 … … 369 530 the vertical sums are kept except for the last column of 370 531 the square } 371 function FilterBlurFast(bmp: TBGRACustomBitmap;372 radius: integer ): TBGRACustomBitmap;373 532 procedure FilterBlurFast(bmp: TBGRACustomBitmap; ABounds: TRect; 533 radius: integer; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 534 {$IFDEF CPU64}{$DEFINE FASTBLUR_DOUBLE}{$ENDIF} 374 535 type 375 536 TRowSum = record 376 sumR,sumG,sumB,rgbDiv,sumA,aDiv: cardinal; 377 end; 378 379 function ComputeAverage(sum: TRowSum): TBGRAPixel; 380 begin 537 sumR,sumG,sumB,rgbDiv,sumA,aDiv: uint32or64; 538 end; 539 TExtendedRowValue = {$IFDEF FASTBLUR_DOUBLE}double{$ELSE}uint64{$ENDIF}; 540 TExtendedRowSum = record 541 sumR,sumG,sumB,rgbDiv,sumA,aDiv: TExtendedRowValue; 542 end; 543 544 function ComputeExtendedAverage(sum: TExtendedRowSum): TBGRAPixel; 545 {$IFDEF FASTBLUR_DOUBLE} 546 var v: uint32or64; 547 {$ENDIF} 548 begin 549 {$IFDEF FASTBLUR_DOUBLE} 550 v := round(sum.sumA/sum.aDiv); 551 if v > 255 then result.alpha := 255 else result.alpha := v; 552 v := round(sum.sumR/sum.rgbDiv); 553 if v > 255 then result.red := 255 else result.red := v; 554 v := round(sum.sumG/sum.rgbDiv); 555 if v > 255 then result.green := 255 else result.green := v; 556 v := round(sum.sumB/sum.rgbDiv); 557 if v > 255 then result.blue := 255 else result.blue := v; 558 {$ELSE} 381 559 result.alpha:= (sum.sumA+sum.aDiv shr 1) div sum.aDiv; 382 560 result.red := (sum.sumR+sum.rgbDiv shr 1) div sum.rgbDiv; 383 561 result.green := (sum.sumG+sum.rgbDiv shr 1) div sum.rgbDiv; 384 562 result.blue := (sum.sumB+sum.rgbDiv shr 1) div sum.rgbDiv; 563 {$ENDIF} 564 end; 565 566 function ComputeClampedAverage(sum: TRowSum): TBGRAPixel; 567 var v: UInt32or64; 568 begin 569 v := (sum.sumA+sum.aDiv shr 1) div sum.aDiv; 570 if v > 255 then result.alpha := 255 else result.alpha := v; 571 v := (sum.sumR+sum.rgbDiv shr 1) div sum.rgbDiv; 572 if v > 255 then result.red := 255 else result.red := v; 573 v := (sum.sumG+sum.rgbDiv shr 1) div sum.rgbDiv; 574 if v > 255 then result.green := 255 else result.green := v; 575 v := (sum.sumB+sum.rgbDiv shr 1) div sum.rgbDiv; 576 if v > 255 then result.blue := 255 else result.blue := v; 577 end; 578 579 function ComputeAverage(sum: TRowSum): TBGRAPixel; 580 begin 581 result.alpha:= (sum.sumA+sum.aDiv shr 1) div sum.aDiv; 582 result.red := (sum.sumR+sum.rgbDiv shr 1) div sum.rgbDiv; 583 result.green := (sum.sumG+sum.rgbDiv shr 1) div sum.rgbDiv; 584 result.blue := (sum.sumB+sum.rgbDiv shr 1) div sum.rgbDiv; 385 585 end; 386 586 … … 389 589 { Normal radial blur compute a blur mask with a GradientFill and 390 590 then posterize to optimize general purpose blur } 391 functionFilterBlurRadialNormal(bmp: TBGRACustomBitmap;392 radius: integer): TBGRACustomBitmap;591 procedure FilterBlurRadialNormal(bmp: TBGRACustomBitmap; 592 ABounds: TRect; radius: integer; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 393 593 var 394 594 blurShape: TBGRACustomBitmap; 395 n: Int eger;595 n: Int32or64; 396 596 p: PBGRAPixel; 397 597 begin 598 if radius = 0 then 599 begin 600 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 601 exit; 602 end; 398 603 blurShape := bmp.NewBitmap(2 * radius + 1, 2 * radius + 1); 399 604 blurShape.GradientFill(0, 0, blurShape.Width, blurShape.Height, BGRAWhite, … … 407 612 inc(p); 408 613 end; 409 Result := FilterBlur(bmp, blurShape);614 FilterBlur(bmp, ABounds, blurShape, ADestination, ACheckShouldStop); 410 615 blurShape.Free; 411 616 end; 412 617 413 618 { Blur disk creates a disk mask with a FillEllipse } 414 function FilterBlurDisk(bmp: TBGRACustomBitmap; radius: integer): TBGRACustomBitmap;619 procedure FilterBlurDisk(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 415 620 var 416 621 blurShape: TBGRACustomBitmap; 417 622 begin 623 if radius = 0 then 624 begin 625 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 626 exit; 627 end; 418 628 blurShape := bmp.NewBitmap(2 * radius + 1, 2 * radius + 1); 419 629 blurShape.Fill(BGRABlack); 420 630 blurShape.FillEllipseAntialias(radius, radius, radius + 0.5, radius + 0.5, BGRAWhite); 421 Result := FilterBlur(bmp, blurShape);631 FilterBlur(bmp, ABounds, blurShape, ADestination, ACheckShouldStop); 422 632 blurShape.Free; 423 633 end; 424 634 425 635 { Corona blur use a circle as mask } 426 function FilterBlurCorona(bmp: TBGRACustomBitmap; radius: integer): TBGRACustomBitmap;636 procedure FilterBlurCorona(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 427 637 var 428 638 blurShape: TBGRACustomBitmap; 429 639 begin 640 if radius = 0 then 641 begin 642 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 643 exit; 644 end; 430 645 blurShape := bmp.NewBitmap(2 * radius + 1, 2 * radius + 1); 431 646 blurShape.Fill(BGRABlack); 432 647 blurShape.EllipseAntialias(radius, radius, radius, radius, BGRAWhite, 1); 433 Result := FilterBlur(bmp, blurShape);648 FilterBlur(bmp, ABounds, blurShape, ADestination, ACheckShouldStop); 434 649 blurShape.Free; 650 end; 651 652 function FilterBlurBox(bmp: TBGRACustomBitmap; radius: integer; ADestination: TBGRACustomBitmap): TBGRACustomBitmap; 653 var task: TBoxBlurTask; 654 begin 655 task := TBoxBlurTask.Create(bmp, rect(0,0,bmp.Width,bmp.Height), radius); 656 task.Destination := ADestination; 657 result := task.Execute; 658 task.Free; 659 end; 660 661 procedure FilterBlurRadial(bmp: TBGRACustomBitmap; ABounds: TRect; radius: integer; 662 blurType: TRadialBlurType; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 663 begin 664 if radius = 0 then 665 begin 666 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 667 exit; 668 end; 669 case blurType of 670 rbCorona: FilterBlurCorona(bmp, ABounds, radius, ADestination, ACheckShouldStop); 671 rbDisk: FilterBlurDisk(bmp, ABounds, radius, ADestination, ACheckShouldStop); 672 rbNormal: FilterBlurRadialNormal(bmp, ABounds, radius, ADestination, ACheckShouldStop); 673 rbFast: FilterBlurFast(bmp, ABounds, radius, ADestination, ACheckShouldStop); 674 rbPrecise: FilterBlurRadialPrecise(bmp, ABounds, radius / 10, ADestination, ACheckShouldStop); 675 rbBox: FilterBlurBox(bmp, radius, ADestination); 676 end; 435 677 end; 436 678 … … 438 680 blurType: TRadialBlurType): TBGRACustomBitmap; 439 681 begin 440 if radius = 0 then 441 begin 442 result := bmp.Duplicate; 443 exit; 444 end; 445 case blurType of 446 rbCorona: Result := FilterBlurCorona(bmp, radius); 447 rbDisk: Result := FilterBlurDisk(bmp, radius); 448 rbNormal: Result := FilterBlurRadialNormal(bmp, radius); 449 rbFast: Result := FilterBlurFast(bmp, radius); 450 rbPrecise: Result := FilterBlurRadialPrecise(bmp, radius / 10); 451 else 452 Result := nil; 453 end; 682 if blurType = rbBox then 683 begin 684 result := FilterBlurBox(bmp,radius,nil); 685 end else 686 begin 687 result := bmp.NewBitmap(bmp.width,bmp.Height); 688 FilterBlurRadial(bmp, rect(0,0,bmp.Width,bmp.height), radius, blurType,result,nil); 689 end; 690 end; 691 692 function CreateRadialBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; ARadius: integer; 693 ABlurType: TRadialBlurType): TFilterTask; 694 begin 695 if ABlurType = rbBox then 696 result := TBoxBlurTask.Create(ABmp,ABounds,ARadius) 697 else 698 result := TRadialBlurTask.Create(ABmp,ABounds,ARadius,ABlurType); 454 699 end; 455 700 456 701 { This filter draws an antialiased line to make the mask, and 457 702 if the motion blur is oriented, does a GradientFill to orient it } 458 function FilterBlurMotion(bmp: TBGRACustomBitmap; distance: single;459 angle: single; oriented: boolean ): TBGRACustomBitmap;703 procedure FilterBlurMotion(bmp: TBGRACustomBitmap; ABounds: TRect; distance: single; 704 angle: single; oriented: boolean; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 460 705 var 461 706 blurShape: TBGRACustomBitmap; … … 463 708 dx, dy, d: single; 464 709 begin 465 if distance = 0then466 begin 467 result := bmp.Duplicate;710 if distance < 1e-6 then 711 begin 712 ADestination.PutImagePart(ABounds.Left,ABounds.Top,bmp,ABounds,dmSet); 468 713 exit; 469 714 end; … … 482 727 pointF(intRadius + dx * (d + 0.5), intRadius + dy * (d + 0.5)), 483 728 dmFastBlend, False); 484 Result := FilterBlur(bmp, blurShape);729 FilterBlur(bmp, ABounds, blurShape, ADestination, ACheckShouldStop); 485 730 blurShape.Free; 731 end; 732 733 function FilterBlurMotion(bmp: TBGRACustomBitmap; distance: single; 734 angle: single; oriented: boolean): TBGRACustomBitmap; 735 begin 736 result := bmp.NewBitmap(bmp.Width,bmp.Height); 737 FilterBlurMotion(bmp,rect(0,0,bmp.Width,bmp.Height),distance,angle,oriented,result,nil); 738 end; 739 740 function CreateMotionBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; 741 ADistance, AAngle: single; AOriented: boolean): TFilterTask; 742 begin 743 result := TMotionBlurTask.Create(ABmp,ABounds,ADistance,AAngle,AOriented); 486 744 end; 487 745 488 746 { General purpose blur : compute pixel sum according to the mask and then 489 747 compute only difference while scanning from the left to the right } 490 function FilterBlurSmallMask(bmp: TBGRACustomBitmap; 491 blurMask: TBGRACustomBitmap): TBGRACustomBitmap; forward; 492 function FilterBlurSmallMaskWithShift(bmp: TBGRACustomBitmap; 493 blurMask: TBGRACustomBitmap; maskShift: integer): TBGRACustomBitmap; forward; 494 function FilterBlurBigMask(bmp: TBGRACustomBitmap; 495 blurMask: TBGRACustomBitmap): TBGRACustomBitmap; forward; 748 procedure FilterBlurSmallMask(bmp: TBGRACustomBitmap; 749 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 750 procedure FilterBlurSmallMaskWithShift(bmp: TBGRACustomBitmap; 751 blurMask: TBGRACustomBitmap; maskShift: integer; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 752 procedure FilterBlurBigMask(bmp: TBGRACustomBitmap; 753 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 754 procedure FilterBlurMask64(bmp: TBGRACustomBitmap; 755 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); forward; 496 756 497 757 //make sure value is in the range 0..255 498 function clampByte(value: integer): byte; inline;758 function clampByte(value: Int32or64): byte; inline; 499 759 begin 500 760 if value < 0 then result := 0 else … … 505 765 function FilterPixelate(bmp: TBGRACustomBitmap; pixelSize: integer; 506 766 useResample: boolean; filter: TResampleFilter): TBGRACustomBitmap; 507 var yb,xb, xs,ys, tx,ty: integer;767 var yb,xb, xs,ys, tx,ty: Int32or64; 508 768 psrc,pdest: PBGRAPixel; 509 769 temp,stretched: TBGRACustomBitmap; … … 531 791 psrc := bmp.scanline[ys]+xs; 532 792 inc(ys,pixelSize); 533 for xb := 0 to temp.width-1do793 for xb := temp.width-1 downto 0 do 534 794 begin 535 795 pdest^ := psrc^; … … 560 820 end; 561 821 562 function FilterBlur(bmp: TBGRACustomBitmap; 563 blurMask: TBGRACustomBitmap): TBGRACustomBitmap; 822 function FilterBlur(bmp: TBGRACustomBitmap; blurMask: TBGRACustomBitmap): TBGRACustomBitmap; 823 begin 824 result := bmp.NewBitmap(bmp.Width,bmp.Height); 825 FilterBlur(bmp,rect(0,0,bmp.Width,bmp.Height),blurMask,result,nil); 826 end; 827 828 function CreateBlurTask(ABmp: TBGRACustomBitmap; ABounds: TRect; 829 AMask: TBGRACustomBitmap; AMaskIsThreadSafe: boolean): TFilterTask; 830 begin 831 result := TCustomBlurTask.Create(ABmp,ABounds,AMask,AMaskIsThreadSafe); 832 end; 833 834 procedure FilterBlur(bmp: TBGRACustomBitmap; 835 ABounds: TRect; blurMask: TBGRACustomBitmap; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 836 {$IFDEF CPU64} 837 begin 838 FilterBlurMask64(bmp,blurMask,ABounds,ADestination,ACheckShouldStop); 839 end; 840 {$ELSE} 564 841 var 565 842 maskSum: int64; 566 i: Int eger;843 i: Int32or64; 567 844 p: PBGRAPixel; 568 845 maskShift: integer; … … 583 860 //check if sum can be stored in a 32-bit signed integer 584 861 if maskShift = 0 then 585 result := FilterBlurSmallMask(bmp,blurMask) else 862 FilterBlurSmallMask(bmp,blurMask,ABounds,ADestination,ACheckShouldStop) else 863 {$IFDEF CPU32} 586 864 if maskShift < 8 then 587 result := FilterBlurSmallMaskWithShift(bmp,blurMask,maskShift) else 588 result := FilterBlurBigMask(bmp,blurMask); 589 end; 865 FilterBlurSmallMaskWithShift(bmp,blurMask,maskShift,ABounds,ADestination,ACheckShouldStop) else 866 {$ENDIF} 867 FilterBlurBigMask(bmp,blurMask,ABounds,ADestination,ACheckShouldStop); 868 end; 869 {$ENDIF} 590 870 591 871 //32-bit blur with shift 592 functionFilterBlurSmallMaskWithShift(bmp: TBGRACustomBitmap;593 blurMask: TBGRACustomBitmap; maskShift: integer ): TBGRACustomBitmap;872 procedure FilterBlurSmallMaskWithShift(bmp: TBGRACustomBitmap; 873 blurMask: TBGRACustomBitmap; maskShift: integer; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 594 874 595 875 var … … 613 893 614 894 //32-bit blur 615 functionFilterBlurSmallMask(bmp: TBGRACustomBitmap;616 blurMask: TBGRACustomBitmap ): TBGRACustomBitmap;895 procedure FilterBlurSmallMask(bmp: TBGRACustomBitmap; 896 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 617 897 618 898 var … … 634 914 {$I blurnormal.inc} 635 915 916 //64-bit blur 917 procedure FilterBlurMask64(bmp: TBGRACustomBitmap; 918 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 919 920 var 921 sumR, sumG, sumB, sumA, Adiv : int64; 922 923 function ComputeAverage: TBGRAPixel; inline; 924 begin 925 result.alpha := (sumA + Adiv shr 1) div Adiv; 926 if result.alpha = 0 then 927 result := BGRAPixelTransparent 928 else 929 begin 930 result.red := clampByte((sumR + sumA shr 1) div sumA); 931 result.green := clampByte((sumG + sumA shr 1) div sumA); 932 result.blue := clampByte((sumB + sumA shr 1) div sumA); 933 end; 934 end; 935 936 {$I blurnormal.inc} 937 636 938 //floating point blur 637 functionFilterBlurBigMask(bmp: TBGRACustomBitmap;638 blurMask: TBGRACustomBitmap ): TBGRACustomBitmap;939 procedure FilterBlurBigMask(bmp: TBGRACustomBitmap; 940 blurMask: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 639 941 640 942 var … … 655 957 656 958 {$I blurnormal.inc} 959 function FilterEmboss(bmp: TBGRACustomBitmap; angle: single): TBGRACustomBitmap; 960 begin 961 result := FilterEmboss(bmp, angle, rect(0,0,bmp.Width,bmp.Height)); 962 end; 657 963 658 964 { Emboss filter computes the difference between each pixel and the surrounding pixels 659 965 in the specified direction. } 660 function FilterEmboss(bmp: TBGRACustomBitmap; angle: single ): TBGRACustomBitmap;966 function FilterEmboss(bmp: TBGRACustomBitmap; angle: single; ABounds: TRect): TBGRACustomBitmap; 661 967 var 662 yb, xb: integer;968 yb, xb: Int32or64; 663 969 dx, dy: single; 664 idx1, idy1, idx2, idy2, idx3, idy3, idx4, idy4: integer;970 idx1, idy1, idx2, idy2, idx3, idy3, idx4, idy4: Int32or64; 665 971 w: array[1..4] of single; 666 iw: cardinal;972 iw: uint32or64; 667 973 c: array[0..4] of TBGRAPixel; 668 974 669 i: integer;670 sumR, sumG, sumB, sumA, RGBdiv, Adiv: cardinal;975 i: Int32or64; 976 sumR, sumG, sumB, sumA, RGBdiv, Adiv: UInt32or64; 671 977 tempPixel, refPixel: TBGRAPixel; 672 978 pdest: PBGRAPixel; 673 979 674 980 bounds: TRect; 675 begin 981 onHorizBorder: boolean; 982 psrc: array[-1..1] of PBGRAPixel; 983 begin 984 if IsRectEmpty(ABounds) then exit; 676 985 //compute pixel position and weight 677 986 dx := cos(angle * Pi / 180); … … 696 1005 697 1006 bounds := bmp.GetImageBounds; 698 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then 699 exit; 1007 if not IntersectRect(bounds, bounds, ABounds) then exit; 700 1008 bounds.Left := max(0, bounds.Left - 1); 701 1009 bounds.Top := max(0, bounds.Top - 1); … … 707 1015 begin 708 1016 pdest := Result.scanline[yb] + bounds.Left; 1017 onHorizBorder:= (yb=0) or (yb=bmp.Height-1); 1018 psrc[0] := bmp.ScanLine[yb]+bounds.Left; 1019 if (yb>0) then psrc[-1] := bmp.ScanLine[yb-1]+bounds.Left else psrc[-1] := nil; 1020 if (yb<bmp.Height-1) then psrc[1] := bmp.ScanLine[yb+1]+bounds.Left else psrc[1] := nil; 709 1021 for xb := bounds.Left to bounds.Right - 1 do 710 1022 begin 711 c[0] := bmp.getPixel(xb, yb); 712 c[1] := bmp.getPixel(integer(xb + idx1), integer(yb + idy1)); 713 c[2] := bmp.getPixel(integer(xb + idx2), integer(yb + idy2)); 714 c[3] := bmp.getPixel(integer(xb + idx3), integer(yb + idy3)); 715 c[4] := bmp.getPixel(integer(xb + idx4), integer(yb + idy4)); 1023 c[0] := psrc[0]^; 1024 if onHorizBorder or (xb=0) or (xb=bmp.Width-1) then 1025 begin 1026 c[1] := bmp.getPixel(xb + idx1, yb + idy1); 1027 c[2] := bmp.getPixel(xb + idx2, yb + idy2); 1028 c[3] := bmp.getPixel(xb + idx3, yb + idy3); 1029 c[4] := bmp.getPixel(xb + idx4, yb + idy4); 1030 end else 1031 begin 1032 c[1] := (psrc[idy1]+idx1)^; 1033 c[2] := (psrc[idy2]+idx2)^; 1034 c[3] := (psrc[idy3]+idx3)^; 1035 c[4] := (psrc[idy4]+idx4)^; 1036 end; 716 1037 717 1038 sumR := 0; … … 762 1083 pdest^ := tempPixel; 763 1084 Inc(pdest); 1085 inc(psrc[0]); 1086 if psrc[-1] <> nil then inc(psrc[-1]); 1087 if psrc[1] <> nil then inc(psrc[1]); 764 1088 end; 765 1089 end; … … 771 1095 FillSelection: boolean; DefineBorderColor: TBGRAPixel): TBGRACustomBitmap; 772 1096 var 773 yb, xb: integer;774 c0,c1,c2,c3,c4,c5,c6: integer;775 776 bmpWidth, bmpHeight: integer;1097 yb, xb: Int32or64; 1098 c0,c1,c2,c3,c4,c5,c6: Int32or64; 1099 1100 bmpWidth, bmpHeight: Int32or64; 777 1101 slope, h: byte; 778 sum: integer;1102 sum: Int32or64; 779 1103 tempPixel, highlight: TBGRAPixel; 780 1104 pdest, psrcUp, psrc, psrcDown: PBGRAPixel; … … 782 1106 bounds: TRect; 783 1107 borderColorOverride: boolean; 784 borderColorLevel: integer;785 786 currentBorderColor: integer;1108 borderColorLevel: Int32or64; 1109 1110 currentBorderColor: Int32or64; 787 1111 begin 788 1112 borderColorOverride := DefineBorderColor.alpha <> 0; … … 905 1229 FillSelection: boolean; DefineBorderColor: TBGRAPixel; var Offset: TPoint): TBGRACustomBitmap; 906 1230 var 907 yb, xb: int eger;908 c0,c1,c2,c3,c4,c5,c6: int eger;909 910 bmpWidth, bmpHeight: int eger;1231 yb, xb: int32or64; 1232 c0,c1,c2,c3,c4,c5,c6: int32or64; 1233 1234 bmpWidth, bmpHeight: int32or64; 911 1235 slope, h: byte; 912 sum: int eger;1236 sum: int32or64; 913 1237 tempPixel, highlight: TBGRAPixel; 914 1238 pdest, psrcUp, psrc, psrcDown: PBGRAPixel; … … 916 1240 bounds: TRect; 917 1241 borderColorOverride: boolean; 918 borderColorLevel: int eger;919 920 currentBorderColor: int eger;1242 borderColorLevel: int32or64; 1243 1244 currentBorderColor: int32or64; 921 1245 begin 922 1246 borderColorOverride := DefineBorderColor.alpha <> 0; … … 1042 1366 end; 1043 1367 1368 function FilterNormalize(bmp: TBGRACustomBitmap; eachChannel: boolean 1369 ): TBGRACustomBitmap; 1370 begin 1371 result := FilterNormalize(bmp, rect(0,0,bmp.Width,bmp.Height), eachChannel); 1372 end; 1373 1044 1374 { Normalize compute min-max of specified channel and apply an affine transformation 1045 1375 to make it use the full range of values } 1046 function FilterNormalize(bmp: TBGRACustomBitmap; 1376 function FilterNormalize(bmp: TBGRACustomBitmap; ABounds: TRect; 1047 1377 eachChannel: boolean = True): TBGRACustomBitmap; 1048 1378 var 1049 1379 psrc, pdest: PBGRAPixel; 1050 1380 c: TExpandedPixel; 1051 n: integer;1381 xcount,xb,yb: int32or64; 1052 1382 minValRed, maxValRed, minValGreen, maxValGreen, minValBlue, maxValBlue, 1053 1383 minAlpha, maxAlpha, addValRed, addValGreen, addValBlue, addAlpha: word; 1054 factorValRed, factorValGreen, factorValBlue, factorAlpha: integer; 1055 begin 1384 factorValRed, factorValGreen, factorValBlue, factorAlpha: int32or64; 1385 begin 1386 if not IntersectRect(ABounds,ABounds,rect(0,0,bmp.Width,bmp.Height)) then exit; 1056 1387 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 1057 1388 bmp.LoadFromBitmapIfNeeded; 1058 psrc := bmp.Data;1059 1389 maxValRed := 0; 1060 1390 minValRed := 65535; … … 1065 1395 maxAlpha := 0; 1066 1396 minAlpha := 65535; 1067 for n := bmp.Width * bmp.Height - 1 downto 0 do 1068 begin 1069 c := GammaExpansion(psrc^); 1070 Inc(psrc); 1071 if c.red > maxValRed then 1072 maxValRed := c.red; 1073 if c.green > maxValGreen then 1074 maxValGreen := c.green; 1075 if c.blue > maxValBlue then 1076 maxValBlue := c.blue; 1077 if c.red < minValRed then 1078 minValRed := c.red; 1079 if c.green < minValGreen then 1080 minValGreen := c.green; 1081 if c.blue < minValBlue then 1082 minValBlue := c.blue; 1083 1084 if c.alpha > maxAlpha then 1085 maxAlpha := c.alpha; 1086 if c.alpha < minAlpha then 1087 minAlpha := c.alpha; 1397 xcount := ABounds.Right-ABounds.Left; 1398 for yb := ABounds.Top to ABounds.Bottom-1 do 1399 begin 1400 psrc := bmp.ScanLine[yb]+ABounds.Left; 1401 for xb := xcount-1 downto 0 do 1402 begin 1403 c := GammaExpansion(psrc^); 1404 Inc(psrc); 1405 if c.red > maxValRed then 1406 maxValRed := c.red; 1407 if c.green > maxValGreen then 1408 maxValGreen := c.green; 1409 if c.blue > maxValBlue then 1410 maxValBlue := c.blue; 1411 if c.red < minValRed then 1412 minValRed := c.red; 1413 if c.green < minValGreen then 1414 minValGreen := c.green; 1415 if c.blue < minValBlue then 1416 minValBlue := c.blue; 1417 1418 if c.alpha > maxAlpha then 1419 maxAlpha := c.alpha; 1420 if c.alpha < minAlpha then 1421 minAlpha := c.alpha; 1422 end; 1088 1423 end; 1089 1424 if not eachChannel then … … 1149 1484 end; 1150 1485 1151 psrc := bmp.Data; 1152 pdest := Result.Data; 1153 for n := bmp.Width * bmp.Height - 1 downto 0 do 1154 begin 1155 c := GammaExpansion(psrc^); 1156 Inc(psrc); 1157 c.red := ((c.red - minValRed) * factorValRed + 2047) shr 12 + addValRed; 1158 c.green := ((c.green - minValGreen) * factorValGreen + 2047) shr 12 + addValGreen; 1159 c.blue := ((c.blue - minValBlue) * factorValBlue + 2047) shr 12 + addValBlue; 1160 c.alpha := ((c.alpha - minAlpha) * factorAlpha + 2047) shr 12 + addAlpha; 1161 pdest^ := GammaCompression(c); 1162 Inc(pdest); 1486 for yb := ABounds.Top to ABounds.Bottom-1 do 1487 begin 1488 psrc := bmp.ScanLine[yb]+ABounds.Left; 1489 pdest := Result.ScanLine[yb]+ABounds.Left; 1490 for xb := xcount-1 downto 0 do 1491 begin 1492 c := GammaExpansion(psrc^); 1493 Inc(psrc); 1494 c.red := ((c.red - minValRed) * factorValRed + 2047) shr 12 + addValRed; 1495 c.green := ((c.green - minValGreen) * factorValGreen + 2047) shr 12 + addValGreen; 1496 c.blue := ((c.blue - minValBlue) * factorValBlue + 2047) shr 12 + addValBlue; 1497 c.alpha := ((c.alpha - minAlpha) * factorAlpha + 2047) shr 12 + addAlpha; 1498 pdest^ := GammaCompression(c); 1499 Inc(pdest); 1500 end; 1163 1501 end; 1164 1502 Result.InvalidateBitmap; … … 1168 1506 calculates the position in the source bitmap with an affine transformation } 1169 1507 function FilterRotate(bmp: TBGRACustomBitmap; origin: TPointF; 1170 angle: single ): TBGRACustomBitmap;1508 angle: single; correctBlur: boolean): TBGRACustomBitmap; 1171 1509 var 1172 1510 bounds: TRect; … … 1175 1513 savexysrc, pt: TPointF; 1176 1514 dx, dy: single; 1177 xb, yb: int eger;1515 xb, yb: int32or64; 1178 1516 minx, miny, maxx, maxy: single; 1517 rf : TResampleFilter; 1179 1518 1180 1519 function RotatePos(x, y: single): TPointF; … … 1188 1527 1189 1528 begin 1190 Result := bmp.NewBitmap(bmp.Width, bmp.Height);1191 1529 bounds := bmp.GetImageBounds; 1192 1530 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then 1531 begin 1532 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 1193 1533 exit; 1534 end; 1535 1536 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 1537 if correctBlur then rf := rfHalfCosine else rf := rfLinear; 1194 1538 1195 1539 //compute new bounding rectangle … … 1251 1595 for xb := bounds.left to bounds.right - 1 do 1252 1596 begin 1253 pdest^ := bmp.GetPixel(xsrc, ysrc );1597 pdest^ := bmp.GetPixel(xsrc, ysrc, rf); 1254 1598 Inc(pdest); 1255 1599 xsrc += dx; … … 1263 1607 1264 1608 { Filter grayscale applies BGRAToGrayscale function to all pixels } 1265 function FilterGrayscale(bmp: TBGRACustomBitmap): TBGRACustomBitmap;1609 procedure FilterGrayscale(bmp: TBGRACustomBitmap; ABounds: TRect; ADestination: TBGRACustomBitmap; ACheckShouldStop: TCheckShouldStopFunc); 1266 1610 var 1267 bounds: TRect;1268 1611 pdest, psrc: PBGRAPixel; 1269 xb, yb: integer; 1270 1271 begin 1272 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 1273 bounds := bmp.GetImageBounds; 1274 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then 1275 exit; 1276 1277 for yb := bounds.Top to bounds.bottom - 1 do 1278 begin 1279 pdest := Result.scanline[yb] + bounds.left; 1280 psrc := bmp.scanline[yb] + bounds.left; 1281 for xb := bounds.left to bounds.right - 1 do 1612 xb, yb: int32or64; 1613 1614 begin 1615 if IsRectEmpty(ABounds) then exit; 1616 1617 for yb := ABounds.Top to ABounds.bottom - 1 do 1618 begin 1619 if Assigned(ACheckShouldStop) and ACheckShouldStop(yb) then break; 1620 pdest := ADestination.scanline[yb] + ABounds.left; 1621 psrc := bmp.scanline[yb] + ABounds.left; 1622 for xb := ABounds.left to ABounds.right - 1 do 1282 1623 begin 1283 1624 pdest^ := BGRAToGrayscale(psrc^); … … 1286 1627 end; 1287 1628 end; 1288 Result.InvalidateBitmap; 1629 ADestination.InvalidateBitmap; 1630 end; 1631 1632 function FilterGrayscale(bmp: TBGRACustomBitmap): TBGRACustomBitmap; 1633 begin 1634 result := FilterGrayscale(bmp, rect(0,0,bmp.width,bmp.Height)); 1635 end; 1636 1637 function FilterGrayscale(bmp: TBGRACustomBitmap; ABounds: TRect): TBGRACustomBitmap; 1638 begin 1639 result := bmp.NewBitmap(bmp.Width,bmp.Height); 1640 FilterGrayscale(bmp,ABounds,result,nil); 1641 end; 1642 1643 function CreateGrayscaleTask(bmp: TBGRACustomBitmap; ABounds: TRect 1644 ): TFilterTask; 1645 begin 1646 result := TGrayscaleTask.Create(bmp,ABounds); 1289 1647 end; 1290 1648 … … 1294 1652 function FilterContour(bmp: TBGRACustomBitmap): TBGRACustomBitmap; 1295 1653 var 1296 yb, xb: int eger;1654 yb, xb: int32or64; 1297 1655 c: array[0..8] of TBGRAPixel; 1298 1656 1299 i, bmpWidth, bmpHeight: int eger;1657 i, bmpWidth, bmpHeight: int32or64; 1300 1658 slope: byte; 1301 sum: int eger;1659 sum: int32or64; 1302 1660 tempPixel: TBGRAPixel; 1303 1661 pdest, psrcUp, psrc, psrcDown: PBGRAPixel; … … 1412 1770 var 1413 1771 cx, cy, x, y, len, fact: single; 1414 xb, yb: int eger;1772 xb, yb: int32or64; 1415 1773 mask: TBGRACustomBitmap; 1416 1774 begin … … 1443 1801 1444 1802 { Applies twirl scanner. See TBGRATwirlScanner } 1445 function FilterTwirl(bmp: TBGRACustomBitmap; A Center: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap;1803 function FilterTwirl(bmp: TBGRACustomBitmap; ABounds: TRect; ACenter: TPoint; ARadius: Single; ATurn: Single=1; AExponent: Single=3): TBGRACustomBitmap; 1446 1804 var twirl: TBGRATwirlScanner; 1447 1805 begin 1448 1806 twirl := TBGRATwirlScanner.Create(bmp,ACenter,ARadius,ATurn,AExponent); 1449 1807 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 1450 result.Fill (twirl);1808 result.FillRect(ABounds, twirl, dmSet); 1451 1809 twirl.free; 1810 end; 1811 1812 function FilterTwirl(bmp: TBGRACustomBitmap; ACenter: TPoint; 1813 ARadius: Single; ATurn: Single; AExponent: Single): TBGRACustomBitmap; 1814 begin 1815 result := FilterTwirl(bmp,rect(0,0,bmp.Width,bmp.Height),ACenter,ARadius,ATurn,AExponent); 1452 1816 end; 1453 1817 … … 1458 1822 var 1459 1823 cx, cy, x, y, len, fact: single; 1460 xb, yb: int eger;1824 xb, yb: int32or64; 1461 1825 begin 1462 1826 Result := bmp.NewBitmap(bmp.Width, bmp.Height); … … 1485 1849 var 1486 1850 cy, x1, x2, y1, y2, z1, z2, h: single; 1487 yb: int eger;1851 yb: int32or64; 1488 1852 resampledBmp: TBGRACustomBitmap; 1489 resampledBmpWidth: int eger;1853 resampledBmpWidth: int32or64; 1490 1854 resampledFactor,newResampleFactor: single; 1491 1855 sub,resampledSub: TBGRACustomBitmap; 1492 1856 partRect: TRect; 1493 resampleSizeY : int eger;1857 resampleSizeY : int32or64; 1494 1858 begin 1495 1859 resampledBmp := bmp.Resample(bmp.Width*2,bmp.Height*2,rmSimpleStretch); … … 1554 1918 begin 1555 1919 if (p1.red + p1.green + p1.blue = p2.red + p2.green + p2.blue) then 1556 Result := (int eger(p1.red) shl 8) + (integer(p1.green) shl 16) +1557 int eger(p1.blue) < (integer(p2.red) shl 8) + (integer(p2.green) shl 16) +1558 int eger(p2.blue)1920 Result := (int32or64(p1.red) shl 8) + (int32or64(p1.green) shl 16) + 1921 int32or64(p1.blue) < (int32or64(p2.red) shl 8) + (int32or64(p2.green) shl 16) + 1922 int32or64(p2.blue) 1559 1923 else 1560 1924 Result := (p1.red + p1.green + p1.blue) < (p2.red + p2.green + p2.blue); … … 1564 1928 nbpix = 9; 1565 1929 var 1566 yb, xb: int eger;1567 dx, dy, n, i, j, k: int eger;1930 yb, xb: int32or64; 1931 dx, dy, n, i, j, k: int32or64; 1568 1932 a_pixels: array[0..nbpix - 1] of TBGRAPixel; 1569 1933 tempPixel, refPixel: TBGRAPixel; 1570 1934 tempValue: byte; 1571 sumR, sumG, sumB, sumA, BGRAdiv, nbA: cardinal;1935 sumR, sumG, sumB, sumA, BGRAdiv, nbA: uint32or64; 1572 1936 tempAlpha: word; 1573 1937 bounds: TRect; … … 1593 1957 for dx := -1 to 1 do 1594 1958 begin 1595 a_pixels[n] := bmp.GetPixel( integer(xb + dx), integer(yb + dy));1959 a_pixels[n] := bmp.GetPixel(xb + dx, yb + dy); 1596 1960 if a_pixels[n].alpha = 0 then 1597 1961 a_pixels[n] := BGRAPixelTransparent; … … 1695 2059 end; 1696 2060 2061 constructor TBoxBlurTask.Create(bmp: TBGRACustomBitmap; ABounds: TRect; 2062 radius: integer); 2063 begin 2064 FSource := bmp; 2065 FBounds := ABounds; 2066 FRadius := radius; 2067 end; 2068 2069 procedure TBoxBlurTask.DoExecute; 2070 type 2071 TVertical = record red,green,blue,alpha,count: NativeUint; end; 2072 PVertical = ^TVertical; 2073 var 2074 verticals: PVertical; 2075 left,right,width,height: NativeInt; 2076 delta: PtrInt; 2077 2078 procedure PrepareVerticals; 2079 var 2080 xb,yb: NativeInt; 2081 psrc,p: PBGRAPixel; 2082 pvert : PVertical; 2083 begin 2084 fillchar(verticals^, width*sizeof(TVertical), 0); 2085 psrc := FSource.ScanLine[FBounds.Top]; 2086 pvert := verticals; 2087 for xb := left to right-1 do 2088 begin 2089 p := psrc+xb; 2090 for yb := 0 to FRadius-1 do 2091 begin 2092 if yb = height then break; 2093 if p^.alpha <> 0 then 2094 begin 2095 pvert^.red += p^.red * p^.alpha; 2096 pvert^.green += p^.green * p^.alpha; 2097 pvert^.blue += p^.blue * p^.alpha; 2098 pvert^.alpha += p^.alpha; 2099 end; 2100 inc(pvert^.count); 2101 PByte(p) += delta; 2102 end; 2103 inc(pvert); 2104 end; 2105 end; 2106 2107 procedure NextVerticals(y: integer); 2108 var 2109 psrc1,psrc2: PBGRAPixel; 2110 pvert : PVertical; 2111 xb: NativeInt; 2112 begin 2113 pvert := verticals; 2114 if y-FRadius-1 >= 0 then 2115 psrc1 := FSource.ScanLine[y-FRadius-1] 2116 else 2117 psrc1 := nil; 2118 if y+FRadius < FSource.Height then 2119 psrc2 := FSource.ScanLine[y+FRadius] 2120 else 2121 psrc2 := nil; 2122 for xb := width-1 downto 0 do 2123 begin 2124 if psrc1 <> nil then 2125 begin 2126 if psrc1^.alpha <> 0 then 2127 begin 2128 {$HINTS OFF} 2129 pvert^.red -= psrc1^.red * psrc1^.alpha; 2130 pvert^.green -= psrc1^.green * psrc1^.alpha; 2131 pvert^.blue -= psrc1^.blue * psrc1^.alpha; 2132 pvert^.alpha -= psrc1^.alpha; 2133 {$HINTS ON} 2134 end; 2135 dec(pvert^.count); 2136 inc(psrc1); 2137 end; 2138 if psrc2 <> nil then 2139 begin 2140 if psrc2^.alpha <> 0 then 2141 begin 2142 pvert^.red += psrc2^.red * psrc2^.alpha; 2143 pvert^.green += psrc2^.green * psrc2^.alpha; 2144 pvert^.blue += psrc2^.blue * psrc2^.alpha; 2145 pvert^.alpha += psrc2^.alpha; 2146 end; 2147 inc(pvert^.count); 2148 inc(psrc2); 2149 end; 2150 inc(pvert); 2151 end; 2152 end; 2153 2154 procedure MainLoop; 2155 var 2156 xb,yb,xdest: NativeInt; 2157 pdest: PBGRAPixel; 2158 pvert : PVertical; 2159 sumRed,sumGreen,sumBlue,sumAlpha,sumCount: NativeUInt; 2160 begin 2161 for yb := FBounds.Top to FBounds.Bottom-1 do 2162 begin 2163 NextVerticals(yb); 2164 if GetShouldStop(yb) then exit; 2165 pdest := Destination.ScanLine[yb]+left; 2166 sumRed := 0; 2167 sumGreen := 0; 2168 sumBlue := 0; 2169 sumAlpha := 0; 2170 sumCount := 0; 2171 pvert := verticals; 2172 for xb := 0 to FRadius-1 do 2173 begin 2174 if xb = width then break; 2175 sumRed += pvert^.red; 2176 sumGreen += pvert^.green; 2177 sumBlue += pvert^.blue; 2178 sumAlpha += pvert^.alpha; 2179 sumCount += pvert^.count; 2180 inc(pvert); 2181 end; 2182 for xdest := 0 to width-1 do 2183 begin 2184 if xdest-FRadius-1 >= 0 then 2185 begin 2186 pvert := verticals+(xdest-FRadius-1); 2187 sumRed -= pvert^.red; 2188 sumGreen -= pvert^.green; 2189 sumBlue -= pvert^.blue; 2190 sumAlpha -= pvert^.alpha; 2191 sumCount -= pvert^.count; 2192 end; 2193 if xdest+FRadius < width then 2194 begin 2195 pvert := verticals+(xdest+FRadius); 2196 sumRed += pvert^.red; 2197 sumGreen += pvert^.green; 2198 sumBlue += pvert^.blue; 2199 sumAlpha += pvert^.alpha; 2200 sumCount += pvert^.count; 2201 end; 2202 if (sumCount > 0) and (sumAlpha >= (sumCount+1) shr 1) then 2203 begin 2204 pdest^.red := (sumRed+(sumAlpha shr 1)) div sumAlpha; 2205 pdest^.green := (sumGreen+(sumAlpha shr 1)) div sumAlpha; 2206 pdest^.blue := (sumBlue+(sumAlpha shr 1)) div sumAlpha; 2207 pdest^.alpha := (sumAlpha+(sumCount shr 1)) div sumCount; 2208 end else 2209 pdest^ := BGRAPixelTransparent; 2210 inc(pdest); 2211 end; 2212 end; 2213 end; 2214 2215 begin 2216 if (FBounds.Right <= FBounds.Left) or (FBounds.Bottom <= FBounds.Top) or (FRadius <= 0) then exit; 2217 left := FBounds.left; 2218 right := FBounds.right; 2219 width := right-left; 2220 height := FBounds.bottom-FBounds.top; 2221 delta := FSource.Width*SizeOf(TBGRAPixel); 2222 if FSource.LineOrder = riloBottomToTop then delta := -delta; 2223 2224 getmem(verticals, width*sizeof(TVertical)); 2225 try 2226 PrepareVerticals; 2227 MainLoop; 2228 finally 2229 freemem(verticals); 2230 end; 2231 end; 2232 2233 constructor TGrayscaleTask.Create(bmp: TBGRACustomBitmap; ABounds: TRect); 2234 begin 2235 FSource := bmp; 2236 FBounds := ABounds; 2237 end; 2238 2239 procedure TGrayscaleTask.DoExecute; 2240 begin 2241 FilterGrayscale(FSource,FBounds,Destination,@GetShouldStop); 2242 end; 2243 2244 { TCustomBlurTask } 2245 2246 constructor TCustomBlurTask.Create(bmp: TBGRACustomBitmap; ABounds: TRect; 2247 AMask: TBGRACustomBitmap; AMaskIsThreadSafe: boolean); 2248 begin 2249 FSource := bmp; 2250 FBounds := ABounds; 2251 if AMaskIsThreadSafe then 2252 begin 2253 FMask := AMask; 2254 FMaskOwned := false; 2255 end else 2256 begin 2257 FMask := AMask.Duplicate; 2258 FMaskOwned := true; 2259 end; 2260 end; 2261 2262 destructor TCustomBlurTask.Destroy; 2263 begin 2264 If FMaskOwned then FreeAndNil(FMask); 2265 inherited Destroy; 2266 end; 2267 2268 procedure TCustomBlurTask.DoExecute; 2269 begin 2270 FilterBlur(FSource,FBounds,FMask,Destination,@GetShouldStop); 2271 end; 2272 2273 constructor TMotionBlurTask.Create(ABmp: TBGRACustomBitmap; ABounds: TRect; 2274 ADistance, AAngle: single; AOriented: boolean); 2275 begin 2276 FSource := ABmp; 2277 FBounds := ABounds; 2278 FDistance := ADistance; 2279 FAngle := AAngle; 2280 FOriented:= AOriented; 2281 end; 2282 2283 procedure TMotionBlurTask.DoExecute; 2284 begin 2285 FilterBlurMotion(FSource,FBounds,FDistance,FAngle,FOriented,Destination,@GetShouldStop); 2286 end; 2287 2288 constructor TRadialPreciseBlurTask.Create(bmp: TBGRACustomBitmap; 2289 ABounds: TRect; radius: single); 2290 begin 2291 FSource := bmp; 2292 FBounds := ABounds; 2293 FRadius := radius; 2294 end; 2295 2296 procedure TRadialPreciseBlurTask.DoExecute; 2297 begin 2298 FilterBlurRadialPrecise(FSource,FBounds,FRadius,Destination,@GetShouldStop); 2299 end; 2300 2301 { TRadialBlurTask } 2302 2303 constructor TRadialBlurTask.Create(bmp: TBGRACustomBitmap; ABounds: TRect; 2304 radius: integer; blurType: TRadialBlurType); 2305 begin 2306 FSource := bmp; 2307 FBounds := ABounds; 2308 FRadius := radius; 2309 FBlurType:= blurType; 2310 end; 2311 2312 procedure TRadialBlurTask.DoExecute; 2313 begin 2314 FilterBlurRadial(FSource,FBounds,FRadius,FBlurType,Destination,@GetShouldStop); 2315 end; 2316 2317 { TFilterTask } 2318 2319 function TFilterTask.GetShouldStop(ACurrentY: integer): boolean; 2320 begin 2321 FCurrentY:= ACurrentY; 2322 if Assigned(FCheckShouldStop) then 2323 result := FCheckShouldStop(ACurrentY) 2324 else 2325 result := false; 2326 end; 2327 2328 function TFilterTask.Execute: TBGRACustomBitmap; 2329 var DestinationOwned: boolean; 2330 begin 2331 FCurrentY := 0; 2332 if Destination = nil then 2333 begin 2334 FDestination := FSource.NewBitmap(FSource.Width,FSource.Height); 2335 DestinationOwned:= true; 2336 end else 2337 DestinationOwned:= false; 2338 try 2339 DoExecute; 2340 result := Destination; 2341 FDestination := nil; 2342 except 2343 on ex: exception do 2344 begin 2345 if DestinationOwned then FreeAndNil(FDestination); 2346 raise ex; 2347 end; 2348 end; 2349 end; 2350 2351 procedure TFilterTask.SetDestination(AValue: TBGRACustomBitmap); 2352 begin 2353 if FDestination <> nil then 2354 raise exception.Create('Destination is already defined'); 2355 FDestination := AValue; 2356 end; 2357 1697 2358 end. 1698 2359 -
GraphicTest/Packages/bgrabitmap/bgrafreetype.pas
r452 r472 3 3 {$mode objfpc}{$H+} 4 4 5 { 6 Font rendering units : BGRAText, BGRATextFX, BGRAVectorize, BGRAFreeType 7 8 This units provide a font renderer with FreeType fonts, using the integrated FreeType font engine in Lazarus. 9 The simplest way to render effects is to use TBGRAFreeTypeFontRenderer class. 10 To do this, create an instance of this class and assign it to a TBGRABitmap.FontRenderer property. Now functions 11 to draw text like TBGRABitmap.TextOut will use the chosen renderer. 12 13 >> Note that you need to defined the default FreeType font collection 14 >> using LazFreeTypeFontCollection unit. 15 16 To set the effects, keep a variable containing 17 the TBGRAFreeTypeFontRenderer class and modify ShadowVisible and other effects parameters. The FontHinted property 18 allows you to choose if the font is snapped to pixels to make it more readable. 19 20 TBGRAFreeTypeDrawer class is the class that provides basic FreeType drawing 21 by deriving the TFreeTypeDrawer type. You can use it directly, but it is not 22 recommended, because there are less text layout parameters. However, it is 23 necessary if you want to create TBGRATextEffect objects using FreeType fonts. 24 } 25 5 26 interface 6 27 7 28 uses 8 Classes, SysUtils, Graphics, BGRABitmapTypes, EasyLazFreeType, FPimage;29 Types, Classes, SysUtils, Graphics, BGRABitmapTypes, EasyLazFreeType, FPimage, BGRAText, BGRATextFX, BGRAPhongTypes, LCLVersion; 9 30 10 31 type 32 TBGRAFreeTypeDrawer = class; 33 34 //this is the class to assign to FontRenderer property of TBGRABitmap 35 { TBGRAFreeTypeFontRenderer } 36 37 TBGRAFreeTypeFontRenderer = class(TBGRACustomFontRenderer) 38 private 39 FDrawer: TBGRAFreeTypeDrawer; 40 FFont: TFreeTypeFont; 41 function GetCollection: TCustomFreeTypeFontCollection; 42 function GetDrawer(ASurface: TBGRACustomBitmap): TBGRAFreeTypeDrawer; 43 function GetShaderLightPosition: TPoint; 44 procedure SetShaderLightPosition(AValue: TPoint); 45 protected 46 FShaderOwner: boolean; 47 FShader: TCustomPhongShading; 48 procedure UpdateFont; 49 procedure Init; 50 public 51 FontHinted: boolean; 52 53 ShaderActive: boolean; 54 55 ShadowVisible: boolean; 56 ShadowColor: TBGRAPixel; 57 ShadowRadius: integer; 58 ShadowOffset: TPoint; 59 60 OutlineColor: TBGRAPixel; 61 OutlineVisible,OuterOutlineOnly: boolean; 62 OutlineTexture: IBGRAScanner; 63 64 constructor Create; 65 constructor Create(AShader: TCustomPhongShading; AShaderOwner: boolean); 66 function GetFontPixelMetric: TFontPixelMetric; override; 67 procedure TextOutAngle({%H-}ADest: TBGRACustomBitmap; {%H-}x, {%H-}y: single; {%H-}orientation: integer; {%H-}s: string; {%H-}c: TBGRAPixel; {%H-}align: TAlignment); override; 68 procedure TextOutAngle({%H-}ADest: TBGRACustomBitmap; {%H-}x, {%H-}y: single; {%H-}orientation: integer; {%H-}s: string; {%H-}texture: IBGRAScanner; {%H-}align: TAlignment); override; 69 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; texture: IBGRAScanner; align: TAlignment); override; 70 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; c: TBGRAPixel; align: TAlignment); override; 71 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); override; 72 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; texture: IBGRAScanner); override; 73 function TextSize(s: string): TSize; override; 74 destructor Destroy; override; 75 property Collection: TCustomFreeTypeFontCollection read GetCollection; 76 property ShaderLightPosition: TPoint read GetShaderLightPosition write SetShaderLightPosition; 77 end; 11 78 12 79 { TBGRAFreeTypeDrawer } … … 16 83 FMask: TBGRACustomBitmap; 17 84 FColor: TBGRAPixel; 85 FInCreateTextEffect: boolean; 18 86 procedure RenderDirectly(x, y, tx: integer; data: pointer); 19 87 procedure RenderDirectlyClearType(x, y, tx: integer; data: pointer); 88 function ShadowActuallyVisible :boolean; 89 function OutlineActuallyVisible: boolean; 90 function ShaderActuallyActive : boolean; 20 91 public 21 92 Destination: TBGRACustomBitmap; 22 93 ClearTypeRGBOrder: boolean; 94 Texture: IBGRAScanner; 95 96 Shader: TCustomPhongShading; 97 ShaderActive: boolean; 98 99 ShadowVisible: boolean; 100 ShadowColor: TBGRAPixel; 101 ShadowRadius: integer; 102 ShadowOffset: TPoint; 103 104 OutlineColor: TBGRAPixel; 105 OutlineVisible,OuterOutlineOnly: boolean; 106 OutlineTexture: IBGRAScanner; 107 23 108 constructor Create(ADestination: TBGRACustomBitmap); 24 109 procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TFPColor); override; overload; 25 110 procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TBGRAPixel); overload; 26 111 procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TBGRAPixel; AAlign: TFreeTypeAlignments); overload; 112 function CreateTextEffect(AText: string; AFont: TFreeTypeRenderableFont): TBGRATextEffect; 27 113 destructor Destroy; override; 28 114 end; 29 115 116 30 117 implementation 31 118 32 uses LCLType, BGRABlend, BGRAText; 119 uses LCLType, BGRABlend, Math; 120 121 { TBGRAFreeTypeFontRenderer } 122 123 function TBGRAFreeTypeFontRenderer.GetCollection: TCustomFreeTypeFontCollection; 124 begin 125 result := EasyLazFreeType.FontCollection; 126 end; 127 128 function TBGRAFreeTypeFontRenderer.GetDrawer(ASurface: TBGRACustomBitmap): TBGRAFreeTypeDrawer; 129 begin 130 result := FDrawer; 131 result.ShadowColor := ShadowColor; 132 result.ShadowOffset := ShadowOffset; 133 result.ShadowRadius := ShadowRadius; 134 result.ShadowVisible := ShadowVisible; 135 result.ClearTypeRGBOrder := FontQuality <> fqFineClearTypeBGR; 136 result.Destination := ASurface; 137 result.OutlineColor := OutlineColor; 138 result.OutlineVisible := OutlineVisible; 139 result.OuterOutlineOnly := OuterOutlineOnly; 140 result.OutlineTexture := OutlineTexture; 141 if ShaderActive then result.Shader := FShader 142 else result.Shader := nil; 143 end; 144 145 function TBGRAFreeTypeFontRenderer.GetShaderLightPosition: TPoint; 146 begin 147 if FShader = nil then 148 result := point(0,0) 149 else 150 result := FShader.LightPosition; 151 end; 152 153 procedure TBGRAFreeTypeFontRenderer.SetShaderLightPosition(AValue: TPoint); 154 begin 155 if FShader <> nil then 156 FShader.LightPosition := AValue; 157 end; 158 159 procedure TBGRAFreeTypeFontRenderer.UpdateFont; 160 var fts: TFreeTypeStyles; 161 begin 162 fts := []; 163 if fsBold in FontStyle then fts += [ftsBold]; 164 if fsItalic in FontStyle then fts += [ftsItalic]; 165 try 166 {$IF (lcl_fullversion>=1010000)} 167 FFont.SetNameAndStyle(FontName,fts); 168 {$ELSE} 169 FFont.Name := FontName; 170 FFont.Style := fts; 171 {$ENDIF} 172 except 173 on ex: exception do 174 begin 175 end; 176 end; 177 if FontEmHeight >= 0 then 178 FFont.SizeInPixels := FontEmHeight 179 else 180 FFont.LineFullHeight := -FontEmHeight; 181 case FontQuality of 182 fqSystem: 183 begin 184 FFont.Quality := grqMonochrome; 185 FFont.ClearType := false; 186 end; 187 fqSystemClearType: 188 begin 189 FFont.Quality:= grqLowQuality; 190 FFont.ClearType:= true; 191 end; 192 fqFineAntialiasing: 193 begin 194 FFont.Quality:= grqHighQuality; 195 FFont.ClearType:= false; 196 end; 197 fqFineClearTypeRGB,fqFineClearTypeBGR: 198 begin 199 FFont.Quality:= grqHighQuality; 200 FFont.ClearType:= true; 201 end; 202 end; 203 FFont.Hinted := FontHinted; 204 {$IF (lcl_fullversion>=1010000)} 205 FFont.StrikeOutDecoration := fsStrikeOut in FontStyle; 206 FFont.UnderlineDecoration := fsUnderline in FontStyle; 207 {$ENDIF} 208 end; 209 210 procedure TBGRAFreeTypeFontRenderer.Init; 211 begin 212 ShaderActive := true; 213 214 FDrawer := TBGRAFreeTypeDrawer.Create(nil); 215 FFont := TFreeTypeFont.Create; 216 FontHinted:= True; 217 218 ShadowColor := BGRABlack; 219 ShadowVisible := false; 220 ShadowOffset := Point(5,5); 221 ShadowRadius := 5; 222 end; 223 224 constructor TBGRAFreeTypeFontRenderer.Create; 225 begin 226 Init; 227 end; 228 229 constructor TBGRAFreeTypeFontRenderer.Create(AShader: TCustomPhongShading; 230 AShaderOwner: boolean); 231 begin 232 Init; 233 FShader := AShader; 234 FShaderOwner := AShaderOwner; 235 end; 236 237 function TBGRAFreeTypeFontRenderer.GetFontPixelMetric: TFontPixelMetric; 238 begin 239 UpdateFont; 240 result.Baseline := round(FFont.Ascent); 241 result.CapLine:= round(FFont.Ascent*0.2); 242 result.DescentLine:= round(FFont.Ascent+FFont.Descent); 243 result.Lineheight := round(FFont.LineFullHeight); 244 result.xLine := round(FFont.Ascent*0.45); 245 result.Defined := True; 246 end; 247 248 procedure TBGRAFreeTypeFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 249 y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); 250 begin 251 252 end; 253 254 procedure TBGRAFreeTypeFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 255 y: single; orientation: integer; s: string; texture: IBGRAScanner; 256 align: TAlignment); 257 begin 258 259 end; 260 261 procedure TBGRAFreeTypeFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 262 y: single; s: string; texture: IBGRAScanner; align: TAlignment); 263 begin 264 FDrawer.Texture := texture; 265 TextOut(ADest,x,y,s,BGRAWhite,align); 266 FDrawer.Texture := nil; 267 end; 268 269 procedure TBGRAFreeTypeFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 270 y: single; s: string; c: TBGRAPixel; align: TAlignment); 271 var 272 ftaAlign: TFreeTypeAlignments; 273 begin 274 UpdateFont; 275 ftaAlign:= [ftaTop]; 276 case align of 277 taLeftJustify: ftaAlign += [ftaLeft]; 278 taCenter: ftaAlign += [ftaCenter]; 279 taRightJustify: ftaAlign += [ftaRight]; 280 end; 281 GetDrawer(ADest).DrawText(s,FFont,x,y,BGRAToFPColor(c),ftaAlign); 282 end; 283 284 procedure TBGRAFreeTypeFontRenderer.TextRect(ADest: TBGRACustomBitmap; 285 ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); 286 var align: TFreeTypeAlignments; 287 intersectedClip,previousClip: TRect; 288 begin 289 previousClip := ADest.ClipRect; 290 if style.Clipping then 291 begin 292 intersectedClip := rect(0,0,0,0); 293 if not IntersectRect(intersectedClip, previousClip, ARect) then exit; 294 ADest.ClipRect := intersectedClip; 295 end; 296 UpdateFont; 297 align := []; 298 case style.Alignment of 299 taCenter: begin ARect.Left := x; align += [ftaCenter]; end; 300 taRightJustify: begin ARect.Left := x; align += [ftaRight]; end; 301 else 302 align += [ftaLeft]; 303 end; 304 case style.Layout of 305 {$IF (lcl_fullversion>=1010000)} 306 tlCenter: begin ARect.Top := y; align += [ftaVerticalCenter]; end; 307 {$ENDIF} 308 tlBottom: begin ARect.top := y; align += [ftaBottom]; end; 309 else align += [ftaTop]; 310 end; 311 try 312 {$IF (lcl_fullversion>=1010000)} 313 if style.Wordbreak then 314 GetDrawer(ADest).DrawTextRect(s, FFont, ARect.Left,ARect.Top,ARect.Right,ARect.Bottom,BGRAToFPColor(c),align) 315 else 316 {$ENDIF} 317 begin 318 case style.Layout of 319 tlCenter: y := (ARect.Top+ARect.Bottom) div 2; 320 tlBottom: y := ARect.Bottom; 321 else 322 y := ARect.Top; 323 end; 324 case style.Alignment of 325 taLeftJustify: GetDrawer(ADest).DrawText(s,FFont,ARect.Left,y,BGRAToFPColor(c),align); 326 taCenter: GetDrawer(ADest).DrawText(s,FFont,(ARect.Left+ARect.Right-1) div 2,y,BGRAToFPColor(c),align); 327 taRightJustify: GetDrawer(ADest).DrawText(s,FFont,ARect.Right,y,BGRAToFPColor(c),align); 328 end; 329 end; 330 finally 331 if style.Clipping then 332 ADest.ClipRect := previousClip; 333 end; 334 end; 335 336 procedure TBGRAFreeTypeFontRenderer.TextRect(ADest: TBGRACustomBitmap; 337 ARect: TRect; x, y: integer; s: string; style: TTextStyle; 338 texture: IBGRAScanner); 339 begin 340 FDrawer.Texture := texture; 341 TextRect(ADest,ARect,x,y,s,style,BGRAWhite); 342 FDrawer.Texture := nil; 343 end; 344 345 function TBGRAFreeTypeFontRenderer.TextSize(s: string): TSize; 346 begin 347 result.cx := round(FFont.TextWidth(s)); 348 result.cy := round(FFont.LineFullHeight); 349 end; 350 351 destructor TBGRAFreeTypeFontRenderer.Destroy; 352 begin 353 FDrawer.Free; 354 FFont.Free; 355 if FShaderOwner then FShader.Free; 356 inherited Destroy; 357 end; 33 358 34 359 { TBGRAFreeTypeDrawer } … … 45 370 if (y < 0) or (y >= Destination.height) or (x < 0) or (x > Destination.width-tx) then exit; 46 371 47 c := FColor;48 372 psrc := pbyte(data); 49 373 pdest := Destination.ScanLine[y]+x; 50 while tx > 0 do 51 begin 52 DrawPixelInlineWithAlphaCheck(pdest,c,psrc^); 53 inc(psrc); 54 inc(pdest); 55 dec(tx); 374 if Texture = nil then 375 begin 376 c := FColor; 377 while tx > 0 do 378 begin 379 DrawPixelInlineWithAlphaCheck(pdest,c,psrc^); 380 inc(psrc); 381 inc(pdest); 382 dec(tx); 383 end; 384 end else 385 begin 386 Texture.ScanMoveTo(x,y); 387 while tx > 0 do 388 begin 389 DrawPixelInlineWithAlphaCheck(pdest,Texture.ScanNextPixel,psrc^); 390 inc(psrc); 391 inc(pdest); 392 dec(tx); 393 end; 56 394 end; 57 395 end; … … 95 433 pdest^.blue := ((psrc+1)^ + (psrc+2)^ + (psrc+2)^) div 3; 96 434 end; 97 BGRAFillClearTypeRGBMask(Destination,x div 3,y,FMask,FColor,nil,ClearTypeRGBOrder); 98 end; 435 BGRAFillClearTypeRGBMask(Destination,x div 3,y,FMask,FColor,Texture,ClearTypeRGBOrder); 436 end; 437 end; 438 439 function TBGRAFreeTypeDrawer.ShadowActuallyVisible: boolean; 440 begin 441 result := ShadowVisible and (ShadowColor.alpha <> 0); 442 end; 443 444 function TBGRAFreeTypeDrawer.OutlineActuallyVisible: boolean; 445 begin 446 result := ((OutlineTexture <> nil) or (OutlineColor.alpha <> 0)) and OutlineVisible; 447 end; 448 449 function TBGRAFreeTypeDrawer.ShaderActuallyActive: boolean; 450 begin 451 result := (Shader <> nil) and ShaderActive; 99 452 end; 100 453 … … 103 456 Destination := ADestination; 104 457 ClearTypeRGBOrder:= true; 458 ShaderActive := true; 105 459 end; 106 460 107 461 procedure TBGRAFreeTypeDrawer.DrawText(AText: string; 108 462 AFont: TFreeTypeRenderableFont; x, y: single; AColor: TFPColor); 109 begin 110 FColor := FPColorToBGRA(AColor); 111 if AFont.ClearType then 112 AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectlyClearType) 113 else 114 AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectly); 463 var fx: TBGRATextEffect; 464 procedure DoOutline; 465 begin 466 if OutlineActuallyVisible then 467 begin 468 if OutlineTexture <> nil then 469 fx.DrawOutline(Destination,round(x),round(y), OutlineTexture) 470 else 471 fx.DrawOutline(Destination,round(x),round(y), OutlineColor); 472 end; 473 end; 474 begin 475 if not FInCreateTextEffect and (ShadowActuallyVisible or OutlineActuallyVisible or ShaderActuallyActive) then 476 begin 477 fx := CreateTextEffect(AText, AFont); 478 y -= AFont.Ascent; 479 if ShadowActuallyVisible then fx.DrawShadow(Destination, round(x+ShadowOffset.X),round(y+ShadowOffset.Y), ShadowRadius, ShadowColor); 480 if OuterOutlineOnly then DoOutline; 481 482 if texture <> nil then 483 begin 484 if ShaderActuallyActive then 485 fx.DrawShaded(Destination,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), texture) 486 else 487 fx.Draw(Destination,round(x),round(y), texture); 488 end else 489 begin 490 if ShaderActuallyActive then 491 fx.DrawShaded(Destination,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), FPColorToBGRA(AColor)) 492 else 493 fx.Draw(Destination,round(x),round(y), FPColorToBGRA(AColor)); 494 end; 495 if not OuterOutlineOnly then DoOutline; 496 fx.Free; 497 end else 498 begin 499 FColor := FPColorToBGRA(AColor); 500 if AFont.ClearType then 501 AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectlyClearType) 502 else 503 AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectly); 504 end; 115 505 end; 116 506 … … 128 518 end; 129 519 520 function TBGRAFreeTypeDrawer.CreateTextEffect(AText: string; 521 AFont: TFreeTypeRenderableFont): TBGRATextEffect; 522 var 523 mask: TBGRACustomBitmap; 524 tx,ty,marginHoriz,marginVert: integer; 525 tempDest: TBGRACustomBitmap; 526 tempTex: IBGRAScanner; 527 tempClearType: boolean; 528 begin 529 FInCreateTextEffect:= True; 530 try 531 tx := ceil(AFont.TextWidth(AText)); 532 ty := ceil(AFont.TextHeight(AText)); 533 marginHoriz := ty div 2; 534 marginVert := 1; 535 mask := BGRABitmapFactory.Create(tx+2*marginHoriz,ty+2*marginVert,BGRABlack); 536 tempDest := Destination; 537 tempTex := Texture; 538 tempClearType:= AFont.ClearType; 539 Destination := mask; 540 Texture := nil; 541 AFont.ClearType := false; 542 DrawText(AText,AFont,marginHoriz,marginVert,BGRAWhite,[ftaTop,ftaLeft]); 543 Destination := tempDest; 544 Texture := tempTex; 545 AFont.ClearType := tempClearType; 546 mask.ConvertToLinearRGB; 547 result := TBGRATextEffect.Create(mask, true,tx,ty,point(-marginHoriz,-marginVert)); 548 finally 549 FInCreateTextEffect:= false; 550 end; 551 end; 552 130 553 destructor TBGRAFreeTypeDrawer.Destroy; 131 554 begin -
GraphicTest/Packages/bgrabitmap/bgragradients.pas
r452 r472 2 2 3 3 {$mode objfpc}{$H+} 4 5 {$i bgrasse.inc} 4 6 5 7 interface … … 115 117 Color : TBGRAPixel); 116 118 117 {$ifdef CPUI386}119 {$ifdef BGRASSE_AVAILABLE} 118 120 procedure DrawMapSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; mapAltitude: integer; ofsX,ofsY: integer; 119 121 ColorMap : TBGRACustomBitmap); … … 174 176 implementation 175 177 176 uses Types, SysUtils, BGRATextFX;178 uses GraphType, Types, SysUtils, BGRATextFX; {GraphType unit used by phongdraw.inc} 177 179 178 180 function TextShadow(AWidth, AHeight: Integer; AText: String; … … 375 377 Color : TBGRAPixel); 376 378 begin 377 {$ifdef CPUI386}379 {$ifdef BGRASSE_AVAILABLE} 378 380 if UseSSE then 379 381 DrawColorSSE(dest,map,mapAltitude,ofsX,ofsY,Color) … … 386 388 mapAltitude: integer; ofsX, ofsY: integer; ColorMap: TBGRACustomBitmap); 387 389 begin 388 {$ifdef CPUI386}390 {$ifdef BGRASSE_AVAILABLE} 389 391 if UseSSE then 390 392 DrawMapSSE(dest,map,mapAltitude,ofsX,ofsY,ColorMap) … … 397 399 mapAltitude: integer; ofsX, ofsY: integer; ColorScan: IBGRAScanner); 398 400 begin 399 {$ifdef CPUI386}401 {$ifdef BGRASSE_AVAILABLE} 400 402 if UseSSE then 401 403 DrawScannerSSE(dest,map,mapAltitude,ofsX,ofsY,ColorScan) … … 575 577 {$I phongdraw.inc } 576 578 577 {$ifdef CPUI386}579 {$ifdef BGRASSE_AVAILABLE} 578 580 procedure TPhongShading.DrawMapSSE(dest: TBGRACustomBitmap; map: TBGRACustomBitmap; 579 581 mapAltitude: integer; ofsX, ofsY: integer; ColorMap: TBGRACustomBitmap); … … 1087 1089 end; 1088 1090 1091 initialization 1092 1093 Randomize; 1094 1089 1095 end. 1090 1096 -
GraphicTest/Packages/bgrabitmap/bgragradientscanner.pas
r452 r472 108 108 end; 109 109 110 { TBGRAConstantScanner } 111 112 TBGRAConstantScanner = class(TBGRAGradientScanner) 113 constructor Create(c: TBGRAPixel); 114 end; 115 116 { TBGRARandomScanner } 117 118 TBGRARandomScanner = class(TBGRACustomScanner) 119 private 120 FOpacity: byte; 121 FGrayscale: boolean; 122 public 123 constructor Create(AGrayscale: Boolean; AOpacity: byte); 124 function ScanAtInteger({%H-}X, {%H-}Y: integer): TBGRAPixel; override; 125 function ScanNextPixel: TBGRAPixel; override; 126 function ScanAt({%H-}X, {%H-}Y: Single): TBGRAPixel; override; 127 end; 128 110 129 { TBGRAGradientTriangleScanner } 111 130 … … 184 203 185 204 uses BGRABlend; 205 206 { TBGRAConstantScanner } 207 208 constructor TBGRAConstantScanner.Create(c: TBGRAPixel); 209 begin 210 inherited Create(c,c,gtLinear,PointF(0,0),PointF(0,0),false); 211 end; 212 213 { TBGRARandomScanner } 214 215 constructor TBGRARandomScanner.Create(AGrayscale: Boolean; AOpacity: byte); 216 begin 217 FGrayscale:= AGrayscale; 218 FOpacity:= AOpacity; 219 end; 220 221 function TBGRARandomScanner.ScanAtInteger(X, Y: integer): TBGRAPixel; 222 begin 223 Result:=ScanNextPixel; 224 end; 225 226 function TBGRARandomScanner.ScanNextPixel: TBGRAPixel; 227 begin 228 if FGrayscale then 229 begin 230 result.red := random(256); 231 result.green := result.red; 232 result.blue := result.red; 233 result.alpha:= FOpacity; 234 end else 235 Result:= BGRA(random(256),random(256),random(256),FOpacity); 236 end; 237 238 function TBGRARandomScanner.ScanAt(X, Y: Single): TBGRAPixel; 239 begin 240 Result:=ScanNextPixel; 241 end; 186 242 187 243 { TBGRAHueGradient } … … 758 814 InitScanInline(X,Y); 759 815 if FVertical then 760 FHorizColor := Scan At(X,Y);816 FHorizColor := ScanNextInline; 761 817 end; 762 818 … … 1247 1303 end; 1248 1304 1305 initialization 1306 1307 Randomize; 1308 1249 1309 end. 1250 1310 -
GraphicTest/Packages/bgrabitmap/bgragtkbitmap.pas
r452 r472 65 65 gdk, gtkdef, gtkProc, gdkpixbuf, glib, 66 66 {$ENDIF} 67 FPImage ;67 FPImage, Dialogs; 68 68 69 69 {$IFDEF LCLgtk2} … … 141 141 end; 142 142 143 //SwapRedBlue;143 SwapRedBlue; 144 144 145 145 P := Rect.TopLeft; 146 DpToLP(ACanvas.Handle, P, 1);146 LPToDP(ACanvas.Handle, P, 1); 147 147 gdk_pixbuf_render_to_drawable(FPixBuf, 148 148 TGtkDeviceContext(ACanvas.Handle).Drawable, 149 149 TGtkDeviceContext(ACanvas.Handle).GC, 150 0,0, 151 TGtkDeviceContext(ACanvas.Handle).Offset.X + P.X, 152 TGtkDeviceContext(ACanvas.Handle).Offset.Y + P.Y, 150 0,0, P.X,P.Y, 153 151 Width,Height, 154 152 GDK_RGB_DITHER_NORMAL,0,0); 155 153 156 //SwapRedBlue;154 SwapRedBlue; 157 155 end; 158 156 … … 251 249 252 250 dest := ACanvas.Handle; 253 pos := TGtkDeviceContext(dest).Offset; 254 pos.X += rect.Left; 255 pos.Y += rect.Top; 251 pos := rect.TopLeft; 252 LPtoDP(dest, pos, 1); 256 253 If ALineOrder = riloBottomToTop then VerticalFlip; 257 //SwapRedBlue;254 SwapRedBlue; 258 255 gdk_draw_rgb_32_image(TGtkDeviceContext(dest).Drawable, 259 TGtkDeviceContext(Dest).GC, pos. X,pos.Y,256 TGtkDeviceContext(Dest).GC, pos.x,pos.y, 260 257 AWidth,AHeight, GDK_RGB_DITHER_NORMAL, 261 258 AData, AWidth*sizeof(TBGRAPixel)); 262 //SwapRedBlue;259 SwapRedBlue; 263 260 If ALineOrder = riloBottomToTop then VerticalFlip; 264 261 end; … … 296 293 297 294 P := Point(x,y); 298 DpToLP(CanvasSource.Handle, P, 1);295 LPToDP(CanvasSource.Handle, P, 1); 299 296 gdk_pixbuf_get_from_drawable(FPixBuf, 300 297 TGtkDeviceContext(CanvasSource.Handle).Drawable, 301 nil, 302 TGtkDeviceContext(CanvasSource.Handle).Offset.X+P.X, 303 TGtkDeviceContext(CanvasSource.Handle).Offset.Y+P.Y,0,0,Width,Height); 298 nil, P.X,P.Y,0,0,Width,Height); 304 299 SwapRedBlue; 305 300 InvalidateBitmap; -
GraphicTest/Packages/bgrabitmap/bgralayers.pas
r452 r472 14 14 TBGRALayeredBitmap = class; 15 15 TBGRALayeredBitmapClass = class of TBGRALayeredBitmap; 16 17 TBGRALayeredBitmapSaveToStreamProc = procedure(AStream: TStream; ALayers: TBGRACustomLayeredBitmap); 18 TBGRALayeredBitmapLoadFromStreamProc = function(AStream: TStream): TBGRALayeredBitmap; 16 19 17 20 { TBGRACustomLayeredBitmap } … … 36 39 function GetLayerName(layer: integer): string; virtual; 37 40 function GetLayerOffset(layer: integer): TPoint; virtual; 38 function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; virtual;39 41 function GetLayerFrozenRange(layer: integer): integer; 40 42 function GetLayerFrozen(layer: integer): boolean; virtual; 43 function GetLayerUniqueId(layer: integer): integer; virtual; 41 44 procedure SetLayerFrozen(layer: integer; AValue: boolean); virtual; 42 45 function RangeIntersect(first1,last1,first2,last2: integer): boolean; … … 50 53 51 54 public 52 procedure SaveToFile(const filename : string); override;55 procedure SaveToFile(const filenameUTF8: string); override; 53 56 procedure SaveToStream(Stream: TStream); override; 54 57 constructor Create; override; 55 58 destructor Destroy; override; 56 59 function ToString: ansistring; override; 60 function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; virtual; 57 61 function GetLayerBitmapCopy(layer: integer): TBGRABitmap; virtual; abstract; 58 62 function ComputeFlatImage: TBGRABitmap; overload; … … 80 84 property LayerOffset[layer: integer]: TPoint read GetLayerOffset; 81 85 property LayerFrozen[layer: integer]: boolean read GetLayerFrozen; 86 property LayerUniqueId[layer: integer]: integer read GetLayerUniqueId; 82 87 property LinearBlend: boolean read GetLinearBlend write SetLinearBlend; //use linear blending unless specified 83 88 property DefaultBlendingOperation: TBlendOperation read GetDefaultBlendingOperation; … … 103 108 FLayers: array of TBGRALayerInfo; 104 109 FWidth,FHeight: integer; 105 function GetLayerUniqueId(layer: integer): integer;106 procedure SetLayerUniqueId(layer: integer; AValue: integer);107 110 108 111 protected … … 122 125 procedure SetLayerName(layer: integer; AValue: string); 123 126 procedure SetLayerFrozen(layer: integer; AValue: boolean); override; 124 function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; override; 127 function GetLayerUniqueId(layer: integer): integer; override; 128 procedure SetLayerUniqueId(layer: integer; AValue: integer); 125 129 126 130 public 127 procedure LoadFromFile(const filename : string); override;131 procedure LoadFromFile(const filenameUTF8: string); override; 128 132 procedure LoadFromStream(stream: TStream); override; 129 133 procedure SetSize(AWidth, AHeight: integer); virtual; … … 155 159 function AddOwnedLayer(ABitmap: TBGRABitmap; BlendOp: TBlendOperation; Opacity: byte = 255): integer; overload; 156 160 destructor Destroy; override; 157 constructor Create; override; 158 constructor Create(AWidth, AHeight: integer); 161 constructor Create; override; overload; 162 constructor Create(AWidth, AHeight: integer); virtual; overload; 163 function GetLayerBitmapDirectly(layer: integer): TBGRABitmap; override; 159 164 function GetLayerBitmapCopy(layer: integer): TBGRABitmap; override; 160 165 function GetLayerIndexFromId(AIdentifier: integer): integer; 161 166 function Duplicate(ASharedLayerIds: boolean = false): TBGRALayeredBitmap; 167 function ProduceLayerUniqueId: integer; 162 168 163 169 procedure RotateCW; … … 180 186 end; 181 187 182 procedure RegisterLayeredBitmapWriter(AExtension: string; AWriter: TBGRALayeredBitmapClass); 183 procedure RegisterLayeredBitmapReader(AExtension: string; AReader: TBGRACustomLayeredBitmapClass); 188 procedure RegisterLayeredBitmapWriter(AExtensionUTF8: string; AWriter: TBGRALayeredBitmapClass); 189 procedure RegisterLayeredBitmapReader(AExtensionUTF8: string; AReader: TBGRACustomLayeredBitmapClass); 190 191 var 192 LayeredBitmapSaveToStreamProc : TBGRALayeredBitmapSaveToStreamProc; 193 LayeredBitmapLoadFromStreamProc : TBGRALayeredBitmapLoadFromStreamProc; 194 195 type 196 TOnLayeredBitmapLoadStartProc = procedure(AFilenameUTF8: string) of object; 197 TOnLayeredBitmapLoadProgressProc = procedure(APercentage: integer) of object; 198 TOnLayeredBitmapLoadedProc = procedure() of object; 199 200 procedure OnLayeredBitmapLoadFromStreamStart; 201 procedure OnLayeredBitmapLoadStart(AFilenameUTF8: string); 202 procedure OnLayeredBitmapLoadProgress(APercentage: integer); 203 procedure OnLayeredBitmapLoaded(); 204 procedure RegisterLoadingHandler(AStart: TOnLayeredBitmapLoadStartProc; AProgress: TOnLayeredBitmapLoadProgressProc; 205 ADone: TOnLayeredBitmapLoadedProc); 206 procedure UnregisterLoadingHandler(AStart: TOnLayeredBitmapLoadStartProc; AProgress: TOnLayeredBitmapLoadProgressProc; 207 ADone: TOnLayeredBitmapLoadedProc); 184 208 185 209 implementation 210 211 uses LCLProc; 212 213 var 214 OnLayeredBitmapLoadStartProc: TOnLayeredBitmapLoadStartProc; 215 OnLayeredBitmapLoadProgressProc: TOnLayeredBitmapLoadProgressProc; 216 OnLayeredBitmapLoadedProc: TOnLayeredBitmapLoadedProc; 186 217 187 218 var … … 380 411 end; 381 412 382 procedure TBGRALayeredBitmap.LoadFromFile(const filename : string);413 procedure TBGRALayeredBitmap.LoadFromFile(const filenameUTF8: string); 383 414 var bmp: TBGRABitmap; 384 415 index: integer; … … 387 418 i: integer; 388 419 begin 389 ext := lowercase(ExtractFileExt(filename));420 ext := UTF8LowerCase(ExtractFileExt(filenameUTF8)); 390 421 for i := 0 to high(LayeredBitmapReaders) do 391 422 if '.'+LayeredBitmapReaders[i].extension = ext then … … 393 424 temp := LayeredBitmapReaders[i].theClass.Create; 394 425 try 395 temp.LoadFromFile(filename );426 temp.LoadFromFile(filenameUTF8); 396 427 Assign(temp); 397 428 finally … … 401 432 end; 402 433 403 bmp := TBGRABitmap.Create(filename );434 bmp := TBGRABitmap.Create(filenameUTF8, True); 404 435 Clear; 405 436 SetSize(bmp.Width,bmp.Height); … … 411 442 var bmp: TBGRABitmap; 412 443 index: integer; 413 begin 444 temp: TBGRALayeredBitmap; 445 begin 446 if Assigned(LayeredBitmapLoadFromStreamProc) then 447 begin 448 temp := LayeredBitmapLoadFromStreamProc(Stream); 449 if temp <> nil then 450 begin 451 Assign(temp); 452 temp.Free; 453 exit; 454 end; 455 end; 414 456 bmp := TBGRABitmap.Create(stream); 415 457 Clear; … … 538 580 FLayers[FNbLayers].Visible := true; 539 581 FLayers[FNbLayers].Frozen := false; 540 FLayers[FNbLayers].UniqueId := InterLockedIncrement(NextLayerUniqueId);582 FLayers[FNbLayers].UniqueId := ProduceLayerUniqueId; 541 583 if Shared then 542 584 begin … … 694 736 result := TBGRALayeredBitmap.Create; 695 737 result.Assign(self, ASharedLayerIds); 738 end; 739 740 function TBGRALayeredBitmap.ProduceLayerUniqueId: integer; 741 begin 742 result := InterLockedIncrement(NextLayerUniqueId); 696 743 end; 697 744 … … 841 888 end; 842 889 result := false; 890 end; 891 892 function TBGRACustomLayeredBitmap.GetLayerUniqueId(layer: integer): integer; 893 begin 894 result := layer; 843 895 end; 844 896 … … 903 955 end; 904 956 905 procedure TBGRACustomLayeredBitmap.SaveToFile(const filename : string);957 procedure TBGRACustomLayeredBitmap.SaveToFile(const filenameUTF8: string); 906 958 var bmp: TBGRABitmap; 907 959 ext: string; … … 909 961 i: integer; 910 962 begin 911 ext := lowercase(ExtractFileExt(filename));963 ext := UTF8LowerCase(ExtractFileExt(filenameUTF8)); 912 964 for i := 0 to high(LayeredBitmapWriters) do 913 965 if '.'+LayeredBitmapWriters[i].extension = ext then … … 916 968 try 917 969 temp.Assign(self); 918 temp.SaveToFile(filename );970 temp.SaveToFile(filenameUTF8); 919 971 finally 920 972 temp.Free; … … 925 977 bmp := ComputeFlatImage; 926 978 try 927 bmp.SaveToFile (filename);979 bmp.SaveToFileUTF8(filenameUTF8); 928 980 finally 929 981 bmp.Free; … … 933 985 procedure TBGRACustomLayeredBitmap.SaveToStream(Stream: TStream); 934 986 begin 935 raise exception.Create('Not implemented'); 987 if Assigned(LayeredBitmapSaveToStreamProc) then 988 LayeredBitmapSaveToStreamProc(Stream, self) 989 else 990 raise exception.Create('Call BGRAStreamLayers.RegisterStreamLayers first'); 936 991 end; 937 992 … … 1188 1243 linear := false; //to avoid hint 1189 1244 for j := firstlayer to lastLayer do 1190 if (BlendOperation[j] in [boTransparent,boLinearBlend]) or (start = 0) then1245 if (BlendOperation[j] in [boTransparent,boLinearBlend]) or (start = 0) or ((firstlayer= 0) and (j=0)) then 1191 1246 begin 1192 1247 nextLinear := (BlendOperation[j] = boLinearBlend) or self.LinearBlend; … … 1239 1294 end; 1240 1295 1241 procedure RegisterLayeredBitmapReader(AExtension : string; AReader: TBGRACustomLayeredBitmapClass);1296 procedure RegisterLayeredBitmapReader(AExtensionUTF8: string; AReader: TBGRACustomLayeredBitmapClass); 1242 1297 begin 1243 1298 setlength(LayeredBitmapReaders,length(LayeredBitmapReaders)+1); 1244 1299 with LayeredBitmapReaders[high(LayeredBitmapReaders)] do 1245 1300 begin 1246 extension:= AExtension;1301 extension:= UTF8LowerCase(AExtensionUTF8); 1247 1302 theClass := AReader; 1248 1303 end; 1249 1304 end; 1250 1305 1251 procedure RegisterLayeredBitmapWriter(AExtension: string; AWriter: TBGRALayeredBitmapClass); 1252 begin 1306 procedure OnLayeredBitmapLoadFromStreamStart; 1307 begin 1308 OnLayeredBitmapLoadStart('<Stream>'); 1309 end; 1310 1311 procedure OnLayeredBitmapLoadStart(AFilenameUTF8: string); 1312 begin 1313 if Assigned(OnLayeredBitmapLoadStartProc) then 1314 OnLayeredBitmapLoadStartProc(AFilenameUTF8); 1315 end; 1316 1317 procedure OnLayeredBitmapLoadProgress(APercentage: integer); 1318 begin 1319 if Assigned(OnLayeredBitmapLoadProgressProc) then 1320 OnLayeredBitmapLoadProgressProc(APercentage); 1321 end; 1322 1323 procedure OnLayeredBitmapLoaded; 1324 begin 1325 if Assigned(OnLayeredBitmapLoadedProc) then 1326 OnLayeredBitmapLoadedProc(); 1327 end; 1328 1329 procedure RegisterLoadingHandler(AStart: TOnLayeredBitmapLoadStartProc; 1330 AProgress: TOnLayeredBitmapLoadProgressProc; ADone: TOnLayeredBitmapLoadedProc 1331 ); 1332 begin 1333 OnLayeredBitmapLoadProgressProc:= AProgress; 1334 OnLayeredBitmapLoadStartProc := AStart; 1335 OnLayeredBitmapLoadedProc:= ADone; 1336 end; 1337 1338 procedure UnregisterLoadingHandler(AStart: TOnLayeredBitmapLoadStartProc; 1339 AProgress: TOnLayeredBitmapLoadProgressProc; ADone: TOnLayeredBitmapLoadedProc); 1340 begin 1341 if OnLayeredBitmapLoadProgressProc = AProgress then OnLayeredBitmapLoadProgressProc := nil; 1342 if OnLayeredBitmapLoadStartProc = AStart then OnLayeredBitmapLoadStartProc := nil; 1343 if OnLayeredBitmapLoadedProc = ADone then OnLayeredBitmapLoadedProc := nil; 1344 end; 1345 1346 procedure RegisterLayeredBitmapWriter(AExtensionUTF8: string; AWriter: TBGRALayeredBitmapClass); 1347 begin 1348 while (length(AExtensionUTF8)>0) and (AExtensionUTF8[1]='.') do delete(AExtensionUTF8,1,1); 1253 1349 setlength(LayeredBitmapWriters,length(LayeredBitmapWriters)+1); 1254 1350 with LayeredBitmapWriters[high(LayeredBitmapWriters)] do 1255 1351 begin 1256 extension:= AExtension;1352 extension:= UTF8LowerCase(AExtensionUTF8); 1257 1353 theClass := AWriter; 1258 1354 end; -
GraphicTest/Packages/bgrabitmap/bgramatrix3d.pas
r452 r472 3 3 {$mode objfpc}{$H+} 4 4 5 {$ifdef CPUI386} 5 {$i bgrasse.inc} 6 {$ifdef BGRASSE_AVAILABLE} 6 7 {$asmmode intel} 7 8 {$endif} … … 14 15 type 15 16 TMatrix3D = packed array[1..3,1..4] of single; 17 TProjection3D = packed record 18 Zoom, Center: TPointF; 19 end; 16 20 17 21 operator*(const A: TMatrix3D; const M: TPoint3D): TPoint3D; 18 operator*(const A: TMatrix3D; var M: TPoint3D_128): TPoint3D_128; 22 operator*(constref A: TMatrix3D; var M: TPoint3D_128): TPoint3D_128; 23 function MultiplyVect3DWithoutTranslation(constref A: TMatrix3D; constref M: TPoint3D_128): TPoint3D_128; 19 24 operator*(A,B: TMatrix3D): TMatrix3D; 20 25 … … 30 35 function MatrixRotateZ(angle: single): TMatrix3D; 31 36 32 {$IFDEF CPUI386}37 {$IFDEF BGRASSE_AVAILABLE} 33 38 procedure Matrix3D_SSE_Load(const A: TMatrix3D); 34 39 procedure MatrixMultiplyVect3D_SSE_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 35 40 procedure MatrixMultiplyVect3D_SSE3_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 41 procedure MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 42 procedure MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 36 43 {$ENDIF} 37 44 … … 52 59 end; 53 60 54 {$IFDEF CPUI386}61 {$IFDEF BGRASSE_AVAILABLE} 55 62 var SingleConst1 : single = 1; 56 63 57 procedure Matrix3D_SSE_Load(const A: TMatrix3D); 58 begin 59 asm 60 mov eax, A 61 movups xmm5, [eax] 62 movups xmm6, [eax+16] 63 movups xmm7, [eax+32] 64 end; 65 end; 64 procedure Matrix3D_SSE_Load(const A: TMatrix3D); 65 begin 66 {$IFDEF cpux86_64} 67 asm 68 mov rax, A 69 movups xmm5, [rax] 70 movups xmm6, [rax+16] 71 movups xmm7, [rax+32] 72 end; 73 {$ELSE} 74 asm 75 mov eax, A 76 movups xmm5, [eax] 77 movups xmm6, [eax+16] 78 movups xmm7, [eax+32] 79 end; 80 {$ENDIF} 81 end; 66 82 67 83 procedure MatrixMultiplyVect3D_SSE_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); … … 70 86 oldMt := M.t; 71 87 M.t := SingleConst1; 88 {$IFDEF cpux86_64} 89 asm 90 mov rax, M 91 movaps xmm0, [rax] 92 93 mov rax, N 94 95 movaps xmm2,xmm0 96 mulps xmm2,xmm5 97 //mix1 98 movaps xmm3, xmm2 99 shufps xmm3, xmm3, $4e 100 addps xmm2, xmm3 101 //mix2 102 movaps xmm3, xmm2 103 shufps xmm3, xmm3, $11 104 addps xmm2, xmm3 105 106 movss [rax], xmm2 107 108 movaps xmm2,xmm0 109 mulps xmm2,xmm6 110 //mix1 111 movaps xmm3, xmm2 112 shufps xmm3, xmm3, $4e 113 addps xmm2, xmm3 114 //mix2 115 movaps xmm3, xmm2 116 shufps xmm3, xmm3, $11 117 addps xmm2, xmm3 118 119 movss [rax+4], xmm2 120 121 mulps xmm0,xmm7 122 //mix1 123 movaps xmm3, xmm0 124 shufps xmm3, xmm3, $4e 125 addps xmm0, xmm3 126 //mix2 127 movaps xmm3, xmm0 128 shufps xmm3, xmm3, $11 129 addps xmm0, xmm3 130 131 movss [rax+8], xmm0 132 end; 133 {$ELSE} 134 asm 135 mov eax, M 136 movaps xmm0, [eax] 137 138 mov eax, N 139 140 movaps xmm2,xmm0 141 mulps xmm2,xmm5 142 //mix1 143 movaps xmm3, xmm2 144 shufps xmm3, xmm3, $4e 145 addps xmm2, xmm3 146 //mix2 147 movaps xmm3, xmm2 148 shufps xmm3, xmm3, $11 149 addps xmm2, xmm3 150 151 movss [eax], xmm2 152 153 movaps xmm2,xmm0 154 mulps xmm2,xmm6 155 //mix1 156 movaps xmm3, xmm2 157 shufps xmm3, xmm3, $4e 158 addps xmm2, xmm3 159 //mix2 160 movaps xmm3, xmm2 161 shufps xmm3, xmm3, $11 162 addps xmm2, xmm3 163 164 movss [eax+4], xmm2 165 166 mulps xmm0,xmm7 167 //mix1 168 movaps xmm3, xmm0 169 shufps xmm3, xmm3, $4e 170 addps xmm0, xmm3 171 //mix2 172 movaps xmm3, xmm0 173 shufps xmm3, xmm3, $11 174 addps xmm0, xmm3 175 176 movss [eax+8], xmm0 177 end; 178 {$ENDIF} 179 M.t := oldMt; 180 N.t := 0; 181 end; 182 183 procedure MatrixMultiplyVect3D_SSE3_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 184 var oldMt: single; 185 begin 186 oldMt := M.t; 187 M.t := SingleConst1; 188 {$IFDEF cpux86_64} 189 asm 190 mov rax, M 191 movaps xmm0, [rax] 192 193 mov rax, N 194 195 movaps xmm2,xmm0 196 mulps xmm2,xmm5 197 haddps xmm2,xmm2 198 haddps xmm2,xmm2 199 movss [rax], xmm2 200 201 movaps xmm2,xmm0 202 mulps xmm2,xmm6 203 haddps xmm2,xmm2 204 haddps xmm2,xmm2 205 movss [rax+4], xmm2 206 207 mulps xmm0,xmm7 208 haddps xmm0,xmm0 209 haddps xmm0,xmm0 210 movss [rax+8], xmm0 211 end; 212 {$ELSE} 72 213 asm 73 214 mov eax, M … … 78 219 movaps xmm2,xmm0 79 220 mulps xmm2,xmm5 80 //mix1 81 movaps xmm3, xmm2 82 shufps xmm3, xmm3, $4e 83 addps xmm2, xmm3 84 //mix2 85 movaps xmm3, xmm2 86 shufps xmm3, xmm3, $11 87 addps xmm2, xmm3 88 221 haddps xmm2,xmm2 222 haddps xmm2,xmm2 89 223 movss [eax], xmm2 90 224 91 225 movaps xmm2,xmm0 92 226 mulps xmm2,xmm6 93 //mix1 94 movaps xmm3, xmm2 95 shufps xmm3, xmm3, $4e 96 addps xmm2, xmm3 97 //mix2 98 movaps xmm3, xmm2 99 shufps xmm3, xmm3, $11 100 addps xmm2, xmm3 101 227 haddps xmm2,xmm2 228 haddps xmm2,xmm2 102 229 movss [eax+4], xmm2 103 230 104 231 mulps xmm0,xmm7 105 //mix1 106 movaps xmm3, xmm0 107 shufps xmm3, xmm3, $4e 108 addps xmm0, xmm3 109 //mix2 110 movaps xmm3, xmm0 111 shufps xmm3, xmm3, $11 112 addps xmm0, xmm3 113 232 haddps xmm0,xmm0 233 haddps xmm0,xmm0 114 234 movss [eax+8], xmm0 115 235 end; 236 {$ENDIF} 116 237 M.t := oldMt; 117 N.t := 0; 118 end; 119 120 procedure MatrixMultiplyVect3D_SSE3_Aligned(var M: TPoint3D_128; out N: TPoint3D_128); 121 var oldMt: single; 122 begin 123 oldMt := M.t; 124 M.t := SingleConst1; 238 end; 239 240 procedure MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned( 241 var M: TPoint3D_128; out N: TPoint3D_128); 242 begin 243 {$IFDEF cpux86_64} 244 asm 245 mov rax, M 246 movaps xmm0, [rax] 247 248 mov rax, N 249 250 movaps xmm2,xmm0 251 mulps xmm2,xmm5 252 //mix1 253 movaps xmm3, xmm2 254 shufps xmm3, xmm3, $4e 255 addps xmm2, xmm3 256 //mix2 257 movaps xmm3, xmm2 258 shufps xmm3, xmm3, $11 259 addps xmm2, xmm3 260 261 movss [rax], xmm2 262 263 movaps xmm2,xmm0 264 mulps xmm2,xmm6 265 //mix1 266 movaps xmm3, xmm2 267 shufps xmm3, xmm3, $4e 268 addps xmm2, xmm3 269 //mix2 270 movaps xmm3, xmm2 271 shufps xmm3, xmm3, $11 272 addps xmm2, xmm3 273 274 movss [rax+4], xmm2 275 276 mulps xmm0,xmm7 277 //mix1 278 movaps xmm3, xmm0 279 shufps xmm3, xmm3, $4e 280 addps xmm0, xmm3 281 //mix2 282 movaps xmm3, xmm0 283 shufps xmm3, xmm3, $11 284 addps xmm0, xmm3 285 286 movss [rax+8], xmm0 287 end; 288 {$ELSE} 289 asm 290 mov eax, M 291 movaps xmm0, [eax] 292 293 mov eax, N 294 295 movaps xmm2,xmm0 296 mulps xmm2,xmm5 297 //mix1 298 movaps xmm3, xmm2 299 shufps xmm3, xmm3, $4e 300 addps xmm2, xmm3 301 //mix2 302 movaps xmm3, xmm2 303 shufps xmm3, xmm3, $11 304 addps xmm2, xmm3 305 306 movss [eax], xmm2 307 308 movaps xmm2,xmm0 309 mulps xmm2,xmm6 310 //mix1 311 movaps xmm3, xmm2 312 shufps xmm3, xmm3, $4e 313 addps xmm2, xmm3 314 //mix2 315 movaps xmm3, xmm2 316 shufps xmm3, xmm3, $11 317 addps xmm2, xmm3 318 319 movss [eax+4], xmm2 320 321 mulps xmm0,xmm7 322 //mix1 323 movaps xmm3, xmm0 324 shufps xmm3, xmm3, $4e 325 addps xmm0, xmm3 326 //mix2 327 movaps xmm3, xmm0 328 shufps xmm3, xmm3, $11 329 addps xmm0, xmm3 330 331 movss [eax+8], xmm0 332 end; 333 {$ENDIF} 334 end; 335 336 procedure MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned( 337 var M: TPoint3D_128; out N: TPoint3D_128); 338 begin 339 {$IFDEF cpux86_64} 340 asm 341 mov rax, M 342 movaps xmm0, [rax] 343 344 mov rax, N 345 346 movaps xmm2,xmm0 347 mulps xmm2,xmm5 348 haddps xmm2,xmm2 349 haddps xmm2,xmm2 350 movss [rax], xmm2 351 352 movaps xmm2,xmm0 353 mulps xmm2,xmm6 354 haddps xmm2,xmm2 355 haddps xmm2,xmm2 356 movss [rax+4], xmm2 357 358 mulps xmm0,xmm7 359 haddps xmm0,xmm0 360 haddps xmm0,xmm0 361 movss [rax+8], xmm0 362 end; 363 {$ELSE} 125 364 asm 126 365 mov eax, M … … 146 385 movss [eax+8], xmm0 147 386 end; 148 M.t := oldMt; 149 end; 387 {$ENDIF} 388 end; 389 150 390 {$ENDIF} 151 391 152 operator*(const A: TMatrix3D; var M: TPoint3D_128): TPoint3D_128;392 operator*(constref A: TMatrix3D; var M: TPoint3D_128): TPoint3D_128; 153 393 {$IFDEF CPUI386}var oldMt: single; {$ENDIF} 154 394 begin … … 248 488 end; 249 489 490 function MultiplyVect3DWithoutTranslation(constref A: TMatrix3D; constref M: TPoint3D_128): TPoint3D_128; 491 begin 492 {$IFDEF CPUI386} 493 if UseSSE then 494 begin 495 if UseSSE3 then 496 asm 497 mov eax, A 498 movups xmm5, [eax] 499 movups xmm6, [eax+16] 500 movups xmm7, [eax+32] 501 502 mov eax, M 503 movups xmm0, [eax] 504 505 mov eax, result 506 507 movaps xmm4,xmm0 508 mulps xmm4,xmm5 509 haddps xmm4,xmm4 510 haddps xmm4,xmm4 511 movss [eax], xmm4 512 513 movaps xmm4,xmm0 514 mulps xmm4,xmm6 515 haddps xmm4,xmm4 516 haddps xmm4,xmm4 517 movss [eax+4], xmm4 518 519 mulps xmm0,xmm7 520 haddps xmm0,xmm0 521 haddps xmm0,xmm0 522 movss [eax+8], xmm0 523 end else 524 asm 525 mov eax, A 526 movups xmm5, [eax] 527 movups xmm6, [eax+16] 528 movups xmm7, [eax+32] 529 530 mov eax, M 531 movups xmm0, [eax] 532 533 mov eax, result 534 535 movaps xmm4,xmm0 536 mulps xmm4,xmm5 537 //mix1 538 movaps xmm3, xmm4 539 shufps xmm3, xmm3, $4e 540 addps xmm4, xmm3 541 //mix2 542 movaps xmm3, xmm4 543 shufps xmm3, xmm3, $11 544 addps xmm4, xmm3 545 546 movss [eax], xmm4 547 548 movaps xmm4,xmm0 549 mulps xmm4,xmm6 550 //mix1 551 movaps xmm3, xmm4 552 shufps xmm3, xmm3, $4e 553 addps xmm4, xmm3 554 //mix2 555 movaps xmm3, xmm4 556 shufps xmm3, xmm3, $11 557 addps xmm4, xmm3 558 559 movss [eax+4], xmm4 560 561 mulps xmm0,xmm7 562 //mix1 563 movaps xmm3, xmm0 564 shufps xmm3, xmm3, $4e 565 addps xmm0, xmm3 566 //mix2 567 movaps xmm3, xmm0 568 shufps xmm3, xmm3, $11 569 addps xmm0, xmm3 570 571 movss [eax+8], xmm0 572 end; 573 end else 574 {$ENDIF} 575 begin 576 result.x := M.x * A[1,1] + M.y * A[1,2] + M.z * A[1,3]; 577 result.y := M.x * A[2,1] + M.y * A[2,2] + M.z * A[2,3]; 578 result.z := M.x * A[3,1] + M.y * A[3,2] + M.z * A[3,3]; 579 result.t := 0; 580 end; 581 end; 582 250 583 operator*(A,B: TMatrix3D): TMatrix3D; 251 584 begin -
GraphicTest/Packages/bgrabitmap/bgraopenraster.pas
r452 r472 38 38 function GetMemoryStreamAsString(AFilename: string): string; 39 39 procedure UnzipFromStream(AStream: TStream); 40 procedure UnzipFromFile(AFilename: string); 41 procedure ZipToFile(AFilename: string); 40 procedure UnzipFromFile(AFilenameUTF8: string); 41 procedure ZipToFile(AFilenameUTF8: string); 42 procedure ZipToStream(AStream: TStream); 42 43 procedure CopyThumbnailToMemoryStream(AMaxWidth, AMaxHeight: integer); 43 44 procedure AnalyzeZip; 45 procedure PrepareZipToSave; 44 46 function GetMimeType: string; override; 45 47 46 48 public 47 constructor Create; override; 49 constructor Create; override; overload; 50 constructor Create(AWidth, AHeight: integer); override; overload; 48 51 procedure Clear; override; 52 function CheckMimeType(AStream: TStream): boolean; 49 53 procedure LoadFromStream(AStream: TStream); override; 50 procedure LoadFromFile(const filename: string); override; 51 procedure SaveToFile(const filename: string); override; 54 procedure LoadFromFile(const filenameUTF8: string); override; 55 procedure SaveToFile(const filenameUTF8: string); override; 56 procedure SaveToStream(AStream: TStream); override; 52 57 property MimeType : string read GetMimeType write SetMimeType; 53 58 property StackXML : TXMLDocument read FStackXML; … … 57 62 58 63 TFPReaderOpenRaster = class(TFPCustomImageReader) 64 private 65 FWidth,FHeight,FNbLayers: integer; 59 66 protected 60 67 function InternalCheck(Stream: TStream): boolean; override; 61 68 procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; 69 public 70 property Width: integer read FWidth; 71 property Height: integer read FHeight; 72 property NbLayers: integer read FNbLayers; 73 end; 74 75 { TFPWriterOpenRaster } 76 77 TFPWriterOpenRaster = class(TFPCustomImageWriter) 78 protected 79 procedure InternalWrite (Str:TStream; Img:TFPCustomImage); override; 62 80 end; 63 81 … … 66 84 implementation 67 85 68 uses Graphics, XMLRead, XMLWrite, FPReadPNG, dialogs, BGRABitmapTypes, zstream; 86 uses Graphics, XMLRead, XMLWrite, FPReadPNG, dialogs, BGRABitmapTypes, zstream, lazutf8classes, 87 UnzipperExt; 69 88 70 89 function IsZipStream(stream: TStream): boolean; … … 89 108 end; 90 109 110 { TFPWriterOpenRaster } 111 112 procedure TFPWriterOpenRaster.InternalWrite(Str: TStream; Img: TFPCustomImage); 113 var doc: TBGRAOpenRasterDocument; 114 tempBmp: TBGRABitmap; 115 x,y: integer; 116 117 begin 118 doc := TBGRAOpenRasterDocument.Create; 119 if Img is TBGRABitmap then doc.AddLayer(Img as TBGRABitmap) else 120 begin 121 tempBmp := TBGRABitmap.Create(img.Width,img.Height); 122 for y := 0 to Img.Height-1 do 123 for x := 0 to img.Width-1 do 124 tempBmp.SetPixel(x,y, FPColorToBGRA(img.Colors[x,y])); 125 doc.AddOwnedLayer(tempBmp); 126 end; 127 doc.SaveToStream(Str); 128 doc.Free; 129 end; 130 91 131 { TFPReaderOpenRaster } 92 132 93 133 function TFPReaderOpenRaster.InternalCheck(Stream: TStream): boolean; 94 begin 95 result := IsZipStream(Stream); 134 var {%h-}magic: packed array[0..3] of byte; 135 OldPos,BytesRead: Int64; 136 doc : TBGRAOpenRasterDocument; 137 begin 138 Result:=false; 139 if Stream=nil then exit; 140 oldPos := stream.Position; 141 BytesRead := Stream.Read({%h-}magic,sizeof(magic)); 142 stream.Position:= OldPos; 143 if BytesRead<>sizeof(magic) then exit; 144 if (magic[0] = $50) and (magic[1] = $4b) and (magic[2] = $03) and (magic[3] = $04) then 145 begin 146 doc := TBGRAOpenRasterDocument.Create; 147 result := doc.CheckMimeType(Stream); 148 doc.Free; 149 end; 96 150 end; 97 151 … … 102 156 x,y: integer; 103 157 begin 158 FWidth := 0; 159 FHeight:= 0; 160 FNbLayers:= 0; 104 161 layeredImage := TBGRAOpenRasterDocument.Create; 105 162 try … … 107 164 flat := layeredImage.ComputeFlatImage; 108 165 try 109 Img.SetSize(flat.Width,flat.Height); 110 for y := 0 to flat.Height-1 do 111 for x := 0 to flat.Width-1 do 112 Img.Colors[x,y] := BGRAToFPColor(flat.GetPixel(x,y)); 166 FWidth:= layeredImage.Width; 167 FHeight:= layeredImage.Height; 168 FNbLayers:= layeredImage.NbLayers; 169 if Img is TBGRACustomBitmap then 170 TBGRACustomBitmap(img).Assign(flat) 171 else 172 begin 173 Img.SetSize(flat.Width,flat.Height); 174 for y := 0 to flat.Height-1 do 175 for x := 0 to flat.Width-1 do 176 Img.Colors[x,y] := BGRAToFPColor(flat.GetPixel(x,y)); 177 end; 113 178 finally 114 179 flat.free; … … 173 238 for i := stackNode.ChildNodes.Length-1 downto 0 do 174 239 begin 240 OnLayeredBitmapLoadProgress((stackNode.ChildNodes.Length-i)*100 div stackNode.ChildNodes.Length); 175 241 layerNode:= stackNode.ChildNodes[i]; 176 242 if (layerNode.NodeName = 'layer') and Assigned(layerNode.Attributes) then … … 291 357 end; 292 358 293 procedure TBGRAOpenRasterDocument.LoadFromFile(const filename: string); 294 begin 295 UnzipFromFile(filename); 296 AnalyzeZip; 297 end; 298 299 procedure TBGRAOpenRasterDocument.SaveToFile(const filename: string); 359 procedure TBGRAOpenRasterDocument.PrepareZipToSave; 300 360 var i: integer; 301 361 imageNode,stackNode,layerNode: TDOMElement; … … 375 435 WriteXMLFile(StackXML, StackStream); 376 436 SetMemoryStream('stack.xml',StackStream); 377 378 ZipToFile(filename); 437 end; 438 439 procedure TBGRAOpenRasterDocument.LoadFromFile(const filenameUTF8: string); 440 var AStream: TFileStreamUTF8; 441 begin 442 AStream := TFileStreamUTF8.Create(filenameUTF8,fmOpenRead or fmShareDenyWrite); 443 try 444 LoadFromStream(AStream); 445 finally 446 AStream.Free; 447 end; 448 end; 449 450 procedure TBGRAOpenRasterDocument.SaveToFile(const filenameUTF8: string); 451 begin 452 PrepareZipToSave; 453 ZipToFile(filenameUTF8); 454 end; 455 456 procedure TBGRAOpenRasterDocument.SaveToStream(AStream: TStream); 457 begin 458 PrepareZipToSave; 459 ZipToStream(AStream); 379 460 end; 380 461 … … 390 471 begin 391 472 inherited Create; 473 RegisterOpenRasterFormat; 474 end; 475 476 constructor TBGRAOpenRasterDocument.Create(AWidth, AHeight: integer); 477 begin 478 inherited Create(AWidth, AHeight); 392 479 RegisterOpenRasterFormat; 393 480 end; … … 514 601 finally 515 602 FZipInputStream := nil; 516 end;517 unzip.Free;518 end; 519 520 procedure TBGRAOpenRasterDocument.UnzipFromFile(AFilename : string);603 unzip.Free; 604 end; 605 end; 606 607 procedure TBGRAOpenRasterDocument.UnzipFromFile(AFilenameUTF8: string); 521 608 var unzip: TUnZipper; 522 609 begin … … 524 611 unzip := TUnZipper.Create; 525 612 try 526 unzip.FileName := AFilename;613 unzip.FileName := Utf8ToAnsi(AFilenameUTF8); 527 614 unzip.OnCreateStream := @ZipOnCreateStream; 528 615 unzip.OnDoneStream := @ZipOnDoneStream; 529 616 unzip.UnZipAllFiles; 530 617 finally 531 end; 532 unzip.Free; 533 end; 534 535 procedure TBGRAOpenRasterDocument.ZipToFile(AFilename: string); 618 unzip.Free; 619 end; 620 end; 621 622 procedure TBGRAOpenRasterDocument.ZipToFile(AFilenameUTF8: string); 623 var 624 stream: TFileStreamUTF8; 625 begin 626 stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate); 627 try 628 ZipToStream(stream); 629 finally 630 stream.Free; 631 end; 632 end; 633 634 procedure TBGRAOpenRasterDocument.ZipToStream(AStream: TStream); 536 635 var zip: TZipper; 537 636 i: integer; … … 539 638 zip := TZipper.Create; 540 639 try 541 zip.FileName := AFilename;542 640 for i := 0 to high(FFiles) do 543 641 begin … … 545 643 zip.Entries.AddFileEntry(FFiles[i].Stream,FFiles[i].Filename).CompressionLevel := clnone; 546 644 end; 547 zip. ZipAllFiles;645 zip.SaveToStream(AStream); 548 646 finally 549 647 zip.Free; … … 557 655 if (Width = 0) or (Height = 0) then exit; 558 656 thumbnail := ComputeFlatImage; 657 CopyBitmapToMemoryStream(thumbnail,'mergedimage.png'); 559 658 if (thumbnail.Width > AMaxWidth) or 560 659 (thumbnail.Height > AMaxHeight) then … … 586 685 end; 587 686 687 function TBGRAOpenRasterDocument.CheckMimeType(AStream: TStream): boolean; 688 var unzip: TUnzipperStreamUtf8; 689 mimeTypeFound: string; 690 oldPos: int64; 691 begin 692 result := false; 693 unzip := TUnzipperStreamUtf8.Create; 694 oldPos := AStream.Position; 695 try 696 unzip.InputStream := AStream; 697 mimeTypeFound := unzip.UnzipFileToString('mimetype'); 698 if mimeTypeFound = OpenRasterMimeType then result := true; 699 except 700 end; 701 unzip.Free; 702 astream.Position:= OldPos; 703 end; 704 588 705 procedure TBGRAOpenRasterDocument.LoadFromStream(AStream: TStream); 589 706 begin 590 UnzipFromStream(AStream); 591 AnalyzeZip; 707 OnLayeredBitmapLoadFromStreamStart; 708 try 709 UnzipFromStream(AStream); 710 AnalyzeZip; 711 finally 712 OnLayeredBitmapLoaded; 713 end; 592 714 end; 593 715 … … 673 795 RegisterLayeredBitmapWriter('ora', TBGRAOpenRasterDocument); 674 796 //TPicture.RegisterFileFormat('ora', 'OpenRaster', TBGRAOpenRasterDocument); 797 DefaultBGRAImageReader[ifOpenRaster] := TFPReaderOpenRaster; 798 DefaultBGRAImageWriter[ifOpenRaster] := TFPWriterOpenRaster; 675 799 AlreadyRegistered:= True; 676 800 end; -
GraphicTest/Packages/bgrabitmap/bgrapaintnet.pas
r452 r472 27 27 TPaintDotNetFile = class(TBGRACustomLayeredBitmap) 28 28 public 29 procedure LoadFromFile(const filename : string); override;29 procedure LoadFromFile(const filenameUTF8: string); override; 30 30 procedure LoadFromStream(stream: TStream); override; 31 31 procedure Clear; override; … … 34 34 constructor Create; override; 35 35 protected 36 procedure InternalLoadFromStream(stream: TStream); 36 37 function GetWidth: integer; override; 37 38 function GetHeight: integer; override; … … 42 43 function GetLayerName(layer: integer): string; override; 43 44 private 44 XmlHeader: string;45 ThumbNail: TBGRABitmap;46 45 Content: TDotNetDeserialization; 47 46 Document: TSerializedClass; … … 60 59 61 60 TFPReaderPaintDotNet = class(TFPCustomImageReader) 61 private 62 FWidth,FHeight,FNbLayers: integer; 62 63 protected 63 64 function InternalCheck(Stream: TStream): boolean; override; 64 65 procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override; 66 public 67 property Width: integer read FWidth; 68 property Height: integer read FHeight; 69 property NbLayers: integer read FNbLayers; 65 70 end; 66 71 67 72 function IsPaintDotNetFile(filename: string): boolean; 73 function IsPaintDotNetFileUTF8(filenameUTF8: string): boolean; 68 74 function IsPaintDotNetStream(stream: TStream): boolean; 69 75 function LoadPaintDotNetFile(filename: string): TBGRABitmap; 76 function LoadPaintDotNetFileUTF8(filenameUTF8: string): TBGRABitmap; 70 77 71 78 procedure RegisterPaintNetFormat; … … 73 80 implementation 74 81 75 uses zstream, Math, graphtype, Graphics ;82 uses zstream, Math, graphtype, Graphics, lazutf8classes, FileUtil; 76 83 77 84 {$hints off} … … 99 106 begin 100 107 stream := TFileStream.Create(filename, fmOpenRead); 108 Result := IsPaintDotNetStream(stream); 109 stream.Free; 110 end; 111 end; 112 113 function IsPaintDotNetFileUTF8(filenameUTF8: string): boolean; 114 var 115 stream: TFileStreamUTF8; 116 begin 117 Result := False; 118 if FileExistsUTF8(filenameUTF8) then 119 begin 120 stream := TFileStreamUTF8.Create(filenameUTF8, fmOpenRead); 101 121 Result := IsPaintDotNetStream(stream); 102 122 stream.Free; … … 127 147 128 148 function LoadPaintDotNetFile(filename: string): TBGRABitmap; 149 begin 150 result := LoadPaintDotNetFileUTF8(SysToUTF8(filename)); 151 end; 152 153 function LoadPaintDotNetFileUTF8(filenameUTF8: string): TBGRABitmap; 129 154 var 130 155 pdn: TPaintDotNetFile; … … 133 158 Result := nil; 134 159 try 135 pdn.LoadFromFile(filename );160 pdn.LoadFromFile(filenameUTF8); 136 161 Result := pdn.ComputeFlatImage; 137 162 pdn.Free; … … 181 206 x,y: integer; 182 207 begin 208 FWidth := 0; 209 FHeight:= 0; 210 FNbLayers:= 0; 183 211 pdn := TPaintDotNetFile.Create; 184 212 try … … 186 214 flat := pdn.ComputeFlatImage; 187 215 try 188 Img.SetSize(pdn.Width,pdn.Height); 189 for y := 0 to pdn.Height-1 do 190 for x := 0 to pdn.Width-1 do 191 Img.Colors[x,y] := BGRAToFPColor(flat.GetPixel(x,y)); 216 FWidth:= pdn.Width; 217 FHeight:= pdn.Height; 218 FNbLayers:= pdn.NbLayers; 219 220 if Img is TBGRACustomBitmap then 221 TBGRACustomBitmap(Img).Assign(flat) else 222 begin 223 Img.SetSize(pdn.Width,pdn.Height); 224 for y := 0 to pdn.Height-1 do 225 for x := 0 to pdn.Width-1 do 226 Img.Colors[x,y] := BGRAToFPColor(flat.GetPixel(x,y)); 227 end; 192 228 finally 193 229 flat.free; … … 205 241 { TPaintDotNetFile } 206 242 207 procedure TPaintDotNetFile.LoadFromFile(const filename: string); 208 var 209 stream: TFileStream; 210 begin 211 stream := TFileStream.Create(filename, fmOpenRead); 243 procedure TPaintDotNetFile.LoadFromFile(const filenameUTF8: string); 244 var 245 stream: TFileStreamUTF8; 246 begin 247 stream := TFileStreamUTF8.Create(filenameUTF8, fmOpenRead); 248 OnLayeredBitmapLoadStart(filenameUTF8); 212 249 try 213 LoadFromStream(stream);250 InternalLoadFromStream(stream); 214 251 finally 252 OnLayeredBitmapLoaded; 215 253 stream.Free; 216 254 end; … … 218 256 219 257 procedure TPaintDotNetFile.LoadFromStream(stream: TStream); 258 begin 259 OnLayeredBitmapLoadFromStreamStart; 260 try 261 InternalLoadFromStream(stream); 262 finally 263 OnLayeredBitmapLoaded; 264 end; 265 end; 266 267 procedure TPaintDotNetFile.InternalLoadFromStream(stream: TStream); 220 268 var 221 269 header: packed array[0..3] of char; … … 233 281 stream.Read(XmlHeaderSize, 3); 234 282 XmlheaderSize := LEtoN(XmlheaderSize); 235 setlength(XmlHeader, XmlHeaderSize); 236 if stream.Read(XmlHeader[1], XmlHeaderSize) <> XmlHeaderSize then 283 if Stream.Position + XmlHeaderSize > stream.Size then 237 284 raise Exception.Create('Xml header size error'); 238 XmlHeader := Utf8ToAnsi(XmlHeader);285 Stream.Position:= Stream.Position + XmlHeaderSize; 239 286 {$hints off} 240 287 stream.Read(CompressionFormat, sizeof(CompressionFormat)); … … 255 302 for i := 0 to NbLayers - 1 do 256 303 begin 304 OnLayeredBitmapLoadProgress((i+1)*100 div NbLayers); 257 305 LayerData[i] := TMemoryStream.Create; 258 306 LoadLayer(LayerData[i], Stream, LayerDataSize(i)); … … 266 314 begin 267 315 Result := 'Paint.Net document' + LineEnding + LineEnding; 268 if length(XmlHeader) > 255 then 269 Result += copy(XmlHeader, 1, 255) + '...' 270 else 271 Result += XmlHeader; 272 Result += LineEnding + LineEnding + Content.ToString; 316 Result += Content.ToString; 273 317 for i := 0 to NbLayers - 1 do 274 318 begin … … 297 341 inherited Create; 298 342 Content := nil; 299 ThumbNail := nil;300 343 Document := nil; 301 344 Layers := nil; … … 308 351 i: integer; 309 352 begin 310 XmlHeader := '';311 353 FreeAndNil(content); 312 FreeAndNil(thumbNail);313 354 document := nil; 314 355 Layers := nil; … … 610 651 RegisterLayeredBitmapReader('pdn', TPaintDotNetFile); 611 652 //TPicture.RegisterFileFormat('pdn', 'Paint.NET image', TPaintDotNetFile); 653 DefaultBGRAImageReader[ifPaintDotNet] := TFPReaderPaintDotNet; 612 654 AlreadyRegistered := true; 613 655 end; -
GraphicTest/Packages/bgrabitmap/bgrapath.pas
r452 r472 5 5 interface 6 6 7 { There are different conventions for angles. 8 9 First is about the unit. It can be one of the following: 10 - degrees (0..360) 11 - radian (0..2*Pi) 12 - tenth of degrees (0..3600) 13 - from 0 to 65536 14 15 Second is about the origin. It can be one of the following: 16 - right-most position (this is the default origin for radian and 65536) 17 - top-most position (this is the default origin for degrees) 18 19 Third is about the sign. It can be one of the following: 20 - positive is clockwise (this is the default for degrees) 21 - positive is counterclockwise (this is the default for radian and 65536) 22 23 TBGRAPath and TBGRACanvas2D follow HTML5 convention which is: 24 (radian, right-most, clockwise) that can be shortened to (radian, clockwise) 25 because right-most is the default for radian. This is abbreviated as "radCW". 26 27 When radian are CCW, it is also specified in order to make it clear, even 28 if it is the default convention in mathematics. 29 30 In order to make things easier, there are some functions that accept angles 31 in degrees. The convention used here is the usual degree convention: 32 (degrees, top-most, clockwise) that can be shortened to (degree) 33 because top-most and clockwise is the default for degrees. 34 35 } 36 7 37 uses 8 Classes, BGRABitmapTypes; 38 Classes, BGRABitmapTypes, BGRATransform; 39 40 type 41 TBGRAPathElementType = (peNone, peMoveTo, peLineTo, peCloseSubPath, peQuadraticBezierTo, peCubicBezierTo, peArc); 42 PBGRAPathElementType = ^TBGRAPathElementType; 43 44 { TBGRAPath } 45 46 TBGRAPath = class(IBGRAPath) 47 private 48 function GetSvgString: string; 49 procedure SetSvgString(const AValue: string); 50 protected 51 FData: pbyte; 52 FDataSize: integer; 53 FDataPos: integer; 54 FLastElementType: TBGRAPathElementType; 55 FLastCoord, 56 FStartCoord: TPointF; 57 FExpectedControlPoint: TPointF; 58 FMatrix: TAffineMatrix; //this matrix must have a base of vectors 59 //orthogonal, of same length and with positive 60 //orientation in order to preserve arcs 61 FScale,FAngleRadCW: single; 62 procedure NeedSpace(count: integer); 63 procedure StoreCoord(const pt: TPointF); 64 function ReadCoord: TPointF; 65 procedure StoreElementType(value: TBGRAPathElementType); 66 function ReadElementType: TBGRAPathElementType; 67 function ReadArcDef: TArcDef; 68 procedure RewindFloat; 69 procedure Init; 70 public 71 constructor Create; overload; 72 constructor Create(ASvgString: string); overload; 73 destructor Destroy; override; 74 procedure beginPath; 75 procedure closePath; 76 procedure translate(x,y: single); 77 procedure resetTransform; 78 procedure rotate(angleRadCW: single); overload; 79 procedure rotateDeg(angleDeg: single); overload; 80 procedure rotate(angleRadCW: single; center: TPointF); overload; 81 procedure rotateDeg(angleDeg: single; center: TPointF); overload; 82 procedure scale(factor: single); 83 procedure moveTo(x,y: single); overload; 84 procedure lineTo(x,y: single); overload; 85 procedure moveTo(const pt: TPointF); overload; 86 procedure lineTo(const pt: TPointF); overload; 87 procedure polylineTo(const pts: array of TPointF); 88 procedure quadraticCurveTo(cpx,cpy,x,y: single); overload; 89 procedure quadraticCurveTo(const cp,pt: TPointF); overload; 90 procedure quadraticCurve(const curve: TQuadraticBezierCurve); overload; 91 procedure smoothQuadraticCurveTo(x,y: single); overload; 92 procedure smoothQuadraticCurveTo(const pt: TPointF); overload; 93 procedure bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y: single); overload; 94 procedure bezierCurveTo(const cp1,cp2,pt: TPointF); overload; 95 procedure bezierCurve(const curve: TCubicBezierCurve); overload; 96 procedure smoothBezierCurveTo(cp2x,cp2y,x,y: single); overload; 97 procedure smoothBezierCurveTo(const cp2,pt: TPointF); overload; 98 procedure rect(x,y,w,h: single); 99 procedure roundRect(x,y,w,h,radius: single); 100 procedure arc(cx, cy, radius, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload; 101 procedure arc(cx, cy, radius, startAngleRadCW, endAngleRadCW: single); overload; 102 procedure arcDeg(cx, cy, radius, startAngleDeg, endAngleDeg: single; anticlockwise: boolean); overload; 103 procedure arcDeg(cx, cy, radius, startAngleDeg, endAngleDeg: single); overload; 104 procedure arcTo(x1, y1, x2, y2, radius: single); overload; 105 procedure arcTo(const p1,p2: TPointF; radius: single); overload; 106 procedure arc(const arcDef: TArcDef); overload; 107 procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single); overload; 108 procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload; 109 procedure arcTo(rx,ry, xAngleRadCW: single; largeArc, anticlockwise: boolean; x,y:single); 110 procedure copyTo(dest: IBGRAPath); 111 procedure addPath(const AValue: string); overload; 112 procedure addPath(source: IBGRAPath); overload; 113 property SvgString: string read GetSvgString write SetSvgString; 114 protected 115 function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 116 function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 117 function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 118 end; 9 119 10 120 {----------------------- Spline ------------------} … … 21 131 function ComputeEllipse(x,y,rx,ry: single; quality: single = 1): ArrayOfTPointF; 22 132 function ComputeArc65536(x, y, rx, ry: single; start65536,end65536: word; quality: single = 1): ArrayOfTPointF; 133 function ComputeArcRad(x, y, rx, ry: single; startRadCCW,endRadCCW: single; quality: single = 1): ArrayOfTPointF; 134 function ComputeArc(const arc: TArcDef; quality: single = 1): ArrayOfTPointF; 23 135 function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; quality: single = 1): ArrayOfTPointF; overload; 24 136 function ComputeRoundRect(x1,y1,x2,y2,rx,ry: single; options: TRoundRectangleOptions; quality: single = 1): ArrayOfTPointF; overload; 25 137 138 function Html5ArcTo(const p0, p1, p2: TPointF; radius: single): TArcDef; 139 function SvgArcTo(const p0: TPointF; rx, ry, xAngleRadCW: single; largeArc, 140 anticlockwise: boolean; const p1: TPointF): TArcDef; 141 function ArcStartPoint(const arc: TArcDef): TPointF; 142 function ArcEndPoint(const arc: TArcDef): TPointF; 143 function IsLargeArc(const arc: TArcDef): boolean; 144 26 145 implementation 27 146 28 uses Math, BGRAResample ;147 uses Math, BGRAResample, SysUtils; 29 148 30 149 function SplineVertexToSide(y0, y1, y2, y3: single; t: single): single; … … 330 449 end; 331 450 332 {$PUSH}{$R-}333 451 function ComputeArc65536(x, y, rx, ry: single; start65536,end65536: word; quality: single): ArrayOfTPointF; 334 452 var i,nb: integer; … … 362 480 for i := 0 to nb-1 do 363 481 begin 482 {$PUSH}{$R-} 364 483 pos := start65536+int64(i)*arclen div (int64(nb)-1); 484 {$POP} 365 485 result[i] := PointF(x+rx*(Cos65536(pos)-32768)/32768, 366 486 y-ry*(Sin65536(pos)-32768)/32768); 367 487 end; 368 488 end; 369 {$R+}370 489 371 490 function ComputeEllipse(x, y, rx, ry: single; quality: single): ArrayOfTPointF; 372 491 begin 373 492 result := ComputeArc65536(x,y,rx,ry,0,0,quality); 493 end; 494 495 function ComputeArcRad(x, y, rx, ry: single; startRadCCW, endRadCCW: single; 496 quality: single): ArrayOfTPointF; 497 begin 498 result := ComputeArc65536(x,y,rx,ry,round(startRadCCW*32768/Pi) and $ffff,round(endRadCCW*32768/Pi) and $ffff,quality); 499 result[0] := PointF(x+cos(startRadCCW)*rx,y-sin(startRadCCW)*ry); 500 result[high(result)] := PointF(x+cos(endRadCCW)*rx,y-sin(endRadCCW)*ry); 501 end; 502 503 function ComputeArc(const arc: TArcDef; quality: single): ArrayOfTPointF; 504 var startAngle,endAngle: single; 505 i,n: integer; 506 temp: TPointF; 507 m: TAffineMatrix; 508 begin 509 startAngle := -arc.startAngleRadCW; 510 endAngle:= -arc.endAngleRadCW; 511 if not arc.anticlockwise then 512 begin 513 result := ComputeArcRad(arc.center.x,arc.center.y,arc.radius.x,arc.radius.y,endAngle,startAngle,quality); 514 n := length(result); 515 if n>1 then 516 for i := 0 to (n-2) div 2 do 517 begin 518 temp := result[i]; 519 result[i] := result[n-1-i]; 520 result[n-1-i] := temp; 521 end; 522 end else 523 result := ComputeArcRad(arc.center.x,arc.center.y,arc.radius.x,arc.radius.y,startAngle,endAngle,quality); 524 if arc.xAngleRadCW <> 0 then 525 begin 526 m := AffineMatrixTranslation(arc.center.x,arc.center.y)*AffineMatrixRotationRad(-arc.xAngleRadCW)*AffineMatrixTranslation(-arc.center.x,-arc.center.y); 527 for i := 0 to high(result) do 528 result[i] := m*result[i]; 529 end; 374 530 end; 375 531 … … 436 592 end; 437 593 594 function Html5ArcTo(const p0, p1, p2: TPointF; radius: single 595 ): TArcDef; 596 var p3,p4,an,bn,cn,c: TPointF; 597 dir, a2, b2, c2, cosx, sinx, d: single; 598 anticlockwise: boolean; 599 begin 600 result.center := p1; 601 result.radius := PointF(0,0); 602 result.xAngleRadCW:= 0; 603 result.startAngleRadCW := 0; 604 result.endAngleRadCW:= 0; 605 result.anticlockwise:= false; 606 607 radius := abs(radius); 608 if (p0 = p1) or (p1 = p2) or (radius = 0) then exit; 609 610 dir := (p2.x-p1.x)*(p0.y-p1.y) + (p2.y-p1.y)*(p1.x-p0.x); 611 if dir = 0 then exit; 612 613 a2 := (p0.x-p1.x)*(p0.x-p1.x) + (p0.y-p1.y)*(p0.y-p1.y); 614 b2 := (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y); 615 c2 := (p0.x-p2.x)*(p0.x-p2.x) + (p0.y-p2.y)*(p0.y-p2.y); 616 cosx := (a2+b2-c2)/(2*sqrt(a2*b2)); 617 618 sinx := sqrt(1 - cosx*cosx); 619 if (sinx = 0) or (cosx = 1) then exit; 620 d := radius / ((1 - cosx) / sinx); 621 622 an := (p1-p0)*(1/sqrt(a2)); 623 bn := (p1-p2)*(1/sqrt(b2)); 624 p3 := p1 - an*d; 625 p4 := p1 - bn*d; 626 anticlockwise := (dir < 0); 627 628 cn := PointF(an.y,-an.x)*radius; 629 if not anticlockwise then cn := -cn; 630 c := p3 + cn; 631 632 result.center := c; 633 result.radius:= PointF(radius,radius); 634 result.startAngleRadCW := arctan2((p3.y-c.y), (p3.x-c.x)); 635 result.endAngleRadCW := arctan2((p4.y-c.y), (p4.x-c.x)); 636 result.anticlockwise:= anticlockwise; 637 end; 638 639 function SvgArcTo(const p0: TPointF; rx, ry, xAngleRadCW: single; largeArc, 640 anticlockwise: boolean; const p1: TPointF): TArcDef; 641 var 642 p0p,cp: TPointF; 643 cross1,cross2,lambda: single; 644 begin 645 if (rx=0) or (ry=0) or (p0 = p1) then 646 begin 647 result.radius := PointF(0,0); 648 result.xAngleRadCW:= 0; 649 result.anticlockwise := false; 650 result.endAngleRadCW := 0; 651 result.startAngleRadCW:= 0; 652 result.center := p1; 653 exit; 654 end; 655 result.xAngleRadCW := xAngleRadCW; 656 result.anticlockwise := anticlockwise; 657 p0p := AffineMatrixRotationRad(xAngleRadCW)*( (p0-p1)*0.5 ); 658 659 //ensure radius is big enough 660 lambda := sqr(p0p.x/rx) + sqr(p0p.y/ry); 661 if lambda > 1 then 662 begin 663 lambda := sqrt(lambda); 664 rx *= lambda; 665 ry *= lambda; 666 end; 667 result.radius := PointF(rx,ry); 668 669 //compute center 670 cross2 := sqr(rx*p0p.y) + sqr(ry*p0p.x); 671 cross1 := sqr(rx*ry); 672 if cross1 <= cross2 then 673 cp := PointF(0,0) 674 else 675 cp := sqrt((cross1-cross2)/cross2)* 676 PointF(rx*p0p.y/ry, -ry*p0p.x/rx); 677 if largeArc <> anticlockwise then cp := -cp; 678 679 result.center := AffineMatrixRotationRad(-xAngleRadCW)*cp + 680 (p0+p1)*0.5; 681 result.startAngleRadCW := arctan2((p0p.y-cp.y)/ry,(p0p.x-cp.x)/rx); 682 result.endAngleRadCW := arctan2((-p0p.y-cp.y)/ry,(-p0p.x-cp.x)/rx); 683 end; 684 685 function ArcStartPoint(const arc: TArcDef): TPointF; 686 begin 687 result := AffineMatrixRotationRad(-arc.xAngleRadCW)*PointF(cos(arc.startAngleRadCW)*arc.radius.x, 688 sin(arc.startAngleRadCW)*arc.radius.y) + arc.center; 689 end; 690 691 function ArcEndPoint(const arc: TArcDef): TPointF; 692 begin 693 result := AffineMatrixRotationRad(-arc.xAngleRadCW)*PointF(cos(arc.endAngleRadCW)*arc.radius.x, 694 sin(arc.endAngleRadCW)*arc.radius.y) + arc.center; 695 end; 696 697 function IsLargeArc(const arc: TArcDef): boolean; 698 var diff,a1,a2: single; 699 begin 700 a1 := arc.startAngleRadCW - floor(arc.startAngleRadCW/(2*Pi))*(2*Pi); 701 a2 := arc.endAngleRadCW - floor(arc.endAngleRadCW/(2*Pi))*(2*Pi); 702 if not arc.anticlockwise then 703 diff := a2 - a1 704 else 705 diff := a1 - a2; 706 result := (diff < 0) or (diff >= Pi); 707 end; 708 709 { TBGRAPath } 710 711 function TBGRAPath.GetSvgString: string; 712 const RadToDeg = 180/Pi; 713 var savedPos: integer; 714 a: TArcDef; 715 formats: TFormatSettings; 716 lastPos,p1: TPointF; 717 implicitCommand: char; 718 719 function FloatToString(value: single): string; 720 begin 721 result := FloatToStrF(value,ffGeneral,7,0,formats)+' '; 722 end; 723 724 function CoordToString(const pt: TPointF): string; 725 begin 726 lastPos := pt; 727 result := FloatToString(pt.x)+FloatToString(pt.y); 728 end; 729 730 function BoolToString(value: boolean): string; 731 begin 732 if value then 733 result := '1 ' else result := '0 '; 734 end; 735 736 procedure addCommand(command: char; parameters: string); 737 begin 738 if result <> '' then result += ' '; //optional whitespace 739 if command <> implicitCommand then result += command; 740 result += trim(parameters); 741 if command = 'M' then implicitCommand:= 'L' 742 else if command = 'm' then implicitCommand:= 'l' 743 else if command in['z','Z'] then implicitCommand:= #0 744 else implicitCommand := command; 745 end; 746 747 var param: string; 748 749 begin 750 formats := DefaultFormatSettings; 751 formats.DecimalSeparator := '.'; 752 753 result := ''; 754 savedPos:= FDataPos; 755 FDataPos := 0; 756 lastPos := EmptyPointF; 757 implicitCommand := #0; 758 while FDataPos < savedPos do 759 begin 760 case ReadElementType of 761 peMoveTo: addCommand('M',CoordToString(ReadCoord)); 762 peLineTo: addCommand('L',CoordToString(ReadCoord)); 763 peCloseSubPath: addCommand('z',''); 764 peQuadraticBezierTo: 765 begin 766 param := CoordToString(ReadCoord); 767 param += CoordToString(ReadCoord); 768 addCommand('Q',param); 769 end; 770 peCubicBezierTo: 771 begin 772 param := CoordToString(ReadCoord); 773 param += CoordToString(ReadCoord); 774 param += CoordToString(ReadCoord); 775 addCommand('C',param); 776 end; 777 peArc: 778 begin 779 a := ReadArcDef; 780 p1 := ArcStartPoint(a); 781 if isEmptyPointF(lastPos) or (p1 <> lastPos) then 782 addCommand('L',CoordToString(p1)); 783 param := CoordToString(a.radius); 784 param += FloatToString(a.xAngleRadCW*RadToDeg); 785 param += BoolToString(IsLargeArc(a)); 786 param += BoolToString(not a.anticlockwise); 787 param += CoordToString(ArcEndPoint(a)); 788 addCommand('A',param); 789 end; 790 end; 791 end; 792 FDataPos := savedPos; 793 end; 794 795 procedure TBGRAPath.SetSvgString(const AValue: string); 796 begin 797 resetTransform; 798 beginPath; 799 addPath(AValue); 800 end; 801 802 procedure TBGRAPath.addPath(const AValue: string); 803 var p: integer; 804 numberError: boolean; 805 806 function parseFloat: single; 807 var numberStart: integer; 808 errPos: integer; 809 begin 810 while (p <= length(AValue)) and (AValue[p] in[#0..#32,',']) do inc(p); 811 numberStart:= p; 812 if (p <= length(AValue)) and (AValue[p] in['+','-']) then inc(p); 813 while (p <= length(AValue)) and (AValue[p] in['0'..'9','.']) do inc(p); 814 if (p <= length(AValue)) and (AValue[p] in['e','E']) then inc(p); 815 if (p <= length(AValue)) and (AValue[p] in['+','-']) then inc(p); 816 while (p <= length(AValue)) and (AValue[p] in['0'..'9','.']) do inc(p); 817 val(copy(AValue,numberStart,p-numberStart),result,errPos); 818 if errPos <> 0 then numberError := true; 819 end; 820 821 function parseCoord(relative: boolean): TPointF; 822 begin 823 result := PointF(parseFloat,parseFloat); 824 if relative and not isEmptyPointF(FLastCoord) then result += FLastCoord; 825 end; 826 827 var 828 command,implicitCommand: char; 829 relative: boolean; 830 c1,c2,p1: TPointF; 831 a: TArcDef; 832 largeArc: boolean; 833 begin 834 FLastCoord := EmptyPointF; 835 FStartCoord := EmptyPointF; 836 p := 1; 837 implicitCommand:= #0; 838 while p <= length(AValue) do 839 begin 840 command := AValue[p]; 841 if (command in['0'..'9','.','+','-']) and (implicitCommand <> #0) then 842 command := implicitCommand 843 else 844 begin 845 inc(p); 846 end; 847 relative := (command = lowerCase(command)); 848 numberError := false; 849 if upcase(command) in ['L','H','V','C','S','Q','T','A'] then 850 implicitCommand:= command; //by default the command repeats 851 case upcase(command) of 852 'Z': begin 853 closePath; 854 implicitCommand:= #0; 855 end; 856 'M': begin 857 p1 := parseCoord(relative); 858 if not numberError then moveTo(p1); 859 if relative then implicitCommand:= 'l' else 860 implicitCommand:= 'L'; 861 end; 862 'L': begin 863 p1 := parseCoord(relative); 864 if not numberError then lineTo(p1); 865 end; 866 'H': begin 867 if not isEmptyPointF(FLastCoord) then p1 := FLastCoord 868 else p1 := PointF(0,0); 869 if relative then p1.x += parseFloat 870 else p1.x := parseFloat; 871 if not numberError then lineTo(p1); 872 end; 873 'V': begin 874 if not isEmptyPointF(FLastCoord) then p1 := FLastCoord 875 else p1 := PointF(0,0); 876 if relative then p1.y += parseFloat 877 else p1.y := parseFloat; 878 if not numberError then lineTo(p1); 879 end; 880 'C': begin 881 c1 := parseCoord(relative); 882 c2 := parseCoord(relative); 883 p1 := parseCoord(relative); 884 if not numberError then bezierCurveTo(c1,c2,p1); 885 end; 886 'S': begin 887 c2 := parseCoord(relative); 888 p1 := parseCoord(relative); 889 if not numberError then smoothBezierCurveTo(c2,p1); 890 end; 891 'Q': begin 892 c1 := parseCoord(relative); 893 p1 := parseCoord(relative); 894 if not numberError then quadraticCurveTo(c1,p1); 895 end; 896 'T': begin 897 p1 := parseCoord(relative); 898 if not numberError then smoothQuadraticCurveTo(p1); 899 end; 900 'A': begin 901 a.radius := parseCoord(false); 902 a.xAngleRadCW := parseFloat*Pi/180; 903 largeArc := parseFloat<>0; 904 a.anticlockwise:= parseFloat=0; 905 p1 := parseCoord(relative); 906 arcTo(a.radius.x,a.radius.y,a.xAngleRadCW,largeArc,a.anticlockwise,p1.x,p1.y); 907 end; 908 end; 909 end; 910 end; 911 912 procedure TBGRAPath.addPath(source: IBGRAPath); 913 begin 914 source.copyTo(self); 915 end; 916 917 procedure TBGRAPath.NeedSpace(count: integer); 918 begin 919 if FDataPos + count > FDataSize then 920 begin 921 FDataSize := FDataSize*2+8; 922 ReAllocMem(FData, FDataSize); 923 end; 924 end; 925 926 procedure TBGRAPath.StoreCoord(const pt: TPointF); 927 begin 928 NeedSpace(sizeof(single)*2); 929 with FMatrix*pt do 930 begin 931 PSingle(FData+FDataPos)^ := x; 932 PSingle(FData+FDataPos+sizeof(single))^ := y; 933 end; 934 Inc(FDataPos, sizeof(single)*2); 935 FLastCoord := pt; 936 end; 937 938 function TBGRAPath.ReadCoord: TPointF; 939 begin 940 result := PPointF(FData+FDataPos)^; 941 inc(FDataPos,sizeof(TPointF)); 942 end; 943 944 procedure TBGRAPath.StoreElementType(value: TBGRAPathElementType); 945 begin 946 NeedSpace(sizeof(TBGRAPathElementType)); 947 PBGRAPathElementType(FData+FDataPos)^ := value; 948 Inc(FDataPos, sizeof(TBGRAPathElementType)); 949 FLastElementType:= value; 950 end; 951 952 function TBGRAPath.ReadElementType: TBGRAPathElementType; 953 begin 954 result := PBGRAPathElementType(FData+FDataPos)^; 955 inc(FDataPos,sizeof(TBGRAPathElementType)); 956 end; 957 958 function TBGRAPath.ReadArcDef: TArcDef; 959 begin 960 result := PArcDef(FData+FDataPos)^; 961 inc(FDataPos,sizeof(TArcDef)); 962 end; 963 964 procedure TBGRAPath.RewindFloat; 965 begin 966 if FDataPos >= sizeof(single) then dec(FDataPos, sizeof(Single)); 967 end; 968 969 procedure TBGRAPath.Init; 970 begin 971 FData := nil; 972 FDataSize := 0; 973 FDataPos := 0; 974 FLastElementType := peNone; 975 FLastCoord := EmptyPointF; 976 FStartCoord := EmptyPointF; 977 FExpectedControlPoint := EmptyPointF; 978 resetTransform; 979 end; 980 981 constructor TBGRAPath.Create; 982 begin 983 Init; 984 end; 985 986 constructor TBGRAPath.Create(ASvgString: string); 987 begin 988 Init; 989 SvgString:= ASvgString; 990 end; 991 992 destructor TBGRAPath.Destroy; 993 begin 994 if Assigned(FData) then 995 begin 996 FreeMem(FData); 997 FData := nil; 998 end; 999 inherited Destroy; 1000 end; 1001 1002 procedure TBGRAPath.beginPath; 1003 begin 1004 FDataPos := 0; 1005 end; 1006 1007 procedure TBGRAPath.closePath; 1008 begin 1009 if (FLastElementType <> peNone) and (FLastElementType <> peCloseSubPath) then 1010 begin 1011 StoreElementType(peCloseSubPath); 1012 FLastCoord := FStartCoord; 1013 end; 1014 end; 1015 1016 procedure TBGRAPath.translate(x, y: single); 1017 begin 1018 FMatrix *= AffineMatrixTranslation(x,y); 1019 end; 1020 1021 procedure TBGRAPath.resetTransform; 1022 begin 1023 FMatrix := AffineMatrixIdentity; 1024 FAngleRadCW := 0; 1025 FScale:= 1; 1026 end; 1027 1028 procedure TBGRAPath.rotate(angleRadCW: single); 1029 begin 1030 FMatrix *= AffineMatrixRotationRad(-angleRadCW); 1031 FAngleRadCW += angleRadCW; 1032 end; 1033 1034 procedure TBGRAPath.rotateDeg(angleDeg: single); 1035 const degToRad = Pi/180; 1036 begin 1037 rotate(angleDeg*degToRad); 1038 end; 1039 1040 procedure TBGRAPath.rotate(angleRadCW: single; center: TPointF); 1041 begin 1042 translate(center.x,center.y); 1043 rotate(angleRadCW); 1044 translate(-center.x,-center.y); 1045 end; 1046 1047 procedure TBGRAPath.rotateDeg(angleDeg: single; center: TPointF); 1048 begin 1049 translate(center.x,center.y); 1050 rotateDeg(angleDeg); 1051 translate(-center.x,-center.y); 1052 end; 1053 1054 procedure TBGRAPath.scale(factor: single); 1055 begin 1056 FMatrix *= AffineMatrixScale(factor,factor); 1057 FScale *= factor; 1058 end; 1059 1060 procedure TBGRAPath.moveTo(x, y: single); 1061 begin 1062 moveTo(PointF(x,y)); 1063 end; 1064 1065 procedure TBGRAPath.lineTo(x, y: single); 1066 begin 1067 lineTo(PointF(x,y)); 1068 end; 1069 1070 procedure TBGRAPath.moveTo(const pt: TPointF); 1071 begin 1072 if FLastElementType <> peMoveTo then 1073 begin 1074 StoreElementType(peMoveTo); 1075 StoreCoord(pt); 1076 end else 1077 begin 1078 RewindFloat; 1079 RewindFloat; 1080 StoreCoord(pt); 1081 end; 1082 FLastCoord := pt; 1083 FStartCoord := FLastCoord; 1084 end; 1085 1086 procedure TBGRAPath.lineTo(const pt: TPointF); 1087 begin 1088 if not isEmptyPointF(FLastCoord) then 1089 begin 1090 StoreElementType(peLineTo); 1091 StoreCoord(pt); 1092 FLastCoord := pt; 1093 end else 1094 moveTo(pt); 1095 end; 1096 1097 procedure TBGRAPath.polylineTo(const pts: array of TPointF); 1098 var i: integer; 1099 begin 1100 NeedSpace((sizeof(TBGRAPathElementType)+2*sizeof(single))*length(pts)); 1101 for i := 0 to high(pts) do with pts[i] do lineTo(x,y); 1102 end; 1103 1104 procedure TBGRAPath.quadraticCurveTo(cpx, cpy, x, y: single); 1105 begin 1106 quadraticCurveTo(PointF(cpx,cpy),PointF(x,y)); 1107 end; 1108 1109 procedure TBGRAPath.quadraticCurveTo(const cp, pt: TPointF); 1110 begin 1111 if not isEmptyPointF(FLastCoord) then 1112 begin 1113 StoreElementType(peQuadraticBezierTo); 1114 StoreCoord(cp); 1115 StoreCoord(pt); 1116 FLastCoord := pt; 1117 end else 1118 lineTo(pt); 1119 FExpectedControlPoint := pt+(pt-cp); 1120 end; 1121 1122 procedure TBGRAPath.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y: single); 1123 begin 1124 bezierCurveTo(PointF(cp1x,cp1y),PointF(cp2x,cp2y),PointF(x,y)); 1125 end; 1126 1127 procedure TBGRAPath.bezierCurveTo(const cp1, cp2, pt: TPointF); 1128 begin 1129 if isEmptyPointF(FLastCoord) then moveTo(cp1); 1130 StoreElementType(peCubicBezierTo); 1131 StoreCoord(cp1); 1132 StoreCoord(cp2); 1133 StoreCoord(pt); 1134 FLastCoord := pt; 1135 FExpectedControlPoint := pt + (pt-cp2); 1136 end; 1137 1138 procedure TBGRAPath.bezierCurve(const curve: TCubicBezierCurve); 1139 begin 1140 moveTo(curve.p1); 1141 bezierCurveTo(curve.c1,curve.c2,curve.p2); 1142 end; 1143 1144 procedure TBGRAPath.smoothBezierCurveTo(cp2x, cp2y, x, y: single); 1145 begin 1146 smoothBezierCurveTo(PointF(cp2x,cp2y),PointF(x,y)); 1147 end; 1148 1149 procedure TBGRAPath.smoothBezierCurveTo(const cp2, pt: TPointF); 1150 begin 1151 if (FLastElementType = peCubicBezierTo) and not isEmptyPointF(FExpectedControlPoint) then 1152 bezierCurveTo(FExpectedControlPoint,cp2,pt) 1153 else if not isEmptyPointF(FLastCoord) then 1154 bezierCurveTo(FLastCoord,cp2,pt) 1155 else 1156 bezierCurveTo(cp2,cp2,pt); 1157 end; 1158 1159 procedure TBGRAPath.quadraticCurve(const curve: TQuadraticBezierCurve); 1160 begin 1161 moveTo(curve.p1); 1162 quadraticCurveTo(curve.c,curve.p2); 1163 end; 1164 1165 procedure TBGRAPath.smoothQuadraticCurveTo(x, y: single); 1166 begin 1167 smoothQuadraticCurveTo(PointF(x,y)); 1168 end; 1169 1170 procedure TBGRAPath.smoothQuadraticCurveTo(const pt: TPointF); 1171 begin 1172 if (FLastElementType = peQuadraticBezierTo) and not isEmptyPointF(FExpectedControlPoint) then 1173 quadraticCurveTo(FExpectedControlPoint,pt) 1174 else if not isEmptyPointF(FLastCoord) then 1175 quadraticCurveTo(FLastCoord,pt) 1176 else 1177 quadraticCurveTo(pt,pt); 1178 end; 1179 1180 procedure TBGRAPath.rect(x, y, w, h: single); 1181 begin 1182 moveTo(x,y); 1183 lineTo(x+w,y); 1184 lineTo(x+w,y+h); 1185 lineTo(x,y+h); 1186 closePath; 1187 end; 1188 1189 procedure TBGRAPath.roundRect(x, y, w, h, radius: single); 1190 begin 1191 if radius <= 0 then 1192 begin 1193 rect(x,y,w,h); 1194 exit; 1195 end; 1196 if (w <= 0) or (h <= 0) then exit; 1197 if radius*2 > w then radius := w/2; 1198 if radius*2 > h then radius := h/2; 1199 moveTo(x+radius,y); 1200 arcTo(PointF(x+w,y),PointF(x+w,y+h), radius); 1201 arcTo(PointF(x+w,y+h),PointF(x,y+h), radius); 1202 arcTo(PointF(x,y+h),PointF(x,y), radius); 1203 arcTo(PointF(x,y),PointF(x+w,y), radius); 1204 closePath; 1205 end; 1206 1207 procedure TBGRAPath.arc(cx, cy, radius, startAngleRadCW, endAngleRadCW: single; 1208 anticlockwise: boolean); 1209 begin 1210 arc(cx,cy,radius,radius,0,startAngleRadCW,endAngleRadCW,anticlockwise); 1211 end; 1212 1213 procedure TBGRAPath.arc(cx, cy, radius, startAngleRadCW, endAngleRadCW: single); 1214 begin 1215 arc(cx,cy,radius,startAngleRadCW,endAngleRadCW,false); 1216 end; 1217 1218 procedure TBGRAPath.arcDeg(cx, cy, radius, startAngleDeg, endAngleDeg: single; 1219 anticlockwise: boolean); 1220 const degToRad = Pi/180; 1221 begin 1222 arc(cx,cy,radius,(startAngleDeg-90)*degToRad,(endAngleDeg-90)*degToRad,anticlockwise); 1223 end; 1224 1225 procedure TBGRAPath.arcDeg(cx, cy, radius, startAngleDeg, endAngleDeg: single); 1226 const degToRad = Pi/180; 1227 begin 1228 arc(cx,cy,radius,(startAngleDeg-90)*degToRad,(endAngleDeg-90)*degToRad); 1229 end; 1230 1231 procedure TBGRAPath.arcTo(x1, y1, x2, y2, radius: single); 1232 begin 1233 arcTo(PointF(x1,y1), PointF(x2,y2), radius); 1234 end; 1235 1236 procedure TBGRAPath.arcTo(const p1, p2: TPointF; radius: single); 1237 var p0 : TPointF; 1238 begin 1239 if isEmptyPointF(FLastCoord) then 1240 p0 := p1 else p0 := FLastCoord; 1241 arc(Html5ArcTo(p0,p1,p2,radius)); 1242 end; 1243 1244 procedure TBGRAPath.arc(const arcDef: TArcDef); 1245 var transformedArc: TArcDef; 1246 begin 1247 if (arcDef.radius.x = 0) and (arcDef.radius.y = 0) then 1248 lineTo(arcDef.center) 1249 else 1250 begin 1251 if isEmptyPointF(FLastCoord) then 1252 moveTo(ArcStartPoint(arcDef)); 1253 StoreElementType(peArc); 1254 NeedSpace(sizeof(TArcDef)); 1255 transformedArc.anticlockwise := arcDef.anticlockwise; 1256 transformedArc.startAngleRadCW := arcDef.startAngleRadCW; 1257 transformedArc.endAngleRadCW := arcDef.endAngleRadCW; 1258 transformedArc.center := FMatrix*arcDef.center; 1259 transformedArc.radius := arcDef.radius*FScale; 1260 transformedArc.xAngleRadCW := arcDef.xAngleRadCW+FAngleRadCW; 1261 PArcDef(FData+FDataPos)^ := transformedArc; 1262 inc(FDataPos, sizeof(TArcDef)); 1263 FLastCoord := ArcEndPoint(arcDef); 1264 end; 1265 end; 1266 1267 procedure TBGRAPath.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, 1268 endAngleRadCW: single); 1269 begin 1270 arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,false)); 1271 end; 1272 1273 procedure TBGRAPath.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; 1274 anticlockwise: boolean); 1275 begin 1276 arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,anticlockwise)); 1277 end; 1278 1279 procedure TBGRAPath.arcTo(rx, ry, xAngleRadCW: single; largeArc, 1280 anticlockwise: boolean; x, y: single); 1281 begin 1282 if isEmptyPointF(FLastCoord) then 1283 moveTo(x,y) 1284 else 1285 arc(SvgArcTo(FLastCoord, rx,ry, xAngleRadCW, largeArc, anticlockwise, PointF(x,y))); 1286 end; 1287 1288 procedure TBGRAPath.copyTo(dest: IBGRAPath); 1289 var savedPos: integer; 1290 cp1,cp2,p1: TPointF; 1291 begin 1292 savedPos:= FDataPos; 1293 FDataPos := 0; 1294 while FDataPos < savedPos do 1295 begin 1296 case ReadElementType of 1297 peMoveTo: dest.moveTo(ReadCoord); 1298 peLineTo: dest.lineTo(ReadCoord); 1299 peCloseSubPath: dest.closePath; 1300 peQuadraticBezierTo: 1301 begin 1302 cp1 := ReadCoord; 1303 p1 := ReadCoord; 1304 dest.quadraticCurveTo(cp1,p1); 1305 end; 1306 peCubicBezierTo: 1307 begin 1308 cp1 := ReadCoord; 1309 cp2 := ReadCoord; 1310 p1 := ReadCoord; 1311 dest.bezierCurveTo(cp1,cp2,p1); 1312 end; 1313 peArc: dest.arc(ReadArcDef); 1314 end; 1315 end; 1316 FDataPos := savedPos; 1317 end; 1318 1319 function TBGRAPath.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1320 begin 1321 if GetInterface(iid, obj) then 1322 Result := S_OK 1323 else 1324 Result := longint(E_NOINTERFACE); 1325 end; 1326 1327 { There is no automatic reference counting, but it is compulsory to define these functions } 1328 function TBGRAPath._AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1329 begin 1330 result := 0; 1331 end; 1332 1333 function TBGRAPath._Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND}; 1334 begin 1335 result := 0; 1336 end; 438 1337 439 1338 end. -
GraphicTest/Packages/bgrabitmap/bgrapen.pas
r452 r472 20 20 TBGRAPolyLineOption = (plRoundCapOpen, //specifies that the line ending is opened 21 21 plCycle, //specifies that it is a polygon 22 plAutoCycle); //specifies that a cycle must be used if the last point is the first point 22 plAutoCycle, //specifies that a cycle must be used if the last point is the first point 23 plNoStartCap, 24 plNoEndCap); 23 25 TBGRAPolyLineOptions = set of TBGRAPolyLineOption; 26 TComputeArrowHeadProc = function(const APosition: TPointF; const ADirection: TPointF; const AWidth: single; const ACurrentPos: single): ArrayOfTPointF of object; 24 27 25 28 { Draw a polyline with specified parameters. If a scanner is specified, it is used as a texture. … … 27 30 procedure BGRAPolyLine(bmp: TBGRACustomBitmap; const linepts: array of TPointF; 28 31 width: single; pencolor: TBGRAPixel; linecap: TPenEndCap; joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 29 options: TBGRAPolyLineOptions; scan: IBGRAScanner = nil; miterLimit: single = 2 );32 options: TBGRAPolyLineOptions; scan: IBGRAScanner = nil; miterLimit: single = 2; arrowStart: TComputeArrowHeadProc = nil; arrowStartPos: single = 0; arrowEnd: TComputeArrowHeadProc = nil; arrowEndPos: single = 0); 30 33 31 34 { Compute the path for a polyline } 32 35 function ComputeWidePolylinePoints(const linepts: array of TPointF; width: single; 33 36 pencolor: TBGRAPixel; linecap: TPenEndCap; joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 34 options: TBGRAPolyLineOptions; miterLimit: single = 2 ): ArrayOfTPointF;37 options: TBGRAPolyLineOptions; miterLimit: single = 2; arrowStart: TComputeArrowHeadProc = nil; wantedStartArrowPos: single = 0; arrowEnd: TComputeArrowHeadProc = nil; WantedEndArrowPos: single = 0): ArrayOfTPointF; 35 38 36 39 { Compute the path for a poly-polyline } 37 40 function ComputeWidePolyPolylinePoints(const linepts: array of TPointF; width: single; 38 41 pencolor: TBGRAPixel; linecap: TPenEndCap; joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 39 options: TBGRAPolyLineOptions; miterLimit: single = 2 ): ArrayOfTPointF;42 options: TBGRAPolyLineOptions; miterLimit: single = 2; arrowStart: TComputeArrowHeadProc = nil; arrowStartPos: single = 0; arrowEnd: TComputeArrowHeadProc = nil; arrowEndPos: single = 0): ArrayOfTPointF; 40 43 41 44 {--------------------- Pixel line procedures --------------------------} … … 44 47 45 48 //aliased version 46 procedure BGRADrawLineAliased(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean );49 procedure BGRADrawLineAliased(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode = dmDrawWithTransparency); 47 50 procedure BGRAEraseLineAliased(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; alpha: byte; DrawLastPixel: boolean); 48 51 49 52 //antialiased version 50 procedure BGRADrawLineAntialias( dest: TBGRACustomBitmap; x1, y1, x2, y2: integer;51 c: TBGRAPixel; DrawLastPixel: boolean );53 procedure BGRADrawLineAntialias({%H-}dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 54 c: TBGRAPixel; DrawLastPixel: boolean; LinearBlend : boolean = false); 52 55 procedure BGRAEraseLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 53 56 calpha: byte; DrawLastPixel: boolean); … … 55 58 //antialiased version with bicolor dashes (to draw a frame) 56 59 procedure BGRADrawLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 57 c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer );60 c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer; LinearBlend : boolean = false); 58 61 59 62 //length added to ensure accepable alpha join (using TBGRAMultishapeFiller is still better) … … 74 77 75 78 procedure BGRADrawLineAliased(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 76 c: TBGRAPixel; DrawLastPixel: boolean); 79 c: TBGRAPixel; DrawLastPixel: boolean; ADrawMode: TDrawMode); 80 var 81 Y, X: integer; 82 DX, DY, SX, SY, E: integer; 83 PixelProc: procedure (x, y: int32or64; c: TBGRAPixel) of object; 84 begin 85 if (Y1 = Y2) then 86 begin 87 if (X1 = X2) then 88 begin 89 if DrawLastPixel then 90 dest.DrawPixel(X1, Y1, c, ADrawMode); 91 end else 92 begin 93 if not DrawLastPixel then 94 begin 95 if X2 > X1 then dec(X2) else inc(X2); 96 end; 97 dest.HorizLine(X1,Y1,X2,c, ADrawMode); 98 end; 99 Exit; 100 end else 101 if (X1 = X2) then 102 begin 103 if not DrawLastPixel then 104 begin 105 if Y2 > Y1 then dec(Y2) else inc(Y2); 106 end; 107 dest.VertLine(X1,Y1,Y2,c, ADrawMode); 108 end; 109 110 DX := X2 - X1; 111 DY := Y2 - Y1; 112 113 if (ADrawMode = dmSetExceptTransparent) and (c.alpha <> 255) then exit else 114 if c.alpha = 0 then 115 begin 116 if ADrawMode in[dmDrawWithTransparency,dmLinearBlend] then exit; 117 if (ADrawMode = dmXor) and (DWord(c)=0) then exit; 118 end; 119 case ADrawMode of 120 dmDrawWithTransparency: PixelProc := @dest.DrawPixel; 121 dmXor: PixelProc := @dest.XorPixel; 122 dmLinearBlend: PixelProc := @dest.FastBlendPixel; 123 else 124 PixelProc := @dest.SetPixel; 125 end; 126 127 if DX < 0 then 128 begin 129 SX := -1; 130 DX := -DX; 131 end 132 else 133 SX := 1; 134 135 if DY < 0 then 136 begin 137 SY := -1; 138 DY := -DY; 139 end 140 else 141 SY := 1; 142 143 DX := DX shl 1; 144 DY := DY shl 1; 145 146 X := X1; 147 Y := Y1; 148 if DX > DY then 149 begin 150 E := DY - DX shr 1; 151 152 while X <> X2 do 153 begin 154 PixelProc(X, Y, c); 155 if E >= 0 then 156 begin 157 Inc(Y, SY); 158 Dec(E, DX); 159 end; 160 Inc(X, SX); 161 Inc(E, DY); 162 end; 163 end 164 else 165 begin 166 E := DX - DY shr 1; 167 168 while Y <> Y2 do 169 begin 170 PixelProc(X, Y, c); 171 if E >= 0 then 172 begin 173 Inc(X, SX); 174 Dec(E, DY); 175 end; 176 Inc(Y, SY); 177 Inc(E, DX); 178 end; 179 end; 180 181 if DrawLastPixel then 182 PixelProc(X2, Y2, c); 183 end; 184 185 procedure BGRAEraseLineAliased(dest: TBGRACustomBitmap; x1, y1, x2, 186 y2: integer; alpha: byte; DrawLastPixel: boolean); 77 187 var 78 188 Y, X: integer; … … 83 193 begin 84 194 if DrawLastPixel then 85 dest. DrawPixel(X1, Y1, c);195 dest.ErasePixel(X1, Y1, alpha); 86 196 Exit; 87 197 end; … … 117 227 while X <> X2 do 118 228 begin 119 dest. DrawPixel(X, Y, c);229 dest.ErasePixel(X, Y, alpha); 120 230 if E >= 0 then 121 231 begin … … 133 243 while Y <> Y2 do 134 244 begin 135 dest. DrawPixel(X, Y, c);245 dest.ErasePixel(X, Y, alpha); 136 246 if E >= 0 then 137 247 begin … … 145 255 146 256 if DrawLastPixel then 147 dest. DrawPixel(X2, Y2, c);257 dest.ErasePixel(X2, Y2, alpha); 148 258 end; 149 259 150 procedure BGRA EraseLineAliased(dest: TBGRACustomBitmap; x1, y1, x2,151 y2: integer; alpha: byte; DrawLastPixel: boolean);152 var 153 Y, X: integer;260 procedure BGRADrawLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 261 c: TBGRAPixel; DrawLastPixel: boolean; LinearBlend : boolean); 262 var 263 Y, X: integer; 154 264 DX, DY, SX, SY, E: integer; 265 alpha: NativeUInt; 266 pixelproc: procedure(x,y: int32or64; c: TBGRAPixel) of object; 155 267 begin 268 if LinearBlend then 269 pixelproc := @dest.FastBlendPixel 270 else 271 pixelproc := @dest.DrawPixel; 156 272 157 273 if (Y1 = Y2) and (X1 = X2) then 158 274 begin 159 275 if DrawLastPixel then 160 dest.ErasePixel(X1, Y1, alpha);276 pixelproc(X1, Y1, c); 161 277 Exit; 162 278 end; … … 186 302 X := X1; 187 303 Y := Y1; 304 188 305 if DX > DY then 189 306 begin 190 E := DY - DX shr 1;307 E := 0; 191 308 192 309 while X <> X2 do 193 310 begin 194 dest.ErasePixel(X, Y, alpha); 195 if E >= 0 then 311 alpha := c.alpha * E div DX; 312 pixelproc(X, Y, BGRA(c.red, c.green, c.blue, c.alpha - alpha)); 313 pixelproc(X, Y + SY, BGRA(c.red, c.green, c.blue, alpha)); 314 Inc(E, DY); 315 if E >= DX then 196 316 begin 197 317 Inc(Y, SY); … … 199 319 end; 200 320 Inc(X, SX); 201 Inc(E, DY);202 321 end; 203 322 end 204 323 else 205 324 begin 206 E := DX - DY shr 1;325 E := 0; 207 326 208 327 while Y <> Y2 do 209 328 begin 210 dest.ErasePixel(X, Y, alpha); 211 if E >= 0 then 329 alpha := c.alpha * E div DY; 330 pixelproc(X, Y, BGRA(c.red, c.green, c.blue, c.alpha - alpha)); 331 pixelproc(X + SX, Y, BGRA(c.red, c.green, c.blue, alpha)); 332 Inc(E, DX); 333 if E >= DY then 212 334 begin 213 335 Inc(X, SX); … … 215 337 end; 216 338 Inc(Y, SY); 217 Inc(E, DX); 218 end; 219 end; 220 339 end; 340 end; 221 341 if DrawLastPixel then 222 dest.ErasePixel(X2, Y2, alpha);342 pixelproc(X2, Y2, c); 223 343 end; 224 344 225 procedure BGRA DrawLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer;226 c: TBGRAPixel; DrawLastPixel: boolean);345 procedure BGRAEraseLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, 346 y2: integer; calpha: byte; DrawLastPixel: boolean); 227 347 var 228 348 Y, X: integer; 229 349 DX, DY, SX, SY, E: integer; 230 alpha: single;350 alpha: NativeUInt; 231 351 begin 232 352 … … 234 354 begin 235 355 if DrawLastPixel then 236 dest. DrawPixel(X1, Y1, c);356 dest.ErasePixel(X1, Y1, calpha); 237 357 Exit; 238 358 end; … … 269 389 while X <> X2 do 270 390 begin 271 alpha := 1 - E / DX; 272 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, round(c.alpha * sqrt(alpha)))); 273 dest.DrawPixel(X, Y + SY, BGRA(c.red, c.green, c.blue, 274 round(c.alpha * sqrt(1 - alpha)))); 391 alpha := calpha * E div DX; 392 dest.ErasePixel(X, Y, calpha - alpha); 393 dest.ErasePixel(X, Y + SY, alpha); 275 394 Inc(E, DY); 276 395 if E >= DX then … … 288 407 while Y <> Y2 do 289 408 begin 290 alpha := 1 - E / DY; 291 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, round(c.alpha * sqrt(alpha)))); 292 dest.DrawPixel(X + SX, Y, BGRA(c.red, c.green, c.blue, 293 round(c.alpha * sqrt(1 - alpha)))); 294 Inc(E, DX); 295 if E >= DY then 296 begin 297 Inc(X, SX); 298 Dec(E, DY); 299 end; 300 Inc(Y, SY); 301 end; 302 end; 303 if DrawLastPixel then 304 dest.DrawPixel(X2, Y2, c); 305 end; 306 307 procedure BGRAEraseLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, 308 y2: integer; calpha: byte; DrawLastPixel: boolean); 309 var 310 Y, X: integer; 311 DX, DY, SX, SY, E: integer; 312 alpha: single; 313 begin 314 315 if (Y1 = Y2) and (X1 = X2) then 316 begin 317 if DrawLastPixel then 318 dest.ErasePixel(X1, Y1, calpha); 319 Exit; 320 end; 321 322 DX := X2 - X1; 323 DY := Y2 - Y1; 324 325 if DX < 0 then 326 begin 327 SX := -1; 328 DX := -DX; 329 end 330 else 331 SX := 1; 332 333 if DY < 0 then 334 begin 335 SY := -1; 336 DY := -DY; 337 end 338 else 339 SY := 1; 340 341 DX := DX shl 1; 342 DY := DY shl 1; 343 344 X := X1; 345 Y := Y1; 346 347 if DX > DY then 348 begin 349 E := 0; 350 351 while X <> X2 do 352 begin 353 alpha := 1 - E / DX; 354 dest.ErasePixel(X, Y, round(calpha * sqrt(alpha))); 355 dest.ErasePixel(X, Y + SY, round(calpha * sqrt(1 - alpha))); 356 Inc(E, DY); 357 if E >= DX then 358 begin 359 Inc(Y, SY); 360 Dec(E, DX); 361 end; 362 Inc(X, SX); 363 end; 364 end 365 else 366 begin 367 E := 0; 368 369 while Y <> Y2 do 370 begin 371 alpha := 1 - E / DY; 372 dest.ErasePixel(X, Y, round(calpha * sqrt(alpha))); 373 dest.ErasePixel(X + SX, Y, round(calpha * sqrt(1 - alpha))); 409 alpha := calpha * E div DY; 410 dest.ErasePixel(X, Y, calpha - alpha); 411 dest.ErasePixel(X + SX, Y, alpha); 374 412 Inc(E, DX); 375 413 if E >= DY then … … 386 424 387 425 procedure BGRADrawLineAntialias(dest: TBGRACustomBitmap; x1, y1, x2, y2: integer; 388 c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer );426 c1, c2: TBGRAPixel; dashLen: integer; DrawLastPixel: boolean; var DashPos: integer; LinearBlend : boolean); 389 427 var 390 428 Y, X: integer; 391 429 DX, DY, SX, SY, E: integer; 392 alpha: single;430 alpha: NativeUInt; 393 431 c: TBGRAPixel; 394 432 begin … … 396 434 if DashLen <= 0 then 397 435 begin 398 BGRADrawLineAntialias(dest,x1,y1,x2,y2,MergeBGRA(c1,c2),DrawLastPixel );436 BGRADrawLineAntialias(dest,x1,y1,x2,y2,MergeBGRA(c1,c2),DrawLastPixel,LinearBlend); 399 437 exit; 400 438 end; … … 441 479 while X <> X2 do 442 480 begin 443 alpha := 1 - E / DX; 444 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, round(c.alpha * sqrt(alpha)))); 445 dest.DrawPixel(X, Y + SY, BGRA(c.red, c.green, c.blue, 446 round(c.alpha * sqrt(1 - alpha)))); 481 alpha := c.alpha * E div DX; 482 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, c.alpha - alpha)); 483 dest.DrawPixel(X, Y + SY, BGRA(c.red, c.green, c.blue, alpha)); 447 484 Inc(E, DY); 448 485 if E >= DX then … … 470 507 while Y <> Y2 do 471 508 begin 472 alpha := 1 - E / DY; 473 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, round(c.alpha * sqrt(alpha)))); 474 dest.DrawPixel(X + SX, Y, BGRA(c.red, c.green, c.blue, 475 round(c.alpha * sqrt(1 - alpha)))); 509 alpha := c.alpha * E div DY; 510 dest.DrawPixel(X, Y, BGRA(c.red, c.green, c.blue, c.alpha - alpha)); 511 dest.DrawPixel(X + SX, Y, BGRA(c.red, c.green, c.blue, alpha)); 476 512 Inc(E, DX); 477 513 if E >= DY then … … 592 628 procedure AddPt(pt: TPointF); 593 629 begin 594 if nbStyled = length(styledPts) then 595 setlength(styledPts,nbStyled*2+4); 596 styledPts[nbStyled] := pt; 597 inc(nbStyled); 630 if (nbStyled = 0) or (pt <> styledPts[nbStyled-1]) then 631 begin 632 if nbStyled = length(styledPts) then 633 setlength(styledPts,nbStyled*2+4); 634 styledPts[nbStyled] := pt; 635 inc(nbStyled); 636 end; 598 637 end; 599 638 … … 708 747 procedure BGRAPolyLine(bmp: TBGRACustomBitmap; const linepts: array of TPointF; width: single; 709 748 pencolor: TBGRAPixel; linecap: TPenEndCap; joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 710 options: TBGRAPolyLineOptions; scan: IBGRAScanner; miterLimit: single );749 options: TBGRAPolyLineOptions; scan: IBGRAScanner; miterLimit: single; arrowStart: TComputeArrowHeadProc; arrowStartPos: single; arrowEnd: TComputeArrowHeadProc; arrowEndPos: single); 711 750 var 712 751 widePolylinePoints: ArrayOfTPointF; 713 752 begin 714 widePolylinePoints := ComputeWidePolylinePoints(linepts,width,pencolor,linecap,joinstyle,penstyle,options,miterLimit );753 widePolylinePoints := ComputeWidePolylinePoints(linepts,width,pencolor,linecap,joinstyle,penstyle,options,miterLimit,arrowStart,arrowStartPos,arrowEnd,arrowEndPos); 715 754 if scan <> nil then 716 755 bmp.FillPolyAntialias(widePolylinePoints,scan) … … 721 760 function ComputeWidePolylinePoints(const linepts: array of TPointF; width: single; 722 761 pencolor: TBGRAPixel; linecap: TPenEndCap; joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 723 options: TBGRAPolyLineOptions; miterLimit: single): ArrayOfTPointF; 724 var 762 options: TBGRAPolyLineOptions; miterLimit: single; arrowStart: TComputeArrowHeadProc; wantedStartArrowPos: single; arrowEnd: TComputeArrowHeadProc; wantedEndArrowPos: single): ArrayOfTPointF; 763 var 764 startArrowPos, startArrowDir, endArrowPos, endArrowDir: TPointF; 765 startArrowLinePos, endArrowLinePos: single; 725 766 borders : array of record 726 767 leftSide,rightSide: TLineDef; … … 883 924 pts[lastPointIndex] - borders[lastPointIndex-1].leftDir); 884 925 885 if (lastPointIndex = high(pts)) and (linecap = pecRound) then926 if (lastPointIndex = high(pts)) and (linecap = pecRound) and not (plNoEndCap in options) then 886 927 begin 887 928 if not (plRoundCapOpen in options) then … … 937 978 end; 938 979 FlushLine(-1); 980 end; 981 end; 982 983 procedure FinalizeArray; 984 var arrowStartData, arrowEndData: ArrayOfTPointF; 985 finalNb,i,delta: integer; 986 hasStart,hasEnd: boolean; 987 begin 988 if assigned(arrowStart) and not isEmptyPointF(startArrowPos) then 989 arrowStartData := arrowStart(startArrowPos, startArrowDir, width, startArrowLinePos) 990 else 991 arrowStartData := nil; 992 if assigned(arrowEnd) and not isEmptyPointF(endArrowPos) then 993 arrowEndData := arrowEnd(endArrowPos, endArrowDir, width, endArrowLinePos) 994 else 995 arrowEndData := nil; 996 hasStart := length(arrowStartData)>0; 997 hasEnd := length(arrowEndData)>0; 998 finalNb := NbPolyAcc; 999 if hasStart then 1000 begin 1001 delta := length(arrowStartData)+1; 1002 finalNb += delta; 1003 end else delta := 0; 1004 if hasEnd then finalNb += length(arrowEndData)+1; 1005 SetLength(Result, finalNb); 1006 if hasStart then 1007 begin 1008 for i := NbPolyAcc-1 downto 0 do 1009 result[i+delta] := result[i]; 1010 result[delta-1] := EmptyPointF; 1011 for i := 0 to high(arrowStartData) do 1012 result[i] := arrowStartData[i]; 1013 end; 1014 if hasEnd then 1015 begin 1016 delta += NbPolyAcc+1; 1017 result[delta-1] := EmptyPointF; 1018 for i := 0 to high(arrowEndData) do 1019 result[i+delta] := arrowEndData[i]; 939 1020 end; 940 1021 end; … … 950 1031 ShouldFlushLine, HasLittleBorder, NormalRestart: Boolean; 951 1032 pt1,pt2,pt3,pt4: TPointF; 1033 linePos: single; 1034 startArrowDone,endArrowDone: boolean; 952 1035 953 1036 begin 954 1037 Result := nil; 955 1038 956 if length(linepts)=0then exit;1039 if (length(linepts)=0) or (width = 0) then exit; 957 1040 if IsClearPenStyle(penstyle) then exit; 958 1041 for i := 0 to high(linepts) do … … 965 1048 if (plAutoCycle in options) and (length(linepts) >= 2) and (linepts[0]=linepts[high(linepts)]) then 966 1049 options := options + [plCycle]; 1050 if plNoEndCap in options then options := options - [plRoundCapOpen]; 967 1051 968 1052 hw := width / 2; … … 1006 1090 exit; 1007 1091 end; 1092 1093 startArrowDir := EmptyPointF; 1094 startArrowPos := EmptyPointF; 1095 endArrowDir := EmptyPointF; 1096 endArrowPos := EmptyPointF; 1097 startArrowDone := @arrowStart = nil; 1098 endArrowDone := @arrowEnd = nil; 1008 1099 1009 1100 //init computed points arrays … … 1014 1105 NbPolyAcc := 0; 1015 1106 1107 if not endArrowDone then 1108 begin 1109 wantedEndArrowPos:= -wantedEndArrowPos*width; 1110 linePos := 0; 1111 for i := high(pts) downto 1 do 1112 begin 1113 dir := pts[i-1]-pts[i]; 1114 len := sqrt(dir*dir); 1115 dir *= 1/len; 1116 if not endArrowDone and (linePos+len >= wantedEndArrowPos) then 1117 begin 1118 endArrowPos := pts[i]; 1119 endArrowDir := -dir; 1120 endArrowLinePos := -linePos/width; 1121 endArrowDone := true; 1122 break; 1123 end; 1124 linePos += len; 1125 end; 1126 end; 1127 1128 wantedStartArrowPos:= -wantedStartArrowPos*width; 1129 linePos := 0; 1016 1130 //compute borders 1017 1131 setlength(borders, length(pts)-1); … … 1021 1135 len := sqrt(dir*dir); 1022 1136 dir *= 1/len; 1023 1024 if (linecap = pecSquare) and ((i=0) or (i=high(pts)-1)) then //for square cap, just start and end further 1137 if not startArrowDone and (linePos+len >= wantedStartArrowPos) then 1138 begin 1139 startArrowPos := pts[i]; 1140 startArrowDir := -dir; 1141 startArrowLinePos := -linePos/width; 1142 startArrowDone := true; 1143 end; 1144 if (linecap = pecSquare) and ((not (plNoStartCap in options) and (i=0)) or 1145 (not (plNoEndCap in options) and (i=high(pts)-1))) then //for square cap, just start and end further 1025 1146 begin 1026 1147 if i=0 then … … 1035 1156 dir *= 1/len; 1036 1157 end else 1037 if (linecap = pecRound) and (i=0) and not (plCycle in options) then1158 if not (plNoStartCap in options) and (linecap = pecRound) and (i=0) and not (plCycle in options) then 1038 1159 AddRoundCap(pts[0], -dir ,true); 1039 1160 … … 1044 1165 borders[i].rightSide.origin := pts[i] - borders[i].leftDir; 1045 1166 borders[i].rightSide.dir := dir; 1167 linePos += len; 1046 1168 end; 1047 1169 … … 1283 1405 FlushLine(high(pts)); 1284 1406 1285 SetLength(Result, NbPolyAcc);1407 FinalizeArray; 1286 1408 end; 1287 1409 … … 1289 1411 width: single; pencolor: TBGRAPixel; linecap: TPenEndCap; 1290 1412 joinstyle: TPenJoinStyle; const penstyle: TBGRAPenStyle; 1291 options: TBGRAPolyLineOptions; miterLimit: single ): ArrayOfTPointF;1413 options: TBGRAPolyLineOptions; miterLimit: single; arrowStart: TComputeArrowHeadProc; arrowStartPos: single; arrowEnd: TComputeArrowHeadProc; arrowEndPos: single): ArrayOfTPointF; 1292 1414 1293 1415 var … … 1306 1428 for j := startIndex to endIndexP1-1 do 1307 1429 subPts[j-startIndex] := linepts[j]; 1308 tempWidePolyline := ComputeWidePolylinePoints(subPts,width,pencolor,linecap,joinstyle,penstyle,options,miterLimit );1430 tempWidePolyline := ComputeWidePolylinePoints(subPts,width,pencolor,linecap,joinstyle,penstyle,options,miterLimit,arrowStart,arrowStartPos,arrowEnd,arrowEndPos); 1309 1431 if length(results) = nbresults then 1310 1432 setlength(results,(nbresults+1)*2); -
GraphicTest/Packages/bgrabitmap/bgrapolygon.pas
r452 r472 5 5 { This unit contains polygon drawing functions and spline functions. 6 6 7 Shapes are drawn using a T FillShapeInfo object, which calculates the7 Shapes are drawn using a TBGRACustomFillInfo object, which calculates the 8 8 intersection of an horizontal line and the polygon. 9 9 10 10 Various shapes are handled : 11 - TFillPolyInfo : polygon 11 - TFillPolyInfo : polygon scanned in any order 12 - TOnePassFillPolyInfo : polygon scanned from top to bottom 12 13 - TFillEllipseInfo : ellipse 13 14 - TFillBorderEllipseInfo : ellipse border … … 34 35 Classes, SysUtils, Graphics, BGRABitmapTypes, BGRAFillInfo; 35 36 36 procedure FillShapeAntialias(bmp: TBGRACustomBitmap; shapeInfo: T FillShapeInfo;37 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean );38 procedure FillShapeAntialiasWithTexture(bmp: TBGRACustomBitmap; shapeInfo: T FillShapeInfo;39 scan: IBGRAScanner; NonZeroWinding: boolean );40 procedure FillShapeAliased(bmp: TBGRACustomBitmap; shapeInfo: T FillShapeInfo;37 procedure FillShapeAntialias(bmp: TBGRACustomBitmap; shapeInfo: TBGRACustomFillInfo; 38 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean = false); 39 procedure FillShapeAntialiasWithTexture(bmp: TBGRACustomBitmap; shapeInfo: TBGRACustomFillInfo; 40 scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean = false); 41 procedure FillShapeAliased(bmp: TBGRACustomBitmap; shapeInfo: TBGRACustomFillInfo; 41 42 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean; drawmode: TDrawMode; AliasingIncludeBottomRight: Boolean= false); 42 43 … … 49 50 nbShapes: integer; 50 51 shapes: array of record 51 info: T FillShapeInfo;52 info: TBGRACustomFillInfo; 52 53 internalInfo: boolean; 53 54 texture: IBGRAScanner; … … 56 57 bounds: TRect; 57 58 end; 58 procedure AddShape(AInfo: T FillShapeInfo; AInternalInfo: boolean; ATexture: IBGRAScanner; AInternalTexture: TObject; AColor: TBGRAPixel);59 procedure AddShape(AInfo: TBGRACustomFillInfo; AInternalInfo: boolean; ATexture: IBGRAScanner; AInternalTexture: TObject; AColor: TBGRAPixel); 59 60 function CheckRectangleBorderBounds(var x1, y1, x2, y2: single; w: single): boolean; 60 61 public … … 65 66 constructor Create; 66 67 destructor Destroy; override; 67 procedure AddShape(AShape: T FillShapeInfo; AColor: TBGRAPixel);68 procedure AddShape(AShape: T FillShapeInfo; ATexture: IBGRAScanner);68 procedure AddShape(AShape: TBGRACustomFillInfo; AColor: TBGRAPixel); 69 procedure AddShape(AShape: TBGRACustomFillInfo; ATexture: IBGRAScanner); 69 70 procedure AddPolygon(const points: array of TPointF; AColor: TBGRAPixel); 70 71 procedure AddPolygon(const points: array of TPointF; ATexture: IBGRAScanner); … … 86 87 procedure AddRectangleBorder(x1, y1, x2, y2, w: single; AColor: TBGRAPixel); 87 88 procedure AddRectangleBorder(x1, y1, x2, y2, w: single; ATexture: IBGRAScanner); 88 procedure Draw(dest: TBGRACustomBitmap );89 procedure Draw(dest: TBGRACustomBitmap; ADrawMode: TDrawMode = dmDrawWithTransparency); 89 90 end; 90 91 … … 94 95 scan: IBGRAScanner; NonZeroWinding: boolean; drawmode: TDrawMode); 95 96 procedure FillPolyAntialias(bmp: TBGRACustomBitmap; points: array of TPointF; 96 c: TBGRAPixel; EraseMode: boolean; NonZeroWinding: boolean );97 c: TBGRAPixel; EraseMode: boolean; NonZeroWinding: boolean; LinearBlend: boolean = false); 97 98 procedure FillPolyAntialiasWithTexture(bmp: TBGRACustomBitmap; points: array of TPointF; 98 scan: IBGRAScanner; NonZeroWinding: boolean );99 scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean = false); 99 100 100 101 procedure FillEllipseAntialias(bmp: TBGRACustomBitmap; x, y, rx, ry: single; 101 c: TBGRAPixel; EraseMode: boolean );102 c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean = false); 102 103 procedure FillEllipseAntialiasWithTexture(bmp: TBGRACustomBitmap; x, y, rx, ry: single; 103 scan: IBGRAScanner );104 scan: IBGRAScanner; LinearBlend: boolean = false); 104 105 105 106 procedure BorderEllipseAntialias(bmp: TBGRACustomBitmap; x, y, rx, ry, w: single; 106 c: TBGRAPixel; EraseMode: boolean );107 c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean = false); 107 108 procedure BorderEllipseAntialiasWithTexture(bmp: TBGRACustomBitmap; x, y, rx, ry, w: single; 108 scan: IBGRAScanner );109 scan: IBGRAScanner; LinearBlend: boolean = false); 109 110 110 111 procedure FillRoundRectangleAntialias(bmp: TBGRACustomBitmap; x1, y1, x2, y2, rx, ry: single; 111 options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean );112 options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean = false); 112 113 procedure FillRoundRectangleAntialiasWithTexture(bmp: TBGRACustomBitmap; x1, y1, x2, y2, rx, ry: single; 113 options: TRoundRectangleOptions; scan: IBGRAScanner );114 options: TRoundRectangleOptions; scan: IBGRAScanner; LinearBlend: boolean = false); 114 115 115 116 procedure BorderRoundRectangleAntialias(bmp: TBGRACustomBitmap; x1, y1, x2, y2, rx, ry, w: single; 116 options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean );117 options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean = false); 117 118 procedure BorderRoundRectangleAntialiasWithTexture(bmp: TBGRACustomBitmap; x1, y1, x2, y2, rx, ry, w: single; 118 options: TRoundRectangleOptions; scan: IBGRAScanner );119 options: TRoundRectangleOptions; scan: IBGRAScanner; LinearBlend: boolean = false); 119 120 120 121 procedure BorderAndFillRoundRectangleAntialias(bmp: TBGRACustomBitmap; x1, y1, x2, y2, rx, ry, w: single; … … 125 126 uses Math, BGRABlend, BGRAGradientScanner, BGRATransform; 126 127 127 procedure FillShapeAntialias(bmp: TBGRACustomBitmap; shapeInfo: T FillShapeInfo;128 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean );128 procedure FillShapeAntialias(bmp: TBGRACustomBitmap; shapeInfo: TBGRACustomFillInfo; 129 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean); 129 130 var 130 131 inter: array of TIntersectionInfo; … … 141 142 density: PDensity; 142 143 143 xb, yb, yc, i, j: integer; 144 xb, yb, yc, i: integer; 145 tempDensity: UInt32or64; 144 146 145 147 x1, x2, x1b,x2b: single; … … 170 172 curdens: single; 171 173 pdens: pdensity; 174 newvalue: Int32or64; 172 175 begin 173 176 if (x1 <> x2) and (x1 < maxx + 1) and (x2 >= minx) then … … 188 191 189 192 if ix1 = ix2 then 190 (density + (ix1 - minx))^ -= round((x2 - x1)*(density1+density2)/2) 193 begin 194 newValue := (density + (ix1 - minx))^ - round((x2 - x1)*(density1+density2)/2); 195 if newValue < 0 then newValue := 0; 196 if newValue > 256 then newValue := 256; 197 (density + (ix1 - minx))^ := newValue 198 end 191 199 else 192 200 begin 193 (density + (ix1 - minx))^ := max(0, (density + (ix1 - minx))^ - round((1 - (x1 - ix1))*(density1+densityAt(ix1+1))/2) ); 201 newValue := (density + (ix1 - minx))^ - round((1 - (x1 - ix1))*(density1+densityAt(ix1+1))/2) ; 202 if newValue < 0 then newValue := 0; 203 if newValue > 256 then newValue := 256; 204 (density + (ix1 - minx))^ := newValue; 194 205 if (ix2 <= maxx) then 195 (density + (ix2 - minx))^ := max(0, (density + (ix2 - minx))^ - round((x2 - ix2)*(density2+densityAt(ix2))/2) ); 206 begin 207 newValue := (density + (ix2 - minx))^ - round((x2 - ix2)*(density2+densityAt(ix2))/2); 208 if newValue < 0 then newValue := 0; 209 if newValue > 256 then newValue := 256; 210 (density + (ix2 - minx))^ := newValue; 211 end; 196 212 end; 197 213 if ix2 > ix1 + 1 then … … 201 217 for n := ix2-1-(ix1+1) downto 0 do 202 218 begin 203 pdens^ -= round(curdens); 219 newValue := pdens^ - round(curdens); 220 if newValue < 0 then newValue := 0; 221 if newValue > 256 then newValue := 256; 222 pdens^ := newValue; 204 223 curdens += slope; 205 224 inc(pdens); … … 308 327 end; 309 328 310 if optimised then 311 {$i renderdensity256.inc} 312 else 313 {$define PARAM_ANTIALIASINGFACTOR} 314 {$i renderdensity256.inc} 329 if LinearBlend then 330 begin 331 if optimised then 332 {$define PARAM_LINEARANTIALIASING} 333 {$i renderdensity256.inc} 334 else 335 {$define PARAM_LINEARANTIALIASING} 336 {$define PARAM_ANTIALIASINGFACTOR} 337 {$i renderdensity256.inc} 338 end else 339 begin 340 if optimised then 341 {$i renderdensity256.inc} 342 else 343 {$define PARAM_ANTIALIASINGFACTOR} 344 {$i renderdensity256.inc} 345 end; 315 346 end; 316 347 … … 336 367 end; 337 368 338 procedure FillShapeAliased(bmp: TBGRACustomBitmap; shapeInfo: T FillShapeInfo;369 procedure FillShapeAliased(bmp: TBGRACustomBitmap; shapeInfo: TBGRACustomFillInfo; 339 370 c: TBGRAPixel; EraseMode: boolean; scan: IBGRAScanner; NonZeroWinding: boolean; drawmode: TDrawMode; AliasingIncludeBottomRight: Boolean= false); 340 371 var … … 370 401 for i := 0 to nbinter div 2 - 1 do 371 402 begin 372 x1 := inter[i + i].interX -AliasingOfs.X;373 x2 := inter[i + i+ 1].interX -AliasingOfs.X;403 x1 := inter[i + i].interX+AliasingOfs.X; 404 x2 := inter[i + i+ 1].interX+AliasingOfs.X; 374 405 375 406 if x1 <> x2 then … … 413 444 414 445 procedure FillShapeAntialiasWithTexture(bmp: TBGRACustomBitmap; 415 shapeInfo: T FillShapeInfo; scan: IBGRAScanner; NonZeroWinding: boolean);416 begin 417 FillShapeAntialias(bmp,shapeInfo,BGRAPixelTransparent,False,scan,NonZeroWinding );446 shapeInfo: TBGRACustomFillInfo; scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean); 447 begin 448 FillShapeAntialias(bmp,shapeInfo,BGRAPixelTransparent,False,scan,NonZeroWinding,LinearBlend); 418 449 end; 419 450 … … 421 452 c: TBGRAPixel; EraseMode: boolean; NonZeroWinding: boolean; drawmode: TDrawMode); 422 453 var 423 info: T FillPolyInfo;454 info: TCustomFillPolyInfo; 424 455 begin 425 456 if length(points) < 3 then 426 457 exit; 427 458 428 info := T FillPolyInfo.Create(points);459 info := TOnePassFillPolyInfo.Create(points); 429 460 FillShapeAliased(bmp, info, c, EraseMode, nil, NonZeroWinding, drawmode); 430 461 info.Free; … … 434 465 points: array of TPointF; scan: IBGRAScanner; NonZeroWinding: boolean; drawmode: TDrawMode); 435 466 var 436 info: T FillPolyInfo;467 info: TCustomFillPolyInfo; 437 468 begin 438 469 if length(points) < 3 then 439 470 exit; 440 471 441 info := T FillPolyInfo.Create(points);472 info := TOnePassFillPolyInfo.Create(points); 442 473 FillShapeAliased(bmp, info, BGRAPixelTransparent,False,scan, NonZeroWinding, drawmode); 443 474 info.Free; … … 445 476 446 477 procedure FillPolyAntialias(bmp: TBGRACustomBitmap; points: array of TPointF; 447 c: TBGRAPixel; EraseMode: boolean; NonZeroWinding: boolean );448 var 449 info: T FillPolyInfo;478 c: TBGRAPixel; EraseMode: boolean; NonZeroWinding: boolean; LinearBlend: boolean); 479 var 480 info: TCustomFillPolyInfo; 450 481 begin 451 482 if length(points) < 3 then 452 483 exit; 453 484 454 info := T FillPolyInfo.Create(points);455 FillShapeAntialias(bmp, info, c, EraseMode, nil, NonZeroWinding );485 info := TOnePassFillPolyInfo.Create(points); 486 FillShapeAntialias(bmp, info, c, EraseMode, nil, NonZeroWinding, LinearBlend); 456 487 info.Free; 457 488 end; 458 489 459 490 procedure FillPolyAntialiasWithTexture(bmp: TBGRACustomBitmap; 460 points: array of TPointF; scan: IBGRAScanner; NonZeroWinding: boolean 461 ); 462 var 463 info: TFillPolyInfo; 491 points: array of TPointF; scan: IBGRAScanner; NonZeroWinding: boolean; LinearBlend: boolean); 492 var 493 info: TCustomFillPolyInfo; 464 494 begin 465 495 if length(points) < 3 then 466 496 exit; 467 497 468 info := T FillPolyInfo.Create(points);469 FillShapeAntialiasWithTexture(bmp, info, scan, NonZeroWinding );498 info := TOnePassFillPolyInfo.Create(points); 499 FillShapeAntialiasWithTexture(bmp, info, scan, NonZeroWinding, LinearBlend); 470 500 info.Free; 471 501 end; 472 502 473 503 procedure FillEllipseAntialias(bmp: TBGRACustomBitmap; x, y, rx, ry: single; 474 c: TBGRAPixel; EraseMode: boolean );504 c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean); 475 505 var 476 506 info: TFillEllipseInfo; … … 480 510 481 511 info := TFillEllipseInfo.Create(x, y, rx, ry); 482 FillShapeAntialias(bmp, info, c, EraseMode, nil, False );512 FillShapeAntialias(bmp, info, c, EraseMode, nil, False, LinearBlend); 483 513 info.Free; 484 514 end; 485 515 486 516 procedure FillEllipseAntialiasWithTexture(bmp: TBGRACustomBitmap; x, y, rx, 487 ry: single; scan: IBGRAScanner );517 ry: single; scan: IBGRAScanner; LinearBlend: boolean); 488 518 var 489 519 info: TFillEllipseInfo; … … 493 523 494 524 info := TFillEllipseInfo.Create(x, y, rx, ry); 495 FillShapeAntialiasWithTexture(bmp, info, scan, False );525 FillShapeAntialiasWithTexture(bmp, info, scan, False, LinearBlend); 496 526 info.Free; 497 527 end; 498 528 499 529 procedure BorderEllipseAntialias(bmp: TBGRACustomBitmap; x, y, rx, ry, w: single; 500 c: TBGRAPixel; EraseMode: boolean );530 c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean); 501 531 var 502 532 info: TFillBorderEllipseInfo; … … 505 535 exit; 506 536 info := TFillBorderEllipseInfo.Create(x, y, rx, ry, w); 507 FillShapeAntialias(bmp, info, c, EraseMode, nil, False );537 FillShapeAntialias(bmp, info, c, EraseMode, nil, False, LinearBlend); 508 538 info.Free; 509 539 end; 510 540 511 541 procedure BorderEllipseAntialiasWithTexture(bmp: TBGRACustomBitmap; x, y, rx, 512 ry, w: single; scan: IBGRAScanner );542 ry, w: single; scan: IBGRAScanner; LinearBlend: boolean); 513 543 var 514 544 info: TFillBorderEllipseInfo; … … 517 547 exit; 518 548 info := TFillBorderEllipseInfo.Create(x, y, rx, ry, w); 519 FillShapeAntialiasWithTexture(bmp, info, scan, False );549 FillShapeAntialiasWithTexture(bmp, info, scan, False, LinearBlend); 520 550 info.Free; 521 551 end; … … 523 553 { TBGRAMultishapeFiller } 524 554 525 procedure TBGRAMultishapeFiller.AddShape(AInfo: T FillShapeInfo; AInternalInfo: boolean; ATexture: IBGRAScanner; AInternalTexture: TObject; AColor: TBGRAPixel);555 procedure TBGRAMultishapeFiller.AddShape(AInfo: TBGRACustomFillInfo; AInternalInfo: boolean; ATexture: IBGRAScanner; AInternalTexture: TObject; AColor: TBGRAPixel); 526 556 begin 527 557 if length(shapes) = nbShapes then … … 580 610 end; 581 611 582 procedure TBGRAMultishapeFiller.AddShape(AShape: T FillShapeInfo; AColor: TBGRAPixel);612 procedure TBGRAMultishapeFiller.AddShape(AShape: TBGRACustomFillInfo; AColor: TBGRAPixel); 583 613 begin 584 614 AddShape(AShape,False,nil,nil,AColor); 585 615 end; 586 616 587 procedure TBGRAMultishapeFiller.AddShape(AShape: T FillShapeInfo;617 procedure TBGRAMultishapeFiller.AddShape(AShape: TBGRACustomFillInfo; 588 618 ATexture: IBGRAScanner); 589 619 begin … … 595 625 begin 596 626 if length(points) <= 2 then exit; 597 AddShape(T FillPolyInfo.Create(points),True,nil,nil,AColor);627 AddShape(TOnePassFillPolyInfo.Create(points),True,nil,nil,AColor); 598 628 end; 599 629 … … 602 632 begin 603 633 if length(points) <= 2 then exit; 604 AddShape(T FillPolyInfo.Create(points),True,ATexture,nil,BGRAPixelTransparent);634 AddShape(TOnePassFillPolyInfo.Create(points),True,ATexture,nil,BGRAPixelTransparent); 605 635 end; 606 636 … … 611 641 begin 612 642 grad := TBGRAGradientTriangleScanner.Create(pt1,pt2,pt3, c1,c2,c3); 613 AddShape(T FillPolyInfo.Create([pt1,pt2,pt3]),True,grad,grad,BGRAPixelTransparent);643 AddShape(TOnePassFillPolyInfo.Create([pt1,pt2,pt3]),True,grad,grad,BGRAPixelTransparent); 614 644 end; 615 645 … … 620 650 begin 621 651 mapping := TBGRATriangleLinearMapping.Create(texture, pt1,pt2,pt3, tex1, tex2, tex3); 622 AddShape(T FillPolyInfo.Create([pt1,pt2,pt3]),True,mapping,mapping,BGRAPixelTransparent);652 AddShape(TOnePassFillPolyInfo.Create([pt1,pt2,pt3]),True,mapping,mapping,BGRAPixelTransparent); 623 653 end; 624 654 … … 657 687 begin 658 688 persp := TBGRAPerspectiveScannerTransform.Create(texture,[tex1,tex2,tex3,tex4],[pt1,pt2,pt3,pt4]); 659 AddShape(T FillPolyInfo.Create([pt1,pt2,pt3,pt4]),True,persp,persp,BGRAPixelTransparent);689 AddShape(TOnePassFillPolyInfo.Create([pt1,pt2,pt3,pt4]),True,persp,persp,BGRAPixelTransparent); 660 690 end; 661 691 … … 745 775 end; 746 776 747 procedure TBGRAMultishapeFiller.Draw(dest: TBGRACustomBitmap );777 procedure TBGRAMultishapeFiller.Draw(dest: TBGRACustomBitmap; ADrawMode: TDrawMode = dmDrawWithTransparency); 748 778 var 749 779 shapeRow: array of record … … 767 797 procedure AddSegment(xa,xb: single); 768 798 var nb: PInteger; 769 prevNb,k: integer;770 799 begin 771 800 nb := @shapeRow[dest].nbinter; 772 801 if length(shapeRow[dest].inter) < nb^+2 then 802 setlength(shapeRow[dest].inter, nb^*2+2); 803 with shapeRow[dest] do 773 804 begin 774 prevNb := length(shapeRow[dest].inter);775 setlength(shapeRow[dest].inter, nb^*2+2);776 for k := prevNb to high(shapeRow[dest].inter) do777 shapeRow[dest].inter[k] := shapes[dest].info.CreateIntersectionInfo;805 if inter[nb^] = nil then inter[nb^] := shapes[dest].info.CreateIntersectionInfo; 806 inter[nb^].interX := xa; 807 if inter[nb^+1] = nil then inter[nb^+1] := shapes[dest].info.CreateIntersectionInfo; 808 inter[nb^+1].interX := xb; 778 809 end; 779 shapeRow[dest].inter[nb^].interX := xa;780 shapeRow[dest].inter[nb^+1].interX := xb;781 810 inc(nb^,2); 782 811 end; … … 813 842 var 814 843 AliasingOfs: TPointF; 844 useAA: boolean; 815 845 816 846 procedure AddOneLineDensity(cury: single); … … 847 877 begin 848 878 //fill density 849 if not Antialiasingthen879 if not useAA then 850 880 begin 851 881 for i := 0 to nbinter div 2 - 1 do … … 895 925 begin 896 926 if nbShapes = 0 then exit; 927 useAA := Antialiasing and (ADrawMode in [dmDrawWithTransparency,dmLinearBlend]); 897 928 if nbShapes = 1 then 898 929 begin 899 if Antialiasingthen900 FillShapeAntialias(dest,shapes[0].info,GammaCompression(shapes[0].color),False,shapes[0].texture,FillMode = fmWinding ) else901 FillShapeAliased(dest,shapes[0].info,GammaCompression(shapes[0].color),False,shapes[0].texture,FillMode = fmWinding, dmDrawWithTransparency,930 if useAA then 931 FillShapeAntialias(dest,shapes[0].info,GammaCompression(shapes[0].color),False,shapes[0].texture,FillMode = fmWinding, ADrawMode=dmLinearBlend) else 932 FillShapeAliased(dest,shapes[0].info,GammaCompression(shapes[0].color),False,shapes[0].texture,FillMode = fmWinding, ADrawMode, 902 933 AliasingIncludeBottomRight); 903 934 exit; … … 963 994 end; 964 995 965 If Antialiasingthen996 If useAA then 966 997 begin 967 998 //precision scan … … 982 1013 FillChar(sums[rowminx-minx],(rowmaxx-rowminx+1)*sizeof(sums[0]),0); 983 1014 984 if Antialiasingthen1015 if useAA then 985 1016 {$define PARAM_ANTIALIASINGFACTOR} 986 1017 {$i multishapeline.inc} … … 991 1022 xb := rowminx; 992 1023 nextSum := @sums[xb-minx]; 993 while xb <= rowmaxx do 994 begin 995 curSum := nextSum; 996 inc(nextSum); 997 with curSum^ do 998 begin 999 if sumA <> 0 then 1024 case ADrawMode of 1025 dmDrawWithTransparency: 1026 while xb <= rowmaxx do 1000 1027 begin 1001 ec.red := (sumR+sumA shr 1) div sumA; 1002 ec.green := (sumG+sumA shr 1) div sumA; 1003 ec.blue := (sumB+sumA shr 1) div sumA; 1004 if sumA > 255 then sumA := 255; 1005 ec.alpha := sumA shl 8 + sumA; 1006 count := 1; 1007 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1008 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1028 curSum := nextSum; 1029 inc(nextSum); 1030 with curSum^ do 1009 1031 begin 1010 inc(xb); 1011 inc(nextSum); 1012 inc(count); 1032 if sumA <> 0 then 1033 begin 1034 ec.red := (sumR+sumA shr 1) div sumA; 1035 ec.green := (sumG+sumA shr 1) div sumA; 1036 ec.blue := (sumB+sumA shr 1) div sumA; 1037 if sumA > 255 then sumA := 255; 1038 ec.alpha := sumA shl 8 + sumA; 1039 count := 1; 1040 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1041 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1042 begin 1043 inc(xb); 1044 inc(nextSum); 1045 inc(count); 1046 end; 1047 if count = 1 then 1048 DrawExpandedPixelInlineNoAlphaCheck(pdest,ec,sumA) else 1049 DrawExpandedPixelsInline(pdest, ec, count ); 1050 inc(pdest,count-1); 1051 end; 1013 1052 end; 1014 if count = 1 then 1015 DrawExpandedPixelInlineWithAlphaCheck(pdest,ec) else 1016 DrawExpandedPixelsInline(pdest, ec, count ); 1017 inc(pdest,count-1); 1053 inc(xb); 1054 inc(pdest); 1018 1055 end; 1019 end; 1020 inc(xb); 1021 inc(pdest); 1056 1057 dmLinearBlend: 1058 while xb <= rowmaxx do 1059 begin 1060 curSum := nextSum; 1061 inc(nextSum); 1062 with curSum^ do 1063 begin 1064 if sumA <> 0 then 1065 begin 1066 ec.red := (sumR+sumA shr 1) div sumA; 1067 ec.green := (sumG+sumA shr 1) div sumA; 1068 ec.blue := (sumB+sumA shr 1) div sumA; 1069 if sumA > 255 then sumA := 255; 1070 ec.alpha := sumA shl 8 + sumA; 1071 count := 1; 1072 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1073 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1074 begin 1075 inc(xb); 1076 inc(nextSum); 1077 inc(count); 1078 end; 1079 if count = 1 then 1080 DrawPixelInlineNoAlphaCheck(pdest,GammaCompression(ec)) else 1081 DrawPixelsInline(pdest, GammaCompression(ec), count ); 1082 inc(pdest,count-1); 1083 end; 1084 end; 1085 inc(xb); 1086 inc(pdest); 1087 end; 1088 1089 dmXor: 1090 while xb <= rowmaxx do 1091 begin 1092 curSum := nextSum; 1093 inc(nextSum); 1094 with curSum^ do 1095 begin 1096 if sumA <> 0 then 1097 begin 1098 ec.red := (sumR+sumA shr 1) div sumA; 1099 ec.green := (sumG+sumA shr 1) div sumA; 1100 ec.blue := (sumB+sumA shr 1) div sumA; 1101 if sumA > 255 then sumA := 255; 1102 ec.alpha := sumA shl 8 + sumA; 1103 count := 1; 1104 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1105 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1106 begin 1107 inc(xb); 1108 inc(nextSum); 1109 inc(count); 1110 end; 1111 XorInline(pdest,GammaCompression(ec),count); 1112 inc(pdest,count-1); 1113 end; 1114 end; 1115 inc(xb); 1116 inc(pdest); 1117 end; 1118 1119 dmSet: 1120 while xb <= rowmaxx do 1121 begin 1122 curSum := nextSum; 1123 inc(nextSum); 1124 with curSum^ do 1125 begin 1126 if sumA <> 0 then 1127 begin 1128 ec.red := (sumR+sumA shr 1) div sumA; 1129 ec.green := (sumG+sumA shr 1) div sumA; 1130 ec.blue := (sumB+sumA shr 1) div sumA; 1131 if sumA > 255 then sumA := 255; 1132 ec.alpha := sumA shl 8 + sumA; 1133 count := 1; 1134 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1135 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1136 begin 1137 inc(xb); 1138 inc(nextSum); 1139 inc(count); 1140 end; 1141 FillInline(pdest,GammaCompression(ec),count); 1142 inc(pdest,count-1); 1143 end; 1144 end; 1145 inc(xb); 1146 inc(pdest); 1147 end; 1148 1149 dmSetExceptTransparent: 1150 while xb <= rowmaxx do 1151 begin 1152 curSum := nextSum; 1153 inc(nextSum); 1154 with curSum^ do 1155 begin 1156 if sumA >= 255 then 1157 begin 1158 ec.red := (sumR+sumA shr 1) div sumA; 1159 ec.green := (sumG+sumA shr 1) div sumA; 1160 ec.blue := (sumB+sumA shr 1) div sumA; 1161 if sumA > 255 then sumA := 255; 1162 ec.alpha := sumA shl 8 + sumA; 1163 count := 1; 1164 while (xb < rowmaxx) and (nextSum^.sumA = sumA) and (nextSum^.sumB = sumB) 1165 and (nextSum^.sumG = sumG) and (nextSum^.sumR = sumR) do 1166 begin 1167 inc(xb); 1168 inc(nextSum); 1169 inc(count); 1170 end; 1171 FillInline(pdest,GammaCompression(ec),count); 1172 inc(pdest,count-1); 1173 end; 1174 end; 1175 inc(xb); 1176 inc(pdest); 1177 end; 1178 1022 1179 end; 1023 1180 end; … … 1035 1192 1036 1193 procedure FillRoundRectangleAntialias(bmp: TBGRACustomBitmap; x1, y1, x2, y2, 1037 rx, ry: single; options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean );1194 rx, ry: single; options: TRoundRectangleOptions; c: TBGRAPixel; EraseMode: boolean; LinearBlend: boolean); 1038 1195 var 1039 1196 info: TFillRoundRectangleInfo; … … 1041 1198 if (x1 = x2) or (y1 = y2) then exit; 1042 1199 info := TFillRoundRectangleInfo.Create(x1, y1, x2, y2, rx, ry, options); 1043 FillShapeAntialias(bmp, info, c, EraseMode,nil, False );1200 FillShapeAntialias(bmp, info, c, EraseMode,nil, False, LinearBlend); 1044 1201 info.Free; 1045 1202 end; … … 1047 1204 procedure FillRoundRectangleAntialiasWithTexture(bmp: TBGRACustomBitmap; x1, 1048 1205 y1, x2, y2, rx, ry: single; options: TRoundRectangleOptions; 1049 scan: IBGRAScanner );1206 scan: IBGRAScanner; LinearBlend: boolean); 1050 1207 var 1051 1208 info: TFillRoundRectangleInfo; … … 1053 1210 if (x1 = x2) or (y1 = y2) then exit; 1054 1211 info := TFillRoundRectangleInfo.Create(x1, y1, x2, y2, rx, ry, options); 1055 FillShapeAntialiasWithTexture(bmp, info, scan, False );1212 FillShapeAntialiasWithTexture(bmp, info, scan, False, LinearBlend); 1056 1213 info.Free; 1057 1214 end; … … 1059 1216 procedure BorderRoundRectangleAntialias(bmp: TBGRACustomBitmap; x1, y1, x2, 1060 1217 y2, rx, ry, w: single; options: TRoundRectangleOptions; c: TBGRAPixel; 1061 EraseMode: boolean );1218 EraseMode: boolean; LinearBlend: boolean); 1062 1219 var 1063 1220 info: TFillBorderRoundRectInfo; … … 1065 1222 if (rx = 0) or (ry = 0) or (w=0) then exit; 1066 1223 info := TFillBorderRoundRectInfo.Create(x1, y1, x2,y2, rx, ry, w, options); 1067 FillShapeAntialias(bmp, info, c, EraseMode, nil, False );1224 FillShapeAntialias(bmp, info, c, EraseMode, nil, False, LinearBlend); 1068 1225 info.Free; 1069 1226 end; … … 1071 1228 procedure BorderRoundRectangleAntialiasWithTexture(bmp: TBGRACustomBitmap; x1, 1072 1229 y1, x2, y2, rx, ry, w: single; options: TRoundRectangleOptions; 1073 scan: IBGRAScanner );1230 scan: IBGRAScanner; LinearBlend: boolean); 1074 1231 var 1075 1232 info: TFillBorderRoundRectInfo; … … 1077 1234 if (rx = 0) or (ry = 0) or (w=0) then exit; 1078 1235 info := TFillBorderRoundRectInfo.Create(x1, y1, x2,y2, rx, ry, w, options); 1079 FillShapeAntialiasWithTexture(bmp, info, scan, False );1236 FillShapeAntialiasWithTexture(bmp, info, scan, False, LinearBlend); 1080 1237 info.Free; 1081 1238 end; … … 1106 1263 end else 1107 1264 begin 1108 FillShapeAntialias(bmp, info.innerBorder, fillcolor, EraseMode, nil, False );1109 FillShapeAntialias(bmp, info, bordercolor, EraseMode, nil, False );1265 FillShapeAntialias(bmp, info.innerBorder, fillcolor, EraseMode, nil, False, False); 1266 FillShapeAntialias(bmp, info, bordercolor, EraseMode, nil, False, False); 1110 1267 end; 1111 1268 info.Free; 1112 1269 end; 1113 1270 1114 initialization1115 1116 Randomize;1117 1118 1271 end. -
GraphicTest/Packages/bgrabitmap/bgrapolygonaliased.pas
r452 r472 2 2 3 3 {$mode objfpc}{$H+} 4 5 {$i bgrasse.inc} 4 6 5 7 interface … … 12 14 13 15 uses 14 Classes, SysUtils, BGRABitmapTypes, BGRAFillInfo, BGRA Polygon, BGRASSE;16 Classes, SysUtils, BGRABitmapTypes, BGRAFillInfo, BGRASSE; 15 17 16 18 type … … 29 31 { TPolygonLinearColorGradientInfo } 30 32 31 TPolygonLinearColorGradientInfo = class(T FillPolyInfo)33 TPolygonLinearColorGradientInfo = class(TOnePassFillPolyInfo) 32 34 protected 33 35 FColors: array of TColorF; 36 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, 37 ANumSegment: integer; dy: single; AData: pointer); override; 34 38 public 35 39 constructor Create(const points: array of TPointF; const Colors: array of TBGRAPixel); 36 40 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; override; 37 41 function CreateIntersectionInfo: TIntersectionInfo; override; 38 procedure ComputeIntersection(cury: single;39 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override;40 42 end; 41 43 … … 61 63 { TPolygonPerspectiveColorGradientInfo } 62 64 63 TPolygonPerspectiveColorGradientInfo = class(T FillPolyInfo)65 TPolygonPerspectiveColorGradientInfo = class(TOnePassFillPolyInfo) 64 66 protected 65 67 FColors: array of TColorF; 66 68 FPointsZ: array of single; 69 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, 70 ANumSegment: integer; dy: single; AData: pointer); override; 67 71 public 68 72 constructor Create(const points: array of TPointF; const pointsZ: array of single; const Colors: array of TBGRAPixel); 69 73 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; override; 70 74 function CreateIntersectionInfo: TIntersectionInfo; override; 71 procedure ComputeIntersection(cury: single;72 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override;73 75 end; 74 76 … … 96 98 { TPolygonLinearTextureMappingInfo } 97 99 98 TPolygonLinearTextureMappingInfo = class(T FillPolyInfo)100 TPolygonLinearTextureMappingInfo = class(TOnePassFillPolyInfo) 99 101 protected 100 102 FTexCoords: array of TPointF; 101 103 FLightnesses: array of Word; 104 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, 105 ANumSegment: integer; dy: single; AData: pointer); override; 102 106 public 103 107 constructor Create(const points: array of TPointF; const texCoords: array of TPointF); … … 105 109 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; override; 106 110 function CreateIntersectionInfo: TIntersectionInfo; override; 107 procedure ComputeIntersection(cury: single;108 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override;109 111 end; 110 112 … … 140 142 { TPolygonPerspectiveTextureMappingInfo } 141 143 142 TPolygonPerspectiveTextureMappingInfo = class(T FillPolyInfo)144 TPolygonPerspectiveTextureMappingInfo = class(TOnePassFillPolyInfo) 143 145 protected 144 146 FTexCoords: array of TPointF; 145 147 FPointsZ: array of single; 146 148 FLightnesses: array of Word; 149 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, 150 ANumSegment: integer; dy: single; AData: pointer); override; 147 151 public 148 152 constructor Create(const points: array of TPointF; const pointsZ: array of single; const texCoords: array of TPointF); … … 150 154 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; override; 151 155 function CreateIntersectionInfo: TIntersectionInfo; override; 152 procedure ComputeIntersection(cury: single;153 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override;154 156 end; 155 157 156 158 { TPolygonPerspectiveMappingShaderInfo } 157 159 158 TPolygonPerspectiveMappingShaderInfo = class(T FillPolyInfo)160 TPolygonPerspectiveMappingShaderInfo = class(TOnePassFillPolyInfo) 159 161 protected 160 162 FTexCoords: array of TPointF; 161 163 FPositions3D, FNormals3D: array of TPoint3D_128; 164 procedure SetIntersectionValues(AInter: TIntersectionInfo; AInterX: Single; AWinding, 165 ANumSegment: integer; dy: single; AData: pointer); override; 162 166 public 163 167 constructor Create(const points: array of TPointF; const points3D: array of TPoint3D; const normals: array of TPoint3D; const texCoords: array of TPointF); … … 165 169 function CreateSegmentData(numPt,nextPt: integer; x,y: single): pointer; override; 166 170 function CreateIntersectionInfo: TIntersectionInfo; override; 167 procedure ComputeIntersection(cury: single;168 var inter: ArrayOfTIntersectionInfo; var nbInter: integer); override;169 171 end; 170 172 … … 192 194 { Aliased round rectangle } 193 195 procedure BGRARoundRectAliased(dest: TBGRACustomBitmap; X1, Y1, X2, Y2: integer; 194 DX, DY: integer; BorderColor, FillColor: TBGRAPixel; FillTexture: IBGRAScanner = nil); 196 DX, DY: integer; BorderColor, FillColor: TBGRAPixel; FillTexture: IBGRAScanner = nil; ADrawMode: TDrawMode = dmDrawWithTransparency; 197 skipFill: boolean = false); 195 198 196 199 implementation … … 199 202 200 203 { TPolygonPerspectiveColorGradientInfo } 204 205 procedure TPolygonPerspectiveColorGradientInfo.SetIntersectionValues( 206 AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; 207 dy: single; AData: pointer); 208 var 209 info: PPerspectiveColorInfo; 210 begin 211 AInter.SetValues(AInterX,AWinding,ANumSegment); 212 info := PPerspectiveColorInfo(AData); 213 TPerspectiveColorGradientIntersectionInfo(AInter).coordInvZ := dy*info^.InvZSlope + info^.InvZ; 214 TPerspectiveColorGradientIntersectionInfo(AInter).ColorDivZ := info^.ColorDivZ + info^.ColorSlopesDivZ*dy; 215 end; 201 216 202 217 constructor TPolygonPerspectiveColorGradientInfo.Create( … … 266 281 end; 267 282 268 procedure TPolygonPerspectiveColorGradientInfo.ComputeIntersection(269 cury: single; var inter: ArrayOfTIntersectionInfo; var nbInter: integer);270 var271 j: integer;272 dy: single;273 info: PPerspectiveColorInfo;274 begin275 if length(FSlices)=0 then exit;276 277 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice);278 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice);279 with FSlices[FCurSlice] do280 if (cury >= y1) and (cury <= y2) then281 begin282 for j := 0 to nbSegments-1 do283 begin284 dy := cury - segments[j].y1;285 inter[nbinter].interX := dy * segments[j].slope + segments[j].x1;286 inter[nbinter].winding := segments[j].winding;287 info := PPerspectiveColorInfo(segments[j].data);288 TPerspectiveColorGradientIntersectionInfo(inter[nbinter]).coordInvZ := dy*info^.InvZSlope + info^.InvZ;289 TPerspectiveColorGradientIntersectionInfo(inter[nbinter]).ColorDivZ := info^.ColorDivZ + info^.ColorSlopesDivZ*dy;290 Inc(nbinter);291 end;292 end;293 end;294 295 283 { TPolygonLinearColorGradientInfo } 284 285 procedure TPolygonLinearColorGradientInfo.SetIntersectionValues( 286 AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; 287 dy: single; AData: pointer); 288 var 289 info: PLinearColorInfo; 290 begin 291 AInter.SetValues(AInterX,AWinding,ANumSegment); 292 info := PLinearColorInfo(AData); 293 TLinearColorGradientIntersectionInfo(AInter).color := info^.Color + info^.ColorSlopes*dy; 294 end; 296 295 297 296 constructor TPolygonLinearColorGradientInfo.Create( … … 343 342 begin 344 343 Result:= TLinearColorGradientIntersectionInfo.Create; 345 end;346 347 procedure TPolygonLinearColorGradientInfo.ComputeIntersection(cury: single;348 var inter: ArrayOfTIntersectionInfo; var nbInter: integer);349 var350 j: integer;351 dy: single;352 info: PLinearColorInfo;353 begin354 if length(FSlices)=0 then exit;355 356 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice);357 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice);358 with FSlices[FCurSlice] do359 if (cury >= y1) and (cury <= y2) then360 begin361 for j := 0 to nbSegments-1 do362 begin363 dy := cury - segments[j].y1;364 inter[nbinter].interX := dy * segments[j].slope + segments[j].x1;365 inter[nbinter].winding := segments[j].winding;366 info := PLinearColorInfo(segments[j].data);367 TLinearColorGradientIntersectionInfo(inter[nbinter]).color := info^.Color + info^.ColorSlopes*dy;368 Inc(nbinter);369 end;370 end;371 344 end; 372 345 … … 389 362 r,g,b,a: integer; 390 363 end; 391 {$IFDEF CPUI386} c: TBGRAPixel; {$ENDIF}364 {$IFDEF BGRASSE_AVAILABLE} c: TBGRAPixel; {$ENDIF} 392 365 begin 393 366 t := ((ix1+0.5)-x1)/(x2-x1); … … 396 369 pdest := bmp.ScanLine[yb]+ix1; 397 370 398 {$IFDEF CPUI386} {$asmmode intel}371 {$IFDEF BGRASSE_AVAILABLE} {$asmmode intel} 399 372 If UseSSE then 400 373 begin … … 499 472 { TPolygonLinearTextureMappingInfo } 500 473 474 procedure TPolygonLinearTextureMappingInfo.SetIntersectionValues( 475 AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; 476 dy: single; AData: pointer); 477 var 478 info: PLinearTextureInfo; 479 begin 480 AInter.SetValues(AInterX,AWinding,ANumSegment); 481 info := PLinearTextureInfo(AData); 482 TLinearTextureMappingIntersectionInfo(AInter).texCoord := info^.TexCoord + info^.TexCoordSlopes*dy; 483 if FLightnesses<>nil then 484 TLinearTextureMappingIntersectionInfo(AInter).lightness := round(info^.lightness + info^.lightnessSlope*dy) 485 else 486 TLinearTextureMappingIntersectionInfo(AInter).lightness := 32768; 487 end; 488 501 489 constructor TPolygonLinearTextureMappingInfo.Create(const points: array of TPointF; 502 490 const texCoords: array of TPointF); … … 585 573 begin 586 574 result := TLinearTextureMappingIntersectionInfo.Create; 587 end;588 589 procedure TPolygonLinearTextureMappingInfo.ComputeIntersection(cury: single;590 var inter: ArrayOfTIntersectionInfo; var nbInter: integer);591 var592 j: integer;593 dy: single;594 info: PLinearTextureInfo;595 begin596 if length(FSlices)=0 then exit;597 598 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice);599 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice);600 with FSlices[FCurSlice] do601 if (cury >= y1) and (cury <= y2) then602 begin603 for j := 0 to nbSegments-1 do604 begin605 dy := cury - segments[j].y1;606 inter[nbinter].interX := dy * segments[j].slope + segments[j].x1;607 inter[nbinter].winding := segments[j].winding;608 info := PLinearTextureInfo(segments[j].data);609 TLinearTextureMappingIntersectionInfo(inter[nbinter]).texCoord := info^.TexCoord + info^.TexCoordSlopes*dy;610 if FLightnesses<>nil then611 TLinearTextureMappingIntersectionInfo(inter[nbinter]).lightness := round(info^.lightness + info^.lightnessSlope*dy)612 else613 TLinearTextureMappingIntersectionInfo(inter[nbinter]).lightness := 32768;614 Inc(nbinter);615 end;616 end;617 575 end; 618 576 … … 637 595 z,invZ,InvZStep: single; 638 596 r,g,b,a: integer; 639 {$IFDEF CPUI386}minVal,maxVal: single;597 {$IFDEF BGRASSE_AVAILABLE}minVal,maxVal: single; 640 598 cInt: packed record 641 599 r,g,b,a: integer; … … 657 615 {$DEFINE PARAM_USEZBUFFER} 658 616 zbufferpos := zbuffer + yb*bmp.Width + ix1; 659 {$IFDEF CPUI386}617 {$IFDEF BGRASSE_AVAILABLE} 660 618 If UseSSE then 661 619 begin … … 679 637 end else 680 638 begin 681 {$IFDEF CPUI386}639 {$IFDEF BGRASSE_AVAILABLE} 682 640 If UseSSE then 683 641 begin … … 846 804 {From LazRGBGraphics} 847 805 procedure BGRARoundRectAliased(dest: TBGRACustomBitmap; X1, Y1, X2, Y2: integer; 848 DX, DY: integer; BorderColor, FillColor: TBGRAPixel; FillTexture: IBGRAScanner = nil); 806 DX, DY: integer; BorderColor, FillColor: TBGRAPixel; FillTexture: IBGRAScanner = nil; ADrawMode: TDrawMode = dmDrawWithTransparency; 807 skipFill: boolean = false); 849 808 var 850 809 CX, CY, CX1, CY1, A, B, NX, NY: single; … … 858 817 LX, LY: integer; 859 818 RowStart,RowEnd: integer; 860 eBorderColor,eFillColor: TExpandedPixel; 819 PixelProc: procedure (x, y: int32or64; c: TBGRAPixel) of object; 820 skipBorder: boolean; 861 821 862 822 procedure AddEdge(X, Y: integer); … … 891 851 Dec(y2); 892 852 893 eBorderColor := GammaExpansion(BorderColor);894 eFillColor := GammaExpansion(FillColor);895 896 853 if (X1 = X2) and (Y1 = Y2) then 897 854 begin 898 dest.DrawPixel(X1, Y1, eBorderColor);855 dest.DrawPixel(X1, Y1, BorderColor, ADrawMode); 899 856 Exit; 900 857 end; … … 902 859 if (X2 - X1 = 1) or (Y2 - Y1 = 1) then 903 860 begin 904 dest.FillRect(X1, Y1, X2 + 1, Y2 + 1, BorderColor, dmDrawWithTransparency);861 dest.FillRect(X1, Y1, X2 + 1, Y2 + 1, BorderColor, ADrawMode); 905 862 Exit; 906 863 end; … … 908 865 if (LX > X2 - X1) or (LY > Y2 - Y1) then 909 866 begin 910 dest.Rectangle(X1, Y1, X2 + 1, Y2 + 1, BorderColor, dmDrawWithTransparency); 911 if FillTexture <> nil then 912 dest.FillRect(X1 + 1, Y1 + 1, X2, Y2, FillTexture, dmDrawWithTransparency) else 913 dest.FillRect(X1 + 1, Y1 + 1, X2, Y2, FillColor, dmDrawWithTransparency); 867 dest.Rectangle(X1, Y1, X2 + 1, Y2 + 1, BorderColor, ADrawMode); 868 if not skipFill then 869 if FillTexture <> nil then 870 dest.FillRect(X1 + 1, Y1 + 1, X2, Y2, FillTexture, ADrawMode) else 871 dest.FillRect(X1 + 1, Y1 + 1, X2, Y2, FillColor, ADrawMode); 914 872 Exit; 915 873 end; … … 977 935 end; 978 936 937 case ADrawMode of 938 dmSetExceptTransparent: begin PixelProc := @dest.SetPixel; skipBorder:= BorderColor.alpha <> 255; end; dmDrawWithTransparency: begin PixelProc := @dest.DrawPixel; skipBorder:= BorderColor.alpha = 0; end; 939 dmXor: begin PixelProc := @dest.XorPixel; skipBorder:= DWord(BorderColor) = 0; end; 940 dmLinearBlend: begin PixelProc := @dest.FastBlendPixel; skipBorder:= BorderColor.alpha = 0; end; 941 else 942 begin PixelProc := @dest.SetPixel; skipBorder := false; end; 943 end; 944 979 945 J := 0; 980 946 while J < Length(EdgeList) do … … 982 948 if (J = 0) and (Frac(CY) > 0) then 983 949 begin 950 if not skipBorder then 984 951 for I := EdgeList[J].X to EdgeList[J].Y do 985 952 begin 986 dest.DrawPixel(Floor(CX) + I, Floor(CY) + J, eBorderColor);987 dest.DrawPixel(Ceil(CX) - Succ(I), Floor(CY) + J, eBorderColor);953 PixelProc(Floor(CX) + I, Floor(CY) + J, BorderColor); 954 PixelProc(Ceil(CX) - Succ(I), Floor(CY) + J, BorderColor); 988 955 end; 989 956 990 if FillTexture <> nil then 991 dest.DrawHorizLine(Ceil(CX) - EdgeList[J].X, Floor(CY) + J, Floor(CX) + 992 Pred(EdgeList[J].X), FillTexture) else 993 dest.DrawHorizLine(Ceil(CX) - EdgeList[J].X, Floor(CY) + J, Floor(CX) + 994 Pred(EdgeList[J].X), eFillColor); 957 if not SkipFill then 958 if FillTexture <> nil then 959 dest.HorizLine(Ceil(CX) - EdgeList[J].X, Floor(CY) + J, Floor(CX) + 960 Pred(EdgeList[J].X), FillTexture, ADrawMode) else 961 dest.HorizLine(Ceil(CX) - EdgeList[J].X, Floor(CY) + J, Floor(CX) + 962 Pred(EdgeList[J].X), FillColor, ADrawMode); 995 963 end 996 964 else … … 1002 970 S := -Succ(EdgeList[J].Y); 1003 971 972 if not skipBorder then 1004 973 for I := S to EdgeList[J].Y do 1005 974 begin 1006 dest.DrawPixel(Floor(CX) + I, Floor(CY) + J, eBorderColor);1007 dest.DrawPixel(Floor(CX) + I, Ceil(CY) - Succ(J), eBorderColor);975 PixelProc(Floor(CX) + I, Floor(CY) + J, BorderColor); 976 PixelProc(Floor(CX) + I, Ceil(CY) - Succ(J), BorderColor); 1008 977 end; 1009 978 end 1010 979 else 1011 980 begin 981 if not skipBorder then 1012 982 for I := EdgeList[J].X to EdgeList[J].Y do 1013 983 begin 1014 dest.DrawPixel(Floor(CX) + I, Floor(CY) + J, eBorderColor);1015 dest.DrawPixel(Floor(CX) + I, Ceil(CY) - Succ(J), eBorderColor);984 PixelProc(Floor(CX) + I, Floor(CY) + J, BorderColor); 985 PixelProc(Floor(CX) + I, Ceil(CY) - Succ(J), BorderColor); 1016 986 if Floor(CX) + I <> Ceil(CX) - Succ(I) then 1017 987 begin 1018 dest.DrawPixel(Ceil(CX) - Succ(I), Floor(CY) + J, eBorderColor);1019 dest.DrawPixel(Ceil(CX) - Succ(I), Ceil(CY) - Succ(J), eBorderColor);988 PixelProc(Ceil(CX) - Succ(I), Floor(CY) + J, BorderColor); 989 PixelProc(Ceil(CX) - Succ(I), Ceil(CY) - Succ(J), BorderColor); 1020 990 end; 1021 991 end; 1022 992 1023 RowStart := Ceil(CX) - EdgeList[J].X;1024 RowEnd := Floor(CX) + Pred(EdgeList[J].X);1025 if RowEnd >= RowStart then1026 begin1027 if FillTexture <> nilthen993 if not SkipFill then 994 begin 995 RowStart := Ceil(CX) - EdgeList[J].X; 996 RowEnd := Floor(CX) + Pred(EdgeList[J].X); 997 if RowEnd >= RowStart then 1028 998 begin 1029 dest.DrawHorizLine(RowStart, Floor(CY) + J, 1030 RowEnd, FillTexture); 1031 dest.DrawHorizLine(RowStart, Ceil(CY) - Succ(J), 1032 RowEnd, FillTexture); 1033 end else 1034 begin 1035 dest.DrawHorizLine(RowStart, Floor(CY) + J, 1036 RowEnd, eFillColor); 1037 dest.DrawHorizLine(RowStart, Ceil(CY) - Succ(J), 1038 RowEnd, eFillColor); 999 if FillTexture <> nil then 1000 begin 1001 dest.HorizLine(RowStart, Floor(CY) + J, 1002 RowEnd, FillTexture, ADrawMode); 1003 dest.HorizLine(RowStart, Ceil(CY) - Succ(J), 1004 RowEnd, FillTexture, ADrawMode); 1005 end else 1006 begin 1007 dest.HorizLine(RowStart, Floor(CY) + J, 1008 RowEnd, FillColor, ADrawMode); 1009 dest.HorizLine(RowStart, Ceil(CY) - Succ(J), 1010 RowEnd, FillColor, ADrawMode); 1011 end; 1039 1012 end; 1040 1013 end; 1014 1041 1015 end; 1042 1016 Inc(J); -
GraphicTest/Packages/bgrabitmap/bgraresample.pas
r452 r472 8 8 without interpolation filters. 9 9 10 SimpleStretch does a fast stretch by splitting the image into zones defined 11 by integers. This can be quite ugly. 10 SimpleStretch does a boxed resample with limited antialiasing. 12 11 13 12 FineResample uses floating point coordinates to get an antialiased resample. … … 20 19 21 20 uses 22 SysUtils, BGRABitmapTypes;21 Types, SysUtils, BGRABitmapTypes; 23 22 24 23 {------------------------------- Simple stretch ------------------------------------} … … 26 25 function SimpleStretch(bmp: TBGRACustomBitmap; 27 26 NewWidth, NewHeight: integer): TBGRACustomBitmap; 27 procedure StretchPutImage(bmp: TBGRACustomBitmap; 28 NewWidth, NewHeight: integer; dest: TBGRACustomBitmap; OffsetX,OffsetY: Integer; ADrawMode: TDrawMode; AOpacity: byte); 29 procedure DownSamplePutImage(source: TBGRACustomBitmap; factorX,factorY: integer; dest: TBGRACustomBitmap; OffsetX,OffsetY: Integer; ADrawMode: TDrawMode); 30 function DownSample(source: TBGRACustomBitmap; factorX,factorY: integer): TBGRACustomBitmap; 28 31 29 32 {---------------------------- Interpolation filters --------------------------------} … … 66 69 end; 67 70 71 { TLanczosKernel } 72 73 TLanczosKernel = class(TWideKernelFilter) 74 private 75 FNumberOfLobes: integer; 76 FFactor: ValReal; 77 procedure SetNumberOfLobes(AValue: integer); 78 public 79 constructor Create(ANumberOfLobes: integer); 80 function Interpolation(t: single): single; override; 81 function ShouldCheckRange: boolean; override; 82 function KernelWidth: single; override; 83 84 property NumberOfLobes : integer read FNumberOfLobes write SetNumberOfLobes; 85 end; 86 68 87 function CreateInterpolator(style: TSplineStyle): TWideKernelFilter; 69 88 … … 78 97 implementation 79 98 80 uses GraphType, Math; 81 82 {-------------------------------- Simple stretch ------------------------------------} 83 84 function FastSimpleStretchLarger(bmp: TBGRACustomBitmap; 85 xFactor, yFactor: integer): TBGRACustomBitmap; 99 uses GraphType, Math, BGRABlend; 100 101 function SimpleStretch(bmp: TBGRACustomBitmap; 102 newWidth, newHeight: integer): TBGRACustomBitmap; 103 begin 104 if (NewWidth = bmp.Width) and (NewHeight = bmp.Height) then 105 begin 106 Result := bmp.Duplicate; 107 exit; 108 end; 109 Result := bmp.NewBitmap(NewWidth, NewHeight); 110 StretchPutImage(bmp, newWidth,newHeight, result, 0,0, dmSet, 255); 111 end; 112 113 procedure StretchPutImage(bmp: TBGRACustomBitmap; NewWidth, NewHeight: integer; 114 dest: TBGRACustomBitmap; OffsetX, OffsetY: Integer; ADrawMode: TDrawMode; AOpacity: byte); 115 type 116 TTransitionState = (tsNone, tsPlain, tsLeft, tsMiddle, tsRight); 86 117 var 87 y_src, yb, y_dest: integer; 88 89 x_src, xb: integer; 90 srcColor: TBGRAPixel; 91 92 PSrc: PBGRAPixel; 93 PDest: array of PBGRAPixel; 94 temp: PBGRAPixel; 95 96 begin 97 if (xFactor < 1) or (yFactor < 1) then 98 raise ERangeError.Create('FastSimpleStretchLarger: New dimensions must be greater or equal (*'+IntToStr(xFactor)+'x*'+IntToStr(yFactor)+')'); 99 100 Result := bmp.NewBitmap(bmp.Width * xFactor, bmp.Height * yFactor); 101 if (Result.Width = 0) or (Result.Height = 0) then 118 x_src,y_src, y_src2, prev_y_src, prev_y_src2: NativeInt; 119 inc_x_src, mod_x_src, acc_x_src, inc_y_src, mod_y_src, acc_y_src, 120 acc_x_src2, acc_y_src2: NativeInt; 121 x_dest, y_dest: NativeInt; 122 123 PDest, PSrc1, PSrc2: PBGRAPixel; 124 vertColors: packed array[1..2] of TBGRAPixel; 125 DeltaSrcX: NativeInt; 126 targetRect: TRect; 127 tempData: PBGRAPixel; 128 prevHorizTransition,horizTransition,prevVertTransition,vertTransition: TTransitionState; 129 horizSlightlyDifferent,vertSlightlyDifferent: boolean; 130 131 procedure LinearMix(PSrc: PBGRAPixel; DeltaSrc: integer; AccSrcQuarter: boolean; 132 PDest: PBGRAPixel; slightlyDifferent: boolean; var transition: TTransitionState); 133 var 134 asum: NativeInt; 135 a1,a2: NativeInt; 136 newTransition: TTransitionState; 137 begin 138 if DeltaSrc=0 then 139 begin 140 PDest^ := PSrc^; 141 transition:= tsPlain; 142 end 143 else 144 begin 145 if slightlyDifferent then 146 begin 147 if AccSrcQuarter then newTransition:= tsRight else 148 newTransition:= tsLeft; 149 end else 150 newTransition:= tsMiddle; 151 152 if (newTransition = tsMiddle) or ((newTransition = tsRight) and (transition = tsLeft)) or 153 ((newTransition = tsLeft) and (transition = tsRight)) then 154 begin 155 transition:= tsMiddle; 156 asum := psrc^.alpha + (psrc+DeltaSrc)^.alpha; 157 if asum = 0 then 158 pdest^ := BGRAPixelTransparent 159 else if asum = 510 then 160 begin 161 pdest^.alpha := 255; 162 pdest^.red := (psrc^.red + (psrc+DeltaSrc)^.red + 1) shr 1; 163 pdest^.green := (psrc^.green + (psrc+DeltaSrc)^.green + 1) shr 1; 164 pdest^.blue := (psrc^.blue + (psrc+DeltaSrc)^.blue + 1) shr 1; 165 end else 166 begin 167 pdest^.alpha := asum shr 1; 168 a1 := psrc^.alpha; 169 a2 := (psrc+DeltaSrc)^.alpha; 170 pdest^.red := (psrc^.red*a1 + (psrc+DeltaSrc)^.red*a2 + (asum shr 1)) div asum; 171 pdest^.green := (psrc^.green*a1 + (psrc+DeltaSrc)^.green*a2 + (asum shr 1)) div asum; 172 pdest^.blue := (psrc^.blue*a1 + (psrc+DeltaSrc)^.blue*a2 + (asum shr 1)) div asum; 173 end; 174 end else 175 if newTransition = tsRight then 176 begin 177 transition := tsRight; 178 asum := psrc^.alpha + (psrc+DeltaSrc)^.alpha*3; 179 if asum = 0 then 180 pdest^ := BGRAPixelTransparent 181 else if asum = 1020 then 182 begin 183 pdest^.alpha := 255; 184 pdest^.red := (psrc^.red + (psrc+DeltaSrc)^.red*3 + 2) shr 2; 185 pdest^.green := (psrc^.green + (psrc+DeltaSrc)^.green*3 + 2) shr 2; 186 pdest^.blue := (psrc^.blue + (psrc+DeltaSrc)^.blue*3 + 2) shr 2; 187 end else 188 begin 189 pdest^.alpha := asum shr 2; 190 a1 := psrc^.alpha; 191 a2 := (psrc+DeltaSrc)^.alpha; 192 pdest^.red := (psrc^.red*a1 + (psrc+DeltaSrc)^.red*a2*3 + (asum shr 1)) div asum; 193 pdest^.green := (psrc^.green*a1 + (psrc+DeltaSrc)^.green*a2*3 + (asum shr 1)) div asum; 194 pdest^.blue := (psrc^.blue*a1 + (psrc+DeltaSrc)^.blue*a2*3 + (asum shr 1)) div asum; 195 end; 196 end else 197 begin 198 transition:= tsLeft; 199 asum := psrc^.alpha*3 + (psrc+DeltaSrc)^.alpha; 200 if asum = 0 then 201 pdest^ := BGRAPixelTransparent 202 else if asum = 1020 then 203 begin 204 pdest^.alpha := 255; 205 pdest^.red := (psrc^.red*3 + (psrc+DeltaSrc)^.red + 2) shr 2; 206 pdest^.green := (psrc^.green*3 + (psrc+DeltaSrc)^.green + 2) shr 2; 207 pdest^.blue := (psrc^.blue*3 + (psrc+DeltaSrc)^.blue + 2) shr 2; 208 end else 209 begin 210 pdest^.alpha := asum shr 2; 211 a1 := psrc^.alpha; 212 a2 := (psrc+DeltaSrc)^.alpha; 213 pdest^.red := (psrc^.red*a1*3 + (psrc+DeltaSrc)^.red*a2 + (asum shr 1)) div asum; 214 pdest^.green := (psrc^.green*a1*3 + (psrc+DeltaSrc)^.green*a2 + (asum shr 1)) div asum; 215 pdest^.blue := (psrc^.blue*a1*3 + (psrc+DeltaSrc)^.blue*a2 + (asum shr 1)) div asum; 216 end; 217 end; 218 end; 219 end; 220 221 begin 222 if (newWidth <= 0) or (newHeight <= 0) or (bmp.Width <= 0) 223 or (bmp.Height <= 0) then 102 224 exit; 103 225 226 targetRect := rect(0,0,NewWidth,NewHeight); 227 if OffsetX < dest.ClipRect.Left then targetRect.Left:= dest.ClipRect.Left-OffsetX; 228 if OffsetY < dest.ClipRect.Top then targetRect.Top:= dest.ClipRect.Top-OffsetY; 229 if OffsetX+NewWidth > dest.ClipRect.Right then targetRect.Right := dest.ClipRect.Right-OffsetX; 230 if OffsetY+NewHeight > dest.ClipRect.Bottom then targetRect.Bottom := dest.ClipRect.Bottom-OffsetY; 231 if (targetRect.Right <= targetRect.Left) or (targetRect.Bottom <= targetRect.Top) then exit; 232 104 233 bmp.LoadFromBitmapIfNeeded; 105 234 106 SetLength(PDest, yFactor); 107 y_dest := 0; 108 for y_src := 0 to bmp.Height - 1 do 109 begin 110 PSrc := bmp.Scanline[y_src]; 111 for yb := 0 to yFactor - 1 do 112 PDest[yb] := Result.scanLine[y_dest + yb]; 113 114 for x_src := 0 to bmp.Width - 1 do 115 begin 116 srcColor := PSrc^; 117 Inc(PSrc); 118 119 for yb := 0 to yFactor - 1 do 120 begin 121 temp := PDest[yb]; 122 for xb := 0 to xFactor - 1 do 123 begin 124 temp^ := srcColor; 125 Inc(temp); 235 if (ADrawMode <> dmSet) or (AOpacity <> 255) then 236 getmem(tempData, (targetRect.Right-targetRect.Left)*sizeof(TBGRAPixel) ) 237 else 238 tempData := nil; 239 240 inc_x_src := bmp.Width div newwidth; 241 mod_x_src := bmp.Width mod newwidth; 242 inc_y_src := bmp.Height div newheight; 243 mod_y_src := bmp.Height mod newheight; 244 245 prev_y_src := -1; 246 prev_y_src2 := -1; 247 248 acc_y_src := targetRect.Top*mod_y_src; 249 y_src := targetRect.Top*inc_y_src + (acc_y_src div NewHeight); 250 acc_y_src := acc_y_src mod NewHeight; 251 252 y_src := y_src+ (bmp.Height div 4) div newheight; 253 acc_y_src := acc_y_src+ (bmp.Height div 4) mod newheight; 254 255 y_src2 := y_src+ (bmp.Height div 2) div newheight; 256 acc_y_src2 := acc_y_src+ (bmp.Height div 2) mod newheight; 257 if acc_y_src2 > NewHeight then 258 begin 259 dec(acc_y_src2, NewHeight); 260 inc(y_src2); 261 end; 262 horizSlightlyDifferent := (NewWidth > bmp.Width*2 div 3) and (NewWidth < bmp.Width*4 div 3); 263 prevVertTransition:= tsNone; 264 vertSlightlyDifferent := (NewHeight > bmp.Height*2 div 3) and (NewHeight < bmp.Height*4 div 3); 265 for y_dest := targetRect.Top to targetRect.Bottom - 1 do 266 begin 267 if (y_src = prev_y_src) and (y_src2 = prev_y_src2) and not vertSlightlyDifferent then 268 begin 269 if tempData = nil then 270 move((dest.ScanLine[y_dest-1+OffsetY]+OffsetX+targetRect.Left)^,(dest.ScanLine[y_dest+OffsetY]+OffsetX+targetRect.Left)^,(targetRect.Right-targetRect.Left)*sizeof(TBGRAPixel)) 271 else 272 PutPixels(dest.ScanLine[y_dest+OffsetY]+OffsetX+targetRect.Left,tempData,targetRect.right-targetRect.left,ADrawMode,AOpacity); 273 end else 274 begin 275 if tempData = nil then 276 PDest := dest.ScanLine[y_dest+OffsetY]+OffsetX+targetRect.Left 277 else 278 PDest := tempData; 279 PSrc1 := bmp.Scanline[y_src]; 280 281 acc_x_src := targetRect.Left*mod_x_src; 282 x_src := targetRect.Left*inc_x_src + (acc_x_src div NewWidth); 283 acc_x_src := acc_x_src mod NewWidth; 284 285 x_src := x_src+ (bmp.Width div 4) div NewWidth; 286 acc_x_src := acc_x_src+ (bmp.Width div 4) mod NewWidth; 287 288 DeltaSrcX := (bmp.Width div 2) div NewWidth; 289 acc_x_src2 := acc_x_src+ (bmp.Width div 2) mod NewWidth; 290 if acc_x_src2 > NewWidth then 291 begin 292 dec(acc_x_src2, NewWidth); 293 inc(DeltaSrcX); 294 end; 295 inc(Psrc1, x_src); 296 prevHorizTransition := tsNone; 297 298 if y_src2=y_src then 299 begin 300 horizTransition:= prevHorizTransition; 301 for x_dest := targetRect.left to targetRect.right - 1 do 302 begin 303 LinearMix(psrc1, DeltaSrcX, acc_x_src2 >= NewWidth shr 2, PDest, horizSlightlyDifferent, horizTransition); 304 305 Inc(PSrc1, inc_x_src); 306 Inc(acc_x_src, mod_x_src); 307 if acc_x_src >= newWidth then 308 begin 309 Dec(acc_x_src, newWidth); 310 Inc(PSrc1); 311 dec(DeltaSrcX); 312 end; 313 Inc(acc_x_src2, mod_x_src); 314 if acc_x_src2 >= newWidth then 315 begin 316 Dec(acc_x_src2, newWidth); 317 Inc(DeltaSrcX); 318 end; 319 inc(PDest); 126 320 end; 127 PDest[yb] := temp; 128 end; 129 end; 130 Inc(y_dest, yFactor); 131 end; 132 133 Result.InvalidateBitmap; 134 end; 135 136 function SimpleStretchLarger(bmp: TBGRACustomBitmap; 137 newWidth, newHeight: integer): TBGRACustomBitmap; 138 var 139 x_src, y_src: integer; 140 inc_x_dest, mod_x_dest, acc_x_dest, inc_y_dest, mod_y_dest, acc_y_dest: integer; 141 x_dest, y_dest, prev_x_dest, prev_y_dest: integer; 142 143 xb, yb: integer; 144 srcColor: TBGRAPixel; 145 PDest, PSrc: PBGRAPixel; 146 delta, lineDelta: integer; 147 148 begin 149 if (newWidth < bmp.Width) or (newHeight < bmp.Height) then 150 raise ERangeError.Create('SimpleStretchLarger: New dimensions must be greater or equal ('+IntToStr(bmp.Width)+'x'+IntToStr(bmp.Height)+'->'+IntToStr(newWidth)+'x'+IntToStr(newHeight)+')'); 151 152 if ((newWidth div bmp.Width) * bmp.Width = newWidth) and 153 ((newHeight div bmp.Height) * bmp.Height = newHeight) then 154 begin 155 Result := FastSimpleStretchLarger(bmp, newWidth div bmp.Width, 156 newHeight div bmp.Height); 157 exit; 158 end; 159 160 Result := bmp.NewBitmap(NewWidth, NewHeight); 161 if (newWidth = 0) or (newHeight = 0) then 162 exit; 163 164 bmp.LoadFromBitmapIfNeeded; 165 166 inc_x_dest := newwidth div bmp.Width; 167 mod_x_dest := newwidth mod bmp.Width; 168 inc_y_dest := newheight div bmp.Height; 169 mod_y_dest := newheight mod bmp.Height; 170 171 y_dest := 0; 172 acc_y_dest := bmp.Height div 2; 173 if Result.LineOrder = riloTopToBottom then 174 lineDelta := newWidth 175 else 176 lineDelta := -newWidth; 177 for y_src := 0 to bmp.Height - 1 do 178 begin 179 prev_y_dest := y_dest; 180 Inc(y_dest, inc_y_dest); 181 Inc(acc_y_dest, mod_y_dest); 182 if acc_y_dest >= bmp.Height then 183 begin 184 Dec(acc_y_dest, bmp.Height); 185 Inc(y_dest); 186 end; 187 188 PSrc := bmp.Scanline[y_src]; 189 190 x_dest := 0; 191 acc_x_dest := bmp.Width div 2; 192 for x_src := 0 to bmp.Width - 1 do 193 begin 194 prev_x_dest := x_dest; 195 Inc(x_dest, inc_x_dest); 196 Inc(acc_x_dest, mod_x_dest); 197 if acc_x_dest >= bmp.Width then 198 begin 199 Dec(acc_x_dest, bmp.Width); 200 Inc(x_dest); 201 end; 202 203 srcColor := PSrc^; 204 Inc(PSrc); 205 206 PDest := Result.scanline[prev_y_dest] + prev_x_dest; 207 delta := lineDelta - (x_dest - prev_x_dest); 208 for yb := prev_y_dest to y_dest - 1 do 209 begin 210 for xb := prev_x_dest to x_dest - 1 do 211 begin 212 PDest^ := srcColor; 213 Inc(PDest); 321 prevVertTransition:= tsPlain; 322 end else 323 begin 324 PSrc2 := bmp.Scanline[y_src2]+x_src; 325 for x_dest := targetRect.left to targetRect.right - 1 do 326 begin 327 horizTransition:= prevHorizTransition; 328 LinearMix(psrc1, DeltaSrcX, acc_x_src2 >= NewWidth shr 2, @vertColors[1], horizSlightlyDifferent, horizTransition); 329 horizTransition:= prevHorizTransition; 330 LinearMix(psrc2, DeltaSrcX, acc_x_src2 >= NewWidth shr 2, @vertColors[2], horizSlightlyDifferent, horizTransition); 331 prevHorizTransition:= horizTransition; 332 vertTransition:= prevVertTransition; 333 LinearMix(@vertColors[1],1,acc_y_src2 >= NewHeight shr 2,PDest,vertSlightlyDifferent,vertTransition); 334 335 Inc(PSrc1, inc_x_src); 336 Inc(PSrc2, inc_x_src); 337 Inc(acc_x_src, mod_x_src); 338 if acc_x_src >= newWidth then 339 begin 340 Dec(acc_x_src, newWidth); 341 Inc(PSrc1); 342 Inc(PSrc2); 343 dec(DeltaSrcX); 344 end; 345 Inc(acc_x_src2, mod_x_src); 346 if acc_x_src2 >= newWidth then 347 begin 348 Dec(acc_x_src2, newWidth); 349 Inc(DeltaSrcX); 350 end; 351 inc(PDest); 214 352 end; 215 Inc(PDest, delta); 216 end; 217 end; 218 end; 219 Result.InvalidateBitmap; 220 end; 221 222 function SimpleStretchSmallerFactor2(source: TBGRACustomBitmap): TBGRACustomBitmap; 223 var xb,yb: integer; 353 prevVertTransition:= vertTransition; 354 end; 355 356 if tempData <> nil then 357 PutPixels(dest.ScanLine[y_dest+OffsetY]+OffsetX+targetRect.Left,tempData,targetRect.right-targetRect.left,ADrawMode,AOpacity); 358 end; 359 360 prev_y_src := y_src; 361 prev_y_src2 := y_src2; 362 363 Inc(y_src, inc_y_src); 364 Inc(acc_y_src, mod_y_src); 365 if acc_y_src >= newheight then 366 begin 367 Dec(acc_y_src, newheight); 368 Inc(y_src); 369 end; 370 371 Inc(y_src2, inc_y_src); 372 Inc(acc_y_src2, mod_y_src); 373 if acc_y_src2 >= newheight then 374 begin 375 Dec(acc_y_src2, newheight); 376 Inc(y_src2); 377 end; 378 end; 379 dest.InvalidateBitmap; 380 if Assigned(tempData) then FreeMem(tempData); 381 end; 382 383 procedure DownSamplePutImage2(source: TBGRACustomBitmap; 384 dest: TBGRACustomBitmap; OffsetX, OffsetY: Integer; ADrawMode: TDrawMode); 385 const factorX = 2; factorY = 2; nbi= factorX*factorY; 386 var xb,yb,ys: NativeInt; 224 387 pdest: PBGRAPixel; 225 388 psrc1,psrc2: PBGRAPixel; 226 asum: integer; 227 a1,a2,a3,a4: integer; 228 newWidth,newHeight: integer; 229 begin 230 newWidth := source.Width div 2; 231 newHeight := source.Height div 2; 232 result := source.NewBitmap(newWidth,newHeight); 389 asum,maxsum: NativeUInt; 390 newWidth,newHeight: NativeInt; 391 r,g,b: NativeUInt; 392 begin 393 if (source.Width mod factorX <> 0) or (source.Height mod factorY <> 0) then 394 raise exception.Create('Source size must be a multiple of factorX and factorY'); 395 newWidth := source.Width div factorX; 396 newHeight := source.Height div factorY; 397 ys := 0; 398 maxsum := 255*NativeInt(factorX)*NativeInt(factorY); 233 399 for yb := 0 to newHeight-1 do 234 400 begin 235 pdest := result.ScanLine[yb];236 psrc1 := source.Scanline[y b shl 1];237 psrc2 := source.Scanline[y b shl 1+1];401 pdest := dest.ScanLine[yb+OffsetY]+OffsetX; 402 psrc1 := source.Scanline[ys]; inc(ys); 403 psrc2 := source.Scanline[ys]; inc(ys); 238 404 for xb := newWidth-1 downto 0 do 239 405 begin 240 asum := psrc1^.alpha + (psrc1+1)^.alpha + psrc2^.alpha + (psrc2+1)^.alpha; 241 if asum = 0 then 242 pdest^ := BGRAPixelTransparent 243 else if asum = 1020 then 406 asum := 0; 407 asum := psrc1^.alpha + psrc2^.alpha + (psrc1+1)^.alpha + (psrc2+1)^.alpha; 408 if asum = maxsum then 244 409 begin 245 410 pdest^.alpha := 255; 246 pdest^.red := (psrc1^.red + (psrc1+1)^.red + psrc2^.red + (psrc2+1)^.red + 2) shr 2; 247 pdest^.green := (psrc1^.green + (psrc1+1)^.green + psrc2^.green + (psrc2+1)^.green+ 2) shr 2; 248 pdest^.blue := (psrc1^.blue + (psrc1+1)^.blue + psrc2^.blue + (psrc2+1)^.blue+ 2) shr 2; 411 r := psrc1^.red + psrc2^.red + (psrc1+1)^.red + (psrc2+1)^.red; 412 g := psrc1^.green + psrc2^.green + (psrc1+1)^.green + (psrc2+1)^.green; 413 b := psrc1^.blue + psrc2^.blue + (psrc1+1)^.blue + (psrc2+1)^.blue; 414 inc(psrc1,factorX); inc(psrc2,factorX); 415 pdest^.red := (r + (nbi shr 1)) shr 2; 416 pdest^.green := (g + (nbi shr 1)) shr 2; 417 pdest^.blue := (b + (nbi shr 1)) shr 2; 249 418 end else 250 begin 251 pdest^.alpha := asum shr 2; 252 a1 := psrc1^.alpha; 253 a2 := (psrc1+1)^.alpha; 254 a3 := psrc2^.alpha; 255 a4 := (psrc2+1)^.alpha; 256 pdest^.red := (psrc1^.red*a1 + (psrc1+1)^.red*a2 + psrc2^.red*a3 + (psrc2+1)^.red*a4 + (asum shr 1)) div asum; 257 pdest^.green := (psrc1^.green*a1 + (psrc1+1)^.green*a2 + psrc2^.green*a3 + (psrc2+1)^.green*a4+ (asum shr 1)) div asum; 258 pdest^.blue := (psrc1^.blue*a1 + (psrc1+1)^.blue*a2 + psrc2^.blue*a3 + (psrc2+1)^.blue*a4+ (asum shr 1)) div asum; 259 end; 260 inc(psrc1,2); 261 inc(psrc2,2); 419 if ADrawMode <> dmSetExceptTransparent then 420 begin 421 if asum = 0 then 422 begin 423 if ADrawMode = dmSet then 424 pdest^ := BGRAPixelTransparent; 425 inc(psrc1,factorX); inc(psrc2,factorX); 426 end 427 else 428 begin 429 r := psrc1^.red*psrc1^.alpha + psrc2^.red*psrc2^.alpha + (psrc1+1)^.red*(psrc1+1)^.alpha + (psrc2+1)^.red*(psrc2+1)^.alpha; 430 g := psrc1^.green*psrc1^.alpha + psrc2^.green*psrc2^.alpha + (psrc1+1)^.green*(psrc1+1)^.alpha + (psrc2+1)^.green*(psrc2+1)^.alpha; 431 b := psrc1^.blue*psrc1^.alpha + psrc2^.blue*psrc2^.alpha + (psrc1+1)^.blue*(psrc1+1)^.alpha + (psrc2+1)^.blue*(psrc2+1)^.alpha; 432 inc(psrc1,factorX); inc(psrc2,factorX); 433 if ADrawMode = dmSet then 434 begin 435 pdest^.alpha := (asum + (nbi shr 1)) shr 2; 436 pdest^.red := (r + (asum shr 1)) div asum; 437 pdest^.green := (g + (asum shr 1)) div asum; 438 pdest^.blue := (b + (asum shr 1)) div asum; 439 end 440 else 441 begin 442 if ADrawMode = dmDrawWithTransparency then 443 DrawPixelInlineWithAlphaCheck(pdest,BGRA((r + (asum shr 1)) div asum, 444 (g + (asum shr 1)) div asum, 445 (b + (asum shr 1)) div asum, 446 (asum + (nbi shr 1)) shr 2)) else 447 if ADrawMode = dmFastBlend then 448 FastBlendPixelInline(pdest,BGRA((r + (asum shr 1)) div asum, 449 (g + (asum shr 1)) div asum, 450 (b + (asum shr 1)) div asum, 451 (asum + (nbi shr 1)) shr 2)); 452 end; 453 end; 454 end; 262 455 inc(pdest); 263 456 end; … … 265 458 end; 266 459 267 function SimpleStretchSmallerFactor4(source: TBGRACustomBitmap): TBGRACustomBitmap; 268 var xb,yb: integer; 460 procedure DownSamplePutImage3(source: TBGRACustomBitmap; 461 dest: TBGRACustomBitmap; OffsetX, OffsetY: Integer; ADrawMode: TDrawMode); 462 const factorX = 3; factorY = 3; nbi= factorX*factorY; 463 var xb,yb,ys: NativeInt; 269 464 pdest: PBGRAPixel; 270 psrc1,psrc2,psrc3 ,psrc4: PBGRAPixel;271 asum : integer;272 a1,a2,a3,a4,273 a5,a6,a7,a8,274 a9,a10,a11,a12, 275 a13,a14,a15,a16: integer;276 newWidth,newHeight: integer;277 begin 278 new Width := source.Width div 4;279 newHeight := source.Height div 4;280 result := source.NewBitmap(newWidth,newHeight);465 psrc1,psrc2,psrc3: PBGRAPixel; 466 asum,maxsum: NativeUInt; 467 newWidth,newHeight: NativeInt; 468 r,g,b: NativeUInt; 469 begin 470 if (source.Width mod factorX <> 0) or (source.Height mod factorY <> 0) then 471 raise exception.Create('Source size must be a multiple of factorX and factorY'); 472 newWidth := source.Width div factorX; 473 newHeight := source.Height div factorY; 474 ys := 0; 475 maxsum := 255*NativeInt(factorX)*NativeInt(factorY); 281 476 for yb := 0 to newHeight-1 do 282 477 begin 283 pdest := result.ScanLine[yb]; 284 psrc1 := source.Scanline[yb shl 2]; 285 psrc2 := source.Scanline[yb shl 2+1]; 286 psrc3 := source.Scanline[yb shl 2+2]; 287 psrc4 := source.Scanline[yb shl 2+3]; 478 pdest := dest.ScanLine[yb+OffsetY]+OffsetX; 479 psrc1 := source.Scanline[ys]; inc(ys); 480 psrc2 := source.Scanline[ys]; inc(ys); 481 psrc3 := source.Scanline[ys]; inc(ys); 288 482 for xb := newWidth-1 downto 0 do 289 483 begin 290 asum := psrc1^.alpha + (psrc1+1)^.alpha + (psrc1+2)^.alpha + (psrc1+3)^.alpha + 291 psrc2^.alpha + (psrc2+1)^.alpha + (psrc2+2)^.alpha + (psrc2+3)^.alpha + 292 psrc3^.alpha + (psrc3+1)^.alpha + (psrc3+2)^.alpha + (psrc3+3)^.alpha + 293 psrc4^.alpha + (psrc4+1)^.alpha + (psrc4+2)^.alpha + (psrc4+3)^.alpha; 294 if asum = 0 then 295 pdest^ := BGRAPixelTransparent 296 else if asum = 4080 then 484 asum := 0; 485 asum := psrc1^.alpha + psrc2^.alpha + psrc3^.alpha 486 + (psrc1+1)^.alpha + (psrc2+1)^.alpha + (psrc3+1)^.alpha 487 + (psrc1+2)^.alpha + (psrc2+2)^.alpha + (psrc3+2)^.alpha; 488 if asum = maxsum then 297 489 begin 298 490 pdest^.alpha := 255; 299 pdest^.red := (psrc1^.red + (psrc1+1)^.red + (psrc1+2)^.red + (psrc1+3)^.red + 300 psrc2^.red + (psrc2+1)^.red + (psrc2+2)^.red + (psrc2+3)^.red + 301 psrc3^.red + (psrc3+1)^.red + (psrc3+2)^.red + (psrc3+3)^.red + 302 psrc4^.red + (psrc4+1)^.red + (psrc4+2)^.red + (psrc4+3)^.red + 8) shr 4; 303 pdest^.green := (psrc1^.green + (psrc1+1)^.green + (psrc1+2)^.green + (psrc1+3)^.green + 304 psrc2^.green + (psrc2+1)^.green + (psrc2+2)^.green + (psrc2+3)^.green + 305 psrc3^.green + (psrc3+1)^.green + (psrc3+2)^.green + (psrc3+3)^.green + 306 psrc4^.green + (psrc4+1)^.green + (psrc4+2)^.green + (psrc4+3)^.green + 8) shr 4; 307 pdest^.blue := (psrc1^.blue + (psrc1+1)^.blue + (psrc1+2)^.blue + (psrc1+3)^.blue + 308 psrc2^.blue + (psrc2+1)^.blue + (psrc2+2)^.blue + (psrc2+3)^.blue + 309 psrc3^.blue + (psrc3+1)^.blue + (psrc3+2)^.blue + (psrc3+3)^.blue + 310 psrc4^.blue + (psrc4+1)^.blue + (psrc4+2)^.blue + (psrc4+3)^.blue + 8) shr 4; 491 r := psrc1^.red + psrc2^.red + psrc3^.red 492 + (psrc1+1)^.red + (psrc2+1)^.red + (psrc3+1)^.red 493 + (psrc1+2)^.red + (psrc2+2)^.red + (psrc3+2)^.red; 494 g := psrc1^.green + psrc2^.green + psrc3^.green 495 + (psrc1+1)^.green + (psrc2+1)^.green + (psrc3+1)^.green 496 + (psrc1+2)^.green + (psrc2+2)^.green + (psrc3+2)^.green; 497 b := psrc1^.blue + psrc2^.blue + psrc3^.blue 498 + (psrc1+1)^.blue + (psrc2+1)^.blue + (psrc3+1)^.blue 499 + (psrc1+2)^.blue + (psrc2+2)^.blue + (psrc3+2)^.blue; 500 inc(psrc1,factorX); inc(psrc2,factorX); inc(psrc3,factorX); 501 pdest^.red := (r + (nbi shr 1)) div 9; 502 pdest^.green := (g + (nbi shr 1)) div 9; 503 pdest^.blue := (b + (nbi shr 1)) div 9; 311 504 end else 312 begin 313 pdest^.alpha := asum shr 4; 314 a1 := psrc1^.alpha; 315 a2 := (psrc1+1)^.alpha; 316 a3 := (psrc1+2)^.alpha; 317 a4 := (psrc1+3)^.alpha; 318 a5 := psrc2^.alpha; 319 a6 := (psrc2+1)^.alpha; 320 a7 := (psrc2+2)^.alpha; 321 a8 := (psrc2+3)^.alpha; 322 a9 := psrc3^.alpha; 323 a10 := (psrc3+1)^.alpha; 324 a11 := (psrc3+2)^.alpha; 325 a12 := (psrc3+3)^.alpha; 326 a13 := psrc4^.alpha; 327 a14 := (psrc4+1)^.alpha; 328 a15 := (psrc4+2)^.alpha; 329 a16 := (psrc4+3)^.alpha; 330 pdest^.red := (psrc1^.red*a1 + (psrc1+1)^.red*a2 + (psrc1+2)^.red*a3 + (psrc1+3)^.red*a4 + 331 psrc2^.red*a5 + (psrc2+1)^.red*a6 + (psrc2+2)^.red*a7 + (psrc2+3)^.red*a8 + 332 psrc3^.red*a9 + (psrc3+1)^.red*a10 + (psrc3+2)^.red*a11 + (psrc3+3)^.red*a12 + 333 psrc4^.red*a13 + (psrc4+1)^.red*a14 + (psrc4+2)^.red*a15 + (psrc4+3)^.red*a16 + (asum shr 1)) div asum; 334 pdest^.green := (psrc1^.green*a1 + (psrc1+1)^.green*a2 + (psrc1+2)^.green*a3 + (psrc1+3)^.green*a4 + 335 psrc2^.green*a5 + (psrc2+1)^.green*a6 + (psrc2+2)^.green*a7 + (psrc2+3)^.green*a8 + 336 psrc3^.green*a9 + (psrc3+1)^.green*a10 + (psrc3+2)^.green*a11 + (psrc3+3)^.green*a12 + 337 psrc4^.green*a13 + (psrc4+1)^.green*a14 + (psrc4+2)^.green*a15 + (psrc4+3)^.green*a16 + (asum shr 1)) div asum; 338 pdest^.blue := (psrc1^.blue*a1 + (psrc1+1)^.blue*a2 + (psrc1+2)^.blue*a3 + (psrc1+3)^.blue*a4 + 339 psrc2^.blue*a5 + (psrc2+1)^.blue*a6 + (psrc2+2)^.blue*a7 + (psrc2+3)^.blue*a8 + 340 psrc3^.blue*a9 + (psrc3+1)^.blue*a10 + (psrc3+2)^.blue*a11 + (psrc3+3)^.blue*a12 + 341 psrc4^.blue*a13 + (psrc4+1)^.blue*a14 + (psrc4+2)^.blue*a15 + (psrc4+3)^.blue*a16 + (asum shr 1)) div asum; 342 end; 343 inc(psrc1,4); 344 inc(psrc2,4); 345 inc(psrc3,4); 346 inc(psrc4,4); 505 if ADrawMode <> dmSetExceptTransparent then 506 begin 507 if asum = 0 then 508 begin 509 if ADrawMode = dmSet then 510 pdest^ := BGRAPixelTransparent; 511 inc(psrc1,factorX); inc(psrc2,factorX); inc(psrc3,factorX); 512 end 513 else 514 begin 515 r := psrc1^.red*psrc1^.alpha + psrc2^.red*psrc2^.alpha + psrc3^.red*psrc3^.alpha 516 + (psrc1+1)^.red*(psrc1+1)^.alpha + (psrc2+1)^.red*(psrc2+1)^.alpha + (psrc3+1)^.red*(psrc3+1)^.alpha 517 + (psrc1+2)^.red*(psrc1+2)^.alpha + (psrc2+2)^.red*(psrc2+2)^.alpha + (psrc3+2)^.red*(psrc3+2)^.alpha; 518 g := psrc1^.green*psrc1^.alpha + psrc2^.green*psrc2^.alpha + psrc3^.green*psrc3^.alpha 519 + (psrc1+1)^.green*(psrc1+1)^.alpha + (psrc2+1)^.green*(psrc2+1)^.alpha + (psrc3+1)^.green*(psrc3+1)^.alpha 520 + (psrc1+2)^.green*(psrc1+2)^.alpha + (psrc2+2)^.green*(psrc2+2)^.alpha + (psrc3+2)^.green*(psrc3+2)^.alpha; 521 b := psrc1^.blue*psrc1^.alpha + psrc2^.blue*psrc2^.alpha + psrc3^.blue*psrc3^.alpha 522 + (psrc1+1)^.blue*(psrc1+1)^.alpha + (psrc2+1)^.blue*(psrc2+1)^.alpha + (psrc3+1)^.blue*(psrc3+1)^.alpha 523 + (psrc1+2)^.blue*(psrc1+2)^.alpha + (psrc2+2)^.blue*(psrc2+2)^.alpha + (psrc3+2)^.blue*(psrc3+2)^.alpha; 524 inc(psrc1,factorX); inc(psrc2,factorX); inc(psrc3,factorX); 525 if ADrawMode = dmSet then 526 begin 527 pdest^.alpha := (asum + (nbi shr 1)) div 9; 528 pdest^.red := (r + (asum shr 1)) div asum; 529 pdest^.green := (g + (asum shr 1)) div asum; 530 pdest^.blue := (b + (asum shr 1)) div asum; 531 end 532 else 533 begin 534 if ADrawMode = dmDrawWithTransparency then 535 DrawPixelInlineWithAlphaCheck(pdest,BGRA((r + (asum shr 1)) div asum, 536 (g + (asum shr 1)) div asum, 537 (b + (asum shr 1)) div asum, 538 (asum + (nbi shr 1)) div 9)) else 539 if ADrawMode = dmFastBlend then 540 FastBlendPixelInline(pdest,BGRA((r + (asum shr 1)) div asum, 541 (g + (asum shr 1)) div asum, 542 (b + (asum shr 1)) div asum, 543 (asum + (nbi shr 1)) div 9)); 544 end; 545 end; 546 end; 347 547 inc(pdest); 348 548 end; … … 350 550 end; 351 551 352 function SimpleStretchSmallerFactor(source: TBGRACustomBitmap; fx,fy: integer): TBGRACustomBitmap; 353 var xb,yb,ys,iy,ix: integer; 354 pdest: PBGRAPixel; 552 procedure DownSamplePutImage(source: TBGRACustomBitmap; factorX, factorY: integer; 553 dest: TBGRACustomBitmap; OffsetX, OffsetY: Integer; ADrawMode: TDrawMode); 554 var xb,yb,ys,iy,ix: NativeInt; 555 pdest,psrci: PBGRAPixel; 355 556 psrc: array of PBGRAPixel; 356 psrci: PBGRAPixel; 357 asum,maxsum: integer; 358 newWidth,newHeight: integer; 359 r,g,b,nbi: integer; 360 begin 361 newWidth := source.Width div fx; 362 newHeight := source.Height div fy; 363 result := source.NewBitmap(newWidth,newHeight); 557 asum,maxsum: NativeUInt; 558 newWidth,newHeight: NativeInt; 559 r,g,b,nbi: NativeUInt; 560 begin 561 if ADrawMode = dmXor then raise exception.Create('dmXor drawmode not supported'); 562 if (factorX = 2) and (factorY = 2) then 563 begin 564 DownSamplePutImage2(source,dest,OffsetX,OffsetY,ADrawMode); 565 exit; 566 end; 567 if (factorX = 3) and (factorY = 3) then 568 begin 569 DownSamplePutImage3(source,dest,OffsetX,OffsetY,ADrawMode); 570 exit; 571 end; 572 if (source.Width mod factorX <> 0) or (source.Height mod factorY <> 0) then 573 raise exception.Create('Source size must be a multiple of factorX and factorY'); 574 newWidth := source.Width div factorX; 575 newHeight := source.Height div factorY; 364 576 ys := 0; 365 maxsum := 255* fx*fy;366 nbi := f x*fy;367 setlength(psrc, f y);577 maxsum := 255*NativeInt(factorX)*NativeInt(factorY); 578 nbi := factorX*factorY; 579 setlength(psrc, factorY); 368 580 for yb := 0 to newHeight-1 do 369 581 begin 370 pdest := result.ScanLine[yb];371 for iy := f y-1 downto 0 do582 pdest := dest.ScanLine[yb+OffsetY]+OffsetX; 583 for iy := factorY-1 downto 0 do 372 584 begin 373 585 psrc[iy] := source.Scanline[ys]; … … 377 589 begin 378 590 asum := 0; 379 for iy := f y-1 downto 0 do591 for iy := factorY-1 downto 0 do 380 592 begin 381 593 psrci := psrc[iy]; 382 for ix := f x-1 downto 0 do594 for ix := factorX-1 downto 0 do 383 595 asum += (psrci+ix)^.alpha; 384 596 end; 385 if asum = 0 then 386 pdest^ := BGRAPixelTransparent 387 else if asum = maxsum then 597 if asum = maxsum then 388 598 begin 389 599 pdest^.alpha := 255; … … 391 601 g := 0; 392 602 b := 0; 393 for iy := fy-1 downto 0 do 394 begin 395 psrci := psrc[iy]; 396 for ix := fx-1 downto 0 do 603 for iy := factorY-1 downto 0 do 604 for ix := factorX-1 downto 0 do 397 605 begin 398 with (psrci+ix)^ do606 with psrc[iy]^ do 399 607 begin 400 608 r += red; … … 402 610 b += blue; 403 611 end; 612 inc(psrc[iy]); 404 613 end; 405 end;406 614 pdest^.red := (r + (nbi shr 1)) div nbi; 407 615 pdest^.green := (g + (nbi shr 1)) div nbi; 408 616 pdest^.blue := (b + (nbi shr 1)) div nbi; 409 617 end else 410 begin 411 pdest^.alpha := (asum + (nbi shr 1)) div nbi; 412 r := 0; 413 g := 0; 414 b := 0; 415 for iy := fy-1 downto 0 do 416 begin 417 psrci := psrc[iy]; 418 for ix := fx-1 downto 0 do 618 if ADrawMode <> dmSetExceptTransparent then 619 begin 620 if asum = 0 then 621 begin 622 if ADrawMode = dmSet then 623 pdest^ := BGRAPixelTransparent; 624 for iy := factorY-1 downto 0 do 625 inc(psrc[iy],factorX); 626 end 627 else 628 begin 629 r := 0; 630 g := 0; 631 b := 0; 632 for iy := factorY-1 downto 0 do 633 for ix := factorX-1 downto 0 do 634 begin 635 with psrc[iy]^ do 636 begin 637 r += red*alpha; 638 g += green*alpha; 639 b += blue*alpha; 640 end; 641 inc(psrc[iy]); 642 end; 643 if ADrawMode = dmSet then 419 644 begin 420 with (psrci+ix)^ do 421 begin 422 r += integer(red)*integer(alpha); 423 g += integer(green)*integer(alpha); 424 b += integer(blue)*integer(alpha); 425 end; 645 pdest^.alpha := (asum + (nbi shr 1)) div nbi; 646 pdest^.red := (r + (asum shr 1)) div asum; 647 pdest^.green := (g + (asum shr 1)) div asum; 648 pdest^.blue := (b + (asum shr 1)) div asum; 649 end 650 else 651 begin 652 if ADrawMode = dmDrawWithTransparency then 653 DrawPixelInlineWithAlphaCheck(pdest,BGRA((r + (asum shr 1)) div asum, 654 (g + (asum shr 1)) div asum, 655 (b + (asum shr 1)) div asum, 656 (asum + (nbi shr 1)) div nbi)) else 657 if ADrawMode = dmFastBlend then 658 FastBlendPixelInline(pdest,BGRA((r + (asum shr 1)) div asum, 659 (g + (asum shr 1)) div asum, 660 (b + (asum shr 1)) div asum, 661 (asum + (nbi shr 1)) div nbi)); 426 662 end; 427 663 end; 428 pdest^.red := (r + (asum shr 1)) div asum; 429 pdest^.green := (g + (asum shr 1)) div asum; 430 pdest^.blue := (b + (asum shr 1)) div asum; 431 end; 432 for iy := fy-1 downto 0 do 433 inc(psrc[iy],fx); 664 end; 434 665 inc(pdest); 435 666 end; … … 437 668 end; 438 669 439 function SimpleStretchSmaller(bmp: TBGRACustomBitmap; 440 newWidth, newHeight: integer): TBGRACustomBitmap; 441 var 442 x_dest, y_dest: integer; 443 inc_x_src, mod_x_src, acc_x_src, inc_y_src, mod_y_src, acc_y_src: integer; 444 x_src, y_src, prev_x_src, prev_y_src: integer; 445 x_src2, y_src2: integer; 446 447 xb, yb: integer; 448 v1, v2, v3, v4, v4shr1: int64; 449 nb,a: integer; 450 pdest, psrc, psrcscan: PBGRAPixel; 451 lineDelta, delta: integer; 452 453 begin 454 if (newWidth > bmp.Width) or (newHeight > bmp.Height) then 455 raise ERangeError.Create('SimpleStretchSmaller: New dimensions must be smaller or equal ('+IntToStr(bmp.Width)+'x'+IntToStr(bmp.Height)+'->'+IntToStr(newWidth)+'x'+IntToStr(newHeight)+')'); 456 457 if (newWidth = 0) or (newHeight = 0) or (bmp.Width = 0) or (bmp.Height = 0) then 458 begin 459 Result := bmp.NewBitmap(NewWidth, NewHeight); 460 exit; 461 end; 462 463 if (newWidth*2 = bmp.Width) and (newHeight*2 = bmp.Height) then 464 begin 465 result := SimpleStretchSmallerFactor2(bmp); 466 exit 467 end 468 else 469 if (newWidth*4 = bmp.Width) and (newHeight*4 = bmp.Height) then 470 begin 471 result := SimpleStretchSmallerFactor4(bmp); 472 exit; 473 end 474 else 475 if (newWidth < bmp.Width) and (newHeight < bmp.Height) and 476 (bmp.Width mod newWidth = 0) and (bmp.Height mod newHeight = 0) then 477 begin 478 result := SimpleStretchSmallerFactor(bmp, bmp.Width div newWidth, bmp.Height div newHeight); 479 exit; 480 end; 481 482 Result := bmp.NewBitmap(NewWidth, NewHeight); 483 484 bmp.LoadFromBitmapIfNeeded; 485 486 inc_x_src := bmp.Width div newWidth; 487 mod_x_src := bmp.Width mod newWidth; 488 inc_y_src := bmp.Height div newHeight; 489 mod_y_src := bmp.Height mod newHeight; 490 491 if bmp.lineOrder = riloTopToBottom then 492 lineDelta := bmp.Width 493 else 494 lineDelta := -bmp.Width; 495 496 y_src := 0; 497 acc_y_src := 0; 498 for y_dest := 0 to newHeight - 1 do 499 begin 500 PDest := Result.ScanLine[y_dest]; 501 502 prev_y_src := y_src; 503 Inc(y_src, inc_y_src); 504 Inc(acc_y_src, mod_y_src); 505 if acc_y_src >= newHeight then 506 begin 507 Dec(acc_y_src, newHeight); 508 Inc(y_src); 509 end; 510 if y_src > prev_y_src then 511 y_src2 := y_src - 1 512 else 513 y_src2 := y_src; 514 psrcscan := bmp.Scanline[prev_y_src]; 515 516 x_src := 0; 517 acc_x_src := 0; 518 for x_dest := 0 to newWidth - 1 do 519 begin 520 prev_x_src := x_src; 521 Inc(x_src, inc_x_src); 522 Inc(acc_x_src, mod_x_src); 523 if acc_x_src >= newWidth then 524 begin 525 Dec(acc_x_src, newWidth); 526 Inc(x_src); 527 end; 528 if x_src > prev_x_src then 529 x_src2 := x_src - 1 530 else 531 x_src2 := x_src; 532 533 v1 := 0; 534 v2 := 0; 535 v3 := 0; 536 v4 := 0; 537 nb := 0; 538 delta := lineDelta - (x_src2 - prev_x_src + 1); 539 540 PSrc := psrcscan + prev_x_src; 541 for yb := prev_y_src to y_src2 do 542 begin 543 for xb := prev_x_src to x_src2 do 544 begin 545 with PSrc^ do 546 begin 547 a := alpha; 548 {$HINTS OFF} 549 v1 += integer(red) * a; 550 v2 += integer(green) * a; 551 v3 += integer(blue) * a; 552 {$HINTS ON} 553 end; 554 v4 += a; 555 Inc(PSrc); 556 Inc(nb); 557 end; 558 Inc(PSrc, delta); 559 end; 560 561 if (v4 <> 0) and (nb <> 0) then 562 begin 563 v4shr1 := v4 shr 1; 564 with PDest^ do 565 begin 566 red := (v1 + v4shr1) div v4; 567 green := (v2 + v4shr1) div v4; 568 blue := (v3 + v4shr1) div v4; 569 alpha := (v4 + (nb shr 1)) div nb; 570 end; 571 end 572 else 573 PDest^ := BGRAPixelTransparent; 574 575 Inc(PDest); 576 end; 577 end; 578 Result.InvalidateBitmap; 579 end; 580 581 function SimpleStretch(bmp: TBGRACustomBitmap; 582 NewWidth, NewHeight: integer): TBGRACustomBitmap; 583 var 584 temp, newtemp: TBGRACustomBitmap; 585 begin 586 if (NewWidth = bmp.Width) and (NewHeight = bmp.Height) then 587 Result := bmp.Duplicate 588 else 589 if (NewWidth >= bmp.Width) and (NewHeight >= bmp.Height) then 590 Result := SimpleStretchLarger(bmp, NewWidth, NewHeight) 591 else 592 if (NewWidth <= bmp.Width) and (NewHeight <= bmp.Height) then 593 Result := SimpleStretchSmaller(bmp, NewWidth, NewHeight) 594 else 595 begin 596 temp := bmp; 597 598 if NewWidth < bmp.Width then 599 begin 600 newtemp := SimpleStretchSmaller(temp, NewWidth, temp.Height); 601 if (temp <> bmp) then 602 temp.Free; 603 temp := newtemp; 604 end; 605 606 if NewHeight < bmp.Height then 607 begin 608 newtemp := SimpleStretchSmaller(temp, temp.Width, NewHeight); 609 if (temp <> bmp) then 610 temp.Free; 611 temp := newtemp; 612 end; 613 614 if NewWidth > bmp.Width then 615 begin 616 newtemp := SimpleStretchLarger(temp, NewWidth, temp.Height); 617 if (temp <> bmp) then 618 temp.Free; 619 temp := newtemp; 620 end; 621 622 if NewHeight > bmp.Height then 623 begin 624 newtemp := SimpleStretchLarger(temp, temp.Width, NewHeight); 625 if (temp <> bmp) then 626 temp.Free; 627 temp := newtemp; 628 end; 629 630 if temp <> bmp then 631 Result := temp 632 else 633 Result := bmp.Duplicate; 634 end; 670 function DownSample(source: TBGRACustomBitmap; factorX, factorY: integer): TBGRACustomBitmap; 671 begin 672 if (source.Width mod factorX <> 0) or (source.Height mod factorY <> 0) then 673 raise exception.Create('Source size must be a multiple of factorX and factorY'); 674 result := source.NewBitmap(source.Width div factorX, source.Height div factorY); 675 DownSamplePutImage(source,factorX,factorY,result,0,0,dmSet); 635 676 end; 636 677 … … 639 680 function FineInterpolation(t: single; ResampleFilter: TResampleFilter): single; 640 681 begin 641 if ResampleFilter = rfLinear then 642 result := t else 682 if ResampleFilter <= rfLinear then 683 begin 684 if ResampleFilter = rfBox then 685 begin 686 result := round(t); 687 end else 688 result := t; 689 end else 643 690 begin 644 691 if t <= 0.5 then … … 651 698 function FineInterpolation256(t256: integer; ResampleFilter: TResampleFilter): integer; 652 699 begin 653 if ResampleFilter = rfLinear then 654 result := t256 else 700 if ResampleFilter <= rfLinear then 701 begin 702 if ResampleFilter = rfBox then 703 begin 704 if t256 < 128 then 705 result := 0 706 else 707 result := 256; 708 end 709 else 710 result := t256; 711 end else 655 712 begin 656 713 if t256 <= 128 then … … 751 808 begin 752 809 Result := 2; 810 end; 811 812 { TLanczosKernel } 813 { by stab } 814 procedure TLanczosKernel.SetNumberOfLobes(AValue: integer); 815 begin 816 if AValue < 1 then AValue := 1; 817 if FNumberOfLobes=AValue then Exit; 818 FNumberOfLobes:=AValue; 819 if AValue = 1 then FFactor := 1.5 else FFactor := AValue; 820 end; 821 822 constructor TLanczosKernel.Create(ANumberOfLobes: integer); 823 begin 824 NumberOfLobes:= ANumberOfLobes; 825 end; 826 827 function TLanczosKernel.Interpolation(t: single): single; 828 var Pi_t: ValReal; 829 begin 830 if t = 0 then 831 Result := 1 832 else if t < FNumberOfLobes then 833 begin 834 Pi_t := pi * t; 835 Result := FFactor * sin(Pi_t) * sin(Pi_t / FNumberOfLobes) / 836 (Pi_t * Pi_t) 837 end 838 else 839 Result := 0; 840 end; 841 842 function TLanczosKernel.ShouldCheckRange: boolean; 843 begin 844 Result := True; 845 end; 846 847 function TLanczosKernel.KernelWidth: single; 848 begin 849 Result := FNumberOfLobes; 753 850 end; 754 851 … … 1090 1187 tempFilter1,tempFilter2: TWideKernelFilter; 1091 1188 begin 1189 if (NewWidth = bmp.Width) and (NewHeight = bmp.Height) then 1190 begin 1191 Result := bmp.Duplicate; 1192 exit; 1193 end; 1092 1194 case ResampleFilter of 1093 1195 rfBicubic: //blur … … 1108 1210 begin 1109 1211 tempFilter1 := TSplineKernel.Create; 1212 result := WideKernelResample(bmp,NewWidth,NewHeight,tempFilter1,tempFilter1); 1213 tempFilter1.Free; 1214 exit; 1215 end; 1216 rfLanczos2,rfLanczos3,rfLanczos4: 1217 begin 1218 tempFilter1 := TLanczosKernel.Create(ord(ResampleFilter)-ord(rfLanczos2)+2); 1110 1219 result := WideKernelResample(bmp,NewWidth,NewHeight,tempFilter1,tempFilter1); 1111 1220 tempFilter1.Free; … … 1123 1232 end; 1124 1233 1125 if (NewWidth = bmp.Width) and (NewHeight = bmp.Height) then1126 Result := bmp.Duplicate1127 else1128 1234 if (NewWidth >= bmp.Width) and (NewHeight >= bmp.Height) then 1129 1235 Result := FineResampleLarger(bmp, NewWidth, NewHeight, ResampleFilter) -
GraphicTest/Packages/bgrabitmap/bgrascene3d.pas
r452 r472 9 9 10 10 type 11 TProjection3D = BGRAMatrix3D.TProjection3D; 12 TBox3D = record 13 min,max: TPoint3D; 14 end; 15 16 TLightingNormal3D = (lnNone, lnFace, lnVertex, lnFaceVertexMix); 17 TLightingInterpolation3D = (liLowQuality, liSpecularHighQuality, liAlwaysHighQuality); 18 TAntialiasingMode3D = (am3dNone, am3dMultishape, am3dResample); 19 TPerspectiveMode3D = (pmLinearMapping, pmPerspectiveMapping, pmZBuffer); 20 21 TRenderingOptions = record 22 LightingInterpolation: TLightingInterpolation3D; 23 AntialiasingMode: TAntialiasingMode3D; 24 AntialiasingResampleLevel: integer; 25 PerspectiveMode: TPerspectiveMode3D; 26 TextureInterpolation: boolean; 27 MinZ: single; 28 end; 29 11 30 PSceneLightingContext = ^TSceneLightingContext; 12 31 TSceneLightingContext = packed record … … 23 42 SaturationHigh: integer; 24 43 SaturationHighF: single; 25 end;26 27 TProjection3D = packed record28 Zoom, Center: TPointF;29 end;30 31 TBox3D = record32 min,max: TPoint3D;33 end;34 35 TLightingNormal3D = (lnNone, lnFace, lnVertex, lnFaceVertexMix);36 TLightingInterpolation3D = (liLowQuality, liSpecularHighQuality, liAlwaysHighQuality);37 TAntialiasingMode3D = (am3dNone, am3dMultishape, am3dResample);38 TPerspectiveMode3D = (pmLinearMapping, pmPerspectiveMapping, pmZBuffer);39 40 type41 TRenderingOptions = record42 LightingInterpolation: TLightingInterpolation3D;43 AntialiasingMode: TAntialiasingMode3D;44 AntialiasingResampleLevel: integer;45 PerspectiveMode: TPerspectiveMode3D;46 TextureInterpolation: boolean;47 MinZ: single;48 44 end; 49 45 … … 81 77 function GetLightCount: integer; 82 78 function GetMaterial(AIndex: integer): IBGRAMaterial3D; 79 function GetNormalCount: integer; 83 80 function GetObject(AIndex: integer): IBGRAObject3D; 84 81 function GetVertexCount: integer; … … 111 108 function ApplyNoLighting(Context: PSceneLightingContext; Color: TBGRAPixel): TBGRAPixel; virtual; 112 109 procedure UseMaterial(AMaterialName: string; AFace: IBGRAFace3D); virtual; 110 function FetchTexture({%H-}AName: string; out texSize: TPointF): IBGRAScanner; virtual; 113 111 114 112 public … … 116 114 DefaultMaterial : IBGRAMaterial3D; 117 115 RenderingOptions: TRenderingOptions; 116 UnknownColor: TBGRAPixel; 118 117 119 118 constructor Create; 120 119 constructor Create(ASurface: TBGRACustomBitmap); 121 120 destructor Destroy; override; 122 procedure Clear; 121 procedure Clear; virtual; 123 122 function LoadObjectFromFile(AFilename: string; SwapFacesOrientation: boolean = true): IBGRAObject3D; 123 function LoadObjectFromFileUTF8(AFilename: string; SwapFacesOrientation: boolean = true): IBGRAObject3D; 124 function LoadObjectFromStream(AStream: TStream; SwapFacesOrientation: boolean = true): IBGRAObject3D; 125 procedure LoadMaterialsFromFile(AFilename: string); 126 procedure LoadMaterialsFromFileUTF8(AFilename: string); 127 procedure LoadMaterialsFromStream(AStream: TStream); 124 128 procedure LookAt(AWhere: TPoint3D; ATopDir: TPoint3D); 125 129 procedure LookLeft(angleDeg: single); … … 145 149 function CreateMaterial: IBGRAMaterial3D; 146 150 function CreateMaterial(ASpecularIndex: integer): IBGRAMaterial3D; 151 function GetMaterialByName(AName: string): IBGRAMaterial3D; 147 152 procedure UpdateMaterials; virtual; 148 153 procedure UpdateMaterial(AMaterialName: string); virtual; 154 procedure ForEachVertex(ACallback: TVertex3DCallback); 155 procedure ForEachFace(ACallback: TFace3DCallback); 149 156 property ViewCenter: TPointF read GetViewCenter write SetViewCenter; 150 157 property AutoViewCenter: boolean read FAutoViewCenter write SetAutoViewCenter; … … 154 161 property Object3DCount: integer read FObjectCount; 155 162 property VertexCount: integer read GetVertexCount; 163 property NormalCount: integer read GetNormalCount; 156 164 property FaceCount: integer read GetFaceCount; 157 165 property Zoom: TPointF read GetZoom write SetZoom; … … 169 177 implementation 170 178 171 uses BGRAPolygon, BGRAPolygonAliased, BGRACoordPool3D; 179 uses BGRAPolygon, BGRAPolygonAliased, BGRACoordPool3D, BGRAResample, 180 lazutf8classes; 172 181 173 182 {$i lightingclasses3d.inc} 183 {$i vertex3d.inc} 184 {$i face3d.inc} 174 185 175 186 type … … 200 211 function AddFace(const AVertices: array of IBGRAVertex3D; AColors: array of TBGRAPixel): IBGRAFace3D; 201 212 function AddFaceReversed(const AVertices: array of IBGRAVertex3D): IBGRAFace3D; 202 procedure ComputeWithMatrix(const AMatrix: TMatrix3D; constAProjection: TProjection3D);213 procedure ComputeWithMatrix(constref AMatrix: TMatrix3D; constref AProjection: TProjection3D); 203 214 function GetColor: TBGRAPixel; 204 215 function GetLight: Single; … … 210 221 function GetFaceCount: integer; 211 222 function GetTotalVertexCount: integer; 223 function GetTotalNormalCount: integer; 212 224 function GetMaterial: IBGRAMaterial3D; 213 225 procedure SetLightingNormal(const AValue: TLightingNormal3D); … … 222 234 function GetRefCount: integer; 223 235 procedure SetBiface(AValue : boolean); 224 end; 225 226 {$i shape3D.inc} 227 228 type 229 { TBGRAPart3D } 230 231 TBGRAPart3D = class(TInterfacedObject,IBGRAPart3D) 232 private 233 FVertices: array of IBGRAVertex3D; 234 FVertexCount: integer; 235 FMatrix: TMatrix3D; 236 FParts: array of IBGRAPart3D; 237 FPartCount: integer; 238 FContainer: IBGRAPart3D; 239 FCoordPool: TBGRACoordPool3D; 240 public 241 constructor Create(AContainer: IBGRAPart3D); 242 destructor Destroy; override; 243 procedure Clear(ARecursive: boolean); 244 function Add(x,y,z: single): IBGRAVertex3D; 245 function Add(pt: TPoint3D): IBGRAVertex3D; 246 function Add(pt: TPoint3D_128): IBGRAVertex3D; 247 function Add(const coords: array of single): arrayOfIBGRAVertex3D; 248 function Add(const pts: array of TPoint3D): arrayOfIBGRAVertex3D; 249 function Add(const pts: array of TPoint3D_128): arrayOfIBGRAVertex3D; 250 procedure Add(const pts: array of IBGRAVertex3D); 251 procedure Add(AVertex: IBGRAVertex3D); 252 procedure RemoveVertex(Index: integer); 253 function GetBoundingBox: TBox3D; 254 function GetRadius: single; 255 function GetMatrix: TMatrix3D; 256 function GetPart(AIndex: Integer): IBGRAPart3D; 257 function GetPartCount: integer; 258 function GetVertex(AIndex: Integer): IBGRAVertex3D; 259 function GetVertexCount: integer; 260 function GetTotalVertexCount: integer; 261 function GetContainer: IBGRAPart3D; 262 procedure SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 263 procedure ResetTransform; 264 procedure Translate(x,y,z: single; Before: boolean = true); 265 procedure Translate(ofs: TPoint3D; Before: boolean = true); 266 procedure Scale(size: single; Before: boolean = true); 267 procedure Scale(x,y,z: single; Before: boolean = true); 268 procedure Scale(size: TPoint3D; Before: boolean = true); 269 procedure RotateXDeg(angle: single; Before: boolean = true); 270 procedure RotateYDeg(angle: single; Before: boolean = true); 271 procedure RotateZDeg(angle: single; Before: boolean = true); 272 procedure RotateXRad(angle: single; Before: boolean = true); 273 procedure RotateYRad(angle: single; Before: boolean = true); 274 procedure RotateZRad(angle: single; Before: boolean = true); 275 procedure SetMatrix(const AValue: TMatrix3D); 276 procedure ComputeWithMatrix(const AMatrix: TMatrix3D; const AProjection: TProjection3D); 277 function ComputeCoordinate(var ASceneCoord: TPoint3D_128; const AProjection: TProjection3D): TPointF; 278 procedure NormalizeViewNormal; 279 function CreatePart: IBGRAPart3D; 280 procedure LookAt(ALookWhere,ATopDir: TPoint3D); 281 procedure RemoveUnusedVertices; 282 function IndexOf(AVertex: IBGRAVertex3D): integer; 283 end; 284 285 { TBGRAFace3D } 286 287 PBGRAFaceVertexDescription = ^TBGRAFaceVertexDescription; 288 TBGRAFaceVertexDescription = record 289 Vertex: IBGRAVertex3D; 290 Color: TBGRAPixel; 291 TexCoord: TPointF; 292 ColorOverride: boolean; 293 TexCoordOverride: boolean; 294 end; 295 296 TBGRAFace3D = class(TInterfacedObject,IBGRAFace3D) 297 private 298 FVertices: packed array of TBGRAFaceVertexDescription; 299 FVertexCount: integer; 300 FTexture: IBGRAScanner; 301 FMaterial: IBGRAMaterial3D; 302 FMaterialName: string; 303 FParentTexture: boolean; 304 FViewNormal: TPoint3D_128; 305 FViewCenter: TPoint3D_128; 306 FObject3D : IBGRAObject3D; 307 FBiface: boolean; 308 FLightThroughFactor: single; 309 FLightThroughFactorOverride: boolean; 310 function GetVertexDescription(AIndex : integer): PBGRAFaceVertexDescription; 311 public 312 function GetObject3D: IBGRAObject3D; 313 constructor Create(AObject3D: IBGRAObject3D; AVertices: array of IBGRAVertex3D); 314 destructor Destroy; override; 315 procedure AddVertex(AVertex: IBGRAVertex3D); 316 function GetParentTexture: boolean; 317 function GetTexture: IBGRAScanner; 318 function GetVertex(AIndex: Integer): IBGRAVertex3D; 319 function GetVertexColor(AIndex: Integer): TBGRAPixel; 320 function GetVertexColorOverride(AIndex: Integer): boolean; 321 function GetVertexCount: integer; 322 function GetMaterial: IBGRAMaterial3D; 323 function GetMaterialName: string; 324 function GetTexCoord(AIndex: Integer): TPointF; 325 function GetTexCoordOverride(AIndex: Integer): boolean; 326 function GetViewNormal: TPoint3D; 327 function GetViewNormal_128: TPoint3D_128; 328 function GetViewCenter: TPoint3D; 329 function GetViewCenter_128: TPoint3D_128; 330 function GetViewCenterZ: single; 331 function GetBiface: boolean; 332 function GetLightThroughFactor: single; 333 function GetLightThroughFactorOverride: boolean; 334 procedure SetParentTexture(const AValue: boolean); 335 procedure SetTexture(const AValue: IBGRAScanner); 336 procedure SetColor(AColor: TBGRAPixel); 337 procedure SetVertexColor(AIndex: Integer; const AValue: TBGRAPixel); 338 procedure SetVertexColorOverride(AIndex: Integer; const AValue: boolean); 339 procedure SetTexCoord(AIndex: Integer; const AValue: TPointF); 340 procedure SetTexCoordOverride(AIndex: Integer; const AValue: boolean); 341 procedure SetBiface(const AValue: boolean); 342 procedure SetLightThroughFactor(const AValue: single); 343 procedure SetLightThroughFactorOverride(const AValue: boolean); 344 procedure SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 345 procedure ComputeViewNormalAndCenter; 346 procedure SetMaterial(const AValue: IBGRAMaterial3D); 347 procedure SetMaterialName(const AValue: string); 348 function GetAsObject: TObject; 349 property Texture: IBGRAScanner read GetTexture write SetTexture; 350 property ParentTexture: boolean read GetParentTexture write SetParentTexture; 351 property VertexCount: integer read GetVertexCount; 352 property Vertex[AIndex: Integer]: IBGRAVertex3D read GetVertex write SetVertex; 353 property VertexColor[AIndex: Integer]: TBGRAPixel read GetVertexColor write SetVertexColor; 354 property VertexColorOverride[AIndex: Integer]: boolean read GetVertexColorOverride write SetVertexColorOverride; 355 property TexCoord[AIndex: Integer]: TPointF read GetTexCoord write SetTexCoord; 356 property TexCoordOverride[AIndex: Integer]: boolean read GetTexCoordOverride write SetTexCoordOverride; 357 property ViewNormal: TPoint3D read GetViewNormal; 358 property ViewNormal_128: TPoint3D_128 read GetViewNormal_128; 359 property ViewCenter: TPoint3D read GetViewCenter; 360 property ViewCenter_128: TPoint3D_128 read GetViewCenter_128; 361 property ViewCenterZ: single read GetViewCenterZ; 362 property Object3D: IBGRAObject3D read GetObject3D; 363 property Biface: boolean read GetBiface write SetBiface; 364 property LightThroughFactor: single read GetLightThroughFactor write SetLightThroughFactor; 365 property LightThroughFactorOverride: boolean read GetLightThroughFactorOverride write SetLightThroughFactorOverride; 366 property Material: IBGRAMaterial3D read GetMaterial write SetMaterial; 367 property VertexDescription[AIndex : integer]: PBGRAFaceVertexDescription read GetVertexDescription; 368 end; 369 370 { TBGRAVertex3D } 371 372 TBGRAVertex3D = class(TInterfacedObject,IBGRAVertex3D) 373 private 374 FColor: TBGRAPixel; 375 FParentColor: boolean; 376 FLight: Single; 377 FTexCoord: TPointF; 378 FCoordPool: TBGRACoordPool3D; 379 FCoordPoolIndex: integer; 380 function GetCoordData: PBGRACoordData3D; 381 procedure Init(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D_128); 382 public 383 constructor Create(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D); overload; 384 constructor Create(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D_128); overload; 385 destructor Destroy; override; 386 function GetColor: TBGRAPixel; 387 function GetLight: Single; 388 function GetViewNormal: TPoint3D; 389 function GetViewNormal_128: TPoint3D_128; 390 function GetSceneCoord: TPoint3D; 391 function GetSceneCoord_128: TPoint3D_128; 392 function GetTexCoord: TPointF; 393 function GetViewCoord: TPoint3D; 394 function GetViewCoord_128: TPoint3D_128; 395 function GetUsage: integer; 396 procedure SetColor(const AValue: TBGRAPixel); 397 procedure SetLight(const AValue: Single); 398 procedure SetViewNormal(const AValue: TPoint3D); 399 procedure SetViewNormal_128(const AValue: TPoint3D_128); 400 procedure NormalizeViewNormal; 401 procedure AddViewNormal(const AValue: TPoint3D_128); 402 procedure SetSceneCoord(const AValue: TPoint3D); 403 procedure SetSceneCoord_128(const AValue: TPoint3D_128); 404 procedure SetTexCoord(const AValue: TPointF); 405 procedure SetViewCoord(const AValue: TPoint3D); 406 procedure SetViewCoord_128(const AValue: TPoint3D_128); 407 function GetViewCoordZ: single; 408 function GetParentColor: Boolean; 409 procedure SetParentColor(const AValue: Boolean); 410 function GetProjectedCoord: TPointF; 411 procedure SetProjectedCoord(const AValue: TPointF); 412 procedure ComputeCoordinateAndClearNormal(const AMatrix: TMatrix3D; const AProjection: TProjection3D); 413 property SceneCoord: TPoint3D read GetSceneCoord write SetSceneCoord; 414 property SceneCoord_128: TPoint3D_128 read GetSceneCoord_128 write SetSceneCoord_128; 415 property ViewCoord: TPoint3D read GetViewCoord write SetViewCoord; 416 property ViewCoord_128: TPoint3D_128 read GetViewCoord_128 write SetViewCoord_128; 417 property ViewCoordZ: single read GetViewCoordZ; 418 property ProjectedCoord: TPointF read GetProjectedCoord write SetProjectedCoord; 419 property TexCoord: TPointF read GetTexCoord write SetTexCoord; 420 property Color: TBGRAPixel read GetColor write SetColor; 421 property ParentColor: Boolean read GetParentColor write SetParentColor; 422 property Light: Single read GetLight write SetLight; 423 property ViewNormal: TPoint3D read GetViewNormal write SetViewNormal; 424 property ViewNormal_128: TPoint3D_128 read GetViewNormal_128 write SetViewNormal_128; 425 property Usage: integer read GetUsage; 426 property CoordData: PBGRACoordData3D read GetCoordData; 427 function GetAsObject: TObject; 428 end; 429 430 { TBGRAVertex3D } 431 432 procedure TBGRAVertex3D.Init(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D_128); 433 begin 434 FCoordPool := ACoordPool; 435 FCoordPoolIndex := FCoordPool.Add; 436 FColor := BGRAWhite; 437 FParentColor := True; 438 FLight := 1; 439 SceneCoord_128 := ASceneCoord; 440 end; 441 442 function TBGRAVertex3D.GetCoordData: PBGRACoordData3D; 443 begin 444 result := FCoordPool.CoordData[FCoordPoolIndex]; 445 end; 446 447 constructor TBGRAVertex3D.Create(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D); 448 begin 449 Init(ACoordPool, Point3D_128(ASceneCoord)); 450 end; 451 452 constructor TBGRAVertex3D.Create(ACoordPool: TBGRACoordPool3D; ASceneCoord: TPoint3D_128); 453 begin 454 Init(ACoordPool, ASceneCoord); 455 end; 456 457 destructor TBGRAVertex3D.Destroy; 458 begin 459 FCoordPool.Remove(FCoordPoolIndex); 460 inherited Destroy; 461 end; 462 463 function TBGRAVertex3D.GetColor: TBGRAPixel; 464 begin 465 result := FColor; 466 end; 467 468 function TBGRAVertex3D.GetLight: Single; 469 begin 470 result := FLight; 471 end; 472 473 function TBGRAVertex3D.GetViewNormal: TPoint3D; 474 begin 475 result := Point3D(FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal); 476 end; 477 478 function TBGRAVertex3D.GetViewNormal_128: TPoint3D_128; 479 begin 480 result := FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal; 481 end; 482 483 function TBGRAVertex3D.GetSceneCoord: TPoint3D; 484 begin 485 result := Point3D(FCoordPool.CoordData[FCoordPoolIndex]^.sceneCoord); 486 end; 487 488 function TBGRAVertex3D.GetSceneCoord_128: TPoint3D_128; 489 begin 490 result := FCoordPool.CoordData[FCoordPoolIndex]^.sceneCoord; 491 end; 492 493 function TBGRAVertex3D.GetTexCoord: TPointF; 494 begin 495 result := FTexCoord; 496 end; 497 498 function TBGRAVertex3D.GetViewCoord: TPoint3D; 499 begin 500 result := Point3D(FCoordPool.CoordData[FCoordPoolIndex]^.viewCoord); 501 end; 502 503 function TBGRAVertex3D.GetViewCoord_128: TPoint3D_128; 504 begin 505 result := FCoordPool.CoordData[FCoordPoolIndex]^.viewCoord; 506 end; 507 508 function TBGRAVertex3D.GetUsage: integer; 509 begin 510 result := frefcount; 511 end; 512 513 procedure TBGRAVertex3D.SetColor(const AValue: TBGRAPixel); 514 begin 515 FColor := AValue; 516 FParentColor := false; 517 end; 518 519 procedure TBGRAVertex3D.SetLight(const AValue: Single); 520 begin 521 FLight := AValue; 522 end; 523 524 procedure TBGRAVertex3D.SetViewNormal(const AValue: TPoint3D); 525 begin 526 FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal := Point3D_128(AValue); 527 end; 528 529 procedure TBGRAVertex3D.SetViewNormal_128(const AValue: TPoint3D_128); 530 begin 531 FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal := AValue; 532 end; 533 534 procedure TBGRAVertex3D.SetSceneCoord(const AValue: TPoint3D); 535 begin 536 FCoordPool.CoordData[FCoordPoolIndex]^.sceneCoord := Point3D_128(AValue); 537 end; 538 539 procedure TBGRAVertex3D.SetSceneCoord_128(const AValue: TPoint3D_128); 540 begin 541 FCoordPool.CoordData[FCoordPoolIndex]^.sceneCoord := AValue; 542 end; 543 544 procedure TBGRAVertex3D.SetTexCoord(const AValue: TPointF); 545 begin 546 FTexCoord := AValue; 547 end; 548 549 procedure TBGRAVertex3D.SetViewCoord(const AValue: TPoint3D); 550 begin 551 FCoordPool.CoordData[FCoordPoolIndex]^.viewCoord := Point3D_128(AValue); 552 end; 553 554 procedure TBGRAVertex3D.SetViewCoord_128(const AValue: TPoint3D_128); 555 begin 556 FCoordPool.CoordData[FCoordPoolIndex]^.viewCoord := AValue; 557 end; 558 559 function TBGRAVertex3D.GetViewCoordZ: single; 560 begin 561 result := FCoordPool.CoordData[FCoordPoolIndex]^.viewCoord.Z; 562 end; 563 564 function TBGRAVertex3D.GetParentColor: Boolean; 565 begin 566 result := FParentColor; 567 end; 568 569 procedure TBGRAVertex3D.SetParentColor(const AValue: Boolean); 570 begin 571 FParentColor := AValue; 572 end; 573 574 function TBGRAVertex3D.GetProjectedCoord: TPointF; 575 begin 576 result := FCoordPool.CoordData[FCoordPoolIndex]^.projectedCoord; 577 end; 578 579 procedure TBGRAVertex3D.SetProjectedCoord(const AValue: TPointF); 580 begin 581 FCoordPool.CoordData[FCoordPoolIndex]^.projectedCoord := AValue; 582 end; 583 584 procedure TBGRAVertex3D.ComputeCoordinateAndClearNormal(const AMatrix: TMatrix3D; const AProjection : TProjection3D); 585 var P: PBGRACoordData3D; 586 begin 587 P := FCoordPool.CoordData[FCoordPoolIndex]; 588 with p^ do 589 begin 590 viewCoord := AMatrix*sceneCoord; 591 ClearPoint3D_128(viewNormal); 592 if viewCoord.z > 0 then 593 begin 594 InvZ := 1/viewCoord.z; 595 projectedCoord := PointF(viewCoord.x*InvZ*AProjection.Zoom.x + AProjection.Center.x, 596 viewCoord.y*InvZ*AProjection.Zoom.Y + AProjection.Center.y); 597 end else 598 projectedCoord := PointF(0,0); 599 end; 600 end; 601 602 function TBGRAVertex3D.GetAsObject: TObject; 603 begin 604 result := self; 605 end; 606 607 procedure TBGRAVertex3D.NormalizeViewNormal; 608 begin 609 Normalize3D_128(FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal); 610 end; 611 612 procedure TBGRAVertex3D.AddViewNormal(const AValue: TPoint3D_128); 613 begin 614 Add3D_Aligned(FCoordPool.CoordData[FCoordPoolIndex]^.viewNormal, AValue); 615 end; 616 617 { TBGRAFace3D } 618 619 function TBGRAFace3D.GetVertexDescription(AIndex : integer 620 ): PBGRAFaceVertexDescription; 621 begin 622 result := @FVertices[AIndex]; 623 end; 624 625 function TBGRAFace3D.GetObject3D: IBGRAObject3D; 626 begin 627 result := FObject3D; 628 end; 629 630 constructor TBGRAFace3D.Create(AObject3D: IBGRAObject3D; 631 AVertices: array of IBGRAVertex3D); 632 var 633 i: Integer; 634 begin 635 SetLength(FVertices, length(AVertices)); 636 for i:= 0 to high(AVertices) do 637 AddVertex(AVertices[i]); 638 FObject3D := AObject3D; 639 FBiface := false; 640 FParentTexture := True; 641 FLightThroughFactor:= 0; 642 FLightThroughFactorOverride:= false; 643 end; 644 645 destructor TBGRAFace3D.Destroy; 646 begin 647 fillchar(FTexture,sizeof(FTexture),0); 648 inherited Destroy; 649 end; 650 651 procedure TBGRAFace3D.AddVertex(AVertex: IBGRAVertex3D); 652 begin 653 if FVertexCount = length(FVertices) then 654 setlength(FVertices, FVertexCount*2+3); 655 with FVertices[FVertexCount] do 656 begin 657 Color := BGRAWhite; 658 ColorOverride := false; 659 TexCoord := PointF(0,0); 660 TexCoordOverride := false; 661 Vertex := AVertex; 662 end; 663 inc(FVertexCount); 664 end; 665 666 function TBGRAFace3D.GetParentTexture: boolean; 667 begin 668 result := FParentTexture; 669 end; 670 671 function TBGRAFace3D.GetTexture: IBGRAScanner; 672 begin 673 result := FTexture; 674 end; 675 676 function TBGRAFace3D.GetVertex(AIndex: Integer): IBGRAVertex3D; 677 begin 678 if (AIndex < 0) or (AIndex >= FVertexCount) then 679 raise Exception.Create('Index out of bounds'); 680 result := FVertices[AIndex].Vertex; 681 end; 682 683 procedure TBGRAFace3D.SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 684 begin 685 if (AIndex < 0) or (AIndex >= FVertexCount) then 686 raise Exception.Create('Index out of bounds'); 687 FVertices[AIndex].Vertex := AValue; 688 end; 689 690 function TBGRAFace3D.GetVertexColor(AIndex: Integer): TBGRAPixel; 691 begin 692 if (AIndex < 0) or (AIndex >= FVertexCount) then 693 raise Exception.Create('Index out of bounds'); 694 result := FVertices[AIndex].Color; 695 end; 696 697 function TBGRAFace3D.GetVertexColorOverride(AIndex: Integer): boolean; 698 begin 699 if (AIndex < 0) or (AIndex >= FVertexCount) then 700 raise Exception.Create('Index out of bounds'); 701 result := FVertices[AIndex].ColorOverride; 702 end; 703 704 function TBGRAFace3D.GetVertexCount: integer; 705 begin 706 result := FVertexCount; 707 end; 708 709 function TBGRAFace3D.GetMaterial: IBGRAMaterial3D; 710 begin 711 result := FMaterial; 712 end; 713 714 function TBGRAFace3D.GetMaterialName: string; 715 begin 716 result := FMaterialName; 717 end; 718 719 procedure TBGRAFace3D.SetParentTexture(const AValue: boolean); 720 begin 721 FParentTexture := AValue; 722 end; 723 724 procedure TBGRAFace3D.SetTexture(const AValue: IBGRAScanner); 725 begin 726 FTexture := AValue; 727 FParentTexture := false; 728 end; 729 730 procedure TBGRAFace3D.SetColor(AColor: TBGRAPixel); 731 var i: integer; 732 begin 733 for i := 0 to GetVertexCount-1 do 734 SetVertexColor(i,AColor); 735 end; 736 737 procedure TBGRAFace3D.SetVertexColor(AIndex: Integer; const AValue: TBGRAPixel 738 ); 739 begin 740 if (AIndex < 0) or (AIndex >= FVertexCount) then 741 raise Exception.Create('Index out of bounds'); 742 with FVertices[AIndex] do 743 begin 744 Color := AValue; 745 ColorOverride := true; 746 end; 747 end; 748 749 procedure TBGRAFace3D.SetVertexColorOverride(AIndex: Integer; 750 const AValue: boolean); 751 begin 752 if (AIndex < 0) or (AIndex >= FVertexCount) then 753 raise Exception.Create('Index out of bounds'); 754 FVertices[AIndex].ColorOverride := AValue; 755 end; 756 757 function TBGRAFace3D.GetTexCoord(AIndex: Integer): TPointF; 758 begin 759 if (AIndex < 0) or (AIndex >= FVertexCount) then 760 raise Exception.Create('Index out of bounds'); 761 result := FVertices[AIndex].TexCoord; 762 end; 763 764 function TBGRAFace3D.GetTexCoordOverride(AIndex: Integer): boolean; 765 begin 766 if (AIndex < 0) or (AIndex >= FVertexCount) then 767 raise Exception.Create('Index out of bounds'); 768 result := FVertices[AIndex].TexCoordOverride; 769 end; 770 771 procedure TBGRAFace3D.SetTexCoord(AIndex: Integer; const AValue: TPointF); 772 begin 773 if (AIndex < 0) or (AIndex >= FVertexCount) then 774 raise Exception.Create('Index out of bounds'); 775 FVertices[AIndex].TexCoord := AValue; 776 FVertices[AIndex].TexCoordOverride := true; 777 end; 778 779 procedure TBGRAFace3D.SetTexCoordOverride(AIndex: Integer; const AValue: boolean 780 ); 781 begin 782 if (AIndex < 0) or (AIndex >= FVertexCount) then 783 raise Exception.Create('Index out of bounds'); 784 FVertices[AIndex].TexCoordOverride := AValue; 785 end; 786 787 function TBGRAFace3D.GetViewNormal: TPoint3D; 788 begin 789 result := Point3D(FViewNormal); 790 end; 791 792 function TBGRAFace3D.GetViewNormal_128: TPoint3D_128; 793 begin 794 result := FViewNormal; 795 end; 796 797 function TBGRAFace3D.GetViewCenter: TPoint3D; 798 begin 799 result := Point3D(FViewCenter); 800 end; 801 802 function TBGRAFace3D.GetViewCenter_128: TPoint3D_128; 803 begin 804 result := FViewCenter; 805 end; 806 807 function TBGRAFace3D.GetViewCenterZ: single; 808 begin 809 result := FViewCenter.Z; 810 end; 811 812 function TBGRAFace3D.GetBiface: boolean; 813 begin 814 result := FBiface; 815 end; 816 817 procedure TBGRAFace3D.SetBiface(const AValue: boolean); 818 begin 819 FBiface := AValue; 820 end; 821 822 function TBGRAFace3D.GetLightThroughFactor: single; 823 begin 824 result := FLightThroughFactor; 825 end; 826 827 function TBGRAFace3D.GetLightThroughFactorOverride: boolean; 828 begin 829 result := FLightThroughFactorOverride; 830 end; 831 832 procedure TBGRAFace3D.SetLightThroughFactor(const AValue: single); 833 begin 834 if AValue < 0 then 835 FLightThroughFactor := 0 836 else 837 FLightThroughFactor:= AValue; 838 FLightThroughFactorOverride := true; 839 end; 840 841 procedure TBGRAFace3D.SetLightThroughFactorOverride(const AValue: boolean); 842 begin 843 FLightThroughFactorOverride := AValue; 844 end; 845 846 procedure TBGRAFace3D.ComputeViewNormalAndCenter; 847 var v1,v2: TPoint3D_128; 848 i: Integer; 849 p0,p1,p2: IBGRAVertex3D; 850 begin 851 if FVertexCount < 3 then 852 ClearPoint3D_128(FViewNormal) 853 else 854 begin 855 p0 := FVertices[0].Vertex; 856 p1 := FVertices[1].Vertex; 857 p2 := FVertices[2].Vertex; 858 v1 := p1.ViewCoord_128 - p0.ViewCoord_128; 859 v2 := p2.ViewCoord_128 - p1.ViewCoord_128; 860 VectProduct3D_128(v2,v1,FViewNormal); 861 Normalize3D_128(FViewNormal); 862 for i := 0 to FVertexCount-1 do 863 FVertices[i].Vertex.AddViewNormal(FViewNormal); 864 end; 865 ClearPoint3D_128(FViewCenter); 866 if FVertexCount > 0 then 867 begin 868 for i := 0 to FVertexCount-1 do 869 FViewCenter += FVertices[i].Vertex.ViewCoord_128; 870 FViewCenter *= 1/FVertexCount; 871 end; 872 end; 873 874 procedure TBGRAFace3D.SetMaterial(const AValue: IBGRAMaterial3D); 875 begin 876 FMaterial := AValue; 877 end; 878 879 procedure TBGRAFace3D.SetMaterialName(const AValue: string); 880 begin 881 if AValue <> FMaterialName then 882 begin 883 FMaterialName := AValue; 884 FObject3D.Scene.UseMaterial(FMaterialName, self); 885 end; 886 end; 887 888 function TBGRAFace3D.GetAsObject: TObject; 889 begin 890 result := self; 891 end; 892 893 { TBGRAPart3D } 894 895 procedure TBGRAPart3D.LookAt(ALookWhere,ATopDir: TPoint3D); 896 var ZDir, XDir, YDir: TPoint3D_128; 897 ViewPoint: TPoint3D_128; 898 CurPart: IBGRAPart3D; 899 ComposedMatrix: TMatrix3D; 900 begin 901 YDir := -Point3D_128(ATopDir); 902 if IsPoint3D_128_Zero(YDir) then exit; 903 Normalize3D_128(YDir); 904 905 ComposedMatrix := FMatrix; 906 CurPart := self.FContainer; 907 while CurPart <> nil do 908 begin 909 ComposedMatrix := CurPart.Matrix*ComposedMatrix; 910 CurPart := CurPart.Container; 911 end; 912 ViewPoint := ComposedMatrix*Point3D_128_Zero; 913 914 ZDir := Point3D_128(ALookWhere)-ViewPoint; 915 if IsPoint3D_128_Zero(ZDir) then exit; 916 Normalize3D_128(ZDir); 917 918 VectProduct3D_128(YDir,ZDir,XDir); 919 VectProduct3D_128(ZDir,XDir,YDir); //correct Y dir 920 921 FMatrix := Matrix3D(XDir,YDir,ZDir,ViewPoint); 922 ComposedMatrix := MatrixIdentity3D; 923 CurPart := self.FContainer; 924 while CurPart <> nil do 925 begin 926 ComposedMatrix := CurPart.Matrix*ComposedMatrix; 927 CurPart := CurPart.Container; 928 end; 929 FMatrix := MatrixInverse3D(ComposedMatrix)*FMatrix; 930 end; 931 932 procedure TBGRAPart3D.RemoveUnusedVertices; 933 var 934 i: Integer; 935 begin 936 for i := FVertexCount-1 downto 0 do 937 if FVertices[i].Usage <= 2 then RemoveVertex(i); 938 for i := 0 to FPartCount-1 do 939 FParts[i].RemoveUnusedVertices; 940 end; 941 942 function TBGRAPart3D.IndexOf(AVertex: IBGRAVertex3D): integer; 943 var i: integer; 944 begin 945 for i := 0 to FVertexCount-1 do 946 if FVertices[i] = AVertex then 947 begin 948 result := i; 949 exit; 950 end; 951 result := -1; 952 end; 953 954 procedure TBGRAPart3D.Add(AVertex: IBGRAVertex3D); 955 begin 956 if FVertexCount = length(FVertices) then 957 setlength(FVertices, FVertexCount*2+3); 958 FVertices[FVertexCount] := AVertex; 959 inc(FVertexCount); 960 end; 961 962 procedure TBGRAPart3D.RemoveVertex(Index: integer); 963 var i: integer; 964 begin 965 if (Index >= 0) and (Index < FVertexCount) then 966 begin 967 for i := Index to FVertexCount-2 do 968 FVertices[i] := FVertices[i+1]; 969 FVertices[FVertexCount-1] := nil; 970 dec(FVertexCount); 971 end; 972 end; 973 974 function TBGRAPart3D.GetRadius: single; 975 var i: integer; 976 pt: TPoint3D_128; 977 d: single; 978 begin 979 result := 0; 980 for i := 0 to GetVertexCount-1 do 981 begin 982 pt := GetVertex(i).SceneCoord_128; 983 d:= sqrt(DotProduct3D_128(pt,pt)); 984 if d > result then result := d; 985 end; 986 end; 987 988 constructor TBGRAPart3D.Create(AContainer: IBGRAPart3D); 989 begin 990 FContainer := AContainer; 991 FMatrix := MatrixIdentity3D; 992 FCoordPool := TBGRACoordPool3D.Create(4); 993 end; 994 995 destructor TBGRAPart3D.Destroy; 996 begin 997 FCoordPool.Free; 998 inherited Destroy; 999 end; 1000 1001 procedure TBGRAPart3D.Clear(ARecursive: boolean); 1002 var i: integer; 1003 begin 1004 FVertices := nil; 1005 FVertexCount := 0; 1006 if ARecursive then 1007 begin 1008 for i := 0 to FPartCount-1 do 1009 FParts[i].Clear(ARecursive); 1010 FParts := nil; 1011 FPartCount := 0; 1012 end; 1013 end; 1014 1015 function TBGRAPart3D.Add(x, y, z: single): IBGRAVertex3D; 1016 begin 1017 result := TBGRAVertex3D.Create(FCoordPool,Point3D(x,y,z)); 1018 Add(result); 1019 end; 1020 1021 function TBGRAPart3D.Add(pt: TPoint3D): IBGRAVertex3D; 1022 begin 1023 result := TBGRAVertex3D.Create(FCoordPool,pt); 1024 Add(result); 1025 end; 1026 1027 function TBGRAPart3D.Add(pt: TPoint3D_128): IBGRAVertex3D; 1028 begin 1029 result := TBGRAVertex3D.Create(FCoordPool,pt); 1030 Add(result); 1031 end; 1032 1033 function TBGRAPart3D.Add(const coords: array of single 1034 ): arrayOfIBGRAVertex3D; 1035 var pts: array of TPoint3D; 1036 CoordsIdx: integer; 1037 i: Integer; 1038 begin 1039 if length(coords) mod 3 <> 0 then 1040 raise exception.Create('Array size must be a multiple of 3'); 1041 setlength(pts, length(coords) div 3); 1042 coordsIdx := 0; 1043 for i := 0 to high(pts) do 1044 begin 1045 pts[i] := Point3D(coords[CoordsIdx],coords[CoordsIdx+1],coords[CoordsIdx+2]); 1046 inc(coordsIdx,3); 1047 end; 1048 result := Add(pts); 1049 end; 1050 1051 function TBGRAPart3D.Add(const pts: array of TPoint3D): arrayOfIBGRAVertex3D; 1052 var 1053 i: Integer; 1054 begin 1055 setlength(result, length(pts)); 1056 for i := 0 to high(pts) do 1057 result[i] := TBGRAVertex3D.Create(FCoordPool,pts[i]); 1058 Add(result); 1059 end; 1060 1061 function TBGRAPart3D.Add(const pts: array of TPoint3D_128 1062 ): arrayOfIBGRAVertex3D; 1063 var 1064 i: Integer; 1065 begin 1066 setlength(result, length(pts)); 1067 for i := 0 to high(pts) do 1068 result[i] := TBGRAVertex3D.Create(FCoordPool,pts[i]); 1069 Add(result); 1070 end; 1071 1072 procedure TBGRAPart3D.Add(const pts: array of IBGRAVertex3D); 1073 var 1074 i: Integer; 1075 begin 1076 if FVertexCount + length(pts) > length(FVertices) then 1077 setlength(FVertices, (FVertexCount*2 + length(pts))+1); 1078 for i := 0 to high(pts) do 1079 begin 1080 FVertices[FVertexCount] := pts[i]; 1081 inc(FVertexCount); 1082 end; 1083 end; 1084 1085 function TBGRAPart3D.GetBoundingBox: TBox3D; 1086 var i: integer; 1087 pt: TPoint3D_128; 1088 begin 1089 if GetVertexCount > 0 then 1090 begin 1091 result.min := GetVertex(0).SceneCoord; 1092 result.max := result.min; 1093 end else 1094 begin 1095 result.min := Point3D(0,0,0); 1096 result.max := Point3D(0,0,0); 1097 exit; 1098 end; 1099 for i := 1 to GetVertexCount-1 do 1100 begin 1101 pt := GetVertex(i).SceneCoord_128; 1102 if pt.x < result.min.x then result.min.x := pt.x else 1103 if pt.x > result.max.x then result.max.x := pt.x; 1104 if pt.y < result.min.y then result.min.y := pt.y else 1105 if pt.y > result.max.y then result.max.y := pt.y; 1106 if pt.z < result.min.z then result.min.z := pt.z else 1107 if pt.z > result.max.z then result.max.z := pt.z; 1108 end; 1109 end; 1110 1111 function TBGRAPart3D.GetMatrix: TMatrix3D; 1112 begin 1113 result := FMatrix; 1114 end; 1115 1116 function TBGRAPart3D.GetPart(AIndex: Integer): IBGRAPart3D; 1117 begin 1118 if (AIndex < 0) or (AIndex >= FPartCount) then 1119 raise exception.Create('Index of out bounds'); 1120 result := FParts[AIndex]; 1121 end; 1122 1123 function TBGRAPart3D.GetPartCount: integer; 1124 begin 1125 result := FPartCount; 1126 end; 1127 1128 function TBGRAPart3D.GetVertex(AIndex: Integer): IBGRAVertex3D; 1129 begin 1130 if (AIndex < 0) or (AIndex >= FVertexCount) then 1131 raise exception.Create('Index of out bounds'); 1132 result := FVertices[AIndex]; 1133 end; 1134 1135 function TBGRAPart3D.GetVertexCount: integer; 1136 begin 1137 result := FVertexCount; 1138 end; 1139 1140 function TBGRAPart3D.GetTotalVertexCount: integer; 1141 var i: integer; 1142 begin 1143 result := GetVertexCount; 1144 for i := 0 to GetPartCount-1 do 1145 result += GetPart(i).GetTotalVertexCount; 1146 end; 1147 1148 procedure TBGRAPart3D.ResetTransform; 1149 begin 1150 FMatrix := MatrixIdentity3D; 1151 end; 1152 1153 procedure TBGRAPart3D.Scale(size: single; Before: boolean = true); 1154 begin 1155 Scale(size,size,size,Before); 1156 end; 1157 1158 procedure TBGRAPart3D.Scale(x, y, z: single; Before: boolean = true); 1159 begin 1160 Scale(Point3D(x,y,z),Before); 1161 end; 1162 1163 procedure TBGRAPart3D.Scale(size: TPoint3D; Before: boolean = true); 1164 begin 1165 if Before then 1166 FMatrix *= MatrixScale3D(size) 1167 else 1168 FMatrix := MatrixScale3D(size)*FMatrix; 1169 end; 1170 1171 procedure TBGRAPart3D.RotateXDeg(angle: single; Before: boolean = true); 1172 begin 1173 RotateXRad(-angle*Pi/180, Before); 1174 end; 1175 1176 procedure TBGRAPart3D.RotateYDeg(angle: single; Before: boolean = true); 1177 begin 1178 RotateYRad(-angle*Pi/180, Before); 1179 end; 1180 1181 procedure TBGRAPart3D.RotateZDeg(angle: single; Before: boolean = true); 1182 begin 1183 RotateZRad(-angle*Pi/180, Before); 1184 end; 1185 1186 procedure TBGRAPart3D.RotateXRad(angle: single; Before: boolean = true); 1187 begin 1188 if Before then 1189 FMatrix *= MatrixRotateX(angle) 1190 else 1191 FMatrix := MatrixRotateX(angle) * FMatrix; 1192 end; 1193 1194 procedure TBGRAPart3D.RotateYRad(angle: single; Before: boolean = true); 1195 begin 1196 if Before then 1197 FMatrix *= MatrixRotateY(angle) 1198 else 1199 FMatrix := MatrixRotateY(angle) * FMatrix; 1200 end; 1201 1202 procedure TBGRAPart3D.RotateZRad(angle: single; Before: boolean = true); 1203 begin 1204 if Before then 1205 FMatrix *= MatrixRotateZ(angle) 1206 else 1207 FMatrix := MatrixRotateZ(angle) * FMatrix; 1208 end; 1209 1210 procedure TBGRAPart3D.SetMatrix(const AValue: TMatrix3D); 1211 begin 1212 FMatrix := AValue; 1213 end; 1214 1215 procedure TBGRAPart3D.ComputeWithMatrix(const AMatrix: TMatrix3D; const AProjection: TProjection3D); 1216 var 1217 i: Integer; 1218 Composed: TMatrix3D; 1219 P: PBGRACoordData3D; 1220 begin 1221 Composed := AMatrix* self.FMatrix; 1222 {$IFDEF CPUI386} 1223 if UseSSE then 1224 begin 1225 Matrix3D_SSE_Load(Composed); 1226 asm 1227 mov eax,[AProjection] 1228 movups xmm4,[eax] 1229 xorps xmm1,xmm1 1230 end; 1231 P := FCoordPool.CoordData[0]; 1232 i := FCoordPool.UsedCapacity; 1233 if UseSSE3 then 1234 begin 1235 while i > 0 do 1236 with P^ do 1237 begin 1238 MatrixMultiplyVect3D_SSE3_Aligned(sceneCoord,viewCoord); 1239 if viewCoord.z > 0 then 1240 begin 1241 asm 1242 mov eax, P 1243 movaps xmm3, [eax+16] //viewCoord 1244 movaps xmm2,xmm3 1245 shufps xmm2,xmm3,2+8+32+128 1246 rcpps xmm2,xmm2 //xmm2 = InvZ 1247 movss [eax+40],xmm2 //-> InvZ 1248 1249 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom 1250 mulps xmm3,xmm2 //xmm3 *= InvZ 1251 1252 movhlps xmm0,xmm4 //xmm2 = Projection.Center 1253 addps xmm3,xmm0 //xmm3 += Projection.Center 1254 1255 movlps [eax+32],xmm3 //->projectedCoord 1256 movaps [eax+48],xmm1 //->normal 1257 end; 1258 end else 1259 asm 1260 mov eax, P 1261 movlps [eax+32],xmm1 //0 ->projectedCoord 1262 movaps [eax+48],xmm1 //->normal 1263 end; 1264 dec(i); 1265 inc(p); 1266 end; 1267 end else 1268 begin 1269 while i > 0 do 1270 with P^ do 1271 begin 1272 MatrixMultiplyVect3D_SSE_Aligned(sceneCoord,viewCoord); 1273 if viewCoord.z > 0 then 1274 begin 1275 asm 1276 mov eax, P 1277 movaps xmm3, [eax+16] //viewCoord 1278 movaps xmm2,xmm3 1279 shufps xmm2,xmm3,2+8+32+128 1280 rcpps xmm2,xmm2 //xmm2 = InvZ 1281 movss [eax+40],xmm2 //-> InvZ 1282 1283 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom 1284 mulps xmm3,xmm2 //xmm3 *= InvZ 1285 1286 movhlps xmm0,xmm4 //xmm2 = Projection.Center 1287 addps xmm3,xmm0 //xmm3 += Projection.Center 1288 1289 movlps [eax+32],xmm3 //->projectedCoord 1290 movaps [eax+48],xmm1 //->normal 1291 end; 1292 end else 1293 asm 1294 mov eax, P 1295 movlps [eax+32],xmm1 //0 ->projectedCoord 1296 movaps [eax+48],xmm1 //->normal 1297 end; 1298 dec(i); 1299 inc(p); 1300 end; 1301 end; 1302 end 1303 else 1304 {$ENDIF} 1305 begin 1306 P := FCoordPool.CoordData[0]; 1307 i := FCoordPool.UsedCapacity; 1308 while i > 0 do 1309 with P^ do 1310 begin 1311 viewCoord := Composed*sceneCoord; 1312 ClearPoint3D_128(viewNormal); 1313 if viewCoord.z > 0 then 1314 begin 1315 InvZ := 1/viewCoord.z; 1316 projectedCoord := PointF(viewCoord.x*InvZ*AProjection.Zoom.x + AProjection.Center.x, 1317 viewCoord.y*InvZ*AProjection.Zoom.Y + AProjection.Center.y); 1318 end else 1319 projectedCoord := PointF(0,0); 1320 dec(i); 1321 inc(p); 1322 end; 1323 end; 1324 for i := 0 to FPartCount-1 do 1325 FParts[i].ComputeWithMatrix(Composed,AProjection); 1326 end; 1327 1328 function TBGRAPart3D.ComputeCoordinate(var ASceneCoord: TPoint3D_128; const AProjection: TProjection3D): TPointF; 1329 var part: IBGRAPart3D; 1330 newViewCoord: TPoint3D_128; 1331 InvZ: single; 1332 begin 1333 newViewCoord := FMatrix * ASceneCoord; 1334 part := FContainer; 1335 while part <> nil do 1336 begin 1337 newViewCoord := part.Matrix * newViewCoord; 1338 part := part.Container; 1339 end; 1340 if NewViewCoord.z > 0 then 1341 begin 1342 InvZ := 1/NewViewCoord.z; 1343 result := PointF(NewViewCoord.x*InvZ*AProjection.Zoom.x + AProjection.Center.x, 1344 NewViewCoord.y*InvZ*AProjection.Zoom.Y + AProjection.Center.y); 1345 end else 1346 result := PointF(0,0); 1347 end; 1348 1349 procedure TBGRAPart3D.NormalizeViewNormal; 1350 var 1351 i: Integer; 1352 begin 1353 for i := 0 to FVertexCount-1 do 1354 FVertices[i].NormalizeViewNormal; 1355 for i := 0 to FPartCount-1 do 1356 FParts[i].NormalizeViewNormal; 1357 end; 1358 1359 procedure TBGRAPart3D.Translate(x, y, z: single; Before: boolean = true); 1360 begin 1361 Translate(Point3D(x,y,z),Before); 1362 end; 1363 1364 procedure TBGRAPart3D.Translate(ofs: TPoint3D; Before: boolean = true); 1365 begin 1366 if Before then 1367 FMatrix *= MatrixTranslation3D(ofs) 1368 else 1369 FMatrix := MatrixTranslation3D(ofs)*FMatrix; 1370 end; 1371 1372 function TBGRAPart3D.CreatePart: IBGRAPart3D; 1373 begin 1374 if FPartCount = length(FParts) then 1375 setlength(FParts, FPartCount*2+1); 1376 result := TBGRAPart3D.Create(self); 1377 FParts[FPartCount] := result; 1378 inc(FPartCount); 1379 end; 1380 1381 function TBGRAPart3D.GetContainer: IBGRAPart3D; 1382 begin 1383 result := FContainer; 1384 end; 1385 1386 procedure TBGRAPart3D.SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 1387 begin 1388 if (AIndex < 0) or (AIndex >= FVertexCount) then 1389 raise exception.Create('Index of out bounds'); 1390 FVertices[AIndex] := AValue; 1391 end; 1392 1393 { TBGRAObject3D } 1394 1395 procedure TBGRAObject3D.AddFace(AFace: IBGRAFace3D); 1396 begin 1397 if FFaceCount = length(FFaces) then 1398 setlength(FFaces,FFaceCount*2+3); 1399 FFaces[FFaceCount] := AFace; 1400 inc(FFaceCount); 1401 end; 1402 1403 constructor TBGRAObject3D.Create(AScene: TBGRAScene3D); 1404 begin 1405 FColor := BGRAWhite; 1406 FLight := 1; 1407 FTexture := nil; 1408 FMainPart := TBGRAPart3D.Create(nil); 1409 FLightingNormal:= AScene.DefaultLightingNormal; 1410 FParentLighting:= True; 1411 FScene := AScene; 1412 end; 1413 1414 destructor TBGRAObject3D.Destroy; 1415 begin 1416 fillchar(FTexture,sizeof(FTexture),0); 1417 inherited Destroy; 1418 end; 1419 1420 procedure TBGRAObject3D.Clear; 1421 begin 1422 FFaces := nil; 1423 FFaceCount := 0; 1424 FMainPart.Clear(True); 1425 end; 1426 1427 function TBGRAObject3D.GetColor: TBGRAPixel; 1428 begin 1429 result := FColor; 1430 end; 1431 1432 function TBGRAObject3D.GetLight: Single; 1433 begin 1434 result := FLight; 1435 end; 1436 1437 function TBGRAObject3D.GetTexture: IBGRAScanner; 1438 begin 1439 result := FTexture; 1440 end; 1441 1442 function TBGRAObject3D.GetMainPart: IBGRAPart3D; 1443 begin 1444 result := FMainPart; 1445 end; 1446 1447 procedure TBGRAObject3D.SetColor(const AValue: TBGRAPixel); 1448 begin 1449 FColor := AValue; 1450 FTexture := nil; 1451 end; 1452 1453 procedure TBGRAObject3D.SetLight(const AValue: Single); 1454 begin 1455 FLight := AValue; 1456 end; 1457 1458 procedure TBGRAObject3D.SetTexture(const AValue: IBGRAScanner); 1459 begin 1460 FTexture := AValue; 1461 end; 1462 1463 procedure TBGRAObject3D.SetMaterial(const AValue: IBGRAMaterial3D); 1464 begin 1465 FMaterial := AValue; 1466 end; 1467 1468 procedure TBGRAObject3D.RemoveUnusedVertices; 1469 begin 1470 GetMainPart.RemoveUnusedVertices; 1471 end; 1472 1473 procedure TBGRAObject3D.SeparatePart(APart: IBGRAPart3D); 1474 var 1475 vertexInfo: array of record 1476 orig,dup: IBGRAVertex3D; 1477 end; 1478 1479 i,j: integer; 1480 inPart,outPart: boolean; 1481 idxV: integer; 1482 begin 1483 setlength(vertexInfo, APart.VertexCount); 1484 for i := 0 to high(vertexInfo) do 1485 with vertexInfo[i] do 1486 begin 1487 orig := APart.Vertex[i]; 1488 dup := APart.Add(orig.SceneCoord_128); 1489 end; 1490 1491 for i := 0 to GetFaceCount-1 do 1492 with GetFace(i) do 1493 begin 1494 inPart := false; 1495 outPart := false; 1496 for j := 0 to VertexCount-1 do 1497 if (APart.IndexOf(Vertex[j]) <> -1) then 1498 inPart := true 1499 else 1500 outPart := true; 1501 1502 if inPart and not outPart then 1503 begin 1504 for j := 0 to VertexCount-1 do 1505 begin 1506 idxV := APart.IndexOf(Vertex[j]); 1507 if idxV <> -1 then 1508 Vertex[j] := vertexInfo[idxV].dup; 1509 end; 1510 end; 1511 end; 1512 1513 for i := APart.VertexCount-1 downto 0 do 1514 APart.RemoveVertex(i); 1515 end; 1516 1517 function TBGRAObject3D.GetScene: TBGRAScene3D; 1518 begin 1519 result := FScene; 1520 end; 1521 1522 function TBGRAObject3D.GetRefCount: integer; 1523 begin 1524 result := RefCount; 1525 end; 1526 1527 procedure TBGRAObject3D.SetBiface(AValue: boolean); 1528 var i: integer; 1529 begin 1530 for i := 0 to GetFaceCount-1 do 1531 GetFace(i).Biface := AValue; 1532 end; 1533 1534 function TBGRAObject3D.GetLightingNormal: TLightingNormal3D; 1535 begin 1536 result := FLightingNormal; 1537 end; 1538 1539 function TBGRAObject3D.GetParentLighting: boolean; 1540 begin 1541 result := FParentLighting; 1542 end; 1543 1544 procedure TBGRAObject3D.SetLightingNormal(const AValue: TLightingNormal3D); 1545 begin 1546 FLightingNormal := AValue; 1547 FParentLighting:= False; 1548 end; 1549 1550 procedure TBGRAObject3D.SetParentLighting(const AValue: boolean); 1551 begin 1552 FParentLighting:= AValue; 1553 end; 1554 1555 procedure TBGRAObject3D.ComputeWithMatrix(const AMatrix: TMatrix3D; const AProjection: TProjection3D); 1556 var 1557 i: Integer; 1558 begin 1559 FMainPart.ComputeWithMatrix(AMatrix,AProjection); 1560 for i := 0 to FFaceCount-1 do 1561 FFaces[i].ComputeViewNormalAndCenter; 1562 FMainPart.NormalizeViewNormal; 1563 end; 1564 1565 function TBGRAObject3D.AddFaceReversed(const AVertices: array of IBGRAVertex3D 1566 ): IBGRAFace3D; 1567 var 1568 tempVertices: array of IBGRAVertex3D; 1569 i: Integer; 1570 begin 1571 setlength(tempVertices,length(AVertices)); 1572 for i := 0 to high(tempVertices) do 1573 tempVertices[i] := AVertices[high(AVertices)-i]; 1574 result := AddFace(tempVertices); 1575 end; 1576 1577 function TBGRAObject3D.AddFace(const AVertices: array of IBGRAVertex3D): IBGRAFace3D; 1578 begin 1579 result := TBGRAFace3D.Create(self,AVertices); 1580 AddFace(result); 1581 end; 1582 1583 function TBGRAObject3D.AddFace(const AVertices: array of IBGRAVertex3D; 1584 ABiface: boolean): IBGRAFace3D; 1585 begin 1586 result := TBGRAFace3D.Create(self,AVertices); 1587 result.Biface := ABiface; 1588 AddFace(result); 1589 end; 1590 1591 function TBGRAObject3D.AddFace(const AVertices: array of IBGRAVertex3D; ATexture: IBGRAScanner): IBGRAFace3D; 1592 var Face: IBGRAFace3D; 1593 begin 1594 Face := TBGRAFace3D.Create(self,AVertices); 1595 Face.Texture := ATexture; 1596 AddFace(Face); 1597 result := face; 1598 end; 1599 1600 function TBGRAObject3D.AddFace(const AVertices: array of IBGRAVertex3D; 1601 AColor: TBGRAPixel): IBGRAFace3D; 1602 var Face: IBGRAFace3D; 1603 begin 1604 Face := TBGRAFace3D.Create(self,AVertices); 1605 Face.SetColor(AColor); 1606 Face.Texture := nil; 1607 AddFace(Face); 1608 result := face; 1609 end; 1610 1611 function TBGRAObject3D.AddFace(const AVertices: array of IBGRAVertex3D; 1612 AColors: array of TBGRAPixel): IBGRAFace3D; 1613 var 1614 i: Integer; 1615 begin 1616 if length(AColors) <> length(AVertices) then 1617 raise Exception.Create('Dimension mismatch'); 1618 result := TBGRAFace3D.Create(self,AVertices); 1619 for i := 0 to high(AColors) do 1620 result.VertexColor[i] := AColors[i]; 1621 AddFace(result); 1622 end; 1623 1624 function TBGRAObject3D.GetFace(AIndex: integer): IBGRAFace3D; 1625 begin 1626 if (AIndex < 0) or (AIndex >= FFaceCount) then 1627 raise Exception.Create('Index out of bounds'); 1628 result := FFaces[AIndex]; 1629 end; 1630 1631 function TBGRAObject3D.GetFaceCount: integer; 1632 begin 1633 result := FFaceCount; 1634 end; 1635 1636 function TBGRAObject3D.GetTotalVertexCount: integer; 1637 begin 1638 result := GetMainPart.TotalVertexCount; 1639 end; 1640 1641 function TBGRAObject3D.GetMaterial: IBGRAMaterial3D; 1642 begin 1643 result := FMaterial; 1644 end; 236 procedure ForEachVertex(ACallback: TVertex3DCallback); 237 procedure ForEachFace(ACallback: TFace3DCallback); 238 end; 239 240 {$i part3d.inc} 241 {$i object3d.inc} 242 {$i shapes3d.inc} 1645 243 1646 244 { TBGRAScene3D } … … 1746 344 end; 1747 345 346 function TBGRAScene3D.GetNormalCount: integer; 347 var i: integer; 348 begin 349 result := 0; 350 for i := 0 to Object3DCount-1 do 351 result += Object3D[i].TotalNormalCount; 352 end; 353 1748 354 function TBGRAScene3D.GetAmbiantLightness: single; 1749 355 begin … … 1822 428 procedure TBGRAScene3D.Init; 1823 429 begin 430 UnknownColor := BGRA(0,128,255); 1824 431 FAutoZoom := True; 1825 432 FAutoViewCenter := True; … … 1866 473 var i: integer; 1867 474 begin 475 for i := 0 to FLights.Count-1 do 476 TBGRALight3D(FLights[i])._Release; 477 FLights.Clear; 478 1868 479 for i := 0 to FObjectCount-1 do 1869 480 FObjects[i].Clear; 1870 481 FObjects := nil; 1871 482 FObjectCount := 0; 1872 for i := 0 to FLights.Count-1 do 1873 IBGRALight3D(TBGRALight3D(FLights[i]))._Release;1874 F Lights.Clear;1875 end;1876 1877 {$hints off} 483 484 FMaterials := nil; 485 FMaterialCount := 0; 486 DefaultMaterial := CreateMaterial; 487 end; 488 1878 489 procedure TBGRAScene3D.UseMaterial(AMaterialName: string; AFace: IBGRAFace3D); 1879 var color: TBGRAPixel; 1880 begin 1881 color := BGRA(0,128,255); 1882 AFace.SetColor(color); 1883 end; 1884 {$hints on} 490 491 function ParseColor(text: string): TBGRAPixel; 492 var 493 color,tempColor: TBGRAPixel; 494 begin 495 color := UnknownColor; 496 497 if copy(text,1,2) = 'dk' then 498 begin 499 tempcolor := ParseColor(copy(text,3,length(text)-2)); 500 tempcolor := MergeBGRA(tempcolor,3,BGRABlack,1); 501 color := StrToBGRA('dark'+copy(text,3,length(text)-2),tempcolor); 502 end; 503 if copy(text,1,2) = 'lt' then 504 begin 505 tempcolor := ParseColor(copy(text,3,length(text)-2)); 506 tempcolor := MergeBGRA(tempcolor,3,BGRAWhite,1); 507 color := StrToBGRA('light'+copy(text,3,length(text)-2),tempcolor); 508 end; 509 Color := StrToBGRA(StringReplace(text,'deep','dark',[]),Color); 510 Color := StrToBGRA(StringReplace(text,'dark','deep',[]),Color); 511 Color := StrToBGRA(text,Color); 512 result := color; 513 end; 514 515 var 516 mat: IBGRAMaterial3D; 517 c: TBGRAPixel; 518 begin 519 mat := GetMaterialByName(AMaterialName); 520 if mat = nil then 521 begin 522 mat := CreateMaterial; 523 mat.Name := AMaterialName; 524 c := ParseColor(AMaterialName); 525 mat.AmbiantColor := c; 526 mat.DiffuseColor := c; 527 end; 528 AFace.Material := mat; 529 end; 530 531 function TBGRAScene3D.FetchTexture(AName: string; out texSize: TPointF): IBGRAScanner; 532 begin 533 result := nil; 534 texSize := PointF(1,1); 535 end; 1885 536 1886 537 function TBGRAScene3D.LoadObjectFromFile(AFilename: string; SwapFacesOrientation: boolean): IBGRAObject3D; 1887 var t: textfile; 1888 s: string; 538 var source: TFileStream; 539 begin 540 source := TFileStream.Create(AFilename,fmOpenRead,fmShareDenyWrite); 541 try 542 result := LoadObjectFromStream(source,SwapFacesOrientation); 543 finally 544 source.free; 545 end; 546 end; 547 548 function TBGRAScene3D.LoadObjectFromFileUTF8(AFilename: string; 549 SwapFacesOrientation: boolean): IBGRAObject3D; 550 var source: TFileStreamUTF8; 551 begin 552 source := TFileStreamUTF8.Create(AFilename,fmOpenRead,fmShareDenyWrite); 553 try 554 result := LoadObjectFromStream(source,SwapFacesOrientation); 555 finally 556 source.free; 557 end; 558 end; 559 560 function TBGRAScene3D.LoadObjectFromStream(AStream: TStream; 561 SwapFacesOrientation: boolean): IBGRAObject3D; 562 var s: string; 563 secondValue,thirdValue: string; 1889 564 1890 565 function GetNextToken: string; 1891 var idxStart,idxEnd : integer;566 var idxStart,idxEnd,idxSlash: integer; 1892 567 begin 1893 568 idxStart := 1; 1894 while (idxStart <= length(s)) and (s[idxStart] =' ') do inc(idxStart);569 while (idxStart <= length(s)) and (s[idxStart]in[' ',#9]) do inc(idxStart); 1895 570 if idxStart > length(s) then 1896 571 begin … … 1899 574 end; 1900 575 idxEnd := idxStart; 1901 while (idxEnd < length(s)) and (s[idxEnd+1]<> ' ') do inc(idxEnd);576 while (idxEnd < length(s)) and not (s[idxEnd+1]in[' ',#9]) do inc(idxEnd); 1902 577 result := copy(s,idxStart, idxEnd-idxStart+1); 1903 578 delete(s,1,idxEnd); 1904 if pos('/',result) <> 0 then result := copy(result,1,pos('/',result)-1); 579 idxSlash := pos('/',result); 580 if idxSlash <> 0 then 581 begin 582 secondValue:= copy(result,idxSlash+1,length(result)-idxSlash); 583 result := copy(result,1,idxSlash-1); 584 idxSlash:= pos('/',secondValue); 585 if idxSlash <> 0 then 586 begin 587 thirdValue:= copy(secondValue,idxSlash+1,length(secondValue)-idxSlash); 588 secondValue:= copy(secondValue,1,idxSlash-1); 589 end else 590 thirdValue:= ''; 591 end else 592 begin 593 secondValue:= ''; 594 thirdValue:= ''; 595 end; 596 end; 597 598 type 599 TFaceVertexExtra = record 600 normal: IBGRANormal3D; 601 texCoord: TPointF; 1905 602 end; 1906 603 … … 1908 605 x,y,z : single; 1909 606 code : integer; 1910 vertices: array of IBGRAVertex3D; 1911 NbVertices,v,i: integer; 607 faceVertices: array of IBGRAVertex3D; 608 faceExtra: array of TFaceVertexExtra; 609 NbFaceVertices,v,v2,v3,i: integer; 1912 610 tempV: IBGRAVertex3D; 611 tempN: TFaceVertexExtra; 1913 612 materialname: string; 1914 613 face: IBGRAFace3D; 1915 1916 begin 614 lines: TStringList; 615 lineIndex: integer; 616 texCoords: array of TPointF; 617 nbTexCoords: integer; 618 619 begin 620 lines := TStringList.Create; 621 lines.LoadFromStream(AStream); 1917 622 result := CreateObject; 1918 assignfile(t,AFilename); 1919 reset(t); 1920 vertices := nil; 1921 NbVertices:= 0; 623 faceVertices := nil; 624 faceExtra := nil; 625 NbFaceVertices:= 0; 1922 626 materialname := 'default'; 1923 while not eof(t) do 1924 begin 1925 readln(t,s); 627 lineIndex := 0; 628 texCoords := nil; 629 nbTexCoords:= 0; 630 while lineIndex < lines.Count do 631 begin 632 s := lines[lineIndex]; 633 if pos('#',s) <> 0 then 634 s := copy(s,1,pos('#',s)-1); 635 inc(lineIndex); 1926 636 lineType := GetNextToken; 1927 637 if lineType = 'v' then … … 1932 642 result.MainPart.Add(x,y,z); 1933 643 end else 644 if lineType = 'vt' then 645 begin 646 val(GetNextToken,x,code); 647 val(GetNextToken,y,code); 648 if nbTexCoords >= length(texCoords) then 649 setlength(texCoords, length(texCoords)*2+1); 650 texCoords[nbTexCoords] := PointF(x,y); 651 inc(nbTexCoords); 652 end else 653 if lineType = 'vn' then 654 begin 655 val(GetNextToken,x,code); 656 val(GetNextToken,y,code); 657 val(GetNextToken,z,code); 658 result.MainPart.AddNormal(x,y,z); 659 result.LightingNormal := lnVertex; 660 end else 1934 661 if lineType = 'usemtl' then 1935 662 materialname := trim(s) … … 1937 664 if lineType = 'f' then 1938 665 begin 1939 Nb Vertices:= 0;666 NbFaceVertices:= 0; 1940 667 repeat 1941 668 val(GetNextToken,v,code); 669 if (code = 0) and (v < 0) then v := result.MainPart.VertexCount+1+v; 1942 670 if (code = 0) and (v >= 1) and (v <= result.MainPart.VertexCount) then 1943 671 begin 1944 if length(vertices) = nbvertices then 1945 setlength(vertices, length(vertices)*2+1); 1946 vertices[NbVertices] := result.MainPart.Vertex[v-1]; 1947 inc(NbVertices); 672 if length(faceVertices) = NbFaceVertices then 673 begin 674 setlength(faceVertices, length(faceVertices)*2+1); 675 setlength(faceExtra, length(faceExtra)*2+1); 676 end; 677 faceVertices[NbFaceVertices] := result.MainPart.Vertex[v-1]; 678 val(secondValue,v2,code); 679 if (code = 0) and (v2 < 0) then v2 := nbTexCoords+1+v2; 680 if (code = 0) and (v2 >= 1) and (v2-1 < nbTexCoords) then 681 faceExtra[NbFaceVertices].texCoord := texCoords[v2-1] 682 else if nbTexCoords > v-1 then 683 faceExtra[NbFaceVertices].texCoord := texCoords[v-1] 684 else 685 faceExtra[NbFaceVertices].texCoord := PointF(0,0); 686 val(thirdValue,v3,code); 687 if (code = 0) and (v3 < 0) then v3 := result.MainPart.NormalCount+1+v3; 688 if code = 0 then 689 faceExtra[NbFaceVertices].normal := result.MainPart.Normal[v3-1] 690 else if result.MainPart.NormalCount > v-1 then 691 faceExtra[NbFaceVertices].normal := result.MainPart.Normal[v-1] 692 else 693 faceExtra[NbFaceVertices].normal := nil; 694 inc(NbFaceVertices); 1948 695 end else break; 1949 696 until false; 1950 if Nb Vertices > 2 then697 if NbFaceVertices > 2 then 1951 698 begin 1952 699 if SwapFacesOrientation then 1953 for i := 0 to Nb Vertices div 2-1 do700 for i := 0 to NbFaceVertices div 2-1 do 1954 701 begin 1955 tempV := vertices[i]; 1956 vertices[i] := vertices[NbVertices-1-i]; 1957 vertices[NbVertices-1-i] := tempV; 702 tempV := faceVertices[i]; 703 faceVertices[i] := faceVertices[NbFaceVertices-1-i]; 704 faceVertices[NbFaceVertices-1-i] := tempV; 705 tempN := faceExtra[i]; 706 faceExtra[i] := faceExtra[NbFaceVertices-1-i]; 707 faceExtra[NbFaceVertices-1-i] := tempN; 1958 708 end; 1959 face := result.AddFace(slice(vertices,NbVertices)); 709 face := result.AddFace(slice(faceVertices,NbFaceVertices)); 710 for i := 0 to NbFaceVertices-1 do 711 begin 712 face.SetNormal(i, faceExtra[i].normal); 713 face.SetTexCoord(i, faceExtra[i].texCoord); 714 end; 1960 715 face.MaterialName := materialname; 1961 716 end; 1962 717 end; 1963 718 end; 1964 closefile(t); 719 lines.Free; 720 end; 721 722 procedure TBGRAScene3D.LoadMaterialsFromFile(AFilename: string); 723 var source: TFileStream; 724 begin 725 source := TFileStream.Create(AFilename,fmOpenRead,fmShareDenyWrite); 726 try 727 LoadMaterialsFromStream(source); 728 finally 729 source.free; 730 end; 731 end; 732 733 procedure TBGRAScene3D.LoadMaterialsFromFileUTF8(AFilename: string); 734 var source: TFileStreamUTF8; 735 begin 736 source := TFileStreamUTF8.Create(AFilename,fmOpenRead,fmShareDenyWrite); 737 try 738 LoadMaterialsFromStream(source); 739 finally 740 source.free; 741 end; 742 end; 743 744 procedure TBGRAScene3D.LoadMaterialsFromStream(AStream: TStream); 745 var 746 s: String; 747 748 function GetNextToken: string; 749 var idxStart,idxEnd: integer; 750 begin 751 idxStart := 1; 752 while (idxStart <= length(s)) and (s[idxStart]in[#9,' ']) do inc(idxStart); 753 if idxStart > length(s) then 754 begin 755 result := ''; 756 exit; 757 end; 758 idxEnd := idxStart; 759 while (idxEnd < length(s)) and not (s[idxEnd+1]in[#9,' ']) do inc(idxEnd); 760 result := copy(s,idxStart, idxEnd-idxStart+1); 761 delete(s,1,idxEnd); 762 end; 763 764 function GetSingle: single; 765 var code: integer; 766 begin 767 val(GetNextToken,result,code); 768 end; 769 770 function GetColorF: TColorF; 771 var r,g,b: single; 772 code: integer; 773 begin 774 val(GetNextToken,r,code); 775 val(GetNextToken,g,code); 776 val(GetNextToken,b,code); 777 result := ColorF(r,g,b,1); 778 end; 779 780 var 781 lines: TStringList; 782 lineIndex: integer; 783 lineType: String; 784 currentMaterial: IBGRAMaterial3D; 785 materialName: string; 786 texZoom: TPointF; 787 v: single; 788 789 begin 790 lines := TStringList.Create; 791 lines.LoadFromStream(AStream); 792 lineIndex := 0; 793 while lineIndex < lines.Count do 794 begin 795 s := lines[lineIndex]; 796 if pos('#',s) <> 0 then 797 s := copy(s,1,pos('#',s)-1); 798 inc(lineIndex); 799 lineType := GetNextToken; 800 if lineType = 'newmtl' then 801 begin 802 materialName := trim(s); 803 currentMaterial := GetMaterialByName(materialName); 804 if currentMaterial = nil then 805 begin 806 currentMaterial := CreateMaterial; 807 currentMaterial.Name := materialName; 808 end; 809 end else 810 if currentMaterial <> nil then 811 begin 812 if lineType = 'Ka' then currentMaterial.AmbiantColorF := GetColorF else 813 if lineType = 'Kd' then currentMaterial.DiffuseColorF := GetColorF else 814 if lineType = 'Ks' then currentMaterial.SpecularColorF := GetColorF else 815 if (lineType = 'map_Ka') or (lineType = 'map_Kd') then 816 begin 817 currentMaterial.Texture := FetchTexture(trim(s),texZoom); 818 texZoom.y := -texZoom.y; 819 currentMaterial.TextureZoom := texZoom; 820 end else 821 if lineType = 'Ns' then currentMaterial.SpecularIndex := round(GetSingle) else 822 if lineType = 'd' then 823 begin 824 v := GetSingle; 825 if v > 1 then 826 currentMaterial.SimpleAlpha := 255 827 else if v < 0 then 828 currentMaterial.SimpleAlpha := 0 829 else 830 currentMaterial.SimpleAlpha := round(v*255); 831 end; 832 end; 833 end; 834 lines.Free; 1965 835 end; 1966 836 … … 2358 1228 LColors[idxL] := BGRA(128,128,128) 2359 1229 else 1230 begin 2360 1231 if ColorOverride then 2361 1232 LColors[idxL] := Color … … 2367 1238 LColors[idxL] := tempV.Color; 2368 1239 end; 1240 end; 2369 1241 2370 1242 if TexCoordOverride then … … 2372 1244 else 2373 1245 LTexCoord[idxL] := tempV.TexCoord; 1246 with LMaterial.GetTextureZoom do 1247 begin 1248 LTexCoord[idxL].x *= x; 1249 LTexCoord[idxL].y *= y; 1250 end; 2374 1251 2375 1252 with tempV.CoordData^ do … … 2380 1257 LZ[idxL] := viewCoord.Z; 2381 1258 end; 1259 if Normal <> nil then 1260 LNormal3D[idxL] := Normal.ViewNormal_128; 2382 1261 end; 2383 1262 end; … … 2389 1268 VCount := VertexCount; 2390 1269 if VCount < 3 then exit; 2391 2392 if ParentTexture then2393 LTexture := Object3D.Texture2394 else2395 LTexture := Texture;2396 1270 2397 1271 if Material <> nil then … … 2403 1277 else 2404 1278 exit; 1279 1280 if ParentTexture then 1281 begin 1282 if LMaterial.GetTexture <> nil then 1283 LTexture := LMaterial.GetTexture 1284 else 1285 LTexture := Object3D.Texture 1286 end 1287 else 1288 LTexture := Texture; 2405 1289 2406 1290 LLightNormal := Object3D.LightingNormal; … … 2635 1519 procedure DrawWithResample; 2636 1520 var 2637 tempSurface ,resampledTempSurface: TBGRACustomBitmap;1521 tempSurface: TBGRACustomBitmap; 2638 1522 begin 2639 1523 tempSurface := ASurface.NewBitmap(ASurface.Width*RenderingOptions.AntialiasingResampleLevel,ASurface.Height*RenderingOptions.AntialiasingResampleLevel); 2640 1524 InternalRender(tempSurface, am3dNone, RenderingOptions.AntialiasingResampleLevel); 2641 resampledTempSurface := tempSurface.Resample(ASurface.Width,ASurface.Height,rmSimpleStretch); 1525 BGRAResample.DownSamplePutImage(tempSurface,RenderingOptions.AntialiasingResampleLevel,RenderingOptions.AntialiasingResampleLevel, 1526 ASurface, 0,0, dmDrawWithTransparency); 2642 1527 tempSurface.Free; 2643 ASurface.PutImage(0,0,resampledTempSurface,dmDrawWithTransparency);2644 resampledTempSurface.Free;2645 1528 end; 2646 1529 … … 2739 1622 Color: TBGRAPixel): TBGRAPixel; 2740 1623 var i: Integer; 2741 begin 1624 m: TBGRAMaterial3D; 1625 begin 1626 m := TBGRAMaterial3D(Context^.material); 1627 if not m.GetAutoSimpleColor then Color := ColorIntToBGRA(BGRAToColorIntMultiply(Color, m.GetSimpleColorInt)); 1628 2742 1629 Context^.lightness := FAmbiantLightness; 2743 1630 … … 2767 1654 Color: TBGRAPixel): TBGRAPixel; 2768 1655 var i: Integer; 2769 begin 2770 Context^.diffuseColor := FAmbiantLightColor; 1656 m: TBGRAMaterial3D; 1657 begin 1658 m := TBGRAMaterial3D(Context^.material); 1659 1660 if m.GetAutoAmbiantColor then 1661 Context^.diffuseColor := FAmbiantLightColor 1662 else 1663 Context^.diffuseColor := FAmbiantLightColor*m.GetAmbiantColorInt; 2771 1664 2772 1665 i := FLights.Count-1; … … 2784 1677 Color: TBGRAPixel): TBGRAPixel; 2785 1678 var i: Integer; 2786 begin 2787 Context^.diffuseColor := FAmbiantLightColor; 1679 m: TBGRAMaterial3D; 1680 begin 1681 m := TBGRAMaterial3D(Context^.material); 1682 1683 if m.GetAutoAmbiantColor then 1684 Context^.diffuseColor := FAmbiantLightColor 1685 else 1686 Context^.diffuseColor := FAmbiantLightColor*m.GetAmbiantColorInt; 2788 1687 Context^.specularColor := ColorInt65536(0,0,0,0); 2789 1688 … … 2802 1701 end; 2803 1702 2804 {$hints off}2805 1703 function TBGRAScene3D.ApplyNoLighting(Context: PSceneLightingContext; 2806 1704 Color: TBGRAPixel): TBGRAPixel; 2807 begin 2808 result := Color; 1705 var 1706 m: TBGRAMaterial3D; 1707 begin 1708 m := TBGRAMaterial3D(Context^.material); 1709 1710 if not m.GetAutoAmbiantColor then 1711 result := ColorIntToBGRA(BGRAToColorIntMultiply(Color, m.GetAmbiantColorInt)) 1712 else 1713 result := Color; 2809 1714 end; 2810 1715 2811 1716 function TBGRAScene3D.ApplyLightingWithAmbiantLightnessOnly( 2812 1717 Context: PSceneLightingContext; Color: TBGRAPixel): TBGRAPixel; 2813 begin 1718 var 1719 m: TBGRAMaterial3D; 1720 begin 1721 m := TBGRAMaterial3D(Context^.material); 1722 1723 if not m.GetAutoAmbiantColor then 1724 Color := ColorIntToBGRA(BGRAToColorIntMultiply(Color, m.GetAmbiantColorInt)); 1725 2814 1726 if FAmbiantLightness <= 0 then 2815 1727 result := BGRA(0,0,0,color.alpha) … … 2817 1729 result := ApplyIntensityFast(Color, FAmbiantLightness); 2818 1730 end; 2819 2820 {$hints on}2821 1731 2822 1732 function TBGRAScene3D.CreateObject: IBGRAObject3D; … … 2963 1873 end; 2964 1874 1875 function TBGRAScene3D.GetMaterialByName(AName: string): IBGRAMaterial3D; 1876 var i: integer; 1877 begin 1878 for i := 0 to MaterialCount-1 do 1879 if AName = Material[i].Name then 1880 begin 1881 result := Material[i]; 1882 exit; 1883 end; 1884 result := nil; 1885 end; 1886 2965 1887 procedure TBGRAScene3D.UpdateMaterials; 2966 1888 var i,j: integer; … … 2997 1919 end; 2998 1920 1921 procedure TBGRAScene3D.ForEachVertex(ACallback: TVertex3DCallback); 1922 var i: integer; 1923 begin 1924 for i := 0 to Object3DCount-1 do 1925 Object3D[i].ForEachVertex(ACallback); 1926 end; 1927 1928 procedure TBGRAScene3D.ForEachFace(ACallback: TFace3DCallback); 1929 var i: integer; 1930 begin 1931 for i := 0 to Object3DCount-1 do 1932 Object3D[i].ForEachFace(ACallback); 1933 end; 1934 1935 initialization 1936 1937 Randomize; 1938 2999 1939 end. 3000 1940 -
GraphicTest/Packages/bgrabitmap/bgrascene3dinterface.inc
r452 r472 4 4 { IBGRALight3D } 5 5 6 IBGRALight3D = interface 6 IBGRALight3D = interface ['{85C683B6-07AC-4B8D-9324-06BC22882433}'] 7 7 procedure ComputeDiffuseLightness(Context: PSceneLightingContext); 8 8 procedure ComputeDiffuseColor(Context: PSceneLightingContext); … … 30 30 end; 31 31 32 IBGRAPointLight3D = interface(IBGRALight3D) 32 IBGRAPointLight3D = interface(IBGRALight3D) ['{C939900D-DDD6-49F0-B1E9-E29F94FDB4C8}'] 33 33 function GetVertex: IBGRAVertex3D; 34 34 procedure SetVertex(const AValue: IBGRAVertex3D); … … 36 36 end; 37 37 38 IBGRADirectionalLight3D = interface(IBGRALight3D) 38 IBGRADirectionalLight3D = interface(IBGRALight3D) ['{8D575CEE-8DD2-46FB-9BCC-17DE3DAAF53D}'] 39 39 function GetDirection: TPoint3D; 40 40 procedure SetDirection(const AValue: TPoint3D); … … 45 45 46 46 IBGRAMaterial3D = interface 47 function GetAmbiantAlpha: byte; 48 function GetAutoAmbiantColor: boolean; 47 49 function GetAutoDiffuseColor: boolean; 50 function GetAutoSimpleColor: boolean; 48 51 function GetAutoSpecularColor: boolean; 52 function GetAmbiantColor: TBGRAPixel; 53 function GetAmbiantColorF: TColorF; 54 function GetAmbiantColorInt: TColorInt65536; 55 function GetDiffuseAlpha: byte; 49 56 function GetDiffuseColor: TBGRAPixel; 50 57 function GetDiffuseColorF: TColorF; 51 58 function GetDiffuseColorInt: TColorInt65536; 52 59 function GetLightThroughFactor: single; 60 function GetName: string; 53 61 function GetSaturationHigh: single; 54 62 function GetSaturationLow: single; 63 function GetSimpleAlpha: byte; 64 function GetSimpleColor: TBGRAPixel; 65 function GetSimpleColorF: TColorF; 66 function GetSimpleColorInt: TColorInt65536; 55 67 function GetSpecularColor: TBGRAPixel; 56 68 function GetSpecularColorF: TColorF; … … 58 70 function GetSpecularIndex: integer; 59 71 function GetSpecularOn: boolean; 72 function GetTexture: IBGRAScanner; 73 function GetTextureZoom: TPointF; 74 procedure SetAmbiantAlpha(AValue: byte); 60 75 procedure SetAutoDiffuseColor(const AValue: boolean); 61 76 procedure SetAutoSpecularColor(const AValue: boolean); 77 procedure SetAmbiantColor(const AValue: TBGRAPixel); 78 procedure SetAmbiantColorF(const AValue: TColorF); 79 procedure SetAmbiantColorInt(const AValue: TColorInt65536); 80 procedure SetDiffuseAlpha(AValue: byte); 62 81 procedure SetDiffuseColor(const AValue: TBGRAPixel); 63 82 procedure SetDiffuseColorF(const AValue: TColorF); 64 83 procedure SetDiffuseColorInt(const AValue: TColorInt65536); 65 84 procedure SetLightThroughFactor(const AValue: single); 85 procedure SetName(const AValue: string); 66 86 procedure SetSaturationHigh(const AValue: single); 67 87 procedure SetSaturationLow(const AValue: single); 88 procedure SetSimpleAlpha(AValue: byte); 89 procedure SetSimpleColor(AValue: TBGRAPixel); 90 procedure SetSimpleColorF(AValue: TColorF); 91 procedure SetSimpleColorInt(AValue: TColorInt65536); 68 92 procedure SetSpecularColor(const AValue: TBGRAPixel); 69 93 procedure SetSpecularColorF(const AValue: TColorF); … … 71 95 procedure SetSpecularIndex(const AValue: integer); 72 96 function GetAsObject: TObject; 97 procedure SetTexture(AValue: IBGRAScanner); 98 procedure SetTextureZoom(AValue: TPointF); 99 100 property AutoSimpleColor: boolean read GetAutoSimpleColor; 101 property SimpleColor: TBGRAPixel read GetSimpleColor write SetSimpleColor; 102 property SimpleColorF: TColorF read GetSimpleColorF write SetSimpleColorF; 103 property SimpleColorInt: TColorInt65536 read GetSimpleColorInt write SetSimpleColorInt; 104 property SimpleAlpha: byte read GetSimpleAlpha write SetSimpleAlpha; 105 106 property AmbiantColor: TBGRAPixel read GetAmbiantColor write SetAmbiantColor; 107 property AmbiantColorF: TColorF read GetAmbiantColorF write SetAmbiantColorF; 108 property AmbiantColorInt: TColorInt65536 read GetAmbiantColorInt write SetAmbiantColorInt; 109 property AutoAmbiantColor: boolean read GetAutoAmbiantColor; 110 property AmbiantAlpha: byte read GetAmbiantAlpha write SetAmbiantAlpha; 111 property Texture: IBGRAScanner read GetTexture write SetTexture; 112 property TextureZoom: TPointF read GetTextureZoom write SetTextureZoom; 73 113 74 114 property DiffuseColor: TBGRAPixel read GetDiffuseColor write SetDiffuseColor; … … 76 116 property DiffuseColorInt: TColorInt65536 read GetDiffuseColorInt write SetDiffuseColorInt; 77 117 property AutoDiffuseColor: boolean read GetAutoDiffuseColor write SetAutoDiffuseColor; 118 property DiffuseAlpha: byte read GetDiffuseAlpha write SetDiffuseAlpha; 78 119 property SaturationLow: single read GetSaturationLow write SetSaturationLow; 79 120 property SaturationHigh: single read GetSaturationHigh write SetSaturationHigh; … … 87 128 88 129 property LightThroughFactor: single read GetLightThroughFactor write SetLightThroughFactor; 130 property Name: string read GetName write SetName; 131 end; 132 133 { IBGRANormal3D } 134 135 IBGRANormal3D = interface 136 function GetCustomNormal: TPoint3D; 137 function GetCustomNormal_128: TPoint3D_128; 138 function GetViewNormal: TPoint3D; 139 function GetViewNormal_128: TPoint3D_128; 140 procedure SetCustomNormal(AValue: TPoint3D); 141 procedure SetCustomNormal_128(AValue: TPoint3D_128); 142 procedure SetViewNormal(AValue: TPoint3D); 143 procedure SetViewNormal_128(AValue: TPoint3D_128); 144 property ViewNormal: TPoint3D read GetViewNormal write SetViewNormal; 145 property ViewNormal_128: TPoint3D_128 read GetViewNormal_128 write SetViewNormal_128; 146 property CustomNormal: TPoint3D read GetCustomNormal write SetCustomNormal; 147 property CustomNormal_128: TPoint3D_128 read GetCustomNormal_128 write SetCustomNormal_128; 89 148 end; 90 149 … … 93 152 IBGRAVertex3D = interface 94 153 function GetColor: TBGRAPixel; 154 function GetCustomFlags: DWord; 155 function GetCustomNormal: TPoint3D; 156 function GetCustomNormal_128: TPoint3D_128; 95 157 function GetLight: Single; 96 158 function GetProjectedCoord: TPointF; … … 107 169 function GetViewCoordZ: single; 108 170 procedure SetColor(const AValue: TBGRAPixel); 171 procedure SetCustomFlags(AValue: DWord); 172 procedure SetCustomNormal(AValue: TPoint3D); 173 procedure SetCustomNormal_128(AValue: TPoint3D_128); 109 174 procedure SetLight(const AValue: Single); 110 175 procedure SetProjectedCoord(const AValue: TPointF); … … 131 196 property ViewNormal: TPoint3D read GetViewNormal write SetViewNormal; 132 197 property ViewNormal_128: TPoint3D_128 read GetViewNormal_128 write SetViewNormal_128; 198 property CustomNormal: TPoint3D read GetCustomNormal write SetCustomNormal; 199 property CustomNormal_128: TPoint3D_128 read GetCustomNormal_128 write SetCustomNormal_128; 133 200 property Usage: integer read GetUsage; 201 property CustomFlags: DWord read GetCustomFlags write SetCustomFlags; 134 202 function GetAsObject: TObject; 135 203 end; 136 204 137 205 arrayOfIBGRAVertex3D = array of IBGRAVertex3D; 206 TVertex3DCallback = procedure(AVertex: IBGRAVertex3D) of object; 138 207 139 208 { IBGRAPart3D } … … 143 212 function Add(x,y,z: single): IBGRAVertex3D; 144 213 function Add(pt: TPoint3D): IBGRAVertex3D; 214 function Add(pt: TPoint3D; normal: TPoint3D): IBGRAVertex3D; 145 215 function Add(pt: TPoint3D_128): IBGRAVertex3D; 216 function Add(pt: TPoint3D_128; normal: TPoint3D_128): IBGRAVertex3D; 217 function AddNormal(x,y,z: single): IBGRANormal3D; 218 function AddNormal(pt: TPoint3D): IBGRANormal3D; 219 function AddNormal(pt: TPoint3D_128): IBGRANormal3D; 146 220 function Add(const coords: array of single): arrayOfIBGRAVertex3D; 147 221 function Add(const pts: array of TPoint3D): arrayOfIBGRAVertex3D; … … 149 223 procedure Add(const pts: array of IBGRAVertex3D); 150 224 procedure Add(AVertex: IBGRAVertex3D); 225 function GetTotalNormalCount: integer; 151 226 function IndexOf(AVertex: IBGRAVertex3D): integer; 152 227 procedure RemoveVertex(Index: integer); 228 procedure RemoveNormal(Index: integer); 153 229 function GetBoundingBox: TBox3D; 154 230 function GetMatrix: TMatrix3D; … … 158 234 function GetVertex(AIndex: Integer): IBGRAVertex3D; 159 235 function GetVertexCount: integer; 236 function GetNormal(AIndex: Integer): IBGRANormal3D; 237 function GetNormalCount: integer; 160 238 function GetTotalVertexCount: integer; 161 239 function GetContainer: IBGRAPart3D; … … 165 243 procedure Scale(size: TPoint3D; Before: boolean = true); 166 244 procedure SetMatrix(const AValue: TMatrix3D); 167 procedure SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 245 procedure SetNormal(AIndex: Integer; AValue: IBGRANormal3D); 246 procedure SetVertex(AIndex: Integer; AValue: IBGRAVertex3D); 168 247 procedure Translate(x,y,z: single; Before: boolean = true); 169 248 procedure Translate(ofs: TPoint3D; Before: boolean = true); … … 180 259 procedure RemoveUnusedVertices; 181 260 function CreatePart: IBGRAPart3D; 261 procedure ForEachVertex(ACallback: TVertex3DCallback); 182 262 property VertexCount: integer read GetVertexCount; 263 property NormalCount: integer read GetNormalCount; 183 264 property Vertex[AIndex: Integer]: IBGRAVertex3D read GetVertex write SetVertex; 265 property Normal[AIndex: Integer]: IBGRANormal3D read GetNormal write SetNormal; 184 266 property Matrix: TMatrix3D read GetMatrix write SetMatrix; 185 267 property PartCount: integer read GetPartCount; … … 188 270 property BoundingBox: TBox3D read GetBoundingBox; 189 271 property TotalVertexCount: integer read GetTotalVertexCount; 272 property TotalNormalCount: integer read GetTotalNormalCount; 190 273 property Container: IBGRAPart3D read GetContainer; 191 274 end; … … 196 279 197 280 IBGRAFace3D = interface 198 procedure AddVertex(AVertex: IBGRAVertex3D);281 function AddVertex(AVertex: IBGRAVertex3D): integer; 199 282 function GetBiface: boolean; 283 function GetCustomFlags: DWord; 200 284 function GetLightThroughFactorOverride: boolean; 201 285 function GetMaterial: IBGRAMaterial3D; … … 207 291 function GetTexture: IBGRAScanner; 208 292 function GetVertex(AIndex: Integer): IBGRAVertex3D; 293 function GetNormal(AIndex: Integer): IBGRANormal3D; 209 294 function GetVertexColor(AIndex: Integer): TBGRAPixel; 210 295 function GetVertexColorOverride(AIndex: Integer): boolean; … … 216 301 function GetViewNormal_128: TPoint3D_128; 217 302 function GetLightThroughFactor: single; 303 procedure SetCustomFlags(AValue: DWord); 218 304 procedure SetLightThroughFactor(const AValue: single); 219 305 procedure SetBiface(const AValue: boolean); … … 225 311 procedure SetTexCoordOverride(AIndex: Integer; const AValue: boolean); 226 312 procedure SetTexture(const AValue: IBGRAScanner); 227 procedure SetVertex(AIndex: Integer; const AValue: IBGRAVertex3D); 313 procedure SetVertex(AIndex: Integer; AValue: IBGRAVertex3D); 314 procedure SetNormal(AIndex: Integer; AValue: IBGRANormal3D); 228 315 procedure SetVertexColor(AIndex: Integer; const AValue: TBGRAPixel); 229 316 procedure SetVertexColorOverride(AIndex: Integer; const AValue: boolean); … … 250 337 property MaterialName: string read GetMaterialName write SetMaterialName; 251 338 function GetAsObject: TObject; 252 end; 339 property CustomFlags: DWord read GetCustomFlags write SetCustomFlags; 340 end; 341 342 TFace3DCallback = procedure(AFace: IBGRAFace3D) of object; 253 343 254 344 { IBGRAObject3D } … … 261 351 function GetMaterial: IBGRAMaterial3D; 262 352 function GetRefCount: integer; 353 function GetTotalNormalCount: integer; 263 354 function GetTotalVertexCount: integer; 264 355 function GetLight: Single; … … 274 365 procedure SetParentLighting(const AValue: boolean); 275 366 procedure SetTexture(const AValue: IBGRAScanner); 276 procedure ComputeWithMatrix(const AMatrix: TMatrix3D; constAProjection: TProjection3D);367 procedure ComputeWithMatrix(constref AMatrix: TMatrix3D; constref AProjection: TProjection3D); 277 368 procedure RemoveUnusedVertices; 369 procedure ForEachVertex(ACallback: TVertex3DCallback); 370 procedure ForEachFace(ACallback: TFace3DCallback); 278 371 function AddFaceReversed(const AVertices: array of IBGRAVertex3D): IBGRAFace3D; 279 372 function AddFace(const AVertices: array of IBGRAVertex3D): IBGRAFace3D; … … 293 386 property ParentLighting: boolean read GetParentLighting write SetParentLighting; 294 387 property TotalVertexCount: integer read GetTotalVertexCount; 388 property TotalNormalCount: integer read GetTotalNormalCount; 295 389 property Material: IBGRAMaterial3D read GetMaterial write SetMaterial; 296 390 property Scene: TBGRAScene3D read GetScene; -
GraphicTest/Packages/bgrabitmap/bgraslicescaling.pas
r452 r472 66 66 // or as a local owned copy in other cases 67 67 constructor Create(ABitmap: TBGRABitmap; 68 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer );68 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer; ABitmapOwner: boolean = false); 69 69 constructor Create(ABitmap: TBitmap; 70 70 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 71 71 constructor Create(AFilename: string; 72 72 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 73 constructor Create(AFilename: string; AIsUtf8: boolean; 74 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 73 75 constructor Create(AStream: TStream; 74 76 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 75 constructor Create(ABitmap: TBGRABitmap );77 constructor Create(ABitmap: TBGRABitmap; ABitmapOwner: boolean = false); 76 78 constructor Create(ABitmap: TBitmap); 77 79 constructor Create(AFilename: string); 80 constructor Create(AFilename: string; AIsUtf8: boolean); 78 81 constructor Create(AStream: TStream); 79 82 constructor Create; … … 121 124 constructor Create(ABitmap: TBGRABitmap; 122 125 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 123 Direction: TSliceScalingDirection );126 Direction: TSliceScalingDirection; ABitmapOwner: boolean = false); 124 127 constructor Create(ABitmap: TBitmap; 125 128 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 126 129 Direction: TSliceScalingDirection); 127 constructor Create(AFilename: string; 130 constructor Create(ABitmapFilename: string; 131 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 132 Direction: TSliceScalingDirection); 133 constructor Create(ABitmapFilename: string; AIsUtf8: boolean; 128 134 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 129 135 Direction: TSliceScalingDirection); … … 132 138 Direction: TSliceScalingDirection); 133 139 destructor Destroy; override; 134 constructor Create( Filename, Section: string);140 constructor Create(AIniFilename, ASection: string; AIsUtf8Filename: boolean= false); 135 141 public 136 142 procedure Draw(ItemNumber: integer; ABitmap: TBGRABitmap; … … 166 172 constructor TBGRAMultiSliceScaling.Create(ABitmap: TBGRABitmap; 167 173 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 168 Direction: TSliceScalingDirection );174 Direction: TSliceScalingDirection; ABitmapOwner: boolean = false); 169 175 var 170 176 i: integer; … … 172 178 begin 173 179 FBitmap := ABitmap; 174 FBitmapOwned := false;180 FBitmapOwned := ABitmapOwner; 175 181 ItemWidth := ABitmap.Width; 176 182 ItemHeight := ABitmap.Height; … … 203 209 begin 204 210 Create(TBGRABitmap.Create(ABitmap), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, 205 NumberOfItems, Direction); 206 FBitmapOwned := true; 207 end; 208 209 constructor TBGRAMultiSliceScaling.Create(AFilename: string; 211 NumberOfItems, Direction, True); 212 end; 213 214 constructor TBGRAMultiSliceScaling.Create(ABitmapFilename: string; 210 215 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 211 216 Direction: TSliceScalingDirection); 212 217 begin 213 Create(TBGRABitmap.Create(AFilename), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, 214 NumberOfItems, Direction); 215 FBitmapOwned := true; 218 Create(TBGRABitmap.Create(ABitmapFilename), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, 219 NumberOfItems, Direction, True); 220 end; 221 222 constructor TBGRAMultiSliceScaling.Create(ABitmapFilename: string; AIsUtf8: boolean; 223 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer; 224 Direction: TSliceScalingDirection); 225 begin 226 Create(TBGRABitmap.Create(ABitmapFilename,AIsUtf8), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, 227 NumberOfItems, Direction, True); 216 228 end; 217 229 … … 221 233 begin 222 234 Create(TBGRABitmap.Create(AStream), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, 223 NumberOfItems, Direction); 224 FBitmapOwned := true; 235 NumberOfItems, Direction, True); 225 236 end; 226 237 … … 236 247 end; 237 248 238 constructor TBGRAMultiSliceScaling.Create(Filename, Section: string); 249 constructor TBGRAMultiSliceScaling.Create(AIniFilename, ASection: string; 250 AIsUtf8Filename: boolean); 239 251 var 240 252 i: integer; … … 242 254 Direction: TSliceScalingDirection; 243 255 defaultRepeat: string; 244 IniPath,BitmapFilename: string; 245 begin 246 if FileExistsUTF8(Filename) then 247 begin 248 temp := TMemIniFile.Create(Filename); 249 IniPath := ExtractFilePath(Filename); 250 251 if temp.ReadBool(Section, 'HorizontalDirection', False) then 252 Direction := sdHorizontal 253 else 254 Direction := sdVertical; 255 256 BitmapFilename := temp.ReadString(Section, 'Bitmap', ''); 257 if (copy(BitmapFilename,1,2) = '.\') or (copy(BitmapFilename,1,2) = './') then 258 BitmapFilename := IniPath+copy(BitmapFilename,3,Length(BitmapFilename)-2); 259 Create( 260 BitmapFilename, 261 temp.ReadInteger(Section, 'MarginTop', 0), 262 temp.ReadInteger(Section, 'MarginRight', 0), 263 temp.ReadInteger(Section, 'MarginBottom', 0), 264 temp.ReadInteger(Section, 'MarginLeft', 0), 265 temp.ReadInteger(Section, 'NumberOfItems', 1), 266 Direction); 267 268 defaultRepeat := temp.ReadString(Section, 'Repeat', 'Auto'); 269 for i := 0 to High(FSliceScalingArray) do 270 FSliceScalingArray[i].SliceRepeatAsString := temp.ReadString(Section, 'Repeat'+IntToStr(i+1), defaultRepeat); 271 272 temp.Free; 273 end; 256 IniPathUTF8,BitmapFilename: string; 257 begin 258 if AIsUtf8Filename then 259 begin 260 if not FileExistsUTF8(AIniFilename) then exit; 261 temp := TMemIniFile.Create(UTF8ToSys(AIniFilename)); 262 IniPathUTF8 := ExtractFilePath(AIniFilename); 263 end else 264 begin 265 if not FileExists(AIniFilename) then exit; 266 temp := TMemIniFile.Create(AIniFilename); 267 IniPathUTF8 := SysToUTF8(ExtractFilePath(AIniFilename)); 268 end; 269 270 if temp.ReadBool(ASection, 'HorizontalDirection', False) then 271 Direction := sdHorizontal 272 else 273 Direction := sdVertical; 274 275 BitmapFilename := temp.ReadString(ASection, 'Bitmap', ''); 276 if (copy(BitmapFilename,1,2) = '.\') or (copy(BitmapFilename,1,2) = './') then 277 BitmapFilename := IniPathUTF8+SysToUTF8(copy(BitmapFilename,3,Length(BitmapFilename)-2)); 278 Create( 279 BitmapFilename,True, 280 temp.ReadInteger(ASection, 'MarginTop', 0), 281 temp.ReadInteger(ASection, 'MarginRight', 0), 282 temp.ReadInteger(ASection, 'MarginBottom', 0), 283 temp.ReadInteger(ASection, 'MarginLeft', 0), 284 temp.ReadInteger(ASection, 'NumberOfItems', 1), 285 Direction); 286 287 defaultRepeat := temp.ReadString(ASection, 'Repeat', 'Auto'); 288 for i := 0 to High(FSliceScalingArray) do 289 FSliceScalingArray[i].SliceRepeatAsString := temp.ReadString(ASection, 'Repeat'+IntToStr(i+1), defaultRepeat); 290 291 temp.Free; 274 292 end; 275 293 … … 582 600 583 601 constructor TBGRASliceScaling.Create(ABitmap: TBGRABitmap; 602 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer; ABitmapOwner: boolean = false); 603 begin 604 Create(ABitmap, ABitmapOwner); 605 SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft); 606 end; 607 608 constructor TBGRASliceScaling.Create(ABitmap: TBitmap; 584 609 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 585 610 begin … … 588 613 end; 589 614 590 constructor TBGRASliceScaling.Create(ABitmap: TBitmap;591 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer);592 begin593 Create(ABitmap);594 SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);595 end;596 597 615 constructor TBGRASliceScaling.Create(AFilename: string; 598 616 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); … … 602 620 end; 603 621 622 constructor TBGRASliceScaling.Create(AFilename: string; AIsUtf8: boolean; 623 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); 624 begin 625 Create(AFilename, AIsUtf8); 626 SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft); 627 end; 628 604 629 constructor TBGRASliceScaling.Create(AStream: TStream; 605 630 AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); … … 609 634 end; 610 635 611 constructor TBGRASliceScaling.Create(ABitmap: TBGRABitmap );636 constructor TBGRASliceScaling.Create(ABitmap: TBGRABitmap; ABitmapOwner: boolean = false); 612 637 begin 613 638 Init; 614 639 FBitmap := ABitmap; 615 FBitmapOwned := False;640 FBitmapOwned := ABitmapOwner; 616 641 FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height); 617 642 end; … … 629 654 Init; 630 655 FBitmap := TBGRABitmap.Create(AFilename); 656 FBitmapOwned := True; 657 FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height); 658 end; 659 660 constructor TBGRASliceScaling.Create(AFilename: string; AIsUtf8: boolean); 661 begin 662 Init; 663 FBitmap := TBGRABitmap.Create(AFilename,AIsUtf8); 631 664 FBitmapOwned := True; 632 665 FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height); -
GraphicTest/Packages/bgrabitmap/bgrasse.pas
r452 r472 2 2 3 3 {$mode objfpc}{$H+} 4 5 {$i bgrasse.inc} 4 6 5 7 interface … … 19 21 var UseSSE, UseSSE2, UseSSE3 : boolean; 20 22 21 {$ifdef CPUI386}23 {$ifdef BGRASSE_AVAILABLE} 22 24 {$asmmode intel} 23 25 //SSE rotate singles … … 37 39 procedure Normalize3D_128_SqLen(var v: TPoint3D_128; out SqLen: single); 38 40 operator * (const v1: TPoint3D_128; const factor: single): TPoint3D_128; 39 operator + (const v1,v2: TPoint3D_128): TPoint3D_128;41 operator + (constref v1,v2: TPoint3D_128): TPoint3D_128; 40 42 operator - (const v1,v2: TPoint3D_128): TPoint3D_128; 41 43 operator - (const v: TPoint3D_128): TPoint3D_128; inline; 42 44 operator = (const v1,v2: TPoint3D_128): boolean; inline; 43 45 procedure ClearPoint3D_128(out v: TPoint3D_128); 44 {$IFDEF CPUI386}46 {$IFDEF BGRASSE_AVAILABLE} 45 47 procedure ClearPoint3D_128_AlignedSSE(out v: TPoint3D_128); 46 48 {$ENDIF} … … 48 50 49 51 var 50 Add3D_Aligned : procedure (var dest: TPoint3D_128; const src: TPoint3D_128);52 Add3D_Aligned : procedure (var dest: TPoint3D_128; constref src: TPoint3D_128); 51 53 Normalize3D_128 : procedure (var v: TPoint3D_128); 52 54 VectProduct3D_128 : procedure (const u,v: TPoint3D_128; out w: TPoint3D_128); 53 DotProduct3D_128 : function (const v1,v2: TPoint3D_128): single;55 DotProduct3D_128 : function (constref v1,v2: TPoint3D_128): single; 54 56 55 57 const … … 125 127 end; 126 128 127 operator + (const v1,v2: TPoint3D_128): TPoint3D_128;129 operator + (constref v1,v2: TPoint3D_128): TPoint3D_128; 128 130 {$ifdef CPUI386} assembler; 129 131 asm … … 152 154 {$endif} 153 155 154 {$ifdef CPUI386}155 procedure Add3D_AlignedSSE(var dest: TPoint3D_128; const src: TPoint3D_128); assembler;156 asm 157 movaps xmm0, [ eax]158 movups xmm1, [ edx]156 {$ifdef BGRASSE_AVAILABLE} 157 procedure Add3D_AlignedSSE(var dest: TPoint3D_128; constref src: TPoint3D_128); assembler; 158 asm 159 movaps xmm0, [dest] 160 movups xmm1, [src] 159 161 addps xmm0, xmm1 160 movaps [ eax], xmm0161 end; 162 {$endif} 163 164 procedure Add3D_NoSSE(var dest: TPoint3D_128; const src: TPoint3D_128);162 movaps [dest], xmm0 163 end; 164 {$endif} 165 166 procedure Add3D_NoSSE(var dest: TPoint3D_128; constref src: TPoint3D_128); 165 167 {$ifdef CPUI386} assembler; 166 168 asm … … 226 228 227 229 procedure ClearPoint3D_128(out v: TPoint3D_128); 228 {$ifdef CPUI386} 229 begin 230 {$ifdef cpux86_64} assembler; 231 asm 232 push rbx 233 mov rax,v 234 xor rbx,rbx 235 mov [rax],rbx 236 mov [rax+8],rbx 237 pop rbx 238 end; 239 {$else} 240 {$ifdef CPUI386} assembler; 241 asm 242 push ebx 243 mov eax,v 244 xor ebx,ebx 245 mov [eax],ebx 246 mov [eax+4],ebx 247 mov [eax+8],ebx 248 pop ebx 249 end; 250 {$else} 251 var p: pdword; 252 begin 253 p := @v; 254 p^ := 0; 255 inc(p); 256 p^ := 0; 257 inc(p); 258 p^ := 0; 259 end; 260 {$endif} 261 {$endif} 262 263 procedure ClearPoint3D_128_AlignedSSE(out v: TPoint3D_128); 264 {$ifdef BGRASSE_AVAILABLE} assembler; 230 265 asm 231 push ebx 232 mov eax,v 233 xor ebx,ebx 234 mov [eax],ebx 235 mov [eax+4],ebx 236 mov [eax+8],ebx 237 pop ebx 266 xorps xmm0,xmm0 267 {$ifdef cpux86_64} 268 mov rax,v 269 movaps [rax],xmm0 270 {$else} 271 mov eax,v 272 movaps [eax],xmm0 273 {$endif} 238 274 end; 239 end;240 275 {$else} 241 276 var p: pdword; … … 250 285 {$endif} 251 286 252 procedure ClearPoint3D_128_AlignedSSE(out v: TPoint3D_128);253 {$ifdef CPUI386}254 begin255 asm256 xorps xmm0,xmm0257 movaps [eax],xmm0258 end;259 end;260 {$else}261 var p: pdword;262 begin263 p := @v;264 p^ := 0;265 inc(p);266 p^ := 0;267 inc(p);268 p^ := 0;269 end;270 {$endif}271 272 287 function IsPoint3D_128_Zero(const v: TPoint3D_128): boolean; 273 288 begin … … 302 317 {$endif} 303 318 304 {$ifdef CPUI386}305 function DotProduct3D_128_SSE3(const v1,v2: TPoint3D_128): single; assembler;319 {$ifdef BGRASSE_AVAILABLE} 320 function DotProduct3D_128_SSE3(constref v1,v2: TPoint3D_128): single; assembler; 306 321 asm 307 322 movups xmm0, [v1] … … 315 330 {$endif} 316 331 317 function DotProduct3D_128_NoSSE(const v1,v2: TPoint3D_128): single;332 function DotProduct3D_128_NoSSE(constref v1,v2: TPoint3D_128): single; 318 333 begin 319 334 result := v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; … … 331 346 end; 332 347 333 {$ifdef CPUI386}348 {$ifdef BGRASSE_AVAILABLE} 334 349 procedure Normalize3D_128_SSE1(var v: TPoint3D_128); 335 350 var len: single; 336 351 begin 337 352 asm 338 mov eax, v 339 movups xmm0, [eax] 340 movaps xmm1, xmm0 341 mulps xmm0, xmm0 353 {$i sseloadv.inc} 354 movaps xmm2, xmm1 355 mulps xmm2, xmm2 342 356 343 357 //mix1 344 movaps xmm7, xmm 0358 movaps xmm7, xmm2 345 359 shufps xmm7, xmm7, $4e 346 addps xmm 0, xmm7360 addps xmm2, xmm7 347 361 //mix2 348 movaps xmm7, xmm 0362 movaps xmm7, xmm2 349 363 shufps xmm7, xmm7, $11 350 addps xmm 0, xmm7351 352 movss len, xmm 0364 addps xmm2, xmm7 365 366 movss len, xmm2 353 367 end; 354 368 if (len = 0) then exit; … … 361 375 end else 362 376 asm 363 rsqrtps xmm0, xmm0 364 mulps xmm0, xmm1 //apply 365 mov eax, v 366 movups [eax], xmm0 367 end; 368 end; 369 {$endif} 370 371 {$ifdef CPUI386} 377 rsqrtps xmm2, xmm2 378 mulps xmm1, xmm2 //apply 379 {$i ssesavev.inc} 380 end; 381 end; 382 {$endif} 383 384 {$ifdef BGRASSE_AVAILABLE} 372 385 procedure Normalize3D_128_SSE3(var v: TPoint3D_128); 373 386 var len: single; 374 387 begin 375 388 asm 376 mov eax, v 377 movups xmm0, [eax] 378 movaps xmm1, xmm0 379 mulps xmm0, xmm0 380 381 haddps xmm0,xmm0 382 haddps xmm0,xmm0 383 384 movss len, xmm0 389 {$i sseloadv.inc} 390 movaps xmm2, xmm1 391 mulps xmm2, xmm2 392 393 haddps xmm2,xmm2 394 haddps xmm2,xmm2 395 396 movss len, xmm2 385 397 end; 386 398 if (len = 0) then exit; … … 393 405 end else 394 406 asm 395 rsqrtps xmm0, xmm0 396 mulps xmm0, xmm1 //apply 397 mov eax, v 398 movups [eax], xmm0 407 rsqrtps xmm2, xmm2 408 mulps xmm1, xmm2 //apply 409 {$i ssesavev.inc} 399 410 end; 400 411 end; … … 404 415 var InvLen: single; 405 416 begin 406 {$ifdef CPUI386}417 {$ifdef BGRASSE_AVAILABLE} 407 418 if UseSSE then 408 419 begin 409 420 asm 410 mov eax, v 411 movups xmm0, [eax] 412 movaps xmm1, xmm0 413 mulps xmm0, xmm0 421 {$i sseloadv.inc} 422 movaps xmm2, xmm1 423 mulps xmm2, xmm2 414 424 end; 415 425 if UseSSE3 then 416 426 asm 417 haddps xmm 0,xmm0418 haddps xmm 0,xmm0419 movss SqLen, xmm 0427 haddps xmm2,xmm2 428 haddps xmm2,xmm2 429 movss SqLen, xmm2 420 430 end else 421 431 asm 422 432 //mix1 423 movaps xmm7, xmm 0433 movaps xmm7, xmm2 424 434 shufps xmm7, xmm7, $4e 425 addps xmm 0, xmm7435 addps xmm2, xmm7 426 436 //mix2 427 movaps xmm7, xmm 0437 movaps xmm7, xmm2 428 438 shufps xmm7, xmm7, $11 429 addps xmm 0, xmm7430 movss SqLen, xmm 0439 addps xmm2, xmm7 440 movss SqLen, xmm2 431 441 end; 432 442 if SqLen = 0 then exit; … … 439 449 end else 440 450 asm 441 rsqrtps xmm0, xmm0 442 mulps xmm0, xmm1 //apply 443 mov eax, v 444 movups [eax], xmm0 451 rsqrtps xmm2, xmm2 452 mulps xmm1, xmm2 //apply 453 {$i ssesavev.inc} 445 454 end; 446 455 end … … 465 474 end; 466 475 467 {$ifdef CPUI386} 468 procedure VectProduct3D_128_SSE(const u,v: TPoint3D_128; out w: TPoint3D_128); assembler; 469 asm 470 mov eax, u 471 movups xmm6, [eax] 476 {$ifdef BGRASSE_AVAILABLE} 477 procedure VectProduct3D_128_SSE(constref u,v: TPoint3D_128; out w: TPoint3D_128); assembler; 478 asm 479 {$ifdef cpux86_64} 480 mov rax,u 481 movups xmm6,[rax] 482 {$else} 483 mov eax,u 484 movups xmm6,[eax] 485 {$endif} 472 486 movaps xmm4, xmm6 473 487 shufps xmm6, xmm6, Shift231 474 488 475 mov eax, v 476 movups xmm7, [eax] 489 {$ifdef cpux86_64} 490 mov rax,v 491 movups xmm7,[rax] 492 {$else} 493 mov eax,v 494 movups xmm7,[eax] 495 {$endif} 477 496 movaps xmm5,xmm7 478 497 shufps xmm7, xmm7, Shift312 … … 487 506 subps xmm3,xmm4 488 507 508 {$ifdef cpux86_64} 509 mov rax,w 510 movups [rax],xmm3 511 {$else} 489 512 mov eax,w 490 movups [eax], xmm3 513 movups [eax],xmm3 514 {$endif} 491 515 end; 492 516 {$endif} … … 496 520 {$hints off} 497 521 constructor TMemoryBlockAlign128.Create(size: integer); 498 {$IFDEF CPUI386}522 {$IFDEF BGRASSE_AVAILABLE} 499 523 var 500 delta: cardinal;524 delta: PtrUInt; 501 525 begin 502 526 getmem(FContainer, size+15); 503 delta := cardinal(FContainer) and 15;527 delta := PtrUInt(FContainer) and 15; 504 528 if delta <> 0 then delta := 16-delta; 505 529 FData := pbyte(FContainer)+delta; … … 519 543 end; 520 544 521 {$ifdef CPUI386} {$ASMMODE ATT}545 {$ifdef BGRASSE_AVAILABLE} 522 546 function sse3_support : boolean; 523 547 … … 526 550 527 551 begin 552 {$IFDEF CPUI386} 528 553 if cpuid_support then 529 554 begin 530 555 asm 531 push l %ebx532 mov l $1,%eax556 push ebx 557 mov eax,1 533 558 cpuid 534 mov l %ecx,_ecx535 pop l %ebx559 mov _ecx,ecx 560 pop ebx 536 561 end; 537 562 sse3_support:=(_ecx and 1)<>0; … … 539 564 else 540 565 sse3_support:=false; 566 {$ELSE} 567 asm 568 push rbx 569 mov eax,1 570 cpuid 571 mov _ecx,ecx 572 pop rbx 573 end; 574 sse3_support:=(_ecx and 1)<>0; 575 {$ENDIF} 541 576 end; 542 577 {$endif} … … 546 581 {$ifdef CPUI386} 547 582 UseSSE := is_sse_cpu and FLAG_ENABLED_SSE; 583 {$else} 584 {$ifdef cpux86_64} 585 UseSSE := FLAG_ENABLED_SSE; 586 {$else} 587 UseSSE := false; 588 {$endif} 589 {$endif} 590 591 {$IFDEF BGRASSE_AVAILABLE} 548 592 if UseSSE then 549 593 begin 594 {$ifdef cpux86_64} 595 UseSSE2 := true; 596 {$else} 550 597 UseSSE2 := is_sse2_cpu; 598 {$endif} 551 599 UseSSE3 := sse3_support; 552 600 … … 565 613 end 566 614 else 567 {$ endif}615 {$ENDIF} 568 616 begin 569 617 UseSSE := false; -
GraphicTest/Packages/bgrabitmap/bgratext.pas
r452 r472 5 5 interface 6 6 7 { Text functions use a temporary bitmap where the operating system text drawing is used. 7 { 8 Font rendering units : BGRAText, BGRATextFX, BGRAVectorize, BGRAFreeType 9 10 This unit provides basic text rendering functions using LCL, and general 11 text definitions. 12 13 Text functions use a temporary bitmap where the operating system text drawing is used. 8 14 Then it is scaled down (if antialiasing is activated), and colored. 9 15 10 These routines are rather slow. } 16 These routines are rather slow, so you may use other font renderers 17 like TBGRATextEffectFontRenderer in BGRATextFX if you want to use LCL fonts, 18 or, if you have TrueType fonts files, you may use TBGRAFreeTypeFontRenderer 19 in BGRAFreeType. } 11 20 12 21 uses 13 Classes, Types, SysUtils, Graphics, BGRABitmapTypes; 14 15 procedure BGRATextOut(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; s: string; 22 Classes, Types, SysUtils, Graphics, BGRABitmapTypes, InterfaceBase, BGRAPen, BGRAGrayscaleMask; 23 24 type 25 TWordBreakHandler = procedure(var ABeforeUTF8, AAfterUTF8: string) of object; 26 27 { TCustomLCLFontRenderer } 28 29 TCustomLCLFontRenderer = class(TBGRACustomFontRenderer) 30 protected 31 FFont: TFont; //font parameters 32 FWordBreakHandler: TWordBreakHandler; 33 procedure UpdateFont; virtual; 34 function TextSizeNoUpdateFont(sUTF8: string): TSize; 35 procedure InternalTextWordBreak(ADest: TBGRACustomBitmap; ATextUTF8: string; x, y, AMaxWidth: integer; AColor: TBGRAPixel; ATexture: IBGRAScanner; AHorizAlign: TAlignment; AVertAlign: TTextLayout); 36 procedure InternalTextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel; ATexture: IBGRAScanner); 37 public 38 procedure SplitText(var ATextUTF8: string; AMaxWidth: integer; out ARemainsUTF8: string); 39 function GetFontPixelMetric: TFontPixelMetric; override; 40 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); override; 41 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); override; 42 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); override; 43 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); override; 44 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); override; 45 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); override; 46 procedure TextWordBreak(ADest: TBGRACustomBitmap; AText: string; x, y, AMaxWidth: integer; AColor: TBGRAPixel; AHorizAlign: TAlignment; AVertAlign: TTextLayout); 47 procedure TextWordBreak(ADest: TBGRACustomBitmap; AText: string; x, y, AMaxWidth: integer; ATexture: IBGRAScanner; AHorizAlign: TAlignment; AVertAlign: TTextLayout); 48 function TextSize(sUTF8: string): TSize; override; 49 constructor Create; 50 destructor Destroy; override; 51 property OnWordBreak: TWordBreakHandler read FWordBreakHandler write FWordBreakHandler; 52 end; 53 54 { TLCLFontRenderer } 55 56 TLCLFontRenderer = class(TCustomLCLFontRenderer) 57 protected 58 function TextSurfaceSmaller(sUTF8: string; ARect: TRect): boolean; 59 public 60 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); override; 61 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); override; 62 end; 63 64 function CleanTextOutString(s: string): string; //this works with UTF8 strings as well 65 function RemoveLineEnding(var s: string; indexByte: integer): boolean; //this works with UTF8 strings however the index is the byte index 66 function RemoveLineEndingUTF8(var sUTF8: string; indexUTF8: integer): boolean; 67 68 procedure BGRATextOut(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; sUTF8: string; 16 69 c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0); 17 70 18 procedure BGRATextOutAngle(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; orientation : integer;19 s : string; c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0);71 procedure BGRATextOutAngle(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; orientationTenthDegCCW: integer; 72 sUTF8: string; c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0); 20 73 21 74 procedure BGRATextRect(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; ARect: TRect; x, y: integer; 22 s: string; style: TTextStyle; c: TBGRAPixel; tex: IBGRAScanner; CustomAntialiasingLevel: Integer = 0); 23 24 function BGRATextSize(Font: TFont; Quality: TBGRAFontQuality; s: string; CustomAntialiasingLevel: Integer): TSize; 25 26 function BGRAOriginalTextSize(Font: TFont; Quality: TBGRAFontQuality; s: string; CustomAntialiasingLevel: integer): TSize; 27 28 function GetFontHeightSign(AFont: TFont): integer; 75 sUTF8: string; style: TTextStyle; c: TBGRAPixel; tex: IBGRAScanner; CustomAntialiasingLevel: Integer = 0); 76 77 function BGRATextSize(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: Integer): TSize; 78 function BGRAOriginalTextSize(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: integer): TSize; 79 function BGRAOriginalTextSizeEx(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: Integer; out actualAntialiasingLevel: integer): TSize; 80 procedure BGRADefaultWordBreakHandler(var ABefore,AAfter: string); 81 82 function BGRATextUnderline(ATopLeft: TPointF; AWidth: Single; AMetrics: TFontPixelMetric): ArrayOfTPointF; overload; 83 function BGRATextUnderline(ATopLeft: TPointF; AWidth: Single; ABaseline, AEmHeight: single): ArrayOfTPointF; overload; 84 function BGRATextStrikeOut(ATopLeft: TPointF; AWidth: Single; AMetrics: TFontPixelMetric): ArrayOfTPointF; overload; 85 function BGRATextStrikeOut(ATopLeft: TPointF; AWidth: Single; ABaseline, AEmHeight, AXHeight: single): ArrayOfTPointF; overload; 86 87 function GetFontHeightSign: integer; 29 88 function FontEmHeightSign: integer; 30 89 function FontFullHeightSign: integer; 31 90 function LCLFontAvailable: boolean; 91 92 procedure BGRAFillClearTypeGrayscaleMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TGrayscaleMask; color: TBGRAPixel; texture: IBGRAScanner = nil; RGBOrder: boolean=true); 32 93 procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner = nil; RGBOrder: boolean=true); 33 94 procedure BGRAFillClearTypeRGBMask(dest: TBGRACustomBitmap; x,y: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner = nil; KeepRGBOrder: boolean=true); 34 35 const FontAntialiasingLevel = 6; 95 procedure BGRAInternalRenderText(dest: TBGRACustomBitmap; Quality: TBGRAFontQuality; grayscale: TGrayscaleMask; temp: TBGRACustomBitmap; 96 x,y,xThird: integer; c: TBGRAPixel; tex: IBGRAScanner); 97 98 const FontAntialiasingLevel = {$IFDEF LINUX}3{$ELSE}6{$ENDIF}; //linux rendering is already great 36 99 const FontDefaultQuality = fqAntialiased; 37 100 … … 40 103 implementation 41 104 42 uses Math, BGRABlend;105 uses GraphType, Math, BGRABlend, LCLProc; 43 106 44 107 const MaxPixelMetricCount = 100; 45 108 46 109 var 110 LCLFontDisabledValue: boolean; 47 111 TempBmp: TBitmap; 48 112 FontHeightSignComputed: boolean; … … 68 132 size: TSize; 69 133 begin 134 if not LCLFontAvailable then 135 begin 136 top := 0; 137 bottom := 0; 138 totalHeight := 0; 139 exit; 140 end; 70 141 size := BGRAOriginalTextSize(font,fqSystem,text,FontAntialiasingLevel); 71 142 mask := BGRABitmapFactory.Create(size.cx,size.cy,BGRABlack); … … 221 292 end; 222 293 223 function GetFontHeightSign(AFont: TFont): integer; 294 const DefaultFontHeightSign = -1; 295 296 function BGRATextUnderline(ATopLeft: TPointF; 297 AWidth: Single; AMetrics: TFontPixelMetric): ArrayOfTPointF; 298 begin 299 result := BGRATextUnderline(ATopLeft, AWidth, AMetrics.Baseline,AMetrics.Baseline-AMetrics.CapLine); 300 end; 301 302 function BGRATextUnderline(ATopLeft: TPointF; 303 AWidth: Single; ABaseline, AEmHeight: single): ArrayOfTPointF; 304 var height,y: single; 305 begin 306 height := AEmHeight*0.1; 307 y := ATopLeft.y+ABaseline+1.5*height; 308 result := ComputeWidePolylinePoints([PointF(ATopLeft.x,y), 309 PointF(ATopLeft.x+AWidth,y)],height,BGRABlack,pecFlat,pjsMiter, 310 SolidPenStyle, []); 311 end; 312 313 function BGRATextStrikeOut(ATopLeft: TPointF; AWidth: Single; 314 AMetrics: TFontPixelMetric): ArrayOfTPointF; 315 begin 316 result := BGRATextStrikeOut(ATopLeft, AWidth, AMetrics.Baseline,AMetrics.Baseline-AMetrics.CapLine,AMetrics.Baseline-AMetrics.xLine); 317 end; 318 319 function BGRATextStrikeOut(ATopLeft: TPointF; AWidth: Single; ABaseline, 320 AEmHeight, AXHeight: single): ArrayOfTPointF; 321 var height,y: single; 322 begin 323 height := AEmHeight*0.075; 324 y := ATopLeft.y+ABaseline-AXHeight*0.5; 325 result := ComputeWidePolylinePoints([PointF(ATopLeft.x,y), 326 PointF(ATopLeft.x+AWidth,y)],height,BGRABlack,pecFlat,pjsMiter, 327 SolidPenStyle, []); 328 end; 329 330 function GetFontHeightSign: integer; 224 331 var 225 332 HeightP1, HeightM1: integer; 226 333 begin 334 if LCLFontDisabledValue then 335 begin 336 result := DefaultFontHeightSign; 337 exit; 338 end; 339 227 340 if FontHeightSignComputed then 228 341 begin … … 231 344 end; 232 345 233 if tempBmp = nil then tempBmp := TBitmap.Create; 234 tempBmp.Canvas.Font.Assign(AFont); 235 tempBmp.Canvas.Font.Height := 20; 236 HeightP1 := tempBmp.Canvas.TextExtent('Hg').cy; 237 tempBmp.Canvas.Font.Height := -20; 238 HeightM1 := tempBmp.Canvas.TextExtent('Hg').cy; 239 240 if HeightP1 > HeightM1 then 241 FontHeightSignValue := 1 242 else 243 FontHeightSignValue := -1; 346 if WidgetSet.LCLPlatform = lpNoGUI then 347 begin 348 LCLFontDisabledValue:= True; 349 result := -1; 350 exit; 351 end; 352 353 try 354 if tempBmp = nil then tempBmp := TBitmap.Create; 355 tempBmp.Canvas.Font.Name := 'Arial'; 356 tempBmp.Canvas.Font.Style := []; 357 tempBmp.Canvas.Font.Height := 20; 358 HeightP1 := tempBmp.Canvas.TextExtent('Hg').cy; 359 tempBmp.Canvas.Font.Height := -20; 360 HeightM1 := tempBmp.Canvas.TextExtent('Hg').cy; 361 362 if HeightP1 > HeightM1 then 363 FontHeightSignValue := 1 364 else 365 FontHeightSignValue := -1; 366 except 367 on ex: Exception do 368 begin 369 LCLFontDisabledValue := True; 370 result := -1; 371 exit; 372 end; 373 end; 244 374 FontHeightSignComputed := true; 245 375 result := FontHeightSignValue; … … 247 377 248 378 function FontEmHeightSign: integer; 249 var f: TFont; 250 begin 251 if FontHeightSignComputed then 252 begin 253 result := FontHeightSignValue; 254 exit; 255 end; 256 f:= TFont.Create; 257 f.Name := 'Arial'; 258 result := GetFontHeightSign(f); 259 f.Free; 379 begin 380 result := GetFontHeightSign; 260 381 end; 261 382 … … 265 386 end; 266 387 267 procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean); 388 function LCLFontAvailable: boolean; 389 begin 390 if not FontHeightSignComputed then GetFontHeightSign; 391 result := not LCLFontDisabledValue; 392 end; 393 394 procedure BGRAFillClearTypeMaskPtr(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; maskData: PByte; maskPixelSize: NativeInt; maskRowSize: NativeInt; maskWidth,maskHeight: integer; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean); 268 395 var 269 396 pdest: PBGRAPixel; … … 302 429 yMask,n: integer; 303 430 a: byte; 304 pmask: PB GRAPixel;431 pmask: PByte; 305 432 dx:integer; 306 433 miny,maxy,minx,minxThird,maxx,alphaMinX,alphaMaxX,alphaLineLen: integer; … … 322 449 323 450 begin 324 alphaLineLen := mask .Width+2;451 alphaLineLen := maskWidth+2; 325 452 326 453 xThird -= 1; //for first subpixel … … 333 460 if y >= dest.ClipRect.Top then miny := 0 334 461 else miny := dest.ClipRect.Top-y; 335 if y+mask .Height-1 < dest.ClipRect.Bottom then336 maxy := mask .Height-1 else462 if y+maskHeight-1 < dest.ClipRect.Bottom then 463 maxy := maskHeight-1 else 337 464 maxy := dest.ClipRect.Bottom-1-y; 338 465 … … 351 478 end; 352 479 353 if x*3+xThird+mask .Width-1 < dest.ClipRect.Right*3 then354 begin 355 maxx := (x*3+xThird+mask .Width-1) div 3;480 if x*3+xThird+maskWidth-1 < dest.ClipRect.Right*3 then 481 begin 482 maxx := (x*3+xThird+maskWidth-1) div 3; 356 483 alphaMaxX := alphaLineLen-1; 357 484 rightOnSide := false; … … 373 500 if leftOnSide then 374 501 begin 375 pmask := mask .ScanLine[yMask]+(alphaMinX-1);376 a := pmask^ .greendiv 3;502 pmask := maskData + (yMask*maskRowSize)+ (alphaMinX-1)*maskPixelSize; 503 a := pmask^ div 3; 377 504 v1 := a+a; 378 505 v2 := a; 379 506 v3 := 0; 380 inc(pmask );507 inc(pmask, maskPixelSize); 381 508 end else 382 509 begin 383 pmask := mask .ScanLine[yMask];510 pmask := maskData + (yMask*maskRowSize); 384 511 v1 := 0; 385 512 v2 := 0; … … 389 516 for n := countBetween-1 downto 0 do 390 517 begin 391 a := pmask^ .greendiv 3;518 a := pmask^ div 3; 392 519 v1 += a; 393 520 v2 += a; 394 521 v3 += a; 395 inc(pmask );522 inc(pmask, maskPixelSize); 396 523 397 524 NextAlpha(v1); … … 403 530 if rightOnSide then 404 531 begin 405 a := pmask^ .greendiv 3;532 a := pmask^ div 3; 406 533 v1 += a; 407 534 v2 += a+a; … … 414 541 end; 415 542 end; 543 end; 544 545 procedure BGRAFillClearTypeGrayscaleMask(dest: TBGRACustomBitmap; x, 546 y: integer; xThird: integer; mask: TGrayscaleMask; color: TBGRAPixel; 547 texture: IBGRAScanner; RGBOrder: boolean); 548 var delta: NativeInt; 549 begin 550 delta := mask.Width; 551 BGRAFillClearTypeMaskPtr(dest,x,y,xThird,mask.ScanLine[0],1,delta,mask.Width,mask.Height,color,texture,RGBOrder); 552 end; 553 554 procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean); 555 var delta: NativeInt; 556 begin 557 delta := mask.Width*sizeof(TBGRAPixel); 558 if mask.LineOrder = riloBottomToTop then 559 delta := -delta; 560 BGRAFillClearTypeMaskPtr(dest,x,y,xThird,pbyte(mask.ScanLine[0])+1,sizeof(TBGRAPixel),delta,mask.Width,mask.Height,color,texture,RGBOrder); 416 561 end; 417 562 … … 466 611 end; 467 612 468 function BGRAOriginalTextSize(Font: TFont; Quality: TBGRAFontQuality; s: string; CustomAntialiasingLevel: Integer): TSize; 469 begin 470 if tempBmp = nil then tempBmp := TBitmap.Create; 471 tempBmp.Canvas.Font := Font; 472 if Quality in[fqFineClearTypeBGR,fqFineClearTypeRGB,fqFineAntialiasing] then tempBmp.Canvas.Font.Height := Font.Height*CustomAntialiasingLevel else 473 tempBmp.Canvas.Font.Height := Font.Height; 474 Result.cx := 0; 475 Result.cy := 0; 476 tempBmp.Canvas.Font.GetTextSize(s, Result.cx, Result.cy); 477 end; 478 479 function BGRATextSize(Font: TFont; Quality: TBGRAFontQuality; s: string; CustomAntialiasingLevel: Integer): TSize; 480 begin 481 result := BGRAOriginalTextSize(Font, Quality, s, CustomAntialiasingLevel); 613 function BGRAOriginalTextSizeEx(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: Integer; out actualAntialiasingLevel: integer): TSize; 614 begin 615 actualAntialiasingLevel:= CustomAntialiasingLevel; 616 if not LCLFontAvailable then 617 result := Size(0,0) 618 else 619 begin 620 try 621 if tempBmp = nil then tempBmp := TBitmap.Create; 622 tempBmp.Canvas.Font := Font; 623 if Quality in[fqFineClearTypeBGR,fqFineClearTypeRGB,fqFineAntialiasing] then 624 begin 625 tempBmp.Canvas.Font.Height := Font.Height*CustomAntialiasingLevel; 626 end else 627 begin 628 tempBmp.Canvas.Font.Height := Font.Height; 629 actualAntialiasingLevel:= 1; 630 end; 631 Result.cx := 0; 632 Result.cy := 0; 633 tempBmp.Canvas.Font.GetTextSize(sUTF8, Result.cx, Result.cy); 634 except 635 on ex: exception do 636 begin 637 result := Size(0,0); 638 LCLFontDisabledValue := True; 639 end; 640 end; 641 642 end; 643 end; 644 645 function BGRAOriginalTextSize(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: Integer): TSize; 646 var actualAntialiasingLevel: integer; 647 begin 648 result := BGRAOriginalTextSizeEx(Font, Quality, sUTF8, CustomAntialiasingLevel, actualAntialiasingLevel); 649 end; 650 651 procedure BGRADefaultWordBreakHandler(var ABefore, AAfter: string); 652 var p: integer; 653 begin 654 if (AAfter <> '') and (ABefore <> '') and (AAfter[1]<> ' ') and (ABefore[length(ABefore)] <> ' ') then 655 begin 656 p := length(ABefore); 657 while (p > 1) and (ABefore[p-1] <> ' ') do dec(p); 658 if p > 1 then //can put the word after 659 begin 660 AAfter := copy(ABefore,p,length(ABefore)-p+1)+AAfter; 661 ABefore := copy(ABefore,1,p-1); 662 end else 663 begin //cannot put the word after, so before 664 665 end; 666 end; 667 while (ABefore <> '') and (ABefore[length(ABefore)] =' ') do delete(ABefore,length(ABefore),1); 668 while (AAfter <> '') and (AAfter[1] =' ') do delete(AAfter,1,1); 669 end; 670 671 function BGRATextSize(Font: TFont; Quality: TBGRAFontQuality; sUTF8: string; CustomAntialiasingLevel: Integer): TSize; 672 begin 673 result := BGRAOriginalTextSize(Font, Quality, sUTF8, CustomAntialiasingLevel); 482 674 if Quality in[fqFineClearTypeBGR,fqFineClearTypeRGB,fqFineAntialiasing] then 483 675 begin … … 488 680 489 681 procedure FilterOriginalText(Quality: TBGRAFontQuality; CustomAntialiasingLevel: Integer; var temp: TBGRACustomBitmap; 490 c: TBGRAPixel; tex: IBGRAScanner);682 out grayscaleMask: TGrayscaleMask); 491 683 var 684 n: integer; 685 maxAlpha: NativeUint; 686 pb: PByte; 687 multiplyX: integer; 492 688 resampled: TBGRACustomBitmap; 493 P: PBGRAPixel; 494 n,xb,yb,v: integer; 495 alpha, maxAlpha: integer; 496 begin 689 begin 690 grayscaleMask := nil; 497 691 case Quality of 498 fqFineClearTypeBGR,fqFineClearTypeRGB: 499 begin 692 fqFineClearTypeBGR,fqFineClearTypeRGB,fqFineAntialiasing: 693 begin 694 if Quality in [fqFineClearTypeBGR,fqFineClearTypeRGB] then multiplyX:= 3 else multiplyX:= 1; 500 695 if (temp.Height < CustomAntialiasingLevel*8) and (temp.Height >= CustomAntialiasingLevel*3) then 501 696 begin 502 697 temp.ResampleFilter := rfSpline; 503 resampled := temp.Resample(round(temp.width/CustomAntialiasingLevel*3),round(temp.Height/CustomAntialiasingLevel),rmFineResample); 698 resampled := temp.Resample(round(temp.width/CustomAntialiasingLevel*multiplyX),round(temp.Height/CustomAntialiasingLevel),rmFineResample); 699 grayscaleMask := TGrayscaleMask.Create(resampled,cGreen); 700 FreeAndNil(resampled); 504 701 end else 505 resampled := temp.Resample(round(temp.width/CustomAntialiasingLevel*3),round(temp.Height/CustomAntialiasingLevel),rmSimpleStretch); 702 grayscaleMask := TGrayscaleMask.CreateDownSample(temp, round(temp.width/CustomAntialiasingLevel*multiplyX),round(temp.Height/CustomAntialiasingLevel)); 703 FreeAndNil(temp); 506 704 507 705 maxAlpha := 0; 508 p := resampled.Data; 509 for n := resampled.NbPixels - 1 downto 0 do 510 begin 511 alpha := P^.green; 512 if alpha > maxAlpha then maxAlpha := alpha; 513 Inc(p); 706 pb := grayscaleMask.Data; 707 for n := grayscaleMask.NbPixels - 1 downto 0 do 708 begin 709 if Pb^ > maxAlpha then maxAlpha := Pb^; 710 Inc(pb); 514 711 end; 515 if maxAlpha <> 0then516 begin 517 p := resampled.Data;518 for n := resampled.NbPixels - 1 downto 0 do712 if (maxAlpha <> 0) and (maxAlpha <> 255) then 713 begin 714 pb := grayscaleMask.Data; 715 for n := grayscaleMask.NbPixels - 1 downto 0 do 519 716 begin 520 v:= integer(p^.green * 255) div maxAlpha; 521 p^.red := v; 522 p^.green := v; 523 p^.blue := v; 524 Inc(p); 717 pb^:= pb^ * 255 div maxAlpha; 718 Inc(pb); 525 719 end; 526 720 end; 527 temp.Free; 528 temp := resampled; 529 end; 530 fqFineAntialiasing: 531 begin 532 if (temp.Height < CustomAntialiasingLevel*8) and (temp.Height >= CustomAntialiasingLevel*3) then 533 begin 534 temp.ResampleFilter := rfSpline; 535 resampled := temp.Resample(round(temp.width/CustomAntialiasingLevel),round(temp.Height/CustomAntialiasingLevel),rmFineResample); 536 end else 537 resampled := temp.Resample(round(temp.width/CustomAntialiasingLevel),round(temp.Height/CustomAntialiasingLevel),rmSimpleStretch); 538 539 maxAlpha := 0; 540 if tex = nil then 541 begin 542 p := resampled.Data; 543 for n := resampled.NbPixels - 1 downto 0 do 544 begin 545 alpha := P^.green; 546 if alpha > maxAlpha then maxAlpha := alpha; 547 if alpha = 0 then 548 p^:= BGRAPixelTransparent else 549 begin 550 p^.red := c.red; 551 p^.green := c.green; 552 p^.blue := c.blue; 553 p^.alpha := alpha; 554 end; 555 Inc(p); 556 end; 557 558 if maxAlpha <> 0 then 559 begin 560 p := resampled.Data; 561 for n := resampled.NbPixels - 1 downto 0 do 562 begin 563 p^.alpha := integer(p^.alpha * c.alpha) div maxAlpha; 564 Inc(p); 565 end; 566 end; 567 end else 568 begin 569 p := resampled.Data; 570 for n := resampled.NbPixels - 1 downto 0 do 571 begin 572 alpha := P^.green; 573 if alpha > maxAlpha then maxAlpha := alpha; 574 Inc(p); 575 end; 576 if maxAlpha = 0 then 577 resampled.FillTransparent 721 end; 722 fqSystem: 723 begin 724 grayscaleMask := TGrayscaleMask.Create(temp, cGreen); 725 FreeAndNil(temp); 726 pb := grayscaleMask.Data; 727 for n := grayscaleMask.NbPixels - 1 downto 0 do 728 begin 729 pb^:= GammaExpansionTab[pb^] shr 8; 730 Inc(pb); 731 end; 732 end; 733 end; 734 end; 735 736 function CleanTextOutString(s: string): string; 737 var idxIn, idxOut: integer; 738 begin 739 setlength(result, length(s)); 740 idxIn := 1; 741 idxOut := 1; 742 while IdxIn <= length(s) do 743 begin 744 if not (s[idxIn] in[#13,#10,#9]) then //those characters are always 1 byte long so it is the same with UTF8 745 begin 746 result[idxOut] := s[idxIn]; 747 inc(idxOut); 748 end; 749 inc(idxIn); 750 end; 751 setlength(result, idxOut-1); 752 end; 753 754 function RemoveLineEnding(var s: string; indexByte: integer): boolean; 755 begin //we can ignore UTF8 character length because #13 and #10 are always 1 byte long 756 //so this function can be applied to UTF8 strings as well 757 result := false; 758 if length(s) >= indexByte then 759 begin 760 if s[indexByte] in[#13,#10] then 761 begin 762 result := true; 763 if length(s) >= indexByte+1 then 764 begin 765 if (s[indexByte+1] <> s[indexByte]) and (s[indexByte+1] in[#13,#10]) then 766 delete(s,indexByte,2) 578 767 else 579 for yb := 0 to resampled.Height-1 do 580 begin 581 p := resampled.ScanLine[yb]; 582 tex.ScanMoveTo(0,yb); 583 for xb := 0 to resampled.Width-1 do 584 begin 585 c := tex.ScanNextPixel; 586 alpha := integer(P^.green*c.alpha) div maxAlpha; 587 if alpha = 0 then 588 p^:= BGRAPixelTransparent else 589 begin 590 c.alpha := alpha; 591 p^ := c; 592 end; 593 Inc(p); 594 end; 595 end; 596 end; 597 598 temp.Free; 599 temp := resampled; 600 end; 601 fqSystem: 602 begin 603 if tex = nil then 604 begin 605 p := temp.Data; 606 for n := temp.NbPixels - 1 downto 0 do 607 begin 608 alpha := GammaExpansionTab[P^.green] shr 8; 609 alpha := (c.alpha * alpha) div (255); 610 if alpha = 0 then p^:= BGRAPixelTransparent else 611 begin 612 p^.red := c.red; 613 p^.green := c.green; 614 p^.blue := c.blue; 615 p^.alpha := alpha; 616 end; 617 Inc(p); 618 end; 619 end else 620 begin 621 for yb := 0 to temp.Height-1 do 622 begin 623 p := temp.Scanline[yb]; 624 tex.ScanMoveTo(0,yb); 625 for xb := 0 to temp.Width-1 do 626 begin 627 c := tex.ScanNextPixel; 628 alpha := GammaExpansionTab[P^.green] shr 8; 629 alpha := (c.alpha * alpha) div (255); 630 if alpha = 0 then p^:= BGRAPixelTransparent else 631 begin 632 p^.red := c.red; 633 p^.green := c.green; 634 p^.blue := c.blue; 635 p^.alpha := alpha; 636 end; 637 Inc(p); 638 end; 639 end; 640 end; 641 end; 642 end; 643 end; 644 645 procedure BGRATextOut(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; s: string; 768 delete(s,indexByte,1); 769 end 770 else 771 delete(s,indexByte,1); 772 end; 773 end; 774 end; 775 776 function RemoveLineEndingUTF8(var sUTF8: string; indexUTF8: integer): boolean; 777 var indexByte: integer; 778 pIndex: PChar; 779 begin 780 pIndex := UTF8CharStart(@sUTF8[1],length(sUTF8),indexUTF8); 781 if pIndex = nil then 782 begin 783 result := false; 784 exit; 785 end; 786 indexByte := pIndex - @sUTF8[1]; 787 result := RemoveLineEnding(sUTF8, indexByte); 788 end; 789 790 procedure BGRAInternalRenderText(dest: TBGRACustomBitmap; Quality: TBGRAFontQuality; grayscale: TGrayscaleMask; temp: TBGRACustomBitmap; 791 x,y,xThird: integer; c: TBGRAPixel; tex: IBGRAScanner); 792 begin 793 if Quality in [fqFineClearTypeBGR,fqFineClearTypeRGB,fqSystemClearType] then 794 begin 795 if grayscale <> nil then 796 BGRAFillClearTypeGrayscaleMask(dest,x,y,xThird, grayscale,c,tex,Quality=fqFineClearTypeRGB) 797 else if temp <> nil then 798 BGRAFillClearTypeRGBMask(dest,x,y, temp,c,tex); 799 end 800 else 801 begin 802 if grayscale <> nil then 803 begin 804 if tex <> nil then 805 grayscale.DrawAsAlpha(dest, x, y, tex) else 806 grayscale.DrawAsAlpha(dest, x, y, c); 807 end 808 else if temp <> nil then 809 dest.PutImage(x, y, temp, dmDrawWithTransparency); 810 end; 811 end; 812 813 procedure BGRATextOut(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; sUTF8: string; 646 814 c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0); 647 815 var … … 653 821 x,y :integer; 654 822 deltaX: single; 655 begin 823 grayscale: TGrayscaleMask; 824 sizeFactor: integer; 825 begin 826 if not LCLFontAvailable then exit; 827 656 828 if CustomAntialiasingLevel = 0 then 657 829 CustomAntialiasingLevel:= FontAntialiasingLevel; … … 659 831 if Font.Orientation mod 3600 <> 0 then 660 832 begin 661 BGRATextOutAngle(bmp,Font,Quality,xf,yf,Font.Orientation,s ,c,tex,align);662 exit; 663 end; 664 665 size := BGRAOriginalTextSize (Font,Quality,s,CustomAntialiasingLevel);833 BGRATextOutAngle(bmp,Font,Quality,xf,yf,Font.Orientation,sUTF8,c,tex,align); 834 exit; 835 end; 836 837 size := BGRAOriginalTextSizeEx(Font,Quality,sUTF8,CustomAntialiasingLevel,sizeFactor); 666 838 if (size.cx = 0) or (size.cy = 0) then 667 839 exit; … … 669 841 if (size.cy >= 144) and (Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) and (CustomAntialiasingLevel > 4) then 670 842 begin 671 BGRATextOut(bmp,Font,Quality,xf,yf,s,c,tex,align,4); 672 exit; 673 end; 674 675 if Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB] then 676 begin 677 case align of 678 taLeftJustify: ; 679 taCenter: xf -= size.cx/2/CustomAntialiasingLevel; 680 taRightJustify: xf -= size.cx/CustomAntialiasingLevel; 681 end; 682 end else 683 begin 684 case align of 685 taLeftJustify: ; 686 taCenter: xf -= size.cx/2; 687 taRightJustify: xf -= size.cx; 688 end; 843 BGRATextOut(bmp,Font,Quality,xf,yf,sUTF8,c,tex,align,4); 844 exit; 845 end; 846 847 case align of 848 taLeftJustify: ; 849 taCenter: xf -= size.cx/2/sizeFactor; 850 taRightJustify: xf -= size.cx/sizeFactor; 689 851 end; 690 852 … … 695 857 tempSize.cx := size.cx; 696 858 tempSize.cy := size.cy; 697 if Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]then698 begin 699 tempSize.cx += CustomAntialiasingLevel-1;700 tempSize.cx -= tempSize.cx mod CustomAntialiasingLevel;701 tempSize.cy += CustomAntialiasingLevel-1;702 tempSize.cy -= tempSize.cy mod CustomAntialiasingLevel;859 if sizeFactor <> 1 then 860 begin 861 tempSize.cx += sizeFactor-1; 862 tempSize.cx -= tempSize.cx mod sizeFactor; 863 tempSize.cy += sizeFactor-1; 864 tempSize.cy -= tempSize.cy mod sizeFactor; 703 865 704 866 deltaX := xf-floor(xf); … … 708 870 deltaX -= xThird/3; 709 871 end; 710 subX := round( CustomAntialiasingLevel*deltaX);872 subX := round(sizeFactor*deltaX); 711 873 x := round(floor(xf)); 712 if subX <> 0 then inc(tempSize.cx, CustomAntialiasingLevel);713 subY := round( CustomAntialiasingLevel*(yf-floor(yf)));874 if subX <> 0 then inc(tempSize.cx, sizeFactor); 875 subY := round(sizeFactor*(yf-floor(yf))); 714 876 y := round(floor(yf)); 715 if subY <> 0 then inc(tempSize.cy, CustomAntialiasingLevel);877 if subY <> 0 then inc(tempSize.cy, sizeFactor); 716 878 end else 717 879 begin … … 721 883 722 884 xMargin := size.cy div 2; 723 if Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]then724 begin 725 xMargin += CustomAntialiasingLevel-1;726 xMargin -= xMargin mod CustomAntialiasingLevel;885 if sizeFactor <> 1 then 886 begin 887 xMargin += sizeFactor-1; 888 xMargin -= xMargin mod sizeFactor; 727 889 end; 728 890 tempSize.cx += xMargin*2; … … 730 892 temp := bmp.NewBitmap(tempSize.cx, tempSize.cy, BGRABlack); 731 893 temp.Canvas.Font := Font; 732 if Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB] then temp.Canvas.Font.Height := Font.Height*CustomAntialiasingLevel 733 else temp.Canvas.Font.Height := Font.Height; 894 temp.Canvas.Font.Height := Font.Height*sizeFactor; 734 895 temp.Canvas.Font.Color := clWhite; 735 896 temp.Canvas.Brush.Style := bsClear; 736 temp.Canvas.TextOut(xMargin+subX, subY, s); 737 738 FilterOriginalText(Quality,CustomAntialiasingLevel, temp,c,tex); 739 740 if Quality in [fqFineClearTypeBGR,fqFineClearTypeRGB] then 741 BGRAFillClearTypeMask(bmp,x-round(xMargin/CustomAntialiasingLevel),y,xThird, temp,c,tex,Quality=fqFineClearTypeRGB) 742 else 743 begin 744 if Quality = fqSystemClearType then 745 BGRAFillClearTypeRGBMask(bmp,x-xMargin,y, temp,c,tex) 746 else if Quality = fqFineAntialiasing then 747 bmp.PutImage(x-round(xMargin/CustomAntialiasingLevel), y, temp, dmDrawWithTransparency) 748 else bmp.PutImage(x-xMargin, y, temp, dmDrawWithTransparency); 749 end; 750 temp.Free; 751 end; 752 753 procedure BGRATextOutAngle(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; orientation: integer; 754 s: string; c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0); 897 temp.Canvas.TextOut(xMargin+subX, subY, sUTF8); 898 899 FilterOriginalText(Quality,CustomAntialiasingLevel, temp, grayscale); 900 dec(x,round(xMargin/sizeFactor)); 901 BGRAInternalRenderText(bmp, Quality, grayscale,temp, x,y,xThird, c,tex); 902 if temp <> nil then temp.Free; 903 if grayscale <> nil then grayscale.Free; 904 end; 905 906 procedure BGRATextOutAngle(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; xf, yf: single; 907 orientationTenthDegCCW: integer; 908 sUTF8: string; c: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; CustomAntialiasingLevel: Integer = 0); 755 909 var 756 910 x,y: integer; … … 766 920 TempFont: TFont; 767 921 oldOrientation: integer; 922 grayscale:TGrayscaleMask; 768 923 769 924 procedure rotBoundsAdd(pt: TPointF); … … 778 933 779 934 begin 935 if not LCLFontAvailable then exit; 936 780 937 if CustomAntialiasingLevel = 0 then 781 938 CustomAntialiasingLevel:= FontAntialiasingLevel; 782 939 783 if orientation mod 3600 = 0 then940 if orientationTenthDegCCW mod 3600 = 0 then 784 941 begin 785 942 oldOrientation := Font.Orientation; 786 943 Font.Orientation := 0; 787 BGRATextOut(bmp,Font,Quality,xf,yf,s ,c,tex,align);944 BGRATextOut(bmp,Font,Quality,xf,yf,sUTF8,c,tex,align); 788 945 Font.Orientation := oldOrientation; 789 946 exit; … … 791 948 TempFont := TFont.Create; 792 949 TempFont.Assign(Font); 793 TempFont.Orientation := orientation ;950 TempFont.Orientation := orientationTenthDegCCW; 794 951 TempFont.Height := Font.Height; 795 size := BGRAOriginalTextSize (TempFont,Quality,s,CustomAntialiasingLevel);952 size := BGRAOriginalTextSizeEx(TempFont,Quality,sUTF8,CustomAntialiasingLevel,sizeFactor); 796 953 if (size.cx = 0) or (size.cy = 0) then 797 954 begin … … 799 956 exit; 800 957 end; 801 if Quality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB] then 802 sizeFactor := CustomAntialiasingLevel 803 else 804 sizeFactor := 1; 805 806 cosA := cos(orientation*Pi/1800); 807 sinA := sin(orientation*Pi/1800); 958 tempFont.Free; 959 960 cosA := cos(orientationTenthDegCCW*Pi/1800); 961 sinA := sin(orientationTenthDegCCW*Pi/1800); 808 962 TopRight := PointF(cosA*size.cx,-sinA*size.cx); 809 963 BottomRight := PointF(cosA*size.cx+sinA*size.cy,cosA*size.cy-sinA*size.cx); … … 843 997 temp.Canvas.Font := Font; 844 998 temp.Canvas.Font.Color := clWhite; 845 temp.Canvas.Font.Orientation := orientation ;999 temp.Canvas.Font.Orientation := orientationTenthDegCCW; 846 1000 temp.Canvas.Font.Height := round(Font.Height*sizeFactor); 847 1001 temp.Canvas.Brush.Style := bsClear; 848 temp.Canvas.TextOut(-rotBounds.Left+deltaX, -rotBounds.Top+deltaY, s); 849 850 FilterOriginalText(Quality,CustomAntialiasingLevel,temp,c,tex); 851 852 if Quality in [fqFineClearTypeRGB,fqFineClearTypeBGR] then 853 BGRAFillClearTypeMask(bmp, x, y, 0, temp, c,tex,Quality = fqFineClearTypeRGB) else 854 begin 855 if Quality = fqSystemClearType then 856 BGRAFillClearTypeRGBMask(bmp, x, y, temp, c,tex) 857 else 858 bmp.PutImage(x, y, temp, dmDrawWithTransparency); 859 end; 1002 temp.Canvas.TextOut(-rotBounds.Left+deltaX, -rotBounds.Top+deltaY, sUTF8); 1003 1004 FilterOriginalText(Quality,CustomAntialiasingLevel,temp,grayscale); 1005 BGRAInternalRenderText(bmp, Quality, grayscale,temp, x,y,0, c,tex); 860 1006 temp.Free; 861 tempFont.Free;1007 grayscale.Free; 862 1008 end; 863 1009 864 1010 procedure BGRATextRect(bmp: TBGRACustomBitmap; Font: TFont; Quality: TBGRAFontQuality; ARect: TRect; x, y: integer; 865 s : string; style: TTextStyle; c: TBGRAPixel; tex: IBGRAScanner; CustomAntialiasingLevel: Integer = 0);1011 sUTF8: string; style: TTextStyle; c: TBGRAPixel; tex: IBGRAScanner; CustomAntialiasingLevel: Integer = 0); 866 1012 var 867 1013 lim: TRect; … … 870 1016 sizeFactor: integer; 871 1017 cr: TRect; 872 begin 1018 grayscale:TGrayscaleMask; 1019 begin 1020 if not LCLFontAvailable then exit; 1021 873 1022 if CustomAntialiasingLevel = 0 then 874 1023 CustomAntialiasingLevel:= FontAntialiasingLevel; … … 901 1050 temp.Canvas.Font.Color := clWhite; 902 1051 temp.Canvas.Brush.Style := bsClear; 903 temp.Canvas.TextRect(rect(lim.Left-ARect.Left, lim.Top-ARect.Top, (ARect.Right-ARect.Left)*sizeFactor, (ARect.Bottom-ARect.Top)*sizeFactor), (x - lim.Left)*sizeFactor, (y - lim.Top)*sizeFactor, s, style); 904 905 FilterOriginalText(Quality,CustomAntialiasingLevel,temp,c,tex); 906 if Quality in [fqFineClearTypeBGR,fqFineClearTypeRGB] then 907 BGRAFillClearTypeMask(bmp,lim.Left, lim.Top, 0, temp, c,tex,Quality = fqFineClearTypeRGB) 908 else if Quality = fqSystemClearType then 909 BGRAFillClearTypeRGBMask(bmp,lim.Left, lim.Top, temp, c,tex) 1052 temp.Canvas.TextRect(rect(lim.Left-ARect.Left, lim.Top-ARect.Top, (ARect.Right-ARect.Left)*sizeFactor, (ARect.Bottom-ARect.Top)*sizeFactor), (x - lim.Left)*sizeFactor, (y - lim.Top)*sizeFactor, sUTF8, style); 1053 1054 FilterOriginalText(Quality,CustomAntialiasingLevel,temp,grayscale); 1055 BGRAInternalRenderText(bmp, Quality, grayscale,temp, lim.left,lim.top,0, c,tex); 1056 temp.Free; 1057 grayscale.Free; 1058 end; 1059 1060 { TLCLFontRenderer } 1061 1062 function TLCLFontRenderer.TextSurfaceSmaller(sUTF8: string; ARect: TRect): boolean; 1063 begin 1064 with TextSize(sUTF8) do 1065 result := cx*cy < (ARect.Right-ARect.Left)*(ARect.Bottom-ARect.Top); 1066 end; 1067 1068 procedure TLCLFontRenderer.TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, 1069 y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); 1070 begin 1071 if not style.Clipping or TextSurfaceSmaller(sUTF8,ARect) then 1072 begin 1073 InternalTextRect(ADest,ARect,x,y,sUTF8,style,c,nil); 1074 exit; 1075 end; 1076 UpdateFont; 1077 BGRAText.BGRATextRect(ADest,FFont,FontQuality,ARect,x,y,sUTF8,style,c,nil); 1078 end; 1079 1080 procedure TLCLFontRenderer.TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, 1081 y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); 1082 begin 1083 if not style.Clipping or TextSurfaceSmaller(sUTF8,ARect) then 1084 begin 1085 InternalTextRect(ADest,ARect,x,y,sUTF8,style,BGRAPixelTransparent,texture); 1086 exit; 1087 end; 1088 UpdateFont; 1089 BGRAText.BGRATextRect(ADest,FFont,FontQuality,ARect,x,y,sUTF8,style,BGRAPixelTransparent,texture); 1090 end; 1091 1092 { TCustomLCLFontRenderer } 1093 1094 { Update font properties to internal TFont object } 1095 procedure TCustomLCLFontRenderer.UpdateFont; 1096 begin 1097 if FFont.Name <> FontName then 1098 FFont.Name := FontName; 1099 if FFont.Style <> FontStyle then 1100 FFont.Style := FontStyle; 1101 if FFont.Height <> FontEmHeight * FontEmHeightSign then 1102 FFont.Height := FontEmHeight * FontEmHeightSign; 1103 if FFont.Orientation <> FontOrientation then 1104 FFont.Orientation := FontOrientation; 1105 if FontQuality = fqSystemClearType then 1106 FFont.Quality := fqCleartype 910 1107 else 911 bmp.PutImage(lim.Left, lim.Top, temp, dmDrawWithTransparency); 912 temp.Free; 1108 FFont.Quality := FontDefaultQuality; 1109 end; 1110 1111 function TCustomLCLFontRenderer.TextSizeNoUpdateFont(sUTF8: string): TSize; 1112 begin 1113 result := BGRAText.BGRATextSize(FFont,FontQuality,sUTF8,FontAntialiasingLevel); 1114 if (result.cy >= 24) and (FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) then 1115 result := BGRAText.BGRATextSize(FFont,FontQuality,sUTF8,4); 1116 end; 1117 1118 procedure TCustomLCLFontRenderer.SplitText(var ATextUTF8: string; 1119 AMaxWidth: integer; out ARemainsUTF8: string); 1120 var p,totalWidth: integer; 1121 begin 1122 if ATextUTF8= '' then 1123 begin 1124 ARemainsUTF8 := ''; 1125 exit; 1126 end; 1127 if RemoveLineEnding(ATextUTF8,1) then 1128 begin 1129 ARemainsUTF8:= ATextUTF8; 1130 ATextUTF8 := ''; 1131 exit; 1132 end; 1133 UpdateFont; 1134 1135 p := 1; 1136 inc(p, UTF8CharacterLength(@ATextUTF8[p])); //UTF8 chars may be more than 1 byte long 1137 while p < length(ATextUTF8)+1 do 1138 begin 1139 if RemoveLineEnding(ATextUTF8,p) then 1140 begin 1141 ARemainsUTF8:= copy(ATextUTF8,p,length(ATextUTF8)-p+1); 1142 ATextUTF8 := copy(ATextUTF8,1,p-1); 1143 exit; 1144 end; 1145 totalWidth := TextSizeNoUpdateFont(copy(ATextUTF8,1,p+UTF8CharacterLength(@ATextUTF8[p])-1)).cx; //copy whole last UTF8 char 1146 if totalWidth > AMaxWidth then 1147 begin 1148 ARemainsUTF8:= copy(ATextUTF8,p,length(ATextUTF8)-p+1); 1149 ATextUTF8 := copy(ATextUTF8,1,p-1); //this includes the whole last UTF8 char 1150 if Assigned(FWordBreakHandler) then 1151 FWordBreakHandler(ATextUTF8,ARemainsUTF8) else 1152 BGRADefaultWordBreakHandler(ATextUTF8,ARemainsUTF8); 1153 exit; 1154 end; 1155 inc(p, UTF8CharacterLength(@ATextUTF8[p])); 1156 end; 1157 ARemainsUTF8 := ''; 1158 end; 1159 1160 function TCustomLCLFontRenderer.GetFontPixelMetric: TFontPixelMetric; 1161 var fxFont: TFont; 1162 begin 1163 UpdateFont; 1164 if FontQuality in[fqSystem,fqSystemClearType] then 1165 result := BGRAText.GetFontPixelMetric(FFont) 1166 else 1167 begin 1168 FxFont := TFont.Create; 1169 FxFont.Assign(FFont); 1170 FxFont.Height := fxFont.Height*FontAntialiasingLevel; 1171 Result:= BGRAText.GetFontPixelMetric(FxFont); 1172 if Result.Baseline <> -1 then Result.Baseline:= round((Result.Baseline-1)/FontAntialiasingLevel); 1173 if Result.CapLine <> -1 then Result.CapLine:= round(Result.CapLine/FontAntialiasingLevel); 1174 if Result.DescentLine <> -1 then Result.DescentLine:= round((Result.DescentLine-1)/FontAntialiasingLevel); 1175 if Result.Lineheight <> -1 then Result.Lineheight:= round(Result.Lineheight/FontAntialiasingLevel); 1176 if Result.xLine <> -1 then Result.xLine:= round(Result.xLine/FontAntialiasingLevel); 1177 FxFont.Free; 1178 end; 1179 end; 1180 1181 procedure TCustomLCLFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; 1182 sUTF8: string; c: TBGRAPixel; align: TAlignment); 1183 begin 1184 UpdateFont; 1185 BGRAText.BGRATextOutAngle(ADest,FFont,FontQuality,x,y,orientationTenthDegCCW,sUTF8,c,nil,align); 1186 end; 1187 1188 procedure TCustomLCLFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; 1189 sUTF8: string; texture: IBGRAScanner; align: TAlignment); 1190 begin 1191 UpdateFont; 1192 BGRAText.BGRATextOutAngle(ADest,FFont,FontQuality,x,y,orientationTenthDegCCW,sUTF8,BGRAPixelTransparent,texture,align); 1193 end; 1194 1195 procedure TCustomLCLFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; 1196 texture: IBGRAScanner; align: TAlignment); 1197 var mode : TBGRATextOutImproveReadabilityMode; 1198 begin 1199 UpdateFont; 1200 1201 if Assigned(BGRATextOutImproveReadabilityProc) and (FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) and (FFont.Orientation mod 3600 = 0) then 1202 begin 1203 case FontQuality of 1204 fqFineClearTypeBGR: mode := irClearTypeBGR; 1205 fqFineClearTypeRGB: mode := irClearTypeRGB; 1206 else 1207 mode := irNormal; 1208 end; 1209 BGRATextOutImproveReadabilityProc(ADest,FFont,x,y,sUTF8,BGRAPixelTransparent,texture,align,mode); 1210 end else 1211 BGRAText.BGRATextOut(ADest,FFont,FontQuality,x,y,sUTF8,BGRAPixelTransparent,texture,align); 1212 end; 1213 1214 procedure TCustomLCLFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; 1215 align: TAlignment); 1216 var mode : TBGRATextOutImproveReadabilityMode; 1217 begin 1218 UpdateFont; 1219 1220 if Assigned(BGRATextOutImproveReadabilityProc) and (FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]) and (FFont.Orientation mod 3600 = 0) then 1221 begin 1222 case FontQuality of 1223 fqFineClearTypeBGR: mode := irClearTypeBGR; 1224 fqFineClearTypeRGB: mode := irClearTypeRGB; 1225 else 1226 mode := irNormal; 1227 end; 1228 BGRATextOutImproveReadabilityProc(ADest,FFont,x,y,sUTF8,c,nil,align,mode); 1229 end else 1230 BGRAText.BGRATextOut(ADest,FFont,FontQuality,x,y,sUTF8,c,nil,align); 1231 end; 1232 1233 procedure TCustomLCLFontRenderer.TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; 1234 style: TTextStyle; c: TBGRAPixel); 1235 begin 1236 InternalTextRect(ADest,ARect,x,y,sUTF8,style,c,nil); 1237 end; 1238 1239 procedure TCustomLCLFontRenderer.TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; 1240 style: TTextStyle; texture: IBGRAScanner); 1241 begin 1242 InternalTextRect(ADest,ARect,x,y,sUTF8,style,BGRAPixelTransparent,texture); 1243 end; 1244 1245 procedure TCustomLCLFontRenderer.TextWordBreak(ADest: TBGRACustomBitmap; 1246 AText: string; x, y, AMaxWidth: integer; AColor: TBGRAPixel; 1247 AHorizAlign: TAlignment; AVertAlign: TTextLayout); 1248 begin 1249 InternalTextWordBreak(ADest,AText,x,y,AMaxWidth,AColor,nil,AHorizAlign,AVertAlign); 1250 end; 1251 1252 procedure TCustomLCLFontRenderer.TextWordBreak(ADest: TBGRACustomBitmap; 1253 AText: string; x, y, AMaxWidth: integer; ATexture: IBGRAScanner; 1254 AHorizAlign: TAlignment; AVertAlign: TTextLayout); 1255 begin 1256 InternalTextWordBreak(ADest,AText,x,y,AMaxWidth,BGRAPixelTransparent,ATexture,AHorizAlign,AVertAlign); 1257 end; 1258 1259 procedure TCustomLCLFontRenderer.InternalTextWordBreak( 1260 ADest: TBGRACustomBitmap; ATextUTF8: string; x, y, AMaxWidth: integer; 1261 AColor: TBGRAPixel; ATexture: IBGRAScanner; AHorizAlign: TAlignment; AVertAlign: TTextLayout); 1262 var ARemains: string; 1263 stepX,stepY: integer; 1264 lines: TStringList; 1265 i: integer; 1266 lineShift: single; 1267 begin 1268 if (ATextUTF8 = '') or (AMaxWidth <= 0) then exit; 1269 1270 stepX := 0; 1271 stepY := TextSize('Hg').cy; 1272 1273 if AVertAlign = tlTop then 1274 begin 1275 repeat 1276 SplitText(ATextUTF8, AMaxWidth, ARemains); 1277 if ATexture <> nil then 1278 TextOut(ADest,x,y,ATextUTF8,ATexture,AHorizAlign) 1279 else 1280 TextOut(ADest,x,y,ATextUTF8,AColor,AHorizAlign); 1281 ATextUTF8 := ARemains; 1282 X+= stepX; 1283 Y+= stepY; 1284 until ARemains = ''; 1285 end else 1286 begin 1287 lines := TStringList.Create; 1288 repeat 1289 SplitText(ATextUTF8, AMaxWidth, ARemains); 1290 lines.Add(ATextUTF8); 1291 ATextUTF8 := ARemains; 1292 until ARemains = ''; 1293 if AVertAlign = tlCenter then lineShift := lines.Count/2 1294 else if AVertAlign = tlBottom then lineShift := lines.Count 1295 else lineShift := 0; 1296 1297 X -= round(stepX*lineShift); 1298 Y -= round(stepY*lineShift); 1299 for i := 0 to lines.Count-1 do 1300 begin 1301 if ATexture <> nil then 1302 TextOut(ADest,x,y,lines[i],ATexture,AHorizAlign) 1303 else 1304 TextOut(ADest,x,y,lines[i],AColor,AHorizAlign); 1305 X+= stepX; 1306 Y+= stepY; 1307 end; 1308 lines.Free; 1309 end; 1310 end; 1311 1312 procedure TCustomLCLFontRenderer.InternalTextRect(ADest: TBGRACustomBitmap; 1313 ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel; 1314 ATexture: IBGRAScanner); 1315 var 1316 previousClip, intersected: TRect; 1317 oldOrientation: integer; 1318 begin 1319 previousClip := ADest.ClipRect; 1320 if style.Clipping then 1321 begin 1322 intersected := rect(0,0,0,0); 1323 if not IntersectRect(intersected, previousClip, ARect) then exit; 1324 ADest.ClipRect := intersected; 1325 end; 1326 oldOrientation:= FontOrientation; 1327 FontOrientation:= 0; 1328 1329 if not (style.Alignment in[taCenter,taRightJustify]) then ARect.Left := x; 1330 if not (style.Layout in[tlCenter,tlBottom]) then ARect.top := y; 1331 if ARect.Right <= ARect.Left then exit; 1332 if style.Layout = tlCenter then Y := (ARect.Top+ARect.Bottom) div 2 else 1333 if style.Layout = tlBottom then Y := ARect.Bottom else 1334 Y := ARect.Top; 1335 if style.Alignment = taCenter then X := (ARect.Left+ARect.Right) div 2 else 1336 if style.Alignment = taRightJustify then X := ARect.Right else 1337 X := ARect.Left; 1338 if style.Wordbreak then 1339 InternalTextWordBreak(ADest,sUTF8,X,Y,ARect.Right-ARect.Left,c,ATexture,style.Alignment,style.Layout) 1340 else 1341 begin 1342 if style.Layout = tlCenter then Y -= TextSize(sUTF8).cy div 2; 1343 if style.Layout = tlBottom then Y -= TextSize(sUTF8).cy; 1344 if ATexture <> nil then 1345 TextOut(ADest,X,Y,sUTF8,ATexture,style.Alignment) 1346 else 1347 TextOut(ADest,X,Y,sUTF8,c,style.Alignment); 1348 end; 1349 1350 FontOrientation:= oldOrientation; 1351 if style.Clipping then 1352 ADest.ClipRect := previousClip; 1353 end; 1354 1355 function TCustomLCLFontRenderer.TextSize(sUTF8: string): TSize; 1356 begin 1357 UpdateFont; 1358 result := TextSizeNoUpdateFont(sUTF8); 1359 end; 1360 1361 constructor TCustomLCLFontRenderer.Create; 1362 begin 1363 FFont := TFont.Create; 1364 end; 1365 1366 destructor TCustomLCLFontRenderer.Destroy; 1367 begin 1368 FFont.Free; 1369 inherited Destroy; 913 1370 end; 914 1371 -
GraphicTest/Packages/bgrabitmap/bgratextfx.pas
r452 r472 3 3 {$mode objfpc}{$H+} 4 4 5 { 6 Font rendering units : BGRAText, BGRATextFX, BGRAVectorize, BGRAFreeType 7 8 This unit provide text effects. The simplest way to render effects is to use TBGRATextEffectFontRenderer class. 9 To do this, create an instance of this class and assign it to a TBGRABitmap.FontRenderer property. Now functions 10 to draw text like TBGRABitmap.TextOut will use the chosen renderer. To set the effects, keep a variable containing 11 the TBGRATextEffectFontRenderer class and modify ShadowVisible and other effects parameters. 12 13 The TBGRATextEffectFontRenderer class makes use of other classes depending on the situation. For example, 14 TBGRATextEffect, which is also in this unit, provides effects on a text mask. But the renderer also uses 15 BGRAVectorize unit in order to have big texts or to rotate them at will. 16 17 Note that you may need TBGRATextEffect if you want to have more control over text effects, especially 18 if you always draw the same text. Keeping the same TBGRATextEffect object will avoid creating the text 19 mask over and over again. 20 21 TextShadow function is a simple function to compute an image containing a text with shadow. 22 23 } 24 5 25 interface 6 26 7 27 uses 8 Classes, SysUtils, Graphics, Types, BGRABitmapTypes, BGRAPhongTypes ;28 Classes, SysUtils, Graphics, Types, BGRABitmapTypes, BGRAPhongTypes, BGRAText, BGRAVectorize; 9 29 10 30 type 31 TBGRATextEffect = class; 32 33 { TBGRATextEffectFontRenderer } 34 35 TBGRATextEffectFontRenderer = class(TCustomLCLFontRenderer) 36 private 37 function GetShaderLightPosition: TPoint; 38 function GetVectorizedRenderer: TBGRAVectorizedFontRenderer; 39 procedure SetShaderLightPosition(AValue: TPoint); 40 protected 41 FShaderOwner: boolean; 42 FShader: TCustomPhongShading; 43 FVectorizedRenderer: TBGRAVectorizedFontRenderer; 44 function ShadowActuallyVisible :boolean; 45 function ShaderActuallyActive: boolean; 46 function OutlineActuallyVisible: boolean; 47 procedure Init; 48 function VectorizedFontNeeded: boolean; 49 procedure InternalTextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; c: TBGRAPixel; texture: IBGRAScanner; align: TAlignment); 50 public 51 ShaderActive: boolean; 52 53 ShadowVisible: boolean; 54 ShadowColor: TBGRAPixel; 55 ShadowRadius: integer; 56 ShadowOffset: TPoint; 57 ShadowQuality: TRadialBlurType; 58 59 OutlineColor: TBGRAPixel; 60 OutlineWidth: single; 61 OutlineVisible,OuterOutlineOnly: boolean; 62 OutlineTexture: IBGRAScanner; 63 constructor Create; 64 constructor Create(AShader: TCustomPhongShading; AShaderOwner: boolean); 65 destructor Destroy; override; 66 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientation: integer; 67 s: string; texture: IBGRAScanner; align: TAlignment); override; 68 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientation: integer; 69 s: string; c: TBGRAPixel; align: TAlignment); override; 70 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; 71 texture: IBGRAScanner; align: TAlignment); override; 72 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; c: TBGRAPixel; 73 align: TAlignment); override; 74 function TextSize(sUTF8: string): TSize; override; 75 property Shader: TCustomPhongShading read FShader; 76 property ShaderLightPosition: TPoint read GetShaderLightPosition write SetShaderLightPosition; 77 property VectorizedFontRenderer: TBGRAVectorizedFontRenderer read GetVectorizedRenderer; 78 end; 11 79 12 80 { TBGRATextEffect } … … 14 82 TBGRATextEffect = class 15 83 private 84 FShadowQuality: TRadialBlurType; 16 85 function GetBounds: TRect; 17 function GetHeight: integer; 86 function GetMaskHeight: integer; 87 class function GetOutlineWidth: integer; static; 18 88 function GetShadowBounds(ARadius: integer): TRect; 19 function GetWidth: integer; 89 function GetMaskWidth: integer; 90 function GetTextHeight: integer; 91 function GetTextWidth: integer; 92 procedure SetShadowQuality(AValue: TRadialBlurType); 20 93 protected 21 94 FTextMask: TBGRACustomBitmap; … … 24 97 FShadingAltitude: integer; 25 98 FShadingRounded: boolean; 26 F Width,FHeight: integer;99 FTextSize: TSize; 27 100 FOffset: TPoint; 28 procedure DrawMaskMulticolored(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; const AColors: array of TBGRAPixel);29 procedure DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; AColor: TBGRAPixel);30 procedure DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; ATexture: IBGRAScanner);101 function DrawMaskMulticolored(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; const AColors: array of TBGRAPixel): TRect; 102 function DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; AColor: TBGRAPixel): TRect; 103 function DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X,Y: Integer; ATexture: IBGRAScanner): TRect; 31 104 function InternalDrawShaded(ADest: TBGRACustomBitmap; X,Y: integer; Shader: TCustomPhongShading; Altitude: integer; AColor: TBGRAPixel; ATexture: IBGRAScanner; ARounded: Boolean): TRect; 105 procedure InitImproveReadability(AText: string; Font: TFont; SubOffsetX,SubOffsetY: single); 32 106 procedure Init(AText: string; Font: TFont; Antialiasing: boolean; SubOffsetX,SubOffsetY: single; GrainX, GrainY: Integer); 107 procedure InitWithFontName(AText: string; AFontName: string; AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean; SubOffsetX,SubOffsetY: single); 33 108 public 34 109 constructor Create(AText: string; Font: TFont; Antialiasing: boolean); 35 110 constructor Create(AText: string; Font: TFont; Antialiasing: boolean; SubOffsetX,SubOffsetY: single); 36 111 constructor Create(AText: string; Font: TFont; Antialiasing: boolean; SubOffsetX,SubOffsetY: single; GrainX, GrainY: Integer); 112 constructor Create(AText: string; AFontName: string; AFullHeight: integer; Antialiasing: boolean); 113 constructor Create(AText: string; AFontName: string; AFullHeight: integer; Antialiasing: boolean; SubOffsetX,SubOffsetY: single); 114 constructor Create(AText: string; AFontName: string; AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean); 115 constructor Create(AText: string; AFontName: string; AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean; SubOffsetX,SubOffsetY: single); 116 constructor Create(AMask: TBGRACustomBitmap; AMaskOwner: boolean; AWidth,AHeight: integer; AOffset: TPoint); 37 117 procedure ApplySphere; 38 118 procedure ApplyVerticalCylinder; 39 119 procedure ApplyHorizontalCylinder; 40 procedure Draw(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel);41 procedure Draw(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner);42 procedure Draw(ADest: TBGRACustomBitmap; X, Y: integer; AColor: TBGRAPixel; AAlign: TAlignment);43 procedure Draw(ADest: TBGRACustomBitmap; X, Y: integer; ATexture: IBGRAScanner; AAlign: TAlignment);120 function Draw(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel): TRect; 121 function Draw(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner): TRect; 122 function Draw(ADest: TBGRACustomBitmap; X, Y: integer; AColor: TBGRAPixel; AAlign: TAlignment): TRect; 123 function Draw(ADest: TBGRACustomBitmap; X, Y: integer; ATexture: IBGRAScanner; AAlign: TAlignment): TRect; 44 124 45 125 function DrawShaded(ADest: TBGRACustomBitmap; X,Y: integer; Shader: TCustomPhongShading; Altitude: integer; AColor: TBGRAPixel; ARounded: Boolean = true): TRect; … … 48 128 function DrawShaded(ADest: TBGRACustomBitmap; X, Y: integer; Shader: TCustomPhongShading; Altitude: integer; ATexture: IBGRAScanner; AAlign: TAlignment; ARounded: Boolean = true): TRect; 49 129 50 procedure DrawMulticolored(ADest: TBGRACustomBitmap; X,Y: integer; const AColors: array of TBGRAPixel);51 procedure DrawMulticolored(ADest: TBGRACustomBitmap; X,Y: integer; const AColors: array of TBGRAPixel; AAlign: TAlignment);52 procedure DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel);53 procedure DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner);54 procedure DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel; AAlign: TAlignment);55 procedure DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner; AAlign: TAlignment);56 procedure DrawShadow(ADest: TBGRACustomBitmap; X,Y,Radius: integer; AColor: TBGRAPixel);57 procedure DrawShadow(ADest: TBGRACustomBitmap; X,Y,Radius: integer; AColor: TBGRAPixel; AAlign: TAlignment);130 function DrawMulticolored(ADest: TBGRACustomBitmap; X,Y: integer; const AColors: array of TBGRAPixel): TRect; 131 function DrawMulticolored(ADest: TBGRACustomBitmap; X,Y: integer; const AColors: array of TBGRAPixel; AAlign: TAlignment): TRect; 132 function DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel): TRect; 133 function DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner): TRect; 134 function DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; AColor: TBGRAPixel; AAlign: TAlignment): TRect; 135 function DrawOutline(ADest: TBGRACustomBitmap; X,Y: integer; ATexture: IBGRAScanner; AAlign: TAlignment): TRect; 136 function DrawShadow(ADest: TBGRACustomBitmap; X,Y,Radius: integer; AColor: TBGRAPixel): TRect; 137 function DrawShadow(ADest: TBGRACustomBitmap; X,Y,Radius: integer; AColor: TBGRAPixel; AAlign: TAlignment): TRect; 58 138 destructor Destroy; override; 59 139 property TextMask: TBGRACustomBitmap read FTextMask; 60 140 property TextMaskOffset: TPoint read FOffset; 61 property Width: integer read GetWidth; 62 property Height: integer read GetHeight; 141 property Width: integer read GetTextWidth; deprecated; 142 property Height: integer read GetTextHeight; deprecated; 143 property MaskWidth: integer read GetMaskWidth; 144 property MaskHeight: integer read GetMaskHeight; 145 property TextSize: TSize read FTextSize; 146 property TextWidth: integer read GetTextWidth; 147 property TextHeight: integer read GetTextHeight; 63 148 property Bounds: TRect read GetBounds; 64 149 property ShadowBounds[ARadius: integer]: TRect read GetShadowBounds; 150 property ShadowQuality: TRadialBlurType read FShadowQuality write SetShadowQuality; 151 class property OutlineWidth: integer read GetOutlineWidth; 65 152 end; 66 153 … … 68 155 AOffSetX,AOffSetY: Integer; ARadius: Integer = 0; AFontStyle: TFontStyles = []; AFontName: String = 'Default'; AShowText: Boolean = True; AFontQuality: TBGRAFontQuality = fqFineAntialiasing): TBGRACustomBitmap; 69 156 70 procedure BGRATextOutImproveReadability(bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; useClearType: boolean; ClearTypeRGBOrder: boolean);157 procedure BGRATextOutImproveReadability(bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; mode : TBGRATextOutImproveReadabilityMode); 71 158 72 159 implementation 73 160 74 uses BGRAGradientScanner, BGRAText, GraphType, Math; 75 76 procedure BGRATextOutImproveReadability(bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; useClearType: boolean; ClearTypeRGBOrder: boolean); 161 uses BGRAGradientScanner, GraphType, Math, BGRAGrayscaleMask; 162 163 const DefaultOutlineWidth = 3; 164 165 procedure BGRATextOutImproveReadability(bmp: TBGRACustomBitmap; AFont: TFont; xf,yf: single; text: string; color: TBGRAPixel; tex: IBGRAScanner; align: TAlignment; mode : TBGRATextOutImproveReadabilityMode); 77 166 var 167 useClearType,clearTypeRGBOrder: boolean; 78 168 metric: TFontPixelMetric; 79 169 deltaX: single; … … 81 171 toAdd: integer; 82 172 lines: array[0..3] of integer; 83 parts: array[0..3] of T BGRACustomBitmap;84 n,nbLines ,v: integer;85 alphaMax: byte;173 parts: array[0..3] of TGrayscaleMask; 174 n,nbLines: integer; 175 alphaMax: NativeUint; 86 176 ptrPart: TBGRACustomBitmap; 87 pmask: PB GRAPixel;177 pmask: PByte; 88 178 fx: TBGRATextEffect; 89 179 FxFont: TFont; … … 92 182 93 183 begin 184 useClearType:= mode in[irClearTypeRGB,irClearTypeBGR]; 185 clearTypeRGBOrder := mode <> irClearTypeBGR; 94 186 deltaX := xf-floor(xf); 95 187 x := round(floor(xf)); … … 105 197 begin 106 198 if ClearTypeRGBOrder then 107 BGRATextOut(bmp, AFont, fqFineClearTypeRGB, xf,yf, text, color, tex, align) else 199 BGRATextOut(bmp, AFont, fqFineClearTypeRGB, xf,yf, text, color, tex, align) 200 else 108 201 BGRATextOut(bmp, AFont, fqFineClearTypeBGR, xf,yf, text, color, tex, align) 109 202 end else … … 144 237 fx := TBGRATextEffect.Create(text,FxFont,False,deltaX*FontAntialiasingLevel,0,FontAntialiasingLevel,FontAntialiasingLevel) else 145 238 fx := TBGRATextEffect.Create(text,FxFont,False,0,0,3,0); 239 240 if fx.TextMask = nil then 241 begin 242 fx.Free; 243 FxFont.Free; 244 exit; 245 end; 146 246 alphaMax := 0; 147 247 prevCenter := 0; … … 156 256 ptrPart := fx.TextMask.GetPtrBitmap(fromy,lines[yb]); 157 257 if useClearType then 158 parts[yb] := ptrPart.Resample(round(ptrPart.Width/FontAntialiasingLevel*3),round(ptrPart.Height/FontAntialiasingLevel),rmSimpleStretch)258 parts[yb] := TGrayscaleMask.CreateDownSample(ptrPart,round(ptrPart.Width/FontAntialiasingLevel*3),round(ptrPart.Height/FontAntialiasingLevel)) 159 259 else 160 parts[yb] := ptrPart.Resample(round(ptrPart.Width/FontAntialiasingLevel),round(ptrPart.Height/FontAntialiasingLevel),rmSimpleStretch);260 parts[yb] := TGrayscaleMask.CreateDownSample(ptrPart,round(ptrPart.Width/FontAntialiasingLevel),round(ptrPart.Height/FontAntialiasingLevel)); 161 261 ptrPart.Free; 162 262 163 263 if alphaMax < 255 then 164 264 begin 165 pmask := parts[yb]. data;265 pmask := parts[yb].Data; 166 266 for n := parts[yb].NbPixels-1 downto 0 do 167 267 begin 168 v := pmask^.green; 169 if v > alphaMax then alphaMax := v; 268 if pmask^ > alphaMax then alphaMax := pmask^; 170 269 inc(pmask); 171 270 end; … … 194 293 begin 195 294 case align of 196 taCenter: xThird:= xThird+round(((fx.TextMaskOffset.x-fx. Width/2)/FontAntialiasingLevel+deltaX)*3);197 taRightJustify: xThird:= xThird+round(((fx.TextMaskOffset.x-fx. Width)/FontAntialiasingLevel+deltaX)*3);295 taCenter: xThird:= xThird+round(((fx.TextMaskOffset.x-fx.TextWidth/2)/FontAntialiasingLevel+deltaX)*3); 296 taRightJustify: xThird:= xThird+round(((fx.TextMaskOffset.x-fx.TextWidth)/FontAntialiasingLevel+deltaX)*3); 198 297 else xThird:= xThird+round((fx.TextMaskOffset.x/FontAntialiasingLevel+deltaX)*3); 199 298 end; … … 201 300 begin 202 301 case align of 203 taCenter: x:= x+round((fx.TextMaskOffset.x-fx. Width/2)/FontAntialiasingLevel);204 taRightJustify: x:= x+round((fx.TextMaskOffset.x-fx. Width)/FontAntialiasingLevel);302 taCenter: x:= x+round((fx.TextMaskOffset.x-fx.TextWidth/2)/FontAntialiasingLevel); 303 taRightJustify: x:= x+round((fx.TextMaskOffset.x-fx.TextWidth)/FontAntialiasingLevel); 205 304 else x:= x+round(fx.TextMaskOffset.x/FontAntialiasingLevel); 206 305 end; … … 215 314 for n := parts[yb].NbPixels-1 downto 0 do 216 315 begin 217 v := integer(pmask^.green)*255 div alphaMax; 218 if v > 255 then v := 255; 219 pmask^.green := v; 220 pmask^.red := v; 221 pmask^.blue := v; 316 pmask^ := pmask^*255 div alphaMax; 222 317 inc(pmask); 223 318 end; 224 319 end; 225 320 if useClearType then 321 BGRAFillClearTypeGrayscaleMask(bmp,x,cury,xThird,parts[yb],color,tex,ClearTypeRGBOrder) 322 else if mode = irMask then 323 parts[yb].Draw(bmp,x,cury) 324 else 226 325 begin 227 326 if tex <> nil then 228 bmp.FillClearTypeMask(x,cury,xThird,parts[yb],tex,ClearTypeRGBOrder) else 229 bmp.FillClearTypeMask(x,cury,xThird,parts[yb],color,ClearTypeRGBOrder); 230 end else 231 begin 232 if tex <> nil then 233 bmp.FillMask(x,cury,parts[yb],tex) else 234 bmp.FillMask(x,cury,parts[yb],color); 327 parts[yb].DrawAsAlpha(bmp,x,cury,tex) else 328 parts[yb].DrawAsAlpha(bmp,x,cury,color); 235 329 end; 236 330 inc(cury,parts[yb].Height); … … 249 343 250 344 function TextShadow(AWidth,AHeight: Integer; AText: String; AFontHeight: Integer; ATextColor,AShadowColor: TBGRAPixel; 251 AOffSetX,AOffSetY: Integer; ARadius: Integer = 0; AFontStyle: TFontStyles = []; AFontName: String = 'Default'; AShowText: Boolean = True; AFontQuality: TBGRAFontQuality = fqFineAntialiasing): TBGRACustomBitmap; 345 AOffSetX,AOffSetY: Integer; ARadius: Integer = 0; AFontStyle: TFontStyles = []; AFontName: String = 'Default'; AShowText: Boolean = True; 346 AFontQuality: TBGRAFontQuality = fqFineAntialiasing): TBGRACustomBitmap; 252 347 var 253 348 bmpOut,bmpSdw: TBGRACustomBitmap; OutTxtSize: TSize; OutX,OutY: Integer; … … 281 376 end; 282 377 378 { TBGRATextEffectFontRenderer } 379 380 function TBGRATextEffectFontRenderer.GetShaderLightPosition: TPoint; 381 begin 382 if FShader = nil then 383 result := point(0,0) 384 else 385 result := FShader.LightPosition; 386 end; 387 388 function TBGRATextEffectFontRenderer.GetVectorizedRenderer: TBGRAVectorizedFontRenderer; 389 begin 390 FVectorizedRenderer.FontEmHeight := FontEmHeight; 391 FVectorizedRenderer.FontName := FontName; 392 FVectorizedRenderer.FontOrientation:= FontOrientation; 393 FVectorizedRenderer.FontQuality := FontQuality; 394 FVectorizedRenderer.FontStyle:= FontStyle; 395 396 FVectorizedRenderer.ShadowColor := ShadowColor; 397 FVectorizedRenderer.ShadowVisible := ShadowVisible; 398 FVectorizedRenderer.ShadowOffset := ShadowOffset; 399 FVectorizedRenderer.ShadowRadius := ShadowRadius; 400 401 FVectorizedRenderer.OutlineColor := OutlineColor; 402 FVectorizedRenderer.OutlineVisible := OutlineVisible; 403 FVectorizedRenderer.OutlineWidth := OutlineWidth; 404 FVectorizedRenderer.OutlineTexture := OutlineTexture; 405 FVectorizedRenderer.OuterOutlineOnly := OuterOutlineOnly; 406 result := FVectorizedRenderer; 407 end; 408 409 procedure TBGRATextEffectFontRenderer.SetShaderLightPosition(AValue: TPoint); 410 begin 411 if FShader <> nil then 412 FShader.LightPosition := AValue; 413 end; 414 415 function TBGRATextEffectFontRenderer.ShadowActuallyVisible: boolean; 416 begin 417 result := ShadowVisible and (ShadowColor.alpha <> 0); 418 end; 419 420 function TBGRATextEffectFontRenderer.ShaderActuallyActive: boolean; 421 begin 422 result := (FShader <> nil) and ShaderActive; 423 end; 424 425 function TBGRATextEffectFontRenderer.OutlineActuallyVisible: boolean; 426 begin 427 result := (OutlineWidth <> 0) and ((OutlineTexture <> nil) or (OutlineColor.alpha <> 0)) and OutlineVisible; 428 end; 429 430 procedure TBGRATextEffectFontRenderer.Init; 431 begin 432 ShaderActive := true; 433 434 ShadowColor := BGRABlack; 435 ShadowVisible := false; 436 ShadowOffset := Point(5,5); 437 ShadowRadius := 5; 438 ShadowQuality:= rbFast; 439 440 OutlineColor := BGRAPixelTransparent; 441 OutlineVisible := True; 442 OutlineWidth:= DefaultOutlineWidth; 443 OuterOutlineOnly:= false; 444 FVectorizedRenderer := TBGRAVectorizedFontRenderer.Create; 445 end; 446 447 function TBGRATextEffectFontRenderer.VectorizedFontNeeded: boolean; 448 var bAntialiasing, bBigFont, bSpecialOutline, bOriented, bEffectVectorizedSupported: boolean; 449 textsz: TSize; 450 begin 451 bAntialiasing := FontQuality in [fqFineAntialiasing,fqFineClearTypeRGB,fqFineClearTypeBGR]; 452 textsz := inherited TextSize('Hg'); 453 bBigFont := (not OutlineActuallyVisible and (textsz.cy >= 24)) or 454 (OutlineActuallyVisible and (textsz.cy > 42)); 455 bSpecialOutline:= OutlineActuallyVisible and (abs(OutlineWidth) <> DefaultOutlineWidth); 456 bOriented := FontOrientation <> 0; 457 bEffectVectorizedSupported := OutlineActuallyVisible or ShadowActuallyVisible; 458 if ShaderActuallyActive and (FontOrientation = 0) then 459 result := false //shader not supported by vectorized font 460 else 461 result := bSpecialOutline or 462 (bAntialiasing and bBigFont) or 463 (bOriented and bEffectVectorizedSupported); 464 end; 465 466 procedure TBGRATextEffectFontRenderer.InternalTextOut(ADest: TBGRACustomBitmap; 467 x, y: single; s: string; c: TBGRAPixel; texture: IBGRAScanner; 468 align: TAlignment); 469 var fx: TBGRATextEffect; 470 procedure DoOutline; 471 begin 472 if OutlineActuallyVisible then 473 begin 474 if OutlineTexture <> nil then 475 fx.DrawOutline(ADest,round(x),round(y), OutlineTexture, align) 476 else 477 fx.DrawOutline(ADest,round(x),round(y), OutlineColor, align); 478 end; 479 end; 480 begin 481 UpdateFont; 482 if (FFont.Orientation <> 0) or (not ShaderActuallyActive and not ShadowActuallyVisible and not OutlineActuallyVisible) then 483 begin 484 if texture <> nil then 485 inherited TextOut(ADest,x,y,s,texture,align) 486 else 487 inherited TextOut(ADest,x,y,s,c,align); 488 exit; 489 end; 490 fx := TBGRATextEffect.Create(s, FFont, FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB], x-floor(x),y-floor(y)); 491 if ShadowActuallyVisible then 492 begin 493 fx.ShadowQuality := ShadowQuality; 494 fx.DrawShadow(ADest,round(x)+ShadowOffset.X,round(y)+ShadowOffset.Y,ShadowRadius,ShadowColor, align); 495 end; 496 if OuterOutlineOnly then DoOutline; 497 if texture <> nil then 498 begin 499 if ShaderActuallyActive then 500 fx.DrawShaded(ADest,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), texture, align) 501 else 502 fx.Draw(ADest,round(x),round(y), texture, align); 503 end else 504 begin 505 if ShaderActuallyActive then 506 fx.DrawShaded(ADest,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), c, align) 507 else 508 fx.Draw(ADest,round(x),round(y), c, align); 509 end; 510 if not OuterOutlineOnly then DoOutline; 511 fx.Free; 512 end; 513 514 constructor TBGRATextEffectFontRenderer.Create; 515 begin 516 inherited Create; 517 FShader := nil; 518 FShaderOwner:= false; 519 Init; 520 end; 521 522 constructor TBGRATextEffectFontRenderer.Create(AShader: TCustomPhongShading; 523 AShaderOwner: boolean); 524 begin 525 inherited Create; 526 Init; 527 FShader := AShader; 528 FShaderOwner := AShaderOwner; 529 end; 530 531 destructor TBGRATextEffectFontRenderer.Destroy; 532 begin 533 if FShaderOwner then FShader.Free; 534 FVectorizedRenderer.Free; 535 inherited Destroy; 536 end; 537 538 procedure TBGRATextEffectFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 539 y: single; orientation: integer; s: string; texture: IBGRAScanner; 540 align: TAlignment); 541 begin 542 VectorizedFontRenderer.TextOutAngle(ADest, x, y, orientation, s, texture, align); 543 end; 544 545 procedure TBGRATextEffectFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 546 y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); 547 begin 548 VectorizedFontRenderer.TextOutAngle(ADest, x, y, orientation, s, c, align); 549 end; 550 551 procedure TBGRATextEffectFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 552 y: single; s: string; texture: IBGRAScanner; align: TAlignment); 553 begin 554 if VectorizedFontNeeded then 555 VectorizedFontRenderer.TextOut(ADest,x,y,s,texture,align) 556 else 557 InternalTextOut(ADest,x,y,s,BGRAPixelTransparent,texture,align); 558 end; 559 560 procedure TBGRATextEffectFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 561 y: single; s: string; c: TBGRAPixel; align: TAlignment); 562 begin 563 if VectorizedFontNeeded then 564 VectorizedFontRenderer.TextOut(ADest,x,y,s,c,align) 565 else 566 InternalTextOut(ADest,x,y,s,c,nil,align); 567 end; 568 569 function TBGRATextEffectFontRenderer.TextSize(sUTF8: string): TSize; 570 begin 571 if VectorizedFontNeeded then 572 result := VectorizedFontRenderer.TextSize(sUTF8) 573 else 574 begin 575 result := inherited TextSize(sUTF8); 576 end; 577 end; 578 283 579 { TBGRATextEffect } 284 580 … … 291 587 end; 292 588 293 function TBGRATextEffect.GetHeight: integer; 294 begin 295 result := FHeight; 589 function TBGRATextEffect.GetMaskHeight: integer; 590 begin 591 if FTextMask = nil then 592 result := 0 593 else 594 result := FTextMask.Height; 595 end; 596 597 class function TBGRATextEffect.GetOutlineWidth: integer; static; 598 begin 599 result := DefaultOutlineWidth; 296 600 end; 297 601 … … 308 612 end; 309 613 310 function TBGRATextEffect.GetWidth: integer; 311 begin 312 result := FWidth; 313 end; 314 315 procedure TBGRATextEffect.DrawMaskMulticolored(ADest: TBGRACustomBitmap; 316 AMask: TBGRACustomBitmap; X, Y: Integer; const AColors: array of TBGRAPixel); 614 function TBGRATextEffect.GetMaskWidth: integer; 615 begin 616 if FTextMask = nil then 617 result := 0 618 else 619 result := FTextMask.Width; 620 end; 621 622 function TBGRATextEffect.GetTextHeight: integer; 623 begin 624 result := FTextSize.cy; 625 end; 626 627 function TBGRATextEffect.GetTextWidth: integer; 628 begin 629 result := FTextSize.cx; 630 end; 631 632 procedure TBGRATextEffect.SetShadowQuality(AValue: TRadialBlurType); 633 begin 634 if FShadowQuality=AValue then Exit; 635 FShadowQuality:=AValue; 636 FreeAndNil(FShadowMask); 637 end; 638 639 function TBGRATextEffect.DrawMaskMulticolored(ADest: TBGRACustomBitmap; 640 AMask: TBGRACustomBitmap; X, Y: Integer; const AColors: array of TBGRAPixel 641 ): TRect; 317 642 var 318 643 scan: TBGRASolidColorMaskScanner; … … 321 646 emptyCol, nextCol: boolean; 322 647 begin 323 if (AMask = nil) or (length(AColors)=0) then exit; 648 if (AMask = nil) or (length(AColors)=0) then 649 begin 650 result := EmptyRect; 651 exit; 652 end; 324 653 if (length(AColors)=0) then 325 654 begin 326 DrawMask(ADest,AMask,X,Y,AColors[0]);655 result := DrawMask(ADest,AMask,X,Y,AColors[0]); 327 656 exit; 328 657 end; … … 399 728 ADest.FillRect(X+startX,Y,X+AMask.Width,Y+AMask.Height,scan,dmDrawWithTransparency); 400 729 scan.Free; 401 end; 402 403 procedure TBGRATextEffect.DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X, 404 Y: Integer; AColor: TBGRAPixel); 730 result := rect(X,Y,X+AMask.Width,Y+AMask.Height); 731 end; 732 733 function TBGRATextEffect.DrawMask(ADest: TBGRACustomBitmap; 734 AMask: TBGRACustomBitmap; X, Y: Integer; AColor: TBGRAPixel): TRect; 405 735 var 406 736 scan: TBGRACustomScanner; 407 737 begin 408 if AMask = nil then exit; 738 if AMask = nil then 739 begin 740 result := EmptyRect; 741 exit; 742 end; 409 743 scan := TBGRASolidColorMaskScanner.Create(AMask,Point(-X,-Y),AColor); 410 744 ADest.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan,dmDrawWithTransparency); 411 745 scan.Free; 412 end; 413 414 procedure TBGRATextEffect.DrawMask(ADest: TBGRACustomBitmap; AMask: TBGRACustomBitmap; X, 415 Y: Integer; ATexture: IBGRAScanner); 746 result := rect(X,Y,X+AMask.Width,Y+AMask.Height); 747 end; 748 749 function TBGRATextEffect.DrawMask(ADest: TBGRACustomBitmap; 750 AMask: TBGRACustomBitmap; X, Y: Integer; ATexture: IBGRAScanner): TRect; 416 751 var 417 752 scan: TBGRACustomScanner; 418 753 begin 419 if AMask = nil then exit; 754 if AMask = nil then 755 begin 756 result := EmptyRect; 757 exit; 758 end; 420 759 scan := TBGRATextureMaskScanner.Create(AMask,Point(-X,-Y),ATexture); 421 760 ADest.FillRect(X,Y,X+AMask.Width,Y+AMask.Height,scan,dmDrawWithTransparency); 422 761 scan.Free; 762 result := rect(X,Y,X+AMask.Width,Y+AMask.Height); 423 763 end; 424 764 … … 433 773 iBlurRadius: integer; 434 774 begin 435 if FTextMask = nilthen775 if (FTextMask = nil) or (FTextMask.Width = 0) or (FTextMask.Height = 0) then 436 776 begin 437 777 result := EmptyRect; … … 491 831 end; 492 832 833 inc(X, FOffset.X); 834 Inc(Y, FOffset.Y); 493 835 if ATexture <> nil then 494 Shader.DrawScan(ADest,FShadingMask,Altitude,X +FOffset.X,Y+FOffset.Y, ATexture)836 Shader.DrawScan(ADest,FShadingMask,Altitude,X,Y, ATexture) 495 837 else 496 Shader.Draw(ADest,FShadingMask,Altitude,X+FOffset.X,Y+FOffset.Y, AColor); 497 result := rect(X+FOffset.X,Y+FOffset.Y, X+FOffset.X+FShadingMask.Width,Y+FOffset.Y+FShadingMask.Height); 498 end; 499 500 procedure TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 501 AColor: TBGRAPixel; AAlign: TAlignment); 838 Shader.Draw(ADest,FShadingMask,Altitude,X,Y, AColor); 839 result := rect(X,Y, X+FShadingMask.Width,Y+FShadingMask.Height); 840 end; 841 842 procedure TBGRATextEffect.InitImproveReadability(AText: string; Font: TFont; 843 SubOffsetX, SubOffsetY: single); 844 var size: TSize; 845 overhang: integer; 846 begin 847 if SubOffsetX < 0 then SubOffsetX := 0; 848 if SubOffsetY < 0 then SubOffsetY := 0; 849 size := BGRATextSize(Font, fqFineAntialiasing, AText, FontAntialiasingLevel); 850 FTextSize := size; 851 if size.cy = 0 then FTextSize.cy := BGRATextSize(Font, fqFineAntialiasing, 'Hg', FontAntialiasingLevel).cy; 852 overhang := size.cy div 2; 853 size.cx += 2*overhang + ceil(SubOffsetX); 854 size.cy += 2 + ceil(SubOffsetY); 855 856 FOffset := Point(-overhang,-1); //include overhang 857 FTextMask := BGRABitmapFactory.Create(size.cx,size.cy,BGRABlack); 858 BGRATextOutImproveReadability(FTextMask, Font, overhang+SubOffsetX,1+SubOffsetY, AText, BGRAWhite, nil, taLeftJustify, irMask); 859 end; 860 861 function TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 862 AColor: TBGRAPixel; AAlign: TAlignment): TRect; 502 863 begin 503 864 Case AAlign of 504 ta LeftJustify: Draw(ADest,X,Y,AColor);505 ta RightJustify: Draw(ADest,X-Width,Y,AColor);506 taCenter: Draw(ADest,X-Width div 2,Y,AColor);507 end; 508 end; 509 510 procedureTBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer;511 ATexture: IBGRAScanner; AAlign: TAlignment) ;865 taRightJustify: result := Draw(ADest,X-TextSize.cx,Y,AColor); 866 taCenter: result := Draw(ADest,X-TextSize.cx div 2,Y,AColor); 867 else result := Draw(ADest,X,Y,AColor); 868 end; 869 end; 870 871 function TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 872 ATexture: IBGRAScanner; AAlign: TAlignment): TRect; 512 873 begin 513 874 Case AAlign of 514 ta LeftJustify: Draw(ADest,X,Y,ATexture);515 ta RightJustify: Draw(ADest,X-Width,Y,ATexture);516 taCenter: Draw(ADest,X-Width div 2,Y,ATexture);875 taRightJustify: result := Draw(ADest,X-TextSize.cx,Y,ATexture); 876 taCenter: result := Draw(ADest,X-TextSize.cx div 2,Y,ATexture); 877 else result := Draw(ADest,X,Y,ATexture); 517 878 end; 518 879 end; … … 538 899 Case AAlign of 539 900 taLeftJustify: result := DrawShaded(ADest,X,Y,Shader,Altitude,AColor,ARounded); 540 taRightJustify: result := DrawShaded(ADest,X- Width,Y,Shader,Altitude,AColor,ARounded);541 taCenter: result := DrawShaded(ADest,X- Widthdiv 2,Y,Shader,Altitude,AColor,ARounded);901 taRightJustify: result := DrawShaded(ADest,X-TextSize.cx,Y,Shader,Altitude,AColor,ARounded); 902 taCenter: result := DrawShaded(ADest,X-TextSize.cx div 2,Y,Shader,Altitude,AColor,ARounded); 542 903 else 543 904 result := EmptyRect; … … 551 912 Case AAlign of 552 913 taLeftJustify: result := DrawShaded(ADest,X,Y,Shader,Altitude,ATexture,ARounded); 553 taRightJustify: result := DrawShaded(ADest,X- Width,Y,Shader,Altitude,ATexture,ARounded);554 taCenter: result := DrawShaded(ADest,X- Widthdiv 2,Y,Shader,Altitude,ATexture,ARounded);914 taRightJustify: result := DrawShaded(ADest,X-TextSize.cx,Y,Shader,Altitude,ATexture,ARounded); 915 taCenter: result := DrawShaded(ADest,X-TextSize.cx div 2,Y,Shader,Altitude,ATexture,ARounded); 555 916 else 556 917 result := EmptyRect; … … 571 932 end; 572 933 573 procedure TBGRATextEffect.Init(AText: string; Font: TFont; 574 Antialiasing: boolean; SubOffsetX,SubOffsetY: single; GrainX, GrainY: Integer); 934 constructor TBGRATextEffect.Create(AText: string; AFontName: string; 935 AFullHeight: integer; Antialiasing: boolean); 936 begin 937 InitWithFontName(AText, AFontName, AFullHeight, [], Antialiasing, 0, 0); 938 end; 939 940 constructor TBGRATextEffect.Create(AText: string; AFontName: string; 941 AFullHeight: integer; Antialiasing: boolean; SubOffsetX, SubOffsetY: single); 942 begin 943 InitWithFontName(AText, AFontName, AFullHeight, [], Antialiasing, SubOffsetX, SubOffsetY); 944 end; 945 946 constructor TBGRATextEffect.Create(AText: string; AFontName: string; 947 AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean); 948 begin 949 InitWithFontName(AText, AFontName, AFullHeight, AStyle, Antialiasing, 0, 0); 950 end; 951 952 constructor TBGRATextEffect.Create(AText: string; AFontName: string; 953 AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean; SubOffsetX, 954 SubOffsetY: single); 955 begin 956 InitWithFontName(AText, AFontName, AFullHeight, AStyle, Antialiasing, SubOffsetX, SubOffsetY); 957 end; 958 959 constructor TBGRATextEffect.Create(AMask: TBGRACustomBitmap; AMaskOwner: boolean; AWidth, 960 AHeight: integer; AOffset: TPoint); 961 begin 962 FTextSize := Size(AWidth,AHeight); 963 FOffset := AOffset; 964 if not AMaskOwner then 965 FTextMask := AMask.Duplicate() 966 else 967 FTextMask := AMask; 968 end; 969 970 procedure TBGRATextEffect.Init(AText: string; Font: TFont; Antialiasing: boolean; SubOffsetX,SubOffsetY: single; GrainX, GrainY: Integer); 971 const FXAntialiasingLevel = FontAntialiasingLevel; 575 972 var temp: TBGRACustomBitmap; 576 973 size: TSize; … … 583 980 iSubX,iSubY: integer; 584 981 begin 982 FShadowQuality := rbFast; 983 if Antialiasing and Assigned(BGRATextOutImproveReadabilityProc) then 984 begin 985 InitImproveReadability(AText, Font, SubOffsetX,SubOffsetY); 986 exit; 987 end; 585 988 if Antialiasing then 586 989 quality := fqFineAntialiasing 587 990 else 588 991 quality := fqSystem; 589 size := BGRAOriginalTextSize(Font,quality,AText,F ontAntialiasingLevel);992 size := BGRAOriginalTextSize(Font,quality,AText,FXAntialiasingLevel); 590 993 if (size.cx = 0) or (size.cy = 0) then 591 994 begin 592 size := BGRATextSize(Font,quality,'Hg',F ontAntialiasingLevel);593 F Width:= 0;594 F Height:= size.cy;995 size := BGRATextSize(Font,quality,'Hg',FXAntialiasingLevel); 996 FTextSize.cx := 0; 997 FTextSize.cy := size.cy; 595 998 FOffset := Point(0,0); 596 999 exit; 597 1000 end; 1001 FTextSize := size; 598 1002 599 1003 sizeX := size.cx+size.cy; … … 607 1011 if Antialiasing then 608 1012 begin 609 sizeX := (sizeX + F ontAntialiasingLevel-1);610 sizeX -= sizeX mod F ontAntialiasingLevel;611 612 sizeY := (sizeY + F ontAntialiasingLevel-1);613 sizeY -= sizeY mod F ontAntialiasingLevel;1013 sizeX := (sizeX + FXAntialiasingLevel-1); 1014 sizeX -= sizeX mod FXAntialiasingLevel; 1015 1016 sizeY := (sizeY + FXAntialiasingLevel-1); 1017 sizeY -= sizeY mod FXAntialiasingLevel; 614 1018 615 1019 if SubOffsetX <> 0 then 616 1020 begin 617 sizeX += ceil(SubOffsetX*F ontAntialiasingLevel);618 iSubX := round(SubOffsetX*F ontAntialiasingLevel);1021 sizeX += ceil(SubOffsetX*FXAntialiasingLevel); 1022 iSubX := round(SubOffsetX*FXAntialiasingLevel); 619 1023 end; 620 1024 if SubOffsetY <> 0 then 621 1025 begin 622 sizeY += ceil(SubOffsetY*F ontAntialiasingLevel);623 iSubY := round(SubOffsetY*F ontAntialiasingLevel);624 end; 625 626 OnePixel := F ontAntialiasingLevel;1026 sizeY += ceil(SubOffsetY*FXAntialiasingLevel); 1027 iSubY := round(SubOffsetY*FXAntialiasingLevel); 1028 end; 1029 1030 OnePixel := FXAntialiasingLevel; 627 1031 end else 628 1032 begin … … 662 1066 if Antialiasing then 663 1067 begin 664 F Width := round(size.cx/FontAntialiasingLevel);665 F Height := round(size.cy/FontAntialiasingLevel);666 FOffset := Point(round(FOffset.X/F ontAntialiasingLevel),round(FOffset.Y/FontAntialiasingLevel));667 668 FTextMask := temp.Resample(round(temp.width/F ontAntialiasingLevel),round(temp.Height/FontAntialiasingLevel),rmSimpleStretch);1068 FTextSize.cx := round(FTextSize.cx/FXAntialiasingLevel); 1069 FTextSize.cy := round(FTextSize.cy/FXAntialiasingLevel); 1070 FOffset := Point(round(FOffset.X/FXAntialiasingLevel),round(FOffset.Y/FXAntialiasingLevel)); 1071 1072 FTextMask := temp.Resample(round(temp.width/FXAntialiasingLevel),round(temp.Height/FXAntialiasingLevel),rmSimpleStretch); 669 1073 670 1074 maxAlpha := 0; … … 692 1096 else 693 1097 begin 694 FWidth := size.cx;695 FHeight := size.cy;696 697 1098 FTextMask := temp; 698 1099 p := FTextMask.data; … … 705 1106 end; 706 1107 end; 1108 end; 1109 1110 procedure TBGRATextEffect.InitWithFontName(AText: string; AFontName: string; 1111 AFullHeight: integer; AStyle: TFontStyles; Antialiasing: boolean; SubOffsetX, SubOffsetY: single); 1112 var lFont: TFont; 1113 begin 1114 lFont := TFont.Create; 1115 lFont.Name := AFontName; 1116 lFont.Height := AFullHeight * FontFullHeightSign; 1117 lFont.Style := AStyle; 1118 Init(AText, lFont, Antialiasing, SubOffsetX, SubOffsetY, 0,0); 1119 lFont.Free; 707 1120 end; 708 1121 … … 746 1159 end; 747 1160 748 procedure TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 749 AColor: TBGRAPixel); 750 begin 751 if FTextMask = nil then exit; 752 DrawMask(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,AColor); 753 end; 754 755 procedure TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 756 ATexture: IBGRAScanner); 757 begin 758 if FTextMask = nil then exit; 759 DrawMask(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,ATexture); 760 end; 761 762 procedure TBGRATextEffect.DrawMulticolored(ADest: TBGRACustomBitmap; X, Y: integer; 763 const AColors: array of TBGRAPixel); 764 begin 765 if FTextMask = nil then exit; 766 DrawMaskMulticolored(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,AColors); 767 end; 768 769 procedure TBGRATextEffect.DrawMulticolored(ADest: TBGRACustomBitmap; X, 770 Y: integer; const AColors: array of TBGRAPixel; AAlign: TAlignment); 1161 function TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 1162 AColor: TBGRAPixel): TRect; 1163 begin 1164 result := DrawMask(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,AColor); 1165 end; 1166 1167 function TBGRATextEffect.Draw(ADest: TBGRACustomBitmap; X, Y: integer; 1168 ATexture: IBGRAScanner): TRect; 1169 begin 1170 result := DrawMask(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,ATexture); 1171 end; 1172 1173 function TBGRATextEffect.DrawMulticolored(ADest: TBGRACustomBitmap; X, 1174 Y: integer; const AColors: array of TBGRAPixel): TRect; 1175 begin 1176 result := DrawMaskMulticolored(ADest,FTextMask,X+FOffset.X,Y+FOffset.Y,AColors); 1177 end; 1178 1179 function TBGRATextEffect.DrawMulticolored(ADest: TBGRACustomBitmap; X, 1180 Y: integer; const AColors: array of TBGRAPixel; AAlign: TAlignment): TRect; 771 1181 begin 772 1182 Case AAlign of 773 taLeftJustify: DrawMulticolored(ADest,X,Y,AColors); 774 taRightJustify: DrawMulticolored(ADest,X-Width,Y,AColors); 775 taCenter: DrawMulticolored(ADest,X-Width div 2,Y,AColors); 776 end; 777 end; 778 779 procedure TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 780 AColor: TBGRAPixel); 781 begin 782 if FTextMask = nil then exit; 1183 taRightJustify: result := DrawMulticolored(ADest,X-TextSize.cx,Y,AColors); 1184 taCenter: result := DrawMulticolored(ADest,X-TextSize.cx div 2,Y,AColors); 1185 else result := DrawMulticolored(ADest,X,Y,AColors); 1186 end; 1187 end; 1188 1189 function TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 1190 AColor: TBGRAPixel): TRect; 1191 begin 1192 if (FTextMask = nil) or (FTextMask.Width = 0) or (FTextMask.Height = 0) then 1193 begin 1194 result := EmptyRect; 1195 exit; 1196 end; 783 1197 if FOutlineMask = nil then 784 1198 begin … … 786 1200 FOutlineMask.LinearNegative; 787 1201 end; 788 DrawMask(ADest,FOutlineMask,X+FOffset.X,Y+FOffset.Y,AColor); 789 end; 790 791 procedure TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 792 ATexture: IBGRAScanner); 793 begin 794 if FTextMask = nil then exit; 1202 result := DrawMask(ADest,FOutlineMask,X+FOffset.X,Y+FOffset.Y,AColor); 1203 end; 1204 1205 function TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 1206 ATexture: IBGRAScanner): TRect; 1207 begin 1208 if (FTextMask = nil) or (FTextMask.Width = 0) or (FTextMask.Height = 0) then 1209 begin 1210 result := EmptyRect; 1211 exit; 1212 end; 795 1213 if FOutlineMask = nil then 796 1214 begin … … 798 1216 FOutlineMask.LinearNegative; 799 1217 end; 800 DrawMask(ADest,FOutlineMask,X+FOffset.X,Y+FOffset.Y,ATexture);801 end; 802 803 procedureTBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer;804 AColor: TBGRAPixel; AAlign: TAlignment) ;1218 result := DrawMask(ADest,FOutlineMask,X+FOffset.X,Y+FOffset.Y,ATexture); 1219 end; 1220 1221 function TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 1222 AColor: TBGRAPixel; AAlign: TAlignment): TRect; 805 1223 begin 806 1224 Case AAlign of 807 ta LeftJustify: DrawOutline(ADest,X,Y,AColor);808 ta RightJustify: DrawOutline(ADest,X-Width,Y,AColor);809 taCenter: DrawOutline(ADest,X-Width div 2,Y,AColor);810 end; 811 end; 812 813 procedureTBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer;814 ATexture: IBGRAScanner; AAlign: TAlignment) ;1225 taRightJustify: result := DrawOutline(ADest,X-TextSize.cx,Y,AColor); 1226 taCenter: result := DrawOutline(ADest,X-TextSize.cx div 2,Y,AColor); 1227 else result := DrawOutline(ADest,X,Y,AColor); 1228 end; 1229 end; 1230 1231 function TBGRATextEffect.DrawOutline(ADest: TBGRACustomBitmap; X, Y: integer; 1232 ATexture: IBGRAScanner; AAlign: TAlignment): TRect; 815 1233 begin 816 1234 Case AAlign of 817 ta LeftJustify: DrawOutline(ADest,X,Y,ATexture);818 ta RightJustify: DrawOutline(ADest,X-Width,Y,ATexture);819 taCenter: DrawOutline(ADest,X-Width div 2,Y,ATexture);820 end; 821 end; 822 823 procedure TBGRATextEffect.DrawShadow(ADest: TBGRACustomBitmap; X, Y,Radius: integer; 824 AColor: TBGRAPixel);825 begin 826 if Radius <= 0then827 begin 828 Draw(ADest,X,Y,AColor);1235 taRightJustify: result := DrawOutline(ADest,X-TextSize.cx,Y,ATexture); 1236 taCenter: result := DrawOutline(ADest,X-TextSize.cx div 2,Y,ATexture); 1237 else result := DrawOutline(ADest,X,Y,ATexture); 1238 end; 1239 end; 1240 1241 function TBGRATextEffect.DrawShadow(ADest: TBGRACustomBitmap; X, Y, 1242 Radius: integer; AColor: TBGRAPixel): TRect; 1243 begin 1244 if (Radius <= 0) or (FTextMask = nil) or (FTextMask.Width = 0) or (FTextMask.Height = 0) then 1245 begin 1246 result := Draw(ADest,X,Y,AColor); 829 1247 exit; 830 1248 end; 831 if FTextMask = nil then exit; 832 if FShadowRadius <> Radius then 1249 if (FShadowRadius <> Radius) or (FShadowMask = nil) then 833 1250 begin 834 1251 FShadowRadius := Radius; … … 836 1253 FShadowMask := BGRABitmapFactory.Create(FTextMask.Width+Radius*2,FTextMask.Height+Radius*2,BGRABlack); 837 1254 FShadowMask.PutImage(Radius,Radius,FTextMask,dmSet); 838 BGRAReplace(FShadowMask, FShadowMask.FilterBlurRadial(Radius,rbFast)); 839 end; 840 DrawMask(ADest,FShadowMask,X-Radius+FOffset.X,Y-Radius+FOffset.Y,AColor) 841 end; 842 843 procedure TBGRATextEffect.DrawShadow(ADest: TBGRACustomBitmap; X, Y, 844 Radius: integer; AColor: TBGRAPixel; AAlign: TAlignment); 1255 BGRAReplace(FShadowMask, FShadowMask.FilterBlurRadial(Radius,ShadowQuality)); 1256 end; 1257 Inc(X,FOffset.X-Radius); 1258 Inc(Y,FOffset.Y-Radius); 1259 DrawMask(ADest,FShadowMask,X,Y,AColor); 1260 result := rect(X,Y,X+FShadowMask.Width,Y+FShadowMask.Height); 1261 end; 1262 1263 function TBGRATextEffect.DrawShadow(ADest: TBGRACustomBitmap; X, Y, 1264 Radius: integer; AColor: TBGRAPixel; AAlign: TAlignment): TRect; 845 1265 begin 846 1266 Case AAlign of 847 ta LeftJustify: DrawShadow(ADest,X,Y,Radius,AColor);848 ta RightJustify: DrawShadow(ADest,X-Width,Y,Radius,AColor);849 taCenter: DrawShadow(ADest,X-Width div 2,Y,Radius,AColor);1267 taRightJustify: result := DrawShadow(ADest,X-TextSize.cx,Y,Radius,AColor); 1268 taCenter: result := DrawShadow(ADest,X-TextSize.cx div 2,Y,Radius,AColor); 1269 else result := DrawShadow(ADest,X,Y,Radius,AColor); 850 1270 end; 851 1271 end; … … 860 1280 end; 861 1281 1282 initialization 1283 1284 BGRATextOutImproveReadabilityProc := @BGRATextOutImproveReadability; 1285 862 1286 end. 863 1287 -
GraphicTest/Packages/bgrabitmap/bgratransform.pas
r452 r472 24 24 TopLeft, TopRight, 25 25 BottomLeft: TPointF; 26 function EmptyBox: TAffineBox;27 function AffineBox(ATopLeft, ATopRight, ABottomLeft: TPointF): TAffineBox;26 class function EmptyBox: TAffineBox; 27 class function AffineBox(ATopLeft, ATopRight, ABottomLeft: TPointF): TAffineBox; 28 28 property BottomRight: TPointF read GetBottomRight; 29 29 property IsEmpty: boolean read GetIsEmpty; … … 55 55 procedure Invert; 56 56 procedure Translate(OfsX,OfsY: Single); 57 procedure RotateDeg(Angle : Single);58 procedure RotateRad(Angle : Single);57 procedure RotateDeg(AngleCW: Single); 58 procedure RotateRad(AngleCCW: Single); 59 59 procedure MultiplyBy(AMatrix: TAffineMatrix); 60 60 procedure Fit(Origin,HAxis,VAxis: TPointF); virtual; … … 79 79 FRepeatImageX,FRepeatImageY: boolean; 80 80 FResampleFilter : TResampleFilter; 81 FBuffer: PBGRAPixel; 82 FBufferSize: Int32or64; 81 83 procedure Init(ABitmap: TBGRACustomBitmap; ARepeatImageX: Boolean= false; ARepeatImageY: Boolean= false; AResampleFilter: TResampleFilter = rfLinear); 82 84 public 83 85 constructor Create(ABitmap: TBGRACustomBitmap; ARepeatImage: Boolean= false; AResampleFilter: TResampleFilter = rfLinear); 84 86 constructor Create(ABitmap: TBGRACustomBitmap; ARepeatImageX: Boolean; ARepeatImageY: Boolean; AResampleFilter: TResampleFilter = rfLinear); 87 destructor Destroy; override; 85 88 function InternalScanCurrentPixel: TBGRAPixel; override; 89 procedure ScanPutPixels(pdest: PBGRAPixel; count: integer; mode: TDrawMode); override; 90 function IsScanPutPixelsDefined: boolean; override; 86 91 procedure Fit(Origin, HAxis, VAxis: TPointF); override; 87 92 end; … … 103 108 end; 104 109 110 { TBGRAExtendedBorderScanner } 111 112 TBGRAExtendedBorderScanner = class(TBGRACustomScanner) 113 protected 114 FSource: IBGRAScanner; 115 FBounds: TRect; 116 public 117 constructor Create(ASource: IBGRAScanner; ABounds: TRect); 118 function ScanAt(X,Y: Single): TBGRAPixel; override; 119 end; 120 105 121 { TBGRAScannerOffset } 106 122 … … 133 149 function IsAffineMatrixInversible(M: TAffineMatrix): boolean; 134 150 151 //check if the matrix is a translation (including the identity) 152 function IsAffineMatrixTranslation(M: TAffineMatrix): boolean; 153 154 //check if the matrix is a scaling (including a projection i.e. with factor 0) 155 function IsAffineMatrixScale(M: TAffineMatrix): boolean; 156 157 //check if the matrix is the identity 158 function IsAffineMatrixIdentity(M: TAffineMatrix): boolean; 159 135 160 //compute inverse (check if inversible before) 136 161 function AffineMatrixInverse(M: TAffineMatrix): TAffineMatrix; … … 145 170 function AffineMatrixLinear(v1,v2: TPointF): TAffineMatrix; 146 171 147 //define a rotation matrix (positive radians are counter clock wise) 148 function AffineMatrixRotationRad(Angle: Single): TAffineMatrix; 149 150 //Positive degrees are clock wise 151 function AffineMatrixRotationDeg(Angle: Single): TAffineMatrix; 172 //define a rotation matrix (positive radians are counter-clockwise) 173 //(assuming the y-axis is pointing down) 174 function AffineMatrixRotationRad(AngleCCW: Single): TAffineMatrix; 175 176 //Positive degrees are clockwise 177 //(assuming the y-axis is pointing down) 178 function AffineMatrixRotationDeg(AngleCW: Single): TAffineMatrix; 152 179 153 180 //define the identity matrix (that do nothing) … … 188 215 FMatrix: TPerspectiveTransform; 189 216 FScanAtProc: TScanAtFunction; 217 function GetIncludeOppositePlane: boolean; 218 procedure SetIncludeOppositePlane(AValue: boolean); 190 219 public 191 220 constructor Create(texture: IBGRAScanner; texCoord1,texCoord2: TPointF; const quad: array of TPointF); … … 195 224 function ScanAt(X, Y: Single): TBGRAPixel; override; 196 225 function ScanNextPixel: TBGRAPixel; override; 226 property IncludeOppositePlane: boolean read GetIncludeOppositePlane write SetIncludeOppositePlane; 197 227 end; 198 228 … … 203 233 sx ,shy ,w0 ,shx ,sy ,w1 ,tx ,ty ,w2 : single; 204 234 scanDenom,scanNumX,scanNumY: single; 235 FOutsideValue: TPointF; 236 FIncludeOppositePlane: boolean; 237 procedure Init; 205 238 public 206 239 constructor Create; overload; … … 222 255 procedure ScanMoveTo(x,y:single); 223 256 function ScanNext: TPointF; 257 property OutsideValue: TPointF read FOutsideValue write FOutsideValue; 258 property IncludeOppositePlane: boolean read FIncludeOppositePlane write FIncludeOppositePlane; 224 259 end; 225 260 … … 249 284 implementation 250 285 251 uses BGRABlend ;286 uses BGRABlend, GraphType; 252 287 253 288 function AffineMatrix(m11, m12, m13, m21, m22, m23: single): TAffineMatrix; … … 281 316 begin 282 317 result := M[1,1]*M[2,2]-M[1,2]*M[2,1] <> 0; 318 end; 319 320 function IsAffineMatrixTranslation(M: TAffineMatrix): boolean; 321 begin 322 result := (m[1,1]=1) and (m[1,2]=0) and (m[2,1] = 1) and (m[2,2]=0); 323 end; 324 325 function IsAffineMatrixScale(M: TAffineMatrix): boolean; 326 begin 327 result := (M[1,3]=0) and (M[2,3]=0) and 328 (M[1,2]=0) and (M[2,1]=0); 329 end; 330 331 function IsAffineMatrixIdentity(M: TAffineMatrix): boolean; 332 begin 333 result := IsAffineMatrixTranslation(M) and (M[1,3]=0) and (M[2,3]=0); 283 334 end; 284 335 … … 314 365 end; 315 366 316 function AffineMatrixRotationRad(Angle: Single): TAffineMatrix; 317 begin 318 result := AffineMatrix(cos(Angle), sin(Angle), 0, 319 -sin(Angle), cos(Angle), 0); 320 end; 321 322 function AffineMatrixRotationDeg(Angle: Single): TAffineMatrix; 323 begin 324 result := AffineMatrixRotationRad(-Angle*Pi/180); 367 function AffineMatrixRotationRad(AngleCCW: Single): TAffineMatrix; 368 begin 369 result := AffineMatrix(cos(AngleCCW), sin(AngleCCW), 0, 370 -sin(AngleCCW), cos(AngleCCW), 0); 371 end; 372 373 function AffineMatrixRotationDeg(AngleCW: Single): TAffineMatrix; 374 const DegToRad = -Pi/180; 375 begin 376 result := AffineMatrixRotationRad(AngleCW*DegToRad); 325 377 end; 326 378 … … 334 386 begin 335 387 result := PointF(M[1,1],M[2,1])*PointF(M[1,2],M[2,2]) = 0; 388 end; 389 390 { TBGRAExtendedBorderScanner } 391 392 constructor TBGRAExtendedBorderScanner.Create(ASource: IBGRAScanner; 393 ABounds: TRect); 394 begin 395 FSource := ASource; 396 FBounds := ABounds; 397 end; 398 399 function TBGRAExtendedBorderScanner.ScanAt(X, Y: Single): TBGRAPixel; 400 begin 401 if x < FBounds.Left then x := FBounds.Left; 402 if y < FBounds.Top then y := FBounds.Top; 403 if x > FBounds.Right-1 then x := FBounds.Right-1; 404 if y > FBounds.Bottom-1 then y := FBounds.Bottom-1; 405 result := FSource.ScanAt(X,Y); 336 406 end; 337 407 … … 356 426 end; 357 427 358 function TAffineBox.EmptyBox: TAffineBox;428 class function TAffineBox.EmptyBox: TAffineBox; 359 429 begin 360 430 result.TopLeft := EmptyPointF; … … 363 433 end; 364 434 365 function TAffineBox.AffineBox(ATopLeft, ATopRight, ABottomLeft: TPointF): TAffineBox;435 class function TAffineBox.AffineBox(ATopLeft, ATopRight, ABottomLeft: TPointF): TAffineBox; 366 436 begin 367 437 result.TopLeft := ATopLeft; … … 556 626 end; 557 627 628 //transformations are inverted because the effect on the resulting image 629 //is the inverse of the transformation. This is due to the fact 630 //that the matrix is applied to source coordinates, not destination coordinates 558 631 procedure TBGRAAffineScannerTransform.Translate(OfsX, OfsY: Single); 559 632 begin … … 561 634 end; 562 635 563 procedure TBGRAAffineScannerTransform.RotateDeg(Angle : Single);564 begin 565 MultiplyBy(AffineMatrixRotationDeg(-Angle ));566 end; 567 568 procedure TBGRAAffineScannerTransform.RotateRad(Angle : Single);569 begin 570 MultiplyBy(AffineMatrixRotationRad(-Angle ));636 procedure TBGRAAffineScannerTransform.RotateDeg(AngleCW: Single); 637 begin 638 MultiplyBy(AffineMatrixRotationDeg(-AngleCW)); 639 end; 640 641 procedure TBGRAAffineScannerTransform.RotateRad(AngleCCW: Single); 642 begin 643 MultiplyBy(AffineMatrixRotationRad(-AngleCCW)); 571 644 end; 572 645 … … 651 724 FRepeatImageY := ARepeatImageY; 652 725 FResampleFilter:= AResampleFilter; 726 FBufferSize:= 0; 653 727 end; 654 728 … … 666 740 end; 667 741 742 destructor TBGRAAffineBitmapTransform.Destroy; 743 begin 744 FreeMem(FBuffer); 745 end; 746 668 747 function TBGRAAffineBitmapTransform.InternalScanCurrentPixel: TBGRAPixel; 669 748 begin 670 if FRepeatImageX or FRepeatImageY then 671 result := FBitmap.GetPixelCycle(FCurX,FCurY,FResampleFilter,FRepeatImageX,FRepeatImageY) 749 result := FBitmap.GetPixelCycle(FCurX,FCurY,FResampleFilter,FRepeatImageX,FRepeatImageY); 750 end; 751 752 procedure TBGRAAffineBitmapTransform.ScanPutPixels(pdest: PBGRAPixel; 753 count: integer; mode: TDrawMode); 754 var p: PBGRAPixel; 755 n: integer; 756 posX4096, posY4096: Int32or64; 757 deltaX4096,deltaY4096: Int32or64; 758 ix,iy,shrMask,w,h: Int32or64; 759 py0: PByte; 760 deltaRow: Int32or64; 761 begin 762 w := FBitmap.Width; 763 h := FBitmap.Height; 764 if (w = 0) or (h = 0) then exit; 765 766 posX4096 := round(FCurX*4096); 767 deltaX4096:= round(FMatrix[1,1]*4096); 768 posY4096 := round(FCurY*4096); 769 deltaY4096:= round(FMatrix[2,1]*4096); 770 shrMask := -1; 771 shrMask := shrMask shr 12; 772 shrMask := not shrMask; 773 774 if mode = dmSet then 775 p := pdest 672 776 else 673 result := FBitmap.GetPixel(FCurX,FCurY,FResampleFilter); 777 begin 778 if count > FBufferSize then 779 begin 780 FBufferSize := count; 781 ReAllocMem(FBuffer, FBufferSize*sizeof(TBGRAPixel)); 782 end; 783 p := FBuffer; 784 end; 785 786 if FResampleFilter = rfBox then 787 begin 788 posX4096 += 2048; 789 posY4096 += 2048; 790 py0 := PByte(FBitmap.ScanLine[0]); 791 if FBitmap.LineOrder = riloTopToBottom then 792 deltaRow := FBitmap.Width*sizeof(TBGRAPixel) else 793 deltaRow := -FBitmap.Width*sizeof(TBGRAPixel); 794 if FRepeatImageX or FRepeatImageY then 795 begin 796 for n := count-1 downto 0 do 797 begin 798 if posX4096 < 0 then ix := (posX4096 shr 12) or shrMask else ix := posX4096 shr 12; 799 if posY4096 < 0 then iy := (posY4096 shr 12) or shrMask else iy := posY4096 shr 12; 800 if FRepeatImageX then ix := PositiveMod(ix,w); 801 if FRepeatImageY then iy := PositiveMod(iy,h); 802 if (ix < 0) or (iy < 0) or (ix >= w) or (iy >= h) then 803 p^ := BGRAPixelTransparent 804 else 805 p^ := (PBGRAPixel(py0 + iy*deltaRow)+ix)^; 806 inc(p); 807 posX4096 += deltaX4096; 808 posY4096 += deltaY4096; 809 end; 810 end else 811 begin 812 for n := count-1 downto 0 do 813 begin 814 if posX4096 < 0 then ix := (posX4096 shr 12) or shrMask else ix := posX4096 shr 12; 815 if posY4096 < 0 then iy := (posY4096 shr 12) or shrMask else iy := posY4096 shr 12; 816 if (ix < 0) or (iy < 0) or (ix >= w) or (iy >= h) then 817 p^ := BGRAPixelTransparent 818 else 819 p^ := (PBGRAPixel(py0 + iy*deltaRow)+ix)^; 820 inc(p); 821 posX4096 += deltaX4096; 822 posY4096 += deltaY4096; 823 end; 824 end; 825 end else 826 begin 827 if FRepeatImageX and FRepeatImageY then 828 begin 829 for n := count-1 downto 0 do 830 begin 831 if posX4096 < 0 then ix := (posX4096 shr 12) or shrMask else ix := posX4096 shr 12; 832 if posY4096 < 0 then iy := (posY4096 shr 12) or shrMask else iy := posY4096 shr 12; 833 p^ := FBitmap.GetPixelCycle256(ix,iy, (posX4096 shr 4) and 255, (posY4096 shr 4) and 255,FResampleFilter); 834 inc(p); 835 posX4096 += deltaX4096; 836 posY4096 += deltaY4096; 837 end; 838 end else 839 if FRepeatImageX or FRepeatImageY then 840 begin 841 for n := count-1 downto 0 do 842 begin 843 if posX4096 < 0 then ix := (posX4096 shr 12) or shrMask else ix := posX4096 shr 12; 844 if posY4096 < 0 then iy := (posY4096 shr 12) or shrMask else iy := posY4096 shr 12; 845 p^ := FBitmap.GetPixelCycle256(ix,iy, (posX4096 shr 4) and 255, (posY4096 shr 4) and 255,FResampleFilter, FRepeatImageX,FRepeatImageY); 846 inc(p); 847 posX4096 += deltaX4096; 848 posY4096 += deltaY4096; 849 end; 850 end else 851 begin 852 for n := count-1 downto 0 do 853 begin 854 if posX4096 < 0 then ix := (posX4096 shr 12) or shrMask else ix := posX4096 shr 12; 855 if posY4096 < 0 then iy := (posY4096 shr 12) or shrMask else iy := posY4096 shr 12; 856 p^ := FBitmap.GetPixel256(ix,iy, (posX4096 shr 4) and 255, (posY4096 shr 4) and 255,FResampleFilter); 857 inc(p); 858 posX4096 += deltaX4096; 859 posY4096 += deltaY4096; 860 end; 861 end; 862 end; 863 864 if mode <> dmSet then PutPixels(pdest,FBuffer,count,mode,255); 865 end; 866 867 function TBGRAAffineBitmapTransform.IsScanPutPixelsDefined: boolean; 868 begin 869 Result:=true; 674 870 end; 675 871 … … 684 880 { TBGRAPerspectiveScannerTransform } 685 881 882 function TBGRAPerspectiveScannerTransform.GetIncludeOppositePlane: boolean; 883 begin 884 if FMatrix = nil then 885 result := false 886 else 887 result := FMatrix.IncludeOppositePlane; 888 end; 889 890 procedure TBGRAPerspectiveScannerTransform.SetIncludeOppositePlane( 891 AValue: boolean); 892 begin 893 if FMatrix <> nil then 894 FMatrix.IncludeOppositePlane := AValue; 895 end; 896 686 897 constructor TBGRAPerspectiveScannerTransform.Create(texture: IBGRAScanner; texCoord1,texCoord2: TPointF; const quad: array of TPointF); 687 898 begin … … 689 900 FMatrix := nil 690 901 else 902 begin 691 903 FMatrix := TPerspectiveTransform.Create(quad,texCoord1.x,texCoord1.y,texCoord2.x,texCoord2.y); 904 FMatrix.OutsideValue := EmptyPointF; 905 end; 692 906 FTexture := texture; 693 907 FScanAtProc:= @FTexture.ScanAt; … … 701 915 FMatrix := nil 702 916 else 917 begin 703 918 FMatrix := TPerspectiveTransform.Create(quad,texCoordsQuad); 919 FMatrix.OutsideValue := EmptyPointF; 920 end; 704 921 FTexture := texture; 705 922 FScanAtProc:= @FTexture.ScanAt; … … 725 942 begin 726 943 ptSource := FMatrix.Apply(PointF(X,Y)); 727 Result:= FScanAtProc(ptSource.X, ptSource.Y); 944 if ptSource.x = EmptySingle then 945 result := BGRAPixelTransparent 946 else 947 Result:= FScanAtProc(ptSource.X, ptSource.Y); 728 948 end; 729 949 end; … … 736 956 begin 737 957 ptSource := FMatrix.ScanNext; 738 Result:= FScanAtProc(ptSource.X, ptSource.Y); 958 if ptSource.x = EmptySingle then 959 result := BGRAPixelTransparent 960 else 961 Result:= FScanAtProc(ptSource.X, ptSource.Y); 739 962 end; 740 963 end; … … 742 965 { TPerspectiveTransform } 743 966 967 procedure TPerspectiveTransform.Init; 968 begin 969 FOutsideValue := PointF(0,0); 970 FIncludeOppositePlane:= True; 971 end; 972 744 973 constructor TPerspectiveTransform.Create; 745 974 begin 975 Init; 746 976 AssignIdentity; 747 977 end; … … 750 980 const quad: array of TPointF); 751 981 begin 982 Init; 752 983 MapRectToQuad(x1 ,y1 ,x2 ,y2 ,quad ); 753 984 end; … … 756 987 x2, y2: single); 757 988 begin 989 Init; 758 990 MapQuadToRect(quad, x1,y1,x2,y2); 759 991 end; … … 762 994 destQuad: array of TPointF); 763 995 begin 996 Init; 764 997 MapQuadToQuad(srcQuad,destQuad); 765 998 end; … … 995 1228 m : single; 996 1229 begin 997 m:= pt.x * w0 + pt.y * w1 + w2 ; 998 if m=0 then 999 begin 1000 result.x := 0; 1001 result.y := 0; 1002 end else 1230 m:= pt.x * w0 + pt.y * w1 + w2; 1231 if (m=0) or (not FIncludeOppositePlane and (m < 0)) then 1232 result := FOutsideValue 1233 else 1003 1234 begin 1004 1235 m := 1/m; … … 1018 1249 var m: single; 1019 1250 begin 1020 if ScanDenom = 0 then 1021 begin 1022 result.x := 0; 1023 result.y := 0; 1024 end else 1251 if (ScanDenom = 0) or (not FIncludeOppositePlane and (ScanDenom < 0)) then 1252 result := FOutsideValue 1253 else 1025 1254 begin 1026 1255 m := 1/scanDenom; -
GraphicTest/Packages/bgrabitmap/bgratypewriter.pas
r452 r472 19 19 protected 20 20 FIdentifier: string; 21 procedure WriteHeader(AStream: TStream; AName: string; AContentSize: longint); 22 class procedure ReadHeader(AStream: TStream; out AName: string; out AContentSize: longint); 23 function ContentSize: integer; virtual; 24 function HeaderName: string; virtual; 25 procedure WriteContent(AStream: TStream); virtual; 26 procedure ReadContent(AStream: TStream); virtual; 21 27 public 22 28 Width,Height: single; 23 29 constructor Create(AIdentifier: string); virtual; 24 procedure Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); virtual; abstract; 30 constructor Create(AStream: TStream); virtual; 31 procedure Path({%H-}ADest: IBGRAPath; {%H-}AMatrix: TAffineMatrix); virtual; 25 32 property Identifier: string read FIdentifier; 26 end; 33 procedure SaveToStream(AStream: TStream); 34 class function LoadFromStream(AStream: TStream): TBGRAGlyph; 35 end; 36 37 TGlyphPointCurveMode= (cmAuto, cmCurve, cmAngle); 27 38 28 39 { TBGRAPolygonalGlyph } … … 34 45 FQuadraticCurves: boolean; 35 46 Points: array of TPointF; 47 CurveMode: array of TGlyphPointCurveMode; 36 48 Curves: array of record 37 49 isCurvedToNext,isCurvedToPrevious: boolean; … … 40 52 function MaybeCurve(start1,end1,start2,end2: integer): boolean; 41 53 procedure ComputeQuadraticCurves; 54 function ContentSize: integer; override; 55 function HeaderName: string; override; 56 procedure WriteContent(AStream: TStream); override; 57 procedure ReadContent(AStream: TStream); override; 58 procedure Init; 42 59 public 43 60 Offset: TPointF; 61 Closed: boolean; 62 MinimumDotProduct: single; 44 63 constructor Create(AIdentifier: string); override; 45 procedure SetPoints(const APoints: array of TPointF); 46 procedure Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); override; 64 constructor Create(AStream: TStream); override; 65 procedure SetPoints(const APoints: array of TPointF); overload; 66 procedure SetPoints(const APoints: array of TPointF; const ACurveMode: array of TGlyphPointCurveMode); overload; 67 procedure Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); override; 47 68 property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves; 69 end; 70 71 TBGRACustomTypeWriterHeader = record 72 HeaderName: String; 73 NbGlyphs: integer; 48 74 end; 49 75 … … 59 85 function GetGlyph(AIdentifier: string): TBGRAGlyph; virtual; 60 86 procedure SetGlyph(AIdentifier: string; AValue: TBGRAGlyph); 61 procedure TextPath(ADest: TBGRACanvas2D; AText : string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);87 procedure TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean); 62 88 procedure GlyphPath(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 63 89 procedure DrawLastPath(ADest: TBGRACanvas2D); … … 66 92 procedure AddGlyph(AGlyph: TBGRAGlyph); 67 93 function GetGlyphMatrix(AGlyph: TBGRAGlyph; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 68 function GetTextMatrix(AText : string; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix;94 function GetTextMatrix(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 69 95 property Glyph[AIdentifier: string]: TBGRAGlyph read GetGlyph write SetGlyph; 96 function CustomHeaderSize: integer; virtual; 97 procedure WriteCustomHeader(AStream: TStream); virtual; 98 function ReadCustomTypeWriterHeader(AStream: TStream): TBGRACustomTypeWriterHeader; 99 procedure ReadAdditionalHeader({%H-}AStream: TStream); virtual; 100 function HeaderName: string; virtual; 70 101 public 71 102 OutlineMode: TBGRATypeWriterOutlineMode; 103 DrawGlyphsSimultaneously : boolean; 72 104 constructor Create; 105 procedure SaveGlyphsToFile(AFilenameUTF8: string); 106 procedure SaveGlyphsToStream(AStream: TStream); 107 procedure LoadGlyphsFromFile(AFilenameUTF8: string); 108 procedure LoadGlyphsFromStream(AStream: TStream); 73 109 procedure DrawGlyph(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 74 procedure DrawText(ADest: TBGRACanvas2D; AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 110 procedure DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual; 111 procedure CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual; 75 112 function GetGlyphBox(AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 76 function GetTextBox(AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 77 function GetTextGlyphBoxes(AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 113 function GetTextBox(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 114 function GetTextGlyphBoxes(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 115 procedure NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal); 116 procedure NeedGlyphAnsiRange; 78 117 destructor Destroy; override; 79 118 end; 80 119 120 function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload; 121 function ComputeEasyBezier(APoints: array of TPointF; ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload; 122 81 123 implementation 82 124 83 uses LCLProc; 125 uses LCLProc, lazutf8classes; 126 127 {$i winstream.inc} 128 129 function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; 130 var 131 glyph: TBGRAPolygonalGlyph; 132 canvas2D: TBGRACanvas2D; 133 i: integer; 134 begin 135 if length(APoints) <= 2 then 136 begin 137 setlength(result, length(APoints)); 138 for i := 0 to high(result) do 139 result[i] := APoints[i]; 140 exit; 141 end; 142 glyph := TBGRAPolygonalGlyph.Create(''); 143 glyph.QuadraticCurves := true; 144 glyph.Closed:= AClosed; 145 glyph.MinimumDotProduct := AMinimumDotProduct; 146 glyph.SetPoints(APoints); 147 canvas2D := TBGRACanvas2D.Create(nil); 148 canvas2D.pixelCenteredCoordinates := true; 149 glyph.Path(canvas2D,AffineMatrixIdentity); 150 glyph.Free; 151 result := canvas2D.currentPath; 152 canvas2D.free; 153 end; 154 155 function ComputeEasyBezier(APoints: array of TPointF; 156 ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; 157 AMinimumDotProduct: single): ArrayOfTPointF; 158 var 159 glyph: TBGRAPolygonalGlyph; 160 canvas2D: TBGRACanvas2D; 161 i: integer; 162 begin 163 if length(APoints) <= 2 then 164 begin 165 setlength(result, length(APoints)); 166 for i := 0 to high(result) do 167 result[i] := APoints[i]; 168 exit; 169 end; 170 glyph := TBGRAPolygonalGlyph.Create(''); 171 glyph.QuadraticCurves := true; 172 glyph.Closed:= AClosed; 173 glyph.MinimumDotProduct := AMinimumDotProduct; 174 glyph.SetPoints(APoints, ACurveMode); 175 canvas2D := TBGRACanvas2D.Create(nil); 176 canvas2D.pixelCenteredCoordinates := true; 177 glyph.Path(canvas2D,AffineMatrixIdentity); 178 glyph.Free; 179 result := canvas2D.currentPath; 180 canvas2D.free; 181 end; 84 182 85 183 { TBGRAPolygonalGlyph } … … 109 207 if lv <> 0 then v *= 1/lv; 110 208 111 result := u*v > 0.707;209 result := u*v > MinimumDotProduct; 112 210 end; 113 211 … … 119 217 FirstPointIndex := 0; 120 218 for i := 0 to high(points) do 219 Curves[i].isCurvedToPrevious := false; 220 for i := 0 to high(points) do 121 221 begin 122 222 Curves[i].isCurvedToNext := false; 123 Curves[i].isCurvedToPrevious := false;124 223 Curves[i].Center := EmptyPointF; 125 224 Curves[i].ControlPoint := EmptyPointF; … … 138 237 Curves[i].Center := (points[i]+points[NextPt])*0.5; 139 238 Curves[i].NextCenter := (points[NextPt]+points[NextPt2])*0.5; 140 141 Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2);142 Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext;143 239 Curves[i].ControlPoint := points[NextPt]; 240 241 if (i < high(points)-1) or Closed then 242 begin 243 case CurveMode[nextPt] of 244 cmAuto: Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2); 245 cmCurve: Curves[i].isCurvedToNext:= true; 246 else Curves[i].isCurvedToNext:= false; 247 end; 248 Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext; 249 end; 144 250 end; 145 251 end; 252 end; 253 254 function TBGRAPolygonalGlyph.ContentSize: integer; 255 begin 256 Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*length(Points); 257 end; 258 259 function TBGRAPolygonalGlyph.HeaderName: string; 260 begin 261 Result:='TBGRAPolygonalGlyph'; 262 end; 263 264 procedure TBGRAPolygonalGlyph.WriteContent(AStream: TStream); 265 var i: integer; 266 begin 267 inherited WriteContent(AStream); 268 WinWritePointF(AStream, Offset); 269 WinWriteLongint(AStream,length(Points)); 270 for i := 0 to high(Points) do 271 WinWritePointF(AStream, Points[i]); 272 end; 273 274 procedure TBGRAPolygonalGlyph.ReadContent(AStream: TStream); 275 var i: integer; 276 tempPts: array of TPointF; 277 begin 278 inherited ReadContent(AStream); 279 Offset := WinReadPointF(AStream); 280 SetLength(tempPts, WinReadLongint(AStream)); 281 for i := 0 to high(tempPts) do 282 tempPts[i] := WinReadPointF(AStream); 283 SetPoints(tempPts); 284 end; 285 286 procedure TBGRAPolygonalGlyph.Init; 287 begin 288 Closed := True; 289 MinimumDotProduct := 0.707; 146 290 end; 147 291 … … 150 294 inherited Create(AIdentifier); 151 295 Offset := PointF(0,0); 296 Init; 297 end; 298 299 constructor TBGRAPolygonalGlyph.Create(AStream: TStream); 300 begin 301 inherited Create(AStream); 302 Init; 152 303 end; 153 304 … … 158 309 for i := 0 to high(points) do 159 310 points[i] := APoints[i]; 311 setlength(CurveMode, length(APoints)); 312 for i := 0 to high(CurveMode) do 313 CurveMode[i] := cmAuto; 160 314 Curves := nil; 161 315 end; 162 316 163 procedure TBGRAPolygonalGlyph.Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); 317 procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF; 318 const ACurveMode: array of TGlyphPointCurveMode); 319 var i: integer; 320 begin 321 if length(APoints) <> length(ACurveMode) then 322 raise exception.Create('Dimension mismatch'); 323 SetLength(Points,length(APoints)); 324 for i := 0 to high(points) do 325 points[i] := APoints[i]; 326 setlength(CurveMode, length(ACurveMode)); 327 for i := 0 to high(CurveMode) do 328 CurveMode[i] := ACurveMode[i]; 329 Curves := nil; 330 end; 331 332 procedure TBGRAPolygonalGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); 164 333 var i: integer; 165 334 nextMove: boolean; 166 335 startCoord: TPointF; 336 167 337 begin 168 338 if Points = nil then exit; … … 171 341 nextMove := true; 172 342 AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y); 343 173 344 for i := 0 to high(Points) do 174 345 if isEmptyPointF(Points[i]) then … … 206 377 nextMove := false; 207 378 end else 379 begin 208 380 ADest.lineTo(AMatrix*Points[i]); 381 end; 209 382 end; 210 if not nextmove then ADest.closePath; 383 if not nextmove then 384 ADest.closePath; 211 385 end; 212 386 213 387 { TBGRAGlyph } 214 388 389 procedure TBGRAGlyph.WriteHeader(AStream: TStream; AName: string; 390 AContentSize: longint); 391 begin 392 WinWriteByte(AStream, length(AName)); 393 AStream.Write(AName[1],length(AName)); 394 WinWriteLongint(AStream, AContentSize); 395 end; 396 397 class procedure TBGRAGlyph.ReadHeader(AStream: TStream; out AName: string; out 398 AContentSize: longint); 399 var NameLength: integer; 400 begin 401 NameLength := WinReadByte(AStream); 402 setlength(AName,NameLength); 403 AStream.Read(AName[1],length(AName)); 404 AContentSize := WinReadLongint(AStream); 405 end; 406 407 function TBGRAGlyph.ContentSize: integer; 408 begin 409 result := 4+length(FIdentifier)+sizeof(single)*2; 410 end; 411 412 function TBGRAGlyph.HeaderName: string; 413 begin 414 result := 'TBGRAGlyph'; 415 end; 416 417 procedure TBGRAGlyph.WriteContent(AStream: TStream); 418 begin 419 WinWriteLongint(AStream,length(FIdentifier)); 420 AStream.Write(FIdentifier[1],length(FIdentifier)); 421 WinWriteSingle(AStream,Width); 422 WinWriteSingle(AStream,Height); 423 end; 424 425 procedure TBGRAGlyph.ReadContent(AStream: TStream); 426 var lIdentifierLength: integer; 427 begin 428 lIdentifierLength:= WinReadLongint(AStream); 429 setlength(FIdentifier, lIdentifierLength); 430 AStream.Read(FIdentifier[1],length(FIdentifier)); 431 Width := WinReadSingle(AStream); 432 Height := WinReadSingle(AStream); 433 end; 434 215 435 constructor TBGRAGlyph.Create(AIdentifier: string); 216 436 begin 217 437 FIdentifier:= AIdentifier; 438 end; 439 440 constructor TBGRAGlyph.Create(AStream: TStream); 441 begin 442 ReadContent(AStream); 443 end; 444 445 procedure TBGRAGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); 446 begin 447 //nothing 448 end; 449 450 procedure TBGRAGlyph.SaveToStream(AStream: TStream); 451 begin 452 WriteHeader(AStream, HeaderName, ContentSize); 453 WriteContent(AStream); 454 end; 455 456 class function TBGRAGlyph.LoadFromStream(AStream: TStream) : TBGRAGlyph; 457 var lName: string; 458 lContentSize: integer; 459 EndPosition: Int64; 460 begin 461 ReadHeader(AStream,lName,lContentSize); 462 EndPosition := AStream.Position + lContentSize; 463 if lName = 'TBGRAPolygonalGlyph' then 464 result := TBGRAPolygonalGlyph.Create(AStream) 465 else if lName = 'TBGRAGlyph' then 466 result := TBGRAGlyph.Create(AStream) 467 else 468 raise exception.Create('Unknown glyph type (' + lName + ')'); 469 AStream.Position:= EndPosition; 218 470 end; 219 471 … … 272 524 TypeWriterMatrix := AffineMatrixIdentity; 273 525 OutlineMode:= twoFill; 526 DrawGlyphsSimultaneously := false; 274 527 end; 275 528 … … 281 534 end; 282 535 283 procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; AText : string;536 procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; 284 537 X, Y: Single; AAlign: TBGRATypeWriterAlignment); 285 538 begin 286 TextPath(ADest, AText, X,Y, AAlign); 287 DrawLastPath(ADest); 539 TextPath(ADest, ATextUTF8, X,Y, AAlign, (OutlineMode <> twoPath) and not DrawGlyphsSimultaneously); 540 end; 541 542 procedure TBGRACustomTypeWriter.CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 543 var 544 pstr: pchar; 545 left,charlen: integer; 546 nextchar: string; 547 g: TBGRAGlyph; 548 m,m2: TAffineMatrix; 549 begin 550 if ATextUTF8 = '' then exit; 551 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 552 m2 := m; 553 554 pstr := @ATextUTF8[1]; 555 left := length(ATextUTF8); 556 while left > 0 do 557 begin 558 charlen := UTF8CharacterLength(pstr); 559 setlength(nextchar, charlen); 560 move(pstr^, nextchar[1], charlen); 561 inc(pstr,charlen); 562 dec(left,charlen); 563 564 g := GetGlyph(nextchar); 565 if g <> nil then 566 begin 567 if AAlign in [twaLeft,twaMiddle,twaRight] then 568 m2 := m*AffineMatrixTranslation(0,-g.Height/2) else 569 if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then 570 m2 := m*AffineMatrixTranslation(0,-g.Height) 571 else 572 m2 := m; 573 g.Path(ADest, m2); 574 m := m*AffineMatrixTranslation(g.Width,0); 575 end; 576 end; 288 577 end; 289 578 … … 301 590 end; 302 591 303 function TBGRACustomTypeWriter.GetTextBox(AText : string; X, Y: Single;592 function TBGRACustomTypeWriter.GetTextBox(ATextUTF8: string; X, Y: Single; 304 593 AAlign: TBGRATypeWriterAlignment): TAffineBox; 305 594 var … … 313 602 314 603 begin 315 if AText = '' then result := TAffineBox.EmptyBox else316 begin 317 m := GetTextMatrix(AText ,X,Y,AAlign);604 if ATextUTF8 = '' then result := TAffineBox.EmptyBox else 605 begin 606 m := GetTextMatrix(ATextUTF8,X,Y,AAlign); 318 607 minY := 0; 319 608 maxY := 0; 320 609 totalWidth := 0; 321 610 322 pstr := @AText [1];323 left := length(AText );611 pstr := @ATextUTF8[1]; 612 left := length(ATextUTF8); 324 613 while left > 0 do 325 614 begin … … 359 648 end; 360 649 361 function TBGRACustomTypeWriter.GetTextGlyphBoxes(AText : string; X, Y: Single;650 function TBGRACustomTypeWriter.GetTextGlyphBoxes(ATextUTF8: string; X, Y: Single; 362 651 AAlign: TBGRATypeWriterAlignment): TGlyphBoxes; 363 652 var … … 372 661 373 662 begin 374 if AText = '' then result := nil else375 begin 376 setlength(result, UTF8Length(AText ));377 378 m := GetTextMatrix(AText ,X,Y,AAlign);379 380 pstr := @AText [1];381 left := length(AText );663 if ATextUTF8 = '' then result := nil else 664 begin 665 setlength(result, UTF8Length(ATextUTF8)); 666 667 m := GetTextMatrix(ATextUTF8,X,Y,AAlign); 668 669 pstr := @ATextUTF8[1]; 670 left := length(ATextUTF8); 382 671 numChar := 0; 383 672 while left > 0 do … … 418 707 end; 419 708 420 procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; AText: string; X, 421 Y: Single; AAlign: TBGRATypeWriterAlignment); 709 procedure TBGRACustomTypeWriter.NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal); 710 var c: cardinal; 711 begin 712 for c := AUnicodeFrom to AUnicodeTo do 713 GetGlyph(UnicodeToUTF8(c)); 714 end; 715 716 procedure TBGRACustomTypeWriter.NeedGlyphAnsiRange; 717 var i: integer; 718 begin 719 for i := 0 to 255 do 720 GetGlyph(AnsiToUtf8(chr(i))); 721 end; 722 723 procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X, 724 Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean); 422 725 var 423 726 pstr: pchar; … … 427 730 m,m2: TAffineMatrix; 428 731 begin 429 ADest.beginPath;430 if AText = '' then exit;431 m := GetTextMatrix(AText , X,Y,AAlign);732 if not ADrawEachChar then ADest.beginPath; 733 if ATextUTF8 = '' then exit; 734 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 432 735 m2 := m; 433 736 434 pstr := @AText [1];435 left := length(AText );737 pstr := @ATextUTF8[1]; 738 left := length(ATextUTF8); 436 739 while left > 0 do 437 740 begin … … 451 754 else 452 755 m2 := m; 756 if ADrawEachChar then ADest.beginPath; 453 757 g.Path(ADest, m2); 758 if ADrawEachChar then DrawLastPath(ADest); 454 759 m := m*AffineMatrixTranslation(g.Width,0); 455 760 end; … … 497 802 end; 498 803 804 procedure TBGRACustomTypeWriter.SaveGlyphsToStream(AStream: TStream); 805 var Enumerator: TAvgLvlTreeNodeEnumerator; 806 begin 807 WinWriteLongint(AStream,CustomHeaderSize); 808 WriteCustomHeader(AStream); 809 810 Enumerator := FGlyphs.GetEnumerator; 811 while Enumerator.MoveNext do 812 TBGRAGlyph(Enumerator.Current.Data).SaveToStream(AStream); 813 Enumerator.Free; 814 end; 815 816 procedure TBGRACustomTypeWriter.LoadGlyphsFromFile(AFilenameUTF8: string); 817 var Stream: TFileStreamUTF8; 818 begin 819 Stream := nil; 820 try 821 Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead); 822 LoadGlyphsFromStream(Stream); 823 finally 824 Stream.Free; 825 end; 826 end; 827 828 procedure TBGRACustomTypeWriter.LoadGlyphsFromStream(AStream: TStream); 829 var Header: TBGRACustomTypeWriterHeader; 830 i: integer; 831 g: TBGRAGlyph; 832 HeaderSize: integer; 833 GlyphStartPosition: Int64; 834 begin 835 HeaderSize := WinReadLongint(AStream); 836 GlyphStartPosition:= AStream.Position+HeaderSize; 837 Header := ReadCustomTypeWriterHeader(AStream); 838 if header.HeaderName <> HeaderName then 839 raise exception.Create('Invalid file format ("'+header.HeaderName+'" should be "'+HeaderName+'")'); 840 ReadAdditionalHeader(AStream); 841 AStream.Position:= GlyphStartPosition; 842 for i := 0 to Header.NbGlyphs-1 do 843 begin 844 g := TBGRAGlyph.LoadFromStream(AStream); 845 AddGlyph(g); 846 end; 847 end; 848 849 procedure TBGRACustomTypeWriter.SaveGlyphsToFile(AFilenameUTF8: string); 850 var Stream: TFileStreamUTF8; 851 begin 852 Stream := nil; 853 try 854 Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate or fmOpenWrite); 855 SaveGlyphsToStream(Stream); 856 finally 857 Stream.Free; 858 end; 859 end; 860 499 861 function TBGRACustomTypeWriter.GetGlyphMatrix(AGlyph: TBGRAGlyph; X, Y: Single; 500 862 AAlign: TBGRATypeWriterAlignment): TAffineMatrix; … … 514 876 end; 515 877 516 function TBGRACustomTypeWriter.GetTextMatrix(AText : string; X, Y: Single;878 function TBGRACustomTypeWriter.GetTextMatrix(ATextUTF8: string; X, Y: Single; 517 879 AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 518 880 var … … 528 890 begin 529 891 totalWidth := 0; 530 pstr := @AText [1];531 left := length(AText );892 pstr := @ATextUTF8[1]; 893 left := length(ATextUTF8); 532 894 while left > 0 do 533 895 begin … … 548 910 end; 549 911 912 function TBGRACustomTypeWriter.CustomHeaderSize: integer; 913 begin 914 result := 1+length(HeaderName)+4; 915 end; 916 917 procedure TBGRACustomTypeWriter.WriteCustomHeader(AStream: TStream); 918 var lHeaderName: string; 919 begin 920 lHeaderName:= HeaderName; 921 WinWriteByte(AStream,length(lHeaderName)); 922 AStream.Write(lHeaderName[1],length(lHeaderName)); 923 WinWriteLongint(AStream,FGlyphs.Count); 924 end; 925 926 function TBGRACustomTypeWriter.ReadCustomTypeWriterHeader(AStream: TStream 927 ): TBGRACustomTypeWriterHeader; 928 begin 929 setlength(result.HeaderName, WinReadByte(AStream)); 930 AStream.Read(result.HeaderName[1],length(result.HeaderName)); 931 result.NbGlyphs:= WinReadLongint(AStream); 932 end; 933 934 procedure TBGRACustomTypeWriter.ReadAdditionalHeader(AStream: TStream); 935 begin 936 //nothing 937 end; 938 939 function TBGRACustomTypeWriter.HeaderName: string; 940 begin 941 result := 'TBGRACustomTypeWriter'; 942 end; 943 550 944 destructor TBGRACustomTypeWriter.Destroy; 551 945 begin -
GraphicTest/Packages/bgrabitmap/bgravectorize.pas
r452 r472 5 5 interface 6 6 7 { 8 Font rendering units : BGRAText, BGRATextFX, BGRAVectorize, BGRAFreeType 9 10 This unit provides vectorizers : 11 - VectorizeMonochrome function vectorizes a back'n'white image 12 - TBGRAVectorizedFont allows to vectorize and to load vectorized font and draw them 13 14 TBGRAVectorizedFontRenderer class works like other font renderers, i.e., it can 15 be assigned to the FontRenderer property. You can use it in two different modes : 16 - if you supply a directory, it will look for *.glyphs files in it to load fonts 17 - if you don't supply a directory, fonts will be vectorized from LCL 18 19 Note that unless you want to supply your own glyphs files, you don't need 20 to use explicitely this renderer, because TBGRATextEffectFontRenderer will 21 make use of it if necessary, according to effects parameters used. 22 } 23 7 24 uses 8 Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATypewriter, BGRATransform, BGRACanvas2D; 9 25 Types, Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATypewriter, BGRATransform, BGRACanvas2D, BGRAText; 26 27 //vectorize a monochrome bitmap 10 28 function VectorizeMonochrome(ASource: TBGRACustomBitmap; zoom: single; PixelCenteredCoordinates: boolean): ArrayOfTPointF; 11 29 12 30 type 31 TBGRAVectorizedFont = class; 32 33 //this is the class to assign to FontRenderer property of TBGRABitmap 34 { TBGRAVectorizedFontRenderer } 35 36 TBGRAVectorizedFontRenderer = class(TBGRACustomFontRenderer) 37 protected 38 FVectorizedFontArray: array of record 39 FontName: string; 40 FontStyle: TFontStyles; 41 VectorizedFont: TBGRAVectorizedFont; 42 end; 43 FVectorizedFont: TBGRAVectorizedFont; 44 FCanvas2D: TBGRACanvas2D; 45 FDirectoryUTF8: string; 46 function OutlineActuallyVisible: boolean; 47 procedure UpdateFont; 48 function GetCanvas2D(ASurface: TBGRACustomBitmap): TBGRACanvas2D; 49 procedure InternalTextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel; texture: IBGRAScanner); 50 procedure Init; 51 public 52 MaxFontResolution: integer; 53 54 OutlineVisible: boolean; 55 OutlineWidth: single; 56 OutlineColor: TBGRAPixel; 57 OutlineTexture: IBGRAScanner; 58 OuterOutlineOnly: boolean; 59 60 ShadowVisible: boolean; 61 ShadowColor: TBGRAPixel; 62 ShadowRadius: integer; 63 ShadowOffset: TPoint; 64 65 constructor Create; 66 constructor Create(ADirectoryUTF8: string); 67 function GetFontPixelMetric: TFontPixelMetric; override; 68 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); override; 69 procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientation: integer; s: string; texture: IBGRAScanner; align: TAlignment); override; 70 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; texture: IBGRAScanner; align: TAlignment); override; 71 procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; c: TBGRAPixel; align: TAlignment); override; 72 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); override; 73 procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; texture: IBGRAScanner); override; 74 procedure CopyTextPathTo(ADest: IBGRAPath; x, y: single; s: string; align: TAlignment); override; 75 function TextSize(s: string): TSize; override; 76 destructor Destroy; override; 77 end; 78 13 79 TGlyphSizes = array of record 14 80 Glyph: String; … … 16 82 end; 17 83 18 TWordBreakHandler = procedure(var ABefore, AAfter: string) of object; 84 TBGRAVectorizedFontHeader = record 85 Name: string; 86 Style: TFontStyles; 87 EmHeightRatio: single; 88 Resolution: integer; 89 PixelMetric: TFontPixelMetric; 90 end; 91 TBGRAGlyphsInfo = record 92 Name: string; 93 Style: TFontStyles; 94 NbGlyphs: integer; 95 end; 19 96 20 97 { TBGRAVectorizedFont } … … 33 110 FItalicSlope: single; 34 111 FWordBreakHandler: TWordBreakHandler; 112 FDirectory: string; 113 FDirectoryContent: array of record 114 Filename: string; 115 FontName: string; 116 FontStyle: TFontStyles; 117 end; 118 FFontEmHeightRatioComputed: boolean; 119 FFontEmHeightRatio: single; 120 FFontPixelMetric: TFontPixelMetric; 121 FFontPixelMetricComputed: boolean; 122 FFontFound: boolean; 123 function GetEmHeight: single; 124 function GetFontPixelMetric: TFontPixelMetric; 125 function GetLCLHeight: single; 126 function GetVectorizeLCL: boolean; 127 procedure SetEmHeight(AValue: single); 35 128 procedure SetItalicSlope(AValue: single); 129 procedure SetLCLHeight(AValue: single); 36 130 procedure SetOrientation(AValue: single); 37 131 procedure SetQuadraticCurves(AValue: boolean); … … 41 135 procedure SetName(AValue: string); 42 136 procedure SetStyle(AValue: TFontStyles); 137 function GetFontEmHeightRatio: single; 138 procedure SetVectorizeLCL(AValue: boolean); 43 139 protected 44 140 procedure UpdateFont; … … 46 142 function GetGlyph(AIdentifier: string): TBGRAGlyph; override; 47 143 procedure DefaultWordBreakHandler(var ABefore, AAfter: string); 144 procedure Init(AVectorize: boolean); 145 function CustomHeaderSize: integer; override; 146 procedure WriteCustomHeader(AStream: TStream); override; 147 procedure ReadAdditionalHeader(AStream: TStream); override; 148 function ReadVectorizedFontHeader(AStream: TStream): TBGRAVectorizedFontHeader; 149 function HeaderName: string; override; 150 procedure SetDirectory(const AValue: string); 48 151 public 152 UnderlineDecoration,StrikeOutDecoration: boolean; 49 153 constructor Create; 154 constructor Create(AVectorizeLCL: boolean); 50 155 destructor Destroy; override; 51 156 function GetGlyphSize(AIdentifier:string): TPointF; 52 157 function GetTextGlyphSizes(AText:string): TGlyphSizes; 53 158 function GetTextSize(AText:string): TPointF; 54 procedure SplitText(var AText: string; AMaxWidth: single; out ARemains: string); 55 procedure DrawTextWordBreak(ADest: TBGRACanvas2D; AText: string; X, Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 56 procedure DrawTextRect(ADest: TBGRACanvas2D; AText: string; X1,Y1,X2,Y2: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 57 procedure DrawTextRect(ADest: TBGRACanvas2D; AText: string; ATopLeft,ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 58 function GetTextWordBreakGlyphBoxes(AText: string; X,Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 59 function GetTextRectGlyphBoxes(AText: string; X1,Y1,X2,Y2: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft): TGlyphBoxes; 60 function GetTextRectGlyphBoxes(AText: string; ATopLeft,ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment=twaTopLeft): TGlyphBoxes; 159 procedure SplitText(var ATextUTF8: string; AMaxWidth: single; out ARemainsUTF8: string); 160 procedure DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; X, Y: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft); override; 161 procedure CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X, Y: Single; 162 AAlign: TBGRATypeWriterAlignment=twaTopLeft); override; 163 procedure DrawTextWordBreak(ADest: TBGRACanvas2D; ATextUTF8: string; X, Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 164 procedure DrawTextRect(ADest: TBGRACanvas2D; ATextUTF8: string; X1,Y1,X2,Y2: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 165 procedure DrawTextRect(ADest: TBGRACanvas2D; ATextUTF8: string; ATopLeft,ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment=twaTopLeft); 166 function GetTextWordBreakGlyphBoxes(ATextUTF8: string; X,Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 167 function GetTextRectGlyphBoxes(ATextUTF8: string; X1,Y1,X2,Y2: Single; AAlign: TBGRATypeWriterAlignment=twaTopLeft): TGlyphBoxes; 168 function GetTextRectGlyphBoxes(ATextUTF8: string; ATopLeft,ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment=twaTopLeft): TGlyphBoxes; 169 procedure UpdateDirectory; 170 function LoadGlyphsInfo(AFilenameUTF8: string): TBGRAGlyphsInfo; 61 171 62 172 property Resolution: integer read FResolution write SetResolution; 63 173 property Style: TFontStyles read FStyle write SetStyle; 64 174 property Name: string read FName write SetName; 175 property LCLHeight: single read GetLCLHeight write SetLCLHeight; 176 property EmHeight: single read GetEmHeight write SetEmHeight; 65 177 property FullHeight: single read FFullHeight write SetFullHeight; 66 178 property FontMatrix: TAffineMatrix read FFontMatrix write SetFontMatrix; … … 69 181 property ItalicSlope: single read FItalicSlope write SetItalicSlope; 70 182 property OnWordBreak: TWordBreakHandler read FWordBreakHandler write FWordBreakHandler; 183 property Directory: string read FDirectory write SetDirectory; 184 property FontEmHeightRatio: single read GetFontEmHeightRatio; 185 property FontPixelMetric: TFontPixelMetric read GetFontPixelMetric; 186 property FontFound: boolean read FFontFound; 187 property VectorizeLCL: boolean read GetVectorizeLCL write SetVectorizeLCL; 71 188 end; 72 189 73 190 implementation 74 191 75 uses BGRAText, LCLProc, Types; 76 192 uses LCLProc, FileUtil, lazutf8classes; 193 194 {$i winstream.inc} 77 195 function VectorizeMonochrome(ASource: TBGRACustomBitmap; zoom: single; PixelCenteredCoordinates: boolean): ArrayOfTPointF; 78 196 const unitShift = 6; … … 516 634 (ord(cur[1])+ord(cur[3])+ord(cur[7])+ord(cur[9]) = 3)) then 517 635 begin 518 if (not cur[6] and not cur[9] and not cur[8] and ((ASource.getPixel( integer(x-1),integer(y-2)).green <= 128) or (ASource.getPixel(integer(x+2),integer(y+1)).green <= 128)) ) or519 (not cur[8] and not cur[7] and not cur[4] and ((ASource.getPixel( integer(x-2),integer(y+1)).green <= 128) or (ASource.getPixel(integer(x+1),integer(y-2)).green <= 128)) ) or520 (not cur[4] and not cur[1] and not cur[2] and ((ASource.getPixel( integer(x+1),integer(y+2)).green <= 128) or (ASource.getPixel(integer(x-2),integer(y-1)).green <= 128)) ) or521 (not cur[2] and not cur[3] and not cur[6] and ((ASource.getPixel( integer(x-1),integer(y+2)).green <= 128) or (ASource.getPixel(integer(x+2),integer(y-1)).green <= 128)) ) then636 if (not cur[6] and not cur[9] and not cur[8] and ((ASource.getPixel(x-1,y-2).green <= 128) or (ASource.getPixel(x+2,y+1).green <= 128)) ) or 637 (not cur[8] and not cur[7] and not cur[4] and ((ASource.getPixel(x-2,y+1).green <= 128) or (ASource.getPixel(x+1,y-2).green <= 128)) ) or 638 (not cur[4] and not cur[1] and not cur[2] and ((ASource.getPixel(x+1,y+2).green <= 128) or (ASource.getPixel(x-2,y-1).green <= 128)) ) or 639 (not cur[2] and not cur[3] and not cur[6] and ((ASource.getPixel(x-1,y+2).green <= 128) or (ASource.getPixel(x+2,y-1).green <= 128)) ) then 522 640 ortho[y,x] := true; 523 641 end; … … 839 957 end; 840 958 959 { TBGRAVectorizedFontRenderer } 960 961 function TBGRAVectorizedFontRenderer.OutlineActuallyVisible: boolean; 962 begin 963 result := OutlineVisible and (abs(OutlineWidth) > 0) and (OutlineColor.Alpha <> 0) or (OutlineTexture <> nil); 964 end; 965 966 procedure TBGRAVectorizedFontRenderer.UpdateFont; 967 var i,neededResolution: integer; 968 begin 969 FVectorizedFont := nil; 970 FontName := Trim(FontName); 971 for i := 0 to high(FVectorizedFontArray) do 972 if (CompareText(FVectorizedFontArray[i].FontName,FontName)=0) and 973 (FVectorizedFontArray[i].FontStyle = FontStyle) then 974 begin 975 FVectorizedFont := FVectorizedFontArray[i].VectorizedFont; 976 break; 977 end; 978 979 if FVectorizedFont = nil then 980 begin 981 FVectorizedFont:= TBGRAVectorizedFont.Create(False); 982 FVectorizedFont.Name := FontName; 983 FVectorizedFont.Style := FontStyle; 984 FVectorizedFont.Directory := FDirectoryUTF8; 985 if not FVectorizedFont.FontFound and LCLFontAvailable then 986 FVectorizedFont.VectorizeLCL := True; 987 Setlength(FVectorizedFontArray,length(FVectorizedFontArray)+1); 988 FVectorizedFontArray[high(FVectorizedFontArray)].FontName := FontName; 989 FVectorizedFontArray[high(FVectorizedFontArray)].FontStyle := FontStyle; 990 FVectorizedFontArray[high(FVectorizedFontArray)].VectorizedFont := FVectorizedFont; 991 end; 992 if FontEmHeight > 0 then 993 FVectorizedFont.EmHeight := FontEmHeight 994 else 995 FVectorizedFont.FullHeight:= -FontEmHeight; 996 if OutlineActuallyVisible then 997 begin 998 if OuterOutlineOnly then 999 FVectorizedFont.OutlineMode := twoFillOverStroke 1000 else 1001 FVectorizedFont.OutlineMode := twoStrokeOverFill; 1002 FVectorizedFont.QuadraticCurves := False; 1003 end 1004 else 1005 begin 1006 FVectorizedFont.OutlineMode := twoFill; 1007 FVectorizedFont.QuadraticCurves := FVectorizedFont.FullHeight > FVectorizedFont.Resolution*0.8; 1008 end; 1009 if FVectorizedFont.VectorizeLCL then 1010 begin 1011 neededResolution := trunc((FVectorizedFont.FullHeight+80)/50)*50; 1012 if neededResolution > MaxFontResolution then neededResolution := MaxFontResolution; 1013 if FVectorizedFont.Resolution < neededResolution then FVectorizedFont.Resolution:= neededResolution; 1014 end; 1015 end; 1016 1017 function TBGRAVectorizedFontRenderer.GetCanvas2D(ASurface: TBGRACustomBitmap 1018 ): TBGRACanvas2D; 1019 begin 1020 if (FCanvas2D = nil) or (FCanvas2D.surface <> ASurface) then 1021 begin 1022 FCanvas2D.Free; 1023 FCanvas2D := TBGRACanvas2D.Create(ASurface); 1024 end; 1025 result := FCanvas2D; 1026 FCanvas2D.antialiasing:= FontQuality in[fqFineAntialiasing,fqFineClearTypeBGR,fqFineClearTypeRGB]; 1027 if OutlineTexture <> nil then 1028 FCanvas2D.strokeStyle(OutlineTexture) 1029 else 1030 FCanvas2D.strokeStyle(OutlineColor); 1031 FCanvas2D.lineWidth := abs(OutlineWidth); 1032 if not ShadowVisible then 1033 FCanvas2D.shadowColor(BGRAPixelTransparent) 1034 else 1035 begin 1036 FCanvas2D.shadowColor(ShadowColor); 1037 FCanvas2D.shadowBlur:= ShadowRadius; 1038 FCanvas2D.shadowOffset := PointF(ShadowOffset.X,ShadowOffset.Y); 1039 end; 1040 end; 1041 1042 procedure TBGRAVectorizedFontRenderer.InternalTextRect( 1043 ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; 1044 style: TTextStyle; c: TBGRAPixel; texture: IBGRAScanner); 1045 var 1046 twAlign : TBGRATypeWriterAlignment; 1047 c2D: TBGRACanvas2D; 1048 intersectedClip,previousClip: TRect; 1049 begin 1050 previousClip := ADest.ClipRect; 1051 if style.Clipping then 1052 begin 1053 intersectedClip := rect(0,0,0,0); 1054 if not IntersectRect(intersectedClip, previousClip, ARect) then exit; 1055 ADest.ClipRect := intersectedClip; 1056 end; 1057 UpdateFont; 1058 FVectorizedFont.Orientation := 0; 1059 case style.Alignment of 1060 taCenter: case style.Layout of 1061 tlCenter: twAlign := twaMiddle; 1062 tlBottom: twAlign := twaBottom; 1063 else twAlign:= twaTop; 1064 end; 1065 taRightJustify: 1066 case style.Layout of 1067 tlCenter: twAlign := twaRight; 1068 tlBottom: twAlign := twaBottomRight; 1069 else twAlign := twaTopRight; 1070 end; 1071 else 1072 case style.Layout of 1073 tlCenter: twAlign := twaLeft; 1074 tlBottom: twAlign := twaBottomLeft; 1075 else twAlign:= twaTopLeft; 1076 end; 1077 end; 1078 c2D := GetCanvas2D(ADest); 1079 if texture = nil then 1080 c2D.fillStyle(c) 1081 else 1082 c2D.fillStyle(texture); 1083 if style.Wordbreak then 1084 FVectorizedFont.DrawTextRect(c2D, sUTF8, x-0.5,y-0.5,ARect.Right-0.5,ARect.Bottom-0.5, twAlign) 1085 else 1086 begin 1087 case style.Layout of 1088 tlCenter: y := (ARect.Top+ARect.Bottom) div 2; 1089 tlBottom: y := ARect.Bottom; 1090 end; 1091 case style.Alignment of 1092 taCenter: FVectorizedFont.DrawText(c2D, sUTF8, (ARect.Left+ARect.Right-1)/2,y-0.5, twAlign); 1093 taRightJustify: FVectorizedFont.DrawText(c2D, sUTF8, ARect.Right-0.5,y-0.5, twAlign); 1094 else 1095 FVectorizedFont.DrawText(c2D, sUTF8, x-0.5,y-0.5, twAlign); 1096 end; 1097 end; 1098 if style.Clipping then 1099 ADest.ClipRect := previousClip; 1100 end; 1101 1102 procedure TBGRAVectorizedFontRenderer.Init; 1103 begin 1104 FVectorizedFontArray := nil; 1105 FDirectoryUTF8 := ''; 1106 1107 OutlineVisible:= True; 1108 OutlineColor := BGRAPixelTransparent; 1109 OuterOutlineOnly := false; 1110 1111 ShadowColor := BGRABlack; 1112 ShadowVisible := false; 1113 ShadowOffset := Point(5,5); 1114 ShadowRadius := 5; 1115 1116 MaxFontResolution := 300; 1117 end; 1118 1119 constructor TBGRAVectorizedFontRenderer.Create; 1120 begin 1121 Init; 1122 end; 1123 1124 constructor TBGRAVectorizedFontRenderer.Create(ADirectoryUTF8: string); 1125 begin 1126 Init; 1127 FDirectoryUTF8 := ADirectoryUTF8; 1128 end; 1129 1130 function TBGRAVectorizedFontRenderer.GetFontPixelMetric: TFontPixelMetric; 1131 var factor: single; 1132 begin 1133 UpdateFont; 1134 result := FVectorizedFont.FontPixelMetric; 1135 if FVectorizedFont.Resolution > 0 then 1136 begin 1137 factor := FVectorizedFont.FullHeight/FVectorizedFont.Resolution; 1138 result.Baseline := round(result.Baseline*factor); 1139 result.CapLine := round(result.CapLine*factor); 1140 result.Lineheight := round(result.Lineheight*factor); 1141 result.DescentLine := round(result.DescentLine*factor); 1142 result.xLine := round(result.xLine*factor); 1143 end; 1144 end; 1145 1146 procedure TBGRAVectorizedFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 1147 y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment); 1148 var 1149 twAlign : TBGRATypeWriterAlignment; 1150 c2D: TBGRACanvas2D; 1151 ofs: TPointF; 1152 begin 1153 UpdateFont; 1154 FVectorizedFont.Orientation := orientation; 1155 case align of 1156 taCenter: twAlign:= twaMiddle; 1157 taRightJustify: twAlign := twaRight; 1158 else twAlign:= twaLeft; 1159 end; 1160 c2D := GetCanvas2D(ADest); 1161 c2D.fillStyle(c); 1162 ofs := PointF(x,y); 1163 ofs += AffineMatrixRotationDeg(-orientation*0.1)*PointF(0,FVectorizedFont.FullHeight*0.5); 1164 FVectorizedFont.DrawText(c2D, s, ofs.x,ofs.y, twAlign); 1165 end; 1166 1167 procedure TBGRAVectorizedFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x, 1168 y: single; orientation: integer; s: string; texture: IBGRAScanner; 1169 align: TAlignment); 1170 var 1171 twAlign : TBGRATypeWriterAlignment; 1172 c2D: TBGRACanvas2D; 1173 begin 1174 UpdateFont; 1175 FVectorizedFont.Orientation := orientation; 1176 case align of 1177 taCenter: twAlign:= twaTop; 1178 taRightJustify: twAlign := twaTopRight; 1179 else twAlign:= twaTopLeft; 1180 end; 1181 c2D := GetCanvas2D(ADest); 1182 c2D.fillStyle(texture); 1183 FVectorizedFont.DrawText(c2D, s, x,y, twAlign); 1184 end; 1185 1186 procedure TBGRAVectorizedFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 1187 y: single; s: string; texture: IBGRAScanner; align: TAlignment); 1188 begin 1189 TextOutAngle(ADest,x,y,FontOrientation,s,texture,align); 1190 end; 1191 1192 procedure TBGRAVectorizedFontRenderer.TextOut(ADest: TBGRACustomBitmap; x, 1193 y: single; s: string; c: TBGRAPixel; align: TAlignment); 1194 begin 1195 TextOutAngle(ADest,x,y,FontOrientation,s,c,align); 1196 end; 1197 1198 procedure TBGRAVectorizedFontRenderer.TextRect(ADest: TBGRACustomBitmap; 1199 ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); 1200 begin 1201 InternalTextRect(ADest,ARect,x,y,s,style,c,nil); 1202 end; 1203 1204 procedure TBGRAVectorizedFontRenderer.TextRect(ADest: TBGRACustomBitmap; 1205 ARect: TRect; x, y: integer; s: string; style: TTextStyle; 1206 texture: IBGRAScanner); 1207 begin 1208 InternalTextRect(ADest,ARect,x,y,s,style,BGRAPixelTransparent,texture); 1209 end; 1210 1211 procedure TBGRAVectorizedFontRenderer.CopyTextPathTo(ADest: IBGRAPath; x, y: single; s: string; align: TAlignment); 1212 var 1213 twAlign : TBGRATypeWriterAlignment; 1214 ofs: TPointF; 1215 begin 1216 UpdateFont; 1217 FVectorizedFont.Orientation := 0; 1218 case align of 1219 taCenter: twAlign:= twaMiddle; 1220 taRightJustify: twAlign := twaRight; 1221 else twAlign:= twaLeft; 1222 end; 1223 ofs := PointF(x,y); 1224 ofs += PointF(0,FVectorizedFont.FullHeight*0.5); 1225 FVectorizedFont.CopyTextPathTo(ADest, s, ofs.x,ofs.y, twAlign); 1226 end; 1227 1228 function TBGRAVectorizedFontRenderer.TextSize(s: string): TSize; 1229 var sizeF: TPointF; 1230 begin 1231 UpdateFont; 1232 sizeF := FVectorizedFont.GetTextSize(s); 1233 result.cx := round(sizeF.x); 1234 result.cy := round(sizeF.y); 1235 end; 1236 1237 destructor TBGRAVectorizedFontRenderer.Destroy; 1238 var i: integer; 1239 begin 1240 FCanvas2D.Free; 1241 for i := 0 to high(FVectorizedFontArray) do 1242 FVectorizedFontArray[i].VectorizedFont.Free; 1243 FVectorizedFontArray := nil; 1244 inherited Destroy; 1245 end; 1246 841 1247 { TBGRAVectorizedFont } 842 1248 … … 862 1268 end; 863 1269 1270 procedure TBGRAVectorizedFont.SetLCLHeight(AValue: single); 1271 begin 1272 if (AValue > 0) xor (FontEmHeightSign < 0) then 1273 EmHeight := abs(AValue) 1274 else 1275 FullHeight := abs(AValue); 1276 end; 1277 1278 function TBGRAVectorizedFont.GetEmHeight: single; 1279 begin 1280 result := FullHeight * FontEmHeightRatio; 1281 end; 1282 1283 function TBGRAVectorizedFont.GetFontPixelMetric: TFontPixelMetric; 1284 begin 1285 if not FFontPixelMetricComputed and (FFont <> nil) then 1286 begin 1287 FFontPixelMetric := BGRAText.GetFontPixelMetric(FFont); 1288 FFontPixelMetricComputed := true; 1289 end; 1290 result := FFontPixelMetric; 1291 end; 1292 1293 function TBGRAVectorizedFont.GetLCLHeight: single; 1294 begin 1295 result := FullHeight * FontFullHeightSign; 1296 end; 1297 1298 function TBGRAVectorizedFont.GetVectorizeLCL: boolean; 1299 begin 1300 result := FFont <> nil; 1301 end; 1302 1303 procedure TBGRAVectorizedFont.SetEmHeight(AValue: single); 1304 begin 1305 if FontEmHeightRatio > 0 then 1306 FullHeight := AValue / FontEmHeightRatio; 1307 end; 1308 864 1309 procedure TBGRAVectorizedFont.SetQuadraticCurves(AValue: boolean); 865 1310 begin … … 895 1340 end; 896 1341 1342 function TBGRAVectorizedFont.GetFontEmHeightRatio: single; 1343 var 1344 lEmHeight, lFullHeight: single; 1345 OldHeight: integer; 1346 begin 1347 if not FFontEmHeightRatioComputed then 1348 begin 1349 if FFont <> nil then 1350 begin 1351 OldHeight := FFont.Height; 1352 FFont.Height := FontEmHeightSign * 100; 1353 lEmHeight := BGRATextSize(FFont, fqSystem, 'Hg', 1).cy; 1354 FFont.Height := FontFullHeightSign * 100; 1355 lFullHeight := BGRATextSize(FFont, fqSystem, 'Hg', 1).cy; 1356 if lEmHeight = 0 then 1357 FFontEmHeightRatio := 1 1358 else 1359 FFontEmHeightRatio := lFullHeight/lEmHeight; 1360 FFontEmHeightRatioComputed := true; 1361 FFont.Height := OldHeight; 1362 end else 1363 begin 1364 result := 1; 1365 exit; 1366 end; 1367 end; 1368 result := FFontEmHeightRatio; 1369 end; 1370 1371 procedure TBGRAVectorizedFont.SetVectorizeLCL(AValue: boolean); 1372 begin 1373 if AValue then 1374 begin 1375 if FFont = nil then 1376 FFont := TFont.Create; 1377 end else 1378 begin 1379 if FFont <> nil then 1380 FreeAndNil(FFont); 1381 end; 1382 UpdateFont; 1383 end; 1384 897 1385 procedure TBGRAVectorizedFont.UpdateFont; 898 begin 899 ClearGlyphs; 900 FFont.Name := FName; 901 FFont.Style := FStyle; 902 FFont.Height := FontFullHeightSign * FResolution; 1386 var i: integer; 1387 bestIndex, bestDistance: integer; 1388 distance: integer; 1389 begin 1390 if FFont <> nil then 1391 begin 1392 ClearGlyphs; 1393 FFont.Name := FName; 1394 FFont.Style := FStyle; 1395 FFont.Height := FontFullHeightSign * FResolution; 1396 FFontEmHeightRatio := 1; 1397 FFontEmHeightRatioComputed := false; 1398 fillchar(FFontPixelMetric,sizeof(FFontPixelMetric),0); 1399 FFontPixelMetricComputed := false; 1400 FFontFound := True; 1401 end else 1402 begin 1403 bestIndex := -1; 1404 bestDistance := 1000; 1405 for i := 0 to high(FDirectoryContent) do 1406 begin 1407 if CompareText(FDirectoryContent[i].FontName,FName) = 0 then 1408 begin 1409 distance := 0; 1410 if (fsBold in FDirectoryContent[i].FontStyle) xor (fsBold in FStyle) then distance += 10; 1411 if (fsItalic in FDirectoryContent[i].FontStyle) xor (fsItalic in FStyle) then distance += 5; 1412 if (fsStrikeOut in FDirectoryContent[i].FontStyle) xor (fsStrikeOut in FStyle) then distance += 1; 1413 if (fsUnderline in FDirectoryContent[i].FontStyle) xor (fsUnderline in FStyle) then distance += 1; 1414 if (bestIndex = -1) or (distance < bestDistance) then 1415 begin 1416 bestIndex := i; 1417 bestDistance := distance; 1418 if FDirectoryContent[i].FontStyle = FStyle then break; 1419 end; 1420 end; 1421 end; 1422 if bestIndex <> -1 then 1423 begin 1424 if not (fsItalic in FDirectoryContent[bestIndex].FontStyle) and (fsItalic in FStyle) then 1425 ItalicSlope := 0.25 1426 else if (fsItalic in FDirectoryContent[bestIndex].FontStyle) and not (fsItalic in FStyle) then 1427 ItalicSlope := -0.25 1428 else 1429 ItalicSlope := 0; 1430 1431 UnderlineDecoration := not (fsUnderline in FDirectoryContent[bestIndex].FontStyle) and (fsUnderline in FStyle); 1432 StrikeOutDecoration := not (fsStrikeOut in FDirectoryContent[bestIndex].FontStyle) and (fsStrikeOut in FStyle); 1433 1434 ClearGlyphs; 1435 LoadGlyphsFromFile(FDirectoryContent[bestIndex].Filename); 1436 FFontFound := True; 1437 end else 1438 FFontFound := false; 1439 end; 903 1440 end; 904 1441 … … 911 1448 begin 912 1449 inherited Create; 913 FName := 'Arial'; 914 FStyle := []; 915 FFontMatrix := AffineMatrixIdentity; 916 FOrientation := 0; 917 FResolution := 100; 918 FFont := TFont.Create; 919 FBuffer := BGRABitmapFactory.Create; 920 FFullHeight := 20; 921 FItalicSlope := 0; 922 UpdateFont; 923 UpdateMatrix; 924 FWordBreakHandler:= nil; 1450 Init(True); 1451 end; 1452 1453 constructor TBGRAVectorizedFont.Create(AVectorizeLCL: boolean); 1454 begin 1455 inherited Create; 1456 Init(AVectorizeLCL); 925 1457 end; 926 1458 … … 1012 1544 end; 1013 1545 1014 procedure TBGRAVectorizedFont.SplitText(var AText : string; AMaxWidth: single;1015 out ARemains : string);1546 procedure TBGRAVectorizedFont.SplitText(var ATextUTF8: string; AMaxWidth: single; 1547 out ARemainsUTF8: string); 1016 1548 var 1017 1549 pstr: pchar; 1018 left,charlen: integer; 1550 p,left,charlen: integer; 1551 totalWidth: single; 1552 firstChar: boolean; 1019 1553 nextchar: string; 1020 1554 g: TBGRAGlyph; 1021 totalWidth: single;1022 firstChar: boolean;1023 1555 begin 1024 1556 totalWidth := 0; 1025 if AText = '' then1026 begin 1027 ARemains := '';1557 if ATextUTF8 = '' then 1558 begin 1559 ARemainsUTF8 := ''; 1028 1560 exit; 1029 1561 end else 1030 1562 begin 1031 pstr := @AText[1]; 1032 left := length(AText); 1563 p := 1; 1564 pstr := @ATextUTF8[1]; 1565 left := length(ATextUTF8); 1033 1566 firstChar := true; 1034 1567 while left > 0 do 1035 1568 begin 1569 if RemoveLineEnding(ATextUTF8,p) then 1570 begin 1571 ARemainsUTF8 := copy(ATextUTF8,p,length(ATextUTF8)-p+1); 1572 ATextUTF8 := copy(ATextUTF8,1,p-1); 1573 exit; 1574 end; 1575 1036 1576 charlen := UTF8CharacterLength(pstr); 1037 1577 setlength(nextchar, charlen); … … 1043 1583 begin 1044 1584 totalWidth += g.Width*FullHeight; 1045 if (totalWidth > AMaxWidth) and not firstCharthen1585 if not firstChar and (totalWidth > AMaxWidth) then 1046 1586 begin 1047 ARemains := copy(AText,length(AText)-left+1,left);1048 AText := copy(AText, 1, length(AText)-left);1587 ARemainsUTF8:= copy(ATextUTF8,p,length(ATextUTF8)-p+1); 1588 ATextUTF8 := copy(ATextUTF8,1,p-1); 1049 1589 if Assigned(FWordBreakHandler) then 1050 FWordBreakHandler(AText ,ARemains) else1051 DefaultWordBreakHandler(AText ,ARemains);1590 FWordBreakHandler(ATextUTF8,ARemainsUTF8) else 1591 DefaultWordBreakHandler(ATextUTF8,ARemainsUTF8); 1052 1592 exit; 1053 1593 end; … … 1055 1595 1056 1596 dec(left,charlen); 1597 inc(p,charlen); 1057 1598 firstChar := false; 1058 1599 end; 1059 1600 end; 1060 ARemains := ''; //no split 1601 ARemainsUTF8 := ''; //no split 1602 end; 1603 1604 procedure TBGRAVectorizedFont.DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; X, 1605 Y: Single; AAlign: TBGRATypeWriterAlignment); 1606 var underlinePoly: ArrayOfTPointF; 1607 m: TAffineMatrix; 1608 i: integer; 1609 deltaY: single; 1610 begin 1611 inherited DrawText(ADest, ATextUTF8, X, Y, AAlign); 1612 if AAlign in [twaBottom,twaBottomLeft,twaBottomRight] then deltaY := -1 else 1613 if AAlign in [twaLeft,twaMiddle,twaRight] then deltaY := -0.5 else 1614 deltaY := 0; 1615 if UnderlineDecoration and (Resolution > 0) then 1616 begin 1617 underlinePoly := BGRATextUnderline(PointF(0,deltaY), GetTextSize(ATextUTF8).x/FullHeight, FontPixelMetric.Baseline/Resolution, 1618 (FontPixelMetric.Baseline-FontPixelMetric.CapLine)/Resolution); 1619 if underlinePoly <> nil then 1620 begin 1621 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 1622 for i := 0 to high(underlinePoly) do 1623 underlinePoly[i] := m*underlinePoly[i]; 1624 if OutlineMode <> twoPath then ADest.beginPath; 1625 ADest.polylineTo(underlinePoly); 1626 DrawLastPath(ADest); 1627 end; 1628 end; 1629 if StrikeOutDecoration and (Resolution > 0) then 1630 begin 1631 underlinePoly := BGRATextStrikeOut(PointF(0,deltaY), GetTextSize(ATextUTF8).x/FullHeight, FontPixelMetric.Baseline/Resolution, 1632 (FontPixelMetric.Baseline-FontPixelMetric.CapLine)/Resolution, (FontPixelMetric.Baseline-FontPixelMetric.xLine)/Resolution); 1633 if underlinePoly <> nil then 1634 begin 1635 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 1636 for i := 0 to high(underlinePoly) do 1637 underlinePoly[i] := m*underlinePoly[i]; 1638 if OutlineMode <> twoPath then ADest.beginPath; 1639 ADest.polylineTo(underlinePoly); 1640 DrawLastPath(ADest); 1641 end; 1642 end; 1643 end; 1644 1645 procedure TBGRAVectorizedFont.CopyTextPathTo(ADest: IBGRAPath; 1646 ATextUTF8: string; X, Y: Single; AAlign: TBGRATypeWriterAlignment); 1647 var underlinePoly: ArrayOfTPointF; 1648 m: TAffineMatrix; 1649 i: integer; 1650 deltaY: single; 1651 begin 1652 inherited CopyTextPathTo(ADest,ATextUTF8, X, Y, AAlign); 1653 if AAlign in [twaBottom,twaBottomLeft,twaBottomRight] then deltaY := -1 else 1654 if AAlign in [twaLeft,twaMiddle,twaRight] then deltaY := -0.5 else 1655 deltaY := 0; 1656 if UnderlineDecoration and (Resolution > 0) then 1657 begin 1658 underlinePoly := BGRATextUnderline(PointF(0,deltaY), GetTextSize(ATextUTF8).x/FullHeight, FontPixelMetric.Baseline/Resolution, 1659 (FontPixelMetric.Baseline-FontPixelMetric.CapLine)/Resolution); 1660 if underlinePoly <> nil then 1661 begin 1662 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 1663 ADest.moveTo(m*underlinePoly[0]); 1664 for i := 1 to high(underlinePoly) do 1665 ADest.lineTo(m*underlinePoly[i]); 1666 ADest.closePath; 1667 end; 1668 end; 1669 if StrikeOutDecoration and (Resolution > 0) then 1670 begin 1671 underlinePoly := BGRATextStrikeOut(PointF(0,deltaY), GetTextSize(ATextUTF8).x/FullHeight, FontPixelMetric.Baseline/Resolution, 1672 (FontPixelMetric.Baseline-FontPixelMetric.CapLine)/Resolution, (FontPixelMetric.Baseline-FontPixelMetric.xLine)/Resolution); 1673 if underlinePoly <> nil then 1674 begin 1675 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 1676 ADest.moveTo(m*underlinePoly[0]); 1677 for i := 1 to high(underlinePoly) do 1678 ADest.lineTo(m*underlinePoly[i]); 1679 ADest.closePath; 1680 end; 1681 end; 1061 1682 end; 1062 1683 1063 1684 procedure TBGRAVectorizedFont.DrawTextWordBreak(ADest: TBGRACanvas2D; 1064 AText : string; X, Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment);1685 ATextUTF8: string; X, Y, MaxWidth: Single; AAlign: TBGRATypeWriterAlignment); 1065 1686 var ARemains: string; 1066 1687 step: TPointF; … … 1071 1692 lineAlignment: TBGRATypeWriterAlignment; 1072 1693 begin 1073 if (AText = '') or (MaxWidth <= 0) then exit;1694 if (ATextUTF8 = '') or (MaxWidth <= 0) then exit; 1074 1695 1075 1696 oldItalicSlope:= ItalicSlope; … … 1104 1725 Y += step.Y*lineShift; 1105 1726 repeat 1106 SplitText(AText , MaxWidth, ARemains);1107 DrawText(ADest,AText ,X,Y,lineAlignment);1108 AText := ARemains;1727 SplitText(ATextUTF8, MaxWidth, ARemains); 1728 DrawText(ADest,ATextUTF8,X,Y,lineAlignment); 1729 ATextUTF8 := ARemains; 1109 1730 X+= step.X; 1110 1731 Y+= step.Y; … … 1114 1735 lines := TStringList.Create; 1115 1736 repeat 1116 SplitText(AText , MaxWidth, ARemains);1117 lines.Add(AText );1118 AText := ARemains;1737 SplitText(ATextUTF8, MaxWidth, ARemains); 1738 lines.Add(ATextUTF8); 1739 ATextUTF8 := ARemains; 1119 1740 until ARemains = ''; 1120 1741 if AAlign in[twaLeft,twaMiddle,twaRight] then lineShift := lines.Count/2-0.5 … … 1140 1761 end; 1141 1762 1142 procedure TBGRAVectorizedFont.DrawTextRect(ADest: TBGRACanvas2D; AText : string;1763 procedure TBGRAVectorizedFont.DrawTextRect(ADest: TBGRACanvas2D; ATextUTF8: string; 1143 1764 X1, Y1, X2, Y2: Single; AAlign: TBGRATypeWriterAlignment); 1144 1765 var X,Y: single; … … 1154 1775 oldOrientation:= Orientation; 1155 1776 Orientation:= 0; 1156 DrawTextWordBreak(ADest,AText ,X,Y,X2-X1,AAlign);1777 DrawTextWordBreak(ADest,ATextUTF8,X,Y,X2-X1,AAlign); 1157 1778 Orientation:= oldOrientation; 1158 1779 end; 1159 1780 1160 procedure TBGRAVectorizedFont.DrawTextRect(ADest: TBGRACanvas2D; AText : string;1781 procedure TBGRAVectorizedFont.DrawTextRect(ADest: TBGRACanvas2D; ATextUTF8: string; 1161 1782 ATopLeft, ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment); 1162 1783 begin 1163 DrawTextRect(ADest,AText ,ATopLeft.X,ATopLeft.Y,ABottomRight.X,ABottomRight.Y,AAlign);1164 end; 1165 1166 function TBGRAVectorizedFont.GetTextWordBreakGlyphBoxes(AText : string; X, Y,1784 DrawTextRect(ADest,ATextUTF8,ATopLeft.X,ATopLeft.Y,ABottomRight.X,ABottomRight.Y,AAlign); 1785 end; 1786 1787 function TBGRAVectorizedFont.GetTextWordBreakGlyphBoxes(ATextUTF8: string; X, Y, 1167 1788 MaxWidth: Single; AAlign: TBGRATypeWriterAlignment): TGlyphBoxes; 1168 1789 var ARemains: string; … … 1177 1798 begin 1178 1799 result := nil; 1179 if AText = '' then exit;1800 if ATextUTF8 = '' then exit; 1180 1801 1181 1802 oldItalicSlope:= ItalicSlope; … … 1202 1823 lines := TStringList.Create; 1203 1824 repeat 1204 SplitText(AText , MaxWidth, ARemains);1205 lines.Add(AText );1206 AText := ARemains;1825 SplitText(ATextUTF8, MaxWidth, ARemains); 1826 lines.Add(ATextUTF8); 1827 ATextUTF8 := ARemains; 1207 1828 until ARemains = ''; 1208 1829 … … 1239 1860 end; 1240 1861 1241 function TBGRAVectorizedFont.GetTextRectGlyphBoxes(AText : string; X1, Y1, X2,1862 function TBGRAVectorizedFont.GetTextRectGlyphBoxes(ATextUTF8: string; X1, Y1, X2, 1242 1863 Y2: Single; AAlign: TBGRATypeWriterAlignment): TGlyphBoxes; 1243 1864 var X,Y,oldOrientation: single; … … 1256 1877 oldOrientation:= Orientation; 1257 1878 Orientation:= 0; 1258 result := GetTextWordBreakGlyphBoxes(AText ,X,Y,X2-X1,AAlign);1879 result := GetTextWordBreakGlyphBoxes(ATextUTF8,X,Y,X2-X1,AAlign); 1259 1880 Orientation:= oldOrientation; 1260 1881 end; 1261 1882 1262 function TBGRAVectorizedFont.GetTextRectGlyphBoxes(AText : string; ATopLeft,1883 function TBGRAVectorizedFont.GetTextRectGlyphBoxes(ATextUTF8: string; ATopLeft, 1263 1884 ABottomRight: TPointF; AAlign: TBGRATypeWriterAlignment): TGlyphBoxes; 1264 1885 begin 1265 result := GetTextRectGlyphBoxes(AText,ATopLeft.X,ATopLeft.Y,ABottomRight.X,ABottomRight.Y,AAlign); 1886 result := GetTextRectGlyphBoxes(ATextUTF8,ATopLeft.X,ATopLeft.Y,ABottomRight.X,ABottomRight.Y,AAlign); 1887 end; 1888 1889 procedure TBGRAVectorizedFont.UpdateDirectory; 1890 var 1891 NbFiles: integer; 1892 SearchRec: TSearchRec; 1893 Info: TBGRAGlyphsInfo; 1894 Fullname: string; 1895 begin 1896 NbFiles := 0; 1897 FDirectoryContent := nil; 1898 if FDirectory = '' then exit; 1899 if (length(FDirectory) > 0) and not (FDirectory[length(FDirectory)] in AllowDirectorySeparators) then 1900 FDirectory += DirectorySeparator; 1901 if FindFirstUTF8(FDirectory +'*.glyphs', faAnyFile, SearchRec) = 0 then 1902 repeat 1903 if (faDirectory or faVolumeId or faSysFile) and SearchRec.Attr = 0 then 1904 begin 1905 Fullname := FDirectory+SearchRec.Name; 1906 Info := LoadGlyphsInfo(Fullname); 1907 if (info.Name <> '') and (info.NbGlyphs > 0) then 1908 begin 1909 if NbFiles = length(FDirectoryContent) then 1910 setlength(FDirectoryContent,2*NbFiles+1); 1911 FDirectoryContent[NbFiles].Filename:= Fullname; 1912 FDirectoryContent[NbFiles].FontName:= info.Name; 1913 FDirectoryContent[NbFiles].FontStyle:= info.Style; 1914 inc(NbFiles); 1915 end; 1916 end; 1917 until FindNext(SearchRec) <> 0; 1918 SetLength(FDirectoryContent,NbFiles); 1919 end; 1920 1921 function TBGRAVectorizedFont.LoadGlyphsInfo(AFilenameUTF8: string): TBGRAGlyphsInfo; 1922 var Stream: TFileStreamUTF8; 1923 twHeader: TBGRACustomTypeWriterHeader; 1924 vfHeader: TBGRAVectorizedFontHeader; 1925 begin 1926 result.Name := ''; 1927 result.NbGlyphs := 0; 1928 result.Style := []; 1929 Stream := nil; 1930 try 1931 Stream := TFileStreamUTF8.Create(AFilenameUTF8,fmOpenRead); 1932 Stream.Position := 4; 1933 twHeader := ReadCustomTypeWriterHeader(Stream); 1934 result.NbGlyphs := twHeader.NbGlyphs; 1935 if twHeader.HeaderName = HeaderName then 1936 begin 1937 vfHeader := ReadVectorizedFontHeader(Stream); 1938 result.Name := vfHeader.Name; 1939 result.Style:= vfHeader.Style; 1940 end; 1941 except 1942 on ex:exception do 1943 begin 1944 1945 end; 1946 end; 1947 Stream.Free; 1266 1948 end; 1267 1949 … … 1271 1953 begin 1272 1954 Result:=inherited GetGlyph(AIdentifier); 1273 if (result = nil) and (FResolution > 0) then1955 if (result = nil) and (FResolution > 0) and (FFont <> nil) then 1274 1956 begin 1275 1957 g := TBGRAPolygonalGlyph.Create(AIdentifier); … … 1294 1976 1295 1977 procedure TBGRAVectorizedFont.DefaultWordBreakHandler(var ABefore,AAfter: string); 1296 var p: integer; 1297 begin 1298 if (AAfter <> '') and (ABefore <> '') and (AAfter[1]<> ' ') and (ABefore[length(ABefore)] <> ' ') then 1299 begin 1300 p := length(ABefore); 1301 while (p > 1) and (ABefore[p-1] <> ' ') do dec(p); 1302 if p > 1 then //can put the word after 1303 begin 1304 AAfter := copy(ABefore,p,length(ABefore)-p+1)+AAfter; 1305 ABefore := copy(ABefore,1,p-1); 1306 end else 1307 begin //cannot put the word after, so before 1308 1309 end; 1310 end; 1311 while (ABefore <> '') and (ABefore[length(ABefore)] =' ') do delete(ABefore,length(ABefore),1); 1312 while (AAfter <> '') and (AAfter[1] =' ') do delete(AAfter,1,1); 1978 begin 1979 BGRADefaultWordBreakHandler(ABefore,AAfter); 1980 end; 1981 1982 procedure TBGRAVectorizedFont.Init(AVectorize: boolean); 1983 begin 1984 FName := 'Arial'; 1985 FStyle := []; 1986 FFontMatrix := AffineMatrixIdentity; 1987 FOrientation := 0; 1988 FResolution := 100; 1989 FFontEmHeightRatio := 1; 1990 FFontEmHeightRatioComputed := false; 1991 if AVectorize then 1992 FFont := TFont.Create 1993 else 1994 FFont := nil; 1995 FBuffer := BGRABitmapFactory.Create; 1996 FFullHeight := 20; 1997 FItalicSlope := 0; 1998 UpdateFont; 1999 UpdateMatrix; 2000 FWordBreakHandler:= nil; 2001 end; 2002 2003 function TBGRAVectorizedFont.CustomHeaderSize: integer; 2004 begin 2005 Result:= (inherited CustomHeaderSize) + 4+length(FName)+4 + sizeof(single) + 4 + 5*4; 2006 end; 2007 2008 procedure TBGRAVectorizedFont.WriteCustomHeader(AStream: TStream); 2009 var metric: TFontPixelMetric; 2010 begin 2011 inherited WriteCustomHeader(AStream); 2012 WinWriteLongint(AStream, length(FName)); 2013 AStream.Write(FName[1],length(FName)); 2014 WinWriteLongint(AStream, integer(FStyle)); 2015 WinWriteSingle(AStream, FontEmHeightRatio); 2016 WinWriteLongint(AStream, Resolution); 2017 metric := FontPixelMetric; 2018 WinWriteLongint(AStream, metric.Baseline); 2019 WinWriteLongint(AStream, metric.xLine); 2020 WinWriteLongint(AStream, metric.CapLine); 2021 WinWriteLongint(AStream, metric.DescentLine); 2022 WinWriteLongint(AStream, metric.Lineheight); 2023 end; 2024 2025 procedure TBGRAVectorizedFont.ReadAdditionalHeader(AStream: TStream); 2026 var Header: TBGRAVectorizedFontHeader; 2027 begin 2028 inherited ReadAdditionalHeader(AStream); 2029 Header := ReadVectorizedFontHeader(AStream); 2030 FName := Header.Name; 2031 FStyle := Header.Style; 2032 if header.EmHeightRatio <> 0 then 2033 begin 2034 FFontEmHeightRatio := Header.EmHeightRatio; 2035 FFontEmHeightRatioComputed := true; 2036 end else 2037 begin 2038 FFontEmHeightRatio := 1; 2039 FFontEmHeightRatioComputed := false; 2040 end; 2041 FFontPixelMetric := Header.PixelMetric; 2042 FFontPixelMetricComputed := True; 2043 if FFont = nil then 2044 FResolution := Header.Resolution; 2045 end; 2046 2047 function TBGRAVectorizedFont.ReadVectorizedFontHeader(AStream: TStream): TBGRAVectorizedFontHeader; 2048 var lNameLength: integer; 2049 begin 2050 lNameLength := WinReadLongint(AStream); 2051 setlength(result.Name, lNameLength); 2052 AStream.Read(result.Name[1],length(result.Name)); 2053 result.Style := TFontStyles(WinReadLongint(AStream)); 2054 result.EmHeightRatio:= WinReadSingle(AStream); 2055 result.Resolution := WinReadLongint(AStream); 2056 result.PixelMetric.Baseline := WinReadLongint(AStream); 2057 result.PixelMetric.xLine := WinReadLongint(AStream); 2058 result.PixelMetric.CapLine := WinReadLongint(AStream); 2059 result.PixelMetric.DescentLine := WinReadLongint(AStream); 2060 result.PixelMetric.Lineheight := WinReadLongint(AStream); 2061 result.PixelMetric.Defined := result.PixelMetric.Lineheight > 0; 2062 end; 2063 2064 function TBGRAVectorizedFont.HeaderName: string; 2065 begin 2066 Result:= 'TBGRAVectorizedFont'; 2067 end; 2068 2069 procedure TBGRAVectorizedFont.SetDirectory(const AValue: string); 2070 begin 2071 if Trim(AValue) = Trim(FDirectory) then exit; 2072 FDirectory := Trim(AValue); 2073 UpdateDirectory; 2074 UpdateFont; 1313 2075 end; 1314 2076 -
GraphicTest/Packages/bgrabitmap/bgrawinbitmap.pas
r452 r472 70 70 procedure TWinBitmapTracker.Changed(Sender: TObject); 71 71 begin 72 FUser.AlphaCorrectionNeeded; 72 if FUser <> nil then 73 FUser.AlphaCorrectionNeeded; 73 74 inherited Changed(Sender); 74 75 end; -
GraphicTest/Packages/bgrabitmap/blendpixelinline.inc
r452 r472 530 530 aw := GammaExpansionTab[a]; 531 531 bw := GammaExpansionTab[b]; 532 {$HINTS OFF} 532 533 Result := GammaCompressionTab[aw+bw-(longword(aw)*longword(bw) shr 15)]; 534 {$HINTS ON} 533 535 end; 534 536 … … 562 564 function ByteLinearExclusionInline(a, b: byte): byte; inline; 563 565 begin 566 {$HINTS OFF} 564 567 Result := a+b-(a*b shr 7); 568 {$HINTS ON} 565 569 end; 566 570 -
GraphicTest/Packages/bgrabitmap/blurfast.inc
r452 r472 1 1 2 2 var 3 blurRow: array of cardinal;3 blurRow: array of UInt32or64; 4 4 5 5 { Compute weights of pixels in a row } … … 19 19 var 20 20 srcDelta, 21 weightShift: integer;21 verticalWeightShift, horizontalWeightShift: integer; 22 22 23 23 { Compute blur result in a vertical direction } … … 36 36 aDiv += w; 37 37 38 aw := aw shr weightShift;38 aw := aw shr verticalWeightShift; 39 39 {$hints off} 40 40 sumR += c.red*aw; … … 51 51 sumStartIndex,curIndex: integer; 52 52 total: TRowSum; 53 extendedTotal: TExtendedRowSum; 53 54 yb,xb,xs,ys1,ys2,x: integer; 54 55 w: cardinal; 55 56 pdest: PBGRAPixel; 56 57 bmpWidth,bmpHeight : integer; 57 radiusSquare: integer;58 accumulationFactor: double; 58 59 bounds: TRect; 59 60 … … 61 62 if radius = 0 then 62 63 begin 63 result := bmp.Duplicate;64 ADestination.PutImage(0,0,bmp,dmSet); 64 65 exit; 65 66 end; … … 67 68 bmpHeight := bmp.Height; 68 69 //create output 69 result := bmp.NewBitmap(bmpWidth,bmpHeight); 70 if (ADestination.Width <> bmp.Width) or (ADestination.Height <> bmp.Height) then 71 raise exception.Create('Dimension mismatch'); 70 72 bounds := bmp.GetImageBounds; 71 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then 72 exit; 73 if IsRectEmpty(bounds) then exit; 73 74 bounds.Left := max(0, bounds.Left - radius); 74 75 bounds.Top := max(0, bounds.Top - radius); 75 76 bounds.Right := min(bmp.Width, bounds.Right + radius); 76 77 bounds.Bottom := min(bmp.Height, bounds.Bottom + radius); 77 78 radiusSquare := sqr((radius+1)*(radius+2) div 2); 79 weightShift := 0; 80 while radiusSquare > 16384 do //18496 do 81 begin 82 radiusSquare := radiusSquare shr 1; 83 inc(weightShift); 78 if not IntersectRect(bounds,bounds,ABounds) then exit; 79 80 accumulationFactor := (radius+2)*(radius+1) div 2 + (radius+1)*radius div 2; 81 verticalWeightShift := 0; 82 while accumulationFactor > (high(UInt32or64) shr 16) + 1 do 83 begin 84 inc(verticalWeightShift); 85 accumulationFactor *= 0.5; 86 end; 87 horizontalWeightShift:= 0; 88 accumulationFactor *= ((radius+2)*(radius+1) div 2 + (radius+1)*radius div 2); 89 while accumulationFactor > (high(UInt32or64) shr 16) + 1 do 90 begin 91 inc(horizontalWeightShift); 92 accumulationFactor *= 0.5; 84 93 end; 85 94 ComputeBlurRow; … … 92 101 for yb := bounds.top to bounds.bottom-1 do 93 102 begin 103 if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break; 94 104 //evalute available vertical range 95 105 if yb - radius < 0 then … … 114 124 sumStartIndex := 0; 115 125 116 pdest := result.scanline[yb]+bounds.left;126 pdest := ADestination.scanline[yb]+bounds.left; 117 127 for xb := bounds.left to bounds.right-1 do 118 128 begin 119 129 //add vertical rows 120 {$hints off}121 fillchar(total,sizeof(total),0);122 {$hints on}123 130 curIndex:= sumStartIndex; 124 for xs := 0 to high(sums) do 125 with sums[curIndex] do 126 begin 127 w := blurRow[xs]; 128 total.sumA += sumA*w; 129 total.aDiv += aDiv*w; 130 total.sumR += sumR*w; 131 total.sumG += sumG*w; 132 total.sumB += sumB*w; 133 total.rgbDiv += rgbDiv*w; 134 inc(curIndex); 135 if curIndex = length(sums) then curIndex := 0; 131 if horizontalWeightShift > 4 then 132 begin //we don't want to loose too much precision 133 {$hints off} 134 fillchar(extendedTotal,sizeof(extendedTotal),0); 135 {$hints on} 136 for xs := 0 to high(sums) do 137 with sums[curIndex] do 138 begin 139 w := blurRow[xs]; 140 extendedTotal.sumA += TExtendedRowValue(sumA)*w; 141 extendedTotal.aDiv += TExtendedRowValue(aDiv)*w; 142 extendedTotal.sumR += TExtendedRowValue(sumR)*w; 143 extendedTotal.sumG += TExtendedRowValue(sumG)*w; 144 extendedTotal.sumB += TExtendedRowValue(sumB)*w; 145 extendedTotal.rgbDiv += TExtendedRowValue(rgbDiv)*w; 146 inc(curIndex); 147 if curIndex = length(sums) then curIndex := 0; 148 end; 149 if (extendedTotal.aDiv > 0) and (extendedTotal.rgbDiv > 0) then 150 pdest^:= ComputeExtendedAverage(extendedTotal) 151 else 152 pdest^:= BGRAPixelTransparent; 153 end else 154 if horizontalWeightShift > 0 then 155 begin //lossy but efficient way 156 {$hints off} 157 fillchar(total,sizeof(total),0); 158 {$hints on} 159 for xs := 0 to high(sums) do 160 with sums[curIndex] do 161 begin 162 w := blurRow[xs]; 163 total.sumA += sumA*w shr horizontalWeightShift; 164 total.aDiv += aDiv*w shr horizontalWeightShift; 165 total.sumR += sumR*w shr horizontalWeightShift; 166 total.sumG += sumG*w shr horizontalWeightShift; 167 total.sumB += sumB*w shr horizontalWeightShift; 168 total.rgbDiv += rgbDiv*w shr horizontalWeightShift; 169 inc(curIndex); 170 if curIndex = length(sums) then curIndex := 0; 171 end; 172 if (total.aDiv > 0) and (total.rgbDiv > 0) then 173 pdest^:= ComputeClampedAverage(total) 174 else 175 pdest^:= BGRAPixelTransparent; 176 end else 177 begin //normal way 178 {$hints off} 179 fillchar(total,sizeof(total),0); 180 {$hints on} 181 for xs := 0 to high(sums) do 182 with sums[curIndex] do 183 begin 184 w := blurRow[xs]; 185 total.sumA += sumA*w; 186 total.aDiv += aDiv*w; 187 total.sumR += sumR*w; 188 total.sumG += sumG*w; 189 total.sumB += sumB*w; 190 total.rgbDiv += rgbDiv*w; 191 inc(curIndex); 192 if curIndex = length(sums) then curIndex := 0; 193 end; 194 if (total.aDiv > 0) and (total.rgbDiv > 0) then 195 pdest^:= ComputeAverage(total) 196 else 197 pdest^:= BGRAPixelTransparent; 136 198 end; 137 if (total.aDiv > 0) and (total.rgbDiv > 0) then138 pdest^:= ComputeAverage(total)139 else140 pdest^:= BGRAPixelTransparent;141 199 inc(pdest); 142 200 //shift vertical rows … … 149 207 end; 150 208 end; 209 ADestination.InvalidateBitmap; 151 210 end; 152 211 -
GraphicTest/Packages/bgrabitmap/blurnormal.inc
r452 r472 108 108 //evaluate required bounds taking blur radius into acount 109 109 bounds := bmp.GetImageBounds; 110 if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then110 if IsRectEmpty(bounds) then 111 111 begin 112 112 result := false; … … 117 117 bounds.Right := min(bmp.Width, bounds.Right + maskWidth - 1 - blurOfs.X); 118 118 bounds.Bottom := min(bmp.Height, bounds.Bottom + maskHeight - 1 - blurOfs.Y); 119 if not IntersectRect(bounds, bounds, ABounds) then 120 begin 121 result := false; 122 exit; 123 end; 119 124 120 125 //init scanlines … … 157 162 LoadMask; 158 163 159 Result := bmp.NewBitmap(bmp.Width, bmp.Height); 164 if (ADestination.Width <> bmp.Width) or (ADestination.Height <> bmp.Height) then 165 raise exception.Create('Dimension mismatch'); 166 160 167 if not PrepareScan then exit; //nothing to do 161 168 … … 164 171 for yb := bounds.Top to bounds.Bottom - 1 do 165 172 begin 166 pdest := Result.ScanLine[yb] + bounds.Left; 173 if (ACheckShouldStop <> nil) and ACheckShouldStop(yb) then break; 174 pdest := ADestination.ScanLine[yb] + bounds.Left; 167 175 //compute vertical range 168 176 mindy := max(-blurOfs.Y, -yb); … … 242 250 ShiftScan(yb-blurOfs.Y+maskHeight); 243 251 end; 244 Result.InvalidateBitmap;252 ADestination.InvalidateBitmap; 245 253 end; 246 254 {$undef PARAM_MASKSHIFT} -
GraphicTest/Packages/bgrabitmap/csscolorconst.inc
r452 r472 1 {$IFDEF INCLUDE_COLOR_CONST} 2 {$UNDEF INCLUDE_COLOR_CONST} 1 3 const 4 //VGA colors 5 VGABlack: TBGRAPixel = (blue: 0; green: 0; red: 0; alpha: 255); 6 VGAGray: TBGRAPixel = (blue: 128; green: 128; red: 128; alpha: 255); 7 VGASilver: TBGRAPixel = (blue: 192; green: 192; red: 192; alpha: 255); 8 VGAWhite: TBGRAPixel = (blue: 255; green: 255; red: 255; alpha: 255); 9 VGAMaroon: TBGRAPixel = (blue: 0; green: 0; red: 128; alpha: 255); 10 VGARed: TBGRAPixel = (blue: 0; green: 0; red: 255; alpha: 255); 11 VGAPurple: TBGRAPixel = (blue: 128; green: 0; red: 128; alpha: 255); 12 VGAFuchsia: TBGRAPixel = (blue: 255; green: 0; red: 255; alpha: 255); 13 VGAGreen: TBGRAPixel = (blue: 0; green: 128; red: 0; alpha: 255); 14 VGALime: TBGRAPixel = (blue: 0; green: 255; red: 0; alpha: 255); 15 VGAOlive: TBGRAPixel = (blue: 0; green: 128; red: 128; alpha: 255); 16 VGAYellow: TBGRAPixel = (blue: 0; green: 255; red: 255; alpha: 255); 17 VGANavy: TBGRAPixel = (blue: 128; green: 0; red: 0; alpha: 255); 18 VGABlue: TBGRAPixel = (blue: 255; green: 0; red: 0; alpha: 255); 19 VGATeal: TBGRAPixel = (blue: 128; green: 128; red: 0; alpha: 255); 20 VGAAqua: TBGRAPixel = (blue: 255; green: 255; red: 0; alpha: 255); 21 2 22 //Red colors 3 23 CSSIndianRed: TBGRAPixel = (blue: 92; green: 92; red: 205; alpha: 255); … … 159 179 CSSDarkSlateGray: TBGRAPixel = (blue: 79; green: 79; red: 47; alpha: 255); 160 180 CSSBlack: TBGRAPixel = (blue: 0; green: 0; red: 0; alpha: 255); 161 181 {$ENDIF} 182 {$IFDEF INCLUDE_COLOR_LIST} 183 {$UNDEF INCLUDE_COLOR_LIST} 184 VGAColors := TBGRAColorList.Create; 185 VGAColors.Add('Black',VGABlack); 186 VGAColors.Add('Gray',VGAGray); 187 VGAColors.Add('Silver',VGASilver); 188 VGAColors.Add('White',VGAWhite); 189 VGAColors.Add('Maroon',VGAMaroon); 190 VGAColors.Add('Red',VGARed); 191 VGAColors.Add('Purple',VGAPurple); 192 VGAColors.Add('Fuchsia',VGAFuchsia); 193 VGAColors.Add('Green',VGAGreen); 194 VGAColors.Add('Lime',VGALime); 195 VGAColors.Add('Olive',VGAOlive); 196 VGAColors.Add('Yellow',VGAYellow); 197 VGAColors.Add('Navy',VGANavy); 198 VGAColors.Add('Blue',VGABlue); 199 VGAColors.Add('Teal',VGATeal); 200 VGAColors.Add('Aqua',VGAAqua); 201 VGAColors.Finished; 202 203 CSSColors := TBGRAColorList.Create; 204 CSSColors.Add('AliceBlue',CSSAliceBlue); 205 CSSColors.Add('AntiqueWhite',CSSAntiqueWhite); 206 CSSColors.Add('Aqua',CSSAqua); 207 CSSColors.Add('Aquamarine',CSSAquamarine); 208 CSSColors.Add('Azure',CSSAzure); 209 CSSColors.Add('Beige',CSSBeige); 210 CSSColors.Add('Bisque',CSSBisque); 211 CSSColors.Add('Black',CSSBlack); 212 CSSColors.Add('BlanchedAlmond',CSSBlanchedAlmond); 213 CSSColors.Add('Blue',CSSBlue); 214 CSSColors.Add('BlueViolet',CSSBlueViolet); 215 CSSColors.Add('Brown',CSSBrown); 216 CSSColors.Add('BurlyWood',CSSBurlyWood); 217 CSSColors.Add('CadetBlue',CSSCadetBlue); 218 CSSColors.Add('Chartreuse',CSSChartreuse); 219 CSSColors.Add('Chocolate',CSSChocolate); 220 CSSColors.Add('Coral',CSSCoral); 221 CSSColors.Add('CornflowerBlue',CSSCornflowerBlue); 222 CSSColors.Add('Cornsilk',CSSCornsilk); 223 CSSColors.Add('Crimson',CSSCrimson); 224 CSSColors.Add('Cyan',CSSCyan); 225 CSSColors.Add('DarkBlue',CSSDarkBlue); 226 CSSColors.Add('DarkCyan',CSSDarkCyan); 227 CSSColors.Add('DarkGoldenrod',CSSDarkGoldenrod); 228 CSSColors.Add('DarkGray',CSSDarkGray); 229 CSSColors.Add('DarkGreen',CSSDarkGreen); 230 CSSColors.Add('DarkKhaki',CSSDarkKhaki); 231 CSSColors.Add('DarkMagenta',CSSDarkMagenta); 232 CSSColors.Add('DarkOliveGreen',CSSDarkOliveGreen); 233 CSSColors.Add('DarkOrange',CSSDarkOrange); 234 CSSColors.Add('DarkOrchid',CSSDarkOrchid); 235 CSSColors.Add('DarkRed',CSSDarkRed); 236 CSSColors.Add('DarkSalmon',CSSDarkSalmon); 237 CSSColors.Add('DarkSeaGreen',CSSDarkSeaGreen); 238 CSSColors.Add('DarkSlateBlue',CSSDarkSlateBlue); 239 CSSColors.Add('DarkSlateGray',CSSDarkSlateGray); 240 CSSColors.Add('DarkTurquoise',CSSDarkTurquoise); 241 CSSColors.Add('DarkViolet',CSSDarkViolet); 242 CSSColors.Add('DeepPink',CSSDeepPink); 243 CSSColors.Add('DeepSkyBlue',CSSDeepSkyBlue); 244 CSSColors.Add('DimGray',CSSDimGray); 245 CSSColors.Add('DodgerBlue',CSSDodgerBlue); 246 CSSColors.Add('FireBrick',CSSFireBrick); 247 CSSColors.Add('FloralWhite',CSSFloralWhite); 248 CSSColors.Add('ForestGreen',CSSForestGreen); 249 CSSColors.Add('Fuchsia',CSSFuchsia); 250 CSSColors.Add('Gainsboro',CSSGainsboro); 251 CSSColors.Add('GhostWhite',CSSGhostWhite); 252 CSSColors.Add('Gold',CSSGold); 253 CSSColors.Add('Goldenrod',CSSGoldenrod); 254 CSSColors.Add('Gray',CSSGray); 255 CSSColors.Add('Green',CSSGreen); 256 CSSColors.Add('GreenYellow',CSSGreenYellow); 257 CSSColors.Add('Honeydew',CSSHoneydew); 258 CSSColors.Add('HotPink',CSSHotPink); 259 CSSColors.Add('IndianRed',CSSIndianRed); 260 CSSColors.Add('Indigo',CSSIndigo); 261 CSSColors.Add('Ivory',CSSIvory); 262 CSSColors.Add('Khaki',CSSKhaki); 263 CSSColors.Add('Lavender',CSSLavender); 264 CSSColors.Add('LavenderBlush',CSSLavenderBlush); 265 CSSColors.Add('LawnGreen',CSSLawnGreen); 266 CSSColors.Add('LemonChiffon',CSSLemonChiffon); 267 CSSColors.Add('LightBlue',CSSLightBlue); 268 CSSColors.Add('LightCoral',CSSLightCoral); 269 CSSColors.Add('LightCyan',CSSLightCyan); 270 CSSColors.Add('LightGoldenrodYellow',CSSLightGoldenrodYellow); 271 CSSColors.Add('LightGray',CSSLightGray); 272 CSSColors.Add('LightGreen',CSSLightGreen); 273 CSSColors.Add('LightPink',CSSLightPink); 274 CSSColors.Add('LightSalmon',CSSLightSalmon); 275 CSSColors.Add('LightSeaGreen',CSSLightSeaGreen); 276 CSSColors.Add('LightSkyBlue',CSSLightSkyBlue); 277 CSSColors.Add('LightSlateGray',CSSLightSlateGray); 278 CSSColors.Add('LightSteelBlue',CSSLightSteelBlue); 279 CSSColors.Add('LightYellow',CSSLightYellow); 280 CSSColors.Add('Lime',CSSLime); 281 CSSColors.Add('LimeGreen',CSSLimeGreen); 282 CSSColors.Add('Linen',CSSLinen); 283 CSSColors.Add('Magenta',CSSMagenta); 284 CSSColors.Add('Maroon',CSSMaroon); 285 CSSColors.Add('MediumAquamarine',CSSMediumAquamarine); 286 CSSColors.Add('MediumBlue',CSSMediumBlue); 287 CSSColors.Add('MediumOrchid',CSSMediumOrchid); 288 CSSColors.Add('MediumPurple',CSSMediumPurple); 289 CSSColors.Add('MediumSeaGreen',CSSMediumSeaGreen); 290 CSSColors.Add('MediumSlateBlue',CSSMediumSlateBlue); 291 CSSColors.Add('MediumSpringGreen',CSSMediumSpringGreen); 292 CSSColors.Add('MediumTurquoise',CSSMediumTurquoise); 293 CSSColors.Add('MediumVioletRed',CSSMediumVioletRed); 294 CSSColors.Add('MidnightBlue',CSSMidnightBlue); 295 CSSColors.Add('MintCream',CSSMintCream); 296 CSSColors.Add('MistyRose',CSSMistyRose); 297 CSSColors.Add('Moccasin',CSSMoccasin); 298 CSSColors.Add('NavajoWhite',CSSNavajoWhite); 299 CSSColors.Add('Navy',CSSNavy); 300 CSSColors.Add('OldLace',CSSOldLace); 301 CSSColors.Add('Olive',CSSOlive); 302 CSSColors.Add('OliveDrab',CSSOliveDrab); 303 CSSColors.Add('Orange',CSSOrange); 304 CSSColors.Add('OrangeRed',CSSOrangeRed); 305 CSSColors.Add('Orchid',CSSOrchid); 306 CSSColors.Add('PaleGoldenrod',CSSPaleGoldenrod); 307 CSSColors.Add('PaleGreen',CSSPaleGreen); 308 CSSColors.Add('PaleTurquoise',CSSPaleTurquoise); 309 CSSColors.Add('PaleVioletRed',CSSPaleVioletRed); 310 CSSColors.Add('PapayaWhip',CSSPapayaWhip); 311 CSSColors.Add('PeachPuff',CSSPeachPuff); 312 CSSColors.Add('Peru',CSSPeru); 313 CSSColors.Add('Pink',CSSPink); 314 CSSColors.Add('Plum',CSSPlum); 315 CSSColors.Add('PowderBlue',CSSPowderBlue); 316 CSSColors.Add('Purple',CSSPurple); 317 CSSColors.Add('Red',CSSRed); 318 CSSColors.Add('RosyBrown',CSSRosyBrown); 319 CSSColors.Add('RoyalBlue',CSSRoyalBlue); 320 CSSColors.Add('SaddleBrown',CSSSaddleBrown); 321 CSSColors.Add('Salmon',CSSSalmon); 322 CSSColors.Add('SandyBrown',CSSSandyBrown); 323 CSSColors.Add('SeaGreen',CSSSeaGreen); 324 CSSColors.Add('Seashell',CSSSeashell); 325 CSSColors.Add('Sienna',CSSSienna); 326 CSSColors.Add('Silver',CSSSilver); 327 CSSColors.Add('SkyBlue',CSSSkyBlue); 328 CSSColors.Add('SlateBlue',CSSSlateBlue); 329 CSSColors.Add('SlateGray',CSSSlateGray); 330 CSSColors.Add('Snow',CSSSnow); 331 CSSColors.Add('SpringGreen',CSSSpringGreen); 332 CSSColors.Add('SteelBlue',CSSSteelBlue); 333 CSSColors.Add('Tan',CSSTan); 334 CSSColors.Add('Teal',CSSTeal); 335 CSSColors.Add('Thistle',CSSThistle); 336 CSSColors.Add('Tomato',CSSTomato); 337 CSSColors.Add('Turquoise',CSSTurquoise); 338 CSSColors.Add('Violet',CSSViolet); 339 CSSColors.Add('Wheat',CSSWheat); 340 CSSColors.Add('White',CSSWhite); 341 CSSColors.Add('WhiteSmoke',CSSWhiteSmoke); 342 CSSColors.Add('Yellow',CSSYellow); 343 CSSColors.Add('YellowGreen',CSSYellowGreen); 344 CSSColors.Finished; 345 {$ENDIF} 346 -
GraphicTest/Packages/bgrabitmap/filldensitysegment256.inc
r452 r472 13 13 14 14 if ix1 = ix2 then 15 (density + (ix1 - minx))^ += round((x2 -x1)*256)15 (density + (ix1 - minx))^ += round((x2-ix2)*256) - round((x1-ix1)*256) 16 16 else 17 17 begin 18 (density + (ix1 - minx))^ += round((1 - (x1 - ix1))*256);18 (density + (ix1 - minx))^ += 256 - round((x1 - ix1)*256); 19 19 if (ix2 <= maxx) then 20 20 (density + (ix2 - minx))^ += round((x2 - ix2)*256); -
GraphicTest/Packages/bgrabitmap/lightingclasses3d.inc
r452 r472 5 5 TBGRAMaterial3D = class(TInterfacedObject, IBGRAMaterial3D) 6 6 private 7 FDiffuseColorInt: TColorInt65536; 7 FName: string; 8 FTexture: IBGRAScanner; 9 FAutoSimpleColor,FAutoAmbiantColor,FAutoDiffuseColor,FAutoSpecularColor: boolean; 10 FSimpleColorInt, FAmbiantColorInt, FDiffuseColorInt: TColorInt65536; 8 11 FDiffuseLightness: integer; 12 FTextureZoom: TPointF; 13 9 14 FSpecularColorInt: TColorInt65536; 10 FAutoDiffuseColor,FAutoSpecularColor: boolean;11 15 FSpecularIndex: integer; 12 16 FSpecularOn: boolean; 17 13 18 FSaturationLowF: single; 14 19 FSaturationHighF: single; … … 21 26 22 27 procedure UpdateSpecular; 28 procedure UpdateSimpleColor; 23 29 procedure ComputePowerTable; 24 30 public … … 26 32 destructor Destroy; override; 27 33 34 function GetAutoAmbiantColor: boolean; 28 35 function GetAutoDiffuseColor: boolean; 29 36 function GetAutoSpecularColor: boolean; 37 function GetAutoSimpleColor: boolean; 38 function GetAmbiantAlpha: byte; 39 function GetAmbiantColor: TBGRAPixel; 40 function GetAmbiantColorF: TColorF; 41 function GetAmbiantColorInt: TColorInt65536; 42 function GetDiffuseAlpha: byte; 30 43 function GetDiffuseColor: TBGRAPixel; 31 44 function GetDiffuseColorF: TColorF; … … 38 51 function GetSaturationHigh: single; 39 52 function GetSaturationLow: single; 53 function GetSimpleAlpha: byte; 54 function GetSimpleColor: TBGRAPixel; 55 function GetSimpleColorF: TColorF; 56 function GetSimpleColorInt: TColorInt65536; 57 function GetTexture: IBGRAScanner; 58 function GetTextureZoom: TPointF; 59 procedure SetAutoAmbiantColor(const AValue: boolean); 40 60 procedure SetAutoDiffuseColor(const AValue: boolean); 41 61 procedure SetAutoSpecularColor(const AValue: boolean); 62 procedure SetAmbiantAlpha(AValue: byte); 63 procedure SetAmbiantColor(const AValue: TBGRAPixel); 64 procedure SetAmbiantColorF(const AValue: TColorF); 65 procedure SetAmbiantColorInt(const AValue: TColorInt65536); 66 procedure SetDiffuseAlpha(AValue: byte); 42 67 procedure SetDiffuseColor(const AValue: TBGRAPixel); 43 68 procedure SetDiffuseColorF(const AValue: TColorF); … … 50 75 procedure SetSaturationHigh(const AValue: single); 51 76 procedure SetSaturationLow(const AValue: single); 77 procedure SetSimpleAlpha(AValue: byte); 78 procedure SetSimpleColor(AValue: TBGRAPixel); 79 procedure SetSimpleColorF(AValue: TColorF); 80 procedure SetSimpleColorInt(AValue: TColorInt65536); 81 procedure SetTexture(AValue: IBGRAScanner); 82 procedure SetTextureZoom(AValue: TPointF); 83 function GetName: string; 84 procedure SetName(const AValue: string); 52 85 53 86 function GetSpecularOn: boolean; … … 63 96 procedure TBGRAMaterial3D.UpdateSpecular; 64 97 begin 98 FAutoSpecularColor := (FSpecularColorInt.r = 65536) and (FSpecularColorInt.g = 65536) and (FSpecularColorInt.b = 65536) and (FSpecularColorInt.a = 65536); 65 99 FSpecularOn := (FSpecularIndex > 0) and ((FSpecularColorInt.r <> 0) or (FSpecularColorInt.g <> 0) or (FSpecularColorInt.b <> 0) or 66 100 FAutoSpecularColor); 101 end; 102 103 procedure TBGRAMaterial3D.UpdateSimpleColor; 104 begin 105 FSimpleColorInt := (FAmbiantColorInt+FDiffuseColorInt)*32768; 106 FAutoSimpleColor := (FSimpleColorInt.r = 65536) and (FSimpleColorInt.g = 65536) and (FSimpleColorInt.b = 65536) and (FSimpleColorInt.a = 65536); 67 107 end; 68 108 … … 91 131 constructor TBGRAMaterial3D.Create; 92 132 begin 133 SetAmbiantColorInt(ColorInt65536(65536,65536,65536)); 93 134 SetDiffuseColorInt(ColorInt65536(65536,65536,65536)); 94 FAutoDiffuseColor:= True;95 FSpecularColorInt := ColorInt65536(0,0,0);96 FAutoSpecularColor:= True;97 135 FSpecularIndex := 10; 98 FSpecularOn := false;136 SetSpecularColorInt(ColorInt65536(0,0,0)); 99 137 FLightThroughFactor:= 0; 100 138 SetSaturationLow(2); 101 139 SetSaturationHigh(3); 102 140 141 FTexture := nil; 142 FTextureZoom := PointF(1,1); 143 103 144 FPowerTableSize := 128; 104 145 FPowerTableSizeF := FPowerTableSize; … … 111 152 end; 112 153 154 function TBGRAMaterial3D.GetAutoAmbiantColor: boolean; 155 begin 156 result := FAutoAmbiantColor; 157 end; 158 159 procedure TBGRAMaterial3D.SetDiffuseAlpha(AValue: byte); 160 begin 161 if AValue = 0 then 162 FDiffuseColorInt.a := 0 163 else 164 FDiffuseColorInt.a := AValue*257+1; 165 UpdateSimpleColor; 166 end; 167 113 168 function TBGRAMaterial3D.GetAutoDiffuseColor: boolean; 114 169 begin … … 121 176 end; 122 177 178 function TBGRAMaterial3D.GetAutoSimpleColor: boolean; 179 begin 180 result := FAutoSimpleColor; 181 end; 182 183 function TBGRAMaterial3D.GetAmbiantAlpha: byte; 184 var v: integer; 185 begin 186 if FAmbiantColorInt.a < 128 then 187 result := 0 188 else 189 begin 190 v := (FAmbiantColorInt.a-128) shr 8; 191 if v > 255 then v := 255; 192 result := v; 193 end; 194 end; 195 196 function TBGRAMaterial3D.GetAmbiantColor: TBGRAPixel; 197 begin 198 result := ColorIntToBGRA(FAmbiantColorInt); 199 end; 200 201 function TBGRAMaterial3D.GetAmbiantColorF: TColorF; 202 begin 203 result := ColorInt65536ToColorF(FAmbiantColorInt); 204 end; 205 206 function TBGRAMaterial3D.GetAmbiantColorInt: TColorInt65536; 207 begin 208 result := FAmbiantColorInt; 209 end; 210 211 function TBGRAMaterial3D.GetDiffuseAlpha: byte; 212 var v: integer; 213 begin 214 if FDiffuseColorInt.a < 128 then 215 result := 0 216 else 217 begin 218 v := (FDiffuseColorInt.a-128) shr 8; 219 if v > 255 then v := 255; 220 result := v; 221 end; 222 end; 223 123 224 function TBGRAMaterial3D.GetDiffuseColor: TBGRAPixel; 124 225 begin … … 171 272 end; 172 273 274 function TBGRAMaterial3D.GetSimpleAlpha: byte; 275 begin 276 result := (GetAmbiantAlpha + GetDiffuseAlpha) shr 1; 277 end; 278 279 function TBGRAMaterial3D.GetSimpleColor: TBGRAPixel; 280 begin 281 result := ColorIntToBGRA(GetSimpleColorInt); 282 end; 283 284 function TBGRAMaterial3D.GetSimpleColorF: TColorF; 285 begin 286 result := ColorInt65536ToColorF(GetSimpleColorInt); 287 end; 288 289 function TBGRAMaterial3D.GetSimpleColorInt: TColorInt65536; 290 begin 291 result := (GetAmbiantColorInt + GetDiffuseColorInt)*32768; 292 end; 293 294 function TBGRAMaterial3D.GetTexture: IBGRAScanner; 295 begin 296 result := FTexture; 297 end; 298 299 function TBGRAMaterial3D.GetTextureZoom: TPointF; 300 begin 301 result := FTextureZoom; 302 end; 303 304 procedure TBGRAMaterial3D.SetAutoAmbiantColor(const AValue: boolean); 305 begin 306 If AValue then 307 SetAmbiantColorInt(ColorInt65536(65536,65536,65536)); 308 end; 309 173 310 procedure TBGRAMaterial3D.SetAutoDiffuseColor(const AValue: boolean); 174 311 begin 175 FAutoDiffuseColor:= AValue; 312 If AValue then 313 SetDiffuseColorInt(ColorInt65536(65536,65536,65536)); 176 314 end; 177 315 178 316 procedure TBGRAMaterial3D.SetAutoSpecularColor(const AValue: boolean); 179 317 begin 180 FAutoSpecularColor:= AValue; 181 UpdateSpecular; 318 If AValue then 319 SetSpecularColorInt(ColorInt65536(65536,65536,65536)); 320 end; 321 322 procedure TBGRAMaterial3D.SetAmbiantAlpha(AValue: byte); 323 begin 324 if AValue = 0 then 325 FAmbiantColorInt.a := 0 326 else 327 FAmbiantColorInt.a := AValue*257+1; 328 UpdateSimpleColor; 329 end; 330 331 procedure TBGRAMaterial3D.SetAmbiantColor(const AValue: TBGRAPixel); 332 begin 333 FAmbiantColorInt := BGRAToColorInt(AValue); 334 FAutoAmbiantColor := (FAmbiantColorInt.r = 65536) and (FAmbiantColorInt.g = 65536) and (FAmbiantColorInt.b = 65536) and (FAmbiantColorInt.a = 65536); 335 UpdateSimpleColor; 336 end; 337 338 procedure TBGRAMaterial3D.SetAmbiantColorF(const AValue: TColorF); 339 begin 340 FAmbiantColorInt := ColorFToColorInt65536(AValue); 341 FAutoAmbiantColor := (FAmbiantColorInt.r = 65536) and (FAmbiantColorInt.g = 65536) and (FAmbiantColorInt.b = 65536) and (FAmbiantColorInt.a = 65536); 342 UpdateSimpleColor; 343 end; 344 345 procedure TBGRAMaterial3D.SetAmbiantColorInt(const AValue: TColorInt65536); 346 begin 347 FAmbiantColorInt := AValue; 348 FAutoAmbiantColor := (FAmbiantColorInt.r = 65536) and (FAmbiantColorInt.g = 65536) and (FAmbiantColorInt.b = 65536) and (FAmbiantColorInt.a = 65536); 349 UpdateSimpleColor; 182 350 end; 183 351 … … 186 354 FDiffuseColorInt := BGRAToColorInt(AValue); 187 355 FDiffuseLightness := (FDiffuseColorInt.r + FDiffuseColorInt.g + FDiffuseColorInt.b) div 6; 356 FAutoDiffuseColor:= (FDiffuseColorInt.r = 65536) and (FDiffuseColorInt.g = 65536) and (FDiffuseColorInt.b = 65536); 357 UpdateSimpleColor; 188 358 end; 189 359 … … 192 362 FDiffuseColorInt := ColorFToColorInt65536(AValue); 193 363 FDiffuseLightness := (FDiffuseColorInt.r + FDiffuseColorInt.g + FDiffuseColorInt.b) div 6; 364 FAutoDiffuseColor:= (FDiffuseColorInt.r = 65536) and (FDiffuseColorInt.g = 65536) and (FDiffuseColorInt.b = 65536); 365 UpdateSimpleColor; 194 366 end; 195 367 … … 198 370 FDiffuseColorInt := AValue; 199 371 FDiffuseLightness := (FDiffuseColorInt.r + FDiffuseColorInt.g + FDiffuseColorInt.b) div 6; 372 FAutoDiffuseColor:= (FDiffuseColorInt.r = 65536) and (FDiffuseColorInt.g = 65536) and (FDiffuseColorInt.b = 65536); 373 UpdateSimpleColor; 200 374 end; 201 375 … … 238 412 begin 239 413 FSaturationLowF:= AValue; 414 end; 415 416 procedure TBGRAMaterial3D.SetSimpleAlpha(AValue: byte); 417 begin 418 SetAmbiantAlpha(AValue); 419 SetDiffuseAlpha(AValue); 420 end; 421 422 procedure TBGRAMaterial3D.SetSimpleColor(AValue: TBGRAPixel); 423 begin 424 SetAmbiantColor(AValue); 425 SetDiffuseColor(AValue); 426 end; 427 428 procedure TBGRAMaterial3D.SetSimpleColorF(AValue: TColorF); 429 begin 430 SetAmbiantColorF(AValue); 431 SetDiffuseColorF(AValue); 432 end; 433 434 procedure TBGRAMaterial3D.SetSimpleColorInt(AValue: TColorInt65536); 435 begin 436 SetAmbiantColorInt(AValue); 437 SetDiffuseColorInt(AValue); 438 end; 439 440 procedure TBGRAMaterial3D.SetTexture(AValue: IBGRAScanner); 441 begin 442 FTexture := AValue; 443 end; 444 445 procedure TBGRAMaterial3D.SetTextureZoom(AValue: TPointF); 446 begin 447 FTextureZoom := AValue; 448 end; 449 450 function TBGRAMaterial3D.GetName: string; 451 begin 452 result := FName; 453 end; 454 455 procedure TBGRAMaterial3D.SetName(const AValue: string); 456 begin 457 FName := AValue; 240 458 end; 241 459 … … 283 501 end 284 502 else 285 NH *=FPowerTableSize;503 PowerTablePos := NH*FPowerTableSize; 286 504 {$ELSE} 287 505 PowerTablePos := NH; … … 298 516 Context^.diffuseColor += ALightColor*round(DiffuseIntensity*65536) 299 517 else 300 Context^.diffuseColor += FDiffuseColorInt*round(DiffuseIntensity*65536);518 Context^.diffuseColor += ALightColor*FDiffuseColorInt*round(DiffuseIntensity*65536); 301 519 302 520 if FAutoSpecularColor then 303 521 Context^.specularColor += ALightColor*round(SpecularIntensity* NnH*65536) 304 522 else 305 Context^.specularColor += FSpecularColorInt*round(SpecularIntensity* NnH*65536);523 Context^.specularColor += ALightColor*FSpecularColorInt*round(SpecularIntensity* NnH*65536); 306 524 end; 307 525 … … 312 530 Context^.diffuseColor += ALightColor*round(DiffuseIntensity*65536) 313 531 else 314 Context^.diffuseColor += FDiffuseColorInt*round(DiffuseIntensity*65536);532 Context^.diffuseColor += ALightColor*FDiffuseColorInt*round(DiffuseIntensity*65536); 315 533 end; 316 534 … … 327 545 begin 328 546 if FDiffuseLightness <> 32768 then 329 Context^.lightness += CombineLightness(DiffuseLightnessTerm32768, FDiffuseLightness)547 Context^.lightness += CombineLightness(DiffuseLightnessTerm32768,CombineLightness(FDiffuseLightness,ALightLightness)) 330 548 else 331 Context^.lightness += DiffuseLightnessTerm32768;549 Context^.lightness += CombineLightness(DiffuseLightnessTerm32768,ALightLightness); 332 550 end; 333 551 end; … … 561 779 function TBGRADirectionalLight3D.GetDirection: TPoint3D; 562 780 begin 563 result := Point3D( FDirection.x,FDirection.y,FDirection.z);781 result := Point3D(-FDirection.x,-FDirection.y,-FDirection.z); 564 782 end; 565 783 -
GraphicTest/Packages/bgrabitmap/lineartexscan.inc
r452 r472 1 {$i bgrasse.inc} 2 1 3 var 2 4 xLen: single; //horizontal length in pixels … … 58 60 {$ENDIF} 59 61 60 {$IFDEF CPUI386}62 {$IFDEF BGRASSE_AVAILABLE} 61 63 if UseSSE then 62 64 begin -
GraphicTest/Packages/bgrabitmap/perspectivescan.inc
r452 r472 1 {$i bgrasse.inc} 2 1 3 var 2 4 //loop variables … … 106 108 {$ENDIF} 107 109 108 {$IFDEF CPUI386}110 {$IFDEF BGRASSE_AVAILABLE} 109 111 if UseSSE then 110 112 begin -
GraphicTest/Packages/bgrabitmap/perspectivescan2.inc
r452 r472 1 {$asmmode intel} 1 {$i bgrasse.inc} 2 3 {$ifdef BGRASSE_AVAILABLE}{$asmmode intel}{$endif} 2 4 {$IFDEF PARAM_USESSE} 3 5 asm 4 6 {$IFDEF PARAM_USESHADER} 5 mov eax, ShaderContext 6 movaps xmm2, [eax+32] //positionInvZ 7 movaps xmm3, [eax+48] //normalInvZ 7 {$IFDEF cpux86_64} 8 mov rax, ShaderContext 9 movaps xmm2, [rax+32] //positionInvZ 10 movaps xmm3, [rax+48] //normalInvZ 11 {$ELSE} 12 mov eax, ShaderContext 13 movaps xmm2, [eax+32] //positionInvZ 14 movaps xmm3, [eax+48] //normalInvZ 15 {$ENDIF} 8 16 {$ENDIF} 9 17 {$IFNDEF PARAM_USESOLIDCOLOR} … … 27 35 28 36 {$IFDEF PARAM_USESHADER} 37 {$ifdef cpux86_64} 38 mov rax, ShaderContext 39 {$else} 29 40 mov eax, ShaderContext 41 {$endif} 30 42 31 43 mulps xmm2, xmm4 //positionInvZ*zPos (A) 32 33 44 mulps xmm3, xmm4 //normalInvZ*zPos 34 45 {$ifdef cpux86_64} 46 movaps [rax+0], xmm2 //(A) Position 47 {$else} 35 48 movaps [eax+0], xmm2 //(A) Position 49 {$endif} 36 50 37 51 //normalize … … 53 67 {$ENDIF} 54 68 69 xorps xmm7,xmm7 70 comiss xmm3,xmm7 71 jna @skipnormal 72 55 73 rsqrtps xmm3,xmm3 56 57 74 mulps xmm3, xmm1 //apply 58 75 @skipnormal: 76 77 {$ifdef cpux86_64} 78 movaps [rax+16], xmm3 //Normal 79 {$else} 59 80 movaps [eax+16], xmm3 //Normal 81 {$endif} 60 82 {$ENDIF} 61 83 … … 142 164 {$IFDEF PARAM_USESHADER} 143 165 {$IFDEF PARAM_USESSE} 166 {$ifdef cpux86_64} 144 167 asm 145 mov eax, ShaderContext146 movaps xmm2, [ eax+32] //PositionInvZ147 movaps xmm1, [ eax+64] //PositionStepInvZ148 movaps xmm3, [ eax+48] //NormalInvZ149 movaps xmm0, [ eax+80] //NormalStepInvZ168 mov rax, ShaderContext 169 movaps xmm2, [rax+32] //PositionInvZ 170 movaps xmm1, [rax+64] //PositionStepInvZ 171 movaps xmm3, [rax+48] //NormalInvZ 172 movaps xmm0, [rax+80] //NormalStepInvZ 150 173 addps xmm2, xmm1 151 174 addps xmm3, xmm0 152 movaps [ eax+32], xmm2153 movaps [ eax+48], xmm3175 movaps [rax+32], xmm2 176 movaps [rax+48], xmm3 154 177 end; 155 {asm 156 mov eax, ShaderContext 157 movaps xmm2, [eax+32] //PositionInvZ 158 movaps xmm1, [eax+64] //PositionStepInvZ 159 addps xmm2, xmm1 160 movaps [eax+32], xmm2 161 162 movaps xmm3, [eax+48] //NormalInvZ 163 movaps xmm1, [eax+80] //NormalStepInvZ 164 addps xmm3, xmm1 165 movaps [eax+48], xmm3 166 end;} 178 {$else} 179 asm 180 mov eax, ShaderContext 181 movaps xmm2, [eax+32] //PositionInvZ 182 movaps xmm1, [eax+64] //PositionStepInvZ 183 movaps xmm3, [eax+48] //NormalInvZ 184 movaps xmm0, [eax+80] //NormalStepInvZ 185 addps xmm2, xmm1 186 addps xmm3, xmm0 187 movaps [eax+32], xmm2 188 movaps [eax+48], xmm3 189 end; 190 {$endif} 167 191 {$ELSE} 168 192 with ShaderContext^ do -
GraphicTest/Packages/bgrabitmap/phongdraw.inc
r452 r472 73 73 x,y : integer; // Coordinates of point in height map. 74 74 vS1,vS2: TPoint3D_128; // surface vectors (plane) 75 deltaDown: Int32or64; 76 IsLineUp,IsLineDown: boolean; 75 77 76 78 begin 79 if map = nil then exit; 77 80 {$ifndef PARAM_SIMPLECOLOR} 78 81 {$ifndef PARAM_SCANNER} … … 106 109 LightPosition.Y-ofsY, 107 110 LightPositionZ); 108 {$ifdef PARAM_PHONGSSE}109 asm110 movups xmm1, vLS111 end;112 LightDestFactor4 := Point3D_128(LightDestFactor,LightDestFactor,LightDestFactor,LightDestFactor);113 {$endif}114 111 115 112 //surface vectors … … 119 116 vV := Point3D_128(0,0,1); 120 117 121 122 118 dist := 0; 123 119 LdotN := 0; 124 120 NnH := 0; 125 121 122 {$ifdef PARAM_PHONGSSE} 123 LightDestFactor4 := Point3D_128(LightDestFactor,LightDestFactor,LightDestFactor,LightDestFactor); 124 {$endif} 125 126 if map.LineOrder = riloTopToBottom then 127 deltaDown := map.Width*sizeof(TBGRAPixel) 128 else 129 deltaDown := -map.Width*sizeof(TBGRAPixel); 126 130 for y := miny to maxy do 127 131 begin … … 138 142 {$endif} 139 143 {$endif} 144 IsLineUp := y > 0; 145 IsLineDown := y < map.Height-1; 146 mcTop := BGRAPixelTransparent; 147 mcBottom := BGRAPixelTransparent; 140 148 for x := minx to maxx do 141 149 begin 142 150 mcLeft := mc; 143 151 mc := mcRight; 144 inc(pmap);145 152 if x < map.width-1 then 146 mcRight := pmap^ else153 mcRight := (pmap+1)^ else 147 154 mcRight := BGRAPixelTransparent; 148 155 if mc.alpha = 0 then … … 156 163 {$endif} 157 164 inc(pdest); 165 inc(pmap); 158 166 continue; 159 167 end; 160 168 161 169 //compute surface vectors 162 mcTop := map.GetPixel(x,y-1); 163 mcBottom := map.GetPixel(x,y+1); 170 if IsLineUp then mcTop := pbgrapixel(pbyte(pmap)-deltaDown)^; 171 if IsLineDown then mcBottom := pbgrapixel(pbyte(pmap)+deltaDown)^; 172 inc(pmap); 173 164 174 z := MapHeight(mc)*mapAltitude; 165 175 if mcLeft.alpha = 0 then … … 196 206 begin 197 207 {$DEFINE PARAM_USESSE3} 208 asm 209 movups xmm1, vLS 210 end; 198 211 {$i phongdrawsse.inc} 199 212 {$UNDEF PARAM_USESSE3} 200 213 end else 201 214 begin 215 asm 216 movups xmm1, vLS 217 end; 202 218 {$i phongdrawsse.inc} 203 219 end; … … 221 237 222 238 NH := DotProduct3D_128(vH,vN); 223 if NH <= 0 then224 NnH := 0225 else226 NnH := exp(SpecularIndex*ln(NH));227 239 {$endif} 228 240 … … 230 242 NnH := 0 231 243 else 232 NnH := exp(SpecularIndex*ln(NH)); 244 NnH := exp(SpecularIndex*ln(NH)); //to be optimized 233 245 234 246 distfactor := LightSourceIntensity / (dist*LightSourceDistanceFactor + LightSourceDistanceTerm); -
GraphicTest/Packages/bgrabitmap/phongdrawsse.inc
r452 r472 2 2 //vL := vLS- vP*LightDestFactor; 3 3 movups xmm4, vP 4 mov ss xmm6,LightDestFactor45 mulps xmm6, xmm4 4 movups xmm6,LightDestFactor4 5 mulps xmm6, xmm4 //keep xmm4 = vP 6 6 movaps xmm0, xmm1 7 7 subps xmm0, xmm6 -
GraphicTest/Packages/bgrabitmap/phonglight.inc
r452 r472 1 {$i bgrasse.inc} 1 2 var 2 dist2,LdotN,NdotH,lightEnergy,diffuse : single;3 {%H-}dist2,LdotN,NdotH,lightEnergy,diffuse : single; 3 4 const 4 5 minus_05 = -0.5; 5 6 begin 6 {$IFDEF CPUI386}If UseSSE then7 {$IFDEF BGRASSE_AVAILABLE}If UseSSE then 7 8 begin 8 9 with Context^ do -
GraphicTest/Packages/bgrabitmap/phonglightsse.inc
r452 r472 1 1 {$asmmode intel} 2 2 asm 3 {$ifdef cpux86_64} 4 mov rax, Context 5 movaps xmm0,[rax+160] //Context^.vL 6 movaps xmm2,[rax+192] //Context^.vH 7 movaps xmm1,[rax+16] //Context^.Normal 8 {$else} 3 9 mov eax, Context 4 10 movaps xmm0,[eax+160] //Context^.vL 5 11 movaps xmm2,[eax+192] //Context^.vH 6 12 movaps xmm1,[eax+16] //Context^.Normal 13 {$endif} 7 14 8 15 {$IFDEF PARAM_POINTLIGHT} 16 {$ifdef cpux86_64} 17 movaps xmm6,[rax+0] //Context^.Position 18 {$else} 9 19 movaps xmm6,[eax+0] //Context^.Position 20 {$endif} 10 21 subps xmm0,xmm6 //xmm0 = vL 11 22 movaps xmm6, xmm0 -
GraphicTest/Packages/bgrabitmap/polyaliaspersp.inc
r452 r472 3 3 4 4 { TPolygonPerspectiveTextureMappingInfo } 5 6 procedure TPolygonPerspectiveTextureMappingInfo.SetIntersectionValues( 7 AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; 8 dy: single; AData: pointer); 9 var info: PPerspectiveTextureInfo; 10 begin 11 AInter.SetValues(AInterX,AWinding,ANumSegment); 12 info := PPerspectiveTextureInfo(AData); 13 TPerspectiveTextureMappingIntersectionInfo(AInter).coordInvZ := dy*info^.InvZSlope + info^.InvZ; 14 TPerspectiveTextureMappingIntersectionInfo(AInter).texCoordDivByZ := info^.TexCoordDivByZ + info^.TexCoordDivByZSlopes*dy; 15 if FLightnesses<>nil then 16 TPerspectiveTextureMappingIntersectionInfo(AInter).lightness := round(info^.lightness + info^.lightnessSlope*dy) 17 else 18 TPerspectiveTextureMappingIntersectionInfo(AInter).lightness := 32768; 19 end; 5 20 6 21 constructor TPolygonPerspectiveTextureMappingInfo.Create( … … 108 123 begin 109 124 Result:= TPerspectiveTextureMappingIntersectionInfo.Create; 110 end;111 112 procedure TPolygonPerspectiveTextureMappingInfo.ComputeIntersection(cury: single;113 var inter: ArrayOfTIntersectionInfo; var nbInter: integer);114 var115 j: integer;116 dy: single;117 info: PPerspectiveTextureInfo;118 begin119 if length(FSlices)=0 then exit;120 121 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice);122 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice);123 with FSlices[FCurSlice] do124 if (cury >= y1) and (cury <= y2) then125 begin126 for j := 0 to nbSegments-1 do127 begin128 dy := cury - segments[j].y1;129 inter[nbinter].interX := dy * segments[j].slope + segments[j].x1;130 inter[nbinter].winding := segments[j].winding;131 info := PPerspectiveTextureInfo(segments[j].data);132 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).coordInvZ := dy*info^.InvZSlope + info^.InvZ;133 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).texCoordDivByZ := info^.TexCoordDivByZ + info^.TexCoordDivByZSlopes*dy;134 if FLightnesses<>nil then135 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).lightness := round(info^.lightness + info^.lightnessSlope*dy)136 else137 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).lightness := 32768;138 Inc(nbinter);139 end;140 end;141 125 end; 142 126 … … 495 479 { TPolygonPerspectiveMappingShaderInfo } 496 480 481 procedure TPolygonPerspectiveMappingShaderInfo.SetIntersectionValues( 482 AInter: TIntersectionInfo; AInterX: Single; AWinding, ANumSegment: integer; 483 dy: single; AData: pointer); 484 var info : PPerspectiveTextureInfo; 485 begin 486 AInter.SetValues(AInterX,AWinding,ANumSegment); 487 info := PPerspectiveTextureInfo(AData); 488 TPerspectiveTextureMappingIntersectionInfo(AInter).coordInvZ := dy*info^.InvZSlope + info^.InvZ; 489 TPerspectiveTextureMappingIntersectionInfo(AInter).texCoordDivByZ := info^.TexCoordDivByZ + info^.TexCoordDivByZSlopes*dy; 490 TPerspectiveTextureMappingIntersectionInfo(AInter).Position3D := info^.Position3D + info^.Position3DSlope*dy; 491 TPerspectiveTextureMappingIntersectionInfo(AInter).Normal3D := info^.Normal3D + info^.Normal3DSlope*dy; 492 end; 493 497 494 constructor TPolygonPerspectiveMappingShaderInfo.Create( 498 495 const points: array of TPointF; const points3D: array of TPoint3D; … … 608 605 end; 609 606 610 procedure TPolygonPerspectiveMappingShaderInfo.ComputeIntersection(611 cury: single; var inter: ArrayOfTIntersectionInfo; var nbInter: integer);612 var613 j: integer;614 dy: single;615 info: PPerspectiveTextureInfo;616 begin617 if length(FSlices)=0 then exit;618 619 while (cury < FSlices[FCurSlice].y1) and (FCurSlice > 0) do dec(FCurSlice);620 while (cury > FSlices[FCurSlice].y2) and (FCurSlice < high(FSlices)) do inc(FCurSlice);621 with FSlices[FCurSlice] do622 if (cury >= y1) and (cury <= y2) then623 begin624 for j := 0 to nbSegments-1 do625 begin626 dy := cury - segments[j].y1;627 inter[nbinter].interX := dy * segments[j].slope + segments[j].x1;628 inter[nbinter].winding := segments[j].winding;629 info := PPerspectiveTextureInfo(segments[j].data);630 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).coordInvZ := dy*info^.InvZSlope + info^.InvZ;631 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).texCoordDivByZ := info^.TexCoordDivByZ + info^.TexCoordDivByZSlopes*dy;632 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).Position3D := info^.Position3D + info^.Position3DSlope*dy;633 TPerspectiveTextureMappingIntersectionInfo(inter[nbinter]).Normal3D := info^.Normal3D + info^.Normal3DSlope*dy;634 Inc(nbinter);635 end;636 end;637 end;638 -
GraphicTest/Packages/bgrabitmap/readme.txt
r452 r472 1 BGRABitmap v6.2- Drawing routines with alpha blending and antialiasing with Lazarus.1 BGRABitmap - Drawing routines with alpha blending and antialiasing with Lazarus. 2 2 3 3 These routines allow to manipulate 32bit images in BGRA format. -
GraphicTest/Packages/bgrabitmap/renderdensity256.inc
r452 r472 17 17 for xb := densMinX to densMaxX do 18 18 begin 19 j:= pdens^;19 tempDensity := pdens^; 20 20 Inc(pdens); 21 21 c := pscan^; 22 22 inc(pscan); 23 if j <> 0 then 24 DrawPixelInlineWithAlphaCheck(pdest, BGRA(c.red, c.green, c.blue, 23 if tempDensity <> 0 then 24 {$ifdef PARAM_LINEARANTIALIASING} 25 FastBlendPixelInline 26 {$else} 27 DrawPixelInlineWithAlphaCheck{$endif}(pdest, BGRA(c.red, c.green, c.blue, 25 28 {$ifdef PARAM_ANTIALIASINGFACTOR}DivByAntialiasPrecision256{$endif} 26 (c.alpha * j29 (c.alpha * tempDensity 27 30 {$ifdef PARAM_ANTIALIASINGFACTOR} ) {$else} +128) shr 8 {$endif} 28 31 )); … … 33 36 for xb := densMinX to densMaxX do 34 37 begin 35 j:= pdens^;38 tempDensity := pdens^; 36 39 Inc(pdens); 37 40 c := ScanNextPixelProc(); 38 if j <> 0 then 39 DrawPixelInlineWithAlphaCheck(pdest, BGRA(c.red, c.green, c.blue, 41 if tempDensity <> 0 then 42 {$ifdef PARAM_LINEARANTIALIASING} 43 FastBlendPixelInline 44 {$else} 45 DrawPixelInlineWithAlphaCheck{$endif}(pdest, BGRA(c.red, c.green, c.blue, 40 46 {$ifdef PARAM_ANTIALIASINGFACTOR}DivByAntialiasPrecision256{$endif} 41 (c.alpha * j47 (c.alpha * tempDensity 42 48 {$ifdef PARAM_ANTIALIASINGFACTOR} ) {$else} +128) shr 8 {$endif} 43 49 )); … … 51 57 for xb := densMinX to densMaxX do 52 58 begin 53 j:= pdens^;59 tempDensity := pdens^; 54 60 Inc(pdens); 55 if j<> 0 then61 if tempDensity <> 0 then 56 62 ErasePixelInline(pdest, 57 63 {$ifdef PARAM_ANTIALIASINGFACTOR}DivByAntialiasPrecision256{$endif} 58 (c.alpha * j64 (c.alpha * tempDensity 59 65 {$ifdef PARAM_ANTIALIASINGFACTOR} ) {$else} +128) shr 8 {$endif} 60 66 ); … … 66 72 for xb := densMinX to densMaxX do 67 73 begin 68 j:= pdens^;74 tempDensity := pdens^; 69 75 Inc(pdens); 70 if j<> 0 then76 if tempDensity <> 0 then 71 77 begin 72 78 c2.alpha := 73 79 {$ifdef PARAM_ANTIALIASINGFACTOR}DivByAntialiasPrecision256{$endif} 74 (c.alpha * j80 (c.alpha * tempDensity 75 81 {$ifdef PARAM_ANTIALIASINGFACTOR} ) {$else} +128) shr 8 {$endif} 76 82 ; 83 {$ifdef PARAM_LINEARANTIALIASING} 84 FastBlendPixelInline(pdest, c2); 85 {$else} 77 86 DrawPixelInlineExpandedOrNotWithAlphaCheck(pdest, ec, c2); 87 {$endif} 78 88 end; 79 89 Inc(pdest); … … 83 93 end 84 94 {$undef PARAM_ANTIALIASINGFACTOR} 95 {$undef PARAM_LINEARANTIALIASING} -
GraphicTest/UDrawForm.lfm
r444 r472 4 4 Top = 208 5 5 Width = 327 6 BorderStyle = bsDialog7 6 Caption = 'Draw frame' 8 7 FormStyle = fsStayOnTop 9 8 OnCreate = FormCreate 10 LCLVersion = '1. 1'9 LCLVersion = '1.5' 11 10 end -
GraphicTest/UDrawForm.pas
r445 r472 16 16 procedure FormCreate(Sender: TObject); 17 17 private 18 { private declarations } 18 19 19 public 20 FrameSize: TPoint; 20 21 EraseBackgroundEnabled: Boolean; 21 22 procedure EraseBackground(DC: HDC); override; -
GraphicTest/UDrawMethod.pas
r471 r472 21 21 FControl: TControl; 22 22 FFPS: Real; 23 FParent: TWinControl; 23 24 public 24 25 Caption: string; … … 39 40 procedure DrawFrame(FastBitmap: TFastBitmap); virtual; 40 41 procedure DrawFrameTiming(FastBitmap: TFastBitmap); 42 procedure UpdateSettings; virtual; 41 43 property Control: TControl read FControl; 42 44 end; … … 48 50 TDrawMethodImage = class(TDrawMethod) 49 51 Image: TImage; 52 procedure UpdateSettings; override; 50 53 procedure Init(Parent: TWinControl; Size: TPoint; PixelFormat: TPixelFormat); override; 51 54 procedure Done; override; … … 57 60 PaintBox: TPaintBox; 58 61 procedure Paint(Sender: TObject); virtual; 62 procedure UpdateSettings; override; 59 63 procedure Init(Parent: TWinControl; Size: TPoint; PixelFormat: TPixelFormat); override; 60 64 procedure Done; override; … … 69 73 TextureId: GLuint; 70 74 OpenGLBitmap: Pointer; 75 procedure UpdateSettings; override; 71 76 procedure InitGL; 72 77 procedure OpenGLControlResize(Sender: TObject); … … 86 91 begin 87 92 93 end; 94 95 procedure TDrawMethodPaintBox.UpdateSettings; 96 begin 97 inherited UpdateSettings; 98 PaintBox.ControlStyle := FParent.ControlStyle; 88 99 end; 89 100 … … 96 107 PaintBox.OnPaint := Paint; 97 108 PaintBox.Show; 109 UpdateSettings; 98 110 end; 99 111 … … 105 117 106 118 { TDrawMethodImage } 119 120 procedure TDrawMethodImage.UpdateSettings; 121 begin 122 inherited; 123 Image.ControlStyle := FParent.ControlStyle; 124 end; 107 125 108 126 procedure TDrawMethodImage.Init(Parent: TWinControl; Size: TPoint; PixelFormat: TPixelFormat); … … 115 133 Image.Picture.Bitmap.SetSize(Size.X, Size.Y); 116 134 Image.Show; 135 UpdateSettings; 117 136 end; 118 137 … … 141 160 end; 142 161 GetMem(OpenGLBitmap, OpenGLControl.Width * OpenGLControl.Height * SizeOf(Integer)); 162 UpdateSettings; 143 163 end; 144 164 … … 153 173 begin 154 174 glViewport(0, 0, OpenGLControl.Width, OpenGLControl.Height); 175 end; 176 177 procedure TDrawMethodOpenGL.UpdateSettings; 178 begin 179 inherited UpdateSettings; 180 OpenGLControl.ControlStyle := FParent.ControlStyle; 155 181 end; 156 182 … … 195 221 procedure TDrawMethod.Init(Parent: TWinControl; Size: TPoint; PixelFormat: TPixelFormat); 196 222 begin 223 FParent := Parent; 197 224 end; 198 225 … … 227 254 end; 228 255 256 procedure TDrawMethod.UpdateSettings; 257 begin 258 end; 259 229 260 end. 230 261 -
GraphicTest/UMainForm.lfm
r470 r472 699 699 TabOrder = 8 700 700 end 701 object CheckBox 1: TCheckBox701 object CheckBoxOpaque: TCheckBox 702 702 Left = 400 703 703 Height = 27 … … 706 706 Anchors = [akLeft, akBottom] 707 707 Caption = 'Opaque' 708 OnChange = CheckBox 1Change708 OnChange = CheckBoxOpaqueChange 709 709 TabOrder = 9 710 710 end … … 718 718 ParentColor = False 719 719 end 720 object ComboBox 1: TComboBox720 object ComboBoxPixelFormat: TComboBox 721 721 Left = 136 722 722 Height = 37 … … 725 725 Anchors = [akLeft, akBottom] 726 726 ItemHeight = 0 727 OnChange = ComboBox 1Change727 OnChange = ComboBoxPixelFormatChange 728 728 Style = csDropDownList 729 729 TabOrder = 10 … … 836 836 end 837 837 end 838 object TimerUpdateSettings: TTimer 839 OnTimer = TimerUpdateSettingsTimer 840 left = 272 841 top = 264 842 end 838 843 end -
GraphicTest/UMainForm.pas
r471 r472 28 28 ButtonSingleTest: TButton; 29 29 ButtonStop: TButton; 30 CheckBox 1: TCheckBox;30 CheckBoxOpaque: TCheckBox; 31 31 CheckBoxDoubleBuffered: TCheckBox; 32 32 CheckBoxEraseBackground: TCheckBox; 33 ComboBox 1: TComboBox;33 ComboBoxPixelFormat: TComboBox; 34 34 FileExit1: TFileExit; 35 35 FloatSpinEdit1: TFloatSpinEdit; … … 65 65 TabSheet1: TTabSheet; 66 66 TabSheet2: TTabSheet; 67 TimerUpdateSettings: TTimer; 67 68 TimerUpdateList: TTimer; 68 69 procedure AExportAsWikiTextExecute(Sender: TObject); … … 71 72 procedure ATestOneMethodExecute(Sender: TObject); 72 73 procedure ATestStopExecute(Sender: TObject); 73 procedure CheckBox 1Change(Sender: TObject);74 procedure CheckBoxOpaqueChange(Sender: TObject); 74 75 procedure CheckBoxDoubleBufferedChange(Sender: TObject); 75 76 procedure CheckBoxEraseBackgroundChange(Sender: TObject); 76 procedure ComboBox 1Change(Sender: TObject);77 procedure ComboBoxPixelFormatChange(Sender: TObject); 77 78 procedure FormCreate(Sender: TObject); 78 79 procedure FormDestroy(Sender: TObject); … … 85 86 procedure SpinEditWidthChange(Sender: TObject); 86 87 procedure TimerUpdateListTimer(Sender: TObject); 88 procedure TimerUpdateSettingsTimer(Sender: TObject); 87 89 private 90 FCurrentMethod: TDrawMethod; 88 91 MethodIndex: Integer; 89 92 SingleTestActive: Boolean; … … 96 99 procedure UpdateMethodList; 97 100 procedure UpdateInterface; 98 procedure UpdateFrameSize;99 101 procedure RegisterDrawMethods; 100 102 procedure RegisterDrawMethod(MethodClass: TDrawMethodClass); … … 105 107 Scenes: TObjectList; // TObjectList<TFastBitmap> 106 108 SceneIndex: Integer; 109 property CurrentMethod: TDrawMethod read FCurrentMethod; 107 110 end; 108 111 … … 141 144 142 145 for PF := Low(TPixelFormat) to High(TPixelFormat) do 143 ComboBox 1.Items.Add(GetEnumName(TypeInfo(TPixelFormat), Integer(PF)));146 ComboBoxPixelFormat.Items.Add(GetEnumName(TypeInfo(TPixelFormat), Integer(PF))); 144 147 145 148 PageControl1.TabIndex := 0; … … 151 154 StartTime: TDateTime; 152 155 begin 156 FCurrentMethod := Method; 153 157 with Method do begin 154 158 Init(DrawForm, FrameSize, PixelFormat); … … 171 175 Done; 172 176 end; 177 FCurrentMethod := nil; 173 178 end; 174 179 … … 255 260 end; 256 261 257 procedure TMainForm.CheckBox 1Change(Sender: TObject);258 begin 259 if CheckBox 1.Checked then262 procedure TMainForm.CheckBoxOpaqueChange(Sender: TObject); 263 begin 264 if CheckBoxOpaque.Checked then 260 265 DrawForm.ControlStyle := DrawForm.ControlStyle + [csOpaque] 261 266 else DrawForm.ControlStyle := DrawForm.ControlStyle - [csOpaque]; 267 if Assigned(FCurrentMethod) then 268 FCurrentMethod.UpdateSettings; 262 269 end; 263 270 … … 272 279 end; 273 280 274 procedure TMainForm.ComboBox 1Change(Sender: TObject);275 begin 276 PixelFormat := TPixelFormat(ComboBox 1.ItemIndex);281 procedure TMainForm.ComboBoxPixelFormatChange(Sender: TObject); 282 begin 283 PixelFormat := TPixelFormat(ComboBoxPixelFormat.ItemIndex); 277 284 UpdateInterface; 278 285 end; … … 292 299 procedure TMainForm.FormShow(Sender: TObject); 293 300 begin 294 UpdateFrameSize;295 301 UpdateMethodList; 296 302 UpdateInterface; 297 303 DrawForm.Show; 304 DrawForm.Left := Left + Width; 305 DrawForm.Top := Top; 298 306 end; 299 307 … … 339 347 begin 340 348 FrameSize.Y := SpinEditHeight.Value; 341 UpdateFrameSize;342 349 end; 343 350 … … 345 352 begin 346 353 FrameSize.X := SpinEditWidth.Value; 347 UpdateFrameSize;348 354 end; 349 355 … … 351 357 begin 352 358 UpdateMethodList; 359 end; 360 361 procedure TMainForm.TimerUpdateSettingsTimer(Sender: TObject); 362 begin 363 if (FrameSize.X <> DrawForm.FrameSize.X) or 364 (FrameSize.Y <> DrawForm.FrameSize.Y) then begin 365 DrawForm.FrameSize := FrameSize; 366 DrawForm.ClientWidth := FrameSize.X; 367 DrawForm.ClientHeight := FrameSize.Y; 368 GenerateSceneFrames; 369 end; 353 370 end; 354 371 … … 382 399 CheckBoxDoubleBuffered.Checked := DrawForm.DoubleBuffered; 383 400 CheckBoxEraseBackground.Checked := DrawForm.EraseBackgroundEnabled; 384 CheckBox1.Checked := csOpaque in DrawForm.ControlStyle; 385 ComboBox1.ItemIndex := Integer(PixelFormat); 386 end; 387 388 procedure TMainForm.UpdateFrameSize; 389 begin 390 DrawForm.ClientWidth := FrameSize.X; 391 DrawForm.ClientHeight := FrameSize.Y; 392 GenerateSceneFrames; 401 CheckBoxOpaque.Checked := csOpaque in DrawForm.ControlStyle; 402 ComboBoxPixelFormat.ItemIndex := Integer(PixelFormat); 393 403 end; 394 404
Note:
See TracChangeset
for help on using the changeset viewer.