blob: c191564d6eba568ecaf1226203fc2916e4095fb0 [file] [log] [blame]
/****************************************************************************
*
* Mesa 3-D graphics library
* Direct3D Driver Interface
*
* ========================================================================
*
* Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ======================================================================
*
* Language: ANSI C
* Environment: Windows 9x/2000/XP/XBox (Win32)
*
* Description: Driver interface code to Mesa
*
****************************************************************************/
//#include <windows.h>
#include "dglcontext.h"
#include "ddlog.h"
#include "gld_dx9.h"
#include "glheader.h"
#include "context.h"
#include "colormac.h"
#include "depth.h"
#include "extensions.h"
#include "macros.h"
#include "matrix.h"
// #include "mem.h"
//#include "mmath.h"
#include "mtypes.h"
#include "texformat.h"
#include "teximage.h"
#include "texstore.h"
#include "vbo/vbo.h"
#include "swrast_setup/swrast_setup.h"
#include "swrast_setup/ss_context.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_pipeline.h"
extern BOOL dglSwapBuffers(HDC hDC);
// HACK: Hack the _33 member of the OpenGL perspective projection matrix
const float _fPersp_33 = 1.6f;
//---------------------------------------------------------------------------
// Internal functions
//---------------------------------------------------------------------------
void _gld_mesa_warning(
__GLcontext *gc,
char *str)
{
// Intercept Mesa's internal warning mechanism
gldLogPrintf(GLDLOG_WARN, "Mesa warning: %s", str);
}
//---------------------------------------------------------------------------
void _gld_mesa_fatal(
__GLcontext *gc,
char *str)
{
// Intercept Mesa's internal fatal-message mechanism
gldLogPrintf(GLDLOG_CRITICAL, "Mesa FATAL: %s", str);
// Mesa calls abort(0) here.
ddlogClose();
exit(0);
}
//---------------------------------------------------------------------------
D3DSTENCILOP _gldConvertStencilOp(
GLenum StencilOp)
{
// Used by Stencil: pass, fail and zfail
switch (StencilOp) {
case GL_KEEP:
return D3DSTENCILOP_KEEP;
case GL_ZERO:
return D3DSTENCILOP_ZERO;
case GL_REPLACE:
return D3DSTENCILOP_REPLACE;
case GL_INCR:
return D3DSTENCILOP_INCRSAT;
case GL_DECR:
return D3DSTENCILOP_DECRSAT;
case GL_INVERT:
return D3DSTENCILOP_INVERT;
case GL_INCR_WRAP_EXT: // GL_EXT_stencil_wrap
return D3DSTENCILOP_INCR;
case GL_DECR_WRAP_EXT: // GL_EXT_stencil_wrap
return D3DSTENCILOP_DECR;
}
#ifdef _DEBUG
gldLogMessage(GLDLOG_ERROR, "_gldConvertStencilOp: Unknown StencilOp\n");
#endif
return D3DSTENCILOP_KEEP;
}
//---------------------------------------------------------------------------
D3DCMPFUNC _gldConvertCompareFunc(
GLenum CmpFunc)
{
// Used for Alpha func, depth func and stencil func.
switch (CmpFunc) {
case GL_NEVER:
return D3DCMP_NEVER;
case GL_LESS:
return D3DCMP_LESS;
case GL_EQUAL:
return D3DCMP_EQUAL;
case GL_LEQUAL:
return D3DCMP_LESSEQUAL;
case GL_GREATER:
return D3DCMP_GREATER;
case GL_NOTEQUAL:
return D3DCMP_NOTEQUAL;
case GL_GEQUAL:
return D3DCMP_GREATEREQUAL;
case GL_ALWAYS:
return D3DCMP_ALWAYS;
};
#ifdef _DEBUG
gldLogMessage(GLDLOG_ERROR, "_gldConvertCompareFunc: Unknown CompareFunc\n");
#endif
return D3DCMP_ALWAYS;
}
//---------------------------------------------------------------------------
D3DBLEND _gldConvertBlendFunc(
GLenum blend,
GLenum DefaultBlend)
{
switch (blend) {
case GL_ZERO:
return D3DBLEND_ZERO;
case GL_ONE:
return D3DBLEND_ONE;
case GL_DST_COLOR:
return D3DBLEND_DESTCOLOR;
case GL_SRC_COLOR:
return D3DBLEND_SRCCOLOR;
case GL_ONE_MINUS_DST_COLOR:
return D3DBLEND_INVDESTCOLOR;
case GL_ONE_MINUS_SRC_COLOR:
return D3DBLEND_INVSRCCOLOR;
case GL_SRC_ALPHA:
return D3DBLEND_SRCALPHA;
case GL_ONE_MINUS_SRC_ALPHA:
return D3DBLEND_INVSRCALPHA;
case GL_DST_ALPHA:
return D3DBLEND_DESTALPHA;
case GL_ONE_MINUS_DST_ALPHA:
return D3DBLEND_INVDESTALPHA;
case GL_SRC_ALPHA_SATURATE:
return D3DBLEND_SRCALPHASAT;
}
#ifdef _DEBUG
gldLogMessage(GLDLOG_ERROR, "_gldConvertBlendFunc: Unknown BlendFunc\n");
#endif
return DefaultBlend;
}
//---------------------------------------------------------------------------
// Misc. functions
//---------------------------------------------------------------------------
void gld_Noop_DX9(
GLcontext *ctx)
{
#ifdef _DEBUG
gldLogMessage(GLDLOG_ERROR, "gld_Noop called!\n");
#endif
}
//---------------------------------------------------------------------------
void gld_Error_DX9(
GLcontext *ctx)
{
#ifdef _DEBUG
// Quite useless.
// gldLogMessage(GLDLOG_ERROR, "ctx->Driver.Error called!\n");
#endif
}
//---------------------------------------------------------------------------
// Required Mesa functions
//---------------------------------------------------------------------------
static GLboolean gld_set_draw_buffer_DX9(
GLcontext *ctx,
GLenum mode)
{
(void) ctx;
if ((mode==GL_FRONT_LEFT) || (mode == GL_BACK_LEFT)) {
return GL_TRUE;
}
else {
return GL_FALSE;
}
}
//---------------------------------------------------------------------------
static void gld_set_read_buffer_DX9(
GLcontext *ctx,
GLframebuffer *buffer,
GLenum mode)
{
/* separate read buffer not supported */
/*
ASSERT(buffer == ctx->DrawBuffer);
ASSERT(mode == GL_FRONT_LEFT);
*/
}
//---------------------------------------------------------------------------
void gld_Clear_DX9(
GLcontext *ctx,
GLbitfield mask,
GLboolean all,
GLint x,
GLint y,
GLint width,
GLint height)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
DWORD dwFlags = 0;
D3DCOLOR Color = 0;
float Z = 0.0f;
DWORD Stencil = 0;
D3DRECT d3dClearRect;
// TODO: Colourmask
const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask;
if (!gld->pDev)
return;
if (mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT)) {
GLubyte col[4];
CLAMPED_FLOAT_TO_UBYTE(col[0], ctx->Color.ClearColor[0]);
CLAMPED_FLOAT_TO_UBYTE(col[1], ctx->Color.ClearColor[1]);
CLAMPED_FLOAT_TO_UBYTE(col[2], ctx->Color.ClearColor[2]);
CLAMPED_FLOAT_TO_UBYTE(col[3], ctx->Color.ClearColor[3]);
dwFlags |= D3DCLEAR_TARGET;
Color = D3DCOLOR_RGBA(col[0], col[1], col[2], col[3]);
}
if (mask & DD_DEPTH_BIT) {
// D3D8 will fail the Clear call if we try and clear a
// depth buffer and we haven't created one.
// Also, some apps try and clear a depth buffer,
// when a depth buffer hasn't been requested by the app.
if (ctx->Visual.depthBits == 0) {
mask &= ~DD_DEPTH_BIT; // Remove depth bit from mask
} else {
dwFlags |= D3DCLEAR_ZBUFFER;
Z = ctx->Depth.Clear;
}
}
if (mask & DD_STENCIL_BIT) {
if (ctx->Visual.stencilBits == 0) {
// No stencil bits in depth buffer
mask &= ~DD_STENCIL_BIT; // Remove stencil bit from mask
} else {
dwFlags |= D3DCLEAR_STENCIL;
Stencil = ctx->Stencil.Clear;
}
}
// Some apps do really weird things with the rect, such as Quake3.
if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0)) {
all = GL_TRUE;
}
if (!all) {
// Calculate clear subrect
d3dClearRect.x1 = x;
d3dClearRect.y1 = gldCtx->dwHeight - (y + height);
d3dClearRect.x2 = x + width;
d3dClearRect.y2 = d3dClearRect.y1 + height;
// gldLogPrintf(GLDLOG_INFO, "Rect %d,%d %d,%d", x,y,width,height);
}
// dwFlags will be zero if there's nothing to clear
if (dwFlags) {
_GLD_DX9_DEV(Clear(
gld->pDev,
all ? 0 : 1,
all ? NULL : &d3dClearRect,
dwFlags,
Color, Z, Stencil));
}
if (mask & DD_ACCUM_BIT) {
// Clear accumulation buffer
}
}
//---------------------------------------------------------------------------
// Mesa 5: Parameter change
static void gld_buffer_size_DX9(
// GLcontext *ctx,
GLframebuffer *fb,
GLuint *width,
GLuint *height)
{
// GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
*width = fb->Width; // gldCtx->dwWidth;
*height = fb->Height; // gldCtx->dwHeight;
}
//---------------------------------------------------------------------------
static void gld_Finish_DX9(
GLcontext *ctx)
{
}
//---------------------------------------------------------------------------
static void gld_Flush_DX9(
GLcontext *ctx)
{
GLD_context *gld = GLD_GET_CONTEXT(ctx);
// TODO: Detect apps that glFlush() then SwapBuffers() ?
if (gld->EmulateSingle) {
// Emulating a single-buffered context.
// [Direct3D doesn't allow rendering to front buffer]
dglSwapBuffers(gld->hDC);
}
}
//---------------------------------------------------------------------------
void gld_NEW_STENCIL(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
// Two-sided stencil. New for Mesa 5
const GLuint uiFace = 0UL;
struct gl_stencil_attrib *pStencil = &ctx->Stencil;
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILENABLE, pStencil->Enabled ? TRUE : FALSE));
if (pStencil->Enabled) {
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILFUNC, _gldConvertCompareFunc(pStencil->Function[uiFace])));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILREF, pStencil->Ref[uiFace]));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILMASK, pStencil->ValueMask[uiFace]));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILWRITEMASK, pStencil->WriteMask[uiFace]));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILFAIL, _gldConvertStencilOp(pStencil->FailFunc[uiFace])));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILZFAIL, _gldConvertStencilOp(pStencil->ZFailFunc[uiFace])));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_STENCILPASS, _gldConvertStencilOp(pStencil->ZPassFunc[uiFace])));
}
}
//---------------------------------------------------------------------------
void gld_NEW_COLOR(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
DWORD dwFlags = 0;
D3DBLEND src;
D3DBLEND dest;
// Alpha func
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ALPHAFUNC, _gldConvertCompareFunc(ctx->Color.AlphaFunc)));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ALPHAREF, (DWORD)ctx->Color.AlphaRef));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ALPHATESTENABLE, ctx->Color.AlphaEnabled));
// Blend func
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ALPHABLENDENABLE, ctx->Color.BlendEnabled));
src = _gldConvertBlendFunc(ctx->Color.BlendSrcRGB, GL_ONE);
dest = _gldConvertBlendFunc(ctx->Color.BlendDstRGB, GL_ZERO);
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SRCBLEND, src));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_DESTBLEND, dest));
// Color mask
if (ctx->Color.ColorMask[0]) dwFlags |= D3DCOLORWRITEENABLE_RED;
if (ctx->Color.ColorMask[1]) dwFlags |= D3DCOLORWRITEENABLE_GREEN;
if (ctx->Color.ColorMask[2]) dwFlags |= D3DCOLORWRITEENABLE_BLUE;
if (ctx->Color.ColorMask[3]) dwFlags |= D3DCOLORWRITEENABLE_ALPHA;
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_COLORWRITEENABLE, dwFlags));
}
//---------------------------------------------------------------------------
void gld_NEW_DEPTH(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ZENABLE, ctx->Depth.Test ? D3DZB_TRUE : D3DZB_FALSE));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ZFUNC, _gldConvertCompareFunc(ctx->Depth.Func)));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_ZWRITEENABLE, ctx->Depth.Mask ? TRUE : FALSE));
}
//---------------------------------------------------------------------------
void gld_NEW_POLYGON(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DFILLMODE d3dFillMode = D3DFILL_SOLID;
D3DCULL d3dCullMode = D3DCULL_NONE;
float fOffset = 0; // Changed from int to float for DX9
// Fillmode
switch (ctx->Polygon.FrontMode) {
case GL_POINT:
d3dFillMode = D3DFILL_POINT;
break;
case GL_LINE:
d3dFillMode = D3DFILL_WIREFRAME;
break;
case GL_FILL:
d3dFillMode = D3DFILL_SOLID;
break;
}
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FILLMODE, d3dFillMode));
if (ctx->Polygon.CullFlag) {
switch (ctx->Polygon.CullFaceMode) {
case GL_BACK:
if (ctx->Polygon.FrontFace == GL_CCW)
d3dCullMode = D3DCULL_CW;
else
d3dCullMode = D3DCULL_CCW;
break;
case GL_FRONT:
if (ctx->Polygon.FrontFace == GL_CCW)
d3dCullMode = D3DCULL_CCW;
else
d3dCullMode = D3DCULL_CW;
break;
case GL_FRONT_AND_BACK:
d3dCullMode = D3DCULL_NONE;
break;
default:
break;
}
} else {
d3dCullMode = D3DCULL_NONE;
}
// d3dCullMode = D3DCULL_NONE; // FOR DEBUGGING
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_CULLMODE, d3dCullMode));
// Polygon offset
// ZBIAS ranges from 0 to 16 and can only move towards the viewer
// Mesa5: ctx->Polygon._OffsetAny removed
if (ctx->Polygon.OffsetFill) {
fOffset = ctx->Polygon.OffsetUnits;
// if (iOffset < 0.0f)
// iOffset = -iOffset;
// else
// iOffset = 0.0f; // D3D can't push away
}
// NOTE: SetRenderState() required a DWORD, so need to cast
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_DEPTHBIAS, *((DWORD*)&fOffset)));
}
//---------------------------------------------------------------------------
void gld_NEW_FOG(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DCOLOR d3dFogColour;
D3DFOGMODE d3dFogMode = D3DFOG_LINEAR;
// TODO: Fog is calculated seperately in the Mesa pipeline
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGENABLE, FALSE));
return;
// Fog enable
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGENABLE, ctx->Fog.Enabled));
if (!ctx->Fog.Enabled) {
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGTABLEMODE, D3DFOG_NONE));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGVERTEXMODE, D3DFOG_NONE));
return; // If disabled, don't bother setting any fog state
}
// Fog colour
d3dFogColour = D3DCOLOR_COLORVALUE( ctx->Fog.Color[0],
ctx->Fog.Color[1],
ctx->Fog.Color[2],
ctx->Fog.Color[3]);
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGCOLOR, d3dFogColour));
// Fog density
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGDENSITY, *((DWORD*) (&ctx->Fog.Density))));
// Fog start
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGSTART, *((DWORD*) (&ctx->Fog.Start))));
// Fog end
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGEND, *((DWORD*) (&ctx->Fog.End))));
// Fog mode
switch (ctx->Fog.Mode) {
case GL_LINEAR:
d3dFogMode = D3DFOG_LINEAR;
break;
case GL_EXP:
d3dFogMode = D3DFOG_EXP;
break;
case GL_EXP2:
d3dFogMode = D3DFOG_EXP2;
break;
}
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGTABLEMODE, d3dFogMode));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_FOGVERTEXMODE, D3DFOG_NONE));
}
//---------------------------------------------------------------------------
void gld_NEW_LIGHT(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
DWORD dwSpecularEnable;
// Shademode
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SHADEMODE, (ctx->Light.ShadeModel == GL_SMOOTH) ? D3DSHADE_GOURAUD : D3DSHADE_FLAT));
// Separate specular colour
if (ctx->Light.Enabled)
dwSpecularEnable = (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) ? TRUE: FALSE;
else
dwSpecularEnable = FALSE;
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SPECULARENABLE, dwSpecularEnable));
}
//---------------------------------------------------------------------------
void gld_NEW_MODELVIEW(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DMATRIX m;
//GLfloat *pM = ctx->ModelView.m;
// Mesa5: Model-view is now a stack
GLfloat *pM = ctx->ModelviewMatrixStack.Top->m;
m._11 = pM[0];
m._12 = pM[1];
m._13 = pM[2];
m._14 = pM[3];
m._21 = pM[4];
m._22 = pM[5];
m._23 = pM[6];
m._24 = pM[7];
m._31 = pM[8];
m._32 = pM[9];
m._33 = pM[10];
m._34 = pM[11];
m._41 = pM[12];
m._42 = pM[13];
m._43 = pM[14];
m._44 = pM[15];
gld->matModelView = m;
}
//---------------------------------------------------------------------------
void gld_NEW_PROJECTION(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DMATRIX m;
//GLfloat *pM = ctx->ProjectionMatrix.m;
// Mesa 5: Now a stack
GLfloat *pM = ctx->ProjectionMatrixStack.Top->m;
m._11 = pM[0];
m._12 = pM[1];
m._13 = pM[2];
m._14 = pM[3];
m._21 = pM[4];
m._22 = pM[5];
m._23 = pM[6];
m._24 = pM[7];
m._31 = pM[8];
m._32 = pM[9];
m._33 = pM[10] / _fPersp_33; // / 1.6f;
m._34 = pM[11];
m._41 = pM[12];
m._42 = pM[13];
m._43 = pM[14] / 2.0f;
m._44 = pM[15];
gld->matProjection = m;
}
//---------------------------------------------------------------------------
/*
void gldFrustumHook_DX9(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearval,
GLdouble farval)
{
GET_CURRENT_CONTEXT(ctx);
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
// Pass values on to Mesa first (in case we mess with them)
_mesa_Frustum(left, right, bottom, top, nearval, farval);
_fPersp_33 = farval / (nearval - farval);
// ddlogPrintf(GLDLOG_SYSTEM, "Frustum: %f", farval/nearval);
}
//---------------------------------------------------------------------------
void gldOrthoHook_DX9(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearval,
GLdouble farval)
{
GET_CURRENT_CONTEXT(ctx);
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
// Pass values on to Mesa first (in case we mess with them)
_mesa_Ortho(left, right, bottom, top, nearval, farval);
_fPersp_33 = 1.6f;
// ddlogPrintf(GLDLOG_SYSTEM, "Ortho: %f", farval/nearval);
}
*/
//---------------------------------------------------------------------------
void gld_NEW_VIEWPORT(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DVIEWPORT9 d3dvp;
// GLint x, y;
// GLsizei w, h;
// Set depth range
_GLD_DX9_DEV(GetViewport(gld->pDev, &d3dvp));
// D3D can't do Quake1/Quake2 z-trick
if (ctx->Viewport.Near <= ctx->Viewport.Far) {
d3dvp.MinZ = ctx->Viewport.Near;
d3dvp.MaxZ = ctx->Viewport.Far;
} else {
d3dvp.MinZ = ctx->Viewport.Far;
d3dvp.MaxZ = ctx->Viewport.Near;
}
/* x = ctx->Viewport.X;
y = ctx->Viewport.Y;
w = ctx->Viewport.Width;
h = ctx->Viewport.Height;
if (x < 0) x = 0;
if (y < 0) y = 0;
if (w > gldCtx->dwWidth) w = gldCtx->dwWidth;
if (h > gldCtx->dwHeight) h = gldCtx->dwHeight;
// Ditto for D3D viewport dimensions
if (w+x > gldCtx->dwWidth) w = gldCtx->dwWidth-x;
if (h+y > gldCtx->dwHeight) h = gldCtx->dwHeight-y;
d3dvp.X = x;
d3dvp.Y = gldCtx->dwHeight - (y + h);
d3dvp.Width = w;
d3dvp.Height = h;*/
_GLD_DX9_DEV(SetViewport(gld->pDev, &d3dvp));
// gld->fFlipWindowY = (float)gldCtx->dwHeight;
}
//---------------------------------------------------------------------------
void gld_NEW_SCISSOR(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
// Bail if IHV driver cannot scissor
if (!gld->bCanScissor)
return;
// Set scissor rect
if (ctx->Scissor.Enabled) {
RECT rcRect;
// Keep in mind that RECT's need an extra row and column
rcRect.left = ctx->Scissor.X;
rcRect.right = ctx->Scissor.X + ctx->Scissor.Width; // + 1;
rcRect.top = gldCtx->dwHeight - (ctx->Scissor.Y + ctx->Scissor.Height);
rcRect.bottom = rcRect.top + ctx->Scissor.Height;
IDirect3DDevice9_SetScissorRect(gld->pDev, &rcRect);
}
// Enable/disable scissor as required
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SCISSORTESTENABLE, ctx->Scissor.Enabled));
}
//---------------------------------------------------------------------------
__inline BOOL _gldAnyEvalEnabled(
GLcontext *ctx)
{
struct gl_eval_attrib *eval = &ctx->Eval;
if ((eval->AutoNormal) ||
(eval->Map1Color4) ||
(eval->Map1Index) ||
(eval->Map1Normal) ||
(eval->Map1TextureCoord1) ||
(eval->Map1TextureCoord2) ||
(eval->Map1TextureCoord3) ||
(eval->Map1TextureCoord4) ||
(eval->Map1Vertex3) ||
(eval->Map1Vertex4) ||
(eval->Map2Color4) ||
(eval->Map2Index) ||
(eval->Map2Normal) ||
(eval->Map2TextureCoord1) ||
(eval->Map2TextureCoord2) ||
(eval->Map2TextureCoord3) ||
(eval->Map2TextureCoord4) ||
(eval->Map2Vertex3) ||
(eval->Map2Vertex4)
)
return TRUE;
return FALSE;
}
//---------------------------------------------------------------------------
BOOL _gldChooseInternalPipeline(
GLcontext *ctx,
GLD_driver_dx9 *gld)
{
// return TRUE; // DEBUGGING: ALWAYS USE MESA
// return FALSE; // DEBUGGING: ALWAYS USE D3D
if ((glb.dwTnL == GLDS_TNL_MESA) || (gld->bHasHWTnL == FALSE))
{
gld->PipelineUsage.qwMesa.QuadPart++;
return TRUE; // Force Mesa TnL
}
if ((ctx->Light.Enabled) ||
(1) ||
(ctx->Texture._TexGenEnabled) ||
(ctx->Texture._TexMatEnabled) ||
// (ctx->Transform._AnyClip) ||
(ctx->Scissor.Enabled) ||
_gldAnyEvalEnabled(ctx) // Put this last so we can early-out
)
{
gld->PipelineUsage.qwMesa.QuadPart++;
return TRUE;
}
gld->PipelineUsage.qwD3DFVF.QuadPart++;
return FALSE;
/* // Force Mesa pipeline?
if (glb.dwTnL == GLDS_TNL_MESA) {
gld->PipelineUsage.dwMesa.QuadPart++;
return GLD_PIPELINE_MESA;
}
// Test for functionality not exposed in the D3D pathways
if ((ctx->Texture._GenFlags)) {
gld->PipelineUsage.dwMesa.QuadPart++;
return GLD_PIPELINE_MESA;
}
// Now decide if vertex shader can be used.
// If two sided lighting is enabled then we must either
// use Mesa TnL or the vertex shader
if (ctx->_TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
if (gld->VStwosidelight.hShader && !ctx->Fog.Enabled) {
// Use Vertex Shader
gld->PipelineUsage.dwD3D2SVS.QuadPart++;
return GLD_PIPELINE_D3D_VS_TWOSIDE;
} else {
// Use Mesa TnL
gld->PipelineUsage.dwMesa.QuadPart++;
return GLD_PIPELINE_MESA;
}
}
// Must be D3D fixed-function pipeline
gld->PipelineUsage.dwD3DFVF.QuadPart++;
return GLD_PIPELINE_D3D_FVF;
*/
}
//---------------------------------------------------------------------------
void gld_update_state_DX9(
GLcontext *ctx,
GLuint new_state)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
GLD_pb_dx9 *gldPB;
if (!gld || !gld->pDev)
return;
_swsetup_InvalidateState( ctx, new_state );
_vbo_InvalidateState( ctx, new_state );
_tnl_InvalidateState( ctx, new_state );
// SetupIndex will be used in the pipelines for choosing setup function
if ((ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE | DD_SEPARATE_SPECULAR)) ||
(ctx->Fog.Enabled))
{
if (ctx->_TriangleCaps & DD_FLATSHADE)
gld->iSetupFunc = GLD_SI_FLAT_EXTRAS;
else
gld->iSetupFunc = GLD_SI_SMOOTH_EXTRAS;
} else {
if (ctx->_TriangleCaps & DD_FLATSHADE)
gld->iSetupFunc = GLD_SI_FLAT; // Setup flat shade + texture
else
gld->iSetupFunc = GLD_SI_SMOOTH; // Setup smooth shade + texture
}
gld->bUseMesaTnL = _gldChooseInternalPipeline(ctx, gld);
if (gld->bUseMesaTnL) {
gldPB = &gld->PB2d;
_GLD_DX9_DEV(SetSoftwareVertexProcessing(gld->pDev, TRUE));
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_CLIPPING, FALSE));
_GLD_DX9_DEV(SetVertexShader(gld->pDev, NULL));
_GLD_DX9_DEV(SetFVF(gld->pDev, gldPB->dwFVF));
} else {
gldPB = &gld->PB3d;
_GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_CLIPPING, TRUE));
// if (gld->TnLPipeline == GLD_PIPELINE_D3D_VS_TWOSIDE) {
// _GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SOFTWAREVERTEXPROCESSING, !gld->VStwosidelight.bHardware));
// _GLD_DX9_DEV(SetVertexShader(gld->pDev, gld->VStwosidelight.hShader));
// } else {
// _GLD_DX9_DEV(SetRenderState(gld->pDev, D3DRS_SOFTWAREVERTEXPROCESSING, !gld->bHasHWTnL));
_GLD_DX9_DEV(SetSoftwareVertexProcessing(gld->pDev, !gld->bHasHWTnL));
_GLD_DX9_DEV(SetVertexShader(gld->pDev, NULL));
_GLD_DX9_DEV(SetFVF(gld->pDev, gldPB->dwFVF));
// }
}
#define _GLD_TEST_STATE(a) \
if (new_state & (a)) { \
gld##a(ctx); \
new_state &= ~(a); \
}
#define _GLD_TEST_STATE_DX9(a) \
if (new_state & (a)) { \
gld##a##_DX9(ctx); \
new_state &= ~(a); \
}
#define _GLD_IGNORE_STATE(a) new_state &= ~(a);
// if (!gld->bUseMesaTnL) {
// Not required if Mesa is doing the TnL.
// Problem: If gld->bUseMesaTnL is TRUE when these are signaled,
// then we'll miss updating the D3D TnL pipeline.
// Therefore, don't test for gld->bUseMesaTnL
_GLD_TEST_STATE(_NEW_MODELVIEW);
_GLD_TEST_STATE(_NEW_PROJECTION);
// }
_GLD_TEST_STATE_DX9(_NEW_TEXTURE); // extern, so guard with _DX9
_GLD_TEST_STATE(_NEW_COLOR);
_GLD_TEST_STATE(_NEW_DEPTH);
_GLD_TEST_STATE(_NEW_POLYGON);
_GLD_TEST_STATE(_NEW_STENCIL);
_GLD_TEST_STATE(_NEW_FOG);
_GLD_TEST_STATE(_NEW_LIGHT);
_GLD_TEST_STATE(_NEW_VIEWPORT);
_GLD_IGNORE_STATE(_NEW_TRANSFORM);
// Scissor Test: New for DX9
_GLD_TEST_STATE(_NEW_SCISSOR);
// Stubs for future use.
/* _GLD_TEST_STATE(_NEW_TEXTURE_MATRIX);
_GLD_TEST_STATE(_NEW_COLOR_MATRIX);
_GLD_TEST_STATE(_NEW_ACCUM);
_GLD_TEST_STATE(_NEW_EVAL);
_GLD_TEST_STATE(_NEW_HINT);
_GLD_TEST_STATE(_NEW_LINE);
_GLD_TEST_STATE(_NEW_PIXEL);
_GLD_TEST_STATE(_NEW_POINT);
_GLD_TEST_STATE(_NEW_POLYGONSTIPPLE);
_GLD_TEST_STATE(_NEW_PACKUNPACK);
_GLD_TEST_STATE(_NEW_ARRAY);
_GLD_TEST_STATE(_NEW_RENDERMODE);
_GLD_TEST_STATE(_NEW_BUFFERS);
_GLD_TEST_STATE(_NEW_MULTISAMPLE);
*/
// For debugging.
#if 0
#define _GLD_TEST_UNHANDLED_STATE(a) \
if (new_state & (a)) { \
gldLogMessage(GLDLOG_ERROR, "Unhandled " #a "\n"); \
}
_GLD_TEST_UNHANDLED_STATE(_NEW_TEXTURE_MATRIX);
_GLD_TEST_UNHANDLED_STATE(_NEW_COLOR_MATRIX);
_GLD_TEST_UNHANDLED_STATE(_NEW_ACCUM);
_GLD_TEST_UNHANDLED_STATE(_NEW_EVAL);
_GLD_TEST_UNHANDLED_STATE(_NEW_HINT);
_GLD_TEST_UNHANDLED_STATE(_NEW_LINE);
_GLD_TEST_UNHANDLED_STATE(_NEW_PIXEL);
_GLD_TEST_UNHANDLED_STATE(_NEW_POINT);
_GLD_TEST_UNHANDLED_STATE(_NEW_POLYGONSTIPPLE);
// _GLD_TEST_UNHANDLED_STATE(_NEW_SCISSOR);
_GLD_TEST_UNHANDLED_STATE(_NEW_PACKUNPACK);
_GLD_TEST_UNHANDLED_STATE(_NEW_ARRAY);
_GLD_TEST_UNHANDLED_STATE(_NEW_RENDERMODE);
_GLD_TEST_UNHANDLED_STATE(_NEW_BUFFERS);
_GLD_TEST_UNHANDLED_STATE(_NEW_MULTISAMPLE);
#undef _GLD_UNHANDLED_STATE
#endif
#undef _GLD_TEST_STATE
}
//---------------------------------------------------------------------------
// Viewport
//---------------------------------------------------------------------------
void gld_Viewport_DX9(
GLcontext *ctx,
GLint x,
GLint y,
GLsizei w,
GLsizei h)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
D3DVIEWPORT9 d3dvp;
if (!gld || !gld->pDev)
return;
// This is a hack. When the app is minimized, Mesa passes
// w=1 and h=1 for viewport dimensions. Without this test
// we get a GPF in gld_wgl_resize_buffers().
if ((w==1) && (h==1))
return;
// Call ResizeBuffersMESA. This function will early-out
// if no resize is needed.
//ctx->Driver.ResizeBuffersMESA(ctx);
// Mesa 5: Changed parameters
ctx->Driver.ResizeBuffers(gldCtx->glBuffer);
#if 0
ddlogPrintf(GLDLOG_SYSTEM, ">> Viewport x=%d y=%d w=%d h=%d", x,y,w,h);
#endif
// ** D3D viewport must not be outside the render target surface **
// Sanity check the GL viewport dimensions
if (x < 0) x = 0;
if (y < 0) y = 0;
if (w > gldCtx->dwWidth) w = gldCtx->dwWidth;
if (h > gldCtx->dwHeight) h = gldCtx->dwHeight;
// Ditto for D3D viewport dimensions
if (w+x > gldCtx->dwWidth) w = gldCtx->dwWidth-x;
if (h+y > gldCtx->dwHeight) h = gldCtx->dwHeight-y;
d3dvp.X = x;
d3dvp.Y = gldCtx->dwHeight - (y + h);
d3dvp.Width = w;
d3dvp.Height = h;
if (ctx->Viewport.Near <= ctx->Viewport.Far) {
d3dvp.MinZ = ctx->Viewport.Near;
d3dvp.MaxZ = ctx->Viewport.Far;
} else {
d3dvp.MinZ = ctx->Viewport.Far;
d3dvp.MaxZ = ctx->Viewport.Near;
}
// TODO: DEBUGGING
// d3dvp.MinZ = 0.0f;
// d3dvp.MaxZ = 1.0f;
_GLD_DX9_DEV(SetViewport(gld->pDev, &d3dvp));
}
//---------------------------------------------------------------------------
extern BOOL dglWglResizeBuffers(GLcontext *ctx, BOOL bDefaultDriver);
// Mesa 5: Parameter change
void gldResizeBuffers_DX9(
// GLcontext *ctx)
GLframebuffer *fb)
{
GET_CURRENT_CONTEXT(ctx);
dglWglResizeBuffers(ctx, TRUE);
}
//---------------------------------------------------------------------------
#ifdef _DEBUG
// This is only for debugging.
// To use, plug into ctx->Driver.Enable pointer below.
void gld_Enable(
GLcontext *ctx,
GLenum e,
GLboolean b)
{
char buf[1024];
sprintf(buf, "Enable: %s (%s)\n", _mesa_lookup_enum_by_nr(e), b?"TRUE":"FALSE");
ddlogMessage(DDLOG_SYSTEM, buf);
}
#endif
//---------------------------------------------------------------------------
// Driver pointer setup
//---------------------------------------------------------------------------
extern const GLubyte* _gldGetStringGeneric(GLcontext*, GLenum);
void gldSetupDriverPointers_DX9(
GLcontext *ctx)
{
GLD_context *gldCtx = GLD_GET_CONTEXT(ctx);
GLD_driver_dx9 *gld = GLD_GET_DX9_DRIVER(gldCtx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
// Mandatory functions
ctx->Driver.GetString = _gldGetStringGeneric;
ctx->Driver.UpdateState = gld_update_state_DX9;
ctx->Driver.Clear = gld_Clear_DX9;
ctx->Driver.DrawBuffer = gld_set_draw_buffer_DX9;
ctx->Driver.GetBufferSize = gld_buffer_size_DX9;
ctx->Driver.Finish = gld_Finish_DX9;
ctx->Driver.Flush = gld_Flush_DX9;
ctx->Driver.Error = gld_Error_DX9;
// Hardware accumulation buffer
ctx->Driver.Accum = NULL; // TODO: gld_Accum;
// Bitmap functions
ctx->Driver.CopyPixels = gld_CopyPixels_DX9;
ctx->Driver.DrawPixels = gld_DrawPixels_DX9;
ctx->Driver.ReadPixels = gld_ReadPixels_DX9;
ctx->Driver.Bitmap = gld_Bitmap_DX9;
// Buffer resize
ctx->Driver.ResizeBuffers = gldResizeBuffers_DX9;
// Texture image functions
ctx->Driver.ChooseTextureFormat = gld_ChooseTextureFormat_DX9;
ctx->Driver.TexImage1D = gld_TexImage1D_DX9;
ctx->Driver.TexImage2D = gld_TexImage2D_DX9;
ctx->Driver.TexImage3D = _mesa_store_teximage3d;
ctx->Driver.TexSubImage1D = gld_TexSubImage1D_DX9;
ctx->Driver.TexSubImage2D = gld_TexSubImage2D_DX9;
ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
ctx->Driver.CopyTexImage1D = gldCopyTexImage1D_DX9; //NULL;
ctx->Driver.CopyTexImage2D = gldCopyTexImage2D_DX9; //NULL;
ctx->Driver.CopyTexSubImage1D = gldCopyTexSubImage1D_DX9; //NULL;
ctx->Driver.CopyTexSubImage2D = gldCopyTexSubImage2D_DX9; //NULL;
ctx->Driver.CopyTexSubImage3D = gldCopyTexSubImage3D_DX9;
ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
// Texture object functions
ctx->Driver.BindTexture = NULL;
ctx->Driver.NewTextureObject = NULL; // Not yet implemented by Mesa!;
ctx->Driver.DeleteTexture = gld_DeleteTexture_DX9;
ctx->Driver.PrioritizeTexture = NULL;
// Imaging functionality
ctx->Driver.CopyColorTable = NULL;
ctx->Driver.CopyColorSubTable = NULL;
ctx->Driver.CopyConvolutionFilter1D = NULL;
ctx->Driver.CopyConvolutionFilter2D = NULL;
// State changing functions
ctx->Driver.AlphaFunc = NULL; //gld_AlphaFunc;
ctx->Driver.BlendFuncSeparate = NULL; //gld_BlendFunc;
ctx->Driver.ClearColor = NULL; //gld_ClearColor;
ctx->Driver.ClearDepth = NULL; //gld_ClearDepth;
ctx->Driver.ClearStencil = NULL; //gld_ClearStencil;
ctx->Driver.ColorMask = NULL; //gld_ColorMask;
ctx->Driver.CullFace = NULL; //gld_CullFace;
ctx->Driver.ClipPlane = NULL; //gld_ClipPlane;
ctx->Driver.FrontFace = NULL; //gld_FrontFace;
ctx->Driver.DepthFunc = NULL; //gld_DepthFunc;
ctx->Driver.DepthMask = NULL; //gld_DepthMask;
ctx->Driver.DepthRange = NULL;
ctx->Driver.Enable = NULL; //gld_Enable;
ctx->Driver.Fogfv = NULL; //gld_Fogfv;
ctx->Driver.Hint = NULL; //gld_Hint;
ctx->Driver.Lightfv = NULL; //gld_Lightfv;
ctx->Driver.LightModelfv = NULL; //gld_LightModelfv;
ctx->Driver.LineStipple = NULL; //gld_LineStipple;
ctx->Driver.LineWidth = NULL; //gld_LineWidth;
ctx->Driver.LogicOpcode = NULL; //gld_LogicOpcode;
ctx->Driver.PointParameterfv = NULL; //gld_PointParameterfv;
ctx->Driver.PointSize = NULL; //gld_PointSize;
ctx->Driver.PolygonMode = NULL; //gld_PolygonMode;
ctx->Driver.PolygonOffset = NULL; //gld_PolygonOffset;
ctx->Driver.PolygonStipple = NULL; //gld_PolygonStipple;
ctx->Driver.RenderMode = NULL; //gld_RenderMode;
ctx->Driver.Scissor = NULL; //gld_Scissor;
ctx->Driver.ShadeModel = NULL; //gld_ShadeModel;
ctx->Driver.StencilFunc = NULL; //gld_StencilFunc;
ctx->Driver.StencilMask = NULL; //gld_StencilMask;
ctx->Driver.StencilOp = NULL; //gld_StencilOp;
ctx->Driver.TexGen = NULL; //gld_TexGen;
ctx->Driver.TexEnv = NULL;
ctx->Driver.TexParameter = NULL;
ctx->Driver.TextureMatrix = NULL; //gld_TextureMatrix;
ctx->Driver.Viewport = gld_Viewport_DX9;
_swsetup_Wakeup(ctx);
tnl->Driver.RunPipeline = _tnl_run_pipeline;
tnl->Driver.Render.ResetLineStipple = gld_ResetLineStipple_DX9;
tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine;
// Hook into glFrustum() and glOrtho()
// ctx->Exec->Frustum = gldFrustumHook_DX9;
// ctx->Exec->Ortho = gldOrthoHook_DX9;
}
//---------------------------------------------------------------------------