/* * $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 "sysinc.h" #include static char rcsid[] = "$Id$"; extern void d_DrawPoints (struct GLcontext_t); extern void d_DrawLines (struct GLcontext_t); extern void d_DrawLineStrip (struct GLcontext_t); extern void d_DrawTriangles (struct GLcontext_t); extern void d_DrawTriangleFan (struct GLcontext_t); extern void d_DrawTriangleStrip (struct GLcontext_t); extern void d_DrawQuads (struct GLcontext_t); extern void d_DrawPolygon (struct GLcontext_t); extern void d_DrawFlatFan (struct GLcontext_t); extern void d_DrawQuadStrip (struct GLcontext_t); extern void tex_ConvertTexture (GLcontext); extern void fog_Set (GLcontext); static struct Device *TimerBase; void TMA_Start(LockTimeHandle *handle); GLboolean TMA_Check(LockTimeHandle *handle); /* Timer based locking stuff. TMA_Start starts the time measuring for the lock time. The 68k uses the ReadEClock function due to its low overhead. PPC will use GetSysTimePPC for the same reasons. The EClock version reads the eclock and stores the current values in the handle. It then calculates a maximum lock time based on the assumption that the lock should be unlocked after 0.05 seconds (i.e. twenty times per second). TMA_Check checks if the specified time has expired. If it returns GL_FALSE, the lock may be kept alive. On return of GL_TRUE, the lock must be released. Note that this routine handles the case where the ev_hi values has changed, i.e. the eV_lo value had an overrun. This code also assumes, however, that the difference between the current and former ev_hi is no more than 1. This is, however, a very safe assumption; It takes approx. 100 minutes for the ev_hi field to increment, and it is extremely unlikely that the ev_hi field overruns - this will happen after approx. 820,000 years uptime (of course, a reliable system should be prepared for this) */ #ifndef __PPC__ void TMA_Start(LockTimeHandle *handle) { struct EClockVal eval; extern struct ExecBase *SysBase; if (!TimerBase) { TimerBase = (struct Device *)FindName(&SysBase->DeviceList, "timer.device"); } handle->e_freq = ReadEClock(&eval); handle->s_hi = eval.ev_hi; handle->s_lo = eval.ev_lo; handle->e_freq /= 20; } GLboolean TMA_Check(LockTimeHandle *handle) { struct EClockVal eval; ULONG ticks; ReadEClock(&eval); if (eval.ev_hi == handle->s_hi) { ticks = eval.ev_lo - handle->s_lo; } else { ticks = (~0)-handle->s_lo + eval.ev_lo; } if (ticks > handle->e_freq) return GL_TRUE; else return GL_FALSE; } #else void TMA_Start(LockTimeHandle *handle) { GetSysTimePPC(&(handle->StartTime)); } GLboolean TMA_Check(LockTimeHandle *handle) { struct timeval curTime; GetSysTimePPC(&curTime); SubTimePPC(&curTime, &(handle->StartTime)); if (curTime.tv_secs) return GL_TRUE; if (curTime.tv_micro > 50000) return GL_TRUE; return GL_FALSE; } #endif void GLBegin(GLcontext context, GLenum mode) { // GLFlagError(context, context->CurrentPrimitive != GL_BASE, GL_INVALID_OPERATION); context->VertexBufferPointer = 0; switch((int)mode) { case GL_POINTS: //LOG(1, glBegin, "GL_POINTS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPoints; break; case GL_LINES: //LOG(1, glBegin, "GL_LINES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLines; break; case GL_LINE_STRIP: //LOG(1, glBegin, "GL_LINE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_LINE_LOOP: //LOG(1, glBegin, "GL_LINE_LOOP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawLineStrip; break; case GL_TRIANGLES: //LOG(1, glBegin, "GL_TRIANLES"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangles; break; case GL_TRIANGLE_STRIP: //LOG(1, glBegin, "GL_TRIANGLE_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleStrip; break; case GL_TRIANGLE_FAN: //LOG(1, glBegin, "GL_TRIANGLE_FAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawTriangleFan; break; case GL_QUADS: //LOG(1, glBegin, "GL_QUADS"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuads; break; case GL_QUAD_STRIP: //LOG(1, glBegin, "GL_QUAD_STRIP"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawQuadStrip; break; case GL_POLYGON: //LOG(1, glBegin, "GL_POLYGON"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawPolygon; break; case MGL_FLATFAN: //LOG(1, glBegin, "MGL_FLATFAN"); context->CurrentPrimitive = mode; context->CurrentDraw = (DrawFn)d_DrawFlatFan; break; default: //LOG(1, glBegin, "Error GL_INVALID_OPERATION"); GLFlagError (context, 1, GL_INVALID_OPERATION); break; } } void GLColor4f(GLcontext context, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { //LOG(2, glColor4f, "%f %f %f %f", red, green, blue, alpha); context->CurrentColor.r = red; context->CurrentColor.g = green; context->CurrentColor.b = blue; context->CurrentColor.a = alpha; } void GLColor4fv(GLcontext context, GLfloat *v) { //LOG(2, glColor4fv, "%f %f %f %f", v[0], v[1], v[2], v[3]); context->CurrentColor.r = v[0]; context->CurrentColor.g = v[1]; context->CurrentColor.b = v[2]; context->CurrentColor.a = v[3]; } void GLColor3fv(GLcontext context, GLfloat *v) { //LOG(2, glColor3fv, "%f %f %f", v[0], v[1], v[2]); context->CurrentColor.r = v[0]; context->CurrentColor.g = v[1]; context->CurrentColor.b = v[2]; context->CurrentColor.a = 1.0; } void GLColor4ub(GLcontext context, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { register float f = 1/255.0; //LOG(2, glColor4ub, "%f %f %f %f", red*f, green*f, blue*f, alpha*f); context->CurrentColor.r = (GLfloat)red*f; context->CurrentColor.g = (GLfloat)green*f; context->CurrentColor.b = (GLfloat)blue*f; context->CurrentColor.a = (GLfloat)alpha*f; } void GLColor4ubv(GLcontext context, GLubyte *v) { register float f = 1/255.0; //LOG(2, glColor4ubv, "%f %f %f %f", v[0]*f, v[1]*f, v[2]*f, v[3]*f); context->CurrentColor.r = (GLfloat)v[0]*f; context->CurrentColor.g = (GLfloat)v[1]*f; context->CurrentColor.b = (GLfloat)v[2]*f; context->CurrentColor.a = (GLfloat)v[3]*f; } void GLColor3ubv(GLcontext context, GLubyte *v) { register float f = 1/255.0; //LOG(2, glColor3ubv, "%f %f %f", v[0]*f, v[1]*f, v[2]*f); context->CurrentColor.r = (GLfloat)v[0]*f; context->CurrentColor.g = (GLfloat)v[1]*f; context->CurrentColor.b = (GLfloat)v[2]*f; context->CurrentColor.a = (GLfloat)1.0; } #ifndef __STORM__ static #endif inline W3D_Float CLAMPF(GLfloat x) { if (x>=0.f && x<=1.f) return x; else if (x<=0.f) return 0.f; else return 1.f; } void GLVertex4f(GLcontext context, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { //LOG(1, glVertex4f, "%f %f %f %f", x,y,z,w); #define thisvertex context->VertexBuffer[context->VertexBufferPointer] thisvertex.bx = x; thisvertex.by = y; thisvertex.bz = z; thisvertex.bw = w; /* ** 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->Texture2D_State == GL_TRUE) { thisvertex.v.u = context->CurrentTexS; thisvertex.v.v = context->CurrentTexT; if (context->w3dTexBuffer[context->CurrentBinding]) { if (context->w3dChipID == W3D_CHIP_VIRGE) { thisvertex.v.u *= (context->w3dTexBuffer[context->CurrentBinding]->texwidth-1); thisvertex.v.v *= (context->w3dTexBuffer[context->CurrentBinding]->texheight-1); } else { thisvertex.v.u *= context->w3dTexBuffer[context->CurrentBinding]->texwidth; thisvertex.v.v *= context->w3dTexBuffer[context->CurrentBinding]->texheight; } } } thisvertex.v.color.r = CLAMPF(context->CurrentColor.r); thisvertex.v.color.g = CLAMPF(context->CurrentColor.g); thisvertex.v.color.b = CLAMPF(context->CurrentColor.b); thisvertex.v.color.a = CLAMPF(context->CurrentColor.a); thisvertex.Normal.x = context->CurrentNormal.x; thisvertex.Normal.y = context->CurrentNormal.y; thisvertex.Normal.z = context->CurrentNormal.z; thisvertex.outcode = 0; thisvertex.inview = GL_FALSE; context->VertexBufferPointer ++; #undef thisvertex } void GLVertex4fv(GLcontext context, GLfloat *v) { GLVertex4f(context, v[0], v[1], v[2], v[3]); } void GLVertex3fv(GLcontext context, GLfloat *v) { GLVertex4f(context, v[0], v[1], v[2], 1.0); } void GLNormal3f(GLcontext context, GLfloat x, GLfloat y, GLfloat z) { //LOG(2, glNormal3f, "%f %f %f", x,y,z); context->CurrentNormal.x = x; context->CurrentNormal.y = y; context->CurrentNormal.z = z; } void GLTexCoord2f(GLcontext context, GLfloat s, GLfloat t) { //LOG(2, glTexCoord2f, "%f %f", s,t); context->CurrentTexS = s; context->CurrentTexT = t; } void GLTexCoord2fv(GLcontext context, GLfloat *v) { //LOG(2, glTexCoord2fv, "%f %f", v[0], v[1]); context->CurrentTexS = v[0]; context->CurrentTexT = v[1]; } void GLDepthRange(GLcontext context, GLclampd n, GLclampd f) { //LOG(2, glDepthRange, "%f %f", n, f); context->near = n; context->far = f; context->sz = (f-n)*0.5; context->az = (n+f)*0.5; } void GLViewport(GLcontext context, GLint x, GLint y, GLsizei w, GLsizei h) { //LOG(2, glViewPort, "%d %d %d %d", x,y,w,h); context->ax = (double)x + (double)w*0.5; context->ay = (double)y + (double)h*0.5; context->sx = (double)w * 0.5; context->sy = (double)h * 0.5; } void GLEnd(GLcontext context) { //LOG(1, glEnd, ""); if (context->FogDirty && context->Fog_State) { fog_Set(context); context->FogDirty = GL_FALSE; } if (context->ShadeModel == GL_FLAT) { static W3D_Color color; color.r = CLAMPF(context->CurrentColor.r); color.g = CLAMPF(context->CurrentColor.g); color.b = CLAMPF(context->CurrentColor.b); color.a = CLAMPF(context->CurrentColor.a); W3D_SetCurrentColor(context->w3dContext, &color); } // Check for blending inconsistancy if (context->AlphaFellBack && (context->SrcAlpha == GL_ONE || context->DstAlpha == GL_ONE) && context->Blend_State == GL_TRUE) { tex_ConvertTexture(context); } #ifdef AUTOMATIC_LOCKING_ENABLE if (context->LockMode == MGL_LOCK_AUTOMATIC) // Automatic: Lock per primitive { if (W3D_SUCCESS == W3D_LockHardware(context->w3dContext)) { context->w3dLocked = GL_TRUE; context->CurrentDraw(context); W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } else { printf("Error during LockHardware\n"); } } else if (context->LockMode == MGL_LOCK_MANUAL) // Manual: Lock manually { context->CurrentDraw(context); } else // Smart: Lock timer based { if (context->w3dLocked == GL_FALSE) { if (W3D_SUCCESS != W3D_LockHardware(context->w3dContext)) { printf("[glEnd] Error during W3D_LockHardware()\n"); return; // give up } context->w3dLocked = GL_TRUE; TMA_Start(&(context->LockTime)); } context->CurrentDraw(context); // Draw! if (TMA_Check(&(context->LockTime)) == GL_TRUE) { // Time to unlock W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } } #else context->CurrentDraw(context); #endif context->CurrentPrimitive = GL_BASE; } void GLFinish(GLcontext context) { //LOG(2, glFinish, ""); GLFlush(context); W3D_WaitIdle(context->w3dContext); } void GLFlush(GLcontext context) { //LOG(2, glFlush, ""); }