static void SetEdgeLineVisibility (Facet& f, int a, int AzmStride, int p, int PolStride, bool ReverseOrientation = false) { // no individual setting, visibility is either true or false if (AzmStride == 1 && PolStride == 1) return; // individual setting int mask = 0; // three or four vertices if (ReverseOrientation) { if ((a+1) % AzmStride == 0) mask |= 4; if ( a % AzmStride == 0) mask |= 1; } else { if ((a+1) % AzmStride == 0) mask |= 1; if ( a % AzmStride == 0) mask |= 4; } if (p % PolStride == 0) mask |= 2; // four vertices if (f.GetNumVertices() == 4) if ((p+1) % PolStride == 0) mask |= 8; // set edge line visibility f.SetEdgeLineVisibility(Facet::Individual,mask); }
void Scene::WireFacet (Facet& f) { // number of vertices int n = f.GetNumVertices(); // remember previous line color ColorF previous_color = foreground_color; // ======================================================= // testing: fog for edgelines to get a depth cueing effect // ======================================================= if (fog_opacity) { float cx,cy,cz; f.Center(cx,cy,cz); // wastes time ! SetColor( ColorF_Weighted(0.5*(1-tanh((6/fog_opacity) *(hypot(cx,cy,cz)-fog_distance-1))), previous_color,fog_color) ); } // facet is degenerate (a line) if (n == 2) // THROW OUT !!!!!!!!!!!!!! Line( f[0].p,f[1].p ); // loop through edges else if (f.edgelines == Facet::Individual) { for (int i = 0, j = n-1; i < n; j = i++) if (f.GetEdgeLine(j)) Line( f[j].p,f[i].p ); } else for (int i = 0, j = n-1; i < n; j = i++) Line( f[j].p,f[i].p ); // reset previous color if (fog_opacity) SetColor(previous_color); }
void Scene::ConstantFacet (Facet& f) // // Uses the global intermediate storage array pix. // { int i,j; short r,g,b; long color; // number of vertices int n = f.GetNumVertices(); // facet is degenerate (a line) ----- CURRENTLY DEGENERATE NOT ALLOWED if (n == 2) { Line(f[0].p,f[1].p); return; } // can't happen ! if (n < 2 || n > MaxVertices) { Warn("Scene::ConstantFacet: number of vertices out of range"); return; } if (coloring == Global) { r = (short)(mat.color.red * 255); // normalize to 0..255 g = (short)(mat.color.green * 255); b = (short)(mat.color.blue * 255); } else { // per-facet colors are assumed r = f.front.red; g = f.front.green; b = f.front.blue; } // copy projected vertex coordinates to polygon array for (i = 0; i < n; i++) pix[i] = f[i].p; // find color in colormap color = LookupColor(r,g,b,&mat); // draw outlines if requested if (edgelines == 1) Polygon(n,pix,color,Outline|Fill); else if (edgelines == 0) Polygon(n,pix,color,Fill); else if (edgelines == Facet::Individual ) { if (f.edgelines == 1) Polygon(n,pix,color,Outline|Fill); else if (f.edgelines == 0) Polygon(n,pix,color,Fill); else if (f.edgelines == Facet::Individual) { Polygon(n,pix,color,Fill); for (i = 0, j = n-1; i < n; j = i++) if ( f.GetEdgeLine(j) ) Line(pix[j],pix[i]); } } }
void stellate (Scene &body, float height) // // Adds starlike jags to every facet of the body. The tip // of a jag is placed in the given height over the center // of the facet. // { float nx,ny,nz,nk,nn,cx,cy,cz,h; Vertex* tip; Facet* f; int i,j,n; Scene stella; for (f = body.TheFacets(); f; f = f->NextFacet() ) { // calculate the normal form and the center of the facet f->Normal(nx,ny,nz,nk); f->Center(cx,cy,cz); // normalization of the normal vector to unit length nn = hypot(nx,ny,nz); // check if facet is degenerate if (nn == 0) continue; // add the tip vertex of the jag h = height / nn; tip = &stella.AddVertex( cx+h*nx, cy+h*ny, cz+h*nz ); // add three-sided facets for each side of the jag n = f->GetNumVertices(); for (i = 0, j = n-1; i < n; j = i++) { Facet& s = stella.AddFacet(3); s(0) = &stella.AddVertex( *(*f)(j) ); s(1) = &stella.AddVertex( *(*f)(i) ); s(2) = tip; } } // now clear the original body.Remove(); // and add the stellated body instead (duplicate vertices are now removed) body.AddScene(stella,Identity); }
void Scene::WireFrame (void) ///// UNUSED CURRENTLY !!!!!!!!!!!!!!!!!!!!! { // remember previous line color ColorF previous_color = foreground_color; for (Facet *f = facets; f; f = f->next) { // clipped facets are invisible if ( ! f->clipped ) { // ======================================================= // testing: fog for edgelines to get a depth cueing effect // ======================================================= if (fog_opacity) { float cx,cy,cz; f->Center(cx,cy,cz); // wastes time ! SetColor( ColorF_Weighted(0.5*(1-tanh((6/fog_opacity) *(hypot(cx,cy,cz)-fog_distance-1))), previous_color,fog_color) ); } int n = f->GetNumVertices(); if (n == 2) Line( (*f)[0].p,(*f)[1].p ); else for (int i = 0, j = n-1; i < n; j = i++) { // don't draw line twice for closed bodies if ( ! facetculling || (facetculling && ( &(*f)[j] < &(*f)[i] )) ) Line( (*f)[j].p,(*f)[i].p ); } } } // reset previous color if (fog_opacity) SetColor(previous_color); }
void Scene::GouraudFacet (Facet& f) // // Draws a facet using Gourauds's color interpolation model. // A scan line approach is taken for drawing this facet. // // Uses the global intermediate storage array pix. // // If outline == True then the facet ist outlined using the // current line drawing color. // { float rstep,gstep,bstep,rr,gg,bb; long /*previous_color,*/ color; int maxy,miny,maxx,minx,k,mono; Pixel2D p; // number of vertices int n = f.GetNumVertices(); // facet is degenerate or has too many facets if (n < 3 || n > MaxVertices) return; Material *Mp; static Material M; if (coloring == PerVertex) { if (f.material) { M.ambient = f.material->ambient; M.specular = f.material->specular; M.exponent = f.material->exponent; } else { M.ambient = mat.ambient; M.specular = mat.specular; M.exponent = mat.exponent; } Mp = &M; } else if (coloring == Global) { Mp = f.GetMaterial(); } else /* (coloring == PerFacet) */ { M.color = f.front; if (f.material) { M.ambient = f.material->ambient; M.specular = f.material->specular; M.exponent = f.material->exponent; } else { M.ambient = mat.ambient; M.specular = mat.specular; M.exponent = mat.exponent; } Mp = &M; } // remember previous line color //previous_color = linecolor; ColorF previous_color = foreground_color; maxy = miny = f[0].p.py; for (int i = 0; i < n; i++) { const Vertex& Vi = f[i]; // copy projected vertex coordinates to polygon array pix[i] = Vi.p; // find minimum and maximum y-value if (pix[i].py > maxy) maxy = pix[i].py; else if (pix[i].py < miny) miny = pix[i].py; // get color at each vertex (vertex color + illumination effect) if (coloring == PerVertex) { M.color.red = float(Vi.red) / 255; M.color.green = float(Vi.green) / 255; M.color.blue = float(Vi.blue) / 255; } PhongColor(Vi.x,Vi.y,Vi.z, Vi.nx,Vi.ny,Vi.nz, Mp,r[i],g[i],b[i]); } // special case of a black/and white display if (displaymono) { Polygon(n,pix,White,Fill); // draw a white background polyogon SetColor(Black); // set foreground color to black for the dots } // fill facet using a scan line approach // loop through the scanlines // -------------------------- for ( p.py = miny; p.py <= maxy; (p.py)++ ) { // polygon is wider than 30000 pixel minx = 30000; maxx = -30000; int imin = 0, imax = 0; for (int i = 0, j = n-1; i < n; j = i++) { int pjy = pix[j].py, piy = pix[i].py; if ((pjy != piy) && (pjy >= p.py || piy >= p.py) && (pjy <= p.py || piy <= p.py)) { float mu = float(p.py-pjy)/float(piy-pjy), mu1 = 1.0-mu; k = int(mu1*pix[j].px+mu*pix[i].px+0.5); if (k < minx) { minx = k; // minimum x imin = i; } if (k > maxx) { maxx = k; // maximum x imax = i; } } } { int i = imin, j = i ? i-1 : n-1, dpy = pix[i].py-pix[j].py; float mu = dpy ? float(p.py-pix[j].py)/float(dpy) : 0, mu1 = 1.0-mu; // minimum values rr = mu1 * r[j] + mu * r[i]; gg = mu1 * g[j] + mu * g[i]; bb = mu1 * b[j] + mu * b[i]; } if (minx < maxx) { int i = imax, j = i ? i-1 : n-1, dpy = pix[i].py-pix[j].py; float mu = dpy ? float(p.py-pix[j].py)/float(dpy) : 0, mu1 = 1.0-mu; // steps float dx = float(maxx-minx); rstep = (mu1 * r[j] + mu * r[i] - rr)/dx; gstep = (mu1 * g[j] + mu * g[i] - gg)/dx; bstep = (mu1 * b[j] + mu * b[i] - bb)/dx; } else rstep = gstep = bstep = 0; if (displaymono) { // for a monochrome display - ditherized for (p.px = minx; p.px <= maxx; ++(p.px)) { // compute the monochrome intensity - scale from 0..255 to 0..63 // and diherize using Bayer's algorithm mono = (int)(0.30*rr+0.59*gg+0.11*bb) >> 2; if (mono < Bayer_Dithering_8x8 [p.px & 7][p.py & 7]) Dot(p); rr += rstep; gg += gstep; bb += bstep; } } else if (colordither) { // for a color display - ditherized for (p.px = minx; p.px <= maxx; ++(p.px)) { // scale from 0..255 to 0..15 // and ditherize using Bayer's algorithm int red,green,blue; red = (int)rr >> 4; green = (int)gg >> 4; blue = (int)bb >> 4; // map to color table (fixed entries 0..8) color = ((blue > Bayer_Dithering_4x4 [p.px & 3][p.py & 3])?1:0) | ((green > Bayer_Dithering_4x4 [p.px & 3][p.py & 3]?1:0)<<1) | ((red > Bayer_Dithering_4x4 [p.px & 3][p.py & 3]?1:0)<<2); Dot(p,color); // color is a color table index rr += rstep; gg += gstep; bb += bstep; } } else { // for a color display - non-ditherized for (p.px = minx; p.px <= maxx; ++(p.px)) {
void Scene::FlatFacet (Facet& f) // // If shading is 'Flat' the facet is drawn using flat shading, otherwise // if shading is 'false' it will be filled with the background color. // // Uses the global intermediate storage array pix. // { int i,j; float cx,cy,cz,nx,ny,nz,nk; short r,g,b; long color; // number of vertices int n = f.GetNumVertices(); // facet is degenerate (a line) ----- CURRENTLY DEGENERATE NOT ALLOWED if (n == 2) { Line(f[0].p,f[1].p); return; } // can't happen ! if (n < 2 || n > MaxVertices) { Warn("Scene::FlatFacet: number of vertices out of range"); return; } static Material M; Material *Mp; if (coloring == Global) { Mp = f.GetMaterial(); } else { M.color = f.front; if (f.material) { M.ambient = f.material->ambient; M.specular = f.material->specular; M.exponent = f.material->exponent; } else { M.ambient = mat.ambient; M.specular = mat.specular; M.exponent = mat.exponent; } Mp = &M; } // copy projected vertex coordinates to polygon array for (i = 0; i < n; i++) pix[i] = f[i].p; // compute color of facet from reflection properties if (shading == Facet::Flat) { f.Normal(nx,ny,nz,nk); f.Center(cx,cy,cz); PhongColor(cx,cy,cz,nx,ny,nz,Mp,r,g,b); // find color in colormap //color = LookupColor(r,g,b,f.GetMaterial()); color = LookupColor(r,g,b,&mat); // else if (shading == false) then use the background color } else color = backcolor; // ======================================================= // testing: fog for edgelines to get a depth cueing effect // ======================================================= ColorF previous_color; if (fog_opacity) { previous_color = foreground_color; SetColor( ColorF_Weighted(0.5*(1-tanh((6/fog_opacity) *(hypot(cx,cy,cz)-fog_distance-1))), previous_color,fog_color) ); } // draw outlines if requested if (edgelines == 1) Polygon(n,pix,color,Outline|Fill); else if (edgelines == 0) Polygon(n,pix,color,Fill); else if (edgelines == Facet::Individual ) { if (f.edgelines == 1) Polygon(n,pix,color,Outline|Fill); else if (f.edgelines == 0) Polygon(n,pix,color,Fill); else if (f.edgelines == Facet::Individual) { Polygon(n,pix,color,Fill); for (i = 0, j = n-1; i < n; j = i++) if ( f.GetEdgeLine(j) ) Line(pix[j],pix[i]); } } if (fog_opacity) SetColor(previous_color); }