[PATCH 6/7] ddraw: Fix d3d6 version of ComputeSphereVisibility().

Matteo Bruni mbruni at codeweavers.com
Mon Mar 13 18:09:57 CDT 2017


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
Might help with bug 40465 (this essentially implements comment 3).

 dlls/ddraw/device.c | 122 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 88 insertions(+), 34 deletions(-)

diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index 6e212c9..772ce3e 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -4494,46 +4494,48 @@ static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface
  *
  *****************************************************************************/
 
-static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius)
+static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius, BOOL equality)
 {
     float distance, norm;
 
     norm = sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
     distance = (p.x * center.u1.x + p.y * center.u2.y + p.z * center.u3.z + p.w) / norm;
 
-    if (fabs(distance) < radius)
-        return D3DSTATUS_CLIPUNIONLEFT << idx;
-    if (distance < -radius)
-        return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
+    if (equality)
+    {
+        if (fabs(distance) <= radius)
+            return D3DSTATUS_CLIPUNIONLEFT << idx;
+        if (distance <= -radius)
+            return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
+    }
+    else
+    {
+        if (fabs(distance) < radius)
+            return D3DSTATUS_CLIPUNIONLEFT << idx;
+        if (distance < -radius)
+            return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
+    }
     return 0;
 }
 
-static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
-        D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
+static void prepare_clip_space_planes(struct d3d_device *device, struct wined3d_vec4 *plane)
 {
-    struct wined3d_vec4 plane[12];
-    DWORD enabled_planes;
     D3DMATRIX m, temp;
-    HRESULT hr;
-    UINT i, j;
 
-    TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
-            iface, centers, radii, sphere_count, flags, return_values);
+    /* We want the wined3d matrices since those include the legacy viewport
+     * transformation. */
+    wined3d_mutex_lock();
+    wined3d_device_get_transform(device->wined3d_device,
+            WINED3D_TS_WORLD, (struct wined3d_matrix *)&m);
 
-    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
-    if (hr != DD_OK)
-        return DDERR_INVALIDPARAMS;
-    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
-    if (hr != DD_OK)
-        return DDERR_INVALIDPARAMS;
+    wined3d_device_get_transform(device->wined3d_device,
+            WINED3D_TS_VIEW, (struct wined3d_matrix *)&temp);
     multiply_matrix(&m, &temp, &m);
 
-    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
-    if (hr != DD_OK)
-        return DDERR_INVALIDPARAMS;
+    wined3d_device_get_transform(device->wined3d_device,
+            WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&temp);
     multiply_matrix(&m, &temp, &m);
-
-    IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &enabled_planes);
+    wined3d_mutex_unlock();
 
     /* Left plane. */
     plane[0].x = m._14 + m._11;
@@ -4570,33 +4572,85 @@ static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *ifac
     plane[5].y = m._24 - m._23;
     plane[5].z = m._34 - m._33;
     plane[5].w = m._44 - m._43;
+}
 
-    for (j = 6; j < 12; ++j)
-        IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
+static void compute_sphere_visibility(struct wined3d_vec4 plane[12], DWORD enabled_planes, BOOL equality,
+        D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD *return_values)
+{
+    UINT i, j;
 
     for (i = 0; i < sphere_count; ++i)
     {
         return_values[i] = 0;
-        for (j = 0; j < 6; ++j)
-            return_values[i] |= in_plane(j, plane[j], centers[i], radii[i]);
-        for (; j < 12; ++j)
-            if (enabled_planes & 1u << (j - 6))
-                return_values[i] |= in_plane(j, plane[j], centers[i], radii[i]);
+        for (j = 0; j < 12; ++j)
+            if (enabled_planes & 1u << j)
+                return_values[i] |= in_plane(j, plane[j], centers[i], radii[i], equality);
     }
+}
+
+static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
+        D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
+{
+    struct wined3d_vec4 plane[12];
+    DWORD enabled_planes = 0x3f;
+    DWORD user_clip_planes;
+    UINT j;
+
+    TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
+            iface, centers, radii, sphere_count, flags, return_values);
+
+    prepare_clip_space_planes(impl_from_IDirect3DDevice7(iface), plane);
 
+    IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &user_clip_planes);
+    enabled_planes |= user_clip_planes << 6;
+    for (j = 6; j < 12; ++j)
+        IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
+
+    compute_sphere_visibility(plane, enabled_planes, FALSE, centers, radii, sphere_count, return_values);
     return D3D_OK;
 }
 
 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
 {
-    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
+    static const DWORD enabled_planes = 0x3f;
+    struct wined3d_vec4 plane[6];
+    unsigned int i, j;
 
     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
             iface, centers, radii, sphere_count, flags, return_values);
 
-    return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
-            centers, radii, sphere_count, flags, return_values);
+    prepare_clip_space_planes(impl_from_IDirect3DDevice3(iface), plane);
+
+    compute_sphere_visibility(plane, enabled_planes, TRUE, centers, radii, sphere_count, return_values);
+    for (i = 0; i < sphere_count; ++i)
+    {
+        BOOL intersect_frustum = FALSE, outside_frustum = FALSE;
+        DWORD d3d7_result = return_values[i];
+
+        return_values[i] = 0;
+
+        for (j = 0; j < 6; ++j)
+        {
+            DWORD clip = (d3d7_result >> j) & (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT);
+
+            if (clip == D3DSTATUS_CLIPUNIONLEFT)
+            {
+                return_values[i] |= D3DVIS_INTERSECT_LEFT << j * 2;
+                intersect_frustum = TRUE;
+            }
+            else if (clip)
+            {
+                return_values[i] |= D3DVIS_OUTSIDE_LEFT << j * 2;
+                outside_frustum = TRUE;
+            }
+        }
+        if (outside_frustum)
+            return_values[i] |= D3DVIS_OUTSIDE_FRUSTUM;
+        else if (intersect_frustum)
+            return_values[i] |= D3DVIS_INTERSECT_FRUSTUM;
+    }
+    return D3D_OK;
 }
 
 /*****************************************************************************
-- 
2.10.2




More information about the wine-patches mailing list