fViewerD.pas 9.7 KB

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