GR32_MicroTiles.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  1. unit GR32_MicroTiles;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is MicroTiles Repaint Optimizer Extension for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Andre Beckedorf - metaException
  26. * [email protected]
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2005-2009
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$include GR32.inc}
  36. {-$DEFINE MICROTILES_DEBUGDRAW}
  37. {-$DEFINE MICROTILES_DEBUGDRAW_RANDOM_COLORS}
  38. {-$DEFINE MICROTILES_DEBUGDRAW_UNOPTIMIZED}
  39. {-$DEFINE MICROTILES_NO_ADAPTION}
  40. {-$DEFINE MICROTILES_NO_ADAPTION_FORCE_WHOLETILES}
  41. // CodeSite test stuff
  42. {-$DEFINE CODESITE}
  43. {-$DEFINE CODESITE_HIGH}
  44. uses
  45. {$IFDEF CODESITE}
  46. CSIntf, CSAux,
  47. {$ENDIF}
  48. {$if defined(UseInlining)}
  49. Types,
  50. {$ifend}
  51. SysUtils, Classes,
  52. GR32,
  53. GR32_System,
  54. GR32_Containers,
  55. GR32_Layers,
  56. GR32_RepaintOpt;
  57. const
  58. MICROTILE_SHIFT = 5;
  59. MICROTILE_SIZE = 1 shl MICROTILE_SHIFT;
  60. MICROTILE_EMPTY = 0;
  61. // MICROTILE_EMPTY -> Left: 0, Top: 0, Right: 0, Bottom: 0
  62. MICROTILE_FULL = MICROTILE_SIZE shl 8 or MICROTILE_SIZE;
  63. // MICROTILE_FULL -> Left: 0, Top: 0, Right: MICROTILE_SIZE, Bottom: MICROTILE_SIZE
  64. MicroTileSize = MaxInt div 16;
  65. {$IFDEF MICROTILES_DEBUGDRAW}
  66. clDebugDrawFill = TColor32($30FF0000);
  67. clDebugDrawFrame = TColor32($90FF0000);
  68. {$ENDIF}
  69. type
  70. PMicroTile = ^TMicroTile;
  71. TMicroTile = type Integer;
  72. PMicroTileArray = ^TMicroTileArray;
  73. TMicroTileArray = array[0..MicroTileSize - 1] of TMicroTile;
  74. PPMicroTiles = ^PMicroTiles;
  75. PMicroTiles = ^TMicroTiles;
  76. TMicroTiles = record
  77. BoundsRect: TRect;
  78. Columns, Rows: Integer;
  79. BoundsUsedTiles: TRect;
  80. Count: Integer;
  81. Tiles: PMicroTileArray;
  82. end;
  83. // MicroTile auxiliary routines
  84. function MakeMicroTile(const Left, Top, Right, Bottom: Integer): TMicroTile; {$IFDEF USEINLINING} inline; {$ENDIF}
  85. function MicroTileHeight(const Tile: TMicroTile): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
  86. function MicroTileWidth(const Tile: TMicroTile): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
  87. var
  88. MicroTileUnion: procedure(var DstTile: TMicroTile; const SrcTile: TMicroTile);
  89. // MicroTiles auxiliary routines
  90. function MakeEmptyMicroTiles: TMicroTiles; {$IFDEF USEINLINING} inline; {$ENDIF}
  91. procedure MicroTilesCreate(var MicroTiles: TMicroTiles); {$IFDEF USEINLINING} inline; {$ENDIF}
  92. procedure MicroTilesDestroy(var MicroTiles: TMicroTiles); {$IFDEF USEINLINING} inline; {$ENDIF}
  93. procedure MicroTilesSetSize(var MicroTiles: TMicroTiles; const DstRect: TRect);
  94. procedure MicroTilesClear(var MicroTiles: TMicroTiles; const Value: TMicroTile = MICROTILE_EMPTY); {$IFDEF USEINLINING} inline; {$ENDIF}
  95. procedure MicroTilesClearUsed(var MicroTiles: TMicroTiles; const Value: TMicroTile = MICROTILE_EMPTY);
  96. procedure MicroTilesCopy(var DstTiles: TMicroTiles; SrcTiles: TMicroTiles);
  97. procedure MicroTilesAddLine(var MicroTiles: TMicroTiles; X1, Y1, X2, Y2: Integer; LineWidth: Integer; RoundToWholeTiles: Boolean = False);
  98. procedure MicroTilesAddRect(var MicroTiles: TMicroTiles; Rect: TRect; RoundToWholeTiles: Boolean = False);
  99. procedure MicroTilesUnion(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles; RoundToWholeTiles: Boolean = False);
  100. function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList; CountOnly: Boolean = False; RoundToWholeTiles: Boolean = False): Integer; overload;
  101. function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList; const Clip: TRect; CountOnly: Boolean = False; RoundToWholeTiles: Boolean = False): Integer; overload;
  102. function MicroTilesCountEmptyTiles(const MicroTiles: TMicroTiles): Integer;
  103. type
  104. { TMicroTilesMap }
  105. { associative array that is used to map Layers to their MicroTiles }
  106. TMicroTilesMap = class(TPointerMap)
  107. private
  108. function GetData(Item: Pointer): PMicroTiles;
  109. procedure SetData(Item: Pointer; const Data: PMicroTiles);
  110. protected
  111. function Delete(BucketIndex: Integer; ItemIndex: Integer): Pointer; override;
  112. public
  113. function Add(Item: Pointer): PPMicroTiles;
  114. property Data[Item: Pointer]: PMicroTiles read GetData write SetData; default;
  115. end;
  116. type
  117. { TMicroTilesRepaintOptimizer }
  118. { Repaint manager that optimizes the repaint process using MicroTiles }
  119. TMicroTilesRepaintOptimizer = class(TCustomRepaintOptimizer,
  120. ILayerUpdateNotification,
  121. IUpdateRectNotification,
  122. ILayerListNotification
  123. )
  124. private
  125. // working tiles
  126. FBufferBounds: TRect;
  127. FWorkMicroTiles: PMicroTiles; // used by DrawLayerToMicroTiles
  128. FTempTiles: TMicroTiles;
  129. FInvalidTiles: TMicroTiles;
  130. FForcedInvalidTiles: TMicroTiles;
  131. // list of invalid layers
  132. FInvalidLayers: TList;
  133. // association that maps layers to their old invalid tiles
  134. FOldInvalidTilesMap: TMicroTilesMap;
  135. FWorkingTilesValid: Boolean;
  136. FOldInvalidTilesValid: Boolean;
  137. FUseInvalidTiles: Boolean;
  138. // adaptive stuff...
  139. FAdaptiveMode: Boolean;
  140. FPerfTimer: TStopWatch;
  141. FPerformanceLevel: Integer;
  142. FElapsedTimeForLastRepaint: Int64;
  143. FElapsedTimeForFullSceneRepaint: Int64;
  144. FAdaptionFailed: Boolean;
  145. // vars for time based approach
  146. FTimedCheck: Boolean;
  147. FTimeDelta: Integer;
  148. FNextCheck: Integer;
  149. FElapsedTimeOnLastPenalty: Int64;
  150. // vars for invalid rect difference approach
  151. FOldInvalidRectsCount: Integer;
  152. {$IFDEF MICROTILES_DEBUGDRAW}
  153. FDebugWholeTiles: Boolean;
  154. FDebugMicroTiles: TMicroTiles;
  155. FDebugInvalidRects: TRectList;
  156. {$ENDIF}
  157. procedure DrawLayerToMicroTiles(var DstTiles: TMicroTiles; Layer: TCustomLayer);
  158. procedure DrawMeasuringHandler(Sender: TObject; const Area: TRect; const Info: Cardinal);
  159. procedure ValidateWorkingTiles;
  160. procedure UpdateOldInvalidTiles;
  161. procedure SetAdaptiveMode(const Value: Boolean);
  162. procedure ResetAdaptiveMode;
  163. procedure BeginAdaption;
  164. procedure EndAdaption;
  165. procedure AddArea(var Tiles: TMicroTiles; const Area: TRect; const Info: Cardinal);
  166. protected
  167. procedure SetEnabled(const Value: Boolean); override;
  168. // ILayerUpdateNotification
  169. procedure LayerUpdated(ALayer: TCustomLayer);
  170. // IUpdateRectNotification
  171. procedure AreaUpdated(const AArea: TRect; const AInfo: Cardinal);
  172. // ILayerListNotification
  173. procedure LayerListNotify(ALayer: TCustomLayer; AAction: TLayerListNotification; AIndex: Integer);
  174. public
  175. constructor Create(Buffer: TBitmap32; InvalidRects: TRectList); override;
  176. destructor Destroy; override;
  177. procedure Reset; override;
  178. function UpdatesAvailable: Boolean; override;
  179. procedure PerformOptimization; override;
  180. procedure BeginPaintBuffer; override;
  181. procedure EndPaintBuffer; override;
  182. // handlers
  183. procedure BufferResizedHandler(const NewWidth, NewHeight: Integer); override;
  184. // custom settings:
  185. property AdaptiveMode: Boolean read FAdaptiveMode write SetAdaptiveMode;
  186. end;
  187. {$IFDEF CODESITE}
  188. TDebugMicroTilesRepaintOptimizer = class(TMicroTilesRepaintOptimizer)
  189. protected
  190. // ILayerNotification
  191. procedure LayerUpdated(ALayer: TCustomLayer); override;
  192. procedure LayerAreaUpdated(ALayer: TCustomLayer; const AArea: TRect; const AInfo: Cardinal); override;
  193. procedure LayerListNotify(ALayer: TCustomLayer; AAction: TLayerListNotification; AIndex: Integer); override;
  194. public
  195. procedure Reset; override;
  196. function UpdatesAvailable: Boolean; override;
  197. procedure PerformOptimization; override;
  198. procedure BeginPaintBuffer; override;
  199. procedure EndPaintBuffer; override;
  200. procedure BufferResizedHandler(const NewWidth, NewHeight: Integer); override;
  201. end;
  202. {$ENDIF}
  203. implementation
  204. uses
  205. GR32_Bindings, GR32_LowLevel, GR32_Math, Math;
  206. var
  207. MicroTilesU: procedure(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles);
  208. { MicroTile auxiliary routines }
  209. function MakeMicroTile(const Left, Top, Right, Bottom: Integer): TMicroTile;
  210. begin
  211. Result := Left shl 24 or Top shl 16 or Right shl 8 or Bottom;
  212. end;
  213. function MicroTileHeight(const Tile: TMicroTile): Integer;
  214. begin
  215. Result := (Tile and $FF) - (Tile shr 16 and $FF);
  216. end;
  217. function MicroTileWidth(const Tile: TMicroTile): Integer;
  218. begin
  219. Result := (Tile shr 8 and $FF) - (Tile shr 24);
  220. end;
  221. procedure MicroTileUnion_Pas(var DstTile: TMicroTile; const SrcTile: TMicroTile);
  222. var
  223. SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
  224. begin
  225. SrcLeft := SrcTile shr 24;
  226. SrcTop := (SrcTile and $FF0000) shr 16;
  227. SrcRight := (SrcTile and $FF00) shr 8;
  228. SrcBottom := SrcTile and $FF;
  229. if (DstTile <> MICROTILE_FULL) and (SrcTile <> MICROTILE_EMPTY) and
  230. (SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
  231. begin
  232. if (DstTile = MICROTILE_EMPTY) or (SrcTile = MICROTILE_FULL) then
  233. DstTile := SrcTile
  234. else
  235. begin
  236. DstTile := Min(DstTile shr 24, SrcLeft) shl 24 or
  237. Min(DstTile shr 16 and $FF, SrcTop) shl 16 or
  238. Max(DstTile shr 8 and $FF, SrcRight) shl 8 or
  239. Max(DstTile and $FF, SrcBottom);
  240. end;
  241. end;
  242. end;
  243. // TODO : rewrite MMX implementations using SSE
  244. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_MMX)) and defined(TARGET_x86)}
  245. procedure MicroTileUnion_EMMX(var DstTile: TMicroTile; const SrcTile: TMicroTile);
  246. var
  247. SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
  248. begin
  249. SrcLeft := SrcTile shr 24;
  250. SrcTop := (SrcTile and $FF0000) shr 16;
  251. SrcRight := (SrcTile and $FF00) shr 8;
  252. SrcBottom := SrcTile and $FF;
  253. if (DstTile <> MICROTILE_FULL) and (SrcTile <> MICROTILE_EMPTY) and
  254. (SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
  255. begin
  256. if (DstTile = MICROTILE_EMPTY) or (SrcTile = MICROTILE_FULL) then
  257. DstTile := SrcTile
  258. else
  259. asm
  260. MOVD MM1,[SrcTile]
  261. MOV EAX,[DstTile]
  262. MOVD MM2, [EAX]
  263. MOVQ MM3, MM1
  264. MOV ECX,$FFFF0000 // Mask
  265. MOVD MM0, ECX
  266. PMINUB MM1, MM2
  267. PAND MM1, MM0
  268. PSRLD MM0, 16 // shift mask right by 16 bits
  269. PMAXUB MM2, MM3
  270. PAND MM2, MM0
  271. POR MM1, MM2
  272. MOVD [EAX], MM1
  273. EMMS
  274. end;
  275. end;
  276. end;
  277. {$ifend}
  278. { MicroTiles auxiliary routines }
  279. function MakeEmptyMicroTiles: TMicroTiles;
  280. begin
  281. FillChar(Result, SizeOf(TMicroTiles), 0);
  282. ReallocMem(Result.Tiles, 0);
  283. end;
  284. procedure MicroTilesCreate(var MicroTiles: TMicroTiles);
  285. begin
  286. FillChar(MicroTiles, SizeOf(TMicroTiles), 0);
  287. ReallocMem(MicroTiles.Tiles, 0);
  288. end;
  289. procedure MicroTilesDestroy(var MicroTiles: TMicroTiles);
  290. begin
  291. ReallocMem(MicroTiles.Tiles, 0);
  292. end;
  293. procedure MicroTilesClear(var MicroTiles: TMicroTiles; const Value: TMicroTile);
  294. begin
  295. MicroTiles.BoundsUsedTiles := MakeRect(MicroTiles.Columns, MicroTiles.Rows, 0, 0);
  296. FillLongword(MicroTiles.Tiles^[0], MicroTiles.Count, Value);
  297. end;
  298. procedure MicroTilesSetSize(var MicroTiles: TMicroTiles; const DstRect: TRect);
  299. begin
  300. MicroTiles.BoundsRect := DstRect;
  301. MicroTiles.Columns := ((DstRect.Right - DstRect.Left) shr MICROTILE_SHIFT) + 1;
  302. MicroTiles.Rows := ((DstRect.Bottom - DstRect.Top) shr MICROTILE_SHIFT) + 1;
  303. MicroTiles.Count := (MicroTiles.Columns + 1) * (MicroTiles.Rows + 1);
  304. ReallocMem(MicroTiles.Tiles, MicroTiles.Count * SizeOf(TMicroTile));
  305. MicroTilesClear(MicroTiles)
  306. end;
  307. procedure MicroTilesClearUsed(var MicroTiles: TMicroTiles; const Value: TMicroTile);
  308. var
  309. I: Integer;
  310. begin
  311. for I := MicroTiles.BoundsUsedTiles.Top to MicroTiles.BoundsUsedTiles.Bottom do
  312. FillLongword(MicroTiles.Tiles^[I * MicroTiles.Columns + MicroTiles.BoundsUsedTiles.Left],
  313. MicroTiles.BoundsUsedTiles.Right - MicroTiles.BoundsUsedTiles.Left + 1, Value);
  314. MicroTiles.BoundsUsedTiles := MakeRect(MicroTiles.Columns, MicroTiles.Rows, 0, 0);
  315. end;
  316. procedure MicroTilesCopy(var DstTiles: TMicroTiles; SrcTiles: TMicroTiles);
  317. var
  318. CurRow, Width: Integer;
  319. SrcTilePtr, DstTilePtr: PMicroTile;
  320. begin
  321. if Assigned(DstTiles.Tiles) and (DstTiles.Count > 0) then
  322. MicroTilesClearUsed(DstTiles);
  323. DstTiles.BoundsRect := SrcTiles.BoundsRect;
  324. DstTiles.Columns := SrcTiles.Columns;
  325. DstTiles.Rows := SrcTiles.Rows;
  326. DstTiles.BoundsUsedTiles := SrcTiles.BoundsUsedTiles;
  327. ReallocMem(DstTiles.Tiles, SrcTiles.Count * SizeOf(TMicroTile));
  328. if DstTiles.Count < SrcTiles.Count then
  329. FillLongword(DstTiles.Tiles^[DstTiles.Count], SrcTiles.Count - DstTiles.Count, MICROTILE_EMPTY);
  330. DstTiles.Count := SrcTiles.Count;
  331. SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  332. DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  333. Width := SrcTiles.BoundsUsedTiles.Right - SrcTiles.BoundsUsedTiles.Left + 1;
  334. for CurRow := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
  335. begin
  336. MoveLongword(SrcTilePtr^, DstTilePtr^, Width);
  337. Inc(DstTilePtr, DstTiles.Columns);
  338. Inc(SrcTilePtr, SrcTiles.Columns);
  339. end
  340. end;
  341. procedure MicroTilesAddLine(var MicroTiles: TMicroTiles; X1, Y1, X2, Y2: Integer; LineWidth: Integer; RoundToWholeTiles: Boolean = False);
  342. var
  343. i: Integer;
  344. DeltaX, DeltaY: Integer;
  345. SignX, SignY: Integer;
  346. Rects: Integer;
  347. NewX, NewY: Integer;
  348. TempRect: TRect;
  349. begin
  350. LineWidth := (LineWidth + 1) shr 1; // Half line width rounded up
  351. DeltaX := X2 - X1;
  352. if DeltaX < 0 then
  353. begin
  354. // Make sure DeltaX*Sign is positive
  355. Swap(X1, X2);
  356. Swap(Y1, Y2);
  357. DeltaX := -DeltaX;
  358. SignX := 1
  359. end else
  360. if DeltaX > 0 then
  361. SignX := 1
  362. else // DeltaX = 0
  363. begin
  364. TempRect := MakeRect(X1, Y1, X2, Y2);
  365. InflateArea(TempRect, LineWidth, LineWidth);
  366. MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
  367. Exit;
  368. end;
  369. DeltaY := Y2 - Y1;
  370. if DeltaY > 0 then
  371. SignY := 1
  372. else
  373. if DeltaY < 0 then
  374. begin
  375. DeltaY := -DeltaY;
  376. SignY := -1;
  377. end else // DeltaY = 0
  378. begin
  379. TempRect := MakeRect(X1, Y1, X2, Y2);
  380. InflateArea(TempRect, LineWidth, LineWidth);
  381. MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
  382. Exit;
  383. end;
  384. X1 := X1 * FixedOne;
  385. Y1 := Y1 * FixedOne;
  386. DeltaX := DeltaX * FixedOne;
  387. DeltaY := DeltaY * FixedOne;
  388. if DeltaX >= DeltaY then
  389. begin
  390. Rects := DeltaX div MICROTILE_SIZE;
  391. DeltaX := SignX * MICROTILE_SIZE * FixedOne;
  392. DeltaY := SignY * FixedDiv(DeltaY, Rects);
  393. end else
  394. begin
  395. Rects := DeltaY div MICROTILE_SIZE;
  396. DeltaY := SignY * MICROTILE_SIZE * FixedOne;
  397. DeltaX := SignX * FixedDiv(DeltaX, Rects);
  398. end;
  399. for i := 1 to FixedCeil(Rects) do
  400. begin
  401. NewX := X1 + DeltaX;
  402. NewY := Y1 + DeltaY;
  403. // Make sure rect is positive or MakeRect will not round correctly
  404. if (SignY >= 0) then
  405. TempRect := MakeRect(FixedRect(X1, Y1, NewX, NewY), rrOutside)
  406. else
  407. TempRect := MakeRect(FixedRect(X1, NewY, NewX, Y1), rrOutside);
  408. InflateArea(TempRect, LineWidth, LineWidth);
  409. MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
  410. X1 := NewX;
  411. Y1 := NewY;
  412. end;
  413. end;
  414. procedure MicroTilesAddRect(var MicroTiles: TMicroTiles; Rect: TRect; RoundToWholeTiles: Boolean);
  415. var
  416. ModLeft, ModRight, ModTop, ModBottom, Temp: Integer;
  417. LeftTile, TopTile, RightTile, BottomTile, ColSpread, RowSpread: Integer;
  418. CurRow, CurCol: Integer;
  419. TilePtr, TilePtr2: PMicroTile;
  420. begin
  421. if MicroTiles.Count = 0 then Exit;
  422. with Rect do
  423. begin
  424. TestSwap(Left, Right);
  425. TestSwap(Top, Bottom);
  426. if Left < 0 then Left := 0;
  427. if Top < 0 then Top := 0;
  428. Temp := MicroTiles.Columns shl MICROTILE_SHIFT;
  429. if Right > Temp then Right := Temp;
  430. Temp := MicroTiles.Rows shl MICROTILE_SHIFT;
  431. if Bottom > Temp then Bottom := Temp;
  432. if (Left > Right) or (Top > Bottom) then Exit;
  433. end;
  434. LeftTile := Rect.Left shr MICROTILE_SHIFT;
  435. TopTile := Rect.Top shr MICROTILE_SHIFT;
  436. RightTile := Rect.Right shr MICROTILE_SHIFT;
  437. BottomTile := Rect.Bottom shr MICROTILE_SHIFT;
  438. TilePtr := @MicroTiles.Tiles^[TopTile * MicroTiles.Columns + LeftTile];
  439. if RoundToWholeTiles then
  440. begin
  441. for CurRow := TopTile to BottomTile do
  442. begin
  443. FillLongword(TilePtr^, RightTile - LeftTile + 1, MICROTILE_FULL);
  444. Inc(TilePtr, MicroTiles.Columns);
  445. end;
  446. end
  447. else
  448. begin
  449. // calculate number of tiles needed in columns and rows
  450. ColSpread := ((Rect.Right + MICROTILE_SIZE) shr MICROTILE_SHIFT) -
  451. (Rect.Left shr MICROTILE_SHIFT);
  452. RowSpread := ((Rect.Bottom + MICROTILE_SIZE) shr MICROTILE_SHIFT) -
  453. (Rect.Top shr MICROTILE_SHIFT);
  454. ModLeft := Rect.Left mod MICROTILE_SIZE;
  455. ModTop := Rect.Top mod MICROTILE_SIZE;
  456. ModRight := Rect.Right mod MICROTILE_SIZE;
  457. ModBottom := Rect.Bottom mod MICROTILE_SIZE;
  458. if (ColSpread = 1) and (RowSpread = 1) then
  459. MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, ModRight, ModBottom))
  460. else if ColSpread = 1 then
  461. begin
  462. MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, ModRight, MICROTILE_SIZE));
  463. Inc(TilePtr, MicroTiles.Columns);
  464. if RowSpread > 2 then
  465. for CurCol := TopTile + 1 to BottomTile - 1 do
  466. begin
  467. MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, 0, ModRight, MICROTILE_SIZE));
  468. Inc(TilePtr, MicroTiles.Columns);
  469. end;
  470. MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, 0, ModRight, ModBottom));
  471. end
  472. else if RowSpread = 1 then
  473. begin
  474. MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, MICROTILE_SIZE, ModBottom));
  475. Inc(TilePtr);
  476. if ColSpread > 2 then
  477. for CurRow := LeftTile + 1 to RightTile - 1 do
  478. begin
  479. MicroTileUnion(TilePtr^, MakeMicroTile(0, ModTop, MICROTILE_SIZE, ModBottom));
  480. Inc(TilePtr);
  481. end;
  482. MicroTileUnion(TilePtr^, MakeMicroTile(0, ModTop, ModRight, ModBottom));
  483. end
  484. else
  485. begin
  486. TilePtr2 := TilePtr;
  487. // TOP:
  488. // render top-left corner
  489. MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, ModTop, MICROTILE_SIZE, MICROTILE_SIZE));
  490. Inc(TilePtr2);
  491. // render top edge
  492. if ColSpread > 2 then
  493. for CurRow := LeftTile + 1 to RightTile - 1 do
  494. begin
  495. MicroTileUnion(TilePtr2^, MakeMicroTile(0, ModTop, MICROTILE_SIZE, MICROTILE_SIZE));
  496. Inc(TilePtr2);
  497. end;
  498. // render top-right corner
  499. MicroTileUnion(TilePtr2^, MakeMicroTile(0, ModTop, ModRight, MICROTILE_SIZE));
  500. Inc(TilePtr, MicroTiles.Columns);
  501. // INTERMEDIATE AREA:
  502. if RowSpread > 2 then
  503. for CurCol := TopTile + 1 to BottomTile - 1 do
  504. begin
  505. TilePtr2 := TilePtr;
  506. // render left edge
  507. MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, 0, MICROTILE_SIZE, MICROTILE_SIZE));
  508. Inc(TilePtr2);
  509. // render content
  510. if ColSpread > 2 then
  511. begin
  512. FillLongword(TilePtr2^, RightTile - LeftTile - 1, MICROTILE_FULL);
  513. Inc(TilePtr2, RightTile - LeftTile - 1);
  514. end;
  515. // render right edge
  516. MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, ModRight, MICROTILE_SIZE));
  517. Inc(TilePtr, MicroTiles.Columns);
  518. end;
  519. TilePtr2 := TilePtr;
  520. // BOTTOM:
  521. // render bottom-left corner
  522. MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, 0, MICROTILE_SIZE, ModBottom));
  523. Inc(TilePtr2);
  524. // render bottom edge
  525. if ColSpread > 2 then
  526. for CurRow := LeftTile + 1 to RightTile - 1 do
  527. begin
  528. MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, MICROTILE_SIZE, ModBottom));
  529. Inc(TilePtr2);
  530. end;
  531. // render bottom-right corner
  532. MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, ModRight, ModBottom));
  533. end;
  534. end;
  535. with MicroTiles.BoundsUsedTiles do
  536. begin
  537. if LeftTile < Left then
  538. Left := LeftTile;
  539. if TopTile < Top then
  540. Top := TopTile;
  541. if RightTile > Right then
  542. Right := RightTile;
  543. if BottomTile > Bottom then
  544. Bottom := BottomTile;
  545. end;
  546. end;
  547. procedure MicroTilesUnion_Pas(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles);
  548. var
  549. SrcTilePtr, DstTilePtr: PMicroTile;
  550. SrcTilePtr2, DstTilePtr2: PMicroTile;
  551. X, Y: Integer;
  552. SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
  553. SrcTile: TMicroTile;
  554. begin
  555. SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  556. DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  557. for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
  558. begin
  559. SrcTilePtr2 := SrcTilePtr;
  560. DstTilePtr2 := DstTilePtr;
  561. for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
  562. begin
  563. SrcTile := SrcTilePtr2^;
  564. SrcLeft := SrcTile shr 24;
  565. SrcTop := (SrcTile and $FF0000) shr 16;
  566. SrcRight := (SrcTile and $FF00) shr 8;
  567. SrcBottom := SrcTile and $FF;
  568. if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
  569. (SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
  570. begin
  571. if (DstTilePtr2^ = MICROTILE_EMPTY) or (SrcTilePtr2^ = MICROTILE_FULL) then
  572. DstTilePtr2^ := SrcTilePtr2^
  573. else
  574. DstTilePtr2^ := Min(DstTilePtr2^ shr 24, SrcLeft) shl 24 or
  575. Min(DstTilePtr2^ shr 16 and $FF, SrcTop) shl 16 or
  576. Max(DstTilePtr2^ shr 8 and $FF, SrcRight) shl 8 or
  577. Max(DstTilePtr2^ and $FF, SrcBottom);
  578. end;
  579. Inc(DstTilePtr2);
  580. Inc(SrcTilePtr2);
  581. end;
  582. Inc(DstTilePtr, DstTiles.Columns);
  583. Inc(SrcTilePtr, SrcTiles.Columns);
  584. end;
  585. end;
  586. // TODO : rewrite MMX implementations using SSE
  587. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_MMX)) and defined(TARGET_x86)}
  588. procedure MicroTilesUnion_EMMX(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles);
  589. var
  590. SrcTilePtr, DstTilePtr: PMicroTile;
  591. SrcTilePtr2, DstTilePtr2: PMicroTile;
  592. X, Y: Integer;
  593. SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
  594. begin
  595. SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  596. DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  597. asm
  598. MOV ECX, $FFFF // Mask
  599. MOVD MM0, ECX
  600. MOVQ MM4, MM0
  601. PSLLD MM4, 16 // shift mask left by 16 bits
  602. end;
  603. for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
  604. begin
  605. SrcTilePtr2 := SrcTilePtr;
  606. DstTilePtr2 := DstTilePtr;
  607. for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
  608. begin
  609. SrcLeft := SrcTilePtr2^ shr 24;
  610. SrcTop := (SrcTilePtr2^ and $FF0000) shr 16;
  611. SrcRight := (SrcTilePtr2^ and $FF00) shr 8;
  612. SrcBottom := SrcTilePtr2^ and $FF;
  613. if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
  614. (SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
  615. begin
  616. if (DstTilePtr2^ = MICROTILE_EMPTY) or (SrcTilePtr2^ = MICROTILE_FULL) then
  617. DstTilePtr2^ := SrcTilePtr2^
  618. else
  619. asm
  620. MOV EAX, [DstTilePtr2]
  621. MOVD MM2, [EAX]
  622. MOV ECX, [SrcTilePtr2]
  623. MOVD MM1, [ECX]
  624. MOVQ MM3, MM1
  625. PMINUB MM1, MM2
  626. PAND MM1, MM4
  627. PMAXUB MM2, MM3
  628. PAND MM2, MM0
  629. POR MM1, MM2
  630. MOVD [EAX], MM1
  631. end;
  632. end;
  633. Inc(DstTilePtr2);
  634. Inc(SrcTilePtr2);
  635. end;
  636. Inc(DstTilePtr, DstTiles.Columns);
  637. Inc(SrcTilePtr, SrcTiles.Columns);
  638. end;
  639. asm
  640. db $0F,$77 /// EMMS
  641. end;
  642. end;
  643. {$ifend}
  644. procedure MicroTilesUnion(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles; RoundToWholeTiles: Boolean);
  645. var
  646. SrcTilePtr, DstTilePtr: PMicroTile;
  647. SrcTilePtr2, DstTilePtr2: PMicroTile;
  648. X, Y: Integer;
  649. SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
  650. begin
  651. if SrcTiles.Count = 0 then Exit;
  652. if RoundToWholeTiles then
  653. begin
  654. SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  655. DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
  656. for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
  657. begin
  658. SrcTilePtr2 := SrcTilePtr;
  659. DstTilePtr2 := DstTilePtr;
  660. for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
  661. begin
  662. SrcLeft := SrcTilePtr2^ shr 24;
  663. SrcTop := (SrcTilePtr2^ and $FF0000) shr 16;
  664. SrcRight := (SrcTilePtr2^ and $FF00) shr 8;
  665. SrcBottom := SrcTilePtr2^ and $FF;
  666. if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
  667. (SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
  668. DstTilePtr2^ := MICROTILE_FULL;
  669. Inc(DstTilePtr2);
  670. Inc(SrcTilePtr2);
  671. end;
  672. Inc(DstTilePtr, DstTiles.Columns);
  673. Inc(SrcTilePtr, SrcTiles.Columns);
  674. end
  675. end
  676. else
  677. MicroTilesU(DstTiles, SrcTiles);
  678. with DstTiles.BoundsUsedTiles do
  679. begin
  680. if SrcTiles.BoundsUsedTiles.Left < Left then Left := SrcTiles.BoundsUsedTiles.Left;
  681. if SrcTiles.BoundsUsedTiles.Top < Top then Top := SrcTiles.BoundsUsedTiles.Top;
  682. if SrcTiles.BoundsUsedTiles.Right > Right then Right := SrcTiles.BoundsUsedTiles.Right;
  683. if SrcTiles.BoundsUsedTiles.Bottom > Bottom then Bottom := SrcTiles.BoundsUsedTiles.Bottom;
  684. end;
  685. end;
  686. function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList;
  687. CountOnly, RoundToWholeTiles: Boolean): Integer;
  688. begin
  689. Result := MicroTilesCalcRects(MicroTiles, DstRects, MicroTiles.BoundsRect, CountOnly);
  690. end;
  691. function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList;
  692. const Clip: TRect; CountOnly, RoundToWholeTiles: Boolean): Integer;
  693. var
  694. Rects: Array Of TRect;
  695. Rect: PRect;
  696. CombLUT: Array Of Integer;
  697. StartIndex: Integer;
  698. CurTile, TempTile: TMicroTile;
  699. Temp: Integer;
  700. NewLeft, NewTop, NewRight, NewBottom: Integer;
  701. CurCol, CurRow, I, RectsCount: Integer;
  702. begin
  703. Result := 0;
  704. if (MicroTiles.Count = 0) or
  705. (MicroTiles.BoundsUsedTiles.Right < MicroTiles.BoundsUsedTiles.Left) or
  706. (MicroTiles.BoundsUsedTiles.Bottom < MicroTiles.BoundsUsedTiles.Top) then Exit;
  707. SetLength(Rects, MicroTiles.Columns * MicroTiles.Rows);
  708. SetLength(CombLUT, MicroTiles.Columns * MicroTiles.Rows);
  709. FillLongword(CombLUT[0], Length(CombLUT), Cardinal(-1));
  710. I := 0;
  711. RectsCount := 0;
  712. if not RoundToWholeTiles then
  713. for CurRow := 0 to MicroTiles.Rows - 1 do
  714. begin
  715. CurCol := 0;
  716. while CurCol < MicroTiles.Columns do
  717. begin
  718. CurTile := MicroTiles.Tiles[I];
  719. if CurTile <> MICROTILE_EMPTY then
  720. begin
  721. Temp := CurRow shl MICROTILE_SHIFT;
  722. NewTop := Constrain(Temp + CurTile shr 16 and $FF, Clip.Top, Clip.Bottom);
  723. NewBottom := Constrain(Temp + CurTile and $FF, Clip.Top, Clip.Bottom);
  724. NewLeft := Constrain(CurCol shl MICROTILE_SHIFT + CurTile shr 24, Clip.Left, Clip.Right);
  725. StartIndex := I;
  726. if (CurTile shr 8 and $FF = MICROTILE_SIZE) and (CurCol <> MicroTiles.Columns - 1) then
  727. begin
  728. while True do
  729. begin
  730. Inc(CurCol);
  731. Inc(I);
  732. TempTile := MicroTiles.Tiles[I];
  733. if (CurCol = MicroTiles.Columns) or
  734. (TempTile shr 16 and $FF <> CurTile shr 16 and $FF) or
  735. (TempTile and $FF <> CurTile and $FF) or
  736. (TempTile shr 24 <> 0) then
  737. begin
  738. Dec(CurCol);
  739. Dec(I);
  740. Break;
  741. end;
  742. end;
  743. end;
  744. NewRight := Constrain(CurCol shl MICROTILE_SHIFT + MicroTiles.Tiles[I] shr 8 and $FF, Clip.Left, Clip.Right);
  745. Temp := CombLUT[StartIndex];
  746. Rect := nil;
  747. if Temp <> -1 then Rect := @Rects[Temp];
  748. if Assigned(Rect) and
  749. (Rect.Left = NewLeft) and
  750. (Rect.Right = NewRight) and
  751. (Rect.Bottom = NewTop) then
  752. begin
  753. Rect.Bottom := NewBottom;
  754. if CurRow <> MicroTiles.Rows - 1 then
  755. CombLUT[StartIndex + MicroTiles.Columns] := Temp;
  756. end
  757. else
  758. with Rects[RectsCount] do
  759. begin
  760. Left := NewLeft; Top := NewTop;
  761. Right := NewRight; Bottom := NewBottom;
  762. if CurRow <> MicroTiles.Rows - 1 then
  763. CombLUT[StartIndex + MicroTiles.Columns] := RectsCount;
  764. Inc(RectsCount);
  765. end;
  766. end;
  767. Inc(I);
  768. Inc(CurCol);
  769. end;
  770. end
  771. else
  772. for CurRow := 0 to MicroTiles.Rows - 1 do
  773. begin
  774. CurCol := 0;
  775. while CurCol < MicroTiles.Columns do
  776. begin
  777. CurTile := MicroTiles.Tiles[I];
  778. if CurTile <> MICROTILE_EMPTY then
  779. begin
  780. Temp := CurRow shl MICROTILE_SHIFT;
  781. NewTop := Constrain(Temp, Clip.Top, Clip.Bottom);
  782. NewBottom := Constrain(Temp + MICROTILE_SIZE, Clip.Top, Clip.Bottom);
  783. NewLeft := Constrain(CurCol shl MICROTILE_SHIFT, Clip.Left, Clip.Right);
  784. StartIndex := I;
  785. if CurCol <> MicroTiles.Columns - 1 then
  786. begin
  787. while True do
  788. begin
  789. Inc(CurCol);
  790. Inc(I);
  791. TempTile := MicroTiles.Tiles[I];
  792. if (CurCol = MicroTiles.Columns) or (TempTile = MICROTILE_EMPTY) then
  793. begin
  794. Dec(CurCol);
  795. Dec(I);
  796. Break;
  797. end;
  798. end;
  799. end;
  800. NewRight := Constrain(CurCol shl MICROTILE_SHIFT + MICROTILE_SIZE, Clip.Left, Clip.Right);
  801. Temp := CombLUT[StartIndex];
  802. Rect := nil;
  803. if Temp <> -1 then Rect := @Rects[Temp];
  804. if Assigned(Rect) and
  805. (Rect.Left = NewLeft) and
  806. (Rect.Right = NewRight) and
  807. (Rect.Bottom = NewTop) then
  808. begin
  809. Rect.Bottom := NewBottom;
  810. if CurRow <> MicroTiles.Rows - 1 then
  811. CombLUT[StartIndex + MicroTiles.Columns] := Temp;
  812. end
  813. else
  814. with Rects[RectsCount] do
  815. begin
  816. Left := NewLeft; Top := NewTop;
  817. Right := NewRight; Bottom := NewBottom;
  818. if CurRow <> MicroTiles.Rows - 1 then
  819. CombLUT[StartIndex + MicroTiles.Columns] := RectsCount;
  820. Inc(RectsCount);
  821. end;
  822. end;
  823. Inc(I);
  824. Inc(CurCol);
  825. end;
  826. end;
  827. Result := RectsCount;
  828. if not CountOnly then
  829. for I := 0 to RectsCount - 1 do DstRects.Add(Rects[I]);
  830. end;
  831. function MicroTilesCountEmptyTiles(const MicroTiles: TMicroTiles): Integer;
  832. var
  833. CurRow, CurCol: Integer;
  834. TilePtr: PMicroTile;
  835. begin
  836. Result := 0;
  837. if MicroTiles.Count > 0 then
  838. begin
  839. TilePtr := @MicroTiles.Tiles^[0];
  840. for CurRow := 0 to MicroTiles.Rows - 1 do
  841. for CurCol := 0 to MicroTiles.Columns - 1 do
  842. begin
  843. if TilePtr^ = MICROTILE_EMPTY then Inc(Result);
  844. Inc(TilePtr);
  845. end;
  846. end;
  847. end;
  848. {$IFDEF MICROTILES_DEBUGDRAW}
  849. procedure MicroTilesDebugDraw(const MicroTiles: TMicroTiles; DstBitmap: TBitmap32; DrawOptimized, RoundToWholeTiles: Boolean);
  850. var
  851. I: Integer;
  852. TempRect: TRect;
  853. Rects: TRectList;
  854. C1, C2: TColor32;
  855. begin
  856. {$IFDEF MICROTILES_DEBUGDRAW_RANDOM_COLORS}
  857. C1 := Random(MaxInt) AND $00FFFFFF;
  858. C2 := C1 OR $90000000;
  859. C1 := C1 OR $30000000;
  860. {$ELSE}
  861. C1 := clDebugDrawFill;
  862. C2 := clDebugDrawFrame;
  863. {$ENDIF}
  864. if DrawOptimized then
  865. begin
  866. Rects := TRectList.Create;
  867. MicroTilesCalcRects(MicroTiles, Rects, False, RoundToWholeTiles);
  868. try
  869. if Rects.Count > 0 then
  870. begin
  871. for I := 0 to Rects.Count - 1 do
  872. begin
  873. DstBitmap.FillRectTS(Rects[I]^, C1);
  874. DstBitmap.FrameRectTS(Rects[I]^, C2);
  875. end;
  876. end
  877. finally
  878. Rects.Free;
  879. end;
  880. end
  881. else
  882. for I := 0 to MicroTiles.Count - 1 do
  883. begin
  884. if MicroTiles.Tiles^[i] <> MICROTILE_EMPTY then
  885. begin
  886. TempRect.Left := ((I mod MicroTiles.Columns) shl MICROTILE_SHIFT) + (MicroTiles.Tiles[i] shr 24);
  887. TempRect.Top := ((I div MicroTiles.Columns) shl MICROTILE_SHIFT) + (MicroTiles.Tiles[i] shr 16 and $FF);
  888. TempRect.Right := ((I mod MicroTiles.Columns) shl MICROTILE_SHIFT) + (MicroTiles.Tiles[i] shr 8 and $FF);
  889. TempRect.Bottom := ((I div MicroTiles.Columns) shl MICROTILE_SHIFT) + (MicroTiles.Tiles[i] and $FF);
  890. DstBitmap.FillRectTS(TempRect, C1);
  891. DstBitmap.FrameRectTS(TempRect, C2);
  892. end;
  893. end;
  894. end;
  895. {$ENDIF}
  896. { TMicroTilesMap }
  897. function TMicroTilesMap.Add(Item: Pointer): PPMicroTiles;
  898. var
  899. TilesPtr: PMicroTiles;
  900. IsNew: Boolean;
  901. begin
  902. Result := PPMicroTiles(inherited Add(Item, IsNew));
  903. if IsNew then
  904. begin
  905. New(TilesPtr);
  906. MicroTilesCreate(TilesPtr^);
  907. Result^ := TilesPtr;
  908. end;
  909. end;
  910. function TMicroTilesMap.Delete(BucketIndex, ItemIndex: Integer): Pointer;
  911. var
  912. TilesPtr: PMicroTiles;
  913. begin
  914. TilesPtr := inherited Delete(BucketIndex, ItemIndex);
  915. MicroTilesDestroy(TilesPtr^);
  916. Dispose(TilesPtr);
  917. Result := nil;
  918. end;
  919. procedure TMicroTilesMap.SetData(Item: Pointer; const Data: PMicroTiles);
  920. begin
  921. inherited SetData(Item, Data);
  922. end;
  923. function TMicroTilesMap.GetData(Item: Pointer): PMicroTiles;
  924. begin
  925. Result := inherited GetData(Item);
  926. end;
  927. { TMicroTilesRepaintManager }
  928. type
  929. TCustomLayerAccess = class(TCustomLayer);
  930. const
  931. PL_MICROTILES = 0;
  932. PL_WHOLETILES = 1;
  933. PL_FULLSCENE = 2;
  934. TIMER_PENALTY = 250;
  935. TIMER_LOWLIMIT = 1000;
  936. TIMER_HIGHLIMIT = 5000;
  937. INVALIDRECTS_DELTA = 10;
  938. constructor TMicroTilesRepaintOptimizer.Create(Buffer: TBitmap32; InvalidRects: TRectList);
  939. begin
  940. inherited;
  941. FOldInvalidTilesMap := TMicroTilesMap.Create;
  942. FInvalidLayers := TList.Create;
  943. {$IFNDEF MICROTILES_DEBUGDRAW}
  944. {$IFNDEF MICROTILES_NO_ADAPTION}
  945. FAdaptiveMode := True;
  946. {$ENDIF}
  947. {$ENDIF}
  948. MicroTilesCreate(FInvalidTiles);
  949. MicroTilesCreate(FTempTiles);
  950. MicroTilesCreate(FForcedInvalidTiles);
  951. {$IFDEF MICROTILES_DEBUGDRAW}
  952. MicroTilesCreate(FDebugMicroTiles);
  953. FDebugInvalidRects := TRectList.Create;
  954. {$ENDIF}
  955. end;
  956. destructor TMicroTilesRepaintOptimizer.Destroy;
  957. begin
  958. MicroTilesDestroy(FForcedInvalidTiles);
  959. MicroTilesDestroy(FTempTiles);
  960. MicroTilesDestroy(FInvalidTiles);
  961. FInvalidLayers.Free;
  962. FOldInvalidTilesMap.Free;
  963. {$IFDEF MICROTILES_DEBUGDRAW}
  964. FDebugInvalidRects.Free;
  965. MicroTilesDestroy(FDebugMicroTiles);
  966. {$ENDIF}
  967. inherited;
  968. end;
  969. procedure TMicroTilesRepaintOptimizer.AddArea(var Tiles: TMicroTiles; const Area: TRect;
  970. const Info: Cardinal);
  971. var
  972. LineWidth: Integer;
  973. begin
  974. if Info and AREAINFO_LINE <> 0 then
  975. begin
  976. LineWidth := Info and $00FFFFFF;
  977. with Area do
  978. MicroTilesAddLine(Tiles, Left, Top, Right, Bottom, LineWidth, FPerformanceLevel > PL_MICROTILES);
  979. end
  980. else
  981. MicroTilesAddRect(Tiles, Area, FPerformanceLevel > PL_MICROTILES);
  982. end;
  983. procedure TMicroTilesRepaintOptimizer.LayerUpdated(ALayer: TCustomLayer);
  984. begin
  985. if not Enabled then
  986. exit;
  987. {$IFDEF CODESITE}
  988. DumpCallStack('TMicroTilesRepaintOptimizer.LayerUpdated');
  989. {$ENDIF}
  990. if (FOldInvalidTilesValid) and (not TCustomLayerAccess(ALayer).Invalid) then
  991. begin
  992. FInvalidLayers.Add(ALayer);
  993. TCustomLayerAccess(ALayer).Invalid := True;
  994. FUseInvalidTiles := True;
  995. end;
  996. end;
  997. procedure TMicroTilesRepaintOptimizer.AreaUpdated(const AArea: TRect; const AInfo: Cardinal);
  998. begin
  999. if not Enabled then
  1000. exit;
  1001. {$IFDEF CODESITE}
  1002. DumpCallStack('TMicroTilesRepaintOptimizer.AreaUpdated');
  1003. {$ENDIF}
  1004. ValidateWorkingTiles;
  1005. AddArea(FForcedInvalidTiles, AArea, AInfo);
  1006. FUseInvalidTiles := True;
  1007. end;
  1008. procedure TMicroTilesRepaintOptimizer.LayerListNotify(ALayer: TCustomLayer; AAction: TLayerListNotification; AIndex: Integer);
  1009. var
  1010. TilesPtr: PMicroTiles;
  1011. begin
  1012. if not Enabled then
  1013. exit;
  1014. {$IFDEF CODESITE}
  1015. DumpCallStack('TMicroTilesRepaintOptimizer.LayerListNotify');
  1016. {$ENDIF}
  1017. case AAction of
  1018. lnLayerAdded, lnLayerInserted:
  1019. begin
  1020. TilesPtr := FOldInvalidTilesMap.Add(ALayer)^;
  1021. MicroTilesSetSize(TilesPtr^, Buffer.BoundsRect);
  1022. FOldInvalidTilesValid := True;
  1023. end;
  1024. lnLayerDeleted:
  1025. begin
  1026. if FOldInvalidTilesValid then
  1027. begin
  1028. // force repaint of tiles that the layer did previously allocate
  1029. MicroTilesUnion(FInvalidTiles, FOldInvalidTilesMap[ALayer]^);
  1030. FUseInvalidTiles := True;
  1031. end;
  1032. FInvalidLayers.Remove(ALayer);
  1033. FOldInvalidTilesMap.Remove(ALayer);
  1034. end;
  1035. lnCleared:
  1036. begin
  1037. if FOldInvalidTilesValid then
  1038. begin
  1039. with TPointerMapIterator.Create(FOldInvalidTilesMap) do
  1040. try
  1041. while Next do
  1042. MicroTilesUnion(FInvalidTiles, PMicroTiles(Data)^);
  1043. finally
  1044. Free;
  1045. end;
  1046. FUseInvalidTiles := True;
  1047. ResetAdaptiveMode;
  1048. end;
  1049. FOldInvalidTilesMap.Clear;
  1050. FOldInvalidTilesValid := True;
  1051. end;
  1052. end;
  1053. end;
  1054. procedure TMicroTilesRepaintOptimizer.ValidateWorkingTiles;
  1055. begin
  1056. if not FWorkingTilesValid then // check if working microtiles need resize...
  1057. begin
  1058. MicroTilesSetSize(FTempTiles, FBufferBounds);
  1059. MicroTilesSetSize(FInvalidTiles, FBufferBounds);
  1060. MicroTilesSetSize(FForcedInvalidTiles, FBufferBounds);
  1061. FWorkingTilesValid := True;
  1062. end;
  1063. end;
  1064. procedure TMicroTilesRepaintOptimizer.BufferResizedHandler(const NewWidth, NewHeight: Integer);
  1065. begin
  1066. FBufferBounds := MakeRect(0, 0, NewWidth, NewHeight);
  1067. Reset;
  1068. end;
  1069. procedure TMicroTilesRepaintOptimizer.Reset;
  1070. begin
  1071. FWorkingTilesValid := False; // force resizing of working microtiles
  1072. FOldInvalidTilesValid := False; // force resizing and rerendering of invalid tiles
  1073. UpdateOldInvalidTiles;
  1074. // mark whole buffer area invalid...
  1075. MicroTilesClear(FForcedInvalidTiles, MICROTILE_FULL);
  1076. FForcedInvalidTiles.BoundsUsedTiles := MakeRect(0, 0, FForcedInvalidTiles.Columns, FForcedInvalidTiles.Rows);
  1077. FUseInvalidTiles := True;
  1078. end;
  1079. function TMicroTilesRepaintOptimizer.UpdatesAvailable: Boolean;
  1080. begin
  1081. UpdateOldInvalidTiles;
  1082. Result := FUseInvalidTiles;
  1083. end;
  1084. procedure TMicroTilesRepaintOptimizer.UpdateOldInvalidTiles;
  1085. var
  1086. I, J: Integer;
  1087. TilesPtr: PMicroTiles;
  1088. Layer: TCustomLayer;
  1089. LayerCollection: TLayerCollection;
  1090. begin
  1091. if FOldInvalidTilesValid then // check if old Invalid tiles need resize and rerendering...
  1092. exit;
  1093. ValidateWorkingTiles;
  1094. if (LayerCollections <> nil) then
  1095. for I := 0 to LayerCollections.Count - 1 do
  1096. begin
  1097. LayerCollection := LayerCollections[I];
  1098. for J := 0 to LayerCollection.Count - 1 do
  1099. begin
  1100. Layer := LayerCollection[J];
  1101. TilesPtr := FOldInvalidTilesMap.Add(Layer)^;
  1102. MicroTilesSetSize(TilesPtr^, FBufferBounds);
  1103. if (Layer.Visible) then
  1104. DrawLayerToMicroTiles(TilesPtr^, Layer);
  1105. TCustomLayerAccess(Layer).Invalid := False;
  1106. end;
  1107. end;
  1108. FInvalidLayers.Clear;
  1109. FOldInvalidTilesValid := True;
  1110. FUseInvalidTiles := False;
  1111. end;
  1112. procedure TMicroTilesRepaintOptimizer.SetEnabled(const Value: Boolean);
  1113. begin
  1114. if (Value = Enabled) then
  1115. exit;
  1116. if Value then
  1117. BufferResizedHandler(Buffer.Width, Buffer.Height)
  1118. else
  1119. begin
  1120. MicroTilesDestroy(FInvalidTiles);
  1121. MicroTilesDestroy(FTempTiles);
  1122. MicroTilesDestroy(FForcedInvalidTiles);
  1123. FUseInvalidTiles := False;
  1124. FOldInvalidTilesValid := False;
  1125. FOldInvalidTilesMap.Clear;
  1126. FInvalidLayers.Clear;
  1127. end;
  1128. inherited;
  1129. end;
  1130. procedure TMicroTilesRepaintOptimizer.SetAdaptiveMode(const Value: Boolean);
  1131. begin
  1132. if FAdaptiveMode <> Value then
  1133. begin
  1134. FAdaptiveMode := Value;
  1135. ResetAdaptiveMode;
  1136. end;
  1137. end;
  1138. procedure TMicroTilesRepaintOptimizer.ResetAdaptiveMode;
  1139. begin
  1140. FTimeDelta := TIMER_LOWLIMIT;
  1141. FAdaptionFailed := False;
  1142. FPerformanceLevel := PL_MICROTILES;
  1143. end;
  1144. procedure TMicroTilesRepaintOptimizer.BeginPaintBuffer;
  1145. begin
  1146. if AdaptiveMode then
  1147. FPerfTimer := TStopWatch.StartNew;
  1148. end;
  1149. procedure TMicroTilesRepaintOptimizer.EndPaintBuffer;
  1150. begin
  1151. FUseInvalidTiles := False;
  1152. {$IFDEF MICROTILES_DEBUGDRAW}
  1153. {$IFDEF MICROTILES_DEBUGDRAW_UNOPTIMIZED}
  1154. MicroTilesDebugDraw(FDebugMicroTiles, Buffer, False, FDebugWholeTiles);
  1155. {$ELSE}
  1156. MicroTilesDebugDraw(FDebugMicroTiles, Buffer, True, FDebugWholeTiles);
  1157. {$ENDIF}
  1158. MicroTilesClear(FDebugMicroTiles);
  1159. {$ENDIF}
  1160. {$IFNDEF MICROTILES_NO_ADAPTION}
  1161. EndAdaption;
  1162. {$ENDIF}
  1163. end;
  1164. procedure TMicroTilesRepaintOptimizer.DrawLayerToMicroTiles(var DstTiles: TMicroTiles; Layer: TCustomLayer);
  1165. begin
  1166. Buffer.BeginMeasuring(DrawMeasuringHandler);
  1167. FWorkMicroTiles := @DstTiles;
  1168. TCustomLayerAccess(Layer).DoPaint(Buffer);
  1169. Buffer.EndMeasuring;
  1170. end;
  1171. procedure TMicroTilesRepaintOptimizer.DrawMeasuringHandler(Sender: TObject; const Area: TRect;
  1172. const Info: Cardinal);
  1173. begin
  1174. AddArea(FWorkMicroTiles^, Area, Info);
  1175. end;
  1176. procedure TMicroTilesRepaintOptimizer.PerformOptimization;
  1177. var
  1178. I: Integer;
  1179. Layer: TCustomLayer;
  1180. UseWholeTiles: Boolean;
  1181. LayerTilesPtr: PMicroTiles;
  1182. begin
  1183. if FUseInvalidTiles then
  1184. begin
  1185. ValidateWorkingTiles;
  1186. // Determine if the use of whole tiles is better for current performance level
  1187. {$IFNDEF MICROTILES_NO_ADAPTION}
  1188. UseWholeTiles := FPerformanceLevel > PL_MICROTILES;
  1189. {$ELSE}
  1190. {$IFDEF MICROTILES_NO_ADAPTION_FORCE_WHOLETILES}
  1191. UseWholeTiles := True;
  1192. {$ELSE}
  1193. UseWholeTiles := False;
  1194. {$ENDIF}
  1195. {$ENDIF}
  1196. if FInvalidLayers.Count > 0 then
  1197. begin
  1198. for I := 0 to FInvalidLayers.Count - 1 do
  1199. begin
  1200. Layer := FInvalidLayers[I];
  1201. if (not Layer.Visible) then
  1202. continue;
  1203. // Clear temporary tiles
  1204. MicroTilesClearUsed(FTempTiles);
  1205. // Draw layer to temporary tiles
  1206. DrawLayerToMicroTiles(FTempTiles, Layer);
  1207. // Combine temporary tiles with the global invalid tiles
  1208. MicroTilesUnion(FInvalidTiles, FTempTiles, UseWholeTiles);
  1209. // Retrieve old invalid tiles for the current layer
  1210. LayerTilesPtr := FOldInvalidTilesMap[Layer];
  1211. // Combine old invalid tiles with the global invalid tiles
  1212. MicroTilesUnion(FInvalidTiles, LayerTilesPtr^, UseWholeTiles);
  1213. // Copy temporary (current) invalid tiles to the layer
  1214. MicroTilesCopy(LayerTilesPtr^, FTempTiles);
  1215. // Unmark layer as invalid
  1216. TCustomLayerAccess(Layer).Invalid := False;
  1217. end;
  1218. FInvalidLayers.Clear;
  1219. end;
  1220. // Create union of global invalid tiles and forced invalid tiles
  1221. MicroTilesUnion(FInvalidTiles, FForcedInvalidTiles);
  1222. // Calculate optimized rectangles from combined tiles
  1223. MicroTilesCalcRects(FInvalidTiles, InvalidRects, False, UseWholeTiles);
  1224. {$IFDEF MICROTILES_DEBUGDRAW}
  1225. MicroTilesCopy(FDebugMicroTiles, FInvalidTiles);
  1226. FDebugWholeTiles := UseWholeTiles;
  1227. {$ENDIF}
  1228. end;
  1229. {$IFNDEF MICROTILES_NO_ADAPTION}
  1230. BeginAdaption;
  1231. {$ENDIF}
  1232. {$IFDEF MICROTILES_DEBUGDRAW}
  1233. if InvalidRects.Count > 0 then
  1234. begin
  1235. FDebugInvalidRects.Count := InvalidRects.Count;
  1236. Move(InvalidRects[0]^, FDebugInvalidRects[0]^, InvalidRects.Count * SizeOf(TRect));
  1237. InvalidRects.Clear;
  1238. end;
  1239. {$ENDIF}
  1240. // Rects have been created, so we don't need the tiles any longer, clear them.
  1241. MicroTilesClearUsed(FInvalidTiles);
  1242. MicroTilesClearUsed(FForcedInvalidTiles);
  1243. end;
  1244. procedure TMicroTilesRepaintOptimizer.BeginAdaption;
  1245. begin
  1246. if AdaptiveMode and (FPerformanceLevel > PL_MICROTILES) then
  1247. begin
  1248. if Integer(GetTickCount) > FNextCheck then
  1249. begin
  1250. FPerformanceLevel := Constrain(FPerformanceLevel - 1, PL_MICROTILES, PL_FULLSCENE);
  1251. {$IFDEF CODESITE}
  1252. CodeSite.SendInteger('PrepareInvalidRects(Timed): FPerformanceLevel', FPerformanceLevel);
  1253. {$ENDIF}
  1254. FTimedCheck := True;
  1255. end
  1256. else if not FAdaptionFailed and (InvalidRects.Count < FOldInvalidRectsCount - INVALIDRECTS_DELTA) then
  1257. begin
  1258. FPerformanceLevel := Constrain(FPerformanceLevel - 1, PL_MICROTILES, PL_FULLSCENE);
  1259. {$IFDEF CODESITE}
  1260. CodeSite.SendInteger('PrepareInvalidRects: FPerformanceLevel', FPerformanceLevel);
  1261. {$ENDIF}
  1262. end
  1263. else if FPerformanceLevel = PL_FULLSCENE then
  1264. // we need a full scene rendition, so clear the invalid rects
  1265. InvalidRects.Clear;
  1266. end;
  1267. end;
  1268. procedure TMicroTilesRepaintOptimizer.EndAdaption;
  1269. var
  1270. TimeElapsed: Int64;
  1271. Level: Integer;
  1272. begin
  1273. // our KISS(TM) repaint mode balancing starts here...
  1274. TimeElapsed := FPerfTimer.ElapsedTicks;
  1275. {$IFDEF MICROTILES_DEBUGDRAW}
  1276. if FDebugInvalidRects.Count = 0 then
  1277. {$ELSE}
  1278. if InvalidRects.Count = 0 then
  1279. {$ENDIF}
  1280. FElapsedTimeForFullSceneRepaint := TimeElapsed
  1281. else if AdaptiveMode then
  1282. begin
  1283. if TimeElapsed > FElapsedTimeForFullSceneRepaint then
  1284. begin
  1285. Level := Constrain(FPerformanceLevel + 1, PL_MICROTILES, PL_FULLSCENE);
  1286. // did performance level change from previous level?
  1287. if Level <> FPerformanceLevel then
  1288. begin
  1289. {$IFDEF MICROTILES_DEBUGDRAW}
  1290. FOldInvalidRectsCount := FDebugInvalidRects.Count;
  1291. {$ELSE}
  1292. // save count of old invalid rects so we can use it in PrepareInvalidRects
  1293. // the next time...
  1294. FOldInvalidRectsCount := InvalidRects.Count;
  1295. {$ENDIF}
  1296. FPerformanceLevel := Level;
  1297. {$IFDEF CODESITE}
  1298. CodeSite.SendInteger('EndPaintBuffer: FPerformanceLevel', FPerformanceLevel);
  1299. {$ENDIF}
  1300. // was this a timed check?
  1301. if FTimedCheck then
  1302. begin
  1303. // time based approach failed, so add penalty
  1304. FTimeDelta := Constrain(Integer(FTimeDelta + TIMER_PENALTY), TIMER_LOWLIMIT, TIMER_HIGHLIMIT);
  1305. // schedule next check
  1306. FNextCheck := Integer(GetTickCount) + FTimeDelta;
  1307. FElapsedTimeOnLastPenalty := TimeElapsed;
  1308. FTimedCheck := False;
  1309. {$IFDEF CODESITE}
  1310. CodeSite.SendInteger('timed check failed, new delta', FTimeDelta);
  1311. {$ENDIF}
  1312. end;
  1313. {$IFDEF CODESITE}
  1314. CodeSite.AddSeparator;
  1315. {$ENDIF}
  1316. FAdaptionFailed := True;
  1317. end;
  1318. end
  1319. else if TimeElapsed < FElapsedTimeForFullSceneRepaint then
  1320. begin
  1321. if FTimedCheck then
  1322. begin
  1323. // time based approach had success!!
  1324. // reset time delta back to lower limit, ie. remove penalties
  1325. FTimeDelta := TIMER_LOWLIMIT;
  1326. // schedule next check
  1327. FNextCheck := Integer(GetTickCount) + FTimeDelta;
  1328. FTimedCheck := False;
  1329. {$IFDEF CODESITE}
  1330. CodeSite.SendInteger('timed check succeeded, new delta', FTimeDelta);
  1331. CodeSite.AddSeparator;
  1332. {$ENDIF}
  1333. FAdaptionFailed := False;
  1334. end
  1335. else
  1336. begin
  1337. // invalid rect count approach had success!!
  1338. // shorten time for next check to benefit nonetheless in case we have a fallback...
  1339. if FTimeDelta > TIMER_LOWLIMIT then
  1340. begin
  1341. // remove the penalty value 4 times from the current time delta
  1342. FTimeDelta := Constrain(FTimeDelta - 4 * TIMER_PENALTY, TIMER_LOWLIMIT, TIMER_HIGHLIMIT);
  1343. // schedule next check
  1344. FNextCheck := Integer(GetTickCount) + FTimeDelta;
  1345. {$IFDEF CODESITE}
  1346. CodeSite.SendInteger('invalid rect count approach succeeded, new timer delta', FTimeDelta);
  1347. CodeSite.AddSeparator;
  1348. {$ENDIF}
  1349. end;
  1350. FAdaptionFailed := False;
  1351. end;
  1352. end
  1353. else if (TimeElapsed < FElapsedTimeOnLastPenalty) and FTimedCheck then
  1354. begin
  1355. // time approach had success optimizing the situation, so shorten time until next check
  1356. FTimeDelta := Constrain(FTimeDelta - TIMER_PENALTY, TIMER_LOWLIMIT, TIMER_HIGHLIMIT);
  1357. // schedule next check
  1358. FNextCheck := Integer(GetTickCount) + FTimeDelta;
  1359. FTimedCheck := False;
  1360. {$IFDEF CODESITE}
  1361. CodeSite.SendInteger('timed check succeeded, new delta', FTimeDelta);
  1362. CodeSite.AddSeparator;
  1363. {$ENDIF}
  1364. end;
  1365. end;
  1366. FElapsedTimeForLastRepaint := TimeElapsed;
  1367. end;
  1368. {$IFDEF CODESITE}
  1369. { TDebugMicroTilesRepaintOptimizer }
  1370. procedure TDebugMicroTilesRepaintOptimizer.BeginPaintBuffer;
  1371. begin
  1372. DumpCallStack('TDebugMicroTilesRepaintOptimizer.BeginPaintBuffer');
  1373. inherited;
  1374. end;
  1375. procedure TDebugMicroTilesRepaintOptimizer.BufferResizedHandler(const NewWidth,
  1376. NewHeight: Integer);
  1377. begin
  1378. DumpCallStack('TDebugMicroTilesRepaintOptimizer.BufferResizedHandler');
  1379. inherited;
  1380. end;
  1381. procedure TDebugMicroTilesRepaintOptimizer.EndPaintBuffer;
  1382. begin
  1383. DumpCallStack('TDebugMicroTilesRepaintOptimizer.EndPaintBuffer');
  1384. inherited;
  1385. CodeSite.AddSeparator;
  1386. end;
  1387. procedure TDebugMicroTilesRepaintOptimizer.PerformOptimization;
  1388. begin
  1389. DumpCallStack('TDebugMicroTilesRepaintOptimizer.PerformOptimization');
  1390. inherited;
  1391. end;
  1392. procedure TDebugMicroTilesRepaintOptimizer.Reset;
  1393. begin
  1394. DumpCallStack('TDebugMicroTilesRepaintOptimizer.Reset');
  1395. inherited;
  1396. CodeSite.AddSeparator;
  1397. end;
  1398. function TDebugMicroTilesRepaintOptimizer.UpdatesAvailable: Boolean;
  1399. begin
  1400. DumpCallStack('TDebugMicroTilesRepaintOptimizer.UpdatesAvailable');
  1401. Result := inherited UpdatesAvailable;
  1402. end;
  1403. {$ENDIF}
  1404. var
  1405. Registry: TFunctionRegistry;
  1406. procedure RegisterBindings;
  1407. begin
  1408. Registry := NewRegistry('GR32_MicroTiles bindings');
  1409. Registry.RegisterBinding(@@MicroTileUnion, 'MicroTileUnion');
  1410. Registry.RegisterBinding(@@MicroTilesU, 'MicroTilesU');
  1411. Registry[@@MicroTileUnion].Add( @MicroTileUnion_Pas, [isPascal]).Name := 'MicroTileUnion_Pas';
  1412. Registry[@@MicroTilesU].Add( @MicroTilesUnion_Pas, [isPascal]).Name := 'MicroTilesUnion_Pas';
  1413. // TODO : rewrite MMX implementations using SSE
  1414. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_MMX)) and defined(TARGET_x86)}
  1415. Registry[@@MicroTileUnion].Add( @MicroTileUnion_EMMX, [isExMMX]).Name := 'MicroTileUnion_EMMX';
  1416. Registry[@@MicroTilesU].Add( @MicroTilesUnion_EMMX, [isExMMX]).Name := 'MicroTilesUnion_EMMX';
  1417. {$ifend}
  1418. Registry.RebindAll;
  1419. end;
  1420. initialization
  1421. RegisterBindings;
  1422. end.