DemoUnit.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. {
  2. Vampyre Imaging Library Demo
  3. D3D9 Demo (D3D9 extension)
  4. Demo that shows how to create Direct3D 9 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 rendered in each corner of the window
  8. using various texture stage and blending settings.
  9. You can change sprite's texture format by pressing SPACE key
  10. (it cycles trough all TImageFormat values). Background texture
  11. can be saved to file by pressing S key and sprite texture
  12. can be saved by pressing D key.
  13. }
  14. unit DemoUnit;
  15. {$I ImagingOptions.inc}
  16. {$R ..\Common\MainIcon.res}
  17. interface
  18. procedure RunDemo;
  19. implementation
  20. uses
  21. Windows,
  22. SysUtils,
  23. ImagingTypes,
  24. Imaging,
  25. ImagingUtility,
  26. sdl,
  27. Direct3D9,
  28. ImagingDirect3D9,
  29. ImagingSdl,
  30. DemoUtils;
  31. type
  32. TVector2 = record
  33. X, Y: Single;
  34. end;
  35. TVector4 = record
  36. X, Y, Z, W: Single;
  37. end;
  38. TVertex = record
  39. Position: TVector4;
  40. TexCoord1: TVector2;
  41. TexCoord2: TVector2;
  42. end;
  43. TRect = array[0..3] of TVertex;
  44. const
  45. SWindowTitle = 'Vampyre Imaging Library (%s) - Direct3D9 Demo (format: %s)';
  46. SWindowIconTitle = 'Direct3D9 Demo';
  47. SBackImageFile = 'Tigers.jpg';
  48. SSpriteImageFile = 'Vezyr.png';
  49. SOutScreenFile = 'D3DScreen.png';
  50. SOutSpriteFile = 'D3DSprite.dds';
  51. SIconFile = 'Icon.png';
  52. DisplayWidth = 800;
  53. DisplayHeight = 600;
  54. SpriteWidth = 256.0;
  55. SpriteHeight = 192.0;
  56. FVF_VERTEX = D3DFVF_XYZRHW or D3DFVF_TEX2;
  57. var
  58. WindowHandle: THandle;
  59. Direct3D: IDirect3D9 = nil;
  60. Device: IDirect3DDevice9 = nil;
  61. BackTex: IDirect3DTexture9 = nil;
  62. SpriteTex: IDirect3DTexture9 = nil;
  63. PresentParams: TD3DPresentParameters;
  64. DisplaySurface: PSDL_Surface = nil;
  65. SpriteImage: TImageData;
  66. SpriteFormat: TImageFormat = ifA8R8G8B8;
  67. BackRect: TRect;
  68. Rects: array[0..3] of TRect;
  69. Event : TSDL_Event;
  70. Running: Boolean = True;
  71. Frames: LongInt = 0;
  72. FPS: LongInt = 0;
  73. LastTime: LongInt = 0;
  74. TextureCaps: TD3DTextureCaps;
  75. function Vector2(X, Y: Single): TVector2;
  76. begin
  77. Result.X := X;
  78. Result.Y := Y;
  79. end;
  80. function Vector4(X, Y, Z, W: Single): TVector4;
  81. begin
  82. Result.X := X;
  83. Result.Y := Y;
  84. Result.Z := Z;
  85. Result.W := W;
  86. end;
  87. procedure PlaceRect(Index: LongInt; X, Y: Single);
  88. begin
  89. Rects[Index, 0].Position.X := X;
  90. Rects[Index, 0].Position.Y := Y;
  91. Rects[Index, 1].Position.X := X + SpriteWidth;
  92. Rects[Index, 1].Position.Y := Y;
  93. Rects[Index, 2].Position.X := X;
  94. Rects[Index, 2].Position.Y := Y + SpriteHeight;
  95. Rects[Index, 3].Position.X := X + SpriteWidth;
  96. Rects[Index, 3].Position.Y := Y + SpriteHeight;
  97. end;
  98. procedure MessageOut(Window: THandle; const Msg: string; const Args: array of const);
  99. begin
  100. MessageBox(Window, PChar(Format(Msg, Args)), 'Message',
  101. MB_ICONINFORMATION or MB_OK);
  102. end;
  103. procedure MessageOutAndHalt(Window: THandle; const Msg: string; const Args: array of const);
  104. begin
  105. MessageBox(Window, PChar(Format(Msg, Args)), 'Error',
  106. MB_ICONERROR or MB_OK);
  107. SDL_Quit;
  108. Halt(1);
  109. end;
  110. procedure UpdateCaption;
  111. begin
  112. SDL_WM_SetCaption(PAnsiChar(AnsiString(Format(SWindowTitle + ' FPS: %d',
  113. [Imaging.GetVersionStr, GetFormatName(SpriteFormat), FPS]))),
  114. SWindowIconTitle);
  115. end;
  116. procedure CreateSpriteTexture(const Device: IDirect3DDevice9; Format: TImageFormat);
  117. var
  118. D3DFormat: TD3DFormat;
  119. ConvTo: TImageFormat;
  120. ConvImage: TImageData;
  121. begin
  122. // Find D3D format that matches given TImageFormat
  123. D3DFormat := ImagingDirect3D9.ImageFormatToD3DFormat(Format, ConvTo);
  124. if D3DFormat <> D3DFMT_UNKNOWN then
  125. begin
  126. // Free old texture and create new one in the different format
  127. SpriteTex := nil;
  128. Imaging.InitImage(ConvImage);
  129. Imaging.CloneImage(SpriteImage, ConvImage);
  130. // Create texture from image
  131. ImagingDirect3D9.CreateD3DTextureFromImage(ConvImage, Device, SpriteTex,
  132. SpriteImage.Width, SpriteImage.Height, 0, 0, D3DFormat, D3DPOOL_MANAGED);
  133. Imaging.FreeImage(ConvImage);
  134. end;
  135. end;
  136. procedure Initialize;
  137. var
  138. Caption, Icon: PAnsiChar;
  139. Mode: TD3DDisplayMode;
  140. I: LongInt;
  141. begin
  142. // Get SDL app window
  143. SDL_WM_GetCaption(Caption, Icon);
  144. WindowHandle := FindWindowA('SDL_app', Caption);
  145. if WindowHandle = 0 then
  146. MessageOutAndHalt(GetActiveWindow, 'Cannot get SDL window handle', []);
  147. // Place window to the center of the screen
  148. SetWindowPos(WindowHandle, 0, (GetSystemMetrics(SM_CXSCREEN) - DisplayWidth) div 2,
  149. (GetSystemMetrics(SM_CYSCREEN) - DisplayHeight - 20) div 2, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
  150. // Create IDirect3D interface
  151. Direct3D := Direct3DCreate9(D3D_SDK_VERSION);
  152. if Direct3D = nil then
  153. MessageOutAndHalt(WindowHandle, 'Cannot create Direct3D interface', []);
  154. // Get the current display mode and fill presentation parameters
  155. Direct3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, Mode);
  156. FillChar(PresentParams, SizeOf(PresentParams), 0);
  157. PresentParams.hDeviceWindow := WindowHandle;
  158. PresentParams.Windowed := True;
  159. PresentParams.BackBufferCount := 1;
  160. PresentParams.BackBufferFormat := Mode.Format;
  161. PresentParams.SwapEffect := D3DSWAPEFFECT_DISCARD;
  162. PresentParams.PresentationInterval := D3DPRESENT_INTERVAL_IMMEDIATE;
  163. // Create Direct3D device
  164. if Failed(Direct3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, PresentParams.hDeviceWindow,
  165. D3DCREATE_SOFTWARE_VERTEXPROCESSING, @PresentParams, Device)) then
  166. MessageOutAndHalt(WindowHandle, 'Cannot create Direct3D device', []);
  167. // Get texture caps
  168. ImagingDirect3D9.GetDeviceTextureCaps(Device, TextureCaps);
  169. // Load background texture from file
  170. ImagingDirect3D9.LoadD3DTextureFromFile(GetDataDir + PathDelim + SBackImageFile, Device, BackTex);
  171. Imaging.InitImage(SpriteImage);
  172. // Load sprite image from file
  173. Imaging.LoadImageFromFile(GetDataDir + PathDelim + SSpriteImageFile, SpriteImage);
  174. // Create sprite texture from image
  175. CreateSpriteTexture(Device, SpriteFormat);
  176. // Set render states
  177. Device.SetRenderState(D3DRS_LIGHTING, 0);
  178. Device.SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
  179. Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  180. Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  181. // Set texture stage states
  182. Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  183. Device.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  184. Device.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  185. Device.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  186. Device.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  187. Device.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  188. Device.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  189. Device.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
  190. Device.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  191. Device.SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
  192. Device.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  193. Device.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  194. Device.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
  195. // Set size of the background
  196. BackRect[0].Position := Vector4(0.0, 0.0, 0.0, 1.0);
  197. BackRect[1].Position := Vector4(DisplayWidth, 0.0, 0.0, 1.0);
  198. BackRect[2].Position := Vector4(0.0, DisplayHeight, 0.0, 1.0);
  199. BackRect[3].Position := Vector4(DisplayWidth, DisplayHeight, 0.0, 1.0);
  200. // Set background's tex coords
  201. BackRect[0].TexCoord1 := Vector2(0.0, 0.0);
  202. BackRect[1].TexCoord1 := Vector2(1.0, 0.0);
  203. BackRect[2].TexCoord1 := Vector2(0.0, 1.0);
  204. BackRect[3].TexCoord1 := Vector2(1.0, 1.0);
  205. // Set sprites' tex coords and default position
  206. for I := 0 to 3 do
  207. begin
  208. Rects[I, 0].Position := Vector4(0.0, 0.0, 0.0, 1.0);
  209. Rects[I, 1].Position := Vector4(0.0, 0.0, 0.0, 1.0);
  210. Rects[I, 2].Position := Vector4(0.0, 0.0, 0.0, 1.0);
  211. Rects[I, 3].Position := Vector4(0.0, 0.0, 0.0, 1.0);
  212. Rects[I, 0].TexCoord1 := Vector2(0.0, 0.0);
  213. Rects[I, 1].TexCoord1 := Vector2(1.0, 0.0);
  214. Rects[I, 2].TexCoord1 := Vector2(0.0, 1.0);
  215. Rects[I, 3].TexCoord1 := Vector2(1.0, 1.0);
  216. Rects[I, 0].TexCoord2 := Vector2(0.0, 1.0);
  217. Rects[I, 1].TexCoord2 := Vector2(1.0, 1.0);
  218. Rects[I, 2].TexCoord2 := Vector2(0.0, 0.0);
  219. Rects[I, 3].TexCoord2 := Vector2(1.0, 0.0);
  220. end;
  221. // Place sprites
  222. PlaceRect(0, 0, 0);
  223. PlaceRect(1, DisplayWidth - SpriteWidth, 0);
  224. PlaceRect(2, 0, DisplayHeight - SpriteHeight);
  225. PlaceRect(3, DisplayWidth - SpriteWidth, DisplayHeight - SpriteHeight);
  226. end;
  227. procedure Present;
  228. begin
  229. Device.Clear(0, nil, D3DCLEAR_TARGET, $FFCCFFFF, 1.0, 0);
  230. if Succeeded(Device.BeginScene) then
  231. begin
  232. Device.SetFVF(FVF_VERTEX);
  233. // First render background
  234. Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  235. Device.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  236. Device.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  237. Device.SetTexture(0, BackTex);
  238. Device.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, BackRect, SizeOf(TVertex));
  239. Device.SetTexture(0, SpriteTex);
  240. Device.SetTexture(1, SpriteTex);
  241. // Render first sprite
  242. Device.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, Rects[0], SizeOf(TVertex));
  243. // Render second sprite
  244. Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);
  245. Device.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);
  246. Device.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  247. Device.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, Rects[1], SizeOf(TVertex));
  248. // Render third sprite
  249. Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
  250. Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
  251. Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  252. Device.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  253. Device.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SUBTRACT);
  254. Device.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  255. Device.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, Rects[2], SizeOf(TVertex));
  256. Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  257. Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  258. // Render last sprite
  259. Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
  260. Device.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
  261. Device.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, Rects[3], SizeOf(TVertex));
  262. Device.SetTexture(0, nil);
  263. Device.SetTexture(1, nil);
  264. Device.EndScene;
  265. end;
  266. // Copy backbuffer to window
  267. Device.Present(nil, nil, 0, nil);
  268. end;
  269. procedure Finalize;
  270. begin
  271. BackTex := nil;
  272. SpriteTex := nil;
  273. Device := nil;
  274. Direct3D := nil;
  275. Imaging.FreeImage(SpriteImage);
  276. end;
  277. procedure TakeScreenShot;
  278. var
  279. RenderTarget, OldRenderTarget: IDirect3DSurface9;
  280. ScreenImg: TImageData;
  281. begin
  282. // Create new render target and activate it
  283. Device.CreateRenderTarget(DisplayWidth, DisplayHeight, D3DFMT_A8R8G8B8,
  284. D3DMULTISAMPLE_NONE, 0, True, RenderTarget, nil);
  285. Device.GetRenderTarget(0, OldRenderTarget);
  286. Device.SetRenderTarget(0, RenderTarget);
  287. // Render to new target
  288. Present;
  289. // Activate old target
  290. Device.SetRenderTarget(0, OldRenderTarget);
  291. // Convert reder target surface to Imaging image and save it to file
  292. ImagingDirect3D9.CreateImageFromD3DSurface(RenderTarget, ScreenImg);
  293. Imaging.SaveImageToFile(SOutScreenFile, ScreenImg);
  294. // Free all
  295. Imaging.FreeImage(ScreenImg);
  296. RenderTarget := nil;
  297. OldRenderTarget := nil;
  298. end;
  299. procedure RunDemo;
  300. begin
  301. // Initialize SDL
  302. if (SDL_Init(SDL_INIT_VIDEO) < 0) then
  303. MessageOutAndHalt(GetActiveWindow, 'SDL initialization failed: %s', [SDL_GetError]);
  304. SDL_WM_SetCaption(PAnsiChar(AnsiString(Format(SWindowTitle, [Imaging.GetVersionStr,
  305. GetFormatName(SpriteFormat)]))), SWindowIconTitle);
  306. SDL_WM_SetIcon(LoadSDLSurfaceFromFile(GetDataDir + PathDelim + SIconFile), 0);
  307. // Initialize video mode
  308. DisplaySurface := SDL_SetVideoMode(DisplayWidth, DisplayHeight, 32, 0);
  309. if DisplaySurface = nil then
  310. MessageOutAndHalt(GetActiveWindow, 'SDL SetVideoMode failed: %s', [SDL_GetError]);
  311. // Initialize surfaces and enter main loop
  312. Initialize;
  313. LastTime := SDL_GetTicks;
  314. while Running do
  315. begin
  316. while SDL_PollEvent(@Event) = 1 do
  317. begin
  318. case Event.type_ of
  319. SDL_QUITEV:
  320. begin
  321. Running := False;
  322. end;
  323. SDL_KEYDOWN:
  324. begin
  325. with Event.key.keysym do
  326. if ((sym = SDLK_F4) and ((modifier and KMOD_ALT) <> 0)) or
  327. (Event.key.keysym.sym = SDLK_ESCAPE) then
  328. Running := False;
  329. // Using S and D keys you can take screen shots and texture
  330. // shots easily
  331. // SPACE key can be used to cycle sprite image formats
  332. case Event.key.keysym.sym of
  333. SDLK_S: TakeScreenShot;
  334. SDLK_D: ImagingDirect3D9.SaveD3DTextureToFile(SOutSpriteFile, SpriteTex);
  335. SDLK_SPACE:
  336. begin
  337. SpriteFormat := NextFormat(SpriteFormat);
  338. CreateSpriteTexture(Device, SpriteFormat);
  339. UpdateCaption;
  340. end;
  341. end;
  342. end;
  343. end;
  344. end;
  345. // Calculate FPS
  346. if LongInt(SDL_GetTicks) - LastTime > 1000 then
  347. begin
  348. FPS := Frames;
  349. UpdateCaption;
  350. Frames := 0;
  351. LastTime := SDL_GetTicks;
  352. end;
  353. Inc(Frames);
  354. // Renders background and sprites to the window
  355. Present;
  356. end;
  357. // Frees all textures, images, and D3D objects
  358. Finalize;
  359. SDL_Quit;
  360. end;
  361. {
  362. File Notes:
  363. -- 0.77.1 ---------------------------------------------------
  364. - Refactored the demo (moved stuff to unit from dpr) and
  365. added Lazarus project files.
  366. -- 0.26.1 Changes/Bug Fixes ---------------------------------
  367. - Delphi 2009 compatibility pchar/string changes.
  368. -- 0.17 Changes/Bug Fixes -----------------------------------
  369. - S key now saves screenshot to file
  370. }
  371. end.