1 #ifdef __REACTOS__ 2 #include "precomp.h" 3 #else 4 /* 5 * Copyright (C) 2008 Tony Wasserka 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 */ 22 23 24 #include "d3dx9_private.h" 25 #endif /* __REACTOS__ */ 26 27 WINE_DEFAULT_DEBUG_CHANNEL(d3dx); 28 29 /* the combination of all possible D3DXSPRITE flags */ 30 #define D3DXSPRITE_FLAGLIMIT 511 31 32 struct sprite_vertex 33 { 34 D3DXVECTOR3 pos; 35 DWORD col; 36 D3DXVECTOR2 tex; 37 }; 38 39 struct sprite 40 { 41 IDirect3DTexture9 *texture; 42 UINT texw, texh; 43 RECT rect; 44 D3DXVECTOR3 center; 45 D3DXVECTOR3 pos; 46 D3DCOLOR color; 47 D3DXMATRIX transform; 48 }; 49 50 struct d3dx9_sprite 51 { 52 ID3DXSprite ID3DXSprite_iface; 53 LONG ref; 54 55 IDirect3DDevice9 *device; 56 IDirect3DVertexDeclaration9 *vdecl; 57 IDirect3DStateBlock9 *stateblock; 58 D3DXMATRIX transform; 59 D3DXMATRIX view; 60 DWORD flags; 61 BOOL ready; 62 63 /* Store the relevant caps to prevent multiple GetDeviceCaps calls */ 64 DWORD texfilter_caps; 65 DWORD maxanisotropy; 66 DWORD alphacmp_caps; 67 68 struct sprite *sprites; 69 int sprite_count; /* number of sprites to be drawn */ 70 int allocated_sprites; /* number of (pre-)allocated sprites */ 71 }; 72 73 static inline struct d3dx9_sprite *impl_from_ID3DXSprite(ID3DXSprite *iface) 74 { 75 return CONTAINING_RECORD(iface, struct d3dx9_sprite, ID3DXSprite_iface); 76 } 77 78 static HRESULT WINAPI d3dx9_sprite_QueryInterface(ID3DXSprite *iface, REFIID riid, void **out) 79 { 80 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); 81 82 if (IsEqualGUID(riid, &IID_ID3DXSprite) 83 || IsEqualGUID(riid, &IID_IUnknown)) 84 { 85 IUnknown_AddRef(iface); 86 *out = iface; 87 return S_OK; 88 } 89 90 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 91 92 *out = NULL; 93 return E_NOINTERFACE; 94 } 95 96 static ULONG WINAPI d3dx9_sprite_AddRef(ID3DXSprite *iface) 97 { 98 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 99 ULONG refcount = InterlockedIncrement(&sprite->ref); 100 101 TRACE("%p increasing refcount to %u.\n", sprite, refcount); 102 103 return refcount; 104 } 105 106 static ULONG WINAPI d3dx9_sprite_Release(ID3DXSprite *iface) 107 { 108 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 109 ULONG refcount = InterlockedDecrement(&sprite->ref); 110 111 TRACE("%p decreasing refcount to %u.\n", sprite, refcount); 112 113 if (!refcount) 114 { 115 if (sprite->sprites) 116 { 117 int i; 118 119 for (i = 0; i < sprite->sprite_count; ++i) 120 { 121 if (sprite->sprites[i].texture) 122 IDirect3DTexture9_Release(sprite->sprites[i].texture); 123 } 124 125 HeapFree(GetProcessHeap(), 0, sprite->sprites); 126 } 127 128 if (sprite->stateblock) 129 IDirect3DStateBlock9_Release(sprite->stateblock); 130 if (sprite->vdecl) 131 IDirect3DVertexDeclaration9_Release(sprite->vdecl); 132 if (sprite->device) 133 IDirect3DDevice9_Release(sprite->device); 134 HeapFree(GetProcessHeap(), 0, sprite); 135 } 136 137 return refcount; 138 } 139 140 static HRESULT WINAPI d3dx9_sprite_GetDevice(struct ID3DXSprite *iface, struct IDirect3DDevice9 **device) 141 { 142 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 143 144 TRACE("iface %p, device %p.\n", iface, device); 145 146 if (!device) 147 return D3DERR_INVALIDCALL; 148 *device = sprite->device; 149 IDirect3DDevice9_AddRef(sprite->device); 150 151 return D3D_OK; 152 } 153 154 static HRESULT WINAPI d3dx9_sprite_GetTransform(ID3DXSprite *iface, D3DXMATRIX *transform) 155 { 156 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 157 158 TRACE("iface %p, transform %p.\n", iface, transform); 159 160 if (!transform) 161 return D3DERR_INVALIDCALL; 162 *transform = sprite->transform; 163 164 return D3D_OK; 165 } 166 167 static HRESULT WINAPI d3dx9_sprite_SetTransform(ID3DXSprite *iface, const D3DXMATRIX *transform) 168 { 169 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 170 171 TRACE("iface %p, transform %p.\n", iface, transform); 172 173 if (!transform) 174 return D3DERR_INVALIDCALL; 175 sprite->transform = *transform; 176 177 return D3D_OK; 178 } 179 180 static HRESULT WINAPI d3dx9_sprite_SetWorldViewRH(ID3DXSprite *iface, 181 const D3DXMATRIX *world, const D3DXMATRIX *view) 182 { 183 FIXME("iface %p, world %p, view %p stub!\n", iface, world, view); 184 185 return E_NOTIMPL; 186 } 187 188 static HRESULT WINAPI d3dx9_sprite_SetWorldViewLH(ID3DXSprite *iface, 189 const D3DXMATRIX *world, const D3DXMATRIX *view) 190 { 191 FIXME("iface %p, world %p, view %p stub!\n", iface, world, view); 192 193 return E_NOTIMPL; 194 } 195 196 /* Helper function */ 197 static void set_states(struct d3dx9_sprite *object) 198 { 199 D3DXMATRIX mat; 200 D3DVIEWPORT9 vp; 201 202 /* Miscellaneous stuff */ 203 IDirect3DDevice9_SetVertexShader(object->device, NULL); 204 IDirect3DDevice9_SetPixelShader(object->device, NULL); 205 IDirect3DDevice9_SetNPatchMode(object->device, 0.0f); 206 207 /* Render states */ 208 IDirect3DDevice9_SetRenderState(object->device, D3DRS_ALPHABLENDENABLE, TRUE); 209 IDirect3DDevice9_SetRenderState(object->device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); 210 IDirect3DDevice9_SetRenderState(object->device, D3DRS_ALPHAREF, 0x00); 211 IDirect3DDevice9_SetRenderState(object->device, D3DRS_ALPHATESTENABLE, object->alphacmp_caps); 212 IDirect3DDevice9_SetRenderState(object->device, D3DRS_BLENDOP, D3DBLENDOP_ADD); 213 IDirect3DDevice9_SetRenderState(object->device, D3DRS_CLIPPING, TRUE); 214 IDirect3DDevice9_SetRenderState(object->device, D3DRS_CLIPPLANEENABLE, 0); 215 IDirect3DDevice9_SetRenderState(object->device, D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | 216 D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); 217 IDirect3DDevice9_SetRenderState(object->device, D3DRS_CULLMODE, D3DCULL_NONE); 218 IDirect3DDevice9_SetRenderState(object->device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 219 IDirect3DDevice9_SetRenderState(object->device, D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); 220 IDirect3DDevice9_SetRenderState(object->device, D3DRS_ENABLEADAPTIVETESSELLATION, FALSE); 221 IDirect3DDevice9_SetRenderState(object->device, D3DRS_FILLMODE, D3DFILL_SOLID); 222 IDirect3DDevice9_SetRenderState(object->device, D3DRS_FOGENABLE, FALSE); 223 IDirect3DDevice9_SetRenderState(object->device, D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); 224 IDirect3DDevice9_SetRenderState(object->device, D3DRS_LIGHTING, FALSE); 225 IDirect3DDevice9_SetRenderState(object->device, D3DRS_RANGEFOGENABLE, FALSE); 226 IDirect3DDevice9_SetRenderState(object->device, D3DRS_SEPARATEALPHABLENDENABLE, FALSE); 227 IDirect3DDevice9_SetRenderState(object->device, D3DRS_SHADEMODE, D3DSHADE_GOURAUD); 228 IDirect3DDevice9_SetRenderState(object->device, D3DRS_SPECULARENABLE, FALSE); 229 IDirect3DDevice9_SetRenderState(object->device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 230 IDirect3DDevice9_SetRenderState(object->device, D3DRS_SRGBWRITEENABLE, FALSE); 231 IDirect3DDevice9_SetRenderState(object->device, D3DRS_STENCILENABLE, FALSE); 232 IDirect3DDevice9_SetRenderState(object->device, D3DRS_VERTEXBLEND, FALSE); 233 IDirect3DDevice9_SetRenderState(object->device, D3DRS_WRAP0, 0); 234 235 /* Texture stage states */ 236 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 237 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); 238 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); 239 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); 240 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); 241 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); 242 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_TEXCOORDINDEX, 0); 243 IDirect3DDevice9_SetTextureStageState(object->device, 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); 244 IDirect3DDevice9_SetTextureStageState(object->device, 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); 245 IDirect3DDevice9_SetTextureStageState(object->device, 1, D3DTSS_COLOROP, D3DTOP_DISABLE); 246 247 /* Sampler states */ 248 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 249 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 250 251 if(object->texfilter_caps & D3DPTFILTERCAPS_MAGFANISOTROPIC) 252 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); 253 else IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 254 255 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MAXMIPLEVEL, 0); 256 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MAXANISOTROPY, object->maxanisotropy); 257 258 if(object->texfilter_caps & D3DPTFILTERCAPS_MINFANISOTROPIC) 259 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); 260 else IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 261 262 if(object->texfilter_caps & D3DPTFILTERCAPS_MIPFLINEAR) 263 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); 264 else IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); 265 266 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_MIPMAPLODBIAS, 0); 267 IDirect3DDevice9_SetSamplerState(object->device, 0, D3DSAMP_SRGBTEXTURE, 0); 268 269 /* Matrices */ 270 D3DXMatrixIdentity(&mat); 271 IDirect3DDevice9_SetTransform(object->device, D3DTS_WORLD, &mat); 272 IDirect3DDevice9_SetTransform(object->device, D3DTS_VIEW, &object->view); 273 IDirect3DDevice9_GetViewport(object->device, &vp); 274 D3DXMatrixOrthoOffCenterLH(&mat, vp.X+0.5f, (float)vp.Width+vp.X+0.5f, (float)vp.Height+vp.Y+0.5f, vp.Y+0.5f, vp.MinZ, vp.MaxZ); 275 IDirect3DDevice9_SetTransform(object->device, D3DTS_PROJECTION, &mat); 276 } 277 278 static HRESULT WINAPI d3dx9_sprite_Begin(ID3DXSprite *iface, DWORD flags) 279 { 280 struct d3dx9_sprite *This = impl_from_ID3DXSprite(iface); 281 HRESULT hr; 282 283 TRACE("iface %p, flags %#x.\n", iface, flags); 284 285 if(flags>D3DXSPRITE_FLAGLIMIT || This->ready) return D3DERR_INVALIDCALL; 286 287 /* TODO: Implement flags: 288 D3DXSPRITE_BILLBOARD: makes the sprite always face the camera 289 D3DXSPRITE_DONOTMODIFY_RENDERSTATE: name says it all 290 D3DXSPRITE_OBJECTSPACE: do not change device transforms 291 D3DXSPRITE_SORT_DEPTH_BACKTOFRONT: sort by position 292 D3DXSPRITE_SORT_DEPTH_FRONTTOBACK: sort by position 293 D3DXSPRITE_SORT_TEXTURE: sort by texture (so that it doesn't change too often) 294 */ 295 /* Seems like alpha blending is always enabled, regardless of D3DXSPRITE_ALPHABLEND flag */ 296 if(flags & (D3DXSPRITE_BILLBOARD | 297 D3DXSPRITE_DONOTMODIFY_RENDERSTATE | D3DXSPRITE_OBJECTSPACE | 298 D3DXSPRITE_SORT_DEPTH_BACKTOFRONT)) 299 FIXME("Flags unsupported: %#x\n", flags); 300 /* These flags should only matter to performance */ 301 else if(flags & (D3DXSPRITE_SORT_DEPTH_FRONTTOBACK | D3DXSPRITE_SORT_TEXTURE)) 302 TRACE("Flags unsupported: %#x\n", flags); 303 304 if(This->vdecl==NULL) { 305 static const D3DVERTEXELEMENT9 elements[] = 306 { 307 { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 308 { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, 309 { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 310 D3DDECL_END() 311 }; 312 IDirect3DDevice9_CreateVertexDeclaration(This->device, elements, &This->vdecl); 313 } 314 315 if(!(flags & D3DXSPRITE_DONOTSAVESTATE)) { 316 if(This->stateblock==NULL) { 317 /* Tell our state block what it must store */ 318 hr=IDirect3DDevice9_BeginStateBlock(This->device); 319 if(hr!=D3D_OK) return hr; 320 321 set_states(This); 322 323 IDirect3DDevice9_SetVertexDeclaration(This->device, This->vdecl); 324 IDirect3DDevice9_SetStreamSource(This->device, 0, NULL, 0, sizeof(struct sprite_vertex)); 325 IDirect3DDevice9_SetIndices(This->device, NULL); 326 IDirect3DDevice9_SetTexture(This->device, 0, NULL); 327 328 IDirect3DDevice9_EndStateBlock(This->device, &This->stateblock); 329 } 330 IDirect3DStateBlock9_Capture(This->stateblock); /* Save current state */ 331 } 332 333 /* Apply device state */ 334 set_states(This); 335 336 This->flags=flags; 337 This->ready=TRUE; 338 339 return D3D_OK; 340 } 341 342 static HRESULT WINAPI d3dx9_sprite_Draw(ID3DXSprite *iface, IDirect3DTexture9 *texture, 343 const RECT *rect, const D3DXVECTOR3 *center, const D3DXVECTOR3 *position, D3DCOLOR color) 344 { 345 struct d3dx9_sprite *This = impl_from_ID3DXSprite(iface); 346 D3DSURFACE_DESC texdesc; 347 348 TRACE("iface %p, texture %p, rect %s, center %p, position %p, color 0x%08x.\n", 349 iface, texture, wine_dbgstr_rect(rect), center, position, color); 350 351 if(texture==NULL) return D3DERR_INVALIDCALL; 352 if(!This->ready) return D3DERR_INVALIDCALL; 353 354 if (!This->allocated_sprites) 355 { 356 This->sprites = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32 * sizeof(*This->sprites)); 357 This->allocated_sprites = 32; 358 } 359 else if (This->allocated_sprites <= This->sprite_count) 360 { 361 This->allocated_sprites += This->allocated_sprites / 2; 362 This->sprites = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 363 This->sprites, This->allocated_sprites * sizeof(*This->sprites)); 364 } 365 This->sprites[This->sprite_count].texture=texture; 366 if(!(This->flags & D3DXSPRITE_DO_NOT_ADDREF_TEXTURE)) 367 IDirect3DTexture9_AddRef(texture); 368 369 /* Reuse the texture desc if possible */ 370 if(This->sprite_count) { 371 if(This->sprites[This->sprite_count-1].texture!=texture) { 372 IDirect3DTexture9_GetLevelDesc(texture, 0, &texdesc); 373 } else { 374 texdesc.Width=This->sprites[This->sprite_count-1].texw; 375 texdesc.Height=This->sprites[This->sprite_count-1].texh; 376 } 377 } else IDirect3DTexture9_GetLevelDesc(texture, 0, &texdesc); 378 379 This->sprites[This->sprite_count].texw=texdesc.Width; 380 This->sprites[This->sprite_count].texh=texdesc.Height; 381 382 if (rect) 383 This->sprites[This->sprite_count].rect = *rect; 384 else 385 SetRect(&This->sprites[This->sprite_count].rect, 0, 0, texdesc.Width, texdesc.Height); 386 387 if(center==NULL) { 388 This->sprites[This->sprite_count].center.x=0.0f; 389 This->sprites[This->sprite_count].center.y=0.0f; 390 This->sprites[This->sprite_count].center.z=0.0f; 391 } else This->sprites[This->sprite_count].center=*center; 392 393 if(position==NULL) { 394 This->sprites[This->sprite_count].pos.x=0.0f; 395 This->sprites[This->sprite_count].pos.y=0.0f; 396 This->sprites[This->sprite_count].pos.z=0.0f; 397 } else This->sprites[This->sprite_count].pos=*position; 398 399 This->sprites[This->sprite_count].color=color; 400 This->sprites[This->sprite_count].transform=This->transform; 401 This->sprite_count++; 402 403 return D3D_OK; 404 } 405 406 static HRESULT WINAPI d3dx9_sprite_Flush(ID3DXSprite *iface) 407 { 408 struct d3dx9_sprite *This = impl_from_ID3DXSprite(iface); 409 struct sprite_vertex *vertices; 410 int i, count=0, start; 411 412 TRACE("iface %p.\n", iface); 413 414 if(!This->ready) return D3DERR_INVALIDCALL; 415 if(!This->sprite_count) return D3D_OK; 416 417 /* TODO: use of a vertex buffer here */ 418 vertices = HeapAlloc(GetProcessHeap(), 0, sizeof(*vertices) * 6 * This->sprite_count); 419 420 for(start=0;start<This->sprite_count;start+=count,count=0) { 421 i=start; 422 while(i<This->sprite_count && 423 (count==0 || This->sprites[i].texture==This->sprites[i-1].texture)) { 424 float spritewidth=(float)This->sprites[i].rect.right-(float)This->sprites[i].rect.left; 425 float spriteheight=(float)This->sprites[i].rect.bottom-(float)This->sprites[i].rect.top; 426 427 vertices[6*i ].pos.x = This->sprites[i].pos.x - This->sprites[i].center.x; 428 vertices[6*i ].pos.y = This->sprites[i].pos.y - This->sprites[i].center.y; 429 vertices[6*i ].pos.z = This->sprites[i].pos.z - This->sprites[i].center.z; 430 vertices[6*i+1].pos.x = spritewidth + This->sprites[i].pos.x - This->sprites[i].center.x; 431 vertices[6*i+1].pos.y = This->sprites[i].pos.y - This->sprites[i].center.y; 432 vertices[6*i+1].pos.z = This->sprites[i].pos.z - This->sprites[i].center.z; 433 vertices[6*i+2].pos.x = spritewidth + This->sprites[i].pos.x - This->sprites[i].center.x; 434 vertices[6*i+2].pos.y = spriteheight + This->sprites[i].pos.y - This->sprites[i].center.y; 435 vertices[6*i+2].pos.z = This->sprites[i].pos.z - This->sprites[i].center.z; 436 vertices[6*i+3].pos.x = This->sprites[i].pos.x - This->sprites[i].center.x; 437 vertices[6*i+3].pos.y = spriteheight + This->sprites[i].pos.y - This->sprites[i].center.y; 438 vertices[6*i+3].pos.z = This->sprites[i].pos.z - This->sprites[i].center.z; 439 vertices[6*i ].col = This->sprites[i].color; 440 vertices[6*i+1].col = This->sprites[i].color; 441 vertices[6*i+2].col = This->sprites[i].color; 442 vertices[6*i+3].col = This->sprites[i].color; 443 vertices[6*i ].tex.x = (float)This->sprites[i].rect.left / (float)This->sprites[i].texw; 444 vertices[6*i ].tex.y = (float)This->sprites[i].rect.top / (float)This->sprites[i].texh; 445 vertices[6*i+1].tex.x = (float)This->sprites[i].rect.right / (float)This->sprites[i].texw; 446 vertices[6*i+1].tex.y = (float)This->sprites[i].rect.top / (float)This->sprites[i].texh; 447 vertices[6*i+2].tex.x = (float)This->sprites[i].rect.right / (float)This->sprites[i].texw; 448 vertices[6*i+2].tex.y = (float)This->sprites[i].rect.bottom / (float)This->sprites[i].texh; 449 vertices[6*i+3].tex.x = (float)This->sprites[i].rect.left / (float)This->sprites[i].texw; 450 vertices[6*i+3].tex.y = (float)This->sprites[i].rect.bottom / (float)This->sprites[i].texh; 451 452 vertices[6*i+4]=vertices[6*i]; 453 vertices[6*i+5]=vertices[6*i+2]; 454 455 D3DXVec3TransformCoordArray(&vertices[6 * i].pos, sizeof(*vertices), 456 &vertices[6 * i].pos, sizeof(*vertices), &This->sprites[i].transform, 6); 457 count++; 458 i++; 459 } 460 461 IDirect3DDevice9_SetTexture(This->device, 0, (struct IDirect3DBaseTexture9 *)This->sprites[start].texture); 462 IDirect3DDevice9_SetVertexDeclaration(This->device, This->vdecl); 463 464 IDirect3DDevice9_DrawPrimitiveUP(This->device, D3DPT_TRIANGLELIST, 465 2 * count, vertices + 6 * start, sizeof(*vertices)); 466 } 467 HeapFree(GetProcessHeap(), 0, vertices); 468 469 if(!(This->flags & D3DXSPRITE_DO_NOT_ADDREF_TEXTURE)) 470 for(i=0;i<This->sprite_count;i++) 471 IDirect3DTexture9_Release(This->sprites[i].texture); 472 473 This->sprite_count=0; 474 475 /* Flush may be called more than once, so we don't reset This->ready here */ 476 477 return D3D_OK; 478 } 479 480 static HRESULT WINAPI d3dx9_sprite_End(ID3DXSprite *iface) 481 { 482 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 483 484 TRACE("iface %p.\n", iface); 485 486 if (!sprite->ready) 487 return D3DERR_INVALIDCALL; 488 489 ID3DXSprite_Flush(iface); 490 491 if (sprite->stateblock && !(sprite->flags & D3DXSPRITE_DONOTSAVESTATE)) 492 IDirect3DStateBlock9_Apply(sprite->stateblock); /* Restore old state */ 493 494 sprite->ready = FALSE; 495 496 return D3D_OK; 497 } 498 499 static HRESULT WINAPI d3dx9_sprite_OnLostDevice(ID3DXSprite *iface) 500 { 501 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 502 503 TRACE("iface %p.\n", iface); 504 505 if (sprite->stateblock) 506 IDirect3DStateBlock9_Release(sprite->stateblock); 507 if (sprite->vdecl) 508 IDirect3DVertexDeclaration9_Release(sprite->vdecl); 509 sprite->vdecl = NULL; 510 sprite->stateblock = NULL; 511 512 /* Reset some variables */ 513 ID3DXSprite_OnResetDevice(iface); 514 515 return D3D_OK; 516 } 517 518 static HRESULT WINAPI d3dx9_sprite_OnResetDevice(ID3DXSprite *iface) 519 { 520 struct d3dx9_sprite *sprite = impl_from_ID3DXSprite(iface); 521 int i; 522 523 TRACE("iface %p.\n", iface); 524 525 for (i = 0; i < sprite->sprite_count; ++i) 526 { 527 if (sprite->sprites[i].texture) 528 IDirect3DTexture9_Release(sprite->sprites[i].texture); 529 } 530 531 sprite->sprite_count = 0; 532 sprite->flags = 0; 533 sprite->ready = FALSE; 534 535 /* keep matrices */ 536 /* device objects get restored on Begin */ 537 538 return D3D_OK; 539 } 540 541 static const ID3DXSpriteVtbl d3dx9_sprite_vtbl = 542 { 543 d3dx9_sprite_QueryInterface, 544 d3dx9_sprite_AddRef, 545 d3dx9_sprite_Release, 546 d3dx9_sprite_GetDevice, 547 d3dx9_sprite_GetTransform, 548 d3dx9_sprite_SetTransform, 549 d3dx9_sprite_SetWorldViewRH, 550 d3dx9_sprite_SetWorldViewLH, 551 d3dx9_sprite_Begin, 552 d3dx9_sprite_Draw, 553 d3dx9_sprite_Flush, 554 d3dx9_sprite_End, 555 d3dx9_sprite_OnLostDevice, 556 d3dx9_sprite_OnResetDevice, 557 }; 558 559 HRESULT WINAPI D3DXCreateSprite(struct IDirect3DDevice9 *device, struct ID3DXSprite **sprite) 560 { 561 struct d3dx9_sprite *object; 562 D3DCAPS9 caps; 563 564 TRACE("device %p, sprite %p.\n", device, sprite); 565 566 if(device==NULL || sprite==NULL) return D3DERR_INVALIDCALL; 567 568 if (!(object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) 569 { 570 *sprite = NULL; 571 return E_OUTOFMEMORY; 572 } 573 object->ID3DXSprite_iface.lpVtbl = &d3dx9_sprite_vtbl; 574 object->ref=1; 575 object->device=device; 576 IUnknown_AddRef(device); 577 578 object->vdecl=NULL; 579 object->stateblock=NULL; 580 581 D3DXMatrixIdentity(&object->transform); 582 D3DXMatrixIdentity(&object->view); 583 584 IDirect3DDevice9_GetDeviceCaps(device, &caps); 585 object->texfilter_caps=caps.TextureFilterCaps; 586 object->maxanisotropy=caps.MaxAnisotropy; 587 object->alphacmp_caps=caps.AlphaCmpCaps; 588 589 ID3DXSprite_OnResetDevice(&object->ID3DXSprite_iface); 590 591 object->sprites=NULL; 592 object->allocated_sprites=0; 593 *sprite=&object->ID3DXSprite_iface; 594 595 return D3D_OK; 596 } 597