[D3D8][D3D9][DDRAW][WINED3D] Sync with Wine Staging 2.9. This work couldn't have...
[reactos.git] / reactos / dll / directx / wine / ddraw / viewport.c
1 /* Direct3D Viewport
2 * Copyright (c) 1998 Lionel ULMER
3 * Copyright (c) 2006-2007 Stefan DÖSINGER
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "ddraw_private.h"
21
22 /*****************************************************************************
23 * Helper functions
24 *****************************************************************************/
25
26 static void update_clip_space(struct d3d_device *device,
27 struct wined3d_vec3 *scale, struct wined3d_vec3 *offset)
28 {
29 D3DMATRIX clip_space =
30 {
31 scale->x, 0.0f, 0.0f, 0.0f,
32 0.0f, scale->y, 0.0f, 0.0f,
33 0.0f, 0.0f, scale->z, 0.0f,
34 offset->x, offset->y, offset->z, 1.0f,
35 };
36 D3DMATRIX projection;
37
38 multiply_matrix(&projection, &clip_space, &device->legacy_projection);
39 wined3d_device_set_transform(device->wined3d_device,
40 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
41 device->legacy_clipspace = clip_space;
42 }
43
44 /*****************************************************************************
45 * viewport_activate
46 *
47 * activates the viewport using IDirect3DDevice7::SetViewport
48 *
49 *****************************************************************************/
50 void viewport_activate(struct d3d_viewport *This, BOOL ignore_lights)
51 {
52 struct wined3d_vec3 scale, offset;
53 D3DVIEWPORT7 vp;
54
55 if (!ignore_lights)
56 {
57 struct d3d_light *light;
58
59 /* Activate all the lights associated with this context */
60 LIST_FOR_EACH_ENTRY(light, &This->light_list, struct d3d_light, entry)
61 {
62 light_activate(light);
63 }
64 }
65
66 /* And copy the values in the structure used by the device */
67 if (This->use_vp2)
68 {
69 vp.dwX = This->viewports.vp2.dwX;
70 vp.dwY = This->viewports.vp2.dwY;
71 vp.dwHeight = This->viewports.vp2.dwHeight;
72 vp.dwWidth = This->viewports.vp2.dwWidth;
73 vp.dvMinZ = 0.0f;
74 vp.dvMaxZ = 1.0f;
75
76 scale.x = 2.0f / This->viewports.vp2.dvClipWidth;
77 scale.y = 2.0f / This->viewports.vp2.dvClipHeight;
78 scale.z = 1.0f / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ);
79 offset.x = -2.0f * This->viewports.vp2.dvClipX / This->viewports.vp2.dvClipWidth - 1.0f;
80 offset.y = -2.0f * This->viewports.vp2.dvClipY / This->viewports.vp2.dvClipHeight + 1.0f;
81 offset.z = -This->viewports.vp2.dvMinZ / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ);
82 }
83 else
84 {
85 vp.dwX = This->viewports.vp1.dwX;
86 vp.dwY = This->viewports.vp1.dwY;
87 vp.dwHeight = This->viewports.vp1.dwHeight;
88 vp.dwWidth = This->viewports.vp1.dwWidth;
89 vp.dvMinZ = 0.0f;
90 vp.dvMaxZ = 1.0f;
91
92 scale.x = 2.0f * This->viewports.vp1.dvScaleX / This->viewports.vp1.dwWidth;
93 scale.y = 2.0f * This->viewports.vp1.dvScaleY / This->viewports.vp1.dwHeight;
94 scale.z = 1.0f;
95 offset.x = 0.0f;
96 offset.y = 0.0f;
97 offset.z = 0.0f;
98 }
99
100 update_clip_space(This->active_device, &scale, &offset);
101 IDirect3DDevice7_SetViewport(&This->active_device->IDirect3DDevice7_iface, &vp);
102 }
103
104 /*****************************************************************************
105 * _dump_D3DVIEWPORT, _dump_D3DVIEWPORT2
106 *
107 * Writes viewport information to TRACE
108 *
109 *****************************************************************************/
110 static void _dump_D3DVIEWPORT(const D3DVIEWPORT *lpvp)
111 {
112 TRACE(" - dwSize = %d dwX = %d dwY = %d\n",
113 lpvp->dwSize, lpvp->dwX, lpvp->dwY);
114 TRACE(" - dwWidth = %d dwHeight = %d\n",
115 lpvp->dwWidth, lpvp->dwHeight);
116 TRACE(" - dvScaleX = %f dvScaleY = %f\n",
117 lpvp->dvScaleX, lpvp->dvScaleY);
118 TRACE(" - dvMaxX = %f dvMaxY = %f\n",
119 lpvp->dvMaxX, lpvp->dvMaxY);
120 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
121 lpvp->dvMinZ, lpvp->dvMaxZ);
122 }
123
124 static void _dump_D3DVIEWPORT2(const D3DVIEWPORT2 *lpvp)
125 {
126 TRACE(" - dwSize = %d dwX = %d dwY = %d\n",
127 lpvp->dwSize, lpvp->dwX, lpvp->dwY);
128 TRACE(" - dwWidth = %d dwHeight = %d\n",
129 lpvp->dwWidth, lpvp->dwHeight);
130 TRACE(" - dvClipX = %f dvClipY = %f\n",
131 lpvp->dvClipX, lpvp->dvClipY);
132 TRACE(" - dvClipWidth = %f dvClipHeight = %f\n",
133 lpvp->dvClipWidth, lpvp->dvClipHeight);
134 TRACE(" - dvMinZ = %f dvMaxZ = %f\n",
135 lpvp->dvMinZ, lpvp->dvMaxZ);
136 }
137
138 static inline struct d3d_viewport *impl_from_IDirect3DViewport3(IDirect3DViewport3 *iface)
139 {
140 return CONTAINING_RECORD(iface, struct d3d_viewport, IDirect3DViewport3_iface);
141 }
142
143 /*****************************************************************************
144 * IUnknown Methods.
145 *****************************************************************************/
146
147 /*****************************************************************************
148 * IDirect3DViewport3::QueryInterface
149 *
150 * A normal QueryInterface. Can query all interface versions and the
151 * IUnknown interface. The VTables of the different versions
152 * are equal
153 *
154 * Params:
155 * refiid: Interface id queried for
156 * obj: Address to write the interface pointer to
157 *
158 * Returns:
159 * S_OK on success.
160 * E_NOINTERFACE if the requested interface wasn't found
161 *
162 *****************************************************************************/
163 static HRESULT WINAPI d3d_viewport_QueryInterface(IDirect3DViewport3 *iface, REFIID riid, void **object)
164 {
165 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
166
167 if (IsEqualGUID(&IID_IDirect3DViewport3, riid)
168 || IsEqualGUID(&IID_IDirect3DViewport2, riid)
169 || IsEqualGUID(&IID_IDirect3DViewport, riid)
170 || IsEqualGUID(&IID_IUnknown, riid))
171 {
172 IDirect3DViewport3_AddRef(iface);
173 *object = iface;
174 return S_OK;
175 }
176
177 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
178
179 *object = NULL;
180 return E_NOINTERFACE;
181 }
182
183 /*****************************************************************************
184 * IDirect3DViewport3::AddRef
185 *
186 * Increases the refcount.
187 *
188 * Returns:
189 * The new refcount
190 *
191 *****************************************************************************/
192 static ULONG WINAPI d3d_viewport_AddRef(IDirect3DViewport3 *iface)
193 {
194 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
195 ULONG ref = InterlockedIncrement(&viewport->ref);
196
197 TRACE("%p increasing refcount to %u.\n", viewport, ref);
198
199 return ref;
200 }
201
202 /*****************************************************************************
203 * IDirect3DViewport3::Release
204 *
205 * Reduces the refcount. If it falls to 0, the interface is released
206 *
207 * Returns:
208 * The new refcount
209 *
210 *****************************************************************************/
211 static ULONG WINAPI d3d_viewport_Release(IDirect3DViewport3 *iface)
212 {
213 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
214 ULONG ref = InterlockedDecrement(&viewport->ref);
215
216 TRACE("%p decreasing refcount to %u.\n", viewport, ref);
217
218 if (!ref)
219 HeapFree(GetProcessHeap(), 0, viewport);
220
221 return ref;
222 }
223
224 /*****************************************************************************
225 * IDirect3DViewport Methods.
226 *****************************************************************************/
227
228 /*****************************************************************************
229 * IDirect3DViewport3::Initialize
230 *
231 * No-op initialization.
232 *
233 * Params:
234 * Direct3D: The direct3D device this viewport is assigned to
235 *
236 * Returns:
237 * DDERR_ALREADYINITIALIZED
238 *
239 *****************************************************************************/
240 static HRESULT WINAPI d3d_viewport_Initialize(IDirect3DViewport3 *iface, IDirect3D *d3d)
241 {
242 TRACE("iface %p, d3d %p.\n", iface, d3d);
243
244 return DDERR_ALREADYINITIALIZED;
245 }
246
247 /*****************************************************************************
248 * IDirect3DViewport3::GetViewport
249 *
250 * Returns the viewport data assigned to this viewport interface
251 *
252 * Params:
253 * Data: Address to store the data
254 *
255 * Returns:
256 * D3D_OK on success
257 * DDERR_INVALIDPARAMS if Data is NULL
258 *
259 *****************************************************************************/
260 static HRESULT WINAPI d3d_viewport_GetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *lpData)
261 {
262 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
263 DWORD dwSize;
264
265 TRACE("iface %p, data %p.\n", iface, lpData);
266
267 wined3d_mutex_lock();
268
269 dwSize = lpData->dwSize;
270 if (!This->use_vp2)
271 memcpy(lpData, &(This->viewports.vp1), dwSize);
272 else {
273 D3DVIEWPORT vp1;
274 vp1.dwSize = sizeof(vp1);
275 vp1.dwX = This->viewports.vp2.dwX;
276 vp1.dwY = This->viewports.vp2.dwY;
277 vp1.dwWidth = This->viewports.vp2.dwWidth;
278 vp1.dwHeight = This->viewports.vp2.dwHeight;
279 vp1.dvMaxX = 0.0;
280 vp1.dvMaxY = 0.0;
281 vp1.dvScaleX = 0.0;
282 vp1.dvScaleY = 0.0;
283 vp1.dvMinZ = This->viewports.vp2.dvMinZ;
284 vp1.dvMaxZ = This->viewports.vp2.dvMaxZ;
285 memcpy(lpData, &vp1, dwSize);
286 }
287
288 if (TRACE_ON(ddraw))
289 {
290 TRACE(" returning D3DVIEWPORT :\n");
291 _dump_D3DVIEWPORT(lpData);
292 }
293
294 wined3d_mutex_unlock();
295
296 return DD_OK;
297 }
298
299 /*****************************************************************************
300 * IDirect3DViewport3::SetViewport
301 *
302 * Sets the viewport information for this interface
303 *
304 * Params:
305 * lpData: Viewport to set
306 *
307 * Returns:
308 * D3D_OK on success
309 * DDERR_INVALIDPARAMS if Data is NULL
310 *
311 *****************************************************************************/
312 static HRESULT WINAPI d3d_viewport_SetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *lpData)
313 {
314 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
315 IDirect3DViewport3 *current_viewport;
316
317 TRACE("iface %p, data %p.\n", iface, lpData);
318
319 if (TRACE_ON(ddraw))
320 {
321 TRACE(" getting D3DVIEWPORT :\n");
322 _dump_D3DVIEWPORT(lpData);
323 }
324
325 wined3d_mutex_lock();
326
327 This->use_vp2 = 0;
328 memset(&(This->viewports.vp1), 0, sizeof(This->viewports.vp1));
329 memcpy(&(This->viewports.vp1), lpData, lpData->dwSize);
330
331 /* Tests on two games show that these values are never used properly so override
332 them with proper ones :-)
333 */
334 This->viewports.vp1.dvMinZ = 0.0;
335 This->viewports.vp1.dvMaxZ = 1.0;
336
337 if (This->active_device)
338 {
339 IDirect3DDevice3 *d3d_device3 = &This->active_device->IDirect3DDevice3_iface;
340 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport)))
341 {
342 if (current_viewport == iface) viewport_activate(This, FALSE);
343 IDirect3DViewport3_Release(current_viewport);
344 }
345 }
346
347 wined3d_mutex_unlock();
348
349 return DD_OK;
350 }
351
352 /*****************************************************************************
353 * IDirect3DViewport3::TransformVertices
354 *
355 * Transforms vertices by the transformation matrix.
356 *
357 * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices,
358 * so it's tempting to forward it to there. However, there are some
359 * tiny differences. First, the lpOffscreen flag that is reported back,
360 * then there is the homogeneous vertex that is generated. Also there's a lack
361 * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some
362 * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to
363 * ProcessVertices doesn't pay of in terms of wrapper code needed and code
364 * reused.
365 *
366 * Params:
367 * dwVertexCount: The number of vertices to be transformed
368 * data: Pointer to the vertex input / output data.
369 * dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED
370 * offscreen: Logical AND of the planes that clipped the vertices if clipping
371 * is on. 0 if clipping is off.
372 *
373 * Returns:
374 * D3D_OK on success
375 * D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device
376 * DDERR_INVALIDPARAMS if no clipping flag is specified
377 *
378 *****************************************************************************/
379 struct transform_vertices_vertex
380 {
381 float x, y, z, w; /* w is unused in input data. */
382 struct
383 {
384 DWORD p[4];
385 } payload;
386 };
387
388 static HRESULT WINAPI d3d_viewport_TransformVertices(IDirect3DViewport3 *iface,
389 DWORD dwVertexCount, D3DTRANSFORMDATA *data, DWORD dwFlags, DWORD *offscreen)
390 {
391 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
392 D3DVIEWPORT vp = viewport->viewports.vp1;
393 D3DMATRIX view_mat, world_mat, proj_mat, mat;
394 struct transform_vertices_vertex *in, *out;
395 float x, y, z, w;
396 unsigned int i;
397 D3DHVERTEX *outH;
398 struct d3d_device *device = viewport->active_device;
399 BOOL activate = device->current_viewport != viewport;
400
401 TRACE("iface %p, vertex_count %u, data %p, flags %#x, offscreen %p.\n",
402 iface, dwVertexCount, data, dwFlags, offscreen);
403
404 /* Tests on windows show that Windows crashes when this occurs,
405 * so don't return the (intuitive) return value
406 if (!device)
407 {
408 WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n");
409 return D3DERR_VIEWPORTHASNODEVICE;
410 }
411 */
412
413 if (!data || data->dwSize != sizeof(*data))
414 {
415 WARN("Transform data is NULL or size is incorrect, returning DDERR_INVALIDPARAMS\n");
416 return DDERR_INVALIDPARAMS;
417 }
418 if (!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED)))
419 {
420 WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n");
421 return DDERR_INVALIDPARAMS;
422 }
423
424 wined3d_mutex_lock();
425 if (activate)
426 viewport_activate(viewport, TRUE);
427
428 wined3d_device_get_transform(device->wined3d_device,
429 D3DTRANSFORMSTATE_VIEW, (struct wined3d_matrix *)&view_mat);
430 wined3d_device_get_transform(device->wined3d_device,
431 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)&world_mat);
432 wined3d_device_get_transform(device->wined3d_device,
433 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&proj_mat);
434 multiply_matrix(&mat, &view_mat, &world_mat);
435 multiply_matrix(&mat, &proj_mat, &mat);
436
437 /* The pointer is not tested against NULL on Windows. */
438 if (dwFlags & D3DTRANSFORM_CLIPPED)
439 *offscreen = ~0U;
440 else
441 *offscreen = 0;
442
443 outH = data->lpHOut;
444 for(i = 0; i < dwVertexCount; i++)
445 {
446 in = (struct transform_vertices_vertex *)((char *)data->lpIn + data->dwInSize * i);
447 out = (struct transform_vertices_vertex *)((char *)data->lpOut + data->dwOutSize * i);
448
449 x = (in->x * mat._11) + (in->y * mat._21) + (in->z * mat._31) + mat._41;
450 y = (in->x * mat._12) + (in->y * mat._22) + (in->z * mat._32) + mat._42;
451 z = (in->x * mat._13) + (in->y * mat._23) + (in->z * mat._33) + mat._43;
452 w = (in->x * mat._14) + (in->y * mat._24) + (in->z * mat._34) + mat._44;
453
454 if(dwFlags & D3DTRANSFORM_CLIPPED)
455 {
456 /* If clipping is enabled, Windows assumes that outH is
457 * a valid pointer. */
458 outH[i].u1.hx = (x - device->legacy_clipspace._41 * w) / device->legacy_clipspace._11;
459 outH[i].u2.hy = (y - device->legacy_clipspace._42 * w) / device->legacy_clipspace._22;
460 outH[i].u3.hz = (z - device->legacy_clipspace._43 * w) / device->legacy_clipspace._33;
461
462 outH[i].dwFlags = 0;
463 if (x > w)
464 outH[i].dwFlags |= D3DCLIP_RIGHT;
465 if (x < -w)
466 outH[i].dwFlags |= D3DCLIP_LEFT;
467 if (y > w)
468 outH[i].dwFlags |= D3DCLIP_TOP;
469 if (y < -w)
470 outH[i].dwFlags |= D3DCLIP_BOTTOM;
471 if (z < 0.0f)
472 outH[i].dwFlags |= D3DCLIP_FRONT;
473 if (z > w)
474 outH[i].dwFlags |= D3DCLIP_BACK;
475
476 *offscreen &= outH[i].dwFlags;
477
478 if(outH[i].dwFlags)
479 {
480 /* Looks like native just drops the vertex, leaves whatever data
481 * it has in the output buffer and goes on with the next vertex.
482 * The exact scheme hasn't been figured out yet, but windows
483 * definitely writes something there.
484 */
485 out->x = x;
486 out->y = y;
487 out->z = z;
488 out->w = w;
489 continue;
490 }
491 }
492
493 w = 1 / w;
494 x *= w; y *= w; z *= w;
495
496 out->x = (x + 1.0f) * vp.dwWidth * 0.5 + vp.dwX;
497 out->y = (-y + 1.0f) * vp.dwHeight * 0.5 + vp.dwY;
498 out->z = z;
499 out->w = w;
500 out->payload = in->payload;
501 }
502
503 if (activate && device->current_viewport)
504 viewport_activate(device->current_viewport, TRUE);
505
506 wined3d_mutex_unlock();
507
508 TRACE("All done\n");
509 return DD_OK;
510 }
511
512 /*****************************************************************************
513 * IDirect3DViewport3::LightElements
514 *
515 * The DirectX 5.0 sdk says that it's not implemented
516 *
517 * Params:
518 * ?
519 *
520 * Returns:
521 * DDERR_UNSUPPORTED
522 *
523 *****************************************************************************/
524 static HRESULT WINAPI d3d_viewport_LightElements(IDirect3DViewport3 *iface,
525 DWORD element_count, D3DLIGHTDATA *data)
526 {
527 TRACE("iface %p, element_count %u, data %p.\n", iface, element_count, data);
528
529 return DDERR_UNSUPPORTED;
530 }
531
532 static HRESULT WINAPI d3d_viewport_SetBackground(IDirect3DViewport3 *iface, D3DMATERIALHANDLE material)
533 {
534 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
535 struct d3d_material *m;
536
537 TRACE("iface %p, material %#x.\n", iface, material);
538
539 wined3d_mutex_lock();
540
541 if (!(m = ddraw_get_object(&viewport->ddraw->d3ddevice->handle_table, material - 1, DDRAW_HANDLE_MATERIAL)))
542 {
543 WARN("Invalid material handle %#x.\n", material);
544 wined3d_mutex_unlock();
545 return DDERR_INVALIDPARAMS;
546 }
547
548 TRACE("Setting background color : %.8e %.8e %.8e %.8e.\n",
549 m->mat.u.diffuse.u1.r, m->mat.u.diffuse.u2.g,
550 m->mat.u.diffuse.u3.b, m->mat.u.diffuse.u4.a);
551 viewport->background = m;
552
553 wined3d_mutex_unlock();
554
555 return D3D_OK;
556 }
557
558 /*****************************************************************************
559 * IDirect3DViewport3::GetBackground
560 *
561 * Returns the material handle assigned to the background of the viewport
562 *
563 * Params:
564 * lphMat: Address to store the handle
565 * lpValid: is set to FALSE if no background is set, TRUE if one is set
566 *
567 * Returns:
568 * D3D_OK
569 *
570 *****************************************************************************/
571 static HRESULT WINAPI d3d_viewport_GetBackground(IDirect3DViewport3 *iface,
572 D3DMATERIALHANDLE *material, BOOL *valid)
573 {
574 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
575
576 TRACE("iface %p, material %p, valid %p.\n", iface, material, valid);
577
578 wined3d_mutex_lock();
579 if (valid)
580 *valid = !!viewport->background;
581 if (material)
582 *material = viewport->background ? viewport->background->Handle : 0;
583 wined3d_mutex_unlock();
584
585 return D3D_OK;
586 }
587
588 /*****************************************************************************
589 * IDirect3DViewport3::SetBackgroundDepth
590 *
591 * Sets a surface that represents the background depth. Its contents are
592 * used to set the depth buffer in IDirect3DViewport3::Clear
593 *
594 * Params:
595 * lpDDSurface: Surface to set
596 *
597 * Returns: D3D_OK, because it's a stub
598 *
599 *****************************************************************************/
600 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth(IDirect3DViewport3 *iface, IDirectDrawSurface *surface)
601 {
602 FIXME("iface %p, surface %p stub!\n", iface, surface);
603
604 return D3D_OK;
605 }
606
607 /*****************************************************************************
608 * IDirect3DViewport3::GetBackgroundDepth
609 *
610 * Returns the surface that represents the depth field
611 *
612 * Params:
613 * lplpDDSurface: Address to store the interface pointer
614 * lpValid: Set to TRUE if a depth is assigned, FALSE otherwise
615 *
616 * Returns:
617 * D3D_OK, because it's a stub
618 * (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL)
619 *
620 *****************************************************************************/
621 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth(IDirect3DViewport3 *iface,
622 IDirectDrawSurface **surface, BOOL *valid)
623 {
624 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid);
625
626 return DD_OK;
627 }
628
629 /*****************************************************************************
630 * IDirect3DViewport3::Clear
631 *
632 * Clears the render target and / or the z buffer
633 *
634 * Params:
635 * dwCount: The amount of rectangles to clear. If 0, the whole buffer is
636 * cleared
637 * lpRects: Pointer to the array of rectangles. If NULL, Count must be 0
638 * dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET
639 *
640 * Returns:
641 * D3D_OK on success
642 * D3DERR_VIEWPORTHASNODEVICE if there's no active device
643 * The return value of IDirect3DDevice7::Clear
644 *
645 *****************************************************************************/
646 static HRESULT WINAPI d3d_viewport_Clear(IDirect3DViewport3 *iface,
647 DWORD rect_count, D3DRECT *rects, DWORD flags)
648 {
649 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
650 DWORD color = 0x00000000;
651 HRESULT hr;
652 IDirect3DViewport3 *current_viewport;
653 IDirect3DDevice3 *d3d_device3;
654
655 TRACE("iface %p, rect_count %u, rects %p, flags %#x.\n", iface, rect_count, rects, flags);
656
657 if (!rects || !rect_count)
658 {
659 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects);
660 return D3D_OK;
661 }
662
663 if (This->active_device == NULL) {
664 ERR(" Trying to clear a viewport not attached to a device!\n");
665 return D3DERR_VIEWPORTHASNODEVICE;
666 }
667 d3d_device3 = &This->active_device->IDirect3DDevice3_iface;
668
669 wined3d_mutex_lock();
670
671 if (flags & D3DCLEAR_TARGET)
672 {
673 if (!This->background)
674 WARN("No background material set.\n");
675 else
676 color = D3DRGBA(This->background->mat.u.diffuse.u1.r,
677 This->background->mat.u.diffuse.u2.g,
678 This->background->mat.u.diffuse.u3.b,
679 This->background->mat.u.diffuse.u4.a);
680 }
681
682 /* Need to temporarily activate the viewport to clear it. The previously
683 * active one will be restored afterwards. */
684 viewport_activate(This, TRUE);
685
686 hr = IDirect3DDevice7_Clear(&This->active_device->IDirect3DDevice7_iface, rect_count, rects,
687 flags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET), color, 1.0, 0x00000000);
688
689 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport)))
690 {
691 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport);
692 viewport_activate(vp, TRUE);
693 IDirect3DViewport3_Release(current_viewport);
694 }
695
696 wined3d_mutex_unlock();
697
698 return hr;
699 }
700
701 /*****************************************************************************
702 * IDirect3DViewport3::AddLight
703 *
704 * Adds an light to the viewport
705 *
706 * Params:
707 * lpDirect3DLight: Interface of the light to add
708 *
709 * Returns:
710 * D3D_OK on success
711 * DDERR_INVALIDPARAMS if Direct3DLight is NULL
712 * DDERR_INVALIDPARAMS if there are 8 lights or more
713 *
714 *****************************************************************************/
715 static HRESULT WINAPI d3d_viewport_AddLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight)
716 {
717 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
718 struct d3d_light *light_impl = unsafe_impl_from_IDirect3DLight(lpDirect3DLight);
719 DWORD i = 0;
720 DWORD map = This->map_lights;
721
722 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight);
723
724 wined3d_mutex_lock();
725
726 if (This->num_lights >= 8)
727 {
728 wined3d_mutex_unlock();
729 return DDERR_INVALIDPARAMS;
730 }
731
732 /* Find a light number and update both light and viewports objects accordingly */
733 while (map & 1)
734 {
735 map >>= 1;
736 ++i;
737 }
738 light_impl->dwLightIndex = i;
739 This->num_lights++;
740 This->map_lights |= 1<<i;
741
742 /* Add the light in the 'linked' chain */
743 list_add_head(&This->light_list, &light_impl->entry);
744 IDirect3DLight_AddRef(lpDirect3DLight);
745
746 /* Attach the light to the viewport */
747 light_impl->active_viewport = This;
748
749 /* If active, activate the light */
750 if (This->active_device && light_impl->light.dwFlags & D3DLIGHT_ACTIVE)
751 {
752 /* Disable the flag so that light_activate actually does its job. */
753 light_impl->light.dwFlags &= ~D3DLIGHT_ACTIVE;
754 light_activate(light_impl);
755 }
756
757 wined3d_mutex_unlock();
758
759 return D3D_OK;
760 }
761
762 /*****************************************************************************
763 * IDirect3DViewport3::DeleteLight
764 *
765 * Deletes a light from the viewports' light list
766 *
767 * Params:
768 * lpDirect3DLight: Light to delete
769 *
770 * Returns:
771 * D3D_OK on success
772 * DDERR_INVALIDPARAMS if the light wasn't found
773 *
774 *****************************************************************************/
775 static HRESULT WINAPI d3d_viewport_DeleteLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight)
776 {
777 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
778 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight);
779
780 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight);
781
782 wined3d_mutex_lock();
783
784 if (l->active_viewport != viewport)
785 {
786 WARN("Light %p active viewport is %p.\n", l, l->active_viewport);
787 wined3d_mutex_unlock();
788 return DDERR_INVALIDPARAMS;
789 }
790
791 light_deactivate(l);
792 list_remove(&l->entry);
793 l->active_viewport = NULL;
794 IDirect3DLight_Release(lpDirect3DLight);
795 --viewport->num_lights;
796 viewport->map_lights &= ~(1 << l->dwLightIndex);
797
798 wined3d_mutex_unlock();
799
800 return D3D_OK;
801 }
802
803 /*****************************************************************************
804 * IDirect3DViewport::NextLight
805 *
806 * Enumerates the lights associated with the viewport
807 *
808 * Params:
809 * lpDirect3DLight: Light to start with
810 * lplpDirect3DLight: Address to store the successor to
811 *
812 * Returns:
813 * D3D_OK, because it's a stub
814 *
815 *****************************************************************************/
816 static HRESULT WINAPI d3d_viewport_NextLight(IDirect3DViewport3 *iface,
817 IDirect3DLight *lpDirect3DLight, IDirect3DLight **lplpDirect3DLight, DWORD flags)
818 {
819 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
820 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight);
821 struct list *entry;
822 HRESULT hr;
823
824 TRACE("iface %p, light %p, next_light %p, flags %#x.\n",
825 iface, lpDirect3DLight, lplpDirect3DLight, flags);
826
827 if (!lplpDirect3DLight)
828 return DDERR_INVALIDPARAMS;
829
830 wined3d_mutex_lock();
831
832 switch (flags)
833 {
834 case D3DNEXT_NEXT:
835 if (!l || l->active_viewport != viewport)
836 {
837 if (l)
838 WARN("Light %p active viewport is %p.\n", l, l->active_viewport);
839 entry = NULL;
840 }
841 else
842 entry = list_next(&viewport->light_list, &l->entry);
843 break;
844
845 case D3DNEXT_HEAD:
846 entry = list_head(&viewport->light_list);
847 break;
848
849 case D3DNEXT_TAIL:
850 entry = list_tail(&viewport->light_list);
851 break;
852
853 default:
854 entry = NULL;
855 WARN("Invalid flags %#x.\n", flags);
856 break;
857 }
858
859 if (entry)
860 {
861 *lplpDirect3DLight = (IDirect3DLight *)LIST_ENTRY(entry, struct d3d_light, entry);
862 IDirect3DLight_AddRef(*lplpDirect3DLight);
863 hr = D3D_OK;
864 }
865 else
866 {
867 *lplpDirect3DLight = NULL;
868 hr = DDERR_INVALIDPARAMS;
869 }
870
871 wined3d_mutex_unlock();
872
873 return hr;
874 }
875
876 /*****************************************************************************
877 * IDirect3DViewport2 Methods.
878 *****************************************************************************/
879
880 /*****************************************************************************
881 * IDirect3DViewport3::GetViewport2
882 *
883 * Returns the currently set viewport in a D3DVIEWPORT2 structure.
884 * Similar to IDirect3DViewport3::GetViewport
885 *
886 * Params:
887 * lpData: Pointer to the structure to fill
888 *
889 * Returns:
890 * D3D_OK on success
891 * DDERR_INVALIDPARAMS if the viewport was set with
892 * IDirect3DViewport3::SetViewport
893 * DDERR_INVALIDPARAMS if Data is NULL
894 *
895 *****************************************************************************/
896 static HRESULT WINAPI d3d_viewport_GetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *lpData)
897 {
898 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
899 DWORD dwSize;
900
901 TRACE("iface %p, data %p.\n", iface, lpData);
902
903 wined3d_mutex_lock();
904 dwSize = lpData->dwSize;
905 if (This->use_vp2)
906 memcpy(lpData, &(This->viewports.vp2), dwSize);
907 else {
908 D3DVIEWPORT2 vp2;
909 vp2.dwSize = sizeof(vp2);
910 vp2.dwX = This->viewports.vp1.dwX;
911 vp2.dwY = This->viewports.vp1.dwY;
912 vp2.dwWidth = This->viewports.vp1.dwWidth;
913 vp2.dwHeight = This->viewports.vp1.dwHeight;
914 vp2.dvClipX = 0.0;
915 vp2.dvClipY = 0.0;
916 vp2.dvClipWidth = 0.0;
917 vp2.dvClipHeight = 0.0;
918 vp2.dvMinZ = This->viewports.vp1.dvMinZ;
919 vp2.dvMaxZ = This->viewports.vp1.dvMaxZ;
920 memcpy(lpData, &vp2, dwSize);
921 }
922
923 if (TRACE_ON(ddraw))
924 {
925 TRACE(" returning D3DVIEWPORT2 :\n");
926 _dump_D3DVIEWPORT2(lpData);
927 }
928
929 wined3d_mutex_unlock();
930
931 return D3D_OK;
932 }
933
934 /*****************************************************************************
935 * IDirect3DViewport3::SetViewport2
936 *
937 * Sets the viewport from a D3DVIEWPORT2 structure
938 *
939 * Params:
940 * lpData: Viewport to set
941 *
942 * Returns:
943 * D3D_OK on success
944 *
945 *****************************************************************************/
946 static HRESULT WINAPI d3d_viewport_SetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *lpData)
947 {
948 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface);
949 IDirect3DViewport3 *current_viewport;
950
951 TRACE("iface %p, data %p.\n", iface, lpData);
952
953 if (TRACE_ON(ddraw))
954 {
955 TRACE(" getting D3DVIEWPORT2 :\n");
956 _dump_D3DVIEWPORT2(lpData);
957 }
958
959 wined3d_mutex_lock();
960
961 This->use_vp2 = 1;
962 memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2));
963 memcpy(&(This->viewports.vp2), lpData, lpData->dwSize);
964
965 if (This->active_device)
966 {
967 IDirect3DDevice3 *d3d_device3 = &This->active_device->IDirect3DDevice3_iface;
968 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport)))
969 {
970 if (current_viewport == iface) viewport_activate(This, FALSE);
971 IDirect3DViewport3_Release(current_viewport);
972 }
973 }
974
975 wined3d_mutex_unlock();
976
977 return D3D_OK;
978 }
979
980 /*****************************************************************************
981 * IDirect3DViewport3 Methods.
982 *****************************************************************************/
983
984 /*****************************************************************************
985 * IDirect3DViewport3::SetBackgroundDepth2
986 *
987 * Sets a IDirectDrawSurface4 surface as the background depth surface
988 *
989 * Params:
990 * lpDDS: Surface to set
991 *
992 * Returns:
993 * D3D_OK, because it's stub
994 *
995 *****************************************************************************/
996 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth2(IDirect3DViewport3 *iface,
997 IDirectDrawSurface4 *surface)
998 {
999 FIXME("iface %p, surface %p stub!\n", iface, surface);
1000
1001 return D3D_OK;
1002 }
1003
1004 /*****************************************************************************
1005 * IDirect3DViewport3::GetBackgroundDepth2
1006 *
1007 * Returns the IDirect3DSurface4 interface to the background depth surface
1008 *
1009 * Params:
1010 * lplpDDS: Address to store the interface pointer at
1011 * lpValid: Set to true if a surface is assigned
1012 *
1013 * Returns:
1014 * D3D_OK because it's a stub
1015 *
1016 *****************************************************************************/
1017 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth2(IDirect3DViewport3 *iface,
1018 IDirectDrawSurface4 **surface, BOOL *valid)
1019 {
1020 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid);
1021
1022 return D3D_OK;
1023 }
1024
1025 /*****************************************************************************
1026 * IDirect3DViewport3::Clear2
1027 *
1028 * Another clearing method
1029 *
1030 * Params:
1031 * Count: Number of rectangles to clear
1032 * Rects: Rectangle array to clear
1033 * Flags: Some flags :)
1034 * Color: Color to fill the render target with
1035 * Z: Value to fill the depth buffer with
1036 * Stencil: Value to fill the stencil bits with
1037 *
1038 * Returns:
1039 *
1040 *****************************************************************************/
1041 static HRESULT WINAPI d3d_viewport_Clear2(IDirect3DViewport3 *iface, DWORD rect_count,
1042 D3DRECT *rects, DWORD flags, DWORD color, D3DVALUE depth, DWORD stencil)
1043 {
1044 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface);
1045 HRESULT hr;
1046 IDirect3DViewport3 *current_viewport;
1047 IDirect3DDevice3 *d3d_device3;
1048
1049 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
1050 iface, rect_count, rects, flags, color, depth, stencil);
1051
1052 if (!rects || !rect_count)
1053 {
1054 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects);
1055 return D3D_OK;
1056 }
1057
1058 wined3d_mutex_lock();
1059
1060 if (!viewport->active_device)
1061 {
1062 WARN("Trying to clear a viewport not attached to a device.\n");
1063 wined3d_mutex_unlock();
1064 return D3DERR_VIEWPORTHASNODEVICE;
1065 }
1066 d3d_device3 = &viewport->active_device->IDirect3DDevice3_iface;
1067 /* Need to temporarily activate viewport to clear it. Previously active
1068 * one will be restored afterwards. */
1069 viewport_activate(viewport, TRUE);
1070
1071 hr = IDirect3DDevice7_Clear(&viewport->active_device->IDirect3DDevice7_iface,
1072 rect_count, rects, flags, color, depth, stencil);
1073 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport)))
1074 {
1075 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport);
1076 viewport_activate(vp, TRUE);
1077 IDirect3DViewport3_Release(current_viewport);
1078 }
1079
1080 wined3d_mutex_unlock();
1081
1082 return hr;
1083 }
1084
1085 /*****************************************************************************
1086 * The VTable
1087 *****************************************************************************/
1088
1089 static const struct IDirect3DViewport3Vtbl d3d_viewport_vtbl =
1090 {
1091 /*** IUnknown Methods ***/
1092 d3d_viewport_QueryInterface,
1093 d3d_viewport_AddRef,
1094 d3d_viewport_Release,
1095 /*** IDirect3DViewport Methods */
1096 d3d_viewport_Initialize,
1097 d3d_viewport_GetViewport,
1098 d3d_viewport_SetViewport,
1099 d3d_viewport_TransformVertices,
1100 d3d_viewport_LightElements,
1101 d3d_viewport_SetBackground,
1102 d3d_viewport_GetBackground,
1103 d3d_viewport_SetBackgroundDepth,
1104 d3d_viewport_GetBackgroundDepth,
1105 d3d_viewport_Clear,
1106 d3d_viewport_AddLight,
1107 d3d_viewport_DeleteLight,
1108 d3d_viewport_NextLight,
1109 /*** IDirect3DViewport2 Methods ***/
1110 d3d_viewport_GetViewport2,
1111 d3d_viewport_SetViewport2,
1112 /*** IDirect3DViewport3 Methods ***/
1113 d3d_viewport_SetBackgroundDepth2,
1114 d3d_viewport_GetBackgroundDepth2,
1115 d3d_viewport_Clear2,
1116 };
1117
1118 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport3(IDirect3DViewport3 *iface)
1119 {
1120 if (!iface) return NULL;
1121 assert(iface->lpVtbl == &d3d_viewport_vtbl);
1122 return CONTAINING_RECORD(iface, struct d3d_viewport, IDirect3DViewport3_iface);
1123 }
1124
1125 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport2(IDirect3DViewport2 *iface)
1126 {
1127 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */
1128 if (!iface) return NULL;
1129 assert(iface->lpVtbl == (IDirect3DViewport2Vtbl *)&d3d_viewport_vtbl);
1130 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface);
1131 }
1132
1133 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport(IDirect3DViewport *iface)
1134 {
1135 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */
1136 if (!iface) return NULL;
1137 assert(iface->lpVtbl == (IDirect3DViewportVtbl *)&d3d_viewport_vtbl);
1138 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface);
1139 }
1140
1141 void d3d_viewport_init(struct d3d_viewport *viewport, struct ddraw *ddraw)
1142 {
1143 viewport->IDirect3DViewport3_iface.lpVtbl = &d3d_viewport_vtbl;
1144 viewport->ref = 1;
1145 viewport->ddraw = ddraw;
1146 viewport->use_vp2 = 0xff;
1147 list_init(&viewport->light_list);
1148 }