fSynthTerrain.pas 7.4 KB

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