OpenGLDemo.dpr 12 KB

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