/***************************************************************************** * IDirect3DViewport3::Release * * Reduces the refcount. If it falls to 0, the interface is released * * Returns: * The new refcount * *****************************************************************************/ static ULONG WINAPI IDirect3DViewportImpl_Release(IDirect3DViewport3 *iface) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->() decrementing from %u.\n", This, ref + 1); if (!ref) { HeapFree(GetProcessHeap(), 0, This); return 0; } return ref; }
/***************************************************************************** * IDirect3DVertexBuffer7::ProcessVerticesStrided * * This method processes untransformed strided vertices into a processed * or optimized vertex buffer. * * For more details on the parameters, see * IDirect3DVertexBuffer7::ProcessVertices * * Params: * VertexOp: Operations to perform * DestIndex: Destination index to write the vertices to * Count: Number of input vertices * StrideData: Array containing the input vertices * VertexTypeDesc: Vertex Description or source index????????? * D3DDevice: IDirect3DDevice7 to use for processing * Flags: Can be D3DPV_DONOTCOPYDATA to avoid copying unmodified vertices * * Returns * D3D_OK on success, or DDERR_* * *****************************************************************************/ static HRESULT WINAPI IDirect3DVertexBufferImpl_ProcessVerticesStrided(IDirect3DVertexBuffer7 *iface, DWORD VertexOp, DWORD DestIndex, DWORD Count, D3DDRAWPRIMITIVESTRIDEDDATA *StrideData, DWORD VertexTypeDesc, IDirect3DDevice7 *D3DDevice, DWORD Flags) { ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface); IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice); FIXME("(%p)->(%08x,%08x,%08x,%p,%08x,%p,%08x): stub!\n", This, VertexOp, DestIndex, Count, StrideData, VertexTypeDesc, D3D, Flags); return DD_OK; }
/***************************************************************************** * IDirect3DVertexBuffer7::Release * * Release for Vertex Buffers * * Returns: * The new refcount * *****************************************************************************/ static ULONG WINAPI IDirect3DVertexBufferImpl_Release(IDirect3DVertexBuffer7 *iface) { ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->() decrementing from %u.\n", This, ref + 1); if (ref == 0) { IWineD3DVertexBuffer *curVB = NULL; UINT offset, stride; EnterCriticalSection(&ddraw_cs); /* D3D7 Vertex buffers don't stay bound in the device, they are passed as a parameter * to drawPrimitiveVB. DrawPrimitiveVB sets them as the stream source in wined3d, * and they should get unset there before they are destroyed */ IWineD3DDevice_GetStreamSource(This->ddraw->wineD3DDevice, 0 /* Stream number */, &curVB, &offset, &stride); if(curVB == This->wineD3DVertexBuffer) { IWineD3DDevice_SetStreamSource(This->ddraw->wineD3DDevice, 0 /* Steam number */, NULL /* stream data */, 0 /* Offset */, 0 /* stride */); } if(curVB) { IWineD3DVertexBuffer_Release(curVB); /* For the GetStreamSource */ } IWineD3DVertexDeclaration_Release(This->wineD3DVertexDeclaration); IWineD3DVertexBuffer_Release(This->wineD3DVertexBuffer); LeaveCriticalSection(&ddraw_cs); HeapFree(GetProcessHeap(), 0, This); return 0; } return ref; }
/***************************************************************************** * IDirect3DVertexBuffer7::Optimize * * Converts an unoptimized vertex buffer into an optimized buffer * * Params: * D3DDevice: Device for which this buffer is optimized * Flags: Not used, should be set to 0 * * Returns * D3D_OK, because it's a stub * *****************************************************************************/ static HRESULT WINAPI IDirect3DVertexBufferImpl_Optimize(IDirect3DVertexBuffer7 *iface, IDirect3DDevice7 *D3DDevice, DWORD Flags) { ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface); IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice); FIXME("(%p)->(%p,%08x): stub!\n", This, D3D, Flags); /* We could forward this call to WineD3D and take advantage * of it once we use OpenGL vertex buffers */ EnterCriticalSection(&ddraw_cs); This->Caps |= D3DVBCAPS_OPTIMIZED; LeaveCriticalSection(&ddraw_cs); return DD_OK; }
static HRESULT WINAPI IDirect3DLightImpl_SetLight(IDirect3DLight *iface, D3DLIGHT *lpLight) { ICOM_THIS_FROM(IDirect3DLightImpl, IDirect3DLight, iface); LPD3DLIGHT7 light7 = &(This->light7); TRACE("(%p)->(%p)\n", This, lpLight); if (TRACE_ON(d3d7)) { TRACE(" Light definition :\n"); dump_light((LPD3DLIGHT2) lpLight); } if ( (lpLight->dltType == 0) || (lpLight->dltType > D3DLIGHT_PARALLELPOINT) ) return DDERR_INVALIDPARAMS; if ( lpLight->dltType == D3DLIGHT_PARALLELPOINT ) FIXME("D3DLIGHT_PARALLELPOINT no supported\n"); /* Translate D3DLIGH2 structure to D3DLIGHT7 */ light7->dltType = lpLight->dltType; light7->dcvDiffuse = lpLight->dcvColor; if ((((LPD3DLIGHT2)lpLight)->dwFlags & D3DLIGHT_NO_SPECULAR) != 0) light7->dcvSpecular = lpLight->dcvColor; else light7->dcvSpecular = *(const D3DCOLORVALUE*)zero_value; light7->dcvAmbient = lpLight->dcvColor; light7->dvPosition = lpLight->dvPosition; light7->dvDirection = lpLight->dvDirection; light7->dvRange = lpLight->dvRange; light7->dvFalloff = lpLight->dvFalloff; light7->dvAttenuation0 = lpLight->dvAttenuation0; light7->dvAttenuation1 = lpLight->dvAttenuation1; light7->dvAttenuation2 = lpLight->dvAttenuation2; light7->dvTheta = lpLight->dvTheta; light7->dvPhi = lpLight->dvPhi; memcpy(&This->light, lpLight, lpLight->dwSize); if ((This->light.dwFlags & D3DLIGHT_ACTIVE) != 0) { This->update(This); } return D3D_OK; }
/***************************************************************************** * IDirect3DViewport3::AddLight * * Adds an light to the viewport * * Params: * lpDirect3DLight: Interface of the light to add * * Returns: * D3D_OK on success * DDERR_INVALIDPARAMS if Direct3DLight is NULL * DDERR_INVALIDPARAMS if there are 8 lights or more * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_AddLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); IDirect3DLightImpl *lpDirect3DLightImpl = ICOM_OBJECT(IDirect3DLightImpl, IDirect3DLight, lpDirect3DLight); DWORD i = 0; DWORD map = This->map_lights; TRACE("(%p)->(%p)\n", This, lpDirect3DLight); EnterCriticalSection(&ddraw_cs); if (This->num_lights >= 8) { LeaveCriticalSection(&ddraw_cs); return DDERR_INVALIDPARAMS; } /* Find a light number and update both light and viewports objects accordingly */ while(map&1) { map>>=1; i++; } lpDirect3DLightImpl->dwLightIndex = i; This->num_lights++; This->map_lights |= 1<<i; /* Add the light in the 'linked' chain */ lpDirect3DLightImpl->next = This->lights; This->lights = lpDirect3DLightImpl; /* Attach the light to the viewport */ lpDirect3DLightImpl->active_viewport = This; /* If active, activate the light */ if (This->active_device != NULL) { lpDirect3DLightImpl->activate(lpDirect3DLightImpl); } LeaveCriticalSection(&ddraw_cs); return D3D_OK; }
/***************************************************************************** * IDirect3DViewport3::Clear2 * * Another clearing method * * Params: * Count: Number of rectangles to clear * Rects: Rectangle array to clear * Flags: Some flags :) * Color: Color to fill the render target with * Z: Value to fill the depth buffer with * Stencil: Value to fill the stencil bits with * * Returns: * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_Clear2(IDirect3DViewport3 *iface, DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, DWORD dwColor, D3DVALUE dvZ, DWORD dwStencil) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); HRESULT hr; LPDIRECT3DVIEWPORT3 current_viewport; TRACE("(%p)->(%08x,%p,%08x,%08x,%f,%08x)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); EnterCriticalSection(&ddraw_cs); if (This->active_device == NULL) { ERR(" Trying to clear a viewport not attached to a device !\n"); LeaveCriticalSection(&ddraw_cs); return D3DERR_VIEWPORTHASNODEVICE; } /* Need to temporarily activate viewport to clear it. Previously active one will be restored afterwards. */ This->activate(This, TRUE); hr = IDirect3DDevice7_Clear(ICOM_INTERFACE(This->active_device, IDirect3DDevice7), dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil); IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), ¤t_viewport); if(current_viewport) { IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport); vp->activate(vp, TRUE); IDirect3DViewport3_Release(current_viewport); } LeaveCriticalSection(&ddraw_cs); return hr; }
/***************************************************************************** * IDirect3DViewport3::SetBackground * * Sets tje background material * * Params: * hMat: Handle from a IDirect3DMaterial interface * * Returns: * D3D_OK on success * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface, D3DMATERIALHANDLE hMat) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); TRACE("(%p)->(%d)\n", This, hMat); EnterCriticalSection(&ddraw_cs); if(hMat && hMat > This->ddraw->d3ddevice->numHandles) { WARN("Specified Handle %d out of range\n", hMat); LeaveCriticalSection(&ddraw_cs); return DDERR_INVALIDPARAMS; } else if(hMat && This->ddraw->d3ddevice->Handles[hMat - 1].type != DDrawHandle_Material) { WARN("Handle %d is not a material handle\n", hMat); LeaveCriticalSection(&ddraw_cs); return DDERR_INVALIDPARAMS; } if(hMat) { This->background = This->ddraw->d3ddevice->Handles[hMat - 1].ptr; TRACE(" setting background color : %f %f %f %f\n", This->background->mat.u.diffuse.u1.r, This->background->mat.u.diffuse.u2.g, This->background->mat.u.diffuse.u3.b, This->background->mat.u.diffuse.u4.a); } else { This->background = NULL; TRACE("Setting background to NULL\n"); } LeaveCriticalSection(&ddraw_cs); return D3D_OK; }
/***************************************************************************** * IDirect3DViewport3::QueryInterface * * A normal QueryInterface. Can query all interface versions and the * IUnknown interface. The VTables of the different versions * are equal * * Params: * refiid: Interface id queried for * obj: Address to write the interface pointer to * * Returns: * S_OK on success. * E_NOINTERFACE if the requested interface wasn't found * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_QueryInterface(IDirect3DViewport3 *iface, REFIID riid, void **obp) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), obp); *obp = NULL; if ( IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDirect3DViewport, riid) || IsEqualGUID(&IID_IDirect3DViewport2, riid) || IsEqualGUID(&IID_IDirect3DViewport3, riid) ) { IDirect3DViewport3_AddRef(ICOM_INTERFACE(This, IDirect3DViewport3)); *obp = ICOM_INTERFACE(This, IDirect3DViewport3); TRACE(" Creating IDirect3DViewport1/2/3 interface %p\n", *obp); return S_OK; } FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid)); return E_NOINTERFACE; }
/***************************************************************************** * IDirect3DViewport3::SetViewport * * Sets the viewport information for this interface * * Params: * lpData: Viewport to set * * Returns: * D3D_OK on success * DDERR_INVALIDPARAMS if Data is NULL * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_SetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *lpData) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); LPDIRECT3DVIEWPORT3 current_viewport; TRACE("(%p/%p)->(%p)\n", This, iface, lpData); if (TRACE_ON(d3d7)) { TRACE(" getting D3DVIEWPORT :\n"); _dump_D3DVIEWPORT(lpData); } EnterCriticalSection(&ddraw_cs); This->use_vp2 = 0; memset(&(This->viewports.vp1), 0, sizeof(This->viewports.vp1)); memcpy(&(This->viewports.vp1), lpData, lpData->dwSize); /* Tests on two games show that these values are never used properly so override them with proper ones :-) */ This->viewports.vp1.dvMinZ = 0.0; This->viewports.vp1.dvMaxZ = 1.0; if (This->active_device) { IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), ¤t_viewport); if (current_viewport) { if (ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport) == This) This->activate(This, FALSE); IDirect3DViewport3_Release(current_viewport); } } LeaveCriticalSection(&ddraw_cs); return DD_OK; }
/***************************************************************************** * IDirect3DTexture2::Load * * Loads a texture created with the DDSCAPS_ALLOCONLOAD * * This function isn't relayed to WineD3D because the whole interface is * implemented in DDraw only. For speed improvements a implementation which * takes OpenGL more into account could be placed into WineD3D. * * Params: * D3DTexture2: Address of the texture to load * * Returns: * D3D_OK on success * D3DERR_TEXTURE_LOAD_FAILED. * *****************************************************************************/ static HRESULT WINAPI IDirect3DTextureImpl_Load(IDirect3DTexture2 *iface, IDirect3DTexture2 *D3DTexture2) { ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, D3DTexture2); IWineD3DPalette *wine_pal, *wine_pal_src; IDirectDrawPalette *pal = NULL, *pal_src = NULL; IDirectDrawPaletteImpl *pal_impl, *pal_impl_src; HRESULT ret_value = D3D_OK; TRACE("(%p)->(%p)\n", This, src_ptr); if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) || (src_ptr->surface_desc.u2.dwMipMapCount != This->surface_desc.u2.dwMipMapCount)) { ERR("Trying to load surfaces with different mip-map counts !\n"); } while(1) { DDSURFACEDESC *src_d, *dst_d; TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, This, src_ptr->mipmap_level); if ( This->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD ) /* If the surface is not allocated and its location is not yet specified, force it to video memory */ if ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) ) This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; /* Suppress the ALLOCONLOAD flag */ This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD; /* Get the palettes */ ret_value = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wine_pal); if( ret_value != D3D_OK) { ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n"); return D3DERR_TEXTURE_LOAD_FAILED; } if(wine_pal) { ret_value = IWineD3DPalette_GetParent(wine_pal, (IUnknown **) &pal); if(ret_value != D3D_OK) { ERR("IWineD3DPalette::GetParent failed! This is unexpected\n"); return D3DERR_TEXTURE_LOAD_FAILED; } pal_impl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, pal); } else { pal_impl = NULL; } ret_value = IWineD3DSurface_GetPalette(src_ptr->WineD3DSurface, &wine_pal_src); if( ret_value != D3D_OK) { ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n"); return D3DERR_TEXTURE_LOAD_FAILED; } if(wine_pal_src) { ret_value = IWineD3DPalette_GetParent(wine_pal_src, (IUnknown **) &pal_src); if(ret_value != D3D_OK) { ERR("IWineD3DPalette::GetParent failed! This is unexpected\n"); return D3DERR_TEXTURE_LOAD_FAILED; } pal_impl_src = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, pal_src); } else { pal_impl_src = NULL; } /* After seeing some logs, not sure at all about this... */ if (pal_impl == NULL) { IWineD3DSurface_SetPalette(This->WineD3DSurface, wine_pal); if (pal_impl_src != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(pal_impl_src, IDirectDrawPalette)); } else { if (pal_impl_src != NULL) { PALETTEENTRY palent[256]; IDirectDrawPalette_GetEntries(ICOM_INTERFACE(pal_impl_src, IDirectDrawPalette), 0, 0, 256, palent); IDirectDrawPalette_SetEntries(ICOM_INTERFACE(pal_impl, IDirectDrawPalette), 0, 0, 256, palent); } } /* Copy one surface on the other */ dst_d = (DDSURFACEDESC *)&(This->surface_desc); src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc); if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) { /* Should also check for same pixel format, u1.lPitch, ... */ ERR("Error in surface sizes\n"); return D3DERR_TEXTURE_LOAD_FAILED; } else { WINED3DLOCKED_RECT pSrcRect, pDstRect; /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */ /* I should put a macro for the calculus of bpp */ /* Copy also the ColorKeying stuff */ if (src_d->dwFlags & DDSD_CKSRCBLT) { dst_d->dwFlags |= DDSD_CKSRCBLT; dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue; dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue; } /* Copy the main memory texture into the surface that corresponds to the OpenGL texture object. */ ret_value = IWineD3DSurface_LockRect(src_ptr->WineD3DSurface, &pSrcRect, NULL, 0); if(ret_value != D3D_OK) { ERR(" (%p) Locking the source surface failed\n", This); return D3DERR_TEXTURE_LOAD_FAILED; } ret_value = IWineD3DSurface_LockRect(This->WineD3DSurface, &pDstRect, NULL, 0); if(ret_value != D3D_OK) { ERR(" (%p) Locking the destination surface failed\n", This); IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface); return D3DERR_TEXTURE_LOAD_FAILED; } if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) memcpy(pDstRect.pBits, pSrcRect.pBits, src_ptr->surface_desc.u1.dwLinearSize); else memcpy(pDstRect.pBits, pSrcRect.pBits, pSrcRect.Pitch * src_d->dwHeight); IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface); IWineD3DSurface_UnlockRect(This->WineD3DSurface); } if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { src_ptr = get_sub_mimaplevel(src_ptr); } else { src_ptr = NULL; } if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { This = get_sub_mimaplevel(This); } else { This = NULL; } if ((src_ptr == NULL) || (This == NULL)) { if (src_ptr != This) { ERR(" Loading surface with different mipmap structure !!!\n"); } break; } } return ret_value; }
/***************************************************************************** * IDirect3DVertexBuffer7::ProcessVertices * * Processes untransformed Vertices into a transformed or optimized vertex * buffer. It can also perform other operations, such as lighting or clipping * * Params * VertexOp: Operation(s) to perform: D3DVOP_CLIP, _EXTENTS, _LIGHT, _TRANSFORM * DestIndex: Index in the destination buffer(This), where the vertices are * placed * Count: Number of Vertices in the Source buffer to process * SrcBuffer: Source vertex buffer * SrcIndex: Index of the first vertex in the src buffer to process * D3DDevice: Device to use for transformation * Flags: 0 for default, D3DPV_DONOTCOPYDATA to prevent copying * unchaned vertices * * Returns: * D3D_OK on success * DDERR_INVALIDPARAMS If D3DVOP_TRANSFORM wasn't passed * *****************************************************************************/ static HRESULT WINAPI IDirect3DVertexBufferImpl_ProcessVertices(IDirect3DVertexBuffer7 *iface, DWORD VertexOp, DWORD DestIndex, DWORD Count, IDirect3DVertexBuffer7 *SrcBuffer, DWORD SrcIndex, IDirect3DDevice7 *D3DDevice, DWORD Flags) { ICOM_THIS_FROM(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, iface); IDirect3DVertexBufferImpl *Src = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, SrcBuffer); IDirect3DDeviceImpl *D3D = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice7, D3DDevice); BOOL oldClip, doClip; HRESULT hr; WINED3DVERTEXBUFFER_DESC Desc; TRACE("(%p)->(%08x,%d,%d,%p,%d,%p,%08x)\n", This, VertexOp, DestIndex, Count, Src, SrcIndex, D3D, Flags); /* Vertex operations: * D3DVOP_CLIP: Clips vertices outside the viewing frustrum. Needs clipping information * in the vertex buffer (Buffer may not be created with D3DVBCAPS_DONOTCLIP) * D3DVOP_EXTENTS: Causes the screen extents to be updated when rendering the vertices * D3DVOP_LIGHT: Lights the vertices * D3DVOP_TRANSFORM: Transform the vertices. This flag is necessary * * WineD3D only transforms and clips the vertices by now, so EXTENTS and LIGHT * are not implemented. Clipping is disabled ATM, because of unsure conditions. */ if( !(VertexOp & D3DVOP_TRANSFORM) ) return DDERR_INVALIDPARAMS; EnterCriticalSection(&ddraw_cs); /* WineD3D doesn't know d3d7 vertex operation, it uses * render states instead. Set the render states according to * the vertex ops */ doClip = VertexOp & D3DVOP_CLIP ? TRUE : FALSE; IWineD3DDevice_GetRenderState(D3D->wineD3DDevice, WINED3DRS_CLIPPING, (DWORD *) &oldClip); if(doClip != oldClip) { IWineD3DDevice_SetRenderState(D3D->wineD3DDevice, WINED3DRS_CLIPPING, doClip); } IWineD3DVertexBuffer_GetDesc(Src->wineD3DVertexBuffer, &Desc); IWineD3DDevice_SetStreamSource(D3D->wineD3DDevice, 0, /* Stream No */ Src->wineD3DVertexBuffer, 0, /* Offset */ get_flexible_vertex_size(Desc.FVF)); IWineD3DDevice_SetVertexDeclaration(D3D->wineD3DDevice, Src->wineD3DVertexDeclaration); hr = IWineD3DDevice_ProcessVertices(D3D->wineD3DDevice, SrcIndex, DestIndex, Count, This->wineD3DVertexBuffer, NULL /* Output vdecl */, Flags); /* Restore the states if needed */ if(doClip != oldClip) IWineD3DDevice_SetRenderState(D3D->wineD3DDevice, WINED3DRS_CLIPPING, oldClip); LeaveCriticalSection(&ddraw_cs); return hr; }
/***************************************************************************** * IDirect3DViewport3::TransformVertices * * Transforms vertices by the transformation matrix. * * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices, * so it's tempting to forward it to there. However, there are some * tiny differences. First, the lpOffscreen flag that is reported back, * then there is the homogeneous vertex that is generated. Also there's a lack * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to * ProcessVertices doesn't pay of in terms of wrapper code needed and code * reused. * * Params: * dwVertexCount: The number of vertices to be transformed * lpData: Pointer to the vertex data * dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED * lpOffScreen: Set to the clipping plane clipping the vertex, if only one * vertex is transformed and clipping is on. 0 otherwise * * Returns: * D3D_OK on success * D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device * DDERR_INVALIDPARAMS if no clipping flag is specified * *****************************************************************************/ static HRESULT WINAPI IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface, DWORD dwVertexCount, D3DTRANSFORMDATA *lpData, DWORD dwFlags, DWORD *lpOffScreen) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); D3DMATRIX view_mat, world_mat, proj_mat, mat; float *in; float *out; float x, y, z, w; unsigned int i; D3DVIEWPORT vp = This->viewports.vp1; D3DHVERTEX *outH; TRACE("(%p)->(%08x,%p,%08x,%p)\n", This, dwVertexCount, lpData, dwFlags, lpOffScreen); /* Tests on windows show that Windows crashes when this occurs, * so don't return the (intuitive) return value if(!This->active_device) { WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n"); return D3DERR_VIEWPORTHASNODEVICE; } */ if(!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED))) { WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n"); return DDERR_INVALIDPARAMS; } EnterCriticalSection(&ddraw_cs); IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice, D3DTRANSFORMSTATE_VIEW, (WINED3DMATRIX*) &view_mat); IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice, D3DTRANSFORMSTATE_PROJECTION, (WINED3DMATRIX*) &proj_mat); IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice, WINED3DTS_WORLDMATRIX(0), (WINED3DMATRIX*) &world_mat); multiply_matrix(&mat,&view_mat,&world_mat); multiply_matrix(&mat,&proj_mat,&mat); in = lpData->lpIn; out = lpData->lpOut; outH = lpData->lpHOut; for(i = 0; i < dwVertexCount; i++) { x = (in[0] * mat._11) + (in[1] * mat._21) + (in[2] * mat._31) + (1.0 * mat._41); y = (in[0] * mat._12) + (in[1] * mat._22) + (in[2] * mat._32) + (1.0 * mat._42); z = (in[0] * mat._13) + (in[1] * mat._23) + (in[2] * mat._33) + (1.0 * mat._43); w = (in[0] * mat._14) + (in[1] * mat._24) + (in[2] * mat._34) + (1.0 * mat._44); if(dwFlags & D3DTRANSFORM_CLIPPED) { /* If clipping is enabled, Windows assumes that outH is * a valid pointer */ outH[i].u1.hx = x; outH[i].u2.hy = y; outH[i].u3.hz = z; outH[i].dwFlags = 0; if(x * vp.dvScaleX > ((float) vp.dwWidth * 0.5)) outH[i].dwFlags |= D3DCLIP_RIGHT; if(x * vp.dvScaleX <= -((float) vp.dwWidth) * 0.5) outH[i].dwFlags |= D3DCLIP_LEFT; if(y * vp.dvScaleY > ((float) vp.dwHeight * 0.5)) outH[i].dwFlags |= D3DCLIP_TOP; if(y * vp.dvScaleY <= -((float) vp.dwHeight) * 0.5) outH[i].dwFlags |= D3DCLIP_BOTTOM; if(z < 0.0) outH[i].dwFlags |= D3DCLIP_FRONT; if(z > 1.0) outH[i].dwFlags |= D3DCLIP_BACK; if(outH[i].dwFlags) { /* Looks like native just drops the vertex, leaves whatever data * it has in the output buffer and goes on with the next vertex. * The exact scheme hasn't been figured out yet, but windows * definitely writes something there. */ out[0] = x; out[1] = y; out[2] = z; out[3] = w; in = (float *) ((char *) in + lpData->dwInSize); out = (float *) ((char *) out + lpData->dwOutSize); continue; } } w = 1 / w; x *= w; y *= w; z *= w; out[0] = vp.dwWidth / 2 + vp.dwX + x * vp.dvScaleX; out[1] = vp.dwHeight / 2 + vp.dwY - y * vp.dvScaleY; out[2] = z; out[3] = w; in = (float *) ((char *) in + lpData->dwInSize); out = (float *) ((char *) out + lpData->dwOutSize); } /* According to the d3d test, the offscreen flag is set only * if exactly one vertex is transformed. Its not documented, * but the test shows that the lpOffscreen flag is set to the * flag combination of clipping planes that clips the vertex. * * If clipping is requested, Windows assumes that the offscreen * param is a valid pointer. */ if(dwVertexCount == 1 && dwFlags & D3DTRANSFORM_CLIPPED) { *lpOffScreen = outH[0].dwFlags; } else if(*lpOffScreen) { *lpOffScreen = 0; } LeaveCriticalSection(&ddraw_cs); TRACE("All done\n"); return DD_OK; }