/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999-2005 The MiniGL team * 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 #include #include "util.h" #include "mgl_profileitems.h" static char rcsid[] UNUSED = "$Id$"; extern void m_CombineMatrices(GLcontext context); extern void RebindTextures(GLcontext context); extern void tex_EstablishEnvCombine(GLcontext context); #define CLIP_EPS (1e-7) static GLboolean CodeRasterPos(GLcontext context) { float w = context->current.RasterPos.w; GLuint outcode = 0; if (context->current.RasterPos.w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > context->current.RasterPos.x) { outcode |= MGL_CLIP_LEFT; } else if (context->current.RasterPos.x > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > context->current.RasterPos.y) { outcode |= MGL_CLIP_BOTTOM; } else if (context->current.RasterPos.y > w) { outcode |= MGL_CLIP_TOP; } if (-w > context->current.RasterPos.z) { outcode |= MGL_CLIP_BACK; } else if (context->current.RasterPos.z > w) { outcode |= MGL_CLIP_FRONT; } #if 0 if (context->MaxClipPlane != -1) { int i; for (i = 0; i <= context->MaxClipPlane; i++) { if (context->UserClipPlane[i].enabled) { GLfloat d = context->UserClipPlane[i].eqn[0] * v->eye.x + context->UserClipPlane[i].eqn[1] * v->eye.y + context->UserClipPlane[i].eqn[2] * v->eye.z + context->UserClipPlane[i].eqn[3] * v->eye.w; if (d < 0.0) { outcode |= context->UserClipPlane[i].outcode; } } } } #endif return (outcode == 0); } void cgl_GLRasterPos4f(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { GLcontext context = GET_INSTANCE(Self); DL_CHECK(RasterPos4f(Self, x, y, z, w)); #if 0 /* ** Current texture coordinates are s/t resp. This means ** that texture wrap occurs at 0 and 1, not at 0 and width/height. */ if (context->MaxTextureUnit > -1) { for (i = 0; i <= context->MaxTextureUnit; i++) { if (context->Tex2D_State[i] == GL_TRUE) { if (context->CurTexQValid[i] == GL_TRUE) { context->RasterTexCoords[i].u = context->CurTexS[i]/context->CurTexQ[i]; context->RasterTexCoords[i].v = context->CurTexT[i]/context->CurTexQ[i]; context->RasterTexCoords[i].w = context->CurTexQ[i]; context->RasterRhwValid[i][i] = GL_TRUE; } else { context->RasterTexCoords[i].u = context->CurTexS[i]; context->RasterTexCoords[i].v = context->CurTexT[i]; context->RasterTexCoords[i].w = 1.0; context->RasterRhwValid[i][i] = GL_FALSE; } } } } #endif context->current.RasterColor.r = context->current.CurrentColor.r; context->current.RasterColor.g = context->current.CurrentColor.g; context->current.RasterColor.b = context->current.CurrentColor.b; context->current.RasterColor.a = context->current.CurrentColor.a; if (context->CombinedValid == GL_FALSE) { m_CombineMatrices(context); } #define a(x) (context->CombinedMatrix.v[OF_##x]) context->current.RasterPos.x = a(11)*x + a(12)*y + a(13)*z + a(14)*w; context->current.RasterPos.y = a(21)*x + a(22)*y + a(23)*z + a(24)*w; context->current.RasterPos.z = a(31)*x + a(32)*y + a(33)*z + a(34)*w; context->current.RasterPos.w = a(41)*x + a(42)*y + a(43)*z + a(44)*w; //IExec->DebugPrintF("x: %f, y: %f, z: %f, w: %f\n", context->current.RasterPos.x, context->current.RasterPos.y, context->current.RasterPos.z, context->current.RasterPos.w); context->current.RasterPosValid = CodeRasterPos(context); if (context->current.RasterPosValid) { /* If valid, project to screen */ float invW = 1.0 / context->current.RasterPos.w; context->current.RasterPos.x = context->ax + context->current.RasterPos.x * invW * context->sx; context->current.RasterPos.y = context->ay - context->current.RasterPos.y * invW * context->sy; context->current.RasterDistance = context->az + context->current.RasterPos.z * invW * context->sz; } /* else { IExec->DebugPrintF("clipped\n"); } */ } void unpack_bitmap_16(void *_context, const GLubyte *from, GLubyte *to, GLsizei num) { /* FIXME: Honor Unpack skip pixels */ GLcontext context = (GLcontext)_context; GLsizei i, j; unsigned int mask; GLushort *dst = (GLushort *)to; for (i = 0; i < num; i += 8) { if (context->pixel_store.unpack.lsb_first) { mask = 0x01; } else { mask = 0x80; } GLubyte cur = *from++; for (j = 0; j < 8; j++) { if (cur & mask) { *dst++ = 0xffff; } else { *dst++ = 0; } if (context->pixel_store.unpack.lsb_first) { mask <<= 1; } else { mask >>= 1; } if (i+j > num) { break; } } } } GLsizei next_pwr(GLsizei x) { GLsizei r = 1; while (r < x) { r <<= 1; } return r; } /* How glBitmaps works: * Since the OpenGL specs say that fragments are only generated for pixels of the bitmap * that are '1', the bitmap is first turned into a texture. Next, it's drawn at the * current raster position as a Quad with chroma keying set up in such a way that only white pixels * pass. */ typedef struct { float x,y,z; float r,g,b,a; float u,v,w; } BMVertex; #define BMVERTEX_FORMAT (W3D_VFORMAT_COLOR | W3D_VFORMAT_TCOORD_0) BOOL EnsureBitmapBackingStore(GLcontext context, uint32 dataSize) { if (context->CurrentBitmapBackingStoreSize < dataSize) { /* Need to enlarge the cache */ if (context->CurrentBitmapBackingStore) { FreeVecInternal(context->CurrentBitmapBackingStore); } context->CurrentBitmapBackingStore = AllocVecInternal(dataSize, MEMF_ANY); if (!context->CurrentBitmapBackingStore) { /* Failed allocation */ context->CurrentBitmapBackingStoreSize = 0; return FALSE; } context->CurrentBitmapBackingStoreSize = dataSize; } return TRUE; } void cgl_GLBitmap(struct GLContextIFace *Self, GLsizei w, GLsizei h, GLfloat xbo, GLfloat ybo, GLfloat xbi, GLfloat ybi, const GLubyte *data) { GLcontext context = GET_INSTANCE(Self); PROFILE_ENTRY(FID_CGL_GL_BITMAP); DL_CHECK(Bitmap(Self, w, h, xbo, ybo, xbi, ybi, data)); GLsizei dataSize; GLubyte *targetData; GLuint i; W3D_Texture *tex = 0; uint32 oldCullState, oldTexmappingState, oldGouraudState, oldAlphaState, oldAlphaTestState; GLsizei rw, rh; uint32 error; /* Round sizes up to next power of two */ rw = next_pwr(w); rh = next_pwr(h); /* Check for valid raster pos. If invalid, just return */ if (!context->current.RasterPosValid) { return; } /* If the data pointer is NULL skip over the rendering bit.... */ if (data) { /* Convert the bitmap into a texture */ dataSize = rw * rh * 4; if (!EnsureBitmapBackingStore(context, dataSize)) { return; } /* If we reach here, we have enough memory to convert the bitmap data. */ targetData = context->CurrentBitmapBackingStore; IUtility->ClearMem(targetData, dataSize); for (i = 0; i < h; i++) { unpack_bitmap_16(context, data, targetData, w); if (context->pixel_store.unpack.row_length == 0) { data += (w/8) + (w%8 == 0 ? 0 : 1); } else { data += (context->pixel_store.unpack.row_length / 8) + (context->pixel_store.unpack.row_length % 8 == 0 ? 0 : 1); } targetData += 2*rw; } /* Allocate a texture with this data */ tex = IWarp3D->W3D_AllocTexObjTags( context->w3dContext, &error, W3D_ATO_IMAGE, context->CurrentBitmapBackingStore, W3D_ATO_FORMAT, W3D_L8A8, W3D_ATO_WIDTH, rw, W3D_ATO_HEIGHT, rh, TAG_DONE ); if (!tex || error != W3D_SUCCESS) { /* Can't allocate the texture, bail out */ dprintf("Couldn't allocate texture, error %d\n", error); return; } /* Set texture parameters and chroma key to pass on white */ oldAlphaTestState = IWarp3D->W3D_GetState(context->w3dContext, W3D_ALPHATEST); IWarp3D->W3D_SetState(context->w3dContext, W3D_ALPHATEST, W3D_ENABLE); IWarp3D->W3D_SetFilter(context->w3dContext, tex, W3D_NEAREST, W3D_NEAREST); IWarp3D->W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL); IWarp3D->W3D_SetWrapMode(context->w3dContext, tex, W3D_CLAMP, W3D_CLAMP, 0); W3D_Float refVal = 0.0; IWarp3D->W3D_SetAlphaMode(context->w3dContext, W3D_A_GREATER, &refVal); oldCullState = IWarp3D->W3D_GetState(context->w3dContext, W3D_CULLFACE); IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, W3D_DISABLE); oldTexmappingState = IWarp3D->W3D_GetState(context->w3dContext, W3D_TEXMAPPING); IWarp3D->W3D_SetState(context->w3dContext, W3D_TEXMAPPING, W3D_ENABLE); oldGouraudState = IWarp3D->W3D_GetState(context->w3dContext, W3D_GOURAUD); IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_ENABLE); oldAlphaState = IWarp3D->W3D_GetState(context->w3dContext, W3D_BLENDING); IWarp3D->W3D_SetState(context->w3dContext, W3D_BLENDING, W3D_ENABLE); /* Set up the drawing structure */ BMVertex quad[4]; /* Lower left corner */ quad[0].x = context->current.RasterPos.x - xbo; quad[0].y = context->current.RasterPos.y + ybo; quad[0].z = context->current.RasterDistance; quad[0].w = 1.0 - context->current.RasterDistance; quad[0].u = 0.0; quad[0].v = 0.0; quad[0].r = context->current.RasterColor.r; quad[0].g = context->current.RasterColor.g; quad[0].b = context->current.RasterColor.b; quad[0].a = context->current.RasterColor.a; /* Lower right corner */ quad[1].x = context->current.RasterPos.x - xbo + w; quad[1].y = context->current.RasterPos.y + ybo; quad[1].z = context->current.RasterDistance; quad[1].w = 1.0 - context->current.RasterDistance; quad[1].u = (float)w; quad[1].v = 0.0; quad[1].r = context->current.RasterColor.r; quad[1].g = context->current.RasterColor.g; quad[1].b = context->current.RasterColor.b; quad[1].a = context->current.RasterColor.a; /* Upper right corner */ quad[2].x = context->current.RasterPos.x - xbo + w; quad[2].y = context->current.RasterPos.y + ybo - h; quad[2].z = context->current.RasterDistance; quad[2].w = 1.0 - context->current.RasterDistance; quad[2].u = (float)w; quad[2].v = (float)h; quad[2].r = context->current.RasterColor.r; quad[2].g = context->current.RasterColor.g; quad[2].b = context->current.RasterColor.b; quad[2].a = context->current.RasterColor.a; /* Upper left corner */ quad[3].x = context->current.RasterPos.x - xbo; quad[3].y = context->current.RasterPos.y + ybo - h; quad[3].z = context->current.RasterDistance; quad[3].w = 1.0 - context->current.RasterDistance; quad[3].u = 0.0; quad[3].v = (float)h; quad[3].r = context->current.RasterColor.r; quad[3].g = context->current.RasterColor.g; quad[3].b = context->current.RasterColor.b; quad[3].a = context->current.RasterColor.a; if (context->LockMode == MGL_LOCK_SMART) { smartlock_beginDraw(context->smartLock); } else if (context->w3dLocked == GL_FALSE) { IWarp3D->W3D_LockHardware(context->w3dContext); } IWarp3D->W3D_InterleavedArray( context->w3dContext, quad, sizeof(BMVertex), BMVERTEX_FORMAT, 0 ); IWarp3D->W3D_BindTexture(context->w3dContext, 0, tex); IWarp3D->W3D_SetTextureBlendTags( context->w3dContext, W3D_BLEND_STAGE, 0, W3D_ENV_MODE, W3D_MODULATE, W3D_BLEND_STAGE, 1, W3D_ENV_MODE, W3D_OFF, TAG_DONE ); error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, 0, 4); /** A workaround for a Warp3D chromatest bug which seems to screw up non-texture-mapped * primitives rendered after this, unless we execute the following three lines */ //IWarp3D->W3D_SetChromaTestBounds(context->w3dContext, tex, 0xffffffff, 0, W3D_CHROMATEST_NONE); //IWarp3D->W3D_SetState(context->w3dContext, W3D_CHROMATEST, oldChromaTestState); //IWarp3D->W3D_BindTexture(context->w3dContext, 0, NULL); //error = IWarp3D->W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, 0, 0); IWarp3D->W3D_SetState(context->w3dContext, W3D_TEXMAPPING, oldTexmappingState); IWarp3D->W3D_SetState(context->w3dContext, W3D_ALPHATEST, oldAlphaTestState); IWarp3D->W3D_FreeTexObj(context->w3dContext, tex); IWarp3D->W3D_SetState(context->w3dContext, W3D_CULLFACE, oldCullState); IWarp3D->W3D_SetState(context->w3dContext, W3D_GOURAUD, oldGouraudState); IWarp3D->W3D_SetState(context->w3dContext, W3D_BLENDING, oldAlphaState); if (context->LockMode == MGL_LOCK_SMART) { smartlock_endDraw(context->smartLock); } else if (context->w3dLocked == GL_FALSE) { IWarp3D->W3D_UnLockHardware(context->w3dContext); } // Might not need this, but it doesn't hurt. IWarp3D->W3D_InterleavedArray( context->w3dContext, context->VertexBuffer, sizeof (MGLVertex), context->VertexFormat, W3D_TEXCOORD_NORMALIZED ); RebindTextures(context); tex_EstablishEnvCombine(context); } /* if data */ context->current.RasterPos.x += xbi; context->current.RasterPos.y -= ybi; context->fbDirty = GL_TRUE; PROFILE_EXIT(FID_CGL_GL_BITMAP); }