/* * $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 "sysinc.h" #include #include #include #include #include "util.h" #include "../minigl.library_rev.h" int snprintf(char *, size_t, const char *, ...); extern int32 mapMGLBlendSourceToW3D(int32 mglSrc, int32 defSrc); extern int32 mapMGLBlendDestToW3D(int32 mglDst, int32 defDst); extern int32 mapMGLATestToW3D(int32 mglA, int32 defA); extern int32 mapMGLLogicOpToW3D(int32 mglL, int32 defL); static char rcsid[] UNUSED = "$Id$"; void cgl_GLLineWidth(struct GLContextIFace *Self, GLfloat lineWidth) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(LineWidth(Self, lineWidth)) context->line.LineWidth = lineWidth; #ifdef MGL_NEW_WARP3D IWarp3D->W3D_SetParameter(context->w3dContext, W3D_LINE_WIDTH, &context->line.LineWidth); #endif } void cgl_GLPointSize(struct GLContextIFace *Self, GLfloat size) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(PointSize(Self, size)) context->point.PointSize = size; #ifdef MGL_NEW_WARP3D IWarp3D->W3D_SetParameter(context->w3dContext, W3D_POINT_SIZE, &context->point.PointSize); #endif } void cgl_GLLineStipple(struct GLContextIFace *Self, GLint factor, GLushort pattern) { #ifdef MGL_NEW_WARP3D GLcontext context = GET_INSTANCE(Self); DL_CHECK(LineStipple(Self, factor, pattern)) /* FIXME: Add states to context */ IWarp3D->W3D_SetParameter(context->w3dContext, W3D_STIPPLE_LINE, &pattern); IWarp3D->W3D_SetParameter(context->w3dContext, W3D_STIPPLE_LINE_FACTOR, &factor); #endif } void cgl_GLPolygonStipple(struct GLContextIFace *Self, GLubyte *pattern) { #ifdef MGL_NEW_WARP3D GLcontext context = GET_INSTANCE(Self); DL_CHECK(PolygonStipple(Self, pattern)) memcpy(context->polygon_stipple.pattern, pattern, 128); IWarp3D->W3D_SetParameter(context->w3dContext, W3D_STIPPLE_POLYGON, &pattern); #endif } void cgl_GLPolygonOffset(struct GLContextIFace *Self, GLfloat factor, GLfloat units) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(PolygonOffset(Self, factor, units)) //dprintf("factor: %f, units: %f\n", factor, units); context->polygon.PolygonOffsetFactor = factor; context->polygon.PolygonOffsetUnits = units; } void cgl_GLAlphaFunc(struct GLContextIFace *Self, GLenum func, GLclampf ref) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(AlphaFunc(Self, func, ref)) //dprintf("func: %x ref: %f\n", func, ref); GLFlagError(context, context->CurrentPrimitive != GL_BASE, GL_INVALID_OPERATION); int32 w3dmode = mapMGLATestToW3D(func, W3D_ILLEGALINPUT); GLFlagError(context, (w3dmode == W3D_ILLEGALINPUT), GL_INVALID_ENUM); W3D_Float refvalue = (W3D_Float)ref; context->color_buffer.AlphaTestFunc = func; context->color_buffer.AlphaTestRef = ref; IWarp3D->W3D_SetAlphaMode(context->w3dContext, w3dmode, &refvalue); } void cgl_GLPolygonMode(struct GLContextIFace *Self, GLenum face, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(PolygonMode(Self, face, mode)) switch(face) { case GL_FRONT: context->polygon.PolygonModeFront = mode; break; case GL_BACK: context->polygon.PolygonModeBack = mode; break; case GL_FRONT_AND_BACK: context->polygon.PolygonModeFront = mode; context->polygon.PolygonModeBack = mode; break; } return ; } void cgl_GLShadeModel(struct GLContextIFace *Self, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(ShadeModel(Self, mode)) context->lighting.ShadeModel = mode ; if (mode == GL_FLAT) { IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_DISABLE); } else if (mode == GL_SMOOTH) { IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_ENABLE); } } #define BLS(X) case GL_##X: src=W3D_##X; break #define BLD(X) case GL_##X: dest=W3D_##X; break void cgl_GLBlendFunc(struct GLContextIFace *Self, GLenum sfactor, GLenum dfactor) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(BlendFunc(Self, sfactor, dfactor)) int32 src = mapMGLBlendSourceToW3D(sfactor, W3D_ILLEGALINPUT); //This assertion may be compiled away GLFlagError(context, (src == W3D_ILLEGALINPUT), GL_INVALID_ENUM); int32 dst = mapMGLBlendDestToW3D(dfactor, W3D_ILLEGALINPUT); // This assertion may be compiled away GLFlagError(context, (dst == W3D_ILLEGALINPUT), GL_INVALID_ENUM); // Try to set the mode, if unavailable, switch to // (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) which is supported // by almost all Amiga supported graphics cards if ( src != W3D_ILLEGALINPUT && dst != W3D_ILLEGALINPUT && IWarp3D->W3D_SetBlendMode(context->w3dContext, src, dst) == W3D_UNSUPPORTEDBLEND ) { dprintf( "Blend mode %04X %04X not supported by hardware\n", (unsigned)sfactor, (unsigned)dfactor ); if (context->NoFallbackAlpha == GL_FALSE) { IWarp3D->W3D_SetBlendMode(context->w3dContext, W3D_SRC_ALPHA, W3D_ONE_MINUS_SRC_ALPHA); context->AlphaFellBack = GL_TRUE; } else { context->AlphaFellBack = GL_FALSE; } } else { context->AlphaFellBack = GL_FALSE; } context->color_buffer.BlendSrc = sfactor; context->color_buffer.BlendDst = dfactor; } void cgl_GLStencilFunc(struct GLContextIFace *Self, GLenum func, GLint ref, GLint mask) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(StencilFunc(Self, func, ref, mask)) uint32 f = W3D_ST_NEVER; switch (func) { case GL_NEVER: f = W3D_ST_NEVER; break; case GL_ALWAYS: f = W3D_ST_ALWAYS; break; case GL_LESS: f = W3D_ST_LESS; break; case GL_LEQUAL: f = W3D_ST_LEQUAL; break; case GL_EQUAL: f = W3D_ST_EQUAL; break; case GL_GEQUAL: f = W3D_ST_GEQUAL; break; case GL_GREATER: f = W3D_ST_GREATER; break; case GL_NOTEQUAL: f = W3D_ST_NOTEQUAL; break; } IWarp3D->W3D_SetStencilFunc(context->w3dContext, f, ref, mask); } static uint32 MapOp(GLenum op) { switch(op) { case GL_KEEP: return W3D_ST_KEEP; case GL_ZERO: return W3D_ST_ZERO; case GL_REPLACE: return W3D_ST_REPLACE; case GL_INCR: return W3D_ST_INCR; case GL_DECR: return W3D_ST_DECR; case GL_INVERT: return W3D_ST_INVERT; case GL_INCR_WRAP: return W3D_ST_INCR_WRAP; case GL_DECR_WRAP: return W3D_ST_DECR_WRAP; default: return 0; } } void cgl_GLStencilOp(struct GLContextIFace *Self, GLenum sfail, GLenum dpfail, GLenum dppass) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(StencilOp(Self, sfail, dpfail, dppass)) uint32 sf = MapOp(sfail), dpf = MapOp(dpfail), dpp = MapOp(dppass); IWarp3D->W3D_SetStencilOp(context->w3dContext, sf, dpf, dpp); } void cgl_GLStencilMask(struct GLContextIFace *Self, GLuint mask) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(StencilMask(Self, mask)) IWarp3D->W3D_SetWriteMask(context->w3dContext, mask); } void cgl_GLColorMask(struct GLContextIFace *Self, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(ColorMask(Self, red, green, blue, alpha)) context->color_buffer.WriteMaskRed = red; context->color_buffer.WriteMaskGreen = green; context->color_buffer.WriteMaskBlue = blue; context->color_buffer.WriteMaskAlpha = alpha; IWarp3D->W3D_SetColorMask(context->w3dContext, red, green, blue, alpha); } void cgl_GLHint(struct GLContextIFace *Self, GLenum target, GLenum mode) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(Hint(Self, target, mode)) uint32 hint = W3D_H_AVERAGE; switch (mode) { case GL_FASTEST: hint = W3D_H_FAST; break; case GL_NICEST: hint = W3D_H_NICE; break; case GL_DONT_CARE: hint = W3D_H_AVERAGE; break; default: // GLFlagError(context, 1, GL_INVALID_ENUM); break; } switch (target) { case GL_FOG_HINT: IWarp3D->W3D_Hint(context->w3dContext, W3D_H_FOGGING, hint); break; case GL_PERSPECTIVE_CORRECTION_HINT: IWarp3D->W3D_Hint(context->w3dContext, W3D_H_PERSPECTIVE, hint); break; case MGL_ZBUFFER_HINT: IWarp3D->W3D_Hint(context->w3dContext, W3D_H_ZBUFFER, hint); break; case MGL_W_ONE_HINT: if (mode == GL_FASTEST) { context->WOne_Hint = GL_TRUE; } else { context->WOne_Hint = GL_FALSE; } break; case MGL_TEXTURE_QUALITY_HINT: if (mode == GL_FASTEST) { context->ConvertTo16Bit = GL_TRUE; } else { context->ConvertTo16Bit = GL_FALSE; } break; default: // GLFlagError(context, 1, GL_INVALID_ENUM); break; } } static void BuildExtensionString(GLcontext context) { #define DEFAULT_EXT "GL_MGL_packed_pixels GL_EXT_packed_pixels GL_EXT_bgra GL_EXT_color_table GL_EXT_vertex_array GL_NV_texgen_reflection GL_ARB_vertex_array_bgra GL_ARB_draw_elements_base_vertex GL_EXT_draw_range_elements" uint32 env_combine = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_ENV_COMBINE, 0); uint32 env_crossbar = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_ENV_CROSSBAR, 0); uint32 env_add = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_ENV_ADD, 0); uint32 anisotropy = IWarp3D->W3D_Query(context->w3dContext, W3D_Q_ANISOTROPICFILTER, 0); uint32 tc_support = 0; #ifdef MGL_TEXTURE_COMPRESSION int i; for (i = W3D_COMPRESSED_R5G6B5; i <= W3D_COMPRESSED_A8R5G6B5; i++) { if (context->textureSupport[i] & W3D_TEXFMT_FAST) { tc_support++; } } #endif struct AddToExt { int supported; const char *str; }; struct AddToExt exts[]={ 1,DEFAULT_EXT, context->NumTextureUnits > 1, "GL_ARB_multitexture", MGL_COMPILED_VERTEX_ARRAYS, "GL_EXT_compiled_vertex_arrays", anisotropy != W3D_NOT_SUPPORTED, "GL_EXT_texture_filter_anisotropic", env_combine != W3D_NOT_SUPPORTED, "GL_ARB_texture_env_combine GL_EXT_texture_env_combine", env_crossbar != W3D_NOT_SUPPORTED, "GL_ARB_texture_env_crossbar GL_ARB_texture_env_dot3 GL_EXT_texture_env_dot3", env_add != W3D_NOT_SUPPORTED, "GL_ARB_texture_env_add GL_EXT_texture_env_add", context->VBOSize > 0, "GL_ARB_vertex_buffer_object GL_ARB_map_buffer_range", tc_support > 0, "GL_ARB_texture_compression GL_EXT_texture_compression_s3tc GL_S3_s3tc", 0,0}; uint32 size=0; for(unsigned int t=0;exts[t].str;++t) { if(exts[t].supported) { size+=strlen(exts[t].str)+1; // t==0 -> +1 for 0 terminator; t>0 -> +1 for leading space :) } } context->extensionString=AllocVecInternal(size,MEMF_ANY); char *d=context->extensionString; for(unsigned int t=0;exts[t].str;++t) { if(exts[t].supported) { if(t) *d++=' '; for(const char *s=exts[t].str;*s;++s) *d++=*s; } } *d=0; } const GLubyte * cgl_GLGetString(struct GLContextIFace *Self, GLenum name) { GLcontext context = GET_INSTANCE(Self); switch(name) { case GL_RENDERER: if (context->w3dContext) { switch(context->w3dContext->CurrentChip) { case W3D_CHIP_VIRGE: return (GLubyte *)"MiniGL/Warp3D S3 ViRGE (virge)"; case W3D_CHIP_PERMEDIA2: return (GLubyte *)"MiniGL/Warp3D 3DLabs Permedia 2 (permedia)"; case W3D_CHIP_VOODOO1: return (GLubyte *)"MiniGL/Warp3D 3DFX Voodoo 1 (voodoo)"; case W3D_CHIP_AVENGER: return (GLubyte *)"MiniGL/Warp3D 3DFX Voodoo 3 (voodoo avenger)"; case W3D_CHIP_RADEON: return (GLubyte *)"MiniGL/Warp3D ATI Radeon (radeon)"; case W3D_CHIP_RADEON_R200: return (GLubyte *)"MiniGL/Warp3D ATI Radeon (radeon r200)"; case W3D_CHIP_NAPALM: return (GLubyte *)"MiniGL/Warp3D 3DFX Voodoo 4 (voodoo napalm)"; case W3D_CHIP_UNKNOWN: return (GLubyte *)"MiniGL/Warp3D Unknown graphics chip"; default: // Extract the Warp3D driver's name from the driver itself if(!context->rendererName) { const char *nameBase = "MiniGL/Warp3D %s"; const int nameBaseLen = strlen(nameBase); W3D_Driver **drivers = IWarp3D->W3D_GetDrivers(); if(drivers) { while(*drivers) { if((*drivers)->ChipID == context->w3dContext->CurrentChip && (*drivers)->name) { int nameLen = nameBaseLen + strlen((*drivers)->name); context->rendererName = (char*)AllocVecInternal(nameLen,MEMF_SHARED); if(context->rendererName) { snprintf(context->rendererName, nameLen, nameBase, (*drivers)->name); } } ++drivers; } } } if(context->rendererName) { return (GLubyte *)context->rendererName; } else { return (GLubyte *)"MiniGL/Warp3D"; } } } else { return (GLubyte *)"MiniGL/Warp3D"; } case GL_VENDOR: return (GLubyte *)"The MiniGL Team (" VERS ")"; case GL_VERSION: return (GLubyte *)"1.3"; case GL_EXTENSIONS: if (!context->extensionString) { BuildExtensionString(context); } if (context->extensionString) { return (GLubyte *)context->extensionString; } return (GLubyte *)DEFAULT_EXT; default: return (GLubyte *)"Huh?"; } } GLenum cgl_GLGetError(struct GLContextIFace *Self) { GLcontext context = GET_INSTANCE(Self); GLenum ret = context->CurrentError; context->CurrentError = GL_NO_ERROR; return ret; } void cgl_GLGetPointerv(struct GLContextIFace *Self, GLenum pname, GLvoid **params) { GLcontext context = GET_INSTANCE(Self); switch(pname) { case GL_COLOR_ARRAY_POINTER: *params = context->vertex_array.ColorArray.pointer; return; case GL_EDGE_FLAG_ARRAY_POINTER: *params = NULL; // Not supported at the moment return; case GL_FOG_COORD_ARRAY_POINTER: *params = NULL; // Not supported at the moment return; case GL_FEEDBACK_BUFFER_POINTER: *params = NULL; // Not supported at the moment return; case GL_INDEX_ARRAY_POINTER: *params = NULL; // Not supported at the moment return; case GL_NORMAL_ARRAY_POINTER: *params = context->vertex_array.NormalArray.pointer; return; case GL_SECONDARY_COLOR_ARRAY_POINTER: *params = NULL; // Not supported at the moment return; case GL_SELECTION_BUFFER_POINTER: *params = context->selectionBuffer; return; case GL_TEXTURE_COORD_ARRAY_POINTER: *params = context->vertex_array.TexCoordArray[context->texture.ActiveTexture].pointer; return; case GL_VERTEX_ARRAY_POINTER: *params = context->vertex_array.VertexArray.pointer; return; default: dprintf("Invalid pname passed to %s\n", __func__); *params = NULL; return; } } void cgl_SetZOffset(struct GLContextIFace *Self, GLfloat offset) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(SetZOffset(Self, offset)) context->depth_buffer.ZOffset = offset; } void cgl_PinTexture(struct GLContextIFace *Self, GLuint texnum) { GLcontext context = GET_INSTANCE(Self); #if 0 DL_CHECK(PinTexture(Self, texnum)) W3D_Texture *tex = context->w3dTextures[texnum].texObj; if (tex) IWarp3D->W3D_PinTexture(context->w3dContext, tex, TRUE); else #endif GLFlagError(context, 1, GL_INVALID_OPERATION); } void cgl_UnpinTexture(struct GLContextIFace *Self, GLuint texnum) { GLcontext context = GET_INSTANCE(Self); #if 0 DL_CHECK(UnpinTexture(Self, texnum)) W3D_Texture *tex = context->w3dTextures[texnum].texObj; if (tex) IWarp3D->W3D_PinTexture(context->w3dContext, tex, FALSE); else #endif GLFlagError(context, 1, GL_INVALID_OPERATION); } void cgl_SetTextureRenderTarget(struct GLContextIFace *Self, GLuint texnum) { GLcontext context = GET_INSTANCE(Self); #if 0 DL_CHECK(SetTextureRenderTarget(Self, texnum)) if (texnum != 0) { W3D_Texture *tex = context->w3dTextures[texnum].texObj; if (tex) { context->backupScissor = context->w3dScissor; context->w3dScissor.left = 0; context->w3dScissor.top = 0; context->w3dScissor.width = tex->texwidth; context->w3dScissor.height = tex->texheight; context->textureRenderTarget = texnum; if (IWarp3D->W3D_SetDrawRegionTexture(context->w3dContext, tex, &context->w3dScissor) != W3D_SUCCESS) { GLFlagError(context, 1, GL_INVALID_OPERATION); } } else GLFlagError(context, 1, GL_INVALID_OPERATION); } else { context->textureRenderTarget = 0; context->w3dScissor = context->backupScissor; IWarp3D->W3D_SetDrawRegionTexture(context->w3dContext, NULL, NULL); } #else GLFlagError(context, 1, GL_INVALID_OPERATION); #endif } void cgl_GLLogicOp(struct GLContextIFace *Self, GLenum op) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(LogicOp(Self, op)) int32 w3dmode = mapMGLLogicOpToW3D(op, W3D_ILLEGALINPUT); // This assertion may be compiled away in non-debug mode GLFlagError(context, (w3dmode == W3D_ILLEGALINPUT), GL_INVALID_ENUM); // Never pass rubbish to Warp3D if (w3dmode != W3D_ILLEGALINPUT) { IWarp3D->W3D_SetLogicOp( context->w3dContext, w3dmode ); context->color_buffer.LogicOpMode = op; } }