// Copyright (C) 1996 Keith Whitwell. // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING in the lib3d distribution. // This is a parameterized generic Viewport implementation for all the // simple colour layouts, where a pixel is set by assigning a colour // value directly to a suitably typed pointer. // // The parameters are: // CLASS - the classname to use. // PIXELTYPE - the C type to use for the screen buffer. CLASS *CLASS::advertisement = new CLASS( Exemplar() ); void CLASS::doTextureTriangleZb(edge_major_texture &maj, edge_minor_step &minor1, edge_minor_step &minor2, const Texture &texture) { const Colour *tex = texture.getBuffer(); int textureSize = texture.getSize(); int umask = texture.getMask() << 16; int vmask = texture.getMask() << (8+textureSize); float v_adj = (1<<(8+textureSize)); PIXELTYPE *scan_ptr = ((PIXELTYPE *)device->getBuffer()) + maj.yMin *device->getWidth(); uint *scan_zptr = zBuffer->getBuffer() + maj.yMin * zBuffer->getWidth(); maj.z += zBuffer->getGenerationMask(); const int AffineLength = 8; edge_minor_step *minor = &minor1; int section = 0; float dw_dax = maj.dw_dx * AffineLength; float duw_dax = maj.duw_dx * AffineLength; float dvw_dax = maj.dvw_dx * AffineLength; int incr = maj.incr; //volatile int foo = 0; do { while(minor->height--) { int width = maj.x - minor->x; if (width != 0) { int nr, mod; float w_right = maj.w + dw_dax; float uw_right = maj.uw + duw_dax; float vw_right = maj.vw + dvw_dax; float _w_left = 1/maj.w; if (width > 0) { nr = width / AffineLength; // bit shift mod = width % AffineLength; // bit mask // if (incr > 0) return; } else { nr = (-width) / AffineLength; mod = (-width) % AffineLength; // if (incr < 0) return; } if(!mod) { nr--; mod = AffineLength; } float u_left = _w_left * maj.uw; float v_left = _w_left * maj.vw; float _w_right = 1/w_right; PIXELTYPE *ptr = scan_ptr + maj.x; uint *zptr = scan_zptr + maj.x; uint z = maj.z; uint z0 = *zptr; int length = AffineLength; if (!nr) length = mod; float u_right = _w_right * uw_right; float v_right = _w_right * vw_right; do { int du_dx = int((u_right-u_left)*(UNITY16/AffineLength)); int dv_dx = int((v_right-v_left)*v_adj) >> 3; int u = int(u_left * UNITY16); int v = int(v_left * v_adj); w_right += dw_dax; uw_right += duw_dax; vw_right += dvw_dax; _w_right = 1/w_right; //foo = *ptr; do { if (z < z0) { *zptr = z; *ptr = tex[((u&umask)>>16) + ((v&vmask)>>8)]; } zptr += incr; ptr += incr; u += du_dx; v += dv_dx; z += maj.dz_dx; z0 = *zptr; } while (--length); u_left = u_right; v_left = v_right; u_right = _w_right * uw_right; v_right = _w_right * vw_right; nr--; length = AffineLength; if (!nr) length = mod; } while (nr >= 0); } scan_ptr += device->getWidth(); scan_zptr += zBuffer->getWidth(); maj.x += maj.xStep; maj.uw += maj.uwStep; maj.vw += maj.vwStep; maj.w += maj.wStep; maj.z += maj.zStep; maj.error += maj.numerator; if(maj.error >= 0) { maj.x++; maj.error -= maj.denominator; maj.w += maj.wStepExtra; maj.uw += maj.uwStepExtra; maj.vw += maj.vwStepExtra; maj.z += maj.zStepExtra; } minor->x += minor->xStep; minor->error += minor->numerator; if (minor->error >= 0) { minor->x++; minor->error -= minor->denominator; } } minor = &minor2; } while (section++ == 0); } void CLASS::doFlatTriangleZb(edge_major_flat &maj, edge_minor &minor1, edge_minor &minor2, Colour colour) { PIXELTYPE *scan_ptr = ((PIXELTYPE *)device->getBuffer()) + maj.yMin *device->getWidth(); uint *scan_zptr = zBuffer->getBuffer() + maj.yMin * zBuffer->getWidth(); maj.z += zBuffer->getGenerationMask(); int height = minor1.height; int minorX = minor1.x; int minorXStep = minor1.xStep; int section = 0; int incr = maj.incr; do { while(height--) { int x = (maj.x >> (2*LOG_UNITY)); int width = x - (minorX >> (2*LOG_UNITY)); if (width != 0) { if ((width^incr) < 0) { PIXELTYPE *ptr = scan_ptr + x; uint *zptr = scan_zptr + x; uint z = maj.z; uint z0 = *zptr; do { if (z < z0) { *zptr = z; *ptr = colour; } zptr += incr; ptr += incr; z += maj.dz_dx; z0 = *zptr; width += incr; } while (width); } else { return; } } scan_ptr += device->getWidth(); scan_zptr += zBuffer->getWidth(); maj.x += maj.xStep; maj.z += maj.zStep; minorX += minorXStep; } height = minor2.height; minorX = minor2.x; minorXStep = minor2.xStep; } while (section++ == 0); } void CLASS::doSmoothTriangleZb(edge_major_smooth &maj, edge_minor_step &minor1, edge_minor_step &minor2, const ColourRamp &ramp ) { PIXELTYPE *scan_ptr = ((PIXELTYPE *)device->getBuffer()) + maj.yMin *device->getWidth(); uint *scan_zptr = zBuffer->getBuffer() + maj.yMin * zBuffer->getWidth(); maj.z += zBuffer->getGenerationMask(); maj.i += 128; const Colour *rampdata = ramp.getRamp(); int height = minor1.height; int minorX = minor1.x; edge_minor_step *minor = &minor1; int section = 0; int incr = maj.incr; do { while(height--) { int width = maj.x - minorX; if (width != 0) { // if ((width^incr) < 0) { PIXELTYPE *ptr = scan_ptr + maj.x; uint *zptr = scan_zptr + maj.x; int i = maj.i; uint z = maj.z; uint z0 = *zptr; do { if (z < z0) { *zptr = z; *ptr = rampdata[(i>>8)]; //*ptr = (i>>8)&255; //*ptr = (z>>16)&255; } zptr += incr; ptr += incr; z += maj.dz_dx; i += maj.di_dx; z0 = *zptr; width += incr; } while (width); //} else { //return; //} } scan_ptr += device->getWidth(); scan_zptr += zBuffer->getWidth(); minorX += minor->xStep; minor->error += minor->numerator; if (minor->error >= 0) { minorX++; minor->error -= minor->denominator; } maj.z += maj.zStep; maj.i += maj.iStep; maj.x += maj.xStep; maj.error += maj.numerator; if(maj.error >= 0) { maj.x++; maj.error -= maj.denominator; maj.i += maj.iStepExtra; maj.z += maj.zStepExtra; } } minorX = minor2.x; height = minor2.height; minor = &minor2; } while (section++ == 0); } /* void CLASS::lineZb(const DeviceVector &from, const DeviceVector &to, DeviceColour colour) { DeviceVector from1(from); DeviceVector to1(to); from1.v[0] >>= LOG_UNITY; from1.v[1] >>= LOG_UNITY; to1.v[0] >>= LOG_UNITY; to1.v[1] >>= LOG_UNITY; DitherViewport::lineZb(from1, to1, colour); } void Line(int x0,int y0,int x1,int y1) { int dx,ix,cx,dy,iy,cy,m,i; if (x0 < x1) { dx=x1-x0; ix=1; } else { dx=x0-x1; ix=-1; } if (y0 < y1) { dy=y1-y0; iy=1; } else { dy=y0-y1; iy=-1; } if (dx > dy) m=dx; else m=dy; cx=cy=(m >> 1); for (i=0; i < m; i++) { //Pixel(x0,y0); if ((cx+=dx)>=m) { cx-=m; x0+=ix; } if ((cy+=dy)>=m) { cy-=m; y0+=iy; } } } */ void CLASS::lineZb(const DeviceVector &from, const DeviceVector &to, DeviceColour colour) { int x0 = from.v[X]; int y0 = from.v[Y]; uint z0 = from.v[Z] + zBuffer->getGenerationMask(); int dy, is, iz; int dx, ix; if (x0 < to.v[X]) { dx=to.v[X]-x0; ix=1; } else { dx=x0-to.v[X]; ix=-1; } int swidth = device->getWidth(); int zwidth = zBuffer->getWidth(); if (y0 < to.v[Y]) { dy=to.v[Y]-y0; is=swidth; iz=zwidth; } else { dy=y0-to.v[Y]; is=-swidth; iz=-zwidth; } // need to do initial adjustment int yMin = y0 >> LOG_UNITY; PIXELTYPE *scan_ptr = ((PIXELTYPE *)device->getBuffer()) + yMin * swidth; uint *zptr = zBuffer->getBuffer() + yMin * zwidth; int dz = to.v[Z] - from.v[Z]; if (dx > dy) { uint z = *zptr; int i = dx>>LOG_UNITY; if (!i) return; int cy = dx>>1; int cz = dz/i; int x = x0>>LOG_UNITY; do { if (z0 < z) { zptr[x] = z0; scan_ptr[x] = colour; } x += ix; if ((cy+=dy)>=dx) { zptr += iz; scan_ptr += is; cy-=dx; } z0 += cz; z = *zptr; i--; } while (i); } else { uint z = *zptr; int i = dy>>LOG_UNITY; if (!i) return; int cx= dy>>1; int cz = dz/i; int x = x0>>LOG_UNITY; do { if (z0 < z) { zptr[x] = z0; scan_ptr[x] = colour; } scan_ptr += is; zptr += iz; if ((cx+=dx)>=dy) { x += ix; cx -= dy; } z0 += cz; z = *zptr; i--; } while (i); } }