DemoUnit.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. {
  2. Vampyre Imaging Library Demo
  3. OpenGL Demo (OpenGL extension)
  4. Demo that shows how to create OpenGL textures from files
  5. and Imaging's images and vice versa. This sample uses SDL to create
  6. window and process messages. Background and sprite textures are loaded from
  7. files and rendered. Sprite is mapped on the spinning cube in the
  8. center of the window. You can change sprite's texture format
  9. by pressing SPACE key (it cycles trough all TImageFormat values).
  10. Background texture can be saved to file by pressing S key and sprite texture
  11. can be saved by pressing D key.
  12. }
  13. unit DemoUnit;
  14. { Define this symbol if you want to use dglOpenGL header.}
  15. {$DEFINE USE_DGL_HEADERS}
  16. { $DEFINE USE_GLSCENE_HEADERS}
  17. {$I ImagingOptions.inc}
  18. {$R ..\Common\MainIcon.res}
  19. interface
  20. procedure RunDemo;
  21. implementation
  22. uses
  23. {$IFDEF MSWINDOWS}
  24. Windows,
  25. {$ENDIF}
  26. SysUtils,
  27. ImagingTypes,
  28. Imaging,
  29. ImagingUtility,
  30. sdl,
  31. {$IF Defined(USE_DGL_HEADERS)}
  32. dglOpenGL,
  33. {$ELSEIF Defined(USE_GLSCENE_HEADERS)}
  34. OpenGL1x,
  35. {$ELSE}
  36. gl, glext,
  37. {$IFEND}
  38. ImagingOpenGL,
  39. ImagingSdl,
  40. DemoUtils;
  41. const
  42. SWindowTitle = 'Vampyre Imaging Library (%s) - OpenGL Demo (format: %s)';
  43. SWindowIconTitle = 'OpenGL Demo';
  44. SBackImageFile = 'Tigers.jng';
  45. SSpriteImageFile = 'Vezyr.png';
  46. SOutScreenFile = 'GLScreen.png';
  47. SOutSpriteFile = 'GLSprite.dds';
  48. SIconFile = 'Icon.png';
  49. DisplayWidth = 800;
  50. DisplayHeight = 600;
  51. CubeSize = 200.0;
  52. var
  53. BackTex: GLuint = 0;
  54. SpriteTex: GLuint = 0;
  55. DisplaySurface: PSDL_Surface = nil;
  56. SpriteImage: TImageData;
  57. SpriteFormat: TImageFormat = ifA8R8G8B8;
  58. Event : TSDL_Event;
  59. Running: Boolean = True;
  60. Frames: LongInt = 0;
  61. FPS, Elapsed: Single;
  62. CurrTime, FrameTime, LastTime: Cardinal;
  63. Angle: Single = 0.0;
  64. TextureCaps: TGLTextureCaps;
  65. {$IFDEF MSWINDOWS}
  66. WindowHandle: THandle;
  67. {$ENDIF}
  68. procedure MessageOut(const Msg: string; const Args: array of const);
  69. begin
  70. {$IFDEF MSWINDOWS}
  71. MessageBox(GetActiveWindow, PChar(Format(Msg, Args)), 'Message',
  72. MB_ICONINFORMATION or MB_OK);
  73. {$ENDIF}
  74. {$IFDEF UNIX}
  75. WriteLn(Format(Msg, Args));
  76. {$ENDIF}
  77. end;
  78. procedure MessageOutAndHalt(const Msg: string; const Args: array of const);
  79. begin
  80. {$IFDEF MSWINDOWS}
  81. MessageBox(GetActiveWindow, PChar(Format(Msg, Args)), 'Error',
  82. MB_ICONERROR or MB_OK);
  83. {$ENDIF}
  84. {$IFDEF UNIX}
  85. WriteLn('Error: ');
  86. MessageOut(' ' + Msg, Args);
  87. WriteLn('Press RETURN to exit');
  88. ReadLn;
  89. {$ENDIF}
  90. SDL_Quit;
  91. Halt(1);
  92. end;
  93. procedure UpdateCaption;
  94. begin
  95. SDL_WM_SetCaption(PAnsiChar(AnsiString(Format(SWindowTitle + ' FPS: %.1f',
  96. [Imaging.GetVersionStr, GetFormatName(SpriteFormat), FPS]))), SWindowIconTitle);
  97. end;
  98. procedure CreateSpriteTexture(Format: TImageFormat);
  99. var
  100. Info: TImageFormatInfo;
  101. begin
  102. // Delete old texture and create new one in the different format
  103. glDeleteTextures(1, @SpriteTex);
  104. SpriteTex := ImagingOpenGL.CreateGLTextureFromImage(SpriteImage,
  105. 256, 256, True, SpriteFormat);
  106. if SpriteTex = 0 then
  107. MessageOut('Sprite texture creation failed.', []);
  108. // Set tex parameters
  109. glBindTexture(GL_TEXTURE_2D, SpriteTex);
  110. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  111. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  112. if TextureCaps.MaxAnisotropy > 0 then
  113. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, TextureCaps.MaxAnisotropy);
  114. if Imaging.GetImageFormatInfo(SpriteFormat, Info) then
  115. begin
  116. if Info.IsFloatingPoint and (Info.BytesPerPixel in [4, 16]) then
  117. begin
  118. // Floating point textures (not half float though) should use nearest
  119. // filter on current hardware. I get 900 fps with nearest filter
  120. // and only 2 fps with linear filter
  121. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  122. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
  123. end
  124. else
  125. begin
  126. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  127. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  128. end;
  129. end;
  130. end;
  131. procedure Initialize;
  132. {$IFDEF MSWINDOWS}
  133. var
  134. Caption, Icon: PAnsiChar;
  135. {$ENDIF}
  136. begin
  137. {$IFDEF MSWINDOWS}
  138. SDL_WM_GetCaption(Caption, Icon);
  139. WindowHandle := FindWindowA('SDL_app', Caption);
  140. if WindowHandle <> 0 then
  141. begin
  142. // Place window to the center of the screen
  143. SetWindowPos(WindowHandle, 0, (GetSystemMetrics(SM_CXSCREEN) - DisplayWidth) div 2,
  144. (GetSystemMetrics(SM_CYSCREEN) - DisplayHeight - 20) div 2, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
  145. end;
  146. {$ENDIF}
  147. {$IFDEF USE_DGL_HEADERS}
  148. dglOpenGL.InitOpenGL;
  149. dglOpenGL.ReadExtensions;
  150. dglOpenGL.ReadImplementationProperties;
  151. {$ENDIF}
  152. ImagingOpenGL.GetGLTextureCaps(TextureCaps);
  153. // Disable some GL states
  154. glDisable(GL_LIGHTING);
  155. // Enable some GL states
  156. glEnable(GL_BLEND);
  157. glEnable(GL_TEXTURE_2D);
  158. // Prepare for alpha blending
  159. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  160. // Set projections and model view transformations
  161. glViewport(0, 0, DisplayWidth, DisplayHeight);
  162. glMatrixMode(GL_PROJECTION);
  163. glLoadIdentity;
  164. glOrtho(0, DisplayWidth, DisplayHeight, 0, -1000.0, 1000.0);
  165. // Load background texture from file
  166. BackTex := ImagingOpenGL.LoadGLTextureFromFile(GetDataDir + PathDelim + SBackImageFile);
  167. // Set tex parameters
  168. glBindTexture(GL_TEXTURE_2D, BackTex);
  169. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  170. Imaging.InitImage(SpriteImage);
  171. // Load sprite image from file
  172. Imaging.LoadImageFromFile(GetDataDir + PathDelim + SSpriteImageFile, SpriteImage);
  173. // Create sprite texture from image
  174. CreateSpriteTexture(SpriteFormat);
  175. end;
  176. procedure Present;
  177. begin
  178. // Clear depth and color buffers
  179. glClearColor(0.0, 0.8, 1.0, 1.0);
  180. glClearDepth(1.0);
  181. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  182. glMatrixMode(GL_MODELVIEW);
  183. glLoadIdentity;
  184. // First draw background
  185. glBindTexture(GL_TEXTURE_2D, BackTex);
  186. glDisable(GL_DEPTH_TEST);
  187. glBegin(GL_QUADS);
  188. glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
  189. glTexCoord2f(1.0, 0.0); glVertex2f(DisplayWidth, 0.0);
  190. glTexCoord2f(1.0, 1.0); glVertex2f(DisplayWidth, DisplayHeight);
  191. glTexCoord2f(0.0, 1.0); glVertex2f(0.0, DisplayHeight);
  192. glEnd;
  193. // Then draw the spinning cube
  194. glEnable(GL_DEPTH_TEST);
  195. glTranslatef(DisplayWidth / 2.0, DisplayHeight / 2.0, 0.0);
  196. glRotatef(-30.0, 1.0, 0.0, 0.0);
  197. glRotatef(Angle, 0.0, 1.0, 0.0);
  198. glTranslatef(-CubeSize / 2.0, -CubeSize / 2.0, -CubeSize / 2.0);
  199. glBindTexture(GL_TEXTURE_2D, SpriteTex);
  200. glBegin(GL_QUADS);
  201. glTexCoord2f(1.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
  202. glTexCoord2f(0.0, 0.0); glVertex3f(CubeSize, 0.0, 0.0);
  203. glTexCoord2f(0.0, 1.0); glVertex3f(CubeSize, CubeSize, 0.0);
  204. glTexCoord2f(1.0, 1.0); glVertex3f(0.0, CubeSize, 0.0);
  205. glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, CubeSize);
  206. glTexCoord2f(1.0, 0.0); glVertex3f(CubeSize, 0.0, CubeSize);
  207. glTexCoord2f(1.0, 1.0); glVertex3f(CubeSize, CubeSize, CubeSize);
  208. glTexCoord2f(0.0, 1.0); glVertex3f(0.0, CubeSize, CubeSize);
  209. glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
  210. glTexCoord2f(0.0, 1.0); glVertex3f(0.0, CubeSize, 0.0);
  211. glTexCoord2f(1.0, 1.0); glVertex3f(0.0, CubeSize, CubeSize);
  212. glTexCoord2f(1.0, 0.0); glVertex3f(0.0, 0.0, CubeSize);
  213. glTexCoord2f(1.0, 0.0); glVertex3f(CubeSize, 0.0, 0.0);
  214. glTexCoord2f(1.0, 1.0); glVertex3f(CubeSize, CubeSize, 0.0);
  215. glTexCoord2f(0.0, 1.0); glVertex3f(CubeSize, CubeSize, CubeSize);
  216. glTexCoord2f(0.0, 0.0); glVertex3f(CubeSize, 0.0, CubeSize);
  217. glEnd;
  218. Angle := Angle + 50 * Elapsed;
  219. SDL_GL_SwapBuffers;
  220. end;
  221. procedure Finalize;
  222. begin
  223. // Free textures and images
  224. glDeleteTextures(1, @BackTex);
  225. glDeleteTextures(1, @SpriteTex);
  226. Imaging.FreeImage(SpriteImage);
  227. end;
  228. procedure TakeScreenShot;
  229. var
  230. RenderTarget: Gluint;
  231. begin
  232. // Setup render target texture
  233. glGenTextures(1, @RenderTarget);
  234. glBindTexture(GL_TEXTURE_2D, RenderTarget);
  235. glTexImage2D(GL_TEXTURE_2D, 0, 3, DisplayWidth, DisplayHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, nil);
  236. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  237. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  238. // Render all
  239. Present;
  240. // Copy framebuffer to texture
  241. glBindTexture(GL_TEXTURE_2D, RenderTarget);
  242. glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, DisplayWidth, DisplayHeight, 0);
  243. // Save texture & delete it
  244. ImagingOpenGL.SaveGLTextureToFile(SOutScreenFile, RenderTarget);
  245. glDeleteTextures(1, @RenderTarget);
  246. end;
  247. procedure RunDemo;
  248. begin
  249. // Initialize SDL
  250. if (SDL_Init(SDL_INIT_VIDEO) < 0) then
  251. MessageOutAndHalt('SDL initialization failed: %s', [SDL_GetError]);
  252. SDL_WM_SetCaption(PAnsiChar(AnsiString(Format(SWindowTitle, [Imaging.GetVersionStr,
  253. GetFormatName(SpriteFormat)]))), SWindowIconTitle);
  254. SDL_WM_SetIcon(LoadSDLSurfaceFromFile(GetDataDir + PathDelim + SIconFile), 0);
  255. // Set GL attributes using SDL
  256. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  257. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  258. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  259. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
  260. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
  261. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  262. // Initialize video mode
  263. DisplaySurface := SDL_SetVideoMode(DisplayWidth, DisplayHeight, 32, SDL_OPENGL);
  264. if DisplaySurface = nil then
  265. MessageOutAndHalt('SDL SetVideoMode failed: %s', [SDL_GetError]);
  266. // Initialize surfaces and enter main loop
  267. Initialize;
  268. LastTime := SDL_GetTicks;
  269. FrameTime := LastTime;
  270. while Running do
  271. begin
  272. while SDL_PollEvent(@Event) = 1 do
  273. begin
  274. case Event.type_ of
  275. SDL_QUITEV:
  276. begin
  277. Running := False;
  278. end;
  279. SDL_KEYDOWN:
  280. begin
  281. with Event.key.keysym do
  282. if ((sym = SDLK_F4) and ((modifier and KMOD_ALT) <> 0)) or
  283. (Event.key.keysym.sym = SDLK_ESCAPE) then
  284. Running := False;
  285. // Using S and D keys you can take screen shots and texture
  286. // shots easily
  287. // SPACE key can be used to cycle sprite image formats
  288. case Event.key.keysym.sym of
  289. SDLK_S: TakeScreenShot;
  290. SDLK_D: ImagingOpenGL.SaveGLTextureToFile(SOutSpriteFile, SpriteTex);
  291. SDLK_SPACE:
  292. begin
  293. SpriteFormat := NextFormat(SpriteFormat);
  294. CreateSpriteTexture(SpriteFormat);
  295. UpdateCaption;
  296. end;
  297. end;
  298. end;
  299. end;
  300. end;
  301. CurrTime := SDL_GetTicks;
  302. Elapsed := (CurrTime - LastTime) / 1000;
  303. LastTime := CurrTime;
  304. Inc(Frames);
  305. // Calculate FPS
  306. if CurrTime - FrameTime > 1000 then
  307. begin
  308. FPS := Frames / (CurrTime - FrameTime) * 1000;
  309. UpdateCaption;
  310. Frames := 0;
  311. FrameTime := CurrTime;
  312. end;
  313. // Renders background and sprites to the window
  314. Present;
  315. end;
  316. // Frees everything
  317. Finalize;
  318. SDL_Quit;
  319. end;
  320. {
  321. File Notes:
  322. -- 0.77.1 ---------------------------------------------------
  323. - Refactored the demo (moved stuff to unit from dpr) and
  324. added Lazarus project files.
  325. -- 0.26.1 Changes/Bug Fixes ---------------------------------
  326. - Added support for GLScene's OpenGL header.
  327. - Delphi 2009 compatibility pchar/string changes.
  328. -- 0.25.0 Changes/Bug Fixes ---------------------------------
  329. - Changes in timing.
  330. - Can use dglOpenGL headers now.
  331. -- 0.19 Changes/Bug Fixes -----------------------------------
  332. - screenshots now work in all OSs and ImagingComponents is no longer needed
  333. -- 0.17 Changes/Bug Fixes -----------------------------------
  334. - S key now saves screenshot to file
  335. - anisotropic filtering enabled if supported by hardware
  336. }
  337. end.