OpenGLDemo.dpr 11 KB

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