DemoUnit.pas 12 KB

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