| /**************************************************************************** |
| * |
| * 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: Texture / Bitmap functions |
| * |
| ****************************************************************************/ |
| |
| #include "dglcontext.h" |
| #include "ddlog.h" |
| #include "gld_dx8.h" |
| |
| #include <d3dx8tex.h> |
| |
| #include "texformat.h" |
| #include "colormac.h" |
| #include "texstore.h" |
| #include "image.h" |
| // #include "mem.h" |
| |
| //--------------------------------------------------------------------------- |
| |
| #define GLD_FLIP_HEIGHT(y,h) (gldCtx->dwHeight - (y) - (h)) |
| |
| //--------------------------------------------------------------------------- |
| // 1D texture fetch |
| //--------------------------------------------------------------------------- |
| |
| #define CHAN_SRC( t, i, j, k, sz ) \ |
| ((GLchan *)(t)->Data + (i) * (sz)) |
| #define UBYTE_SRC( t, i, j, k, sz ) \ |
| ((GLubyte *)(t)->Data + (i) * (sz)) |
| #define USHORT_SRC( t, i, j, k ) \ |
| ((GLushort *)(t)->Data + (i)) |
| #define FLOAT_SRC( t, i, j, k ) \ |
| ((GLfloat *)(t)->Data + (i)) |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| GLchan *rgba = (GLchan *)texel; |
| rgba[RCOMP] = src[2]; |
| rgba[GCOMP] = src[1]; |
| rgba[BCOMP] = src[0]; |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_f_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| texel[RCOMP] = CHAN_TO_FLOAT(src[0]); |
| texel[GCOMP] = CHAN_TO_FLOAT(src[1]); |
| texel[BCOMP] = CHAN_TO_FLOAT(src[2]); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf8) * 255 / 0xf8 ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_f_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf8) * 255 / 0xf8 ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 8) & 0xf) * 255 / 0xf ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 4) & 0xf) * 255 / 0xf ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf) * 255 / 0xf ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_1d_texel_f_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 8) & 0xf) * 255 / 0xf ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 4) & 0xf) * 255 / 0xf ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf) * 255 / 0xf ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| #undef CHAN_SRC |
| #undef UBYTE_SRC |
| #undef USHORT_SRC |
| #undef FLOAT_SRC |
| |
| //--------------------------------------------------------------------------- |
| // 2D texture fetch |
| //--------------------------------------------------------------------------- |
| |
| #define CHAN_SRC( t, i, j, k, sz ) \ |
| ((GLchan *)(t)->Data + ((t)->Width * (j) + (i)) * (sz)) |
| #define UBYTE_SRC( t, i, j, k, sz ) \ |
| ((GLubyte *)(t)->Data + ((t)->Width * (j) + (i)) * (sz)) |
| #define USHORT_SRC( t, i, j, k ) \ |
| ((GLushort *)(t)->Data + ((t)->Width * (j) + (i))) |
| #define FLOAT_SRC( t, i, j, k ) \ |
| ((GLfloat *)(t)->Data + ((t)->Width * (j) + (i))) |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| GLchan *rgba = (GLchan *)texel; |
| rgba[RCOMP] = src[2]; |
| rgba[GCOMP] = src[1]; |
| rgba[BCOMP] = src[0]; |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_f_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| texel[RCOMP] = CHAN_TO_FLOAT(src[0]); |
| texel[GCOMP] = CHAN_TO_FLOAT(src[1]); |
| texel[BCOMP] = CHAN_TO_FLOAT(src[2]); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf8) * 255 / 0xf8 ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_f_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf8) * 255 / 0xf8 ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 8) & 0xf) * 255 / 0xf ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 4) & 0xf) * 255 / 0xf ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf) * 255 / 0xf ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_2d_texel_f_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 8) & 0xf) * 255 / 0xf ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 4) & 0xf) * 255 / 0xf ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf) * 255 / 0xf ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| #undef CHAN_SRC |
| #undef UBYTE_SRC |
| #undef USHORT_SRC |
| #undef FLOAT_SRC |
| |
| //--------------------------------------------------------------------------- |
| // 3D texture fetch |
| //--------------------------------------------------------------------------- |
| |
| #define CHAN_SRC( t, i, j, k, sz ) \ |
| (GLchan *)(t)->Data + (((t)->Height * (k) + (j)) * \ |
| (t)->Width + (i)) * (sz) |
| #define UBYTE_SRC( t, i, j, k, sz ) \ |
| ((GLubyte *)(t)->Data + (((t)->Height * (k) + (j)) * \ |
| (t)->Width + (i)) * (sz)) |
| #define USHORT_SRC( t, i, j, k ) \ |
| ((GLushort *)(t)->Data + (((t)->Height * (k) + (j)) * \ |
| (t)->Width + (i))) |
| #define FLOAT_SRC( t, i, j, k ) \ |
| ((GLfloat *)(t)->Data + (((t)->Height * (k) + (j)) * \ |
| (t)->Width + (i))) |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| GLchan *rgba = (GLchan *)texel; |
| rgba[RCOMP] = src[2]; |
| rgba[GCOMP] = src[1]; |
| rgba[BCOMP] = src[0]; |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_f_X8R8G8B8( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLchan *src = CHAN_SRC( texImage, i, j, k, 4 ); |
| texel[RCOMP] = CHAN_TO_FLOAT(src[0]); |
| texel[GCOMP] = CHAN_TO_FLOAT(src[1]); |
| texel[BCOMP] = CHAN_TO_FLOAT(src[2]); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf8) * 255 / 0xf8 ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_f_X1R5G5B5( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 10) & 0xf8) * 255 / 0xf8 ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 5) & 0xf8) * 255 / 0xf8 ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf8) * 255 / 0xf8 ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLchan *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLchan *rgba = (GLchan *) texel; GLushort s = *src; |
| rgba[RCOMP] = UBYTE_TO_CHAN( ((s >> 8) & 0xf) * 255 / 0xf ); |
| rgba[GCOMP] = UBYTE_TO_CHAN( ((s >> 4) & 0xf) * 255 / 0xf ); |
| rgba[BCOMP] = UBYTE_TO_CHAN( ((s ) & 0xf) * 255 / 0xf ); |
| rgba[ACOMP] = CHAN_MAX; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| static void gld_fetch_3d_texel_f_X4R4G4B4( |
| const struct gl_texture_image *texImage, |
| GLint i, GLint j, GLint k, GLfloat *texel ) |
| { |
| const GLushort *src = USHORT_SRC( texImage, i, j, k ); |
| GLushort s = *src; |
| texel[RCOMP] = UBYTE_TO_FLOAT( ((s >> 8) & 0xf) * 255 / 0xf ); |
| texel[GCOMP] = UBYTE_TO_FLOAT( ((s >> 4) & 0xf) * 255 / 0xf ); |
| texel[BCOMP] = UBYTE_TO_FLOAT( ((s ) & 0xf) * 255 / 0xf ); |
| texel[ACOMP] = 1.f; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| #undef CHAN_SRC |
| #undef UBYTE_SRC |
| #undef USHORT_SRC |
| #undef FLOAT_SRC |
| |
| //--------------------------------------------------------------------------- |
| // Direct3D texture formats that have no Mesa equivalent |
| //--------------------------------------------------------------------------- |
| |
| const struct gl_texture_format _gld_texformat_X8R8G8B8 = { |
| MESA_FORMAT_ARGB8888, /* MesaFormat */ |
| GL_RGBA, /* BaseFormat */ |
| GL_UNSIGNED_NORMALIZED_ARB, /* DataType */ |
| 8, /* RedBits */ |
| 8, /* GreenBits */ |
| 8, /* BlueBits */ |
| 0, /* AlphaBits */ |
| 0, /* LuminanceBits */ |
| 0, /* IntensityBits */ |
| 0, /* IndexBits */ |
| 0, /* DepthBits */ |
| 4, /* TexelBytes */ |
| _mesa_texstore_argb8888, /* StoreTexImageFunc */ |
| gld_fetch_1d_texel_X8R8G8B8, /* FetchTexel1D */ |
| gld_fetch_2d_texel_X8R8G8B8, /* FetchTexel2D */ |
| gld_fetch_3d_texel_X8R8G8B8, /* FetchTexel3D */ |
| gld_fetch_1d_texel_f_X8R8G8B8, /* FetchTexel1Df */ |
| gld_fetch_2d_texel_f_X8R8G8B8, /* FetchTexel2Df */ |
| gld_fetch_3d_texel_f_X8R8G8B8, /* FetchTexel3Df */ |
| }; |
| |
| const struct gl_texture_format _gld_texformat_X1R5G5B5 = { |
| MESA_FORMAT_ARGB1555, /* MesaFormat */ |
| GL_RGBA, /* BaseFormat */ |
| GL_UNSIGNED_NORMALIZED_ARB, /* DataType */ |
| 5, /* RedBits */ |
| 5, /* GreenBits */ |
| 5, /* BlueBits */ |
| 0, /* AlphaBits */ |
| 0, /* LuminanceBits */ |
| 0, /* IntensityBits */ |
| 0, /* IndexBits */ |
| 0, /* DepthBits */ |
| 2, /* TexelBytes */ |
| _mesa_texstore_argb1555, /* StoreTexImageFunc */ |
| gld_fetch_1d_texel_X1R5G5B5, /* FetchTexel1D */ |
| gld_fetch_2d_texel_X1R5G5B5, /* FetchTexel2D */ |
| gld_fetch_3d_texel_X1R5G5B5, /* FetchTexel3D */ |
| gld_fetch_1d_texel_f_X1R5G5B5, /* FetchTexel1Df */ |
| gld_fetch_2d_texel_f_X1R5G5B5, /* FetchTexel2Df */ |
| gld_fetch_3d_texel_f_X1R5G5B5, /* FetchTexel3Df */ |
| }; |
| |
| const struct gl_texture_format _gld_texformat_X4R4G4B4 = { |
| MESA_FORMAT_ARGB4444, /* MesaFormat */ |
| GL_RGBA, /* BaseFormat */ |
| GL_UNSIGNED_NORMALIZED_ARB, /* DataType */ |
| 4, /* RedBits */ |
| 4, /* GreenBits */ |
| 4, /* BlueBits */ |
| 0, /* AlphaBits */ |
| 0, /* LuminanceBits */ |
| 0, /* IntensityBits */ |
| 0, /* IndexBits */ |
| 0, /* DepthBits */ |
| 2, /* TexelBytes */ |
| _mesa_texstore_argb4444, /* StoreTexImageFunc */ |
| gld_fetch_1d_texel_X4R4G4B4, /* FetchTexel1D */ |
| gld_fetch_2d_texel_X4R4G4B4, /* FetchTexel2D */ |
| gld_fetch_3d_texel_X4R4G4B4, /* FetchTexel3D */ |
| gld_fetch_1d_texel_f_X4R4G4B4, /* FetchTexel1Df */ |
| gld_fetch_2d_texel_f_X4R4G4B4, /* FetchTexel2Df */ |
| gld_fetch_3d_texel_f_X4R4G4B4, /* FetchTexel3Df */ |
| }; |
| |
| //--------------------------------------------------------------------------- |
| // Texture unit constants |
| //--------------------------------------------------------------------------- |
| |
| // List of possible combinations of texture environments. |
| // Example: GLD_TEXENV_MODULATE_RGBA means |
| // GL_MODULATE, GL_RGBA base internal format. |
| #define GLD_TEXENV_DECAL_RGB 0 |
| #define GLD_TEXENV_DECAL_RGBA 1 |
| #define GLD_TEXENV_DECAL_ALPHA 2 |
| #define GLD_TEXENV_REPLACE_RGB 3 |
| #define GLD_TEXENV_REPLACE_RGBA 4 |
| #define GLD_TEXENV_REPLACE_ALPHA 5 |
| #define GLD_TEXENV_MODULATE_RGB 6 |
| #define GLD_TEXENV_MODULATE_RGBA 7 |
| #define GLD_TEXENV_MODULATE_ALPHA 8 |
| #define GLD_TEXENV_BLEND_RGB 9 |
| #define GLD_TEXENV_BLEND_RGBA 10 |
| #define GLD_TEXENV_BLEND_ALPHA 11 |
| #define GLD_TEXENV_ADD_RGB 12 |
| #define GLD_TEXENV_ADD_RGBA 13 |
| #define GLD_TEXENV_ADD_ALPHA 14 |
| |
| // Per-stage (i.e. per-unit) texture environment |
| typedef struct { |
| DWORD ColorArg1; // Colour argument 1 |
| D3DTEXTUREOP ColorOp; // Colour operation |
| DWORD ColorArg2; // Colour argument 2 |
| DWORD AlphaArg1; // Alpha argument 1 |
| D3DTEXTUREOP AlphaOp; // Alpha operation |
| DWORD AlphaArg2; // Alpha argument 2 |
| } GLD_texenv; |
| |
| // TODO: Do we really need to set ARG1 and ARG2 every time? |
| // They seem to always be TEXTURE and CURRENT respectively. |
| |
| // C = Colour out |
| // A = Alpha out |
| // Ct = Colour from Texture |
| // Cf = Colour from fragment (diffuse) |
| // At = Alpha from Texture |
| // Af = Alpha from fragment (diffuse) |
| // Cc = GL_TEXTURE_ENV_COLOUR (GL_BLEND) |
| const GLD_texenv gldTexEnv[] = { |
| // DECAL_RGB: C=Ct, A=Af |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // DECAL_RGBA: C=Cf(1-At)+CtAt, A=Af |
| {D3DTA_TEXTURE, D3DTOP_BLENDTEXTUREALPHA, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // DECAL_ALPHA: <undefined> use DECAL_RGB |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| |
| // REPLACE_RGB: C=Ct, A=Af |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // REPLACE_RGBA: C=Ct, A=At |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT}, |
| // REPLACE_ALPHA: C=Cf, A=At |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG1, D3DTA_CURRENT}, |
| |
| // MODULATE_RGB: C=CfCt, A=Af |
| {D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // MODULATE_RGBA: C=CfCt, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| // MODULATE_ALPHA: C=Cf, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| |
| // BLEND_RGB: C=Cf(1-Ct)+CcCt, A=Af |
| {D3DTA_TEXTURE, D3DTOP_LERP, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // BLEND_RGBA: C=Cf(1-Ct)+CcCt, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_LERP, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| // BLEND_ALPHA: C=Cf, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| |
| // ADD_RGB: C=Cf+Ct, A=Af |
| {D3DTA_TEXTURE, D3DTOP_ADD, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT}, |
| // ADD_RGBA: C=Cf+Ct, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_ADD, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| // ADD_ALPHA: C=Cf, A=AfAt |
| {D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_CURRENT, |
| D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT}, |
| }; |
| |
| //--------------------------------------------------------------------------- |
| |
| D3DTEXTUREADDRESS _gldConvertWrap( |
| GLenum wrap) |
| { |
| return (wrap == GL_CLAMP) ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| D3DTEXTUREFILTERTYPE _gldConvertMagFilter( |
| GLenum magfilter) |
| { |
| return (magfilter == GL_LINEAR) ? D3DTEXF_LINEAR : D3DTEXF_POINT; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void _gldConvertMinFilter( |
| GLenum minfilter, |
| D3DTEXTUREFILTERTYPE *min_filter, |
| D3DTEXTUREFILTERTYPE *mip_filter) |
| { |
| switch (minfilter) { |
| case GL_NEAREST: |
| *min_filter = D3DTEXF_POINT; |
| *mip_filter = D3DTEXF_NONE; |
| break; |
| case GL_LINEAR: |
| *min_filter = D3DTEXF_LINEAR; |
| *mip_filter = D3DTEXF_NONE; |
| break; |
| case GL_NEAREST_MIPMAP_NEAREST: |
| *min_filter = D3DTEXF_POINT; |
| *mip_filter = D3DTEXF_POINT; |
| break; |
| case GL_LINEAR_MIPMAP_NEAREST: |
| *min_filter = D3DTEXF_LINEAR; |
| *mip_filter = D3DTEXF_POINT; |
| break; |
| case GL_NEAREST_MIPMAP_LINEAR: |
| *min_filter = D3DTEXF_POINT; |
| *mip_filter = D3DTEXF_LINEAR; |
| break; |
| case GL_LINEAR_MIPMAP_LINEAR: |
| *min_filter = D3DTEXF_LINEAR; |
| *mip_filter = D3DTEXF_LINEAR; |
| break; |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| D3DFORMAT _gldGLFormatToD3DFormat( |
| GLenum internalFormat) |
| { |
| switch (internalFormat) { |
| case GL_INTENSITY: |
| case GL_INTENSITY4: |
| case GL_INTENSITY8: |
| case GL_INTENSITY12: |
| case GL_INTENSITY16: |
| // LUNIMANCE != INTENSITY, but D3D doesn't have I8 textures |
| return D3DFMT_L8; |
| case 1: |
| case GL_LUMINANCE: |
| case GL_LUMINANCE4: |
| case GL_LUMINANCE8: |
| case GL_LUMINANCE12: |
| case GL_LUMINANCE16: |
| return D3DFMT_L8; |
| case GL_ALPHA: |
| case GL_ALPHA4: |
| case GL_ALPHA8: |
| case GL_ALPHA12: |
| case GL_ALPHA16: |
| return D3DFMT_A8; |
| case GL_COLOR_INDEX: |
| case GL_COLOR_INDEX1_EXT: |
| case GL_COLOR_INDEX2_EXT: |
| case GL_COLOR_INDEX4_EXT: |
| case GL_COLOR_INDEX8_EXT: |
| case GL_COLOR_INDEX12_EXT: |
| case GL_COLOR_INDEX16_EXT: |
| return D3DFMT_X8R8G8B8; |
| case 2: |
| case GL_LUMINANCE_ALPHA: |
| case GL_LUMINANCE4_ALPHA4: |
| case GL_LUMINANCE6_ALPHA2: |
| case GL_LUMINANCE8_ALPHA8: |
| case GL_LUMINANCE12_ALPHA4: |
| case GL_LUMINANCE12_ALPHA12: |
| case GL_LUMINANCE16_ALPHA16: |
| return D3DFMT_A8L8; |
| case GL_R3_G3_B2: |
| // TODO: Mesa does not support RGB332 internally |
| return D3DFMT_X4R4G4B4; //D3DFMT_R3G3B2; |
| case GL_RGB4: |
| return D3DFMT_X4R4G4B4; |
| case GL_RGB5: |
| return D3DFMT_X1R5G5B5; |
| case 3: |
| case GL_RGB: |
| case GL_RGB8: |
| case GL_RGB10: |
| case GL_RGB12: |
| case GL_RGB16: |
| return D3DFMT_R8G8B8; |
| case GL_RGBA4: |
| return D3DFMT_A4R4G4B4; |
| case 4: |
| case GL_RGBA: |
| case GL_RGBA2: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| return D3DFMT_A8R8G8B8; |
| case GL_RGB5_A1: |
| return D3DFMT_A1R5G5B5; |
| } |
| |
| // Return an acceptable default |
| return D3DFMT_A8R8G8B8; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| GLenum _gldDecodeBaseFormat( |
| IDirect3DTexture8 *pTex) |
| { |
| // Examine Direct3D texture and return base OpenGL internal texture format |
| // NOTE: We can't use any base format info from Mesa because D3D might have |
| // used a different texture format when we used D3DXCreateTexture(). |
| |
| // Base internal format is one of (Red Book p355): |
| // GL_ALPHA, |
| // GL_LUMINANCE, |
| // GL_LUMINANCE_ALPHA, |
| // GL_INTENSITY, |
| // GL_RGB, |
| // GL_RGBA |
| |
| // NOTE: INTENSITY not used (not supported by Direct3D) |
| // LUMINANCE has same texture functions as RGB |
| // LUMINANCE_ALPHA has same texture functions as RGBA |
| |
| // TODO: cache format instead of using GetLevelDesc() |
| D3DSURFACE_DESC desc; |
| _GLD_DX8_TEX(GetLevelDesc(pTex, 0, &desc)); |
| |
| switch (desc.Format) { |
| case D3DFMT_R8G8B8: |
| case D3DFMT_X8R8G8B8: |
| case D3DFMT_R5G6B5: |
| case D3DFMT_X1R5G5B5: |
| case D3DFMT_R3G3B2: |
| case D3DFMT_X4R4G4B4: |
| case D3DFMT_P8: |
| case D3DFMT_L8: |
| return GL_RGB; |
| case D3DFMT_A8R8G8B8: |
| case D3DFMT_A1R5G5B5: |
| case D3DFMT_A4R4G4B4: |
| case D3DFMT_A8R3G3B2: |
| case D3DFMT_A8P8: |
| case D3DFMT_A8L8: |
| case D3DFMT_A4L4: |
| return GL_RGBA; |
| case D3DFMT_A8: |
| return GL_ALPHA; |
| // Compressed texture formats. Need to check these... |
| case D3DFMT_DXT1: |
| return GL_RGBA; |
| case D3DFMT_DXT2: |
| return GL_RGB; |
| case D3DFMT_DXT3: |
| return GL_RGBA; |
| case D3DFMT_DXT4: |
| return GL_RGB; |
| case D3DFMT_DXT5: |
| return GL_RGBA; |
| } |
| |
| // Fell through. Return arbitary default. |
| return GL_RGBA; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| const struct gl_texture_format* _gldMesaFormatForD3DFormat( |
| D3DFORMAT d3dfmt) |
| { |
| switch (d3dfmt) { |
| case D3DFMT_A8R8G8B8: |
| return &_mesa_texformat_argb8888; |
| case D3DFMT_R8G8B8: |
| return &_mesa_texformat_rgb888; |
| case D3DFMT_R5G6B5: |
| return &_mesa_texformat_rgb565; |
| case D3DFMT_A4R4G4B4: |
| return &_mesa_texformat_argb4444; |
| case D3DFMT_A1R5G5B5: |
| return &_mesa_texformat_argb1555; |
| case D3DFMT_A8L8: |
| return &_mesa_texformat_al88; |
| case D3DFMT_R3G3B2: |
| return &_mesa_texformat_rgb332; |
| case D3DFMT_A8: |
| return &_mesa_texformat_a8; |
| case D3DFMT_L8: |
| return &_mesa_texformat_l8; |
| case D3DFMT_X8R8G8B8: |
| return &_gld_texformat_X8R8G8B8; |
| case D3DFMT_X1R5G5B5: |
| return &_gld_texformat_X1R5G5B5; |
| case D3DFMT_X4R4G4B4: |
| return &_gld_texformat_X4R4G4B4; |
| } |
| |
| // If we reach here then we've made an error somewhere else |
| // by allowing a format that is not supported. |
| assert(0); |
| |
| return NULL; // Shut up compiler warning |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Copy* functions |
| //--------------------------------------------------------------------------- |
| |
| void gldCopyTexImage1D_DX8( |
| GLcontext *ctx, |
| GLenum target, GLint level, |
| GLenum internalFormat, |
| GLint x, GLint y, |
| GLsizei width, GLint border ) |
| { |
| // TODO |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gldCopyTexImage2D_DX8( |
| GLcontext *ctx, |
| GLenum target, |
| GLint level, |
| GLenum internalFormat, |
| GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height, |
| GLint border) |
| { |
| // TODO |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gldCopyTexSubImage1D_DX8( |
| GLcontext *ctx, |
| GLenum target, GLint level, |
| GLint xoffset, GLint x, GLint y, GLsizei width ) |
| { |
| // TODO |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gldCopyTexSubImage2D_DX8( |
| GLcontext *ctx, |
| GLenum target, |
| GLint level, |
| GLint xoffset, |
| GLint yoffset, |
| GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height) |
| { |
| // TODO |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gldCopyTexSubImage3D_DX8( |
| GLcontext *ctx, |
| GLenum target, |
| GLint level, |
| GLint xoffset, |
| GLint yoffset, |
| GLint zoffset, |
| GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height ) |
| { |
| // TODO ? |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Bitmap/Pixel functions |
| //--------------------------------------------------------------------------- |
| |
| #define GLD_FLIP_Y(y) (gldCtx->dwHeight - (y)) |
| |
| #define _GLD_FVF_IMAGE (D3DFVF_XYZRHW | D3DFVF_TEX1) |
| |
| typedef struct { |
| FLOAT x, y; // 2D raster coords |
| FLOAT z; // depth value |
| FLOAT rhw; // reciprocal homogenous W (always 1.0f) |
| FLOAT tu, tv; // texture coords |
| } _GLD_IMAGE_VERTEX; |
| |
| //--------------------------------------------------------------------------- |
| |
| HRESULT _gldDrawPixels( |
| GLcontext *ctx, |
| BOOL bChromakey, // Alpha test for glBitmap() images |
| GLint x, // GL x position |
| GLint y, // GL y position (needs flipping) |
| GLsizei width, // Width of input image |
| GLsizei height, // Height of input image |
| IDirect3DSurface8 *pImage) |
| { |
| // |
| // Draw input image as texture implementing PixelZoom and clipping. |
| // Any fragment operations currently enabled will be used. |
| // |
| |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| IDirect3DTexture8 *pTexture; |
| D3DSURFACE_DESC d3dsd; |
| IDirect3DSurface8 *pSurface; |
| _GLD_IMAGE_VERTEX v[4]; |
| HRESULT hr; |
| |
| float ZoomWidth, ZoomHeight; |
| float ScaleWidth, ScaleHeight; |
| |
| // Create a texture to hold image |
| hr = D3DXCreateTexture( |
| gld->pDev, |
| width, height, |
| 1, // miplevels |
| 0, // usage |
| D3DFMT_A8R8G8B8, // format |
| D3DPOOL_MANAGED, // pool |
| &pTexture); |
| if (FAILED(hr)) |
| return hr; |
| |
| hr = IDirect3DTexture8_GetSurfaceLevel(pTexture, 0, &pSurface); |
| if (FAILED(hr)) { |
| IDirect3DTexture8_Release(pTexture); |
| return hr; |
| } |
| |
| // Copy image into texture |
| hr = D3DXLoadSurfaceFromSurface( |
| pSurface, NULL, NULL, // Dest surface |
| pImage, NULL, NULL, // Src surface |
| D3DX_FILTER_NONE, |
| 0); |
| IDirect3DSurface8_Release(pSurface); |
| if (FAILED(hr)) { |
| IDirect3DTexture8_Release(pTexture); |
| return hr; |
| } |
| |
| // |
| // Set up the quad like this (ascii-art ahead!) |
| // |
| // 3--2 |
| // | | |
| // 0--1 |
| // |
| // |
| |
| // Set depth |
| v[0].z = v[1].z = v[2].z = v[3].z = ctx->Current.RasterPos[2]; |
| // Set Reciprocal Homogenous W |
| v[0].rhw = v[1].rhw = v[2].rhw = v[3].rhw = 1.0f; |
| |
| // Set texcoords |
| // Examine texture size - if different to input width and height |
| // then we'll need to munge the texcoords to fit. |
| IDirect3DTexture8_GetLevelDesc(pTexture, 0, &d3dsd); |
| ScaleWidth = (float)width / (float)d3dsd.Width; |
| ScaleHeight = (float)height / (float)d3dsd.Height; |
| v[0].tu = 0.0f; v[0].tv = 0.0f; |
| v[1].tu = ScaleWidth; v[1].tv = 0.0f; |
| v[2].tu = ScaleWidth; v[2].tv = ScaleHeight; |
| v[3].tu = 0.0f; v[3].tv = ScaleHeight; |
| |
| // Set raster positions |
| ZoomWidth = (float)width * ctx->Pixel.ZoomX; |
| ZoomHeight = (float)height * ctx->Pixel.ZoomY; |
| |
| v[0].x = x; v[0].y = GLD_FLIP_Y(y); |
| v[1].x = x+ZoomWidth; v[1].y = GLD_FLIP_Y(y); |
| v[2].x = x+ZoomWidth; v[2].y = GLD_FLIP_Y(y+ZoomHeight); |
| v[3].x = x; v[3].y = GLD_FLIP_Y(y+ZoomHeight); |
| |
| // Draw image with full HW acceleration |
| // NOTE: Be nice to use a State Block for all this state... |
| IDirect3DDevice8_SetTexture(gld->pDev, 0, pTexture); |
| IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_CULLMODE, D3DCULL_NONE); |
| IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_CLIPPING, TRUE); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_MINFILTER, D3DTEXF_POINT); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_MIPFILTER, D3DTEXF_POINT); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_MAGFILTER, D3DTEXF_POINT); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 1, D3DTSS_COLOROP, D3DTOP_DISABLE); |
| IDirect3DDevice8_SetTextureStageState(gld->pDev, 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); |
| IDirect3DDevice8_SetVertexShader(gld->pDev, _GLD_FVF_IMAGE); |
| |
| // |
| // Emulate Chromakey with an Alpha Test. |
| // [Alpha Test is more widely supported anyway] |
| // |
| if (bChromakey) { |
| // Switch on alpha testing |
| IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_ALPHATESTENABLE, TRUE); |
| // Fragment passes is alpha is greater than reference value |
| IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_ALPHAFUNC, D3DCMP_GREATER); |
| // Set alpha reference value between Bitmap alpha values of |
| // zero (transparent) and one (opaque). |
| IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_ALPHAREF, 0x7f); |
| } |
| |
| IDirect3DDevice8_DrawPrimitiveUP(gld->pDev, D3DPT_TRIANGLEFAN, 2, &v, sizeof(_GLD_IMAGE_VERTEX)); |
| |
| // Release texture |
| IDirect3DDevice8_SetTexture(gld->pDev, 0, NULL); |
| IDirect3DTexture8_Release(pTexture); |
| |
| // Reset state to before we messed it up |
| FLUSH_VERTICES(ctx, _NEW_ALL); |
| |
| return S_OK; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_DrawPixels_DX8( |
| GLcontext *ctx, |
| GLint x, GLint y, GLsizei width, GLsizei height, |
| GLenum format, GLenum type, |
| const struct gl_pixelstore_attrib *unpack, |
| const GLvoid *pixels ) |
| { |
| GLD_context *gldCtx; |
| GLD_driver_dx8 *gld; |
| |
| IDirect3DSurface8 *pImage; |
| HRESULT hr; |
| D3DLOCKED_RECT d3dLockedRect; |
| |
| const struct gl_texture_format *MesaFormat; |
| |
| gldCtx = GLD_GET_CONTEXT(ctx); |
| gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| hr = IDirect3DDevice8_CreateImageSurface( |
| gld->pDev, |
| width, |
| height, |
| D3DFMT_A8R8G8B8, |
| &pImage); |
| if (FAILED(hr)) { |
| return; |
| } |
| |
| // |
| // Use Mesa to fill in image |
| // |
| |
| // Lock all of surface |
| hr = IDirect3DSurface8_LockRect(pImage, &d3dLockedRect, NULL, 0); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pImage); |
| return; |
| } |
| |
| MesaFormat = _mesa_choose_tex_format(ctx, format, format, type); |
| |
| // unpack image, apply transfer ops and store directly in texture |
| MesaFormat->StoreImage( |
| ctx, |
| 2, |
| GL_RGBA, |
| &_mesa_texformat_argb8888, |
| d3dLockedRect.pBits, |
| width, height, 1, 0, 0, 0, |
| d3dLockedRect.Pitch, |
| 0, /* dstImageStride */ |
| format, type, pixels, unpack); |
| |
| IDirect3DSurface8_UnlockRect(pImage); |
| |
| _gldDrawPixels(ctx, FALSE, x, y, width, height, pImage); |
| |
| IDirect3DSurface8_Release(pImage); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_ReadPixels_DX8( |
| GLcontext *ctx, |
| GLint x, GLint y, GLsizei width, GLsizei height, |
| GLenum format, GLenum type, |
| const struct gl_pixelstore_attrib *pack, |
| GLvoid *dest) |
| { |
| |
| GLD_context *gldCtx; |
| GLD_driver_dx8 *gld; |
| |
| IDirect3DSurface8 *pBackbuffer = NULL; |
| IDirect3DSurface8 *pNativeImage = NULL; |
| IDirect3DSurface8 *pCanonicalImage = NULL; |
| |
| D3DSURFACE_DESC d3dsd; |
| RECT rcSrc; // Source rect |
| POINT ptDst; // Dest point |
| HRESULT hr; |
| D3DLOCKED_RECT d3dLockedRect; |
| struct gl_pixelstore_attrib srcPacking; |
| int i; |
| GLint DstRowStride; |
| const struct gl_texture_format *MesaFormat; |
| |
| switch (format) { |
| case GL_STENCIL_INDEX: |
| case GL_DEPTH_COMPONENT: |
| return; |
| } |
| |
| MesaFormat = _mesa_choose_tex_format(ctx, format, format, type); |
| DstRowStride = _mesa_image_row_stride(pack, width, format, type); |
| |
| gldCtx = GLD_GET_CONTEXT(ctx); |
| gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| // Get backbuffer |
| hr = IDirect3DDevice8_GetBackBuffer( |
| gld->pDev, |
| 0, // First backbuffer |
| D3DBACKBUFFER_TYPE_MONO, |
| &pBackbuffer); |
| if (FAILED(hr)) |
| return; |
| |
| // Get backbuffer description |
| hr = IDirect3DSurface8_GetDesc(pBackbuffer, &d3dsd); |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| // Create a surface compatible with backbuffer |
| hr = IDirect3DDevice8_CreateImageSurface( |
| gld->pDev, |
| width, |
| height, |
| d3dsd.Format, |
| &pNativeImage); |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| // Compute source rect and dest point |
| SetRect(&rcSrc, 0, 0, width, height); |
| OffsetRect(&rcSrc, x, GLD_FLIP_HEIGHT(y, height)); |
| ptDst.x = ptDst.y = 0; |
| |
| // Get source pixels. |
| // |
| // This intermediate surface ensure that we can use CopyRects() |
| // instead of relying on D3DXLoadSurfaceFromSurface(), which may |
| // try and lock the backbuffer. This way seems safer. |
| // |
| hr = IDirect3DDevice8_CopyRects( |
| gld->pDev, |
| pBackbuffer, |
| &rcSrc, |
| 1, |
| pNativeImage, |
| &ptDst); |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| // Create an RGBA8888 surface |
| hr = IDirect3DDevice8_CreateImageSurface( |
| gld->pDev, |
| width, |
| height, |
| D3DFMT_A8R8G8B8, |
| &pCanonicalImage); |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| // Convert to RGBA8888 |
| hr = D3DXLoadSurfaceFromSurface( |
| pCanonicalImage, // Dest surface |
| NULL, NULL, // Dest palette, RECT |
| pNativeImage, // Src surface |
| NULL, NULL, // Src palette, RECT |
| D3DX_FILTER_NONE, // Filter |
| 0); // Colourkey |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| srcPacking.Alignment = 1; |
| srcPacking.ImageHeight = height; |
| srcPacking.LsbFirst = GL_FALSE; |
| srcPacking.RowLength = 0; |
| srcPacking.SkipImages = 0; |
| srcPacking.SkipPixels = 0; |
| srcPacking.SkipRows = 0; |
| srcPacking.SwapBytes = GL_FALSE; |
| |
| // Lock all of image |
| hr = IDirect3DSurface8_LockRect(pCanonicalImage, &d3dLockedRect, NULL, 0); |
| if (FAILED(hr)) { |
| goto gld_ReadPixels_DX8_return; |
| } |
| |
| // We need to flip the data. Yuck. |
| // Perhaps Mesa has a span packer we can use in future... |
| for (i=0; i<height; i++) { |
| BYTE *pDestRow = (BYTE*)_mesa_image_address(2,pack, dest, width, height, format, type, 0, i, 0); |
| BYTE *pSrcRow = (BYTE*)d3dLockedRect.pBits + (d3dLockedRect.Pitch * (height-i-1)); |
| MesaFormat->StoreImage( |
| ctx, |
| 2, |
| GL_RGBA, // base format |
| MesaFormat, // dst format |
| pDestRow, // dest addr |
| width, 1, 1, 0, 0, 0, // src x,y,z & dst offsets x,y,z |
| DstRowStride, // dst row stride |
| 0, // dstImageStride |
| GL_BGRA, // src format |
| GL_UNSIGNED_BYTE, // src type |
| pSrcRow, // src addr |
| &srcPacking); // packing params of source image |
| } |
| |
| IDirect3DSurface8_UnlockRect(pCanonicalImage); |
| |
| gld_ReadPixels_DX8_return: |
| SAFE_RELEASE_SURFACE8(pCanonicalImage); |
| SAFE_RELEASE_SURFACE8(pNativeImage); |
| SAFE_RELEASE_SURFACE8(pBackbuffer); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_CopyPixels_DX8( |
| GLcontext *ctx, |
| GLint srcx, |
| GLint srcy, |
| GLsizei width, |
| GLsizei height, |
| GLint dstx, |
| GLint dsty, |
| GLenum type) |
| { |
| // |
| // NOTE: Not allowed to copy vidmem to vidmem! |
| // Therefore we use an intermediate image surface. |
| // |
| |
| GLD_context *gldCtx; |
| GLD_driver_dx8 *gld; |
| |
| IDirect3DSurface8 *pBackbuffer; |
| D3DSURFACE_DESC d3dsd; |
| IDirect3DSurface8 *pImage; |
| RECT rcSrc; // Source rect |
| POINT ptDst; // Dest point |
| HRESULT hr; |
| |
| // Only backbuffer |
| if (type != GL_COLOR) |
| return; |
| |
| gldCtx = GLD_GET_CONTEXT(ctx); |
| gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| // Get backbuffer |
| hr = IDirect3DDevice8_GetBackBuffer( |
| gld->pDev, |
| 0, // First backbuffer |
| D3DBACKBUFFER_TYPE_MONO, |
| &pBackbuffer); |
| if (FAILED(hr)) |
| return; |
| |
| // Get backbuffer description |
| hr = IDirect3DSurface8_GetDesc(pBackbuffer, &d3dsd); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pBackbuffer); |
| return; |
| } |
| |
| // Create a surface compatible with backbuffer |
| hr = IDirect3DDevice8_CreateImageSurface( |
| gld->pDev, |
| width, |
| height, |
| d3dsd.Format, |
| &pImage); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pBackbuffer); |
| return; |
| } |
| |
| // Compute source rect and dest point |
| SetRect(&rcSrc, 0, 0, width, height); |
| OffsetRect(&rcSrc, srcx, GLD_FLIP_HEIGHT(srcy, height)); |
| ptDst.x = ptDst.y = 0; |
| |
| // Get source pixels |
| hr = IDirect3DDevice8_CopyRects( |
| gld->pDev, |
| pBackbuffer, |
| &rcSrc, |
| 1, |
| pImage, |
| &ptDst); |
| IDirect3DSurface8_Release(pBackbuffer); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pImage); |
| return; |
| } |
| |
| _gldDrawPixels(ctx, FALSE, dstx, dsty, width, height, pImage); |
| |
| IDirect3DSurface8_Release(pImage); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_Bitmap_DX8( |
| GLcontext *ctx, |
| GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height, |
| const struct gl_pixelstore_attrib *unpack, |
| const GLubyte *bitmap) |
| { |
| GLD_context *gldCtx; |
| GLD_driver_dx8 *gld; |
| |
| IDirect3DSurface8 *pImage; |
| HRESULT hr; |
| D3DLOCKED_RECT d3dLockedRect; |
| BYTE *pTempBitmap; |
| D3DCOLOR clBitmapOne, clBitmapZero; |
| D3DCOLOR *pBits; |
| const GLubyte *src; |
| int i, j, k; |
| |
| gldCtx = GLD_GET_CONTEXT(ctx); |
| gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| clBitmapZero = D3DCOLOR_RGBA(0,0,0,0); // NOTE: Alpha is Zero |
| clBitmapOne = D3DCOLOR_COLORVALUE( |
| ctx->Current.RasterColor[0], |
| ctx->Current.RasterColor[1], |
| ctx->Current.RasterColor[2], |
| 1.0f); // NOTE: Alpha is One |
| |
| hr = IDirect3DDevice8_CreateImageSurface( |
| gld->pDev, |
| width, |
| height, |
| D3DFMT_A8R8G8B8, |
| &pImage); |
| if (FAILED(hr)) { |
| return; |
| } |
| |
| // Lock all of surface |
| hr = IDirect3DSurface8_LockRect(pImage, &d3dLockedRect, NULL, 0); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pImage); |
| return; |
| } |
| |
| pTempBitmap = _mesa_unpack_bitmap(width, height, bitmap, unpack); |
| if (pTempBitmap == NULL) { |
| IDirect3DSurface8_Release(pImage); |
| return; |
| } |
| |
| pBits = (D3DCOLOR*)d3dLockedRect.pBits; |
| |
| for (i=0; i<height; i++) { |
| GLubyte byte; |
| pBits = (D3DCOLOR*)((BYTE*)d3dLockedRect.pBits + (i*d3dLockedRect.Pitch)); |
| src = (const GLubyte *) _mesa_image_address(2, |
| &ctx->DefaultPacking, pTempBitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, |
| 0, i, 0); |
| for (j=0; j<(width>>3); j++) { |
| byte = *src++; |
| for (k=0; k<8; k++) { |
| *pBits++ = (byte & 128) ? clBitmapOne : clBitmapZero; |
| byte <<= 1; |
| } |
| } |
| // Fill remaining bits from bitmap |
| if (width & 7) { |
| byte = *src; |
| for (k=0; k<(width & 7); k++) { |
| *pBits++ = (byte & 128) ? clBitmapOne : clBitmapZero; |
| byte <<= 1; |
| } |
| } |
| } |
| |
| FREE(pTempBitmap); |
| |
| /* |
| // unpack image, apply transfer ops and store directly in texture |
| texImage->TexFormat->StoreImage( |
| ctx, |
| 2, |
| GL_BITMAP, |
| &_mesa_texformat_argb8888, |
| d3dLockedRect.pBits, |
| width, height, 1, 0, 0, 0, |
| d3dLockedRect.Pitch, |
| 0, // dstImageStride |
| GL_BITMAP, GL_COLOR_INDEX, bitmap, unpack); |
| */ |
| IDirect3DSurface8_UnlockRect(pImage); |
| |
| _gldDrawPixels(ctx, TRUE, x, y, width, height, pImage); |
| |
| IDirect3DSurface8_Release(pImage); |
| } |
| |
| //--------------------------------------------------------------------------- |
| // Texture functions |
| //--------------------------------------------------------------------------- |
| |
| void _gldAllocateTexture( |
| GLcontext *ctx, |
| struct gl_texture_object *tObj, |
| struct gl_texture_image *texImage) |
| { |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| IDirect3DTexture8 *pTex; |
| D3DFORMAT d3dFormat; |
| |
| if (!tObj || !texImage) |
| return; |
| |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (pTex) { |
| // Decide whether we can keep existing D3D texture |
| // by examining top-level surface. |
| D3DSURFACE_DESC d3dsd; |
| _GLD_DX8_TEX(GetLevelDesc(pTex, 0, &d3dsd)); |
| // Release existing texture if not compatible |
| if ((d3dsd.Width == texImage->Width) || |
| (d3dsd.Height == texImage->Height)) |
| { |
| return; // Keep the existing texture |
| } |
| tObj->DriverData = NULL; |
| _GLD_DX8_TEX(Release(pTex)); |
| } |
| |
| d3dFormat = _gldGLFormatToD3DFormat(texImage->IntFormat); |
| D3DXCreateTexture( |
| gld->pDev, |
| texImage->Width, |
| texImage->Height, |
| // TODO: Re-evaluate mipmapping |
| (glb.bUseMipmaps) ? D3DX_DEFAULT : 1, |
| 0, // Usage |
| d3dFormat, |
| D3DPOOL_MANAGED, |
| &pTex); |
| tObj->DriverData = pTex; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| const struct gl_texture_format* gld_ChooseTextureFormat_DX8( |
| GLcontext *ctx, |
| GLint internalFormat, |
| GLenum srcFormat, |
| GLenum srcType) |
| { |
| // [Based on mesa_choose_tex_format()] |
| // |
| // We will choose only texture formats that are supported |
| // by Direct3D. If the hardware doesn't support a particular |
| // texture format, then the D3DX texture calls that we use |
| // will automatically use a HW supported format. |
| // |
| // The most critical aim is to reduce copying; if we can use |
| // texture-image data directly then it will be a big performance assist. |
| // |
| |
| switch (internalFormat) { |
| case GL_INTENSITY: |
| case GL_INTENSITY4: |
| case GL_INTENSITY8: |
| case GL_INTENSITY12: |
| case GL_INTENSITY16: |
| return &_mesa_texformat_l8; // D3DFMT_L8 |
| case 1: |
| case GL_LUMINANCE: |
| case GL_LUMINANCE4: |
| case GL_LUMINANCE8: |
| case GL_LUMINANCE12: |
| case GL_LUMINANCE16: |
| return &_mesa_texformat_l8; // D3DFMT_L8 |
| case GL_ALPHA: |
| case GL_ALPHA4: |
| case GL_ALPHA8: |
| case GL_ALPHA12: |
| case GL_ALPHA16: |
| return &_mesa_texformat_a8; // D3DFMT_A8 |
| case GL_COLOR_INDEX: |
| case GL_COLOR_INDEX1_EXT: |
| case GL_COLOR_INDEX2_EXT: |
| case GL_COLOR_INDEX4_EXT: |
| case GL_COLOR_INDEX8_EXT: |
| case GL_COLOR_INDEX12_EXT: |
| case GL_COLOR_INDEX16_EXT: |
| return &_mesa_texformat_rgb565; // D3DFMT_R5G6B5 |
| // Mesa will convert this for us later... |
| // return &_mesa_texformat_ci8; // D3DFMT_R5G6B5 |
| case 2: |
| case GL_LUMINANCE_ALPHA: |
| case GL_LUMINANCE4_ALPHA4: |
| case GL_LUMINANCE6_ALPHA2: |
| case GL_LUMINANCE8_ALPHA8: |
| case GL_LUMINANCE12_ALPHA4: |
| case GL_LUMINANCE12_ALPHA12: |
| case GL_LUMINANCE16_ALPHA16: |
| return &_mesa_texformat_al88; // D3DFMT_A8L8 |
| case GL_R3_G3_B2: |
| return &_mesa_texformat_rgb332; // D3DFMT_R3G3B2 |
| case GL_RGB4: |
| case GL_RGBA4: |
| case GL_RGBA2: |
| return &_mesa_texformat_argb4444; // D3DFMT_A4R4G4B4 |
| case 3: |
| case GL_RGB: |
| case GL_RGB5: |
| case GL_RGB8: |
| case GL_RGB10: |
| case GL_RGB12: |
| case GL_RGB16: |
| return &_mesa_texformat_rgb565; |
| case 4: |
| case GL_RGBA: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGBA12: |
| case GL_RGBA16: |
| return &_mesa_texformat_argb8888; |
| case GL_RGB5_A1: |
| return &_mesa_texformat_argb1555; |
| default: |
| _mesa_problem(NULL, "unexpected format in fxDDChooseTextureFormat"); |
| return NULL; |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| /* |
| // Safer(?), slower version. |
| void gld_TexImage2D_DX8( |
| GLcontext *ctx, |
| GLenum target, |
| GLint level, |
| GLint internalFormat, |
| GLint width, |
| GLint height, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *tObj, |
| struct gl_texture_image *texImage) |
| { |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| IDirect3DTexture8 *pTex; |
| IDirect3DSurface8 *pSurface; |
| RECT rcSrcRect; |
| HRESULT hr; |
| GLint texelBytes = 4; |
| GLvoid *tempImage; |
| |
| if (!tObj || !texImage) |
| return; |
| |
| if (level == 0) { |
| _gldAllocateTexture(ctx, tObj, texImage); |
| } |
| |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (!pTex) |
| return; // Texture has not been created |
| if (level >= IDirect3DTexture8_GetLevelCount(pTex)) |
| return; // Level does not exist |
| hr = IDirect3DTexture8_GetSurfaceLevel(pTex, level, &pSurface); |
| if (FAILED(hr)) |
| return; // Surface level doesn't exist (or just a plain error) |
| |
| tempImage = MALLOC(width * height * texelBytes); |
| if (!tempImage) { |
| _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); |
| IDirect3DSurface8_Release(pSurface); |
| return; |
| } |
| // unpack image, apply transfer ops and store in tempImage |
| texImage->TexFormat->StoreImage(ctx, 2, texImage->Format, |
| &_mesa_texformat_argb8888, // dest format |
| tempImage, |
| width, height, 1, 0, 0, 0, |
| width * texelBytes, |
| 0, // dstImageStride |
| format, type, pixels, packing); |
| |
| SetRect(&rcSrcRect, 0, 0, width, height); |
| D3DXLoadSurfaceFromMemory( |
| pSurface, |
| NULL, |
| NULL, |
| tempImage, |
| D3DFMT_A8R8G8B8, |
| width * texelBytes, |
| NULL, |
| &rcSrcRect, |
| D3DX_FILTER_NONE, |
| 0); |
| |
| FREE(tempImage); |
| IDirect3DSurface8_Release(pSurface); |
| } |
| */ |
| |
| //--------------------------------------------------------------------------- |
| |
| // Faster, more efficient version. |
| // Copies subimage straight to dest texture |
| void gld_TexImage2D_DX8( |
| GLcontext *ctx, |
| GLenum target, |
| GLint level, |
| GLint internalFormat, |
| GLint width, |
| GLint height, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *tObj, |
| struct gl_texture_image *texImage) |
| { |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| IDirect3DTexture8 *pTex; |
| IDirect3DSurface8 *pSurface; |
| HRESULT hr; |
| D3DLOCKED_RECT d3dLockedRect; |
| D3DSURFACE_DESC d3dsd; |
| |
| if (!tObj || !texImage) |
| return; |
| |
| // GLQUAKE FIX |
| // Test for input alpha data with non-alpha internalformat |
| if (((internalFormat==3) || (internalFormat==GL_RGB)) && (format==GL_RGBA)) { |
| // Input format has alpha, but a non-alpha format has been requested. |
| texImage->IntFormat = GL_RGBA; |
| internalFormat = GL_RGBA; |
| } |
| |
| if (level == 0) { |
| _gldAllocateTexture(ctx, tObj, texImage); |
| } |
| |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (!pTex) |
| return; // Texture has not been created |
| if (level >= IDirect3DTexture8_GetLevelCount(pTex)) |
| return; // Level does not exist |
| hr = IDirect3DTexture8_GetSurfaceLevel(pTex, level, &pSurface); |
| if (FAILED(hr)) |
| return; // Surface level doesn't exist (or just a plain error) |
| |
| IDirect3DSurface8_GetDesc(pSurface, &d3dsd); |
| |
| // Lock all of surface |
| hr = IDirect3DSurface8_LockRect(pSurface, &d3dLockedRect, NULL, 0); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pSurface); |
| return; |
| } |
| |
| // unpack image, apply transfer ops and store directly in texture |
| texImage->TexFormat->StoreImage( |
| ctx, |
| 2, |
| texImage->Format, |
| _gldMesaFormatForD3DFormat(d3dsd.Format), |
| d3dLockedRect.pBits, |
| width, height, 1, 0, 0, 0, |
| d3dLockedRect.Pitch, |
| 0, // dstImageStride |
| format, type, pixels, packing); |
| |
| IDirect3DSurface8_UnlockRect(pSurface); |
| IDirect3DSurface8_Release(pSurface); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_TexImage1D_DX8(GLcontext *ctx, GLenum target, GLint level, |
| GLint internalFormat, |
| GLint width, GLint border, |
| GLenum format, GLenum type, const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *texObj, |
| struct gl_texture_image *texImage ) |
| { |
| // A 1D texture is a 2D texture with a height of zero |
| gld_TexImage2D_DX8(ctx, target, level, internalFormat, width, 1, border, format, type, pixels, packing, texObj, texImage); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| /* |
| void gld_TexSubImage2D( GLcontext *ctx, GLenum target, GLint level, |
| GLint xoffset, GLint yoffset, |
| GLsizei width, GLsizei height, |
| GLenum format, GLenum type, |
| const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *tObj, |
| struct gl_texture_image *texImage ) |
| { |
| GLD_GET_CONTEXT |
| IDirect3DTexture8 *pTex; |
| IDirect3DSurface8 *pSurface; |
| D3DFORMAT d3dFormat; |
| HRESULT hr; |
| GLint texelBytes = 4; |
| GLvoid *tempImage; |
| RECT rcSrcRect; |
| RECT rcDstRect; |
| |
| if (!tObj || !texImage) |
| return; |
| |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (!pTex) |
| return; // Texture has not been created |
| if (level >= _GLD_DX8_TEX(GetLevelCount(pTex)) |
| return; // Level does not exist |
| hr = _GLD_DX8_TEX(GetSurfaceLevel(pTex, level, &pSurface); |
| if (FAILED(hr)) |
| return; // Surface level doesn't exist (or just a plain error) |
| |
| d3dFormat = _gldGLFormatToD3DFormat(texImage->Format); |
| tempImage = MALLOC(width * height * texelBytes); |
| if (!tempImage) { |
| _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); |
| IDirect3DSurface8_Release(pSurface); |
| return; |
| } |
| |
| // unpack image, apply transfer ops and store in tempImage |
| texImage->TexFormat->StoreImage(ctx, 2, texImage->Format, |
| &_mesa_texformat_argb8888, // dest format |
| tempImage, |
| width, height, 1, 0, 0, 0, |
| width * texelBytes, |
| 0, // dstImageStride |
| format, type, pixels, packing); |
| |
| // Source rectangle is whole of input image |
| SetRect(&rcSrcRect, 0, 0, width, height); |
| |
| // Dest rectangle must be offset to dest image |
| SetRect(&rcDstRect, 0, 0, width, height); |
| OffsetRect(&rcDstRect, xoffset, yoffset); |
| |
| D3DXLoadSurfaceFromMemory( |
| pSurface, |
| NULL, |
| &rcDstRect, |
| tempImage, |
| D3DFMT_A8R8G8B8, |
| width * texelBytes, |
| NULL, |
| &rcSrcRect, |
| D3DX_FILTER_NONE, |
| 0); |
| |
| FREE(tempImage); |
| IDirect3DSurface8_Release(pSurface); |
| } |
| */ |
| |
| //--------------------------------------------------------------------------- |
| |
| // Faster, more efficient version. |
| // Copies subimage straight to dest texture |
| void gld_TexSubImage2D_DX8( GLcontext *ctx, GLenum target, GLint level, |
| GLint xoffset, GLint yoffset, |
| GLsizei width, GLsizei height, |
| GLenum format, GLenum type, |
| const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *tObj, |
| struct gl_texture_image *texImage ) |
| { |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| IDirect3DTexture8 *pTex; |
| IDirect3DSurface8 *pSurface; |
| HRESULT hr; |
| RECT rcDstRect; |
| D3DLOCKED_RECT d3dLockedRect; |
| D3DSURFACE_DESC d3dsd; |
| |
| if (!tObj || !texImage) |
| return; |
| |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (!pTex) |
| return; // Texture has not been created |
| if (level >= IDirect3DTexture8_GetLevelCount(pTex)) |
| return; // Level does not exist |
| hr = IDirect3DTexture8_GetSurfaceLevel(pTex, level, &pSurface); |
| if (FAILED(hr)) |
| return; // Surface level doesn't exist (or just a plain error) |
| |
| IDirect3DSurface8_GetDesc(pSurface, &d3dsd); |
| |
| // Dest rectangle must be offset to dest image |
| SetRect(&rcDstRect, 0, 0, width, height); |
| OffsetRect(&rcDstRect, xoffset, yoffset); |
| |
| // Lock sub-rect of surface |
| hr = IDirect3DSurface8_LockRect(pSurface, &d3dLockedRect, &rcDstRect, 0); |
| if (FAILED(hr)) { |
| IDirect3DSurface8_Release(pSurface); |
| return; |
| } |
| |
| // unpack image, apply transfer ops and store directly in texture |
| texImage->TexFormat->StoreImage(ctx, 2, texImage->Format, |
| _gldMesaFormatForD3DFormat(d3dsd.Format), |
| d3dLockedRect.pBits, |
| width, height, 1, |
| 0, 0, 0, // NOTE: d3dLockedRect.pBits is already offset!!! |
| d3dLockedRect.Pitch, |
| 0, // dstImageStride |
| format, type, pixels, packing); |
| |
| |
| IDirect3DSurface8_UnlockRect(pSurface); |
| IDirect3DSurface8_Release(pSurface); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_TexSubImage1D_DX8( GLcontext *ctx, GLenum target, GLint level, |
| GLint xoffset, GLsizei width, |
| GLenum format, GLenum type, |
| const GLvoid *pixels, |
| const struct gl_pixelstore_attrib *packing, |
| struct gl_texture_object *texObj, |
| struct gl_texture_image *texImage ) |
| { |
| gld_TexSubImage2D_DX8(ctx, target, level, xoffset, 0, width, 1, format, type, pixels, packing, texObj, texImage); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_DeleteTexture_DX8( |
| GLcontext *ctx, |
| struct gl_texture_object *tObj) |
| { |
| GLD_context *gld = (GLD_context*)(ctx->DriverCtx); |
| |
| if (tObj) { |
| IDirect3DTexture8 *pTex = (IDirect3DTexture8*)tObj->DriverData; |
| if (pTex) { |
| /* // Make sure texture is not bound to a stage before releasing it |
| for (int i=0; i<MAX_TEXTURE_UNITS; i++) { |
| if (gld->CurrentTexture[i] == pTex) { |
| gld->pDev->SetTexture(i, NULL); |
| gld->CurrentTexture[i] = NULL; |
| } |
| }*/ |
| _GLD_DX8_TEX(Release(pTex)); |
| tObj->DriverData = NULL; |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| __inline void _gldSetColorOps( |
| const GLD_driver_dx8 *gld, |
| GLuint unit, |
| DWORD ColorArg1, |
| D3DTEXTUREOP ColorOp, |
| DWORD ColorArg2) |
| { |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_COLORARG1, ColorArg1)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_COLOROP, ColorOp)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_COLORARG2, ColorArg2)); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| __inline void _gldSetAlphaOps( |
| const GLD_driver_dx8 *gld, |
| GLuint unit, |
| DWORD AlphaArg1, |
| D3DTEXTUREOP AlphaOp, |
| DWORD AlphaArg2) |
| { |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_ALPHAARG1, AlphaArg1)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_ALPHAOP, AlphaOp)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_ALPHAARG2, AlphaArg2)); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gldUpdateTextureUnit( |
| GLcontext *ctx, |
| GLuint unit, |
| BOOL bPassThrough) |
| { |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| |
| D3DTEXTUREFILTERTYPE minfilter; |
| D3DTEXTUREFILTERTYPE mipfilter; |
| GLenum BaseFormat; |
| DWORD dwColorArg0; |
| int iTexEnv = 0; |
| GLD_texenv *pTexenv; |
| |
| // NOTE: If bPassThrough is FALSE then texture stage can be |
| // disabled otherwise it must pass-through it's current fragment. |
| |
| const struct gl_texture_unit *pUnit = &ctx->Texture.Unit[unit]; |
| const struct gl_texture_object *tObj = pUnit->_Current; |
| |
| IDirect3DTexture8 *pTex = NULL; |
| if (tObj) { |
| pTex = (IDirect3DTexture8*)tObj->DriverData; |
| } |
| |
| // Enable texturing if unit is enabled and a valid D3D texture exists |
| // Mesa 5: TEXTUREn_x altered to TEXTURE_nD_BIT |
| //if (pTex && (pUnit->Enabled & (TEXTURE0_1D | TEXTURE0_2D))) { |
| if (pTex && (pUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT))) { |
| // Enable texturing |
| _GLD_DX8_DEV(SetTexture(gld->pDev, unit, pTex)); |
| } else { |
| // Disable texturing, then return |
| _GLD_DX8_DEV(SetTexture(gld->pDev, unit, NULL)); |
| if (bPassThrough) { |
| _gldSetColorOps(gld, unit, D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_DIFFUSE); |
| _gldSetAlphaOps(gld, unit, D3DTA_TEXTURE, D3DTOP_SELECTARG2, D3DTA_DIFFUSE); |
| } else { |
| _gldSetColorOps(gld, unit, D3DTA_TEXTURE, D3DTOP_DISABLE, D3DTA_DIFFUSE); |
| _gldSetAlphaOps(gld, unit, D3DTA_TEXTURE, D3DTOP_DISABLE, D3DTA_DIFFUSE); |
| } |
| return; |
| } |
| |
| // Texture parameters |
| _gldConvertMinFilter(tObj->MinFilter, &minfilter, &mipfilter); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_MINFILTER, minfilter)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_MIPFILTER, mipfilter)); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_MAGFILTER, _gldConvertMagFilter(tObj->MagFilter))); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_ADDRESSU, _gldConvertWrap(tObj->WrapS))); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_ADDRESSV, _gldConvertWrap(tObj->WrapT))); |
| |
| // Texture priority |
| _GLD_DX8_TEX(SetPriority(pTex, (DWORD)(tObj->Priority*65535.0f))); |
| |
| // Texture environment |
| // TODO: Examine input texture for alpha and use specific alpha/non-alpha ops. |
| // See Page 355 of the Red Book. |
| BaseFormat = _gldDecodeBaseFormat(pTex); |
| |
| switch (BaseFormat) { |
| case GL_RGB: |
| iTexEnv = 0; |
| break; |
| case GL_RGBA: |
| iTexEnv = 1; |
| break; |
| case GL_ALPHA: |
| iTexEnv = 2; |
| break; |
| } |
| |
| switch (pUnit->EnvMode) { |
| case GL_DECAL: |
| iTexEnv += 0; |
| break; |
| case GL_REPLACE: |
| iTexEnv += 3; |
| break; |
| case GL_MODULATE: |
| iTexEnv += 6; |
| break; |
| case GL_BLEND: |
| // Set blend colour |
| dwColorArg0 = D3DCOLOR_COLORVALUE(pUnit->EnvColor[0], pUnit->EnvColor[1], pUnit->EnvColor[2], pUnit->EnvColor[3]); |
| _GLD_DX8_DEV(SetTextureStageState(gld->pDev, unit, D3DTSS_COLORARG0, dwColorArg0)); |
| iTexEnv += 9; |
| break; |
| case GL_ADD: |
| iTexEnv += 12; |
| break; |
| } |
| pTexenv = (GLD_texenv*)&gldTexEnv[iTexEnv]; |
| _gldSetColorOps(gld, unit, pTexenv->ColorArg1, pTexenv->ColorOp, pTexenv->ColorArg2); |
| _gldSetAlphaOps(gld, unit, pTexenv->AlphaArg1, pTexenv->AlphaOp, pTexenv->AlphaArg2); |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| void gld_NEW_TEXTURE_DX8( |
| GLcontext *ctx) |
| { |
| // TODO: Support for three (ATI Radeon) or more (nVidia GeForce3) texture units |
| |
| BOOL bUnit0Enabled; |
| BOOL bUnit1Enabled; |
| |
| if (!ctx) |
| return; // Sanity check |
| |
| if (ctx->Const.MaxTextureUnits == 1) { |
| gldUpdateTextureUnit(ctx, 0, TRUE); |
| return; |
| } |
| |
| // |
| // NOTE: THE FOLLOWING RELATES TO TWO TEXTURE UNITS, AND TWO ONLY!! |
| // |
| |
| // Mesa 5: Texture Units altered |
| //bUnit0Enabled = (ctx->Texture._ReallyEnabled & (TEXTURE0_1D | TEXTURE0_2D)) ? TRUE : FALSE; |
| //bUnit1Enabled = (ctx->Texture._ReallyEnabled & (TEXTURE1_1D | TEXTURE1_2D)) ? TRUE : FALSE; |
| bUnit0Enabled = (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) ? TRUE : FALSE; |
| bUnit1Enabled = (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) ? TRUE : FALSE; |
| |
| // If Unit0 is disabled and Unit1 is enabled then we must pass-though |
| gldUpdateTextureUnit(ctx, 0, (!bUnit0Enabled && bUnit1Enabled) ? TRUE : FALSE); |
| // We can always disable the last texture unit |
| gldUpdateTextureUnit(ctx, 1, FALSE); |
| |
| #ifdef _DEBUG |
| { |
| // Find out whether device supports current renderstates |
| GLD_context *gldCtx = GLD_GET_CONTEXT(ctx); |
| GLD_driver_dx8 *gld = GLD_GET_DX8_DRIVER(gldCtx); |
| // GLD_context *gld = GLD_GET_CONTEXT(ctx); |
| |
| DWORD dwPasses; |
| _GLD_DX8_DEV(ValidateDevice(gld->pDev, &dwPasses)); |
| // if (FAILED(hr)) { |
| // gldLogError(GLDLOG_ERROR, "ValidateDevice failed", hr); |
| // } |
| if (dwPasses != 1) { |
| gldLogMessage(GLDLOG_ERROR, "ValidateDevice: Can't do in one pass\n"); |
| } |
| } |
| #endif |
| }; |
| |
| //--------------------------------------------------------------------------- |