ddraw: Better simulate what 'GetVerticalBlankStatus' does on real hardware.
[wine] / dlls / ddraw / d3d_utils.c
1 /* Direct3D Common functions
2  * Copyright (c) 1998 Lionel ULMER
3  *
4  * This file contains all common miscellaneous code that spans
5  * different 'objects'
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 <stdarg.h>
23
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 #include "wingdi.h"
30 #include "ddraw.h"
31 #include "d3d.h"
32 #include "wine/debug.h"
33
34 #include "d3d_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
37
38 const char *_get_renderstate(D3DRENDERSTATETYPE type) {
39     static const char * const states[] = {
40         "ERR",
41         "D3DRENDERSTATE_TEXTUREHANDLE",
42         "D3DRENDERSTATE_ANTIALIAS",
43         "D3DRENDERSTATE_TEXTUREADDRESS",
44         "D3DRENDERSTATE_TEXTUREPERSPECTIVE",
45         "D3DRENDERSTATE_WRAPU",
46         "D3DRENDERSTATE_WRAPV",
47         "D3DRENDERSTATE_ZENABLE",
48         "D3DRENDERSTATE_FILLMODE",
49         "D3DRENDERSTATE_SHADEMODE",
50         "D3DRENDERSTATE_LINEPATTERN",
51         "D3DRENDERSTATE_MONOENABLE",
52         "D3DRENDERSTATE_ROP2",
53         "D3DRENDERSTATE_PLANEMASK",
54         "D3DRENDERSTATE_ZWRITEENABLE",
55         "D3DRENDERSTATE_ALPHATESTENABLE",
56         "D3DRENDERSTATE_LASTPIXEL",
57         "D3DRENDERSTATE_TEXTUREMAG",
58         "D3DRENDERSTATE_TEXTUREMIN",
59         "D3DRENDERSTATE_SRCBLEND",
60         "D3DRENDERSTATE_DESTBLEND",
61         "D3DRENDERSTATE_TEXTUREMAPBLEND",
62         "D3DRENDERSTATE_CULLMODE",
63         "D3DRENDERSTATE_ZFUNC",
64         "D3DRENDERSTATE_ALPHAREF",
65         "D3DRENDERSTATE_ALPHAFUNC",
66         "D3DRENDERSTATE_DITHERENABLE",
67         "D3DRENDERSTATE_ALPHABLENDENABLE",
68         "D3DRENDERSTATE_FOGENABLE",
69         "D3DRENDERSTATE_SPECULARENABLE",
70         "D3DRENDERSTATE_ZVISIBLE",
71         "D3DRENDERSTATE_SUBPIXEL",
72         "D3DRENDERSTATE_SUBPIXELX",
73         "D3DRENDERSTATE_STIPPLEDALPHA",
74         "D3DRENDERSTATE_FOGCOLOR",
75         "D3DRENDERSTATE_FOGTABLEMODE",
76         "D3DRENDERSTATE_FOGTABLESTART",
77         "D3DRENDERSTATE_FOGTABLEEND",
78         "D3DRENDERSTATE_FOGTABLEDENSITY",
79         "D3DRENDERSTATE_STIPPLEENABLE",
80         "D3DRENDERSTATE_EDGEANTIALIAS",
81         "D3DRENDERSTATE_COLORKEYENABLE",
82         "ERR",
83         "D3DRENDERSTATE_BORDERCOLOR",
84         "D3DRENDERSTATE_TEXTUREADDRESSU",
85         "D3DRENDERSTATE_TEXTUREADDRESSV",
86         "D3DRENDERSTATE_MIPMAPLODBIAS",
87         "D3DRENDERSTATE_ZBIAS",
88         "D3DRENDERSTATE_RANGEFOGENABLE",
89         "D3DRENDERSTATE_ANISOTROPY",
90         "D3DRENDERSTATE_FLUSHBATCH",
91         "D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT",
92         "D3DRENDERSTATE_STENCILENABLE",
93         "D3DRENDERSTATE_STENCILFAIL",
94         "D3DRENDERSTATE_STENCILZFAIL",
95         "D3DRENDERSTATE_STENCILPASS",
96         "D3DRENDERSTATE_STENCILFUNC",
97         "D3DRENDERSTATE_STENCILREF",
98         "D3DRENDERSTATE_STENCILMASK",
99         "D3DRENDERSTATE_STENCILWRITEMASK",
100         "D3DRENDERSTATE_TEXTUREFACTOR",
101         "ERR",
102         "ERR",
103         "ERR",
104         "D3DRENDERSTATE_STIPPLEPATTERN00",
105         "D3DRENDERSTATE_STIPPLEPATTERN01",
106         "D3DRENDERSTATE_STIPPLEPATTERN02",
107         "D3DRENDERSTATE_STIPPLEPATTERN03",
108         "D3DRENDERSTATE_STIPPLEPATTERN04",
109         "D3DRENDERSTATE_STIPPLEPATTERN05",
110         "D3DRENDERSTATE_STIPPLEPATTERN06",
111         "D3DRENDERSTATE_STIPPLEPATTERN07",
112         "D3DRENDERSTATE_STIPPLEPATTERN08",
113         "D3DRENDERSTATE_STIPPLEPATTERN09",
114         "D3DRENDERSTATE_STIPPLEPATTERN10",
115         "D3DRENDERSTATE_STIPPLEPATTERN11",
116         "D3DRENDERSTATE_STIPPLEPATTERN12",
117         "D3DRENDERSTATE_STIPPLEPATTERN13",
118         "D3DRENDERSTATE_STIPPLEPATTERN14",
119         "D3DRENDERSTATE_STIPPLEPATTERN15",
120         "D3DRENDERSTATE_STIPPLEPATTERN16",
121         "D3DRENDERSTATE_STIPPLEPATTERN17",
122         "D3DRENDERSTATE_STIPPLEPATTERN18",
123         "D3DRENDERSTATE_STIPPLEPATTERN19",
124         "D3DRENDERSTATE_STIPPLEPATTERN20",
125         "D3DRENDERSTATE_STIPPLEPATTERN21",
126         "D3DRENDERSTATE_STIPPLEPATTERN22",
127         "D3DRENDERSTATE_STIPPLEPATTERN23",
128         "D3DRENDERSTATE_STIPPLEPATTERN24",
129         "D3DRENDERSTATE_STIPPLEPATTERN25",
130         "D3DRENDERSTATE_STIPPLEPATTERN26",
131         "D3DRENDERSTATE_STIPPLEPATTERN27",
132         "D3DRENDERSTATE_STIPPLEPATTERN28",
133         "D3DRENDERSTATE_STIPPLEPATTERN29",
134         "D3DRENDERSTATE_STIPPLEPATTERN30",
135         "D3DRENDERSTATE_STIPPLEPATTERN31"
136     };
137     static const char * const states_2[] = {
138         "D3DRENDERSTATE_WRAP0",
139         "D3DRENDERSTATE_WRAP1",
140         "D3DRENDERSTATE_WRAP2",
141         "D3DRENDERSTATE_WRAP3",
142         "D3DRENDERSTATE_WRAP4",
143         "D3DRENDERSTATE_WRAP5",
144         "D3DRENDERSTATE_WRAP6",
145         "D3DRENDERSTATE_WRAP7",
146         "D3DRENDERSTATE_CLIPPING",
147         "D3DRENDERSTATE_LIGHTING",
148         "D3DRENDERSTATE_EXTENTS",
149         "D3DRENDERSTATE_AMBIENT",
150         "D3DRENDERSTATE_FOGVERTEXMODE",
151         "D3DRENDERSTATE_COLORVERTEX",
152         "D3DRENDERSTATE_LOCALVIEWER",
153         "D3DRENDERSTATE_NORMALIZENORMALS",
154         "D3DRENDERSTATE_COLORKEYBLENDENABLE",
155         "D3DRENDERSTATE_DIFFUSEMATERIALSOURCE",
156         "D3DRENDERSTATE_SPECULARMATERIALSOURCE",
157         "D3DRENDERSTATE_AMBIENTMATERIALSOURCE",
158         "D3DRENDERSTATE_EMISSIVEMATERIALSOURCE",
159         "ERR",
160         "ERR",
161         "D3DRENDERSTATE_VERTEXBLEND",
162         "D3DRENDERSTATE_CLIPPLANEENABLE",
163     };
164     if (type >= D3DRENDERSTATE_WRAP0) {
165         type -= D3DRENDERSTATE_WRAP0;
166         if (type >= (sizeof(states_2) / sizeof(states_2[0]))) return "ERR";
167         return states_2[type];
168     }
169     if (type >= (sizeof(states) / sizeof(states[0]))) return "ERR";
170     return states[type];
171 }
172
173 void
174 dump_D3DCOLORVALUE(D3DCOLORVALUE *lpCol)
175 {
176     DPRINTF("%f %f %f %f", lpCol->u1.r, lpCol->u2.g, lpCol->u3.b, lpCol->u4.a);
177 }
178
179 void
180 dump_D3DVECTOR(D3DVECTOR *lpVec)
181 {
182     DPRINTF("%f %f %f", lpVec->u1.x, lpVec->u2.y, lpVec->u3.z);
183 }
184
185 void
186 dump_D3DMATERIAL7(LPD3DMATERIAL7 lpMat)
187 {
188     DPRINTF(" - diffuse  : "); dump_D3DCOLORVALUE(&(lpMat->u.diffuse)); DPRINTF("\n");
189     DPRINTF(" - ambient  : "); dump_D3DCOLORVALUE(&(lpMat->u1.ambient)); DPRINTF("\n");
190     DPRINTF(" - specular : "); dump_D3DCOLORVALUE(&(lpMat->u2.specular)); DPRINTF("\n");
191     DPRINTF(" - emissive : "); dump_D3DCOLORVALUE(&(lpMat->u3.emissive)); DPRINTF("\n");
192     DPRINTF(" - power    : %f\n", lpMat->u4.power);
193 }
194
195 void
196 dump_D3DLIGHT7(LPD3DLIGHT7 lpLight)
197 {
198     DPRINTF(" - light type : %s\n", (lpLight->dltType == D3DLIGHT_POINT ? "D3DLIGHT_POINT" : 
199                                      (lpLight->dltType == D3DLIGHT_SPOT ? "D3DLIGHT_SPOT" : 
200                                       (lpLight->dltType == D3DLIGHT_DIRECTIONAL ? "D3DLIGHT_DIRECTIONAL" : 
201                                        "UNSUPPORTED"))));
202     DPRINTF(" - diffuse       : "); dump_D3DCOLORVALUE(&(lpLight->dcvDiffuse)); DPRINTF("\n");
203     DPRINTF(" - specular      : "); dump_D3DCOLORVALUE(&(lpLight->dcvSpecular)); DPRINTF("\n");
204     DPRINTF(" - ambient       : "); dump_D3DCOLORVALUE(&(lpLight->dcvAmbient)); DPRINTF("\n");
205     DPRINTF(" - position      : "); dump_D3DVECTOR(&(lpLight->dvPosition)); DPRINTF("\n");
206     DPRINTF(" - direction     : "); dump_D3DVECTOR(&(lpLight->dvDirection)); DPRINTF("\n");
207     DPRINTF(" - dvRange       : %f\n", lpLight->dvRange);
208     DPRINTF(" - dvFalloff     : %f\n", lpLight->dvFalloff);
209     DPRINTF(" - dvAttenuation : %f %f %f\n", lpLight->dvAttenuation0, lpLight->dvAttenuation1, lpLight->dvAttenuation2);
210     DPRINTF(" - dvTheta       : %f\n", lpLight->dvTheta);
211     DPRINTF(" - dvPhi         : %f\n", lpLight->dvPhi);
212 }
213
214 void
215 dump_DPFLAGS(DWORD dwFlags)
216 {
217     static const flag_info flags[] =
218     {
219         FE(D3DDP_WAIT),
220         FE(D3DDP_OUTOFORDER),
221         FE(D3DDP_DONOTCLIP),
222         FE(D3DDP_DONOTUPDATEEXTENTS),
223         FE(D3DDP_DONOTLIGHT)
224     };
225
226     DDRAW_dump_flags(dwFlags, flags, sizeof(flags)/sizeof(flags[0]));
227 }
228
229 void
230 dump_D3DMATRIX(D3DMATRIX *mat)
231 {
232     DPRINTF("  %f %f %f %f\n", mat->_11, mat->_12, mat->_13, mat->_14);
233     DPRINTF("  %f %f %f %f\n", mat->_21, mat->_22, mat->_23, mat->_24);
234     DPRINTF("  %f %f %f %f\n", mat->_31, mat->_32, mat->_33, mat->_34);
235     DPRINTF("  %f %f %f %f\n", mat->_41, mat->_42, mat->_43, mat->_44);
236 }
237
238 DWORD get_flexible_vertex_size(DWORD d3dvtVertexType)
239 {
240     DWORD size = 0;
241     int i;
242     
243     if (d3dvtVertexType & D3DFVF_NORMAL) size += 3 * sizeof(D3DVALUE);
244     if (d3dvtVertexType & D3DFVF_DIFFUSE) size += sizeof(DWORD);
245     if (d3dvtVertexType & D3DFVF_SPECULAR) size += sizeof(DWORD);
246     if (d3dvtVertexType & D3DFVF_RESERVED1) size += sizeof(DWORD);
247     switch (d3dvtVertexType & D3DFVF_POSITION_MASK) {
248         case D3DFVF_XYZ: size += 3 * sizeof(D3DVALUE); break;
249         case D3DFVF_XYZRHW: size += 4 * sizeof(D3DVALUE); break;
250         default: TRACE(" matrix weighting not handled yet...\n");
251     }
252     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); i++) {
253         size += GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, i) * sizeof(D3DVALUE);
254     }
255     
256     return size;
257 }
258
259 void dump_flexible_vertex(DWORD d3dvtVertexType)
260 {
261     static const flag_info flags[] = {
262         FE(D3DFVF_NORMAL),
263         FE(D3DFVF_RESERVED1),
264         FE(D3DFVF_DIFFUSE),
265         FE(D3DFVF_SPECULAR)
266     };
267     unsigned int i;
268     
269     if (d3dvtVertexType & D3DFVF_RESERVED0) DPRINTF("D3DFVF_RESERVED0 ");
270     switch (d3dvtVertexType & D3DFVF_POSITION_MASK) {
271 #define GEN_CASE(a) case a: DPRINTF(#a " "); break
272         GEN_CASE(D3DFVF_XYZ);
273         GEN_CASE(D3DFVF_XYZRHW);
274         GEN_CASE(D3DFVF_XYZB1);
275         GEN_CASE(D3DFVF_XYZB2);
276         GEN_CASE(D3DFVF_XYZB3);
277         GEN_CASE(D3DFVF_XYZB4);
278         GEN_CASE(D3DFVF_XYZB5);
279     }
280     DDRAW_dump_flags_(d3dvtVertexType, flags, sizeof(flags)/sizeof(flags[0]), FALSE);
281     switch (d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) {
282         GEN_CASE(D3DFVF_TEX0);
283         GEN_CASE(D3DFVF_TEX1);
284         GEN_CASE(D3DFVF_TEX2);
285         GEN_CASE(D3DFVF_TEX3);
286         GEN_CASE(D3DFVF_TEX4);
287         GEN_CASE(D3DFVF_TEX5);
288         GEN_CASE(D3DFVF_TEX6);
289         GEN_CASE(D3DFVF_TEX7);
290         GEN_CASE(D3DFVF_TEX8);
291     }
292 #undef GEN_CASE
293     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); i++) {
294         DPRINTF(" T%d-s%ld", i + 1, GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, i));
295     }
296     DPRINTF("\n");
297 }
298
299 void
300 convert_FVF_to_strided_data(DWORD d3dvtVertexType, LPVOID lpvVertices, D3DDRAWPRIMITIVESTRIDEDDATA *strided, DWORD dwStartVertex)
301 {
302     int current_offset = 0;
303     unsigned int tex_index;
304     int size = get_flexible_vertex_size(d3dvtVertexType);
305
306     lpvVertices = ((BYTE *) lpvVertices) + (size * dwStartVertex);
307     
308     if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
309         strided->position.lpvData = lpvVertices;
310         current_offset += 3 * sizeof(D3DVALUE);
311     } else {
312         strided->position.lpvData  = lpvVertices;
313         current_offset += 4 * sizeof(D3DVALUE);
314     }
315     if (d3dvtVertexType & D3DFVF_RESERVED1) {
316         current_offset += sizeof(DWORD);
317     }
318     if (d3dvtVertexType & D3DFVF_NORMAL) { 
319         strided->normal.lpvData  = ((char *) lpvVertices) + current_offset;
320         current_offset += 3 * sizeof(D3DVALUE);
321     }
322     if (d3dvtVertexType & D3DFVF_DIFFUSE) { 
323         strided->diffuse.lpvData  = ((char *) lpvVertices) + current_offset;
324         current_offset += sizeof(DWORD);
325     }
326     if (d3dvtVertexType & D3DFVF_SPECULAR) {
327         strided->specular.lpvData  = ((char *) lpvVertices) + current_offset;
328         current_offset += sizeof(DWORD);
329     }
330     for (tex_index = 0; tex_index < GET_TEXCOUNT_FROM_FVF(d3dvtVertexType); tex_index++) {
331         strided->textureCoords[tex_index].lpvData  = ((char *) lpvVertices) + current_offset;
332         current_offset += GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_index) * sizeof(D3DVALUE);
333     }
334     strided->position.dwStride = current_offset;
335     strided->normal.dwStride   = current_offset;
336     strided->diffuse.dwStride  = current_offset;
337     strided->specular.dwStride = current_offset;
338     for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++)
339         strided->textureCoords[tex_index].dwStride  = current_offset;   
340 }
341
342 void
343 dump_D3DVOP(DWORD dwVertexOp)
344 {
345     static const flag_info flags[] =
346     {
347         FE(D3DVOP_LIGHT),
348         FE(D3DVOP_CLIP),
349         FE(D3DVOP_EXTENTS),
350         FE(D3DVOP_TRANSFORM)
351     };
352     DDRAW_dump_flags(dwVertexOp, flags, sizeof(flags)/sizeof(flags[0]));
353 }
354
355 void
356 dump_D3DPV(DWORD dwFlags)
357 {
358     if (dwFlags == D3DPV_DONOTCOPYDATA) DPRINTF("D3DPV_DONOTCOPYDATA\n");
359     else if (dwFlags != 0) DPRINTF("Unknown !!!\n");
360     else DPRINTF("\n");
361 }
362
363 void multiply_matrix(LPD3DMATRIX dest, LPD3DMATRIX src1, LPD3DMATRIX src2)
364 {
365     D3DMATRIX temp;
366
367     /* Now do the multiplication 'by hand'.
368        I know that all this could be optimised, but this will be done later :-) */
369     temp._11 = (src1->_11 * src2->_11) + (src1->_21 * src2->_12) + (src1->_31 * src2->_13) + (src1->_41 * src2->_14);
370     temp._21 = (src1->_11 * src2->_21) + (src1->_21 * src2->_22) + (src1->_31 * src2->_23) + (src1->_41 * src2->_24);
371     temp._31 = (src1->_11 * src2->_31) + (src1->_21 * src2->_32) + (src1->_31 * src2->_33) + (src1->_41 * src2->_34);
372     temp._41 = (src1->_11 * src2->_41) + (src1->_21 * src2->_42) + (src1->_31 * src2->_43) + (src1->_41 * src2->_44);
373
374     temp._12 = (src1->_12 * src2->_11) + (src1->_22 * src2->_12) + (src1->_32 * src2->_13) + (src1->_42 * src2->_14);
375     temp._22 = (src1->_12 * src2->_21) + (src1->_22 * src2->_22) + (src1->_32 * src2->_23) + (src1->_42 * src2->_24);
376     temp._32 = (src1->_12 * src2->_31) + (src1->_22 * src2->_32) + (src1->_32 * src2->_33) + (src1->_42 * src2->_34);
377     temp._42 = (src1->_12 * src2->_41) + (src1->_22 * src2->_42) + (src1->_32 * src2->_43) + (src1->_42 * src2->_44);
378
379     temp._13 = (src1->_13 * src2->_11) + (src1->_23 * src2->_12) + (src1->_33 * src2->_13) + (src1->_43 * src2->_14);
380     temp._23 = (src1->_13 * src2->_21) + (src1->_23 * src2->_22) + (src1->_33 * src2->_23) + (src1->_43 * src2->_24);
381     temp._33 = (src1->_13 * src2->_31) + (src1->_23 * src2->_32) + (src1->_33 * src2->_33) + (src1->_43 * src2->_34);
382     temp._43 = (src1->_13 * src2->_41) + (src1->_23 * src2->_42) + (src1->_33 * src2->_43) + (src1->_43 * src2->_44);
383
384     temp._14 = (src1->_14 * src2->_11) + (src1->_24 * src2->_12) + (src1->_34 * src2->_13) + (src1->_44 * src2->_14);
385     temp._24 = (src1->_14 * src2->_21) + (src1->_24 * src2->_22) + (src1->_34 * src2->_23) + (src1->_44 * src2->_24);
386     temp._34 = (src1->_14 * src2->_31) + (src1->_24 * src2->_32) + (src1->_34 * src2->_33) + (src1->_44 * src2->_34);
387     temp._44 = (src1->_14 * src2->_41) + (src1->_24 * src2->_42) + (src1->_34 * src2->_43) + (src1->_44 * src2->_44);
388
389     /* And copy the new matrix in the good storage.. */
390     memcpy(dest, &temp, 16 * sizeof(D3DVALUE));    
391 }