fSynthTerrainD.pas 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. unit fSynthTerrainD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.OpenGL,
  6. System.SysUtils,
  7. System.Classes,
  8. System.UITypes,
  9. Vcl.Graphics,
  10. Vcl.Controls,
  11. Vcl.Forms,
  12. Vcl.Dialogs,
  13. Vcl.ExtCtrls,
  14. Vcl.StdCtrls,
  15. Vcl.Imaging.Jpeg,
  16. GLS.Scene,
  17. GLS.Objects,
  18. GLS.TerrainRenderer,
  19. GLS.HeightData,
  20. GLS.Cadencer,
  21. GLScene.VectorTypes,
  22. GLS.Texture,
  23. GLS.SceneViewer,
  24. GLS.Material,
  25. GLScene.Keyboard,
  26. GLScene.VectorGeometry,
  27. GLS.Coordinates,
  28. GLS.BaseClasses,
  29. GLS.XCollection,
  30. GLS.ShadowHDS;
  31. type
  32. TFormSynthTerrain = class(TForm)
  33. GLSceneViewer1: TGLSceneViewer;
  34. GLScene1: TGLScene;
  35. GLCamera1: TGLCamera;
  36. DummyCube1: TGLDummyCube;
  37. TerrainRenderer1: TGLTerrainRenderer;
  38. Timer1: TTimer;
  39. GLCadencer1: TGLCadencer;
  40. GLMaterialLibrary1: TGLMaterialLibrary;
  41. GLCustomHDS: TGLCustomHDS;
  42. GLShadowHDS: TGLShadowHDS;
  43. procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  44. Shift: TShiftState; X, Y: Integer);
  45. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  46. X, Y: Integer);
  47. procedure Timer1Timer(Sender: TObject);
  48. procedure GLCadencer1Progress(Sender: TObject;
  49. const deltaTime, newTime: Double);
  50. procedure FormCreate(Sender: TObject);
  51. procedure FormKeyPress(Sender: TObject; var Key: Char);
  52. procedure GLCustomHDSStartPreparingData(HeightData: TGLHeightData);
  53. public
  54. mx, my: Integer;
  55. fullScreen: Boolean;
  56. FCamHeight: Single;
  57. end;
  58. var
  59. FormSynthTerrain: TFormSynthTerrain;
  60. implementation
  61. {$R *.DFM}
  62. procedure TFormSynthTerrain.FormCreate(Sender: TObject);
  63. var
  64. i: Integer;
  65. bmp: TBitmap;
  66. begin
  67. // 8 MB height data cache
  68. // Note this is the data size in terms of elevation samples, it does not
  69. // take into account all the data required/allocated by the renderer
  70. GLCustomHDS.MaxPoolSize := 8 * 1024 * 1024;
  71. // Move camera starting point to an interesting hand-picked location
  72. DummyCube1.Position.X := 50;
  73. DummyCube1.Position.Z := 150;
  74. // Initial camera height offset (controled with pageUp/pageDown)
  75. FCamHeight := 20;
  76. // We build several basic 1D textures which are just color ramps
  77. // all use automatic texture mapping corodinates, in ObjectLinear method
  78. // (ie. texture coordinates for a vertex depend on that vertex coordinates)
  79. bmp := TBitmap.Create;
  80. bmp.PixelFormat := pf24bit;
  81. bmp.Width := 256;
  82. bmp.Height := 1;
  83. // Black-White ramp, autotexture maps to Z coordinate
  84. // This one changes with altitude, this is a quick way to obtain
  85. // altitude-dependant coloring
  86. for i := 0 to 255 do
  87. bmp.Canvas.Pixels[i, 0] := RGB(i, i, i);
  88. with GLMaterialLibrary1.AddTextureMaterial('BW', bmp) do
  89. begin
  90. Material.Texture.MappingMode := tmmObjectLinear;
  91. Material.Texture.MappingSCoordinates.AsVector := VectorMake(0, 0, 0.0001, 0);
  92. end;
  93. // Red, Blue map linearly to X and Y axis respectively
  94. for i := 0 to 255 do
  95. bmp.Canvas.Pixels[i, 0] := RGB(i, 0, 0);
  96. with GLMaterialLibrary1.AddTextureMaterial('Red', bmp) do
  97. begin
  98. Material.Texture.MappingMode := tmmObjectLinear;
  99. Material.Texture.MappingSCoordinates.AsVector := VectorMake(0.1, 0, 0, 0);
  100. end;
  101. for i := 0 to 255 do
  102. bmp.Canvas.Pixels[i, 0] := RGB(0, 0, i);
  103. with GLMaterialLibrary1.AddTextureMaterial('Blue', bmp) do
  104. begin
  105. Material.Texture.MappingMode := tmmObjectLinear;
  106. Material.Texture.MappingSCoordinates.AsVector := VectorMake(0, 0.1, 0, 0);
  107. end;
  108. bmp.Free;
  109. TerrainRenderer1.MaterialLibrary := GLMaterialLibrary1;
  110. end;
  111. //
  112. // The beef : this event does all the interesting elevation data stuff
  113. //
  114. procedure TFormSynthTerrain.GLCustomHDSStartPreparingData(HeightData: TGLHeightData);
  115. var
  116. Y, X: Integer;
  117. rasterLine: PByteArray;
  118. oldType: TGLHeightDataType;
  119. b: Byte;
  120. d, dy: Single;
  121. begin
  122. HeightData.DataState := hdsPreparing;
  123. // retrieve data
  124. with HeightData do
  125. begin
  126. oldType := DataType;
  127. Allocate(hdtByte);
  128. // Cheap texture changed (32 is our tileSize = 2^5)
  129. // This basicly picks a texture for each tile depending on the tile's position
  130. case (((XLeft xor YTop) shr 5) and 3) of
  131. 0, 3: HeightData.MaterialName := 'BW';
  132. 1: HeightData.MaterialName := 'Blue';
  133. 2: HeightData.MaterialName := 'Red';
  134. end;
  135. // 'Cheap' elevation data : this is just a formula z=f(x, y)
  136. for Y := YTop to YTop + Size - 1 do
  137. begin
  138. rasterLine := ByteRaster[Y - YTop];
  139. dy := Sqr(Y);
  140. for X := XLeft to XLeft + Size - 1 do
  141. begin
  142. d := Sqrt(Sqr(X) + dy);
  143. b := Round(128 + 128 * Sin(d * 0.2) / (d * 0.1 + 1));
  144. rasterLine[X - XLeft] := b;
  145. end;
  146. end;
  147. if oldType <> hdtByte then
  148. DataType := oldType;
  149. end;
  150. inherited;
  151. end;
  152. // Movement, mouse handling etc.
  153. procedure TFormSynthTerrain.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  154. Shift: TShiftState; X, Y: Integer);
  155. begin
  156. mx := X;
  157. my := Y;
  158. end;
  159. procedure TFormSynthTerrain.GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  160. X, Y: Integer);
  161. begin
  162. if ssLeft in Shift then
  163. begin
  164. GLCamera1.MoveAroundTarget(my - Y, mx - X);
  165. mx := X;
  166. my := Y;
  167. end;
  168. end;
  169. procedure TFormSynthTerrain.Timer1Timer(Sender: TObject);
  170. begin
  171. Caption := Format('%.1f FPS - %d', [GLSceneViewer1.FramesPerSecond,
  172. TerrainRenderer1.LastTriangleCount]);
  173. GLSceneViewer1.ResetPerformanceMonitor;
  174. end;
  175. procedure TFormSynthTerrain.FormKeyPress(Sender: TObject; var Key: Char);
  176. begin
  177. case Key of
  178. '+':
  179. if GLCamera1.DepthOfView < 4000 then
  180. begin
  181. GLCamera1.DepthOfView := GLCamera1.DepthOfView * 1.2;
  182. with GLSceneViewer1.Buffer.FogEnvironment do
  183. begin
  184. FogEnd := FogEnd * 1.2;
  185. FogStart := FogStart * 1.2;
  186. end;
  187. end;
  188. '-':
  189. if GLCamera1.DepthOfView > 300 then
  190. begin
  191. GLCamera1.DepthOfView := GLCamera1.DepthOfView / 1.2;
  192. with GLSceneViewer1.Buffer.FogEnvironment do
  193. begin
  194. FogEnd := FogEnd / 1.2;
  195. FogStart := FogStart / 1.2;
  196. end;
  197. end;
  198. '*':
  199. with TerrainRenderer1 do
  200. if CLODPrecision > 5 then
  201. CLODPrecision := Round(CLODPrecision * 0.8);
  202. '/':
  203. with TerrainRenderer1 do
  204. if CLODPrecision < 500 then
  205. CLODPrecision := Round(CLODPrecision * 1.2);
  206. '8':
  207. with TerrainRenderer1 do
  208. if QualityDistance > 40 then
  209. QualityDistance := Round(QualityDistance * 0.8);
  210. '9':
  211. with TerrainRenderer1 do
  212. if QualityDistance < 1000 then
  213. QualityDistance := Round(QualityDistance * 1.2);
  214. end;
  215. Key := #0;
  216. end;
  217. procedure TFormSynthTerrain.GLCadencer1Progress(Sender: TObject;
  218. const deltaTime, newTime: Double);
  219. var
  220. speed: Single;
  221. begin
  222. // handle keypresses
  223. if IsKeyDown(VK_SHIFT) then
  224. speed := 5 * deltaTime
  225. else
  226. speed := deltaTime;
  227. with GLCamera1.Position do
  228. begin
  229. if IsKeyDown(VK_RIGHT) then
  230. DummyCube1.Translate(Z * speed, 0, -X * speed);
  231. if IsKeyDown(VK_LEFT) then
  232. DummyCube1.Translate(-Z * speed, 0, X * speed);
  233. if IsKeyDown(VK_UP) then
  234. DummyCube1.Translate(-X * speed, 0, -Z * speed);
  235. if IsKeyDown(VK_DOWN) then
  236. DummyCube1.Translate(X * speed, 0, Z * speed);
  237. if IsKeyDown(VK_PRIOR) then
  238. FCamHeight := FCamHeight + 10 * speed;
  239. if IsKeyDown(VK_NEXT) then
  240. FCamHeight := FCamHeight - 10 * speed;
  241. if IsKeyDown(VK_ESCAPE) then
  242. Close;
  243. end;
  244. // don't drop through terrain!
  245. with DummyCube1.Position do
  246. Y := TerrainRenderer1.InterpolatedHeight(AsVector) + FCamHeight;
  247. end;
  248. end.