/******************************Module*Header*******************************\ * Module Name: mcdline.c * * Contains all of the line-rendering routines for the Cirrus Logic 546X MCD driver. * * (based on mcdline.c from NT4.0 DDK) * * Copyright (c) 1996 Microsoft Corporation * Copyright (c) 1997 Cirrus Logic, Inc. \**************************************************************************/ #include "precomp.h" #include "mcdhw.h" #include "mcdutil.h" #include "mcdmath.h" //#undef CHECK_FIFO_FREE //#define CHECK_FIFO_FREE #define EXCHANGE(i,j) \ { \ ptemp=i; \ i=j; j=ptemp; \ } VOID FASTCALL __MCDRenderLine(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, BOOL resetLine) { ULONG clipNum; RECTL *pClip; LONG lCoord; PDEV *ppdev = pRc->ppdev; unsigned int *pdwNext = ppdev->LL_State.pDL->pdwNext; void *ptemp; // for EXCHANGE and ROTATE_L macros // output queue stuff... DWORD *pSrc; DWORD *pDest = ppdev->LL_State.pRegs + HOST_3D_DATA_PORT; DWORD *pdwStart = ppdev->LL_State.pDL->pdwStartOutPtr; DWORD dwFlags=0; // MCD_TEMP - dwflags initialized to 0 DWORD *dwOrig; /* Temp display list pointer */ DWORD dwOpcode; // Built opcode float frecip_step; float v1red,v1grn,v1blu; LONG ax, bx, ay, by; // FUTURE - do something with resetLine input to line render proc if ((clipNum = pRc->pEnumClip->c) > 1) { pClip = &pRc->pEnumClip->arcl[0]; SET_HW_CLIP_REGS(pRc,pdwNext); pClip++; } // window coords are float values, and need to have // viewportadjust (MCDVIEWPORT) values subtracted to get to real screen space // color values are 0->1 floats and must be multiplied by scale values (MCDRCINFO) // to get to nbits range (scale = 0xff for 8 bit, 0x7 for 3 bit, etc.) // Z values are 0->1 floats and must be multiplied by zscale values (MCDRCINFO) // Exchange the pointers to vertices if the second point // of the line is above the first one // pRc->pvProvoking = a; // keep track of original first for possible flat shading if( a->windowCoord.y > b->windowCoord.y ) { EXCHANGE(a,b); } // Store the first address for the opcode // dwOrig = pdwNext; pdwNext += 3; // Start with a plain line instruction (no modifiers) // and assume same color. Also add three words for DDA // line parameters + count (they can not be avoided) // dwOpcode = LINE | SAME_COLOR | (2+3); // Set flags as requested from the dwFlags field of a batch. // These bits have 1-1 correspondence to their instruction // counterparts. // // Flags : LL_DITHER - Use dither pattern // LL_PATTERN - Draw pattern // LL_STIPPLE - Use stipple mask // LL_LIGHTING - Do lighting // LL_Z_BUFFER - Use Z buffer // FETCH_COLOR - Appended for alpha blending // LL_GOURAUD - Use Gouraud shading // LL_TEXTURE - Texture mapping // /* dwOpcode |= dwFlags & ( LL_DITHER | LL_PATTERN | LL_STIPPLE | LL_LIGHTING | LL_Z_BUFFER | FETCH_COLOR | LL_GOURAUD | LL_TEXTURE ); */ dwOpcode |= pRc->privateEnables & (__MCDENABLE_SMOOTH|__MCDENABLE_Z); if (pRc->privateEnables & __MCDENABLE_LINE_STIPPLE) { dwOpcode |= LL_STIPPLE; } else { // can dither only if no stipple dwOpcode |= (pRc->privateEnables & __MCDENABLE_DITHER) ; } if( !(dwFlags & LL_SAME_COLOR) ) { register DWORD color; // Clear same_color flag // dwOpcode ^= LL_SAME_COLOR; // If the line is shaded, the starting color that should // be set is the topmost point (pVert1) if (pRc->privateEnables & __MCDENABLE_SMOOTH) { v1red = a->colors[0].r * pRc->rScale; *pdwNext = FTOL(v1red); v1grn = a->colors[0].g * pRc->gScale; v1blu = a->colors[0].b * pRc->bScale; *(pdwNext+1) = FTOL(v1grn); *(pdwNext+2) = FTOL(v1blu); dwOpcode += 3; pdwNext += 3; } else { MCDCOLOR *pColor = &pRc->pvProvoking->colors[0]; *pdwNext = FTOL(pColor->r * pRc->rScale); *(pdwNext+1) = FTOL(pColor->g * pRc->gScale); *(pdwNext+2) = FTOL(pColor->b * pRc->bScale); dwOpcode += 3; pdwNext += 3; } } // Set the parameters of a line slope and count // Note: line can only go down, so dy is always positive // { int dx, dy, abs_dx, xdir; // Well ordered points - set starting point1 coords // using a pointer to the origin of the instruction // ax = FTOL(a->windowCoord.x); lCoord = ax + pRc->xOffset; *(dwOrig+1) = (DWORD) (lCoord << 16 ); ay = FTOL(a->windowCoord.y); lCoord = ay + pRc->yOffset; *(dwOrig+2) = (DWORD) (lCoord << 16 ); bx = FTOL(b->windowCoord.x); by = FTOL(b->windowCoord.y); // dx = x2 - x1, // dy = y2 - y1 (always positive) // dx = bx - ax; dy = by - ay; // NOTE that dx and dy are in 32.0 format (LL3D has them in 16.16) // so math below differs from LL3D // make sure dx is positive, and setup xdir needed for x major since we're // already doing the compare here to prevent having to do again for x major case if (dx < 0) { abs_dx = -dx; xdir = 0xffff0000; } else { abs_dx = dx; xdir = 0x00010000; } if( abs_dx > dy ) { // X-major // // compute slope with positive dx frecip_step = ppdev->frecips[abs_dx]; *(pdwNext + 0) = xdir; *(pdwNext + 1) = abs_dx; // *(pdwNext + 2) = (double)dy / (double)ABS(dx) * 65536.0; *(pdwNext + 2) = FTOL(dy * frecip_step * (float)65536.0); // equivalent to above } else { // Y-major // frecip_step = ppdev->frecips[dy]; *(pdwNext + 1) = dy; // Positive count always, by virtue of earlier EXCHANGE *(pdwNext + 2) = 0x10000; // dy = 1 // *(pdwNext + 0) = (double)dx / (double)dy * 65536.0; *(pdwNext + 0) = FTOL(dx * frecip_step * (float)65536.0); // equivalent to above } pdwNext += 3; } if (pRc->privateEnables & __MCDENABLE_SMOOTH) { float tmp; // Calculate and set the color gradients // tmp = ((b->colors[0].r * pRc->rScale) - v1red) * frecip_step; *pdwNext++ = FTOL(tmp); tmp = ((b->colors[0].g * pRc->gScale) - v1grn) * frecip_step; *pdwNext++ = FTOL(tmp); tmp = ((b->colors[0].b * pRc->bScale) - v1blu) * frecip_step; *pdwNext++ = FTOL(tmp); // Increase count field by 6 for DR_MAIN_3D, DG_MAIN_3D, // DB_MAIN_3D and DR_ORTHO_3D, DG_ORTHO_3D, DB_ORTHO_3D // dwOpcode += 3; } if( pRc->privateEnables & __MCDENABLE_Z) { float fdz_main = (b->windowCoord.z - a->windowCoord.z) * pRc->zScale * frecip_step; *pdwNext++ = FTOL(a->windowCoord.z * pRc->zScale); *pdwNext++ = FTOL(fdz_main); // Increase count field by 2 for Z_3D, DZ_MAIN_3D // dwOpcode += 2; } #if 0 if( dwFlags & LL_TEXTURE ) { ... ... ... } #endif if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG)) { float v1alp,tmp; if (pRc->privateEnables & __MCDENABLE_BLEND) { // recall that if both blending and fog active, all prims punted back to software v1alp = a->colors[0].a * pRc->aScale; *(pdwNext+0) = FTOL(v1alp); tmp = ((b->colors[0].a * pRc->aScale) - v1alp) * frecip_step; *(pdwNext+1) = FTOL(tmp); } else { v1alp = a->fog * (float)16777215.0; // convert from 0->1.0 val to 0->ff.ffff val *(pdwNext+0) = FTOL(v1alp); tmp = ((b->fog * (float)16777215.0) - v1alp) * frecip_step; *(pdwNext+1) = FTOL(tmp); } *(pdwNext+0) &= 0x00ffff00;// bits 31->24 and 7->0 reserved *(pdwNext+1) &= 0xffffff00;// bits 7->0 reserved dwOpcode += ( FETCH_COLOR | ALPHA + 2 ); pdwNext += 2; } // Store the final opcode // *dwOrig = dwOpcode; while (--clipNum) { int len = (dwOpcode & 0x3F) + 1; // num words for line primitive SET_HW_CLIP_REGS(pRc,pdwNext) pClip++; // dump same line regs again to draw while clipping against occlusion rectangle pSrc = dwOrig; while( len-- ) *pdwNext++ = *pSrc++; } // output queued data here.... #if 0 // FUTURE - enable queueing algorithm - just outputting everything for now OUTPUT_COPROCMODE_QUEUE #else // 0 { pSrc = pdwStart; while (pSrc != pdwNext) { /* Get the amount of data for this opcode */ int len = (*pSrc & 0x3F) + 1; USB_TIMEOUT_FIX(ppdev) while( len-- ) *pDest = *pSrc++; } } #endif // 0 ppdev->LL_State.pDL->pdwNext = ppdev->LL_State.pDL->pdwStartOutPtr = pdwStart; } VOID FASTCALL __MCDRenderGenLine(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL resetLine) { // MGA and S3 MCD's have no code in this proc MCDBG_PRINT("__MCDRenderGenLine - EMPTY ROUTINE"); }