1301 lines
54 KiB
C
1301 lines
54 KiB
C
/*
|
|
* IWineD3DDevice implementation
|
|
*
|
|
* Copyright 2002-2004 Jason Edmeades
|
|
* Copyright 2003-2004 Raphael Junqueira
|
|
* Copyright 2004 Christian Costa
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "wined3d_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
|
WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
|
|
#define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
|
|
|
|
/**********************************************************
|
|
* Global variable / Constants follow
|
|
**********************************************************/
|
|
const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
|
|
|
|
/**********************************************************
|
|
* Utility functions follow
|
|
**********************************************************/
|
|
/* Convert the D3DLIGHT properties into equivalent gl lights */
|
|
void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
|
|
|
|
float quad_att;
|
|
float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
/* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
|
|
|
|
/* Diffuse: */
|
|
colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
|
|
colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
|
|
colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
|
|
colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
|
|
glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
|
|
checkGLcall("glLightfv");
|
|
|
|
/* Specular */
|
|
colRGBA[0] = lightInfo->OriginalParms.Specular.r;
|
|
colRGBA[1] = lightInfo->OriginalParms.Specular.g;
|
|
colRGBA[2] = lightInfo->OriginalParms.Specular.b;
|
|
colRGBA[3] = lightInfo->OriginalParms.Specular.a;
|
|
glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
|
|
checkGLcall("glLightfv");
|
|
|
|
/* Ambient */
|
|
colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
|
|
colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
|
|
colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
|
|
colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
|
|
glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
|
|
checkGLcall("glLightfv");
|
|
|
|
/* Attenuation - Are these right? guessing... */
|
|
glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
|
|
checkGLcall("glLightf");
|
|
glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
|
|
checkGLcall("glLightf");
|
|
|
|
quad_att = 1.4/(lightInfo->OriginalParms.Range*lightInfo->OriginalParms.Range);
|
|
if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
|
|
glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
|
|
checkGLcall("glLightf");
|
|
|
|
switch (lightInfo->OriginalParms.Type) {
|
|
case D3DLIGHT_POINT:
|
|
/* Position */
|
|
glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
|
|
checkGLcall("glLightfv");
|
|
glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
|
|
checkGLcall("glLightf");
|
|
/* FIXME: Range */
|
|
break;
|
|
|
|
case D3DLIGHT_SPOT:
|
|
/* Position */
|
|
glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
|
|
checkGLcall("glLightfv");
|
|
/* Direction */
|
|
glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
|
|
checkGLcall("glLightfv");
|
|
glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
|
|
checkGLcall("glLightf");
|
|
glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
|
|
checkGLcall("glLightf");
|
|
/* FIXME: Range */
|
|
break;
|
|
|
|
case D3DLIGHT_DIRECTIONAL:
|
|
/* Direction */
|
|
glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
|
|
checkGLcall("glLightfv");
|
|
glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
|
|
checkGLcall("glLightf");
|
|
glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
|
|
checkGLcall("glLightf");
|
|
break;
|
|
|
|
default:
|
|
FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
|
|
}
|
|
|
|
/* Restore the modelview matrix */
|
|
glPopMatrix();
|
|
}
|
|
|
|
/**********************************************************
|
|
* IWineD3DDevice implementation follows
|
|
**********************************************************/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
*pParent = This->parent;
|
|
IUnknown_AddRef(This->parent);
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
|
|
DWORD FVF, D3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
|
|
IUnknown *parent) {
|
|
|
|
IWineD3DVertexBufferImpl *object;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
/* Allocate the storage for the device */
|
|
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DVertexBufferImpl));
|
|
object->lpVtbl = &IWineD3DVertexBuffer_Vtbl;
|
|
object->resource.wineD3DDevice= iface;
|
|
IWineD3DDevice_AddRef(iface);
|
|
object->resource.parent = parent;
|
|
object->resource.resourceType = D3DRTYPE_VERTEXBUFFER;
|
|
object->resource.ref = 1;
|
|
object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
|
|
object->currentDesc.Usage = Usage;
|
|
object->currentDesc.Pool = Pool;
|
|
object->currentDesc.FVF = FVF;
|
|
object->currentDesc.Size = Size;
|
|
|
|
TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->allocatedMemory, object);
|
|
*ppVertexBuffer = (IWineD3DVertexBuffer *)object;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
|
|
D3DFORMAT Format, D3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
|
|
HANDLE *sharedHandle, IUnknown *parent) {
|
|
IWineD3DIndexBufferImpl *object;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
/* Allocate the storage for the device */
|
|
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DIndexBufferImpl));
|
|
object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
|
|
object->resource.wineD3DDevice = iface;
|
|
object->resource.resourceType = D3DRTYPE_INDEXBUFFER;
|
|
object->resource.parent = parent;
|
|
IWineD3DDevice_AddRef(iface);
|
|
object->resource.ref = 1;
|
|
object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
|
|
object->currentDesc.Usage = Usage;
|
|
object->currentDesc.Pool = Pool;
|
|
object->currentDesc.Format= Format;
|
|
object->currentDesc.Size = Length;
|
|
|
|
TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
|
|
debug_d3dformat(Format), Pool, object, object->allocatedMemory);
|
|
*ppIndexBuffer = (IWineD3DIndexBuffer *) object;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
|
|
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
IWineD3DStateBlockImpl *object;
|
|
|
|
/* Allocate Storage for the state block */
|
|
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
|
|
object->lpVtbl = &IWineD3DStateBlock_Vtbl;
|
|
object->wineD3DDevice = iface;
|
|
IWineD3DDevice_AddRef(iface);
|
|
object->parent = parent;
|
|
object->ref = 1;
|
|
object->blockType = Type;
|
|
*ppStateBlock = (IWineD3DStateBlock *)object;
|
|
|
|
/* Special case - Used during initialization to produce a placeholder stateblock
|
|
so other functions called can update a state block */
|
|
if (Type == (D3DSTATEBLOCKTYPE) 0) {
|
|
/* Don't bother increasing the reference count otherwise a device will never
|
|
be freed due to circular dependencies */
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Otherwise, might as well set the whole state block to the appropriate values */
|
|
IWineD3DDevice_AddRef(iface);
|
|
memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
|
|
FIXME("unfinished - needs to set up changed and set attributes\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set FVF
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
/* Update the current statte block */
|
|
This->updateStateBlock->fvf = fvf;
|
|
This->updateStateBlock->changed.fvf = TRUE;
|
|
This->updateStateBlock->set.fvf = TRUE;
|
|
|
|
TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
|
|
|
|
/* No difference if recording or not */
|
|
return D3D_OK;
|
|
}
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
|
|
*pfvf = This->stateBlock->fvf;
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Stream Source
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
IWineD3DVertexBuffer *oldSrc;
|
|
|
|
oldSrc = This->stateBlock->stream_source[StreamNumber];
|
|
TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
|
|
|
|
This->updateStateBlock->changed.stream_source[StreamNumber] = TRUE;
|
|
This->updateStateBlock->set.stream_source[StreamNumber] = TRUE;
|
|
This->updateStateBlock->stream_stride[StreamNumber] = Stride;
|
|
This->updateStateBlock->stream_source[StreamNumber] = pStreamData;
|
|
This->updateStateBlock->stream_offset[StreamNumber] = OffsetInBytes;
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Not recording... */
|
|
if (oldSrc != NULL) IWineD3DVertexBuffer_Release(oldSrc);
|
|
if (pStreamData != NULL) IWineD3DVertexBuffer_AddRef(pStreamData);
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber, This->stateBlock->stream_source[StreamNumber], This->stateBlock->stream_stride[StreamNumber]);
|
|
*pStream = This->stateBlock->stream_source[StreamNumber];
|
|
*pStride = This->stateBlock->stream_stride[StreamNumber];
|
|
*pOffset = This->stateBlock->stream_offset[StreamNumber];
|
|
IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set & Multipy Transform
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
/* Most of this routine, comments included copied from ddraw tree initially: */
|
|
TRACE("(%p) : Transform State=%d\n", This, d3dts);
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
This->updateStateBlock->changed.transform[d3dts] = TRUE;
|
|
This->updateStateBlock->set.transform[d3dts] = TRUE;
|
|
memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*
|
|
* If the new matrix is the same as the current one,
|
|
* we cut off any further processing. this seems to be a reasonable
|
|
* optimization because as was noticed, some apps (warcraft3 for example)
|
|
* tend towards setting the same matrix repeatedly for some reason.
|
|
*
|
|
* From here on we assume that the new matrix is different, wherever it matters.
|
|
*/
|
|
if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
|
|
TRACE("The app is setting the same matrix over again\n");
|
|
return D3D_OK;
|
|
} else {
|
|
conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
|
|
}
|
|
|
|
/*
|
|
ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
|
|
where ViewMat = Camera space, WorldMat = world space.
|
|
|
|
In OpenGL, camera and world space is combined into GL_MODELVIEW
|
|
matrix. The Projection matrix stay projection matrix.
|
|
*/
|
|
|
|
/* Capture the times we can just ignore the change for now */
|
|
if (d3dts == D3DTS_WORLDMATRIX(0)) {
|
|
This->modelview_valid = FALSE;
|
|
return D3D_OK;
|
|
|
|
} else if (d3dts == D3DTS_PROJECTION) {
|
|
This->proj_valid = FALSE;
|
|
return D3D_OK;
|
|
|
|
} else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
|
|
/* Indexed Vertex Blending Matrices 256 -> 511 */
|
|
/* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
|
|
FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Now we really are going to have to change a matrix */
|
|
ENTER_GL();
|
|
|
|
if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
|
|
if (d3dts < GL_LIMITS(textures)) {
|
|
int tex = d3dts - D3DTS_TEXTURE0;
|
|
GL_ACTIVETEXTURE(tex);
|
|
#if 0 /* TODO: */
|
|
set_texture_matrix((float *)lpmatrix,
|
|
This->updateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]);
|
|
#endif
|
|
}
|
|
|
|
} else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
|
|
unsigned int k;
|
|
|
|
/* If we are changing the View matrix, reset the light and clipping planes to the new view
|
|
* NOTE: We have to reset the positions even if the light/plane is not currently
|
|
* enabled, since the call to enable it will not reset the position.
|
|
* NOTE2: Apparently texture transforms do NOT need reapplying
|
|
*/
|
|
|
|
PLIGHTINFOEL *lightChain = NULL;
|
|
This->modelview_valid = FALSE;
|
|
This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float));
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
checkGLcall("glMatrixMode(GL_MODELVIEW)");
|
|
glPushMatrix();
|
|
glLoadMatrixf((float *)lpmatrix);
|
|
checkGLcall("glLoadMatrixf(...)");
|
|
|
|
/* Reset lights */
|
|
lightChain = This->stateBlock->lights;
|
|
while (lightChain && lightChain->glIndex != -1) {
|
|
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
|
|
checkGLcall("glLightfv posn");
|
|
glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
|
|
checkGLcall("glLightfv dirn");
|
|
lightChain = lightChain->next;
|
|
}
|
|
|
|
/* Reset Clipping Planes if clipping is enabled */
|
|
for (k = 0; k < GL_LIMITS(clipplanes); k++) {
|
|
glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
|
|
checkGLcall("glClipPlane");
|
|
}
|
|
glPopMatrix();
|
|
|
|
} else { /* What was requested!?? */
|
|
WARN("invalid matrix specified: %i\n", d3dts);
|
|
}
|
|
|
|
/* Release lock, all done */
|
|
LEAVE_GL();
|
|
return D3D_OK;
|
|
|
|
}
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : for Transform State %d\n", This, State);
|
|
memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
|
|
D3DMATRIX *mat = NULL;
|
|
D3DMATRIX temp;
|
|
|
|
/* Note: Using 'updateStateBlock' rather then 'stateblock' in the code below
|
|
means it will be recorded in a state block change, but iworks regardless of recording being on.
|
|
If this is found to be wrong, change to StateBlock. */
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : For state %u\n", This, State);
|
|
|
|
if (State < HIGHEST_TRANSFORMSTATE)
|
|
{
|
|
mat = &This->updateStateBlock->transforms[State];
|
|
} else {
|
|
FIXME("Unhandled transform state!!\n");
|
|
}
|
|
|
|
/* Copied from ddraw code: */
|
|
temp.u.s._11 = (mat->u.s._11 * pMatrix->u.s._11) + (mat->u.s._21 * pMatrix->u.s._12) + (mat->u.s._31 * pMatrix->u.s._13) + (mat->u.s._41 * pMatrix->u.s._14);
|
|
temp.u.s._21 = (mat->u.s._11 * pMatrix->u.s._21) + (mat->u.s._21 * pMatrix->u.s._22) + (mat->u.s._31 * pMatrix->u.s._23) + (mat->u.s._41 * pMatrix->u.s._24);
|
|
temp.u.s._31 = (mat->u.s._11 * pMatrix->u.s._31) + (mat->u.s._21 * pMatrix->u.s._32) + (mat->u.s._31 * pMatrix->u.s._33) + (mat->u.s._41 * pMatrix->u.s._34);
|
|
temp.u.s._41 = (mat->u.s._11 * pMatrix->u.s._41) + (mat->u.s._21 * pMatrix->u.s._42) + (mat->u.s._31 * pMatrix->u.s._43) + (mat->u.s._41 * pMatrix->u.s._44);
|
|
|
|
temp.u.s._12 = (mat->u.s._12 * pMatrix->u.s._11) + (mat->u.s._22 * pMatrix->u.s._12) + (mat->u.s._32 * pMatrix->u.s._13) + (mat->u.s._42 * pMatrix->u.s._14);
|
|
temp.u.s._22 = (mat->u.s._12 * pMatrix->u.s._21) + (mat->u.s._22 * pMatrix->u.s._22) + (mat->u.s._32 * pMatrix->u.s._23) + (mat->u.s._42 * pMatrix->u.s._24);
|
|
temp.u.s._32 = (mat->u.s._12 * pMatrix->u.s._31) + (mat->u.s._22 * pMatrix->u.s._32) + (mat->u.s._32 * pMatrix->u.s._33) + (mat->u.s._42 * pMatrix->u.s._34);
|
|
temp.u.s._42 = (mat->u.s._12 * pMatrix->u.s._41) + (mat->u.s._22 * pMatrix->u.s._42) + (mat->u.s._32 * pMatrix->u.s._43) + (mat->u.s._42 * pMatrix->u.s._44);
|
|
|
|
temp.u.s._13 = (mat->u.s._13 * pMatrix->u.s._11) + (mat->u.s._23 * pMatrix->u.s._12) + (mat->u.s._33 * pMatrix->u.s._13) + (mat->u.s._43 * pMatrix->u.s._14);
|
|
temp.u.s._23 = (mat->u.s._13 * pMatrix->u.s._21) + (mat->u.s._23 * pMatrix->u.s._22) + (mat->u.s._33 * pMatrix->u.s._23) + (mat->u.s._43 * pMatrix->u.s._24);
|
|
temp.u.s._33 = (mat->u.s._13 * pMatrix->u.s._31) + (mat->u.s._23 * pMatrix->u.s._32) + (mat->u.s._33 * pMatrix->u.s._33) + (mat->u.s._43 * pMatrix->u.s._34);
|
|
temp.u.s._43 = (mat->u.s._13 * pMatrix->u.s._41) + (mat->u.s._23 * pMatrix->u.s._42) + (mat->u.s._33 * pMatrix->u.s._43) + (mat->u.s._43 * pMatrix->u.s._44);
|
|
|
|
temp.u.s._14 = (mat->u.s._14 * pMatrix->u.s._11) + (mat->u.s._24 * pMatrix->u.s._12) + (mat->u.s._34 * pMatrix->u.s._13) + (mat->u.s._44 * pMatrix->u.s._14);
|
|
temp.u.s._24 = (mat->u.s._14 * pMatrix->u.s._21) + (mat->u.s._24 * pMatrix->u.s._22) + (mat->u.s._34 * pMatrix->u.s._23) + (mat->u.s._44 * pMatrix->u.s._24);
|
|
temp.u.s._34 = (mat->u.s._14 * pMatrix->u.s._31) + (mat->u.s._24 * pMatrix->u.s._32) + (mat->u.s._34 * pMatrix->u.s._33) + (mat->u.s._44 * pMatrix->u.s._34);
|
|
temp.u.s._44 = (mat->u.s._14 * pMatrix->u.s._41) + (mat->u.s._24 * pMatrix->u.s._42) + (mat->u.s._34 * pMatrix->u.s._43) + (mat->u.s._44 * pMatrix->u.s._44);
|
|
|
|
/* Apply change via set transform - will reapply to eg. lights this way */
|
|
IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Light
|
|
* WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
|
|
*****/
|
|
/* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
|
|
you can reference any indexes you want as long as that number max are enabled are any
|
|
one point in time! Therefore since the indexes can be anything, we need a linked list of them.
|
|
However, this causes stateblock problems. When capturing the state block, I duplicate the list,
|
|
but when recording, just build a chain pretty much of commands to be replayed. */
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
|
|
float rho;
|
|
PLIGHTINFOEL *object, *temp;
|
|
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
|
|
|
|
/* If recording state block, just add to end of lights chain */
|
|
if (This->isRecordingState) {
|
|
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
|
|
if (NULL == object) {
|
|
return D3DERR_OUTOFVIDEOMEMORY;
|
|
}
|
|
memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
|
|
object->OriginalIndex = Index;
|
|
object->glIndex = -1;
|
|
object->changed = TRUE;
|
|
|
|
/* Add to the END of the chain of lights changes to be replayed */
|
|
if (This->updateStateBlock->lights == NULL) {
|
|
This->updateStateBlock->lights = object;
|
|
} else {
|
|
temp = This->updateStateBlock->lights;
|
|
while (temp->next != NULL) temp=temp->next;
|
|
temp->next = object;
|
|
}
|
|
TRACE("Recording... not performing anything more\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Ok, not recording any longer so do real work */
|
|
object = This->stateBlock->lights;
|
|
while (object != NULL && object->OriginalIndex != Index) object = object->next;
|
|
|
|
/* If we didn't find it in the list of lights, time to add it */
|
|
if (object == NULL) {
|
|
PLIGHTINFOEL *insertAt,*prevPos;
|
|
|
|
object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
|
|
if (NULL == object) {
|
|
return D3DERR_OUTOFVIDEOMEMORY;
|
|
}
|
|
object->OriginalIndex = Index;
|
|
object->glIndex = -1;
|
|
|
|
/* Add it to the front of list with the idea that lights will be changed as needed
|
|
BUT after any lights currently assigned GL indexes */
|
|
insertAt = This->stateBlock->lights;
|
|
prevPos = NULL;
|
|
while (insertAt != NULL && insertAt->glIndex != -1) {
|
|
prevPos = insertAt;
|
|
insertAt = insertAt->next;
|
|
}
|
|
|
|
if (insertAt == NULL && prevPos == NULL) { /* Start of list */
|
|
This->stateBlock->lights = object;
|
|
} else if (insertAt == NULL) { /* End of list */
|
|
prevPos->next = object;
|
|
object->prev = prevPos;
|
|
} else { /* Middle of chain */
|
|
if (prevPos == NULL) {
|
|
This->stateBlock->lights = object;
|
|
} else {
|
|
prevPos->next = object;
|
|
}
|
|
object->prev = prevPos;
|
|
object->next = insertAt;
|
|
insertAt->prev = object;
|
|
}
|
|
}
|
|
|
|
/* Initialze the object */
|
|
TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
|
|
pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
|
|
pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
|
|
pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
|
|
TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
|
|
pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
|
|
TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
|
|
|
|
/* Save away the information */
|
|
memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
|
|
|
|
switch (pLight->Type) {
|
|
case D3DLIGHT_POINT:
|
|
/* Position */
|
|
object->lightPosn[0] = pLight->Position.x;
|
|
object->lightPosn[1] = pLight->Position.y;
|
|
object->lightPosn[2] = pLight->Position.z;
|
|
object->lightPosn[3] = 1.0f;
|
|
object->cutoff = 180.0f;
|
|
/* FIXME: Range */
|
|
break;
|
|
|
|
case D3DLIGHT_DIRECTIONAL:
|
|
/* Direction */
|
|
object->lightPosn[0] = -pLight->Direction.x;
|
|
object->lightPosn[1] = -pLight->Direction.y;
|
|
object->lightPosn[2] = -pLight->Direction.z;
|
|
object->lightPosn[3] = 0.0;
|
|
object->exponent = 0.0f;
|
|
object->cutoff = 180.0f;
|
|
break;
|
|
|
|
case D3DLIGHT_SPOT:
|
|
/* Position */
|
|
object->lightPosn[0] = pLight->Position.x;
|
|
object->lightPosn[1] = pLight->Position.y;
|
|
object->lightPosn[2] = pLight->Position.z;
|
|
object->lightPosn[3] = 1.0;
|
|
|
|
/* Direction */
|
|
object->lightDirn[0] = pLight->Direction.x;
|
|
object->lightDirn[1] = pLight->Direction.y;
|
|
object->lightDirn[2] = pLight->Direction.z;
|
|
object->lightDirn[3] = 1.0;
|
|
|
|
/*
|
|
* opengl-ish and d3d-ish spot lights use too different models for the
|
|
* light "intensity" as a function of the angle towards the main light direction,
|
|
* so we only can approximate very roughly.
|
|
* however spot lights are rather rarely used in games (if ever used at all).
|
|
* furthermore if still used, probably nobody pays attention to such details.
|
|
*/
|
|
if (pLight->Falloff == 0) {
|
|
rho = 6.28f;
|
|
} else {
|
|
rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
|
|
}
|
|
if (rho < 0.0001) rho = 0.0001f;
|
|
object->exponent = -0.3/log(cos(rho/2));
|
|
object->cutoff = pLight->Phi*90/M_PI;
|
|
|
|
/* FIXME: Range */
|
|
break;
|
|
|
|
default:
|
|
FIXME("Unrecognized light type %d\n", pLight->Type);
|
|
}
|
|
|
|
/* Update the live definitions if the light is currently assigned a glIndex */
|
|
if (object->glIndex != -1) {
|
|
setup_light(iface, object->glIndex, object);
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
|
|
PLIGHTINFOEL *lightInfo = NULL;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
|
|
|
|
/* Locate the light in the live lights */
|
|
lightInfo = This->stateBlock->lights;
|
|
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
|
|
|
|
if (lightInfo == NULL) {
|
|
TRACE("Light information requested but light not defined\n");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Light Enable
|
|
* (Note for consistency, renamed d3dx function by adding the 'set' prefix)
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
|
|
PLIGHTINFOEL *lightInfo = NULL;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
|
|
|
|
/* If recording state block, just add to end of lights chain with changedEnable set to true */
|
|
if (This->isRecordingState) {
|
|
lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
|
|
if (NULL == lightInfo) {
|
|
return D3DERR_OUTOFVIDEOMEMORY;
|
|
}
|
|
lightInfo->OriginalIndex = Index;
|
|
lightInfo->glIndex = -1;
|
|
lightInfo->enabledChanged = TRUE;
|
|
|
|
/* Add to the END of the chain of lights changes to be replayed */
|
|
if (This->updateStateBlock->lights == NULL) {
|
|
This->updateStateBlock->lights = lightInfo;
|
|
} else {
|
|
PLIGHTINFOEL *temp = This->updateStateBlock->lights;
|
|
while (temp->next != NULL) temp=temp->next;
|
|
temp->next = lightInfo;
|
|
}
|
|
TRACE("Recording... not performing anything more\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Not recording... So, locate the light in the live lights */
|
|
lightInfo = This->stateBlock->lights;
|
|
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
|
|
|
|
/* Special case - enabling an undefined light creates one with a strict set of parms! */
|
|
if (lightInfo == NULL) {
|
|
D3DLIGHT9 lightParms;
|
|
/* Warning - untested code :-) Prob safe to change fixme to a trace but
|
|
wait until someone confirms it seems to work! */
|
|
TRACE("Light enabled requested but light not defined, so defining one!\n");
|
|
lightParms.Type = D3DLIGHT_DIRECTIONAL;
|
|
lightParms.Diffuse.r = 1.0;
|
|
lightParms.Diffuse.g = 1.0;
|
|
lightParms.Diffuse.b = 1.0;
|
|
lightParms.Diffuse.a = 0.0;
|
|
lightParms.Specular.r = 0.0;
|
|
lightParms.Specular.g = 0.0;
|
|
lightParms.Specular.b = 0.0;
|
|
lightParms.Specular.a = 0.0;
|
|
lightParms.Ambient.r = 0.0;
|
|
lightParms.Ambient.g = 0.0;
|
|
lightParms.Ambient.b = 0.0;
|
|
lightParms.Ambient.a = 0.0;
|
|
lightParms.Position.x = 0.0;
|
|
lightParms.Position.y = 0.0;
|
|
lightParms.Position.z = 0.0;
|
|
lightParms.Direction.x = 0.0;
|
|
lightParms.Direction.y = 0.0;
|
|
lightParms.Direction.z = 1.0;
|
|
lightParms.Range = 0.0;
|
|
lightParms.Falloff = 0.0;
|
|
lightParms.Attenuation0 = 0.0;
|
|
lightParms.Attenuation1 = 0.0;
|
|
lightParms.Attenuation2 = 0.0;
|
|
lightParms.Theta = 0.0;
|
|
lightParms.Phi = 0.0;
|
|
IWineD3DDeviceImpl_SetLight(iface, Index, &lightParms);
|
|
|
|
/* Search for it again! Should be fairly quick as near head of list */
|
|
lightInfo = This->stateBlock->lights;
|
|
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
|
|
if (lightInfo == NULL) {
|
|
FIXME("Adding default lights has failed dismally\n");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
|
|
/* OK, we now have a light... */
|
|
if (Enable == FALSE) {
|
|
|
|
/* If we are disabling it, check it was enabled, and
|
|
still only do something if it has assigned a glIndex (which it should have!) */
|
|
if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
|
|
TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
|
|
ENTER_GL();
|
|
glDisable(GL_LIGHT0 + lightInfo->glIndex);
|
|
checkGLcall("glDisable GL_LIGHT0+Index");
|
|
LEAVE_GL();
|
|
} else {
|
|
TRACE("Nothing to do as light was not enabled\n");
|
|
}
|
|
lightInfo->lightEnabled = FALSE;
|
|
} else {
|
|
|
|
/* We are enabling it. If it is enabled, its really simple */
|
|
if (lightInfo->lightEnabled) {
|
|
/* nop */
|
|
TRACE("Nothing to do as light was enabled\n");
|
|
|
|
/* If it already has a glIndex, its still simple */
|
|
} else if (lightInfo->glIndex != -1) {
|
|
TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
|
|
lightInfo->lightEnabled = TRUE;
|
|
ENTER_GL();
|
|
glEnable(GL_LIGHT0 + lightInfo->glIndex);
|
|
checkGLcall("glEnable GL_LIGHT0+Index already setup");
|
|
LEAVE_GL();
|
|
|
|
/* Otherwise got to find space - lights are ordered gl indexes first */
|
|
} else {
|
|
PLIGHTINFOEL *bsf = NULL;
|
|
PLIGHTINFOEL *pos = This->stateBlock->lights;
|
|
PLIGHTINFOEL *prev = NULL;
|
|
int Index= 0;
|
|
int glIndex = -1;
|
|
|
|
/* Try to minimize changes as much as possible */
|
|
while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
|
|
|
|
/* Try to remember which index can be replaced if necessary */
|
|
if (bsf==NULL && pos->lightEnabled == FALSE) {
|
|
/* Found a light we can replace, save as best replacement */
|
|
bsf = pos;
|
|
}
|
|
|
|
/* Step to next space */
|
|
prev = pos;
|
|
pos = pos->next;
|
|
Index ++;
|
|
}
|
|
|
|
/* If we have too many active lights, fail the call */
|
|
if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
|
|
FIXME("Program requests too many concurrent lights\n");
|
|
return D3DERR_INVALIDCALL;
|
|
|
|
/* If we have allocated all lights, but not all are enabled,
|
|
reuse one which is not enabled */
|
|
} else if (Index == This->maxConcurrentLights) {
|
|
/* use bsf - Simply swap the new light and the BSF one */
|
|
PLIGHTINFOEL *bsfNext = bsf->next;
|
|
PLIGHTINFOEL *bsfPrev = bsf->prev;
|
|
|
|
/* Sort out ends */
|
|
if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
|
|
if (bsf->prev != NULL) {
|
|
bsf->prev->next = lightInfo;
|
|
} else {
|
|
This->stateBlock->lights = lightInfo;
|
|
}
|
|
|
|
/* If not side by side, lots of chains to update */
|
|
if (bsf->next != lightInfo) {
|
|
lightInfo->prev->next = bsf;
|
|
bsf->next->prev = lightInfo;
|
|
bsf->next = lightInfo->next;
|
|
bsf->prev = lightInfo->prev;
|
|
lightInfo->next = bsfNext;
|
|
lightInfo->prev = bsfPrev;
|
|
|
|
} else {
|
|
/* Simple swaps */
|
|
bsf->prev = lightInfo;
|
|
bsf->next = lightInfo->next;
|
|
lightInfo->next = bsf;
|
|
lightInfo->prev = bsfPrev;
|
|
}
|
|
|
|
|
|
/* Update states */
|
|
glIndex = bsf->glIndex;
|
|
bsf->glIndex = -1;
|
|
lightInfo->glIndex = glIndex;
|
|
lightInfo->lightEnabled = TRUE;
|
|
|
|
/* Finally set up the light in gl itself */
|
|
TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
|
|
ENTER_GL();
|
|
setup_light(iface, glIndex, lightInfo);
|
|
glEnable(GL_LIGHT0 + glIndex);
|
|
checkGLcall("glEnable GL_LIGHT0 new setup");
|
|
LEAVE_GL();
|
|
|
|
/* If we reached the end of the allocated lights, with space in the
|
|
gl lights, setup a new light */
|
|
} else if (pos->glIndex == -1) {
|
|
|
|
/* We reached the end of the allocated gl lights, so already
|
|
know the index of the next one! */
|
|
glIndex = Index;
|
|
lightInfo->glIndex = glIndex;
|
|
lightInfo->lightEnabled = TRUE;
|
|
|
|
/* In an ideal world, its already in the right place */
|
|
if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
|
|
/* No need to move it */
|
|
} else {
|
|
/* Remove this light from the list */
|
|
lightInfo->prev->next = lightInfo->next;
|
|
if (lightInfo->next != NULL) {
|
|
lightInfo->next->prev = lightInfo->prev;
|
|
}
|
|
|
|
/* Add in at appropriate place (inbetween prev and pos) */
|
|
lightInfo->prev = prev;
|
|
lightInfo->next = pos;
|
|
if (prev == NULL) {
|
|
This->stateBlock->lights = lightInfo;
|
|
} else {
|
|
prev->next = lightInfo;
|
|
}
|
|
if (pos != NULL) {
|
|
pos->prev = lightInfo;
|
|
}
|
|
}
|
|
|
|
/* Finally set up the light in gl itself */
|
|
TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
|
|
ENTER_GL();
|
|
setup_light(iface, glIndex, lightInfo);
|
|
glEnable(GL_LIGHT0 + glIndex);
|
|
checkGLcall("glEnable GL_LIGHT0 new setup");
|
|
LEAVE_GL();
|
|
|
|
}
|
|
}
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
|
|
|
|
PLIGHTINFOEL *lightInfo = NULL;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : for idx(%ld)\n", This, Index);
|
|
|
|
/* Locate the light in the live lights */
|
|
lightInfo = This->stateBlock->lights;
|
|
while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
|
|
|
|
if (lightInfo == NULL) {
|
|
TRACE("Light enabled state requested but light not defined\n");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
*pEnable = lightInfo->lightEnabled;
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Clip Planes
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
|
|
|
|
/* Validate Index */
|
|
if (Index >= GL_LIMITS(clipplanes)) {
|
|
TRACE("Application has requested clipplane this device doesn't support\n");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
This->updateStateBlock->changed.clipplane[Index] = TRUE;
|
|
This->updateStateBlock->set.clipplane[Index] = TRUE;
|
|
This->updateStateBlock->clipplane[Index][0] = pPlane[0];
|
|
This->updateStateBlock->clipplane[Index][1] = pPlane[1];
|
|
This->updateStateBlock->clipplane[Index][2] = pPlane[2];
|
|
This->updateStateBlock->clipplane[Index][3] = pPlane[3];
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* Apply it */
|
|
|
|
ENTER_GL();
|
|
|
|
/* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
|
|
|
|
TRACE("Clipplane [%f,%f,%f,%f]\n",
|
|
This->updateStateBlock->clipplane[Index][0],
|
|
This->updateStateBlock->clipplane[Index][1],
|
|
This->updateStateBlock->clipplane[Index][2],
|
|
This->updateStateBlock->clipplane[Index][3]);
|
|
glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
|
|
checkGLcall("glClipPlane");
|
|
|
|
glPopMatrix();
|
|
LEAVE_GL();
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : for idx %ld\n", This, Index);
|
|
|
|
/* Validate Index */
|
|
if (Index >= GL_LIMITS(clipplanes)) {
|
|
TRACE("Application has requested clipplane this device doesn't support\n");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
pPlane[0] = This->stateBlock->clipplane[Index][0];
|
|
pPlane[1] = This->stateBlock->clipplane[Index][1];
|
|
pPlane[2] = This->stateBlock->clipplane[Index][2];
|
|
pPlane[3] = This->stateBlock->clipplane[Index][3];
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Clip Plane Status
|
|
* WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
FIXME("(%p) : stub\n", This);
|
|
if (NULL == pClipStatus) {
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
|
|
This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
FIXME("(%p) : stub\n", This);
|
|
if (NULL == pClipStatus) {
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
|
|
pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Material
|
|
* WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
This->updateStateBlock->changed.material = TRUE;
|
|
This->updateStateBlock->set.material = TRUE;
|
|
memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
ENTER_GL();
|
|
TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
|
|
TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
|
|
TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
|
|
TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
|
|
TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
|
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
|
|
checkGLcall("glMaterialfv");
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
|
|
checkGLcall("glMaterialfv");
|
|
|
|
/* Only change material color if specular is enabled, otherwise it is set to black */
|
|
#if 0 /* TODO */
|
|
if (This->stateBlock->renderstate[D3DRS_SPECULARENABLE]) {
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular);
|
|
checkGLcall("glMaterialfv");
|
|
} else {
|
|
#endif
|
|
{
|
|
float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
|
|
checkGLcall("glMaterialfv");
|
|
}
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
|
|
checkGLcall("glMaterialfv");
|
|
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
|
|
checkGLcall("glMaterialf");
|
|
|
|
LEAVE_GL();
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
|
|
TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
|
|
TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
|
|
TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
|
|
TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
|
|
TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Indices
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
|
|
UINT BaseVertexIndex) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
IWineD3DIndexBuffer *oldIdxs;
|
|
|
|
TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
|
|
oldIdxs = This->updateStateBlock->pIndexData;
|
|
|
|
This->updateStateBlock->changed.indices = TRUE;
|
|
This->updateStateBlock->set.indices = TRUE;
|
|
This->updateStateBlock->pIndexData = pIndexData;
|
|
This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
if (oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
|
|
if (pIndexData) IWineD3DIndexBuffer_AddRef(This->stateBlock->pIndexData);
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
*ppIndexData = This->stateBlock->pIndexData;
|
|
|
|
/* up ref count on ppindexdata */
|
|
if (*ppIndexData) IWineD3DIndexBuffer_AddRef(*ppIndexData);
|
|
*pBaseVertexIndex = This->stateBlock->baseVertexIndex;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Get / Set Viewports
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
TRACE("(%p)\n", This);
|
|
This->updateStateBlock->changed.viewport = TRUE;
|
|
This->updateStateBlock->set.viewport = TRUE;
|
|
memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
|
|
|
|
/* Handle recording of state blocks */
|
|
if (This->isRecordingState) {
|
|
TRACE("Recording... not performing anything\n");
|
|
return D3D_OK;
|
|
}
|
|
|
|
ENTER_GL();
|
|
|
|
TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
|
|
pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
|
|
|
|
glDepthRange(pViewport->MinZ, pViewport->MaxZ);
|
|
checkGLcall("glDepthRange");
|
|
|
|
#if 0 /* TODO */
|
|
/* Note: GL requires lower left, DirectX supplies upper left */
|
|
glViewport(pViewport->X, (This->renderTarget->myDesc.Height - (pViewport->Y + pViewport->Height)),
|
|
pViewport->Width, pViewport->Height);
|
|
checkGLcall("glViewport");
|
|
#endif
|
|
|
|
LEAVE_GL();
|
|
|
|
return D3D_OK;
|
|
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p)\n", This);
|
|
memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Scene related functions
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
|
|
/* At the moment we have no need for any functionality at the beginning
|
|
of a scene */
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : stub\n", This);
|
|
return D3D_OK;
|
|
}
|
|
|
|
/*****
|
|
* Drawing functions
|
|
*****/
|
|
HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
|
|
UINT PrimitiveCount) {
|
|
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
This->stateBlock->streamIsUP = FALSE;
|
|
|
|
TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
|
|
debug_d3dprimitivetype(PrimitiveType),
|
|
StartVertex, PrimitiveCount);
|
|
drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, -1, 0, NULL, 0);
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
/* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
|
|
HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
|
|
D3DPRIMITIVETYPE PrimitiveType,
|
|
INT baseVIndex, UINT minIndex,
|
|
UINT NumVertices,UINT startIndex,UINT primCount) {
|
|
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
UINT idxStride = 2;
|
|
IWineD3DIndexBuffer *pIB;
|
|
D3DINDEXBUFFER_DESC IdxBufDsc;
|
|
|
|
pIB = This->stateBlock->pIndexData;
|
|
This->stateBlock->streamIsUP = FALSE;
|
|
|
|
TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d \n", This,
|
|
PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
|
|
minIndex, NumVertices, startIndex, baseVIndex, primCount);
|
|
|
|
IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
|
|
if (IdxBufDsc.Format == D3DFMT_INDEX16) {
|
|
idxStride = 2;
|
|
} else {
|
|
idxStride = 4;
|
|
}
|
|
|
|
drawPrimitive(iface, PrimitiveType, primCount, baseVIndex,
|
|
startIndex, idxStride,
|
|
((IWineD3DIndexBufferImpl *) pIB)->allocatedMemory,
|
|
minIndex);
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
|
|
UINT VertexStreamZeroStride) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
|
|
debug_d3dprimitivetype(PrimitiveType),
|
|
PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
|
|
|
|
if (This->stateBlock->stream_source[0] != NULL) IWineD3DVertexBuffer_Release(This->stateBlock->stream_source[0]);
|
|
|
|
/* Note in the following, its not this type, but thats the purpose of streamIsUP */
|
|
This->stateBlock->stream_source[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
|
|
This->stateBlock->stream_stride[0] = VertexStreamZeroStride;
|
|
This->stateBlock->streamIsUP = TRUE;
|
|
drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
|
|
This->stateBlock->stream_stride[0] = 0;
|
|
This->stateBlock->stream_source[0] = NULL;
|
|
|
|
/*stream zero settings set to null at end, as per the msdn */
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT MinVertexIndex,
|
|
UINT NumVertexIndices,UINT PrimitiveCount,CONST void* pIndexData,
|
|
D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
|
|
UINT VertexStreamZeroStride) {
|
|
int idxStride;
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
|
|
TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
|
|
This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
|
|
MinVertexIndex, NumVertexIndices, PrimitiveCount, pIndexData,
|
|
IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
|
|
|
|
if (This->stateBlock->stream_source[0] != NULL) IWineD3DVertexBuffer_Release(This->stateBlock->stream_source[0]);
|
|
|
|
if (IndexDataFormat == D3DFMT_INDEX16) {
|
|
idxStride = 2;
|
|
} else {
|
|
idxStride = 4;
|
|
}
|
|
|
|
/* Note in the following, its not this type, but thats the purpose of streamIsUP */
|
|
This->stateBlock->stream_source[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
|
|
This->stateBlock->streamIsUP = TRUE;
|
|
This->stateBlock->stream_stride[0] = VertexStreamZeroStride;
|
|
|
|
drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, idxStride, pIndexData, MinVertexIndex);
|
|
|
|
/* stream zero settings set to null at end as per the msdn */
|
|
This->stateBlock->stream_source[0] = NULL;
|
|
This->stateBlock->stream_stride[0] = 0;
|
|
IWineD3DDevice_SetIndices(iface, NULL, 0);
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
/**********************************************************
|
|
* IUnknown parts follows
|
|
**********************************************************/
|
|
|
|
HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
TRACE("(%p) : AddRef increasing from %ld\n", This, This->ref);
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
|
|
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
|
ULONG ref;
|
|
TRACE("(%p) : Releasing from %ld\n", This, This->ref);
|
|
ref = InterlockedDecrement(&This->ref);
|
|
if (ref == 0) {
|
|
IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
|
|
IWineD3D_Release(This->wineD3D);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
return ref;
|
|
}
|
|
|
|
/**********************************************************
|
|
* IWineD3DDevice VTbl follows
|
|
**********************************************************/
|
|
|
|
IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
|
|
{
|
|
IWineD3DDeviceImpl_QueryInterface,
|
|
IWineD3DDeviceImpl_AddRef,
|
|
IWineD3DDeviceImpl_Release,
|
|
IWineD3DDeviceImpl_GetParent,
|
|
IWineD3DDeviceImpl_CreateVertexBuffer,
|
|
IWineD3DDeviceImpl_CreateIndexBuffer,
|
|
IWineD3DDeviceImpl_CreateStateBlock,
|
|
|
|
IWineD3DDeviceImpl_SetFVF,
|
|
IWineD3DDeviceImpl_GetFVF,
|
|
IWineD3DDeviceImpl_SetStreamSource,
|
|
IWineD3DDeviceImpl_GetStreamSource,
|
|
IWineD3DDeviceImpl_SetTransform,
|
|
IWineD3DDeviceImpl_GetTransform,
|
|
IWineD3DDeviceImpl_MultiplyTransform,
|
|
IWineD3DDeviceImpl_SetLight,
|
|
IWineD3DDeviceImpl_GetLight,
|
|
IWineD3DDeviceImpl_SetLightEnable,
|
|
IWineD3DDeviceImpl_GetLightEnable,
|
|
IWineD3DDeviceImpl_SetClipPlane,
|
|
IWineD3DDeviceImpl_GetClipPlane,
|
|
IWineD3DDeviceImpl_SetClipStatus,
|
|
IWineD3DDeviceImpl_GetClipStatus,
|
|
IWineD3DDeviceImpl_SetMaterial,
|
|
IWineD3DDeviceImpl_GetMaterial,
|
|
IWineD3DDeviceImpl_SetIndices,
|
|
IWineD3DDeviceImpl_GetIndices,
|
|
IWineD3DDeviceImpl_SetViewport,
|
|
IWineD3DDeviceImpl_GetViewport,
|
|
|
|
IWineD3DDeviceImpl_BeginScene,
|
|
|
|
IWineD3DDeviceImpl_DrawPrimitive,
|
|
IWineD3DDeviceImpl_DrawIndexedPrimitive,
|
|
IWineD3DDeviceImpl_DrawPrimitiveUP,
|
|
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
|
|
};
|