fViewerD.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. unit fViewerD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. System.SysUtils,
  6. System.Classes,
  7. System.Actions,
  8. System.ImageList,
  9. Vcl.Graphics,
  10. Vcl.Controls,
  11. Vcl.Forms,
  12. Vcl.Dialogs,
  13. Vcl.ActnList,
  14. Vcl.StdCtrls,
  15. Vcl.ExtCtrls,
  16. Vcl.ComCtrls,
  17. Vcl.ImgList,
  18. Vcl.ToolWin,
  19. Vcl.Menus,
  20. GR32_Image,
  21. GR32,
  22. GLS.HeightTileFileHDS,
  23. Stage.VectorGeometry,
  24. Stage.Utils;
  25. type
  26. TViewerForm = class(TForm)
  27. ToolBar: TToolBar;
  28. ImageList: TImageList;
  29. ActionList: TActionList;
  30. ToolButton1: TToolButton;
  31. LAMap: TLabel;
  32. ToolButton2: TToolButton;
  33. ACOpen: TAction;
  34. ACExit: TAction;
  35. ToolButton3: TToolButton;
  36. OpenDialog: TOpenDialog;
  37. PaintBox: TPaintBox32;
  38. ToolButton4: TToolButton;
  39. TBGrid: TToolButton;
  40. ToolButton5: TToolButton;
  41. ToolButton6: TToolButton;
  42. ACNavMap: TAction;
  43. StatusBar: TStatusBar;
  44. ToolButton7: TToolButton;
  45. ACPalette: TAction;
  46. PMPalettes: TPopupMenu;
  47. OpenDialogPal: TOpenDialog;
  48. procedure ACExitExecute(Sender: TObject);
  49. procedure FormDestroy(Sender: TObject);
  50. procedure ACOpenExecute(Sender: TObject);
  51. procedure FormCreate(Sender: TObject);
  52. procedure PaintBoxResize(Sender: TObject);
  53. procedure PaintBoxMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
  54. X, Y: Integer);
  55. procedure PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  56. procedure TBGridClick(Sender: TObject);
  57. procedure ACNavMapExecute(Sender: TObject);
  58. procedure PaintBoxMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
  59. X, Y: Integer);
  60. procedure ACNavMapUpdate(Sender: TObject);
  61. procedure ACPaletteExecute(Sender: TObject);
  62. private
  63. Path: TFileName;
  64. public
  65. htf: TGLHeightTileFile;
  66. bmpTile: TBitmap32;
  67. curX, curY, mx, my: Integer;
  68. procedure PrepareBitmap;
  69. end;
  70. var
  71. ViewerForm: TViewerForm;
  72. heightColor: array [Low(SmallInt) .. High(SmallInt)] of TColor32;
  73. implementation //----------------------------------------------------------
  74. {$R *.dfm}
  75. uses
  76. fNavD;
  77. (*
  78. Quick'n dirty parser for palette file format '.pal', in which each line defines
  79. nodes in the color ramp palette:
  80. value:red,green,blue
  81. color is then interpolated between node values (ie. between each line in the file)
  82. *)
  83. procedure PreparePal(const fileName: String);
  84. procedure ParseLine(buf: String; var n: Integer; var c: TAffineVector);
  85. var
  86. p: Integer;
  87. begin
  88. p := Pos(':', buf);
  89. n := StrToInt(Copy(buf, 1, p - 1));
  90. buf := Copy(buf, p + 1, MaxInt);
  91. p := Pos(',', buf);
  92. c.X := StrToInt(Copy(buf, 1, p - 1));
  93. buf := Copy(buf, p + 1, MaxInt);
  94. p := Pos(',', buf);
  95. c.Y := StrToInt(Copy(buf, 1, p - 1));
  96. buf := Copy(buf, p + 1, MaxInt);
  97. c.Z := StrToInt(buf);
  98. end;
  99. var
  100. prev, next: Integer;
  101. pC, nC: TAffineVector;
  102. procedure Ramp;
  103. var
  104. cur: Integer;
  105. cC: TAffineVector;
  106. d: Single;
  107. begin
  108. if prev < next then
  109. d := 1 / (next - prev)
  110. else
  111. d := 0;
  112. for cur := prev to next do
  113. begin
  114. cC := VectorLerp(pC, nC, (cur - prev) * d);
  115. heightColor[cur] := Color32(Round(cC.X), Round(cC.Y), Round(cC.Z));
  116. end;
  117. end;
  118. var
  119. i: Integer;
  120. sl: TStrings;
  121. begin
  122. sl := TStringList.Create;
  123. try
  124. sl.LoadFromFile(fileName);
  125. prev := 0;
  126. pC := NullVector;
  127. for i := 0 to sl.Count - 1 do
  128. begin
  129. ParseLine(sl[i], next, nC);
  130. Ramp;
  131. prev := next;
  132. pC := nC;
  133. end;
  134. finally
  135. sl.Free;
  136. end;
  137. end;
  138. // ----------------------------------------------------------------
  139. procedure TViewerForm.FormCreate(Sender: TObject);
  140. var
  141. i: Integer;
  142. sr: TSearchRec;
  143. mi: TMenuItem;
  144. sl: TStringList;
  145. AppDir: TFileName;
  146. begin
  147. bmpTile := TBitmap32.Create;
  148. AppDir := ExtractFilePath(ParamStr(0));
  149. PreparePal(AppDir + 'Blue-Green-Red.pal');
  150. i := FindFirst(AppDir + '*.pal', faAnyFile, sr);
  151. sl := TStringList.Create;
  152. try
  153. while i = 0 do
  154. begin
  155. sl.Add(sr.Name);
  156. i := FindNext(sr);
  157. end;
  158. sl.Sort;
  159. for i := 0 to sl.Count - 1 do
  160. begin
  161. mi := TMenuItem.Create(PMPalettes);
  162. mi.Caption := Copy(sl[i], 1, Length(sl[i]) - 4);
  163. mi.Hint := AppDir + sl[i];
  164. mi.OnClick := ACPaletteExecute;
  165. PMPalettes.Items.Add(mi);
  166. end;
  167. finally
  168. sl.Free;
  169. FindClose(sr);
  170. end;
  171. end;
  172. // ----------------------------------------------------------------
  173. procedure TViewerForm.FormDestroy(Sender: TObject);
  174. begin
  175. htf.Free;
  176. bmpTile.Free;
  177. end;
  178. // ----------------------------------------------------------------
  179. procedure TViewerForm.ACExitExecute(Sender: TObject);
  180. begin
  181. Close;
  182. end;
  183. // ----------------------------------------------------------------
  184. procedure TViewerForm.ACOpenExecute(Sender: TObject);
  185. var
  186. i: Integer;
  187. begin
  188. Path := GetCurrentAssetPath() + '\landscape';
  189. OpenDialog.InitialDir := Path;
  190. if OpenDialog.Execute then
  191. begin
  192. htf.Free;
  193. htf := TGLHeightTileFile.Create(OpenDialog.fileName);
  194. Caption := 'HTFViewer - ' + ExtractFileName(OpenDialog.fileName);
  195. curX := 0;
  196. curY := 0;
  197. PrepareBitmap;
  198. PaintBox.Invalidate;
  199. end;
  200. end;
  201. // ----------------------------------------------------------------
  202. procedure TViewerForm.PrepareBitmap;
  203. var
  204. i, sx, tx, ty: Integer;
  205. scanLine: PColor32Array;
  206. tileInfo: PGLHeightTileInfo;
  207. dataRow: PSmallIntArray;
  208. tile: PGLHeightTile;
  209. start, lap, stop, htfTime, drawTime, freq: Int64;
  210. tileList: TList;
  211. bmp: TBitmap32;
  212. begin
  213. sx := PaintBox.Width;
  214. bmp := PaintBox.Buffer;
  215. bmp.Clear(clBlack32);
  216. if not Assigned(htf) then
  217. Exit;
  218. drawTime := 0;
  219. tileList := TList.Create;
  220. try
  221. QueryPerformanceCounter(start);
  222. htf.TilesInRect(curX, curY, curX + sx - 1, curY + bmp.Height - 1, tileList);
  223. QueryPerformanceCounter(stop);
  224. htfTime := stop - start;
  225. for i := 0 to tileList.Count - 1 do
  226. begin
  227. tileInfo := PGLHeightTileInfo(tileList[i]);
  228. QueryPerformanceCounter(start);
  229. tile := htf.GetTile(tileInfo.left, tileInfo.top);
  230. QueryPerformanceCounter(lap);
  231. bmpTile.Width := tileInfo.Width;
  232. bmpTile.Height := tileInfo.Height;
  233. for ty := 0 to tileInfo.Height - 1 do
  234. begin
  235. scanLine := bmpTile.scanLine[ty];
  236. dataRow := @tile.data[ty * tileInfo.Width];
  237. for tx := 0 to tileInfo.Width - 1 do
  238. scanLine[tx] := heightColor[dataRow[tx]];
  239. end;
  240. bmp.Draw(tileInfo.left - curX, tileInfo.top - curY, bmpTile);
  241. QueryPerformanceCounter(stop);
  242. htfTime := htfTime + lap - start;
  243. drawTime := drawTime + stop - lap;
  244. end;
  245. if TBGrid.Down then
  246. begin
  247. for i := 0 to tileList.Count - 1 do
  248. with PGLHeightTileInfo(tileList[i])^ do
  249. begin
  250. bmp.FrameRectS(left - curX, top - curY, left + Width - curX + 1, top + Height - curY + 1,
  251. clWhite32);
  252. end;
  253. end;
  254. finally
  255. tileList.Free;
  256. end;
  257. QueryPerformanceFrequency(freq);
  258. LAMap.Caption := Format(' %d x %d - %.1f ms HTF - %.1fms Draw ',
  259. [htf.SizeX, htf.SizeY, 1000 * htfTime / freq, 1000 * drawTime / freq]);
  260. end;
  261. procedure TViewerForm.PaintBoxResize(Sender: TObject);
  262. begin
  263. if Assigned(htf) then
  264. PrepareBitmap;
  265. end;
  266. procedure TViewerForm.PaintBoxMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
  267. X, Y: Integer);
  268. begin
  269. mx := X;
  270. my := Y;
  271. Screen.Cursor := crSizeAll;
  272. end;
  273. //----------------------------------------------------------------
  274. procedure TViewerForm.PaintBoxMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
  275. X, Y: Integer);
  276. begin
  277. Screen.Cursor := crDefault;
  278. end;
  279. //----------------------------------------------------------------
  280. procedure TViewerForm.PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  281. var
  282. tileIdx, n: Integer;
  283. tileInfo: PGLHeightTileInfo;
  284. begin
  285. if Shift <> [] then
  286. begin
  287. curX := curX - (X - mx);
  288. curY := curY - (Y - my);
  289. mx := X;
  290. my := Y;
  291. PrepareBitmap;
  292. PaintBox.Refresh;
  293. end;
  294. if Assigned(htf) then
  295. begin
  296. X := X + curX;
  297. Y := Y + curY;
  298. StatusBar.Panels[0].Text := ' X: ' + IntToStr(X);
  299. StatusBar.Panels[1].Text := ' Y: ' + IntToStr(Y);
  300. StatusBar.Panels[2].Text := ' H: ' + IntToStr(htf.XYHeight(X, Y));
  301. tileInfo := htf.XYTileInfo(X, Y);
  302. if Assigned(tileInfo) then
  303. begin
  304. tileIdx := htf.IndexOfTile(tileInfo);
  305. StatusBar.Panels[3].Text := ' Tile: ' + IntToStr(tileIdx);
  306. n := htf.TileCompressedSize(tileIdx) + SizeOf(TGLHeightTileInfo);
  307. StatusBar.Panels[4].Text := Format(' %.2f kB (%.0f %%)',
  308. [n / 1024, 100 - 100 * n / (htf.TileSize * htf.TileSize * 2)]);
  309. StatusBar.Panels[5].Text := Format(' Tile average: %d, range: [%d; %d])',
  310. [tileInfo.average, tileInfo.min, tileInfo.max]);
  311. end
  312. else
  313. begin
  314. StatusBar.Panels[3].Text := ' Tile: N/A';
  315. StatusBar.Panels[4].Text := ' N/A';
  316. StatusBar.Panels[5].Text := ' N/A';
  317. end;
  318. end;
  319. end;
  320. //----------------------------------------------------------------
  321. procedure TViewerForm.TBGridClick(Sender: TObject);
  322. begin
  323. PrepareBitmap;
  324. PaintBox.Invalidate;
  325. end;
  326. //----------------------------------------------------------------
  327. procedure TViewerForm.ACNavMapExecute(Sender: TObject);
  328. begin
  329. if NavForm.Execute(htf) then
  330. begin
  331. curX := NavForm.PickX;
  332. curY := NavForm.PickY;
  333. PrepareBitmap;
  334. PaintBox.Invalidate;
  335. end;
  336. end;
  337. //----------------------------------------------------------------
  338. procedure TViewerForm.ACNavMapUpdate(Sender: TObject);
  339. begin
  340. ACNavMap.Enabled := Assigned(htf);
  341. end;
  342. //----------------------------------------------------------------
  343. procedure TViewerForm.ACPaletteExecute(Sender: TObject);
  344. begin
  345. if Sender is TMenuItem then
  346. PreparePal(TMenuItem(Sender).Hint)
  347. else if OpenDialogPal.Execute then
  348. PreparePal(OpenDialogPal.fileName);
  349. PrepareBitmap;
  350. PaintBox.Invalidate;
  351. end;
  352. end.