GR32_MicroTiles.pas 51 KB

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