fShadedTerrain.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. unit fShadedTerrain;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.OpenGL,
  6. System.SysUtils,
  7. System.UITypes,
  8. System.Classes,
  9. System.Math,
  10. Vcl.Graphics,
  11. Vcl.Controls,
  12. Vcl.Forms,
  13. Vcl.Imaging.Jpeg,
  14. Vcl.ExtCtrls,
  15. Vcl.ComCtrls,
  16. Vcl.StdCtrls,
  17. GLS.Scene,
  18. GLS.BaseClasses,
  19. GLS.Objects,
  20. GLS.Keyboard,
  21. GLS.TerrainRenderer,
  22. GLS.ROAMPatch,
  23. GLS.HeightData,
  24. GLS.Cadencer,
  25. GLS.Texture,
  26. GLS.SkyDome,
  27. GLS.SceneViewer,
  28. GLS.VectorTypes,
  29. GLS.VectorGeometry,
  30. GLS.LensFlare,
  31. GLS.BumpMapHDS,
  32. GLSL.TextureShaders,
  33. GLS.Material,
  34. GLS.Coordinates,
  35. GLS.State,
  36. GLS.Utils;
  37. type
  38. TFormShadedTerrain = class(TForm)
  39. GLSceneViewer1: TGLSceneViewer;
  40. GLBitmapHDS1: TGLBitmapHDS;
  41. GLScene1: TGLScene;
  42. GLCamera1: TGLCamera;
  43. DummyCube1: TGLDummyCube;
  44. TerrainRenderer1: TGLTerrainRenderer;
  45. Timer1: TTimer;
  46. GLCadencer1: TGLCadencer;
  47. GLMaterialLibrary1: TGLMaterialLibrary;
  48. SkyDome1: TGLSkyDome;
  49. SPSun: TGLSprite;
  50. GLLensFlare: TGLLensFlare;
  51. GLDummyCube1: TGLDummyCube;
  52. GLTexCombineShader1: TGLTexCombineShader;
  53. GLBumpmapHDS1: TGLBumpmapHDS;
  54. Panel1: TPanel;
  55. Label1: TLabel;
  56. TBSubSampling: TTrackBar;
  57. LASubFactor: TLabel;
  58. Label2: TLabel;
  59. TBIntensity: TTrackBar;
  60. LABumpIntensity: TLabel;
  61. TBContourInterval: TTrackBar;
  62. TBScaleZ: TTrackBar;
  63. LaScaleZ: TLabel;
  64. LabelZ: TLabel;
  65. LabelContInterval: TLabel;
  66. CBContourIntervals: TCheckBox;
  67. procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  68. Shift: TShiftState; X, Y: Integer);
  69. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  70. X, Y: Integer);
  71. procedure Timer1Timer(Sender: TObject);
  72. procedure GLCadencer1Progress(Sender: TObject;
  73. const deltaTime, newTime: Double);
  74. procedure FormCreate(Sender: TObject);
  75. procedure FormKeyPress(Sender: TObject; var Key: Char);
  76. procedure GLSceneViewer1BeforeRender(Sender: TObject);
  77. procedure GLBumpmapHDS1NewTilePrepared(Sender: TGLBumpmapHDS;
  78. heightData: TGLHeightData; normalMapMaterial: TGLLibMaterial);
  79. procedure TBSubSamplingChange(Sender: TObject);
  80. procedure FormShow(Sender: TObject);
  81. procedure TBIntensityChange(Sender: TObject);
  82. procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
  83. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  84. procedure TBScaleZChange(Sender: TObject);
  85. procedure TBContourIntervalChange(Sender: TObject);
  86. procedure CBContourIntervalsClick(Sender: TObject);
  87. public
  88. mx, my: Integer;
  89. fullScreen: Boolean;
  90. FCamHeight: Single;
  91. end;
  92. var
  93. FormShadedTerrain: TFormShadedTerrain;
  94. implementation
  95. {$R *.DFM}
  96. procedure TFormShadedTerrain.FormCreate(Sender: TObject);
  97. begin
  98. SetGLSceneMediaDir();
  99. // Load Terrain in 8 MB height data cache
  100. // Note this is the data size in terms of elevation samples, it does not
  101. // take into account all the data required/allocated by the renderer
  102. GLBitmapHDS1.MaxPoolSize := 8 * 1024 * 1024;
  103. // specify a map for height field data
  104. GLBitmapHDS1.Picture.LoadFromFile('terrain.bmp');
  105. GLMaterialLibrary1.LibMaterialByName('details').Material.Texture.Image.LoadFromFile('detailmap.jpg');
  106. (*
  107. GLMaterialLibrary1.LibMaterialByName('texture').Material.Texture.Image.LoadFromFile('texture.jpg');
  108. *)
  109. SPSun.Material.Texture.Image.LoadFromFile('flare1.bmp');
  110. // Could've been done at design time, but then it hurts the eyes ;)
  111. GLSceneViewer1.Buffer.BackgroundColor := clWhite;
  112. // Initial camera height offset (controled with pageUp/pageDown)
  113. FCamHeight := 20;
  114. // apply texture map scale (our heightmap size is 256)
  115. TerrainRenderer1.TilesPerTexture := 4; // 256/TerrainRenderer1.TileSize;
  116. // TerrainRenderer1.MaterialLibrary := GLMaterialLibrary1;
  117. TerrainRenderer1.ContourWidth := 2;
  118. TBIntensityChange(Self);
  119. TBScaleZChange(Self);
  120. end;
  121. procedure TFormShadedTerrain.FormShow(Sender: TObject);
  122. begin
  123. TBSubSamplingChange(Self);
  124. TBContourIntervalChange(Self);
  125. end;
  126. procedure TFormShadedTerrain.GLBumpmapHDS1NewTilePrepared(Sender: TGLBumpmapHDS;
  127. heightData: TGLHeightData; normalMapMaterial: TGLLibMaterial);
  128. var
  129. Vec: TGLVector;
  130. begin
  131. heightData.MaterialName := normalMapMaterial.Name;
  132. normalMapMaterial.Texture2Name := 'contrast';//'details', 'texture' or 'contrast';
  133. normalMapMaterial.Shader := GLTexCombineShader1;
  134. normalMapMaterial.Material.MaterialOptions := [moNoLighting];
  135. Vec := VectorNormalize(SPSun.AbsolutePosition);
  136. ScaleVector(Vec, 0.5);
  137. Vec.Y := -Vec.Y;
  138. Vec.Z := -Vec.Z;
  139. AddVector(Vec, 0.5);
  140. normalMapMaterial.Material.FrontProperties.Diffuse.Color := Vec;
  141. end;
  142. procedure TFormShadedTerrain.GLCadencer1Progress(Sender: TObject;
  143. const deltaTime, newTime: Double);
  144. var
  145. speed: Single;
  146. begin
  147. // handle keypresses
  148. if IsKeyDown(VK_SHIFT) then
  149. speed := 10 * deltaTime
  150. else
  151. speed := deltaTime;
  152. with GLCamera1.Position do
  153. begin
  154. if IsKeyDown(VK_UP) then
  155. DummyCube1.Translate(-X * speed, 0, -Z * speed);
  156. if IsKeyDown(VK_DOWN) then
  157. DummyCube1.Translate(X * speed, 0, Z * speed);
  158. if IsKeyDown(VK_LEFT) then
  159. DummyCube1.Translate(-Z * speed, 0, X * speed);
  160. if IsKeyDown(VK_RIGHT) then
  161. DummyCube1.Translate(Z * speed, 0, -X * speed);
  162. if IsKeyDown(VK_PRIOR) then
  163. FCamHeight := FCamHeight + 10 * speed;
  164. if IsKeyDown(VK_NEXT) then
  165. FCamHeight := FCamHeight - 10 * speed;
  166. if IsKeyDown(VK_ESCAPE) then
  167. Close;
  168. end;
  169. // don't drop through terrain!
  170. with DummyCube1.Position do
  171. Y := TerrainRenderer1.InterpolatedHeight(AsVector) + FCamHeight;
  172. end;
  173. // Standard mouse rotation & FPS code below
  174. procedure TFormShadedTerrain.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  175. Shift: TShiftState; X, Y: Integer);
  176. begin
  177. GLSceneViewer1.SetFocus;
  178. mx := X;
  179. my := Y;
  180. end;
  181. procedure TFormShadedTerrain.GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  182. X, Y: Integer);
  183. begin
  184. if ssLeft in Shift then
  185. begin
  186. GLCamera1.MoveAroundTarget((my - Y) * 0.5, (mx - X) * 0.5);
  187. mx := X;
  188. my := Y;
  189. end;
  190. end;
  191. procedure TFormShadedTerrain.Timer1Timer(Sender: TObject);
  192. begin
  193. Caption := 'Shaded Terrain ' + GLSceneViewer1.FramesPerSecondText;
  194. GLSceneViewer1.ResetPerformanceMonitor;
  195. end;
  196. procedure TFormShadedTerrain.FormKeyPress(Sender: TObject; var Key: Char);
  197. begin
  198. case Key of
  199. 'w', 'W':
  200. with GLMaterialLibrary1.Materials[0].Material do
  201. begin
  202. if PolygonMode = pmLines then
  203. PolygonMode := pmFill
  204. else
  205. PolygonMode := pmLines;
  206. end;
  207. '+':
  208. if GLCamera1.DepthOfView < 2000 then
  209. begin
  210. GLCamera1.DepthOfView := GLCamera1.DepthOfView * 1.2;
  211. with GLSceneViewer1.Buffer.FogEnvironment do
  212. begin
  213. FogEnd := FogEnd * 1.2;
  214. FogStart := FogStart * 1.2;
  215. end;
  216. end;
  217. '-':
  218. if GLCamera1.DepthOfView > 300 then
  219. begin
  220. GLCamera1.DepthOfView := GLCamera1.DepthOfView / 1.2;
  221. with GLSceneViewer1.Buffer.FogEnvironment do
  222. begin
  223. FogEnd := FogEnd / 1.2;
  224. FogStart := FogStart / 1.2;
  225. end;
  226. end;
  227. '*':
  228. with TerrainRenderer1 do
  229. if CLODPrecision > 10 then
  230. CLODPrecision := Round(CLODPrecision * 0.8);
  231. '/':
  232. with TerrainRenderer1 do
  233. if CLODPrecision < 1000 then
  234. CLODPrecision := Round(CLODPrecision * 1.2);
  235. 'l':
  236. with GLLensFlare do
  237. Visible := (not Visible) and SPSun.Visible;
  238. end;
  239. Key := #0;
  240. end;
  241. procedure TFormShadedTerrain.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  242. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  243. begin
  244. if GLSceneViewer1.Focused then
  245. GLCamera1.AdjustDistanceToTarget(Power(1.02, WheelDelta / 120));
  246. end;
  247. procedure TFormShadedTerrain.GLSceneViewer1BeforeRender(Sender: TObject);
  248. var
  249. TexUnits: Cardinal;
  250. begin
  251. if GLTexCombineShader1.Enabled then
  252. begin
  253. GLSceneViewer1.Buffer.RenderingContext.Activate;
  254. TexUnits := GLSceneViewer1.Buffer.LimitOf[limNbTextureUnits];
  255. GLSceneViewer1.Buffer.RenderingContext.Deactivate;
  256. if TexUnits < 4 then
  257. begin
  258. Application.MessageBox
  259. ('Not enough texture units! The shader will be disabled.',
  260. 'Error', MB_OK);
  261. GLTexCombineShader1.Enabled := False;
  262. end;
  263. end;
  264. GLLensFlare.PreRender(Sender as TGLSceneBuffer);
  265. end;
  266. procedure TFormShadedTerrain.TBSubSamplingChange(Sender: TObject);
  267. begin
  268. GLBumpmapHDS1.SubSampling := (1 shl TBSubSampling.Position);
  269. LASubFactor.Caption := Format('(%d) -> %dx%1:d', [GLBumpmapHDS1.SubSampling,
  270. TerrainRenderer1.TileSize div GLBumpmapHDS1.SubSampling]);
  271. // don't leave the focus to the trackbar, otherwise it'll keep some keystrokes
  272. // for itself, like the arrow keys
  273. SetFocus;
  274. end;
  275. procedure TFormShadedTerrain.TBIntensityChange(Sender: TObject);
  276. var
  277. i: Integer;
  278. bmp: TBitmap;
  279. begin
  280. with GLMaterialLibrary1.LibMaterialByName('contrast').Material do
  281. begin
  282. bmp := TBitmap.Create;
  283. try
  284. bmp.PixelFormat := pf24bit;
  285. bmp.Width := 1;
  286. bmp.Height := 1;
  287. i := 255;
  288. bmp.Canvas.Pixels[0, 0] := RGB(i, i, i);
  289. Texture.Image.Assign(bmp);
  290. finally
  291. bmp.Free;
  292. end;
  293. i := (TBIntensity.Position * 255) div 100;
  294. Texture.EnvColor.AsWinColor := RGB(i, i, i);
  295. end;
  296. LABumpIntensity.Caption := IntToStr(TBIntensity.Position) + ' %';
  297. end;
  298. procedure TFormShadedTerrain.TBContourIntervalChange(Sender: TObject);
  299. begin
  300. TerrainRenderer1.ContourInterval := TBContourInterval.Position;
  301. LabelContInterval.Caption := IntToStr(TerrainRenderer1.ContourInterval);
  302. end;
  303. procedure TFormShadedTerrain.TBScaleZChange(Sender: TObject);
  304. begin
  305. TerrainRenderer1.Scale.Z := TBScaleZ.Position / 20;
  306. LabelZ.Caption := FloatToStrF(TerrainRenderer1.Scale.Z, ffFixed, 5, 2);
  307. end;
  308. procedure TFormShadedTerrain.CBContourIntervalsClick(Sender: TObject);
  309. begin
  310. if CBContourIntervals.Checked = True then
  311. TerrainRenderer1.ContourInterval := TBContourInterval.Position
  312. else
  313. TerrainRenderer1.ContourInterval := 0;
  314. TBContourinterval.SetFocus;
  315. end;
  316. end.