UnitMain.pas 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. unit UnitMain;
  2. interface
  3. uses
  4. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  5. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  6. GR32,
  7. GR32_Transforms,
  8. GR32_Rasterizers,
  9. GR32_Image;
  10. const
  11. MSG_AFTER_SHOW = WM_USER;
  12. MSG_AFTER_RESIZE = WM_USER+1;
  13. type
  14. TFormMain = class(TForm)
  15. PaintBox32: TPaintBox32;
  16. TimerRotate: TTimer;
  17. procedure FormResize(Sender: TObject);
  18. procedure PaintBox32PaintBuffer(Sender: TObject);
  19. procedure FormShow(Sender: TObject);
  20. procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  21. procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  22. procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  23. procedure TimerRotateTimer(Sender: TObject);
  24. procedure PaintBox32DblClick(Sender: TObject);
  25. procedure PaintBox32MouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  26. var Handled: Boolean);
  27. private
  28. FBitmap: TBitmap32;
  29. FTransformation: TSphereTransformation;
  30. FRasterizer: TRasterizer;
  31. FDraftRasterizer: TRasterizer;
  32. FCurrentRasterizer: TRasterizer;
  33. FLastMousePos: TPoint;
  34. procedure MsgAfterShow(var Msg: TMessage); message MSG_AFTER_SHOW;
  35. procedure MsgAfterResize(var Msg: TMessage); message MSG_AFTER_RESIZE;
  36. public
  37. constructor Create(AOwner: TComponent); override;
  38. destructor Destroy; override;
  39. end;
  40. var
  41. FormMain: TFormMain;
  42. //------------------------------------------------------------------------------
  43. //------------------------------------------------------------------------------
  44. //------------------------------------------------------------------------------
  45. implementation
  46. {$R *.dfm}
  47. {$if defined(DCC) and (CompilerVersion >= 26.0)} // XE5 and later?
  48. {-$define USE_GEOLOCATION}
  49. {$ifend}
  50. uses
  51. System.Math,
  52. System.Diagnostics,
  53. {$ifdef USE_GEOLOCATION}
  54. System.Sensors,
  55. {$endif}
  56. GR32_Backends_Generic,
  57. GR32.ImageFormats.JPG,
  58. GR32.Examples;
  59. //------------------------------------------------------------------------------
  60. constructor TFormMain.Create(AOwner: TComponent);
  61. begin
  62. inherited;
  63. FBitmap := TBitmap32.Create(TMemoryBackend);
  64. FBitmap.ResamplerClassName := 'TLinearResampler';
  65. FBitmap.Resampler.PixelAccessMode := pamTransparentEdge;
  66. FTransformation := TSphereTransformation.Create;
  67. FRasterizer := TMultithreadedRegularRasterizer.Create;
  68. FDraftRasterizer := TDraftRasterizer.Create;
  69. FCurrentRasterizer := FRasterizer;
  70. PaintBox32.Visible := False;
  71. end;
  72. destructor TFormMain.Destroy;
  73. begin
  74. FBitmap.Free;
  75. FTransformation.Free;
  76. FRasterizer.Free;
  77. FDraftRasterizer.Free;
  78. inherited;
  79. end;
  80. //------------------------------------------------------------------------------
  81. procedure TFormMain.FormResize(Sender: TObject);
  82. begin
  83. PostMessage(Handle, MSG_AFTER_RESIZE, 0, 0);
  84. end;
  85. procedure TFormMain.FormShow(Sender: TObject);
  86. begin
  87. // Loading the source image can take a while so defer it until the form has actually been shown
  88. PostMessage(Handle, MSG_AFTER_SHOW, 0, 0);
  89. end;
  90. //------------------------------------------------------------------------------
  91. procedure TFormMain.MsgAfterResize(var Msg: TMessage);
  92. begin
  93. FTransformation.Radius := Min(PaintBox32.Width, PaintBox32.Height) / 2;
  94. FTransformation.Center := FloatPoint(PaintBox32.Width / 2, PaintBox32.Height / 2);
  95. end;
  96. procedure TFormMain.MsgAfterShow(var Msg: TMessage);
  97. {$ifdef USE_GEOLOCATION}
  98. var
  99. SensorManager: TSensorManager;
  100. Sensors: TSensorArray;
  101. Sensor: TCustomSensor;
  102. WasStarted: boolean;
  103. {$endif}
  104. var
  105. s: string;
  106. Size: TSize;
  107. begin
  108. Screen.Cursor := crAppStart;
  109. PaintBox32.Buffer.Clear(clBlack32);
  110. PaintBox32.Visible := True;
  111. s := 'Loading - Please wait...';
  112. Size := PaintBox32.Buffer.TextExtent(s);
  113. PaintBox32.Buffer.RenderText((PaintBox32.Width-Size.cx) div 2, (PaintBox32.Height-Size.cy) div 2, s, -1, clRed32);
  114. PaintBox32.Flush;
  115. FBitmap.LoadFromFile(Graphics32Examples.MediaFolder + '\Globe.jpg');
  116. FTransformation.SrcRect := MakeRect(FBitmap.BoundsRect);
  117. Screen.Cursor := crDefault;
  118. // Start with some random location, a bit more interesting than the Pacific Ocean
  119. FTransformation.Longitude := 55.29952826015878 / 90 * PI*2; // TODO : Something wrong here
  120. FTransformation.Lattitude := -12.052785473578014 / 90 * PI*2;
  121. {$ifdef USE_GEOLOCATION}
  122. // Try to get current location. Unfortunately this doesn't seem to work without
  123. // an actual location device although Windows is able to provide a user-specified
  124. // default location.
  125. SensorManager := TSensorManager.Current;
  126. SensorManager.Activate;
  127. Sensors := SensorManager.GetSensorsByCategory(TSensorCategory.Location);
  128. for Sensor in Sensors do
  129. begin
  130. WasStarted := Sensor.Started;
  131. if (not WasStarted) then
  132. Sensor.Start;
  133. if (not Sensor.Started) then
  134. continue;
  135. FTransformation.Longitude := TCustomLocationSensor(Sensor).Longitude / 180 * PI;
  136. FTransformation.Lattitude := TCustomLocationSensor(Sensor).Latitude / 90 * PI*2;
  137. if (not WasStarted) then
  138. Sensor.Stop;
  139. break;
  140. end;
  141. {$endif}
  142. end;
  143. //------------------------------------------------------------------------------
  144. procedure TFormMain.PaintBox32DblClick(Sender: TObject);
  145. begin
  146. TimerRotate.Enabled := not TimerRotate.Enabled;
  147. end;
  148. procedure TFormMain.PaintBox32MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  149. begin
  150. if (FBitmap = nil) or (FBitmap.Empty) then
  151. Exit;
  152. if ([ssLeft, ssRight] * Shift = []) then
  153. Exit;
  154. // Store current mouse position and switch to the draft rasterizer
  155. FLastMousePos := Point(X, Y);
  156. FCurrentRasterizer := FDraftRasterizer;
  157. end;
  158. procedure TFormMain.PaintBox32MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  159. var
  160. DeltaX, DeltaY: Integer;
  161. begin
  162. if (FBitmap = nil) or (FBitmap.Empty) then
  163. Exit;
  164. if ([ssLeft, ssRight] * Shift = []) then
  165. Exit;
  166. TimerRotate.Enabled := False;
  167. DeltaX := X - FLastMousePos.X;
  168. DeltaY := Y - FLastMousePos.Y;
  169. if (Abs(DeltaX) <= 5) and (Abs(DeltaY) <= 5) then
  170. Exit;
  171. FLastMousePos := Point(X, Y);
  172. if (ssLeft in Shift) then
  173. begin
  174. // Rotate
  175. FTransformation.Longitude := FTransformation.Longitude - (DeltaX / FTransformation.Radius) * (PI / 2);
  176. FTransformation.Lattitude := FTransformation.Lattitude - (DeltaY / FTransformation.Radius) * (PI / 2);
  177. end else
  178. if (ssRight in Shift) then
  179. // Pan
  180. FTransformation.Center := FloatPoint(FTransformation.Center.X + DeltaX, FTransformation.Center.Y + DeltaY);
  181. PaintBox32.Invalidate;
  182. end;
  183. procedure TFormMain.PaintBox32MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  184. begin
  185. if (FBitmap = nil) or (FBitmap.Empty) then
  186. Exit;
  187. FCurrentRasterizer := FRasterizer;
  188. PaintBox32.Invalidate;
  189. end;
  190. procedure TFormMain.PaintBox32MouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  191. var Handled: Boolean);
  192. begin
  193. // Zoom
  194. FTransformation.Radius := FTransformation.Radius + 50 * WheelDelta / 120;
  195. PaintBox32.Invalidate;
  196. Handled := True;
  197. end;
  198. //------------------------------------------------------------------------------
  199. procedure TFormMain.PaintBox32PaintBuffer(Sender: TObject);
  200. var
  201. StopWatch: TStopWatch;
  202. begin
  203. PaintBox32.Buffer.Clear(clBlack32);
  204. StopWatch := TStopWatch.StartNew;
  205. if (FBitmap <> nil) and (not FBitmap.Empty) then
  206. Transform(PaintBox32.Buffer, FBitmap, FTransformation, FCurrentRasterizer);
  207. StopWatch.Stop;
  208. PaintBox32.Buffer.RenderText(0, 0, Format('Rasterized in %d mS', [StopWatch.ElapsedMilliseconds]), -1, clWhite32);
  209. // While manually panning or rotating, adjust the pixel size so we are able to maintain
  210. // a frame rate between 25-50 fps
  211. if (FCurrentRasterizer = FDraftRasterizer) then
  212. begin
  213. if (StopWatch.ElapsedMilliseconds < 20) then
  214. TDraftRasterizer(FDraftRasterizer).PixelSize := TDraftRasterizer(FDraftRasterizer).PixelSize - 1
  215. else
  216. if (StopWatch.ElapsedMilliseconds > 40) then
  217. TDraftRasterizer(FDraftRasterizer).PixelSize := TDraftRasterizer(FDraftRasterizer).PixelSize + 1;
  218. PaintBox32.Buffer.RenderText(0, 20, Format('Pixel size: %d', [TDraftRasterizer(FDraftRasterizer).PixelSize]), -1, clWhite32);
  219. end;
  220. end;
  221. //------------------------------------------------------------------------------
  222. procedure TFormMain.TimerRotateTimer(Sender: TObject);
  223. begin
  224. FTransformation.Longitude := FTransformation.Longitude - 0.001;
  225. PaintBox32.Invalidate;
  226. end;
  227. //------------------------------------------------------------------------------
  228. end.