// 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. #include #include #include Viewport *Viewport::children = 0; Viewport * Viewport::create( Device *device ) { if (device == 0 || device->isBad()) return 0; const char *viewportString; if ((viewportString = getenv("R_VIEWPORT")) != 0) { for (Viewport *child = children ; child ; child = child->next) { if (strcmp(viewportString, child->getName()) == 0) { ::debug() << "Trying viewport: " << child->getName() << endlog; Viewport *viewport = child->clone( device ); if (viewport && viewport->isGood()) { return viewport; } ::debug() << "Failed to create viewport: " << child->getName() << endlog; delete viewport; } } } for (Viewport *child = children ; child ; child = child->next) { if (child->quality == 0) continue; ::debug() << "Trying viewport: " << child->getName() << endlog; Viewport *viewport = child->clone( device ); if (viewport && viewport->isGood()) { return viewport; } ::debug() << "Failed to create viewport: " << child->getName() << endlog; delete viewport; } delete device; return 0; } Viewport::Viewport( Exemplar, uint quality ) : quality(quality), next(0), device(0), zBuffer(0) { if (children == 0) { children = this; return; } Viewport **child; for (child = &children; (**child).next; child = &((**child).next)){ if ((*child)->quality < quality) { next = *child; *child = this; return; } } (*child)->next = this; } Viewport::Viewport( Device *device, uint xscale, uint yscale ) : next(0), xscale(xscale), yscale(yscale), coordinateWidth( device->getWidth() * xscale ), coordinateHeight( device->getHeight() * yscale ), extensions(0), device( device ) { zBuffer = new ZBuffer( *device ); deviceTransform.setIdentity(); deviceTransform.scale(coordinateWidth/2, coordinateHeight/2, zBuffer->getScale() ); deviceTransform.translate(coordinateWidth/2, coordinateHeight/2, 0); } Viewport::~Viewport() { delete device; delete zBuffer; delete next; } void Viewport::swapBuffers() { device->swapBuffers(); device->clearBuffer(); zBuffer->clear(); } void Viewport::clearZBuffer() { zBuffer->clear(); } void Viewport::notifyResize() { if (device) { zBuffer->resize( device->getWidth(), device->getHeight() ); coordinateWidth = device->getWidth() * xscale; coordinateHeight = device->getHeight() * yscale; deviceTransform.setIdentity(); deviceTransform.scale(coordinateWidth/2, coordinateHeight/2, zBuffer->getScale() ); deviceTransform.translate(coordinateWidth/2, coordinateHeight/2, 0); if_debug debug() << *this << endlog; } } inline uchar computeOutcodes( int x, int y, int width, int height ) { uint oc = 0; if (y > height) { oc = 0x1; } else if (y < 0) { oc = 0x2; } if (x > width) { return oc|0x4; } else if (x < 0) { return oc|0x8; } return oc; } void Viewport::lineZb(const DeviceVector &, const DeviceVector &, DeviceColour ) { } void Viewport::clipLine(const DeviceVector &a, const DeviceVector &b, DeviceColour colour) { int x0 = a.v[X]; int y0 = a.v[Y]; int x1 = b.v[X]; int y1 = b.v[Y]; int width = getCoordinateWidth(); int height = getCoordinateHeight(); uchar oc0 = computeOutcodes(x0, y0, width, height); uchar oc1 = computeOutcodes(x1, y1, width, height); while(oc0|oc1) { if (oc0 & oc1) { return; } if (oc0) { if (oc0 & 0x1) { x0 = int(x0 + (x1 - x0) * (height - y0)/float(y1 - y0)); y0 = height; } else if (oc0 & 0x2) { x0 = int(x0 + (x1 - x0) * (-y0)/float(y1 - y0)); y0 = 0; } else if (oc0 & 0x4) { y0 = int(y0 + (y1 - y0) * (width - x0)/float(x1 - x0)); x0 = width; } else if (oc0 & 0x8) { y0 = int(y0 + (y1 - y0) * (-x0)/float(x1 - x0)); x0 = 0; } oc0 = computeOutcodes(x0, y0, width, height); } else if (oc1) { if (oc1 & 0x1) { x1 = int(x0 + (x1 - x0) * (height - y0)/float(y1 - y0)); y1 = height; } else if (oc1 & 0x2) { x1 = int(x0 + (x1 - x0) * (-y0)/float(y1 - y0)); y1 = 0; } else if (oc1 & 0x4) { y1 = int(y0 + (y1 - y0) * (width - x0)/float(x1 - x0)); x1 = width; } else if (oc1 & 0x8) { y1 = int(y0 + (y1 - y0) * (-x0)/float(x1 - x0)); x1 = 0; } oc1 = computeOutcodes(x1, y1, width, height); } } DeviceVector c(x0,y0,0); // well... DeviceVector d(x1,y1,0); lineZb(c, d, colour); } ostream & Viewport::print( ostream &out ) const { return Debuggable::print(out) << "\n\twidth:"<setDirty(xmin, ymin, xmax, ymax); zBuffer->setDirty(xmin, ymin, xmax, ymax); } // Fallback implementations. void Viewport::smoothPolygonZb(uint nrVertices, SmoothPipelineData * const vertices[], const ColourRamp &colour) { flatPolygonZb(nrVertices, (PipelineData *const[])vertices, colour.getColour(127)); } void Viewport::smoothTriangleZb(SmoothPipelineData * const vertices[], const ColourRamp &colour) { smoothPolygonZb(3, vertices, colour); } void Viewport::flatTriangleZb(PipelineData * const vertices[], Colour colour) { flatPolygonZb(3, vertices, colour); } void Viewport::wireTriangle(PipelineData * const vertex[], Colour colour ) { // Only draw the downward, righward slanting edges. For closed // polyhedral models without backface culling, in the absence of // clipping, no edges will be missed. It would be preferable not // to draw any clipped edges. if (vertex[2]->device.v[Y] < vertex[0]->device.v[Y] || (vertex[2]->device.v[Y] == vertex[0]->device.v[Y] && vertex[2]->device.v[X] < vertex[0]->device.v[X])) lineZb( vertex[2]->device, vertex[0]->device, colour ); if (vertex[0]->device.v[Y] < vertex[1]->device.v[Y] || (vertex[0]->device.v[Y] == vertex[1]->device.v[Y] && vertex[0]->device.v[X] < vertex[1]->device.v[X])) lineZb( vertex[0]->device, vertex[1]->device, colour ); if (vertex[1]->device.v[Y] < vertex[2]->device.v[Y] || (vertex[1]->device.v[Y] == vertex[2]->device.v[Y] && vertex[1]->device.v[X] < vertex[2]->device.v[X])) lineZb( vertex[1]->device, vertex[2]->device, colour ); } void Viewport::wirePolygon(uint nr, PipelineData * const vertex[], Colour colour ) { uint j = nr - 1; for (uint i = 0 ; i < nr ; i++) { if (vertex[j]->device.v[Y] < vertex[i]->device.v[Y] || (vertex[j]->device.v[Y] == vertex[i]->device.v[Y] && vertex[j]->device.v[X] < vertex[i]->device.v[X])) lineZb( vertex[j]->device, vertex[i]->device, colour ); j = i; } } void Viewport::texturePolygonZb(uint , TexturePipelineData * const [], const Texture &) { return; } void Viewport::textureTriangleZb(TexturePipelineData * const [], const Texture &) { return; }