FViewerForm.pas 8.9 KB

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