Added last error code for XP SP1.
[wine] / dlls / d3d8 / volume.c
1 /*
2  * IDirect3DVolume8 implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  *                     Raphael Junqueira
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25
26 #define COBJMACROS
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wingdi.h"
34 #include "wine/debug.h"
35
36 #include "d3d8_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
39
40 /* IDirect3DVolume IUnknown parts follow: */
41 HRESULT WINAPI IDirect3DVolume8Impl_QueryInterface(LPDIRECT3DVOLUME8 iface, REFIID riid, LPVOID* ppobj) {
42     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
43
44     if (IsEqualGUID(riid, &IID_IUnknown)
45         || IsEqualGUID(riid, &IID_IDirect3DVolume8)) {
46         IDirect3DVolume8Impl_AddRef(iface);
47         *ppobj = This;
48         return D3D_OK;
49     }
50
51     WARN("(%p)->(%s,%p) not found\n", This, debugstr_guid(riid), ppobj);
52     return E_NOINTERFACE;
53 }
54
55 ULONG WINAPI IDirect3DVolume8Impl_AddRef(LPDIRECT3DVOLUME8 iface) {
56     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
57     ULONG ref = InterlockedIncrement(&This->ref);
58
59     TRACE("(%p) : AddRef from %ld\n", This, ref - 1);
60
61     return ref;
62 }
63
64 ULONG WINAPI IDirect3DVolume8Impl_Release(LPDIRECT3DVOLUME8 iface) {
65     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
66     ULONG ref = InterlockedDecrement(&This->ref);
67
68     TRACE("(%p) : ReleaseRef to %ld\n", This, ref);
69
70     if (ref == 0) {
71         HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
72         HeapFree(GetProcessHeap(), 0, This);
73     }
74     return ref;
75 }
76
77 /* IDirect3DVolume8: */
78 HRESULT WINAPI IDirect3DVolume8Impl_GetDevice(LPDIRECT3DVOLUME8 iface, IDirect3DDevice8** ppDevice) {
79     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
80     TRACE("(%p) : returning %p\n", This, This->Device);
81     *ppDevice = (LPDIRECT3DDEVICE8) This->Device;
82
83     /* Note  Calling this method will increase the internal reference count 
84        on the IDirect3DDevice8 interface. */
85     IDirect3DDevice8Impl_AddRef(*ppDevice);
86
87     return D3D_OK;
88 }
89
90 HRESULT WINAPI IDirect3DVolume8Impl_SetPrivateData(LPDIRECT3DVOLUME8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
91     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
92     FIXME("(%p) : stub\n", This);    
93     return D3D_OK;
94 }
95
96 HRESULT WINAPI IDirect3DVolume8Impl_GetPrivateData(LPDIRECT3DVOLUME8 iface, REFGUID  refguid, void* pData, DWORD* pSizeOfData) {
97     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
98     FIXME("(%p) : stub\n", This);    
99     return D3D_OK;
100 }
101
102 HRESULT WINAPI IDirect3DVolume8Impl_FreePrivateData(LPDIRECT3DVOLUME8 iface, REFGUID refguid) {
103     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
104     FIXME("(%p) : stub\n", This);    
105     return D3D_OK;
106 }
107
108 HRESULT WINAPI IDirect3DVolume8Impl_GetContainer(LPDIRECT3DVOLUME8 iface, REFIID riid, void** ppContainer) {
109     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
110     TRACE("(%p) : returning %p\n", This, This->Container);
111     *ppContainer = This->Container;
112     IUnknown_AddRef(This->Container);
113     return D3D_OK;
114 }
115
116 HRESULT WINAPI IDirect3DVolume8Impl_GetDesc(LPDIRECT3DVOLUME8 iface, D3DVOLUME_DESC* pDesc) {
117     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
118     TRACE("(%p) : copying into %p\n", This, pDesc);
119     memcpy(pDesc, &This->myDesc, sizeof(D3DVOLUME_DESC));
120     return D3D_OK;
121 }
122
123 HRESULT WINAPI IDirect3DVolume8Impl_LockBox(LPDIRECT3DVOLUME8 iface, D3DLOCKED_BOX* pLockedVolume, CONST D3DBOX* pBox, DWORD Flags) {
124     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
125     FIXME("(%p) : pBox=%p stub\n", This, pBox);    
126
127     /* fixme: should we really lock as such? */
128     TRACE("(%p) : box=%p, output pbox=%p, allMem=%p\n", This, pBox, pLockedVolume, This->allocatedMemory);
129
130     pLockedVolume->RowPitch   = This->bytesPerPixel * This->myDesc.Width;                        /* Bytes / row   */
131     pLockedVolume->SlicePitch = This->bytesPerPixel * This->myDesc.Width * This->myDesc.Height;  /* Bytes / slice */
132     if (!pBox) {
133         TRACE("No box supplied - all is ok\n");
134         pLockedVolume->pBits = This->allocatedMemory;
135         This->lockedBox.Left   = 0;
136         This->lockedBox.Top    = 0;
137         This->lockedBox.Front  = 0;
138         This->lockedBox.Right  = This->myDesc.Width;
139         This->lockedBox.Bottom = This->myDesc.Height;
140         This->lockedBox.Back   = This->myDesc.Depth;
141     } else {
142         TRACE("Lock Box (%p) = l %d, t %d, r %d, b %d, fr %d, ba %d\n", pBox, pBox->Left, pBox->Top, pBox->Right, pBox->Bottom, pBox->Front, pBox->Back);
143         pLockedVolume->pBits = This->allocatedMemory + 
144           (pLockedVolume->SlicePitch * pBox->Front) + /* FIXME: is front < back or vica versa? */
145           (pLockedVolume->RowPitch * pBox->Top) + 
146           (pBox->Left * This->bytesPerPixel);
147         This->lockedBox.Left   = pBox->Left;
148         This->lockedBox.Top    = pBox->Top;
149         This->lockedBox.Front  = pBox->Front;
150         This->lockedBox.Right  = pBox->Right;
151         This->lockedBox.Bottom = pBox->Bottom;
152         This->lockedBox.Back   = pBox->Back;
153     }
154     
155     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
156       /* Don't dirtify */
157     } else {
158       /**
159        * Dirtify on lock
160        * as seen in msdn docs
161        */
162       IDirect3DVolume8Impl_AddDirtyBox(iface, &This->lockedBox);
163
164       /**  Dirtify Container if needed */
165       if (NULL != This->Container) {
166         IDirect3DVolumeTexture8* cont = (IDirect3DVolumeTexture8*) This->Container;     
167         D3DRESOURCETYPE containerType = IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) cont);
168         if (containerType == D3DRTYPE_VOLUMETEXTURE) {
169           IDirect3DBaseTexture8Impl* pTexture = (IDirect3DBaseTexture8Impl*) cont;
170           pTexture->Dirty = TRUE;
171         } else {
172           FIXME("Set dirty on container type %d\n", containerType);
173         }
174       }
175     }
176
177     This->locked = TRUE;
178     TRACE("returning memory@%p rpitch(%d) spitch(%d)\n", pLockedVolume->pBits, pLockedVolume->RowPitch, pLockedVolume->SlicePitch);
179     return D3D_OK;
180 }
181
182 HRESULT WINAPI IDirect3DVolume8Impl_UnlockBox(LPDIRECT3DVOLUME8 iface) {
183     IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
184     if (FALSE == This->locked) {
185       ERR("trying to lock unlocked volume@%p\n", This);  
186       return D3DERR_INVALIDCALL;
187     }
188     TRACE("(%p) : unlocking volume\n", This);
189     This->locked = FALSE;
190     memset(&This->lockedBox, 0, sizeof(RECT));
191     return D3D_OK;
192 }
193
194
195 const IDirect3DVolume8Vtbl Direct3DVolume8_Vtbl =
196 {
197     IDirect3DVolume8Impl_QueryInterface,
198     IDirect3DVolume8Impl_AddRef,
199     IDirect3DVolume8Impl_Release,
200     IDirect3DVolume8Impl_GetDevice,
201     IDirect3DVolume8Impl_SetPrivateData,
202     IDirect3DVolume8Impl_GetPrivateData,
203     IDirect3DVolume8Impl_FreePrivateData,
204     IDirect3DVolume8Impl_GetContainer,
205     IDirect3DVolume8Impl_GetDesc,
206     IDirect3DVolume8Impl_LockBox,
207     IDirect3DVolume8Impl_UnlockBox
208 };
209
210
211 HRESULT WINAPI IDirect3DVolume8Impl_CleanDirtyBox(LPDIRECT3DVOLUME8 iface) {
212   IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
213   This->Dirty = FALSE;
214   This->lockedBox.Left   = This->myDesc.Width;
215   This->lockedBox.Top    = This->myDesc.Height;
216   This->lockedBox.Front  = This->myDesc.Depth;  
217   This->lockedBox.Right  = 0;
218   This->lockedBox.Bottom = 0;
219   This->lockedBox.Back   = 0;
220   return D3D_OK;
221 }
222
223 /**
224  * Raphael:
225  *   very stupid way to handle multiple dirty box but it works :)
226  */
227 HRESULT WINAPI IDirect3DVolume8Impl_AddDirtyBox(LPDIRECT3DVOLUME8 iface, CONST D3DBOX* pDirtyBox) {
228   IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface;
229   This->Dirty = TRUE;
230    if (NULL != pDirtyBox) {
231     This->lockedBox.Left   = min(This->lockedBox.Left,   pDirtyBox->Left);
232     This->lockedBox.Top    = min(This->lockedBox.Top,    pDirtyBox->Top);
233     This->lockedBox.Front  = min(This->lockedBox.Front,  pDirtyBox->Front);
234     This->lockedBox.Right  = max(This->lockedBox.Right,  pDirtyBox->Right);
235     This->lockedBox.Bottom = max(This->lockedBox.Bottom, pDirtyBox->Bottom);
236     This->lockedBox.Back   = max(This->lockedBox.Back,   pDirtyBox->Back);
237   } else {
238     This->lockedBox.Left   = 0;
239     This->lockedBox.Top    = 0;
240     This->lockedBox.Front  = 0;
241     This->lockedBox.Right  = This->myDesc.Width;
242     This->lockedBox.Bottom = This->myDesc.Height;
243     This->lockedBox.Back   = This->myDesc.Depth;
244   }
245   return D3D_OK;
246 }