/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "displaylists.h" #include "smartlock.h" #include "sysinc.h" #include #include #include #include "util.h" static char rcsid[] UNUSED = "$Id$"; #define min(x,y) (x) < (y) ? (x) : (y) #define max(x,y) (x) > (y) ? (x) : (y) void tex_FreeTextures(GLcontext context); void tex_SetEnv(GLcontext context, GLenum env); static uint32 tex_GLFilter2W3D(GLenum filter, GLboolean useMip, GLboolean useAniso); void tex_SetFilter(GLcontext context, GLenum min, GLenum mag, GLint maxAniso); void tex_SetWrap(GLcontext context, GLenum wrap_s, GLenum wrap_t); void DisableBlendStage(GLcontext context, uint32 stage); uint32 MGLConvert(GLcontext context, GLenum internalformat, GLuint width, GLuint height, GLenum format, GLenum type, GLubyte *source, GLubyte *dest); BOOL MGLUpdate(GLcontext context, GLenum internalformat, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, const GLubyte *source, GLubyte *dest, GLsizei destWidth, GLenum format, GLenum type); int32 SelectUnpacker(GLcontext context, GLenum format, GLenum type); int32 SelectInternalFormat(GLcontext context, GLenum internalformat); struct W3DtoGL *MGLGetFormatInfo(uint32 w3dFormat); extern GLsizei next_pwr(GLsizei x); extern struct InternalToW3D i2w3d[]; extern GLboolean MGLUnpackImage(GLcontext context, GLsizei width, GLsizei height, GLimage_info *src, GLimage_info *dst, GLboolean doPixelState); extern GLboolean MGLPackImage(GLcontext context, GLsizei width, GLsizei height, GLimage_info *src, GLimage_info *dst, GLboolean doPixelState); extern _glPackFn MGLSelectPacker(GLenum format, GLenum type, GLuint *pixelStride); extern _glUnpackFn MGLSelectUnpacker(GLenum format, GLenum type, GLuint *pixelStride); extern float CLAMPF(float a); void m_BuildInvertedFull(GLcontext context); static uint32 Allocated_Size = 0; static uint32 Peak_Size = 0; extern int32 mapMGLTexEnvToW3D(int32 mglEnv, int32 defEnv); void SetBlendStageState(GLcontext context, uint32 stage) { if (context->enable.Texture2D[stage] || context->enable.Texture1D[stage]) { int32 w3dMode = mapMGLTexEnvToW3D(context->texture.TextureEnv[stage], W3D_ILLEGALINPUT); if (w3dMode != W3D_ILLEGALINPUT) { if (context->NumTextureUnits > 1) { IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, w3dMode, TAG_DONE ); } else { // Permedia ? W3D_Texture* tex = context->w3dTextures[context->texture.CurrentBinding[0]].texObj; if (tex) { IWarp3D->W3D_SetTexEnv(context->w3dContext, tex, w3dMode, 0); } } } /* switch (context->texture.TextureEnv[stage]) { case GL_REPLACE: IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_REPLACE, TAG_DONE ); break; case GL_MODULATE: IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_MODULATE, TAG_DONE ); break; case GL_DECAL: IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_DECAL, TAG_DONE ); break; case GL_BLEND: IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_BLEND, TAG_DONE ); break; case GL_ADD: IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_ADD, TAG_DONE ); break; } */ } else { DisableBlendStage(context, stage); } } void DisableBlendStage(GLcontext context, uint32 stage) { IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, stage, W3D_ENV_MODE, W3D_OFF, TAG_DONE ); } void RebindTextures(GLcontext context) { int i; for (i = 0; i <= context->texture.MaxTextureUnit; i++) { if (context->w3dTextures[context->texture.CurrentBinding[i]].texObj == 0) { dprintf("Warning: rebinding texture that does not exist\n"); IWarp3D->W3D_BindTexture( context->w3dContext, i, context->w3dTextures[context->texture.CurrentBinding[i]].texObj ); // Incomplete textures should be rendered as if texturing was disabled IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, i, W3D_ENV_MODE, W3D_ADD, TAG_DONE ); } else { IWarp3D->W3D_BindTexture( context->w3dContext, i, context->w3dTextures[context->texture.CurrentBinding[i]].texObj ); SetBlendStageState(context, i); } } } void *tex_Alloc(uint32 size, BOOL clear) { uint32 *x; Allocated_Size += size+4; if (clear) { x=(uint32 *)AllocVecInternal(size+4, MEMF_ANY | MEMF_CLEAR); } else { x=(uint32 *)AllocVecInternal(size+4, MEMF_ANY); } if (!x) { return 0; } *x = size; if (Allocated_Size > Peak_Size) { Peak_Size = Allocated_Size; } return x+1; } void tex_Free(void *chunk) { uint32 *mem = (uint32 *)chunk; mem--; Allocated_Size -= *mem; Allocated_Size -= 4; FreeVecInternal(mem); } void tex_Statistic(void) { dprintf("Peak Allocation Size: %ld\n", Peak_Size); } void MGLTexMemStat(GLcontext context, GLint *Current, GLint *Peak) { if (Current) { *Current = (GLint)Allocated_Size; } if (Peak) { *Peak = (GLint)Peak_Size; } } void cgl_GLDeleteTextures(struct GLContextIFace *Self, GLsizei n, const GLuint *textures) { GLcontext context = GET_INSTANCE(Self); int i; if (!context) return; for (i=0; i 0 && j < context->TexBufferSize) { if (context->w3dTextures[j].texObj) { // Work around a bug in Warp3D (fixed in the meantime) //IWarp3D->W3D_BindTexture(context->w3dContext, j, NULL); IWarp3D->W3D_FreeTexObj(context->w3dContext, context->w3dTextures[j].texObj); context->w3dTextures[j].texObj = NULL; } if (context->w3dTextures[j].texData) { tex_Free(context->w3dTextures[j].texData); context->w3dTextures[j].texData = NULL; } context->GeneratedTextures[j] = 0; } } } void cgl_GLGenTextures(struct GLContextIFace *Self, GLsizei n, GLuint *textures) { GLcontext context = GET_INSTANCE(Self); int i,j; j = 1; for (i=0; iTexBufferSize) { if (context->GeneratedTextures[j] == 0) { break; } j++; } // If we get here, we found one, or there's noting available. Flag an error in that case.. if (j == context->TexBufferSize) { GLFlagError(context, j == context->TexBufferSize, GL_INVALID_OPERATION); return; } // Insert the texture in the output array, and flag it as used internally *textures = j; context->GeneratedTextures[j] = 1; textures++; j++; } } void tex_FreeTextures(GLcontext context) { int i; for (i=0; iTexBufferSize; i++) { if (context->w3dTextures[i].texObj) { IWarp3D->W3D_FreeTexObj(context->w3dContext, context->w3dTextures[i].texObj); context->w3dTextures[i].texObj = NULL; } if (context->w3dTextures[i].texData) { tex_Free(context->w3dTextures[i].texData); context->w3dTextures[i].texData = 0; } } IWarp3D->W3D_FreeAllTexObj(context->w3dContext); } void tex_SetEnv(GLcontext context, GLenum env) { SetBlendStageState(context, context->texture.ActiveTexture); } static uint32 tex_GLFilter2W3D(GLenum filter, GLboolean useMip, GLboolean useAniso) { switch (filter) { case GL_NEAREST: return useAniso ? W3D_ANISOTROPIC_NEAREST : W3D_NEAREST; case GL_LINEAR: return useAniso ? W3D_ANISOTROPIC_LINEAR : W3D_LINEAR; case GL_NEAREST_MIPMAP_NEAREST: return useMip ? (useAniso ? W3D_ANISOTROPIC_NEAREST_MIP_NEAREST : W3D_NEAREST_MIP_NEAREST) : (useAniso ? W3D_ANISOTROPIC_NEAREST : W3D_NEAREST); case GL_LINEAR_MIPMAP_NEAREST: return useMip ? (useAniso ? W3D_ANISOTROPIC_NEAREST_MIP_NEAREST : W3D_LINEAR_MIP_NEAREST) : (useAniso ? W3D_ANISOTROPIC_LINEAR : W3D_LINEAR); case GL_NEAREST_MIPMAP_LINEAR: return useMip ? (useAniso ? W3D_ANISOTROPIC_NEAREST_MIP_LINEAR : W3D_NEAREST_MIP_LINEAR) : (useAniso ? W3D_ANISOTROPIC_NEAREST : W3D_NEAREST); case GL_LINEAR_MIPMAP_LINEAR: return useMip ? (useAniso ? W3D_ANISOTROPIC_NEAREST_MIP_LINEAR : W3D_LINEAR_MIP_LINEAR) : (useAniso ? W3D_ANISOTROPIC_LINEAR : W3D_LINEAR); } return 0; } void tex_SetFilter(GLcontext context, GLenum min, GLenum mag, GLint maxAniso) { uint32 minf, magf; W3D_Texture *tex = context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].texObj; if (!tex) { return; } if (maxAniso > context->MaxAnisotropy) { maxAniso = context->MaxAnisotropy; } /* Minification can use MIP and/or Anisotropic filtering */ minf = tex_GLFilter2W3D(min, !context->NoMipMapping, (maxAniso > 1)); /* Magnification can only use nearest or linear filtering */ magf = tex_GLFilter2W3D(mag, GL_FALSE, GL_FALSE); //kprintf("Setting MinFilter %s, MagFilter %s\n", filters[minf-1], filters[magf-1]); IWarp3D->W3D_SetFilter(context->w3dContext, tex, minf, magf); if (maxAniso > 1) { uint32 w3dAniso = 1 + fast_log2(maxAniso); IWarp3D->W3D_SetMaxAnisotropy(context->w3dContext, tex, w3dAniso); } else if (maxAniso < 1) { maxAniso = 1; } context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].MinFilter = min; context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].MagFilter = mag; context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].MaxAnisotropy = maxAniso; } void tex_SetWrap(GLcontext context, GLenum wrap_s, GLenum wrap_t) { uint32 Ws,Wt; W3D_Texture *tex = context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].texObj; if (!tex) { return; } if (wrap_s == GL_REPEAT) { Ws = W3D_REPEAT; } else { Ws = W3D_CLAMP; } if (wrap_t == GL_REPEAT) { Wt = W3D_REPEAT; } else { Wt = W3D_CLAMP; } IWarp3D->W3D_SetWrapMode(context->w3dContext, tex, Ws, Wt, NULL); context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].WrapS = wrap_s; context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].WrapT = wrap_t; } void cgl_GLTexEnvi(struct GLContextIFace *Self, GLenum target, GLenum pname, GLint param) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexEnvi(Self, target, pname, param)) GLFlagError(context, target != GL_TEXTURE_ENV, GL_INVALID_ENUM); switch(pname) { case GL_TEXTURE_ENV_MODE: GLFlagError(context, param != GL_ADD && param != GL_MODULATE && param != GL_DECAL && param != GL_BLEND && param != GL_REPLACE && param != GL_COMBINE, GL_INVALID_ENUM); context->texture.TextureEnv[context->texture.ActiveTexture] = (GLenum)param; tex_SetEnv(context, param); break; case GL_COMBINE_RGB: if(param == GL_DOT3_RGB_EXT) { param = GL_DOT3_RGB; } else if(param == GL_DOT3_RGBA_EXT) { param = GL_DOT3_RGBA; } GLFlagError(context, param != GL_REPLACE && param != GL_MODULATE && param != GL_ADD && param != GL_ADD_SIGNED && param != GL_INTERPOLATE && param != GL_SUBTRACT && param != GL_DOT3_RGB && param != GL_DOT3_RGBA, GL_INVALID_ENUM); if (context->texture.colorCombine[context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorCombine[context->texture.ActiveTexture] = (GLenum)param; break; case GL_COMBINE_ALPHA: GLFlagError(context, param != GL_REPLACE && param != GL_MODULATE && param != GL_ADD && param != GL_ADD_SIGNED && param != GL_INTERPOLATE && param != GL_SUBTRACT, GL_INVALID_ENUM); if (context->texture.alphaCombine[context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaCombine[context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE0_RGB: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.colorSource[0][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorSource[0][context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE1_RGB: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.colorSource[1][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorSource[1][context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE2_RGB: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.colorSource[2][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorSource[2][context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE0_ALPHA: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.alphaSource[0][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaSource[0][context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE1_ALPHA: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.alphaSource[1][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaSource[1][context->texture.ActiveTexture] = (GLenum)param; break; case GL_SOURCE2_ALPHA: GLFlagError(context, param != GL_TEXTURE && param != GL_TEXTURE0 && param != GL_TEXTURE1 && param != GL_TEXTURE2 && param != GL_TEXTURE3 && param != GL_CONSTANT && param != GL_PRIMARY_COLOR && param != GL_PREVIOUS, GL_INVALID_ENUM); if (context->texture.alphaSource[2][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaSource[2][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND0_RGB: GLFlagError(context, param != GL_SRC_COLOR && param != GL_ONE_MINUS_SRC_COLOR && param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.colorOperand[0][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorOperand[0][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND1_RGB: GLFlagError(context, param != GL_SRC_COLOR && param != GL_ONE_MINUS_SRC_COLOR && param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.colorOperand[1][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorOperand[1][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND2_RGB: GLFlagError(context, param != GL_SRC_COLOR && param != GL_ONE_MINUS_SRC_COLOR && param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.colorOperand[2][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorOperand[2][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND0_ALPHA: GLFlagError(context, param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.alphaOperand[0][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaOperand[0][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND1_ALPHA: GLFlagError(context, param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.alphaOperand[1][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaOperand[1][context->texture.ActiveTexture] = (GLenum)param; break; case GL_OPERAND2_ALPHA: GLFlagError(context, param != GL_SRC_ALPHA && param != GL_ONE_MINUS_SRC_ALPHA, GL_INVALID_ENUM); if (context->texture.alphaOperand[2][context->texture.ActiveTexture] == (GLenum)param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaOperand[2][context->texture.ActiveTexture] = (GLenum)param; break; case GL_RGB_SCALE: GLFlagError(context, param != 1 && param != 2 && param != 4, GL_INVALID_VALUE); if (context->texture.colorScale[context->texture.ActiveTexture] == param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.colorScale[context->texture.ActiveTexture] = param; break; case GL_ALPHA_SCALE: GLFlagError(context, param != 1 && param != 2 && param != 4, GL_INVALID_VALUE); if (context->texture.alphaScale[context->texture.ActiveTexture] == param) { break; } context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.alphaScale[context->texture.ActiveTexture] = param; break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } } void cgl_GLTexEnvfv(struct GLContextIFace *Self, GLenum target, GLenum pname, const GLfloat* param) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexEnvfv(Self, target, pname, param)) GLFlagError(context, target != GL_TEXTURE_ENV, GL_INVALID_ENUM); switch (pname) { case GL_TEXTURE_ENV_COLOR: context->combineDirty[context->texture.ActiveTexture] = GL_TRUE; context->texture.envColor[context->texture.ActiveTexture].r = CLAMPF(param[0]); context->texture.envColor[context->texture.ActiveTexture].g = CLAMPF(param[1]); context->texture.envColor[context->texture.ActiveTexture].b = CLAMPF(param[2]); context->texture.envColor[context->texture.ActiveTexture].a = CLAMPF(param[3]); break; default: Self->GLTexEnvi(target, pname, (GLint)param[0]); break; } } void cgl_GLGetTexEnviv(struct GLContextIFace *Self, GLenum target, GLenum pname, GLint* params) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, target != GL_TEXTURE_ENV, GL_INVALID_ENUM); #define FROM_BOOL(x) (GLint)((x) ? 1 : 0) #define FROM_COLOR(x) (GLint)((0xffffffff * (x) - 1)/2) #define FROM_FLOAT(x) (GLint)(x) #define FROM_INT(x) (x) switch (pname) { case GL_TEXTURE_ENV_MODE: params[0] = FROM_INT(context->texture.TextureEnv[context->texture.ActiveTexture]); break; case GL_TEXTURE_ENV_COLOR: params[0] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].r); params[1] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].g); params[2] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].b); params[3] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].a); break; case GL_COMBINE_RGB: params[0] = FROM_INT(context->texture.colorCombine[context->texture.ActiveTexture]); break; case GL_COMBINE_ALPHA: params[0] = FROM_INT(context->texture.alphaCombine[context->texture.ActiveTexture]); break; case GL_SOURCE0_RGB: params[0] = FROM_INT(context->texture.colorSource[0][context->texture.ActiveTexture]); break; case GL_SOURCE1_RGB: params[0] = FROM_INT(context->texture.colorSource[1][context->texture.ActiveTexture]); break; case GL_SOURCE2_RGB: params[0] = FROM_INT(context->texture.colorSource[2][context->texture.ActiveTexture]); break; case GL_SOURCE0_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[0][context->texture.ActiveTexture]); break; case GL_SOURCE1_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[1][context->texture.ActiveTexture]); break; case GL_SOURCE2_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[2][context->texture.ActiveTexture]); break; case GL_OPERAND0_RGB: params[0] = FROM_INT(context->texture.colorOperand[0][context->texture.ActiveTexture]); break; case GL_OPERAND1_RGB: params[0] = FROM_INT(context->texture.colorOperand[1][context->texture.ActiveTexture]); break; case GL_OPERAND2_RGB: params[0] = FROM_INT(context->texture.colorOperand[2][context->texture.ActiveTexture]); break; case GL_OPERAND0_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[0][context->texture.ActiveTexture]); break; case GL_OPERAND1_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[1][context->texture.ActiveTexture]); break; case GL_OPERAND2_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[2][context->texture.ActiveTexture]); break; case GL_RGB_SCALE: params[0] = FROM_INT(context->texture.colorScale[context->texture.ActiveTexture]); break; case GL_ALPHA_SCALE: params[0] = FROM_INT(context->texture.alphaScale[context->texture.ActiveTexture]); break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } #undef FROM_BOOL #undef FROM_COLOR #undef FROM_FLOAT #undef FROM_INT } void cgl_GLGetTexEnvfv(struct GLContextIFace* Self, GLenum target, GLenum pname, GLfloat* params) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, target != GL_TEXTURE_ENV, GL_INVALID_ENUM); #define FROM_BOOL(x) (GLfloat)((x) ? 1.0f : 0.0f) #define FROM_COLOR(x) (GLfloat)(x) #define FROM_FLOAT(x) (x) #define FROM_INT(x) (GLfloat)(x) switch (pname) { case GL_TEXTURE_ENV_MODE: params[0] = FROM_INT(context->texture.TextureEnv[context->texture.ActiveTexture]); break; case GL_TEXTURE_ENV_COLOR: params[0] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].r); params[1] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].g); params[2] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].b); params[3] = FROM_COLOR(context->texture.envColor[context->texture.ActiveTexture].a); break; case GL_COMBINE_RGB: params[0] = FROM_INT(context->texture.colorCombine[context->texture.ActiveTexture]); break; case GL_COMBINE_ALPHA: params[0] = FROM_INT(context->texture.alphaCombine[context->texture.ActiveTexture]); break; case GL_SOURCE0_RGB: params[0] = FROM_INT(context->texture.colorSource[0][context->texture.ActiveTexture]); break; case GL_SOURCE1_RGB: params[0] = FROM_INT(context->texture.colorSource[1][context->texture.ActiveTexture]); break; case GL_SOURCE2_RGB: params[0] = FROM_INT(context->texture.colorSource[2][context->texture.ActiveTexture]); break; case GL_SOURCE0_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[0][context->texture.ActiveTexture]); break; case GL_SOURCE1_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[1][context->texture.ActiveTexture]); break; case GL_SOURCE2_ALPHA: params[0] = FROM_INT(context->texture.alphaSource[2][context->texture.ActiveTexture]); break; case GL_OPERAND0_RGB: params[0] = FROM_INT(context->texture.colorOperand[0][context->texture.ActiveTexture]); break; case GL_OPERAND1_RGB: params[0] = FROM_INT(context->texture.colorOperand[1][context->texture.ActiveTexture]); break; case GL_OPERAND2_RGB: params[0] = FROM_INT(context->texture.colorOperand[2][context->texture.ActiveTexture]); break; case GL_OPERAND0_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[0][context->texture.ActiveTexture]); break; case GL_OPERAND1_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[1][context->texture.ActiveTexture]); break; case GL_OPERAND2_ALPHA: params[0] = FROM_INT(context->texture.alphaOperand[2][context->texture.ActiveTexture]); break; case GL_RGB_SCALE: params[0] = FROM_INT(context->texture.colorScale[context->texture.ActiveTexture]); break; case GL_ALPHA_SCALE: params[0] = FROM_INT(context->texture.alphaScale[context->texture.ActiveTexture]); break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } #undef FROM_BOOL #undef FROM_COLOR #undef FROM_FLOAT #undef FROM_INT } void cgl_GLTexParameteri(struct GLContextIFace *Self, GLenum target, GLenum pname, GLint param) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexParameteri(Self, target, pname, param)) switch (pname) { case GL_TEXTURE_MIN_FILTER: tex_SetFilter(context, (GLenum)param, context->texture.MagFilter, context->texture.MaxAnisotropy); context->texture.MinFilter = (GLenum)param; break; case GL_TEXTURE_MAG_FILTER: tex_SetFilter(context, context->texture.MinFilter, (GLenum)param, context->texture.MaxAnisotropy); context->texture.MagFilter = (GLenum)param; break; case GL_TEXTURE_WRAP_S: tex_SetWrap(context, (GLenum)param, context->texture.WrapT); context->texture.WrapS = (GLenum)param; break; case GL_TEXTURE_WRAP_T: tex_SetWrap(context, context->texture.WrapS, (GLenum)param); context->texture.WrapT = (GLenum)param; break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: context->texture.MaxAnisotropy = param; tex_SetFilter(context, context->texture.MinFilter, context->texture.MagFilter, param); break; default: GLFlagError(context, 1, GL_INVALID_ENUM); } } void cgl_GLTexParameterfv(struct GLContextIFace *Self, GLenum target, GLenum pname, GLfloat *param) { Self->GLTexParameteri(target, pname, (GLint)param[0]); } void cgl_GLTexParameteriv(struct GLContextIFace *Self, GLenum target, GLenum pname, GLint *param) { Self->GLTexParameteri(target, pname, param[0]); } void cgl_GLBindTexture(struct GLContextIFace *Self, GLenum target, GLuint texture) { GLcontext context = GET_INSTANCE(Self); if (!context) { return; } DL_CHECK(BindTexture(Self, target, texture)) GLFlagError(context, target != GL_TEXTURE_2D && target != GL_TEXTURE_1D, GL_INVALID_ENUM); GLFlagError(context, texture >= context->TexBufferSize, GL_INVALID_OPERATION); context->texture.CurrentBinding[context->texture.ActiveTexture] = texture; if ( context->w3dTextures[ context->texture.CurrentBinding[context->texture.ActiveTexture] ].texObj == NULL ) { IWarp3D->W3D_BindTexture(context->w3dContext, context->texture.ActiveTexture, context->w3dTextures[context->texture.CurrentBinding[ context->texture.ActiveTexture]].texObj ); // Incomplete textures should be rendered as if texturing was disabled IWarp3D->W3D_SetTextureBlendTags(context->w3dContext, W3D_BLEND_STAGE, context->texture.ActiveTexture, W3D_ENV_MODE, W3D_ADD, TAG_DONE ); } else { IWarp3D->W3D_BindTexture(context->w3dContext, context->texture.ActiveTexture, context->w3dTextures[context->texture.CurrentBinding[ context->texture.ActiveTexture]].texObj ); SetBlendStageState(context, context->texture.ActiveTexture); } } void GLTexImage2DNoMIP( GLcontext context, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); static void UpdateTexImage(GLcontext context, int texnum, void *image, int level, uint32 *pal) { IWarp3D->W3D_UpdateTexImage(context->w3dContext, context->w3dTextures[texnum].texObj, image, level, pal); /* Rebind the currently bound textures, just in case the current one hasn't * been bound before */ RebindTextures(context); } static void UpdateTexSubImage( GLcontext context, int texnum, void *image, int level, uint32 *pal, int x, int y, int width, int height, int bytesPerRow) { GLboolean relock = GL_FALSE; // for manual locking mode only if (context->w3dLocked == GL_TRUE) { switch(context->LockMode) { case MGL_LOCK_AUTOMATIC: break; case MGL_LOCK_SMART: smartlock_forceUnlock(context->smartLock); break; case MGL_LOCK_MANUAL: IWarp3D->W3D_UnLockHardware(context->w3dContext); relock = GL_TRUE; context->w3dLocked = GL_FALSE; break; } } W3D_Scissor scissor = {x, y, width, height}; IWarp3D->W3D_UpdateTexSubImage( context->w3dContext, context->w3dTextures[texnum].texObj, image, level, pal, &scissor, bytesPerRow ); if (relock) { IWarp3D->W3D_LockHardware(context->w3dContext); context->w3dLocked = GL_TRUE; } /* Rebind the currently bound textures, just in case the current one hasn't * been bound before */ RebindTextures(context); } #ifdef MGL_TEXTURE_COMPRESSION #define ROUND_UP(num, mult) ((((num) + (mult) - 1) / (mult)) * (mult)) #endif static uint32 MGLCalculateMipArray(uint32 width, uint32 height, uint32 bpp, GLubyte *mipmaps[]) { int level = 0; #ifdef MGL_TEXTURE_COMPRESSION uint32 res = ROUND_UP(width, 16) * ROUND_UP(height, 16) * bpp; #else uint32 res = width * height * bpp; #endif int i; for (i = 0; i < 20; i++) { mipmaps[i] = (GLubyte *)0xffffffff; } mipmaps[level++] = (GLubyte *)res; do { if (width > 1) { width /= 2; } if (height > 1) { height /= 2; } #ifdef MGL_TEXTURE_COMPRESSION res += ROUND_UP(width, 16) * ROUND_UP(height, 16) * bpp; #else res += width * height * bpp; #endif mipmaps[level++] = (GLubyte *)res; if (width == 1 && height == 1) { break; } } while (1); return res; } void cgl_GLTexImage2D( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) { GLcontext context = GET_INSTANCE(Self); // Pretend to support GL_RGBA16 if (internalformat == GL_RGBA16) { internalformat = GL_RGBA8; } /* if (gltarget != GL_PROXY_TEXTURE_2D && dl_IsDLActive(Self)){ dl_save_TexImage2D(Self, gltarget, level, internalformat, width, height, border, format, type, pixels); if (!dl_CompileAndExecuteMode(Self)){ return; } } */ if (gltarget != GL_PROXY_TEXTURE_2D) { DL_CHECK(TexImage2D(Self, gltarget, level, internalformat, width, height, border, format, type, pixels)) } int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; uint32 w,h; uint32 targetsize; uint32 error; uint8 *target; uint32 useFormat; int32 internal = SelectInternalFormat(context, internalformat); int32 unpacker = SelectUnpacker(context, format, type); /* Handle GL_PROXY_TEXTURE_2D */ if (gltarget == GL_PROXY_TEXTURE_2D) { extern struct InternalToW3D i2w3d[]; context->proxy_width = width << level; context->proxy_height = height << level; if (internal == -1) { context->proxy_internalFormat = -1; } else { context->proxy_internalFormat = i2w3d[internal].internalformat; } return; } if (context->NoMipMapping == GL_TRUE) { GLTexImage2DNoMIP(context, gltarget, level, internalformat, width, height, border, format, type, pixels); return; } GLFlagError(context, internal == -1 || unpacker == -1, GL_INVALID_OPERATION); GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_PROXY_TEXTURE_2D, GL_INVALID_ENUM); /* ** We will use width and height only when the mipmap level ** is really 0. Otherwise, we need to upscale the values ** according to the level. ** ** Note this will most likely be difficult with non-square ** textures, as the first side to reach one will remain ** there. For example, consider the sequence ** 8x4, 4x2, 2x1, 1x1 ** 0 1 2 3 ** If the 1x1 mipmap is given, upscaling will yield 8x8, not 8x4 */ if (context->w3dTextures[current].texObj == NULL) { w=(uint32)width<w3dTextures[current].texObj->texwidth; h = context->w3dTextures[current].texObj->texheight; if ( (!((width|height)&1) && (w != (width<W3D_FreeTexObj(context->w3dContext, context->w3dTextures[current].texObj); context->w3dTextures[current].texObj = NULL; // dprintf("texture size change detected (%ldx%ld -> %ldx%ld)\n", // w, h, width<w3dTextures[current].texObj == NULL) { int i; /* ** Create a new texture object ** Get the memory */ targetsize = MGLCalculateMipArray(w, h, i2w3d[internal].w3dBpp, context->w3dTextures[current].mipmaps); if (context->w3dTextures[current].texData) { tex_Free(context->w3dTextures[current].texData); } context->w3dTextures[current].texData = (GLubyte *)tex_Alloc(targetsize, (pixels ? FALSE : TRUE)); context->w3dTextures[current].internalFormat = internalformat; // dprintf("(re)allocated texData at %p-%p (%ldx%ldx%ld = %ld bytes)\n", context->w3dTextures[current].texData, context->w3dTextures[current].texData + targetsize - 1, w, h, i2w3d[internal].w3dBpp, targetsize); /* Fixup mipmaps */ for (i = 0; i < 20; i++) { if (context->w3dTextures[current].mipmaps[i] != (GLubyte *)0xffffffff) { context->w3dTextures[current].mipmaps[i] = (GLubyte *)((uint32)context->w3dTextures[current].mipmaps[i] + (uint32)context->w3dTextures[current].texData); } else { context->w3dTextures[current].mipmaps[i] = 0; } } if (!context->w3dTextures[current].texData) { return; } } /* ** Find the starting address for the given mipmap level in the ** texture memory area */ if (level == 0) { target = context->w3dTextures[current].texData; } else { target = context->w3dTextures[current].mipmaps[level-1]; } // dprintf("Mipmap %ld at %p\n", level, target); /* ** Convert the data to the target address */ if (pixels) { useFormat = MGLConvert(context, internalformat, width, height, format, type, (GLubyte *)pixels, (GLubyte *)target); } else { useFormat = i2w3d[internal].w3dFormat; } /* ** Create a new W3D_Texture if none was present, using the converted ** data. ** Otherwise, call W3D_UpdateTexImage */ if (context->w3dTextures[current].texObj == NULL) { context->w3dTextures[current].texObj = IWarp3D->W3D_AllocTexObjTags(context->w3dContext, &error, W3D_ATO_IMAGE, context->w3dTextures[current].texData, W3D_ATO_FORMAT, useFormat, W3D_ATO_WIDTH, w, W3D_ATO_HEIGHT, h, W3D_ATO_MIPMAP, 0, W3D_ATO_MIPMAPPTRS, context->w3dTextures[current].mipmaps, TAG_DONE ); if (context->w3dTextures[current].texObj == NULL || error != W3D_SUCCESS) { dprintf("Failed to create texture object, error %d\n", error); return; } // dprintf("Allocated new texture object %p (%ldx%ld)\n", context->w3dTextures[current].texObj, w, h); RebindTextures(context); /* ** Set the appropriate wrap modes, texture env, and filters */ tex_SetWrap(context, context->texture.WrapS, context->texture.WrapT); tex_SetFilter(context, context->texture.MinFilter, context->texture.MagFilter, context->texture.MaxAnisotropy); tex_SetEnv(context, context->texture.TextureEnv[context->texture.ActiveTexture]); } else { UpdateTexImage(context, current, target, level, NULL); } } void GLTexImage2DNoMIP( GLcontext context, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) { int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; uint32 w,h; uint32 targetsize; uint32 error; uint8 *target; uint32 useFormat; int32 internal = SelectInternalFormat(context, internalformat); int32 unpacker = SelectUnpacker(context, format, type); //LOG(3, glTexImage2DNoMIP, "target = %d level=%d, size=%d�%d", gltarget, level, width, height); GLFlagError(context, internal == -1 || unpacker == -1, GL_INVALID_OPERATION); GLFlagError(context, gltarget != GL_TEXTURE_2D, GL_INVALID_ENUM); if (level != 0) { return; } w = (uint32)width; h = (uint32)height; if (context->w3dTextures[current].texObj && (w != context->w3dTextures[current].texObj->texwidth || h != context->w3dTextures[current].texObj->texheight) ) { dprintf( "texture size change detected (%ldx%ld -> %ldx%ld)\n", w, h, context->w3dTextures[current].texObj->texwidth, context->w3dTextures[current].texObj->texheight ); IWarp3D->W3D_FreeTexObj(context->w3dContext, context->w3dTextures[current].texObj); context->w3dTextures[current].texObj = NULL; } if (context->w3dTextures[current].texObj == NULL) { /* ** Create a new texture object ** Get the memory */ #ifdef MGL_TEXTURE_COMPRESSION targetsize = (ROUND_UP(w, 16) * ROUND_UP(h, 16) * i2w3d[internal].w3dBpp); #else targetsize = (w * h * i2w3d[internal].w3dBpp); #endif if (context->w3dTextures[current].texData) { tex_Free(context->w3dTextures[current].texData); } context->w3dTextures[current].texData = (GLubyte *)tex_Alloc(targetsize, (pixels ? FALSE : TRUE)); if (!context->w3dTextures[current].texData) { return; } context->w3dTextures[current].internalFormat = internalformat; } target = context->w3dTextures[current].texData; /* ** Convert the data to the target address */ if (pixels) { useFormat = MGLConvert(context, internalformat, width, height, format, type, (GLubyte *)pixels, (GLubyte *)target); } else { useFormat = i2w3d[internal].w3dFormat; } /* ** Create a new W3D_Texture if none was present, using the converted ** data. ** Otherwise, call W3D_UpdateTexImage */ if (context->w3dTextures[current].texObj == NULL) { int i; W3D_Texture *tex; tex = IWarp3D->W3D_AllocTexObjTags(context->w3dContext, &error, W3D_ATO_IMAGE, context->w3dTextures[current].texData, W3D_ATO_FORMAT, useFormat, W3D_ATO_WIDTH, w, W3D_ATO_HEIGHT, h, TAG_DONE ); if (tex == NULL || error != W3D_SUCCESS) { dprintf("Failed to create texture object, error %d\n", error); return; } context->w3dTextures[current].texObj = tex; context->w3dTextures[current].mipmaps[0] = target; for (i = 1; i < 20; i++) { context->w3dTextures[current].mipmaps[i] = 0; } /* ** Set the appropriate wrap modes, texture env, and filters */ RebindTextures(context); tex_SetWrap(context, context->texture.WrapS, context->texture.WrapT); tex_SetFilter(context, context->texture.MinFilter, context->texture.MagFilter, context->texture.MaxAnisotropy); tex_SetEnv(context, context->texture.TextureEnv[context->texture.ActiveTexture]); } else { UpdateTexImage(context, current, target, level, NULL); } } void cgl_GLTexImage1D( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) { // Faking 1D textures using 2D textures // WARNING: This assumes that Warp3D doesn't support texture borders. If this changes, then so must this // function cgl_GLTexImage2D(Self, GL_TEXTURE_2D, level, internalformat, width, 1, border, format, type, pixels); // The vertical direction should always be repeated cgl_GLTexParameteri(Self, gltarget, GL_TEXTURE_WRAP_T, GL_REPEAT); } void GLTexSubImage2DNoMIP( GLcontext context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); #define max(x,y) (x) > (y) ? (x) : (y) void cgl_GLTexSubImage2D( struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexSubImage2D(Self, target, level, xoffset, yoffset, width, height, format, type, pixels)) int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; GLubyte *dest; if (context->NoMipMapping == GL_TRUE) { GLTexSubImage2DNoMIP(context, target, level, xoffset, yoffset, width, height, format, type, pixels); return; } GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM); GLFlagError( context, context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].texObj == NULL, GL_INVALID_OPERATION ); if (level == 0) { dest = context->w3dTextures[current].texData; } else { dest = context->w3dTextures[current].mipmaps[level-1]; } GLFlagError(context, dest == NULL, GL_INVALID_OPERATION); BOOL success = MGLUpdate( context, context->w3dTextures[current].internalFormat, xoffset, yoffset, width, height, (GLubyte *)pixels, dest, max(1, context->w3dTextures[current].texObj->texwidth >> level), format, type ); GLFlagError(context, !success, GL_INVALID_ENUM); UpdateTexImage(context, current, context->w3dTextures[current].texData, 0, NULL); } void GLTexSubImage2DNoMIP( GLcontext context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; GLubyte *dest; GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM); GLFlagError( context, context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].texObj == NULL, GL_INVALID_OPERATION ); GLFlagError(context, level != 0, GL_INVALID_OPERATION); dest = context->w3dTextures[current].texData; BOOL success = MGLUpdate( context, context->w3dTextures[current].internalFormat, xoffset, yoffset, width, height, pixels, dest, context->w3dTextures[current].texObj->texwidth, format, type ); GLFlagError(context, !success, GL_INVALID_ENUM); UpdateTexImage(context, current, context->w3dTextures[current].texData, 0, NULL); } void cgl_GLTexSubImage1D(struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) { // Faking 1D textures using 2D textures cgl_GLTexSubImage2D(Self, GL_TEXTURE_2D, level, xoffset, 0, width,1, format, type, pixels); // The vertical direction should always be repeated cgl_GLTexParameteri(Self, target, GL_TEXTURE_WRAP_T, GL_REPEAT); } static RGBFTYPE getP96Format(GLenum internalFormat); // returns bytes per row, or 0 if failed static int p96CopyBMToTex( GLcontext context, GLint srcXOffset, GLint srcYOffset, GLint destXOffset, GLint destYOffset, GLsizei width, GLsizei height, struct BitMap *source, GLubyte *dest, GLsizei destWidth, RGBFTYPE destFormat ); void GLCopyTexImage2DNoMIP( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); void cgl_GLCopyTexImage2D( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) { GLcontext context = GET_INSTANCE(Self); // Pretend to support GL_RGBA16 if (internalFormat == GL_RGBA16) { internalFormat = GL_RGBA8; } DL_CHECK(CopyTexImage2D(Self, gltarget, level, internalFormat, x, y, width, height, border)) GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_PROXY_TEXTURE_2D, GL_INVALID_ENUM); // Prepare for the copy GLFlagError(context, width < 0, GL_INVALID_VALUE); GLFlagError(context, height < 0, GL_INVALID_VALUE); struct BitMap *inputBitMap = context->readBuffer->bitMap; if (!inputBitMap) { return; } if (context->NoMipMapping == GL_TRUE) { GLCopyTexImage2DNoMIP(Self, gltarget, level, internalFormat, x, y, width, height, border); return; } GLsizei rw = next_pwr(width); GLsizei rh = next_pwr(height); uint32 maxTextureSize = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_MAXTEXWIDTH, 0); uint32 texWidthReal = min(maxTextureSize, rw); uint32 texHeightReal = min(maxTextureSize, rh); uint32 ibmWidth = IGraphics->GetBitMapAttr(inputBitMap, BMA_WIDTH); uint32 ibmHeight = IGraphics->GetBitMapAttr(inputBitMap, BMA_HEIGHT); if (x + width > ibmWidth) { width = ibmWidth - x; } if (y + height > ibmHeight) { height = ibmHeight - y; } if (width > texWidthReal) { width = texWidthReal; } if (height > texHeightReal) { height = texHeightReal; } int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; uint32 w,h; uint32 targetsize; uint32 error; uint8 *target; int32 internal = SelectInternalFormat(context, internalFormat); RGBFTYPE p96Format = getP96Format(internalFormat); uint32 useFormat = i2w3d[internal].w3dFormat; GLFlagError(context, internal == -1, GL_INVALID_OPERATION); /* ** We will use width and height only when the mipmap level ** is really 0. Otherwise, we need to upscale the values ** according to the level. ** ** Note this will most likely be difficult with non-square ** textures, as the first side to reach one will remain ** there. For example, consider the sequence ** 8x4, 4x2, 2x1, 1x1 ** 0 1 2 3 ** If the 1x1 mipmap is given, upscaling will yield 8x8, not 8x4 */ if (context->w3dTextures[current].texObj == NULL) { w = (uint32)texWidthReal<w3dTextures[current].texObj->texwidth; h = context->w3dTextures[current].texObj->texheight; if ( (!((texWidthReal|texHeightReal)&1) && (w != (texWidthReal<W3D_FreeTexObj(context->w3dContext, context->w3dTextures[current].texObj); context->w3dTextures[current].texObj = NULL; } w=(uint32)texWidthReal<w3dTextures[current].texObj == NULL) { int i; /* ** Create a new texture object ** Get the memory */ targetsize = MGLCalculateMipArray(w, h, i2w3d[internal].w3dBpp, context->w3dTextures[current].mipmaps); if (context->w3dTextures[current].texData) { tex_Free(context->w3dTextures[current].texData); } context->w3dTextures[current].texData = (GLubyte *)tex_Alloc(targetsize, FALSE); context->w3dTextures[current].internalFormat = internalFormat; /* Fixup mipmaps */ for (i = 0; i < 20; i++) { if (context->w3dTextures[current].mipmaps[i] != (GLubyte *)0xffffffff) { context->w3dTextures[current].mipmaps[i] = (GLubyte *)((uint32)context->w3dTextures[current].mipmaps[i] + (uint32)context->w3dTextures[current].texData); } else { context->w3dTextures[current].mipmaps[i] = 0; } } if (!context->w3dTextures[current].texData) { return; } } /* ** Find the starting address for the given mipmap level in the ** texture memory area */ if (level == 0) { target = context->w3dTextures[current].texData; } else { target = context->w3dTextures[current].mipmaps[level-1]; } // -------------------------------------------------------------------- // Currently graphics operations and Warp3D cannot be used simultaneously, this speeds it up by // forcing an immediate unlock smartlock_forceUnlock(context->smartLock); if (p96Format != RGBFB_NONE) { // The texture data can be copied directly into the texture's buffer using Picasso96 p96CopyBMToTex(context, x, y, 0, 0, width, height, inputBitMap, target, w, p96Format); /* FIXME: Add color scale/bias */ } #if 0 else { // Will need to do a pixel format conversion // ##### FIXME! ##### } #endif // ##### FIXME! ##### what about glPixelZoom? // -------------------------------------------------------------------- /* ** Create a new W3D_Texture if none was present, using the converted ** data. ** Otherwise, call W3D_UpdateTexImage */ if (context->w3dTextures[current].texObj == NULL) { context->w3dTextures[current].texObj = IWarp3D->W3D_AllocTexObjTags(context->w3dContext, &error, W3D_ATO_IMAGE, context->w3dTextures[current].texData, W3D_ATO_FORMAT, useFormat, W3D_ATO_WIDTH, w, W3D_ATO_HEIGHT, h, W3D_ATO_MIPMAP, 0, W3D_ATO_MIPMAPPTRS, context->w3dTextures[current].mipmaps, TAG_DONE ); if (context->w3dTextures[current].texObj == NULL || error != W3D_SUCCESS) { dprintf("Failed to create texture object, error %d\n", error); return; } // dprintf("Allocated new texture object %p (%ldx%ld)\n", context->w3dTextures[current].texObj, w, h); RebindTextures(context); /* ** Set the appropriate wrap modes, texture env, and filters */ tex_SetWrap(context, context->texture.WrapS, context->texture.WrapT); tex_SetFilter(context, context->texture.MinFilter, context->texture.MagFilter, context->texture.MaxAnisotropy); tex_SetEnv(context, context->texture.TextureEnv[context->texture.ActiveTexture]); } else { UpdateTexImage(context, current, target, level, NULL); } } void GLCopyTexImage2DNoMIP( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, gltarget != GL_TEXTURE_2D, GL_INVALID_ENUM); struct BitMap *inputBitMap = context->readBuffer->bitMap; if (!inputBitMap) { return; } int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; uint32 w,h; uint32 targetsize; uint32 error; uint8 *target; int32 internal = SelectInternalFormat(context, internalFormat); RGBFTYPE p96Format = getP96Format(internalFormat); uint32 useFormat = i2w3d[internal].w3dFormat; GLFlagError(context, internal == -1, GL_INVALID_OPERATION); GLsizei rw = next_pwr(width); GLsizei rh = next_pwr(height); uint32 maxTextureSize = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_MAXTEXWIDTH, 0); uint32 texWidthReal = min(maxTextureSize, rw); uint32 texHeightReal = min(maxTextureSize, rh); uint32 ibmWidth = IGraphics->GetBitMapAttr(inputBitMap, BMA_WIDTH); uint32 ibmHeight = IGraphics->GetBitMapAttr(inputBitMap, BMA_HEIGHT); if (x + width > ibmWidth) { width = ibmWidth - x; } if (y + height > ibmHeight) { height = ibmHeight - y; } if (width > texWidthReal) { width = texWidthReal; } if (height > texHeightReal) { height = texHeightReal; } if (level != 0) { return; } w = (uint32)texWidthReal; h = (uint32)texHeightReal; if (context->w3dTextures[current].texObj && (w != context->w3dTextures[current].texObj->texwidth || h != context->w3dTextures[current].texObj->texheight) ) { dprintf( "texture size change detected (%ldx%ld -> %ldx%ld)\n", w, h, context->w3dTextures[current].texObj->texwidth, context->w3dTextures[current].texObj->texheight ); IWarp3D->W3D_FreeTexObj(context->w3dContext, context->w3dTextures[current].texObj); context->w3dTextures[current].texObj = NULL; } if (context->w3dTextures[current].texObj == NULL) { /* ** Create a new texture object ** Get the memory */ #ifdef MGL_TEXTURE_COMPRESSION targetsize = (ROUND_UP(w, 16) * ROUND_UP(h, 16) * i2w3d[internal].w3dBpp); #else targetsize = (w * h * i2w3d[internal].w3dBpp); #endif if (context->w3dTextures[current].texData) { tex_Free(context->w3dTextures[current].texData); } context->w3dTextures[current].texData = (GLubyte *)tex_Alloc(targetsize, FALSE); if (!context->w3dTextures[current].texData) { return; } context->w3dTextures[current].internalFormat = internalFormat; } target = context->w3dTextures[current].texData; // -------------------------------------------------------------------- // Currently graphics operations and Warp3D cannot be used simultaneously, this speeds it up by // forcing an immediate unlock smartlock_forceUnlock(context->smartLock); if (p96Format != RGBFB_NONE) { // The texture data can be copied directly into the texture's buffer using Picasso96 p96CopyBMToTex(context, x, y, 0, 0, width, height, inputBitMap, target, w, p96Format); /* FIXME: Add color scale/bias */ } #if 0 else { // Will need to do a pixel format conversion // ##### FIXME! ##### } #endif // ##### FIXME! ##### what about glPixelZoom? // -------------------------------------------------------------------- /* ** Create a new W3D_Texture if none was present, using the converted ** data. ** Otherwise, call W3D_UpdateTexImage */ if (context->w3dTextures[current].texObj == NULL) { int i; W3D_Texture *tex; tex = IWarp3D->W3D_AllocTexObjTags(context->w3dContext, &error, W3D_ATO_IMAGE, context->w3dTextures[current].texData, W3D_ATO_FORMAT, useFormat, W3D_ATO_WIDTH, w, W3D_ATO_HEIGHT, h, TAG_DONE ); if (tex == NULL || error != W3D_SUCCESS) { dprintf("Failed to create texture object, error %d\n", error); return; } context->w3dTextures[current].texObj = tex; context->w3dTextures[current].mipmaps[0] = target; for (i = 1; i < 20; i++) { context->w3dTextures[current].mipmaps[i] = 0; } /* ** Set the appropriate wrap modes, texture env, and filters */ RebindTextures(context); tex_SetWrap(context, context->texture.WrapS, context->texture.WrapT); tex_SetFilter(context, context->texture.MinFilter, context->texture.MagFilter, context->texture.MaxAnisotropy); tex_SetEnv(context, context->texture.TextureEnv[context->texture.ActiveTexture] ); } else { UpdateTexImage(context, current, target, level, NULL); } } void cgl_GLCopyTexImage1D( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border ) { // Faking 1D textures using 2D textures // WARNING: This assumes that Warp3D doesn't support texture borders. If this changes, then so must this // function cgl_GLCopyTexImage2D(Self, GL_TEXTURE_2D, level, internalFormat, x, y, width, 1, border); // The vertical direction should always be repeated cgl_GLTexParameteri(Self, gltarget, GL_TEXTURE_WRAP_T, GL_REPEAT); } void GLCopyTexSubImage2DNoMIP( struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); void cgl_GLCopyTexSubImage2D( struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(CopyTexSubImage2D(Self, target, level, xoffset, yoffset, x, y, width, height)) int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; GLubyte *dest; GLenum internalFormat = context->w3dTextures[current].internalFormat; RGBFTYPE p96Format = getP96Format(internalFormat); if (context->NoMipMapping == GL_TRUE) { GLCopyTexSubImage2DNoMIP(Self, target, level, xoffset, yoffset, x, y, width, height); return; } struct BitMap *inputBitMap = context->readBuffer->bitMap; if (!inputBitMap) { return; } GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM); GLFlagError( context, context->w3dTextures[context->texture.CurrentBinding[context->texture.ActiveTexture]].texObj == NULL, GL_INVALID_OPERATION ); uint32 ibmWidth = IGraphics->GetBitMapAttr(inputBitMap, BMA_WIDTH); uint32 ibmHeight = IGraphics->GetBitMapAttr(inputBitMap, BMA_HEIGHT); if (x + width > ibmWidth) { width = ibmWidth - x; } if (y + height > ibmHeight) { height = ibmHeight - y; } GLint texWidth = max(1,context->w3dTextures[current].texObj->texwidth >> level); GLint texHeight = max(1,context->w3dTextures[current].texObj->texheight >> level); if (xoffset + width > texWidth) { width = texWidth - xoffset; } if (yoffset + height > texHeight) { height = texHeight - yoffset; } if (level == 0) { dest = context->w3dTextures[current].texData; } else { dest = context->w3dTextures[current].mipmaps[level-1]; } GLFlagError(context, dest == NULL, GL_INVALID_OPERATION); // ---------------------------------------------------------------------------------- int bytesPerRow; if (p96Format != RGBFB_NONE) { // The texture data can be copied directly into the texture's buffer using Picasso96 bytesPerRow = p96CopyBMToTex(context, x, y, xoffset, yoffset, width, height, inputBitMap, dest, texWidth, p96Format); } else { bytesPerRow = 0; // Will need to do a pixel format conversion // ##### FIXME! ##### } //MGLUpdate(context, xoffset, yoffset, width, height, (GLubyte *)pixels, dest, // max(1,context->w3dTextures[current].texObj->texwidth >> level), // internal, unpacker); // Now perform color scale and bias // ##### FIXME! ##### // ##### FIXME! ##### what about glPixelZoom? // ---------------------------------------------------------------------------------- if (bytesPerRow) { //UpdateTexImage(context, current, context->w3dTextures[current].texData, 0, NULL); UpdateTexSubImage( context, current, context->w3dTextures[current].texData, 0, NULL, xoffset, yoffset, width, height, bytesPerRow ); } } void GLCopyTexSubImage2DNoMIP( struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) { GLcontext context = GET_INSTANCE(Self); int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; GLubyte *dest; GLenum internalFormat = context->w3dTextures[current].internalFormat; RGBFTYPE p96Format = getP96Format(internalFormat); struct BitMap *inputBitMap = context->readBuffer->bitMap; if (!inputBitMap) { return; } GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM); GLFlagError(context, context->w3dTextures[current].texObj == NULL, GL_INVALID_OPERATION); uint32 ibmWidth = IGraphics->GetBitMapAttr(inputBitMap, BMA_WIDTH); uint32 ibmHeight = IGraphics->GetBitMapAttr(inputBitMap, BMA_HEIGHT); if (x + width > ibmWidth) { width = ibmWidth - x; } if (y + height > ibmHeight) { height = ibmHeight - y; } GLint texWidth = max(1,context->w3dTextures[current].texObj->texwidth >> level); GLint texHeight = max(1,context->w3dTextures[current].texObj->texheight >> level); if (xoffset + width > texWidth) { width = texWidth - xoffset; } if (yoffset + height > texHeight) { height = texHeight - yoffset; } dest = context->w3dTextures[current].texData; GLFlagError(context, level != 0, GL_INVALID_OPERATION); // -------------------------------------------------------------------- int bytesPerRow; if (p96Format != RGBFB_NONE) { // The texture data can be copied directly into the texture's buffer using Picasso96 bytesPerRow = p96CopyBMToTex(context, x, y, xoffset, yoffset, width, height, inputBitMap, dest, texWidth, p96Format); } else { bytesPerRow = 0; // Will need to do a pixel format conversion // ##### FIXME! ##### } // ##### FIXME! ##### //MGLUpdate(context, xoffset, yoffset, width, height, pixels, dest, // context->w3dTextures[current].texObj->texwidth, // internal, unpacker); // Now perform color scale and bias // ##### FIXME! ##### // ##### FIXME! ##### what about glPixelZoom? // -------------------------------------------------------------------- if (bytesPerRow) { //UpdateTexImage(context, current, context->w3dTextures[current].texData, 0, NULL); UpdateTexSubImage( context, current, context->w3dTextures[current].texData, 0, NULL, xoffset, yoffset, width, height, bytesPerRow ); } } void cgl_GLCopyTexSubImage1D( struct GLContextIFace *Self, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { // Faking 1D textures using 2D textures cgl_GLCopyTexSubImage2D(Self, GL_TEXTURE_2D, level, xoffset, 0, x, y, width, 1); // The vertical direction should always be repeated cgl_GLTexParameteri(Self, target, GL_TEXTURE_WRAP_T, GL_REPEAT); } static RGBFTYPE getP96Format(GLenum internalFormat) { switch(internalFormat) { case GL_RGB: case GL_RGB8: case 3: return RGBFB_R8G8B8; case GL_BGR: // case GL_BGR8: return RGBFB_R8G8B8; case GL_RGBA: case 4: case GL_RGBA8: return RGBFB_A8R8G8B8; case GL_RGB5: return RGBFB_R5G6B5PC; case GL_RGB5_A1: return RGBFB_R5G5B5PC; // None of the following have Picasso96 equivalents case GL_RGB4: case GL_RGBA4: case GL_ALPHA: case GL_LUMINANCE: case 1: case GL_LUMINANCE_ALPHA: case 2: case GL_INTENSITY: default: return RGBFB_NONE; } } static int p96CopyBMToTex( GLcontext context, GLint srcXOffset, GLint srcYOffset, GLint destXOffset, GLint destYOffset, GLsizei width, GLsizei height, struct BitMap *source, GLubyte *dest, GLsizei destWidth, RGBFTYPE destFormat ) { struct RenderInfo rInfo; int bytesPerPixel; switch (destFormat) { case RGBFB_R8G8B8: case RGBFB_B8G8R8: bytesPerPixel = 3; break; case RGBFB_A8R8G8B8: case RGBFB_A8B8G8R8: case RGBFB_R8G8B8A8: case RGBFB_B8G8R8A8: bytesPerPixel = 4; break; case RGBFB_R5G6B5: case RGBFB_R5G5B5: case RGBFB_B5G6R5PC: case RGBFB_B5G5R5PC: case RGBFB_R5G6B5PC: case RGBFB_R5G5B5PC: bytesPerPixel = 2; break; case RGBFB_CLUT: bytesPerPixel = 1; break; default: return 0; } // Need to invert the y-axis coordinates uint32 ibmHeight = IGraphics->GetBitMapAttr(source, BMA_HEIGHT); srcYOffset = ibmHeight - srcYOffset - height - 1; rInfo.Memory = dest + (height + destYOffset - 1) * destWidth * bytesPerPixel; rInfo.BytesPerRow = -destWidth * bytesPerPixel; // OpenGL starts at the bottom left, not the top left rInfo.RGBFormat = destFormat; struct RastPort rPort; IGraphics->InitRastPort(&rPort); rPort.BitMap = source; #if defined (__amigaos4__) PIX_FMT pix_fmt=(PIX_FMT)((destFormat-RGBFB_CLUT)+PIXF_CLUT); IGraphics->ReadPixelArray(&rPort,srcXOffset,srcYOffset,rInfo.Memory,destXOffset,0,rInfo.BytesPerRow,pix_fmt,width,height); #else IP96->p96ReadPixelArray(&rInfo, destXOffset, 0, &rPort, srcXOffset, srcYOffset, width, height); #endif return -rInfo.BytesPerRow; } void cgl_GLColorTable( struct GLContextIFace *Self, GLenum target, GLenum internalformat, GLint width, GLenum format, GLenum type, const GLvoid* data ) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(ColorTable(Self, target, internalformat, width, format, type, data)) int i; GLubyte *palette; GLubyte *where; GLubyte a,r,g,b; GLFlagError(context, width>256, GL_INVALID_VALUE); GLFlagError(context, target!=GL_COLOR_TABLE, GL_INVALID_OPERATION); palette = (GLubyte *)data; where = (GLubyte *)context->PaletteData; GLFlagError(context, where == NULL, GL_INVALID_OPERATION); switch (internalformat) { case 4: case GL_RGBA: // convert to argb from... switch(format) { case GL_RGB: // ...RGB, ignoring alpha for (i=0; iPaletteFormat = format; context->PaletteSize = width; } void cgl_GLActiveTexture(struct GLContextIFace *Self, GLenum unit) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(ActiveTexture(Self, unit)) unit -= GL_TEXTURE0; GLFlagError(context, unit >= context->NumTextureUnits, GL_INVALID_VALUE); context->texture.ActiveTexture = unit; } GLboolean cgl_GLAreTexturesResident(struct GLContextIFace* Self, GLsizei n, GLuint* textures, GLboolean* residences) { int t = 0; GLboolean all_resident = GL_TRUE; GLcontext context = GET_INSTANCE(Self); // Cannot be called between glBegin and glEnd GLFlagError2(context, context->CurrentPrimitive != GL_BASE, GL_INVALID_OPERATION, GL_FALSE); for (t = 0; t < n; ++t) { GLuint texture = textures[t]; // Texture object 0 cannot be used GLFlagError2(context, texture == 0, GL_INVALID_VALUE, GL_FALSE); // Cant have more textures than TexBuffserSize GLFlagError2(context, texture >= context->TexBufferSize, GL_INVALID_VALUE, GL_FALSE); // Has the texture been generated? GLFlagError2(context, context->GeneratedTextures[texture] == 0, GL_INVALID_VALUE, GL_FALSE); // Is the texture used? GLFlagError2(context, context->w3dTextures[texture].texObj == NULL, GL_INVALID_VALUE, GL_FALSE); } for (t = 0; t < n; ++t) { all_resident &= (GLboolean)context->w3dTextures[textures[t]].texObj->resident; } if (all_resident == GL_FALSE) { for (t = 0; t < n; ++t) { residences[t] = (GLboolean)context->w3dTextures[textures[t]].texObj->resident; } return GL_FALSE; } return GL_TRUE; } void tex_EstablishEnvCombine(GLcontext context) { int i,j; uint32 colorarg[3]; uint32 alphaarg[3]; uint32 colorcombine = W3D_COMBINE_DISABLED, alphacombine = W3D_COMBINE_DISABLED; for (i=0; iNumTextureUnits; i++) { if (context->enable.Texture2D[i] == GL_FALSE && context->enable.Texture1D[i] == GL_FALSE) { IWarp3D->W3D_SetTextureBlendTags(context->w3dContext, W3D_BLEND_STAGE, i, W3D_COLOR_COMBINE, W3D_COMBINE_DISABLED, W3D_ALPHA_COMBINE, W3D_COMBINE_DISABLED, TAG_DONE); IWarp3D->W3D_SetTextureBlend(context->w3dContext, NULL); continue; } if (context->texture.TextureEnv[i] != GL_COMBINE) { continue; } if (context->combineDirty[i] == GL_FALSE) { continue; } switch(context->texture.colorCombine[i]) { case GL_REPLACE: colorcombine = W3D_COMBINE_SELECT_A; break; case GL_MODULATE: colorcombine = W3D_COMBINE_MODULATE; break; case GL_ADD: colorcombine = W3D_COMBINE_ADD; break; case GL_ADD_SIGNED: colorcombine = W3D_COMBINE_ADDSIGNED; break; case GL_SUBTRACT: colorcombine = W3D_COMBINE_SUBTRACT; break; case GL_INTERPOLATE: colorcombine = W3D_COMBINE_INTERPOLATE; break; case GL_DOT3_RGB: colorcombine = W3D_COMBINE_DOT3RGB; break; case GL_DOT3_RGBA: colorcombine = W3D_COMBINE_DOT3RGB; break; } switch(context->texture.alphaCombine[i]) { case GL_REPLACE: alphacombine = W3D_COMBINE_SELECT_A; break; case GL_MODULATE: alphacombine = W3D_COMBINE_MODULATE; break; case GL_ADD: alphacombine = W3D_COMBINE_ADD; break; case GL_ADD_SIGNED: alphacombine = W3D_COMBINE_ADDSIGNED; break; case GL_INTERPOLATE: alphacombine = W3D_COMBINE_INTERPOLATE; break; case GL_SUBTRACT: alphacombine = W3D_COMBINE_SUBTRACT; break; } for (j=0; j<3; j++) { switch(context->texture.colorSource[j][i]) { case GL_TEXTURE: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE0: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE0_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE0_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE0_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE0_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE1: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE1_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE1_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE1_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE1_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE2: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE2_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE2_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE2_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE2_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE3: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE3_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_TEXTURE3_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE3_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_TEXTURE3_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_CONSTANT: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_FACTOR_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_FACTOR_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_FACTOR_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_FACTOR_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_PRIMARY_COLOR: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_DIFFUSE_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_DIFFUSE_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_DIFFUSE_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_DIFFUSE_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_PREVIOUS: switch(context->texture.colorOperand[j][i]) { case GL_SRC_COLOR: colorarg[j] = W3D_ARG_PREVIOUS_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: colorarg[j] = W3D_ARG_PREVIOUS_COLOR | W3D_ARG_COMPLEMENT; break; case GL_SRC_ALPHA: colorarg[j] = W3D_ARG_PREVIOUS_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: colorarg[j] = W3D_ARG_PREVIOUS_ALPHA | W3D_ARG_COMPLEMENT; break; } break; } // switch color arg switch(context->texture.alphaSource[j][i]) { case GL_TEXTURE: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE0: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE0_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE0_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE1: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE1_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE1_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE2: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE2_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE2_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_TEXTURE3: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE3_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_TEXTURE3_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_CONSTANT: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_FACTOR_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_FACTOR_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_PRIMARY_COLOR: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_DIFFUSE_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_DIFFUSE_ALPHA | W3D_ARG_COMPLEMENT; break; } break; case GL_PREVIOUS: switch(context->texture.alphaOperand[j][i]) { case GL_SRC_ALPHA: alphaarg[j] = W3D_ARG_PREVIOUS_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: alphaarg[j] = W3D_ARG_PREVIOUS_ALPHA | W3D_ARG_COMPLEMENT; break; } break; } // Switch alpha arg } // for j IWarp3D->W3D_SetTextureBlendTags(context->w3dContext, W3D_BLEND_STAGE, i, W3D_COLOR_COMBINE, colorcombine, W3D_COLOR_ARG_A, colorarg[0], W3D_COLOR_ARG_B, colorarg[1], W3D_COLOR_ARG_C, colorarg[2], W3D_ALPHA_COMBINE, alphacombine, W3D_ALPHA_ARG_A, alphaarg[0], W3D_ALPHA_ARG_B, alphaarg[1], W3D_ALPHA_ARG_C, alphaarg[2], W3D_COLOR_SCALE, context->texture.colorScale[i], W3D_ALPHA_SCALE, context->texture.alphaScale[i], W3D_BLEND_FACTOR, context->texture.envColor[i], TAG_DONE); } // for texture unit IWarp3D->W3D_SetTextureBlend(context->w3dContext, NULL); } void cgl_GLTexGenfv(struct GLContextIFace *Self, GLenum coord, GLenum pname, GLfloat *params) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexGenfv(Self, coord, pname, params)) uint32 current = context->texture.ActiveTexture; GLtexgen *texgen = 0; if (coord == GL_S) { texgen = & context->texture.TexGenS[current]; } else if (coord == GL_T) { texgen = & context->texture.TexGenT[current]; } else if (coord == GL_Q) { texgen = & context->texture.TexGenQ[current]; } else if (coord == GL_R) { return; } GLFlagError(context, texgen == 0, GL_INVALID_ENUM); switch (pname) { case GL_EYE_PLANE: if (context->InverseModelViewValid != GL_TRUE) { m_BuildInvertedFull(context); } #define a(x) (context->InverseModelView.v[OF_##x]) texgen->eyePlane[0] = a(11)*params[0] + a(21)*params[1] + a(31)*params[2] + a(41)*params[3]; texgen->eyePlane[1] = a(12)*params[0] + a(22)*params[1] + a(32)*params[2] + a(42)*params[3]; texgen->eyePlane[2] = a(13)*params[0] + a(23)*params[1] + a(33)*params[2] + a(43)*params[3]; texgen->eyePlane[3] = a(14)*params[0] + a(24)*params[1] + a(34)*params[2] + a(44)*params[3]; #undef a break; case GL_OBJECT_PLANE: texgen->objectPlane[0] = params[0]; texgen->objectPlane[1] = params[1]; texgen->objectPlane[2] = params[2]; texgen->objectPlane[3] = params[3]; break; default: Self->GLTexGeni(coord, pname, (GLint)params[0]); break; } } void cgl_GLTexGeni(struct GLContextIFace *Self, GLenum coord, GLenum pname, GLint param) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(TexGeni(Self, coord, pname, param)) uint32 current = context->texture.ActiveTexture; GLtexgen *texgen = 0; if (coord == GL_S) { texgen = & context->texture.TexGenS[current]; } else if (coord == GL_T) { texgen = & context->texture.TexGenT[current]; } else if (coord == GL_Q) { texgen = & context->texture.TexGenQ[current]; } else if (coord == GL_R) { return; } GLFlagError(context, texgen == 0, GL_INVALID_ENUM); switch (pname) { case GL_TEXTURE_GEN_MODE: GLFlagError(context, param != GL_OBJECT_LINEAR && param != GL_EYE_LINEAR && param != GL_SPHERE_MAP && param != GL_REFLECTION_MAP && param != GL_NORMAL_MAP, GL_INVALID_ENUM); GLFlagError(context, (param == GL_SPHERE_MAP || param == GL_REFLECTION_MAP || param == GL_NORMAL_MAP) && coord == GL_Q, GL_INVALID_ENUM); texgen->mode = param; if (param == GL_SPHERE_MAP) { texgen->needR = GL_TRUE; texgen->needM = GL_TRUE; } else if (param == GL_REFLECTION_MAP) { texgen->needR = GL_TRUE; texgen->needM = GL_FALSE; } else { texgen->needR = GL_FALSE; texgen->needM = GL_FALSE; } break; default: GLFlagError(context, 1, GL_INVALID_ENUM); break; } } GLboolean cgl_GLIsTexture(struct GLContextIFace *Self, GLuint texture){ GLcontext context = GET_INSTANCE(Self); if (texture > context->TexBufferSize) { return GL_FALSE; } if (context->GeneratedTextures[texture] != 0) { return GL_TRUE; } else { return GL_FALSE; } } void cgl_GLGetTexLevelParameterfv(struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum pname, GLfloat *param) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_PROXY_TEXTURE_2D && gltarget != GL_TEXTURE_1D && gltarget != GL_PROXY_TEXTURE_1D, GL_INVALID_ENUM); int current; MGLTexture *curTex; if (gltarget == GL_TEXTURE_2D || gltarget == GL_TEXTURE_1D) { current = context->texture.CurrentBinding[context->texture.ActiveTexture]; curTex = &context->w3dTextures[current]; switch (pname) { case GL_TEXTURE_WIDTH: if (!curTex->texObj) { param[0] = 0; } else { uint32 width = curTex->texObj->texwidth >> level; param[0] = width > 0 ? width : 1; } break; case GL_TEXTURE_HEIGHT: if (!curTex->texObj) { param[0] = 0; } else { uint32 height = curTex->texObj->texheight >> level; param[0] = height > 0 ? height : 1; } break; case GL_TEXTURE_DEPTH: param[0] = 0; break; case GL_TEXTURE_INTERNAL_FORMAT: param[0] = curTex->internalFormat; break; case GL_TEXTURE_BORDER: param[0] = 0; break; case GL_TEXTURE_RED_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].redsize; } else { param[0] = 0; } break; case GL_TEXTURE_GREEN_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].greensize; } else { param[0] = 0; } break; case GL_TEXTURE_BLUE_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].bluesize; } else { param[0] = 0; } break; case GL_TEXTURE_ALPHA_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].alphasize; } else { param[0] = 0; } break; case GL_TEXTURE_LUMINANCE_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].luminancesize; } else { param[0] = 0; } break; case GL_TEXTURE_INTENSITY_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].intensitysize; } else { param[0] = 0; } break; #ifdef MGL_TEXTURE_COMPRESSION case GL_TEXTURE_COMPRESSED_ARB: if (i2w3d[curTex->internalFormat].w3dFormat >= W3D_COMPRESSED_R5G6B5 && i2w3d[curTex->internalFormat].w3dFormat <= W3D_COMPRESSED_A8R5G6B5) { param[0] = GL_TRUE; } else { param[0] = GL_FALSE; } break; /* case GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB: if (i2w3d[curTex->internalFormat].w3dFormat >= W3D_COMPRESSED_R5G6B5 && i2w3d[curTex->internalFormat].w3dFormat <= W3D_COMPRESSED_A8R5G6B5) { param[0] = CompressedTextureSize(i2w3d[curTex->internalFormat].internalformat, curTex->texObj->texwidth >> level, curTex->texObj->texwidth >> level); } else { param[0] = 0; } break; */ #endif default: context->CurrentError = GL_INVALID_ENUM; break; } } if (gltarget == GL_PROXY_TEXTURE_2D || gltarget == GL_PROXY_TEXTURE_1D) { switch (pname) { case GL_TEXTURE_WIDTH: param[0] = (GLfloat)context->proxy_width; break; case GL_TEXTURE_HEIGHT: param[0] = (GLfloat)context->proxy_height; break; case GL_TEXTURE_DEPTH: param[0] = 0.0; break; case GL_TEXTURE_INTERNAL_FORMAT: param[0] = (GLfloat)context->proxy_internalFormat; break; case GL_TEXTURE_BORDER: param[0] = 0.0; break; case GL_TEXTURE_RED_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].redsize; } else { param[0] = 0.0; } break; case GL_TEXTURE_GREEN_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].greensize; } else { param[0] = 0.0; } break; case GL_TEXTURE_BLUE_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].bluesize; } else { param[0] = 0.0; } break; case GL_TEXTURE_ALPHA_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].alphasize; } else { param[0] = 0.0; } break; case GL_TEXTURE_LUMINANCE_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].luminancesize; } else { param[0] = 0.0; } break; case GL_TEXTURE_INTENSITY_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = (GLfloat)i2w3d[context->proxy_internalFormat].intensitysize; } else { param[0] = 0.0; } break; default: context->CurrentError = GL_INVALID_ENUM; break; } } } void cgl_GLGetTexLevelParameteriv( struct GLContextIFace *Self, GLenum gltarget, GLint level, GLenum pname, GLint *param ) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_PROXY_TEXTURE_2D && gltarget != GL_TEXTURE_2D && gltarget != GL_PROXY_TEXTURE_2D, GL_INVALID_ENUM); int current; MGLTexture *curTex; if (gltarget == GL_TEXTURE_2D || gltarget == GL_TEXTURE_1D) { current = context->texture.CurrentBinding[context->texture.ActiveTexture]; curTex = &context->w3dTextures[current]; switch (pname) { case GL_TEXTURE_WIDTH: if (!curTex->texObj) { param[0] = 0; } else { uint32 width = curTex->texObj->texwidth >> level; param[0] = width > 0 ? width : 1; } break; case GL_TEXTURE_HEIGHT: if (!curTex->texObj) { param[0] = 0; } else { uint32 height = curTex->texObj->texheight >> level; param[0] = height > 0 ? height : 1; } break; case GL_TEXTURE_DEPTH: param[0] = 0; break; case GL_TEXTURE_INTERNAL_FORMAT: param[0] = curTex->internalFormat; break; case GL_TEXTURE_BORDER: param[0] = 0; break; case GL_TEXTURE_RED_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].redsize; } else { param[0] = 0; } break; case GL_TEXTURE_GREEN_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].greensize; } else { param[0] = 0; } break; case GL_TEXTURE_BLUE_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].bluesize; } else { param[0] = 0; } break; case GL_TEXTURE_ALPHA_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].alphasize; } else { param[0] = 0; } break; case GL_TEXTURE_LUMINANCE_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].luminancesize; } else { param[0] = 0; } break; case GL_TEXTURE_INTENSITY_SIZE: if (curTex->internalFormat >= 0) { param[0] = i2w3d[curTex->internalFormat].intensitysize; } else { param[0] = 0; } break; default: context->CurrentError = GL_INVALID_ENUM; break; } } if (gltarget == GL_PROXY_TEXTURE_2D || gltarget == GL_PROXY_TEXTURE_1D) { switch (pname) { case GL_TEXTURE_WIDTH: param[0] = context->proxy_width; break; case GL_TEXTURE_HEIGHT: param[0] = context->proxy_height; break; case GL_TEXTURE_DEPTH: param[0] = 0; break; case GL_TEXTURE_INTERNAL_FORMAT: param[0] = context->proxy_internalFormat; break; case GL_TEXTURE_BORDER: param[0] = 0; break; case GL_TEXTURE_RED_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].redsize; } else { param[0] = 0; } break; case GL_TEXTURE_GREEN_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].greensize; } else { param[0] = 0; } break; case GL_TEXTURE_BLUE_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].bluesize; } else { param[0] = 0; } break; case GL_TEXTURE_ALPHA_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].alphasize; } else { param[0] = 0; } break; case GL_TEXTURE_LUMINANCE_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].luminancesize; } else { param[0] = 0; } break; case GL_TEXTURE_INTENSITY_SIZE: if (context->proxy_internalFormat >= 0) { param[0] = i2w3d[context->proxy_internalFormat].intensitysize; } else { param[0] = 0; } break; default: context->CurrentError = GL_INVALID_ENUM; break; } } } void cgl_GLGetTexParameterfv(struct GLContextIFace *Self, GLenum gltarget, GLenum pname, GLfloat *param) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_TEXTURE_1D, GL_INVALID_ENUM); int current; MGLTexture *curTex; #define FROM_BOOL(x) (GLfloat)((x) ? 1.0f : 0.0f) #define FROM_COLOR(x) (GLfloat)(x) #define FROM_FLOAT(x) (x) #define FROM_INT(x) (GLfloat)(x) current = context->texture.CurrentBinding[context->texture.ActiveTexture]; curTex = &context->w3dTextures[current]; switch (pname) { case GL_TEXTURE_RESIDENT: if (!curTex->texObj) { param[0] = 0.0; } else { param[0] = FROM_BOOL(curTex->texObj->resident); } break; case GL_TEXTURE_WRAP_S: param[0] = FROM_INT(curTex->WrapS); break; case GL_TEXTURE_WRAP_T: param[0] = FROM_INT(curTex->WrapT); break; case GL_TEXTURE_WRAP_R: param[0] = 0.0; break; case GL_TEXTURE_MIN_FILTER: param[0] = FROM_INT(curTex->MinFilter); break; case GL_TEXTURE_MAG_FILTER: param[0] = FROM_INT(curTex->MagFilter); break; } #undef FROM_BOOL #undef FROM_COLOR #undef FROM_FLOAT #undef FROM_INT } void cgl_GLGetTexParameteriv(struct GLContextIFace *Self, GLenum gltarget, GLenum pname, GLint *param) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, gltarget != GL_TEXTURE_2D && gltarget != GL_TEXTURE_1D, GL_INVALID_ENUM); int current; MGLTexture *curTex; #define FROM_BOOL(x) (GLint)((x) ? 1 : 0) #define FROM_COLOR(x) (GLint)((0xffffffff * (x) - 1)/2) #define FROM_FLOAT(x) (GLint)(x) #define FROM_INT(x) (x) current = context->texture.CurrentBinding[context->texture.ActiveTexture]; curTex = &context->w3dTextures[current]; switch (pname) { case GL_TEXTURE_RESIDENT: if (!curTex->texObj) { param[0] = 0.0; } else { param[0] = FROM_BOOL(curTex->texObj->resident); } break; case GL_TEXTURE_WRAP_S: param[0] = FROM_INT(curTex->WrapS); break; case GL_TEXTURE_WRAP_T: param[0] = FROM_INT(curTex->WrapT); break; case GL_TEXTURE_WRAP_R: param[0] = 0.0; break; case GL_TEXTURE_MIN_FILTER: param[0] = FROM_INT(curTex->MinFilter); break; case GL_TEXTURE_MAG_FILTER: param[0] = FROM_INT(curTex->MagFilter); break; } #undef FROM_BOOL #undef FROM_COLOR #undef FROM_FLOAT #undef FROM_INT } void cgl_GLGetTexImage( struct GLContextIFace *Self, GLenum target, GLint lod, GLenum format, GLenum type, GLvoid *pixels ) { GLcontext context = GET_INSTANCE(Self); GLFlagError(context, target != GL_TEXTURE_2D && target != GL_TEXTURE_1D, GL_INVALID_ENUM); if (pixels == 0) { return; } if (context->NoMipMapping == GL_TRUE && lod != 0) { context->CurrentError = GL_INVALID_ENUM; return; } GLimage_info src; GLimage_info dst; int current = context->texture.CurrentBinding[context->texture.ActiveTexture]; /* Find and setup the source image */ if (context->w3dTextures[current].texObj == NULL) { context->CurrentError = GL_INVALID_ENUM; return; } /* Peek the size. We didn't record it anywhere, so we peek it from the * texture object :S */ GLsizei width = (context->w3dTextures[current].texObj->texwidth); GLsizei height = (context->w3dTextures[current].texObj->texheight); if (width == 0) { width = 1; } if (height == 0) { height = 1; } struct W3DtoGL *formatInfo = MGLGetFormatInfo(context->w3dTextures[current].texObj->texfmtsrc); if (!formatInfo) { context->CurrentError = GL_INVALID_ENUM; return; } if (lod == 0) { src.data = context->w3dTextures[current].texData; } else { src.data = context->w3dTextures[current].mipmaps[lod-1]; } src.stride = formatInfo->w3dBpp * width; src.format = formatInfo->glformat; src.type = formatInfo->gltype; src.pixel_stride = formatInfo->w3dBpp; /* Setup destination. Select a packer to get the pixel stride */ dst.data = pixels; MGLSelectPacker(format, type, &dst.pixel_stride); dst.format = format; dst.type = type; dst.stride = width * dst.pixel_stride; MGLPackImage(context, width, height, &src, &dst, GL_FALSE); }