open-axiom repository from github
/*1Copyright (C) 1991-2002, The Numerical ALgorithms Group Ltd.2All rights reserved.3Copyright (C) 2007-2010, Gabriel Dos Reis.4All rights reserved.56Redistribution and use in source and binary forms, with or without7modification, are permitted provided that the following conditions are8met:910- Redistributions of source code must retain the above copyright11notice, this list of conditions and the following disclaimer.1213- Redistributions in binary form must reproduce the above copyright14notice, this list of conditions and the following disclaimer in15the documentation and/or other materials provided with the16distribution.1718- Neither the name of The Numerical ALgorithms Group Ltd. nor the19names of its contributors may be used to endorse or promote products20derived from this software without specific prior written permission.2122THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS23IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED24TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A25PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER26OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,27EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,28PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR29PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF30LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING31NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.33*/3435#define _SMOOTHSHADE_C36#include "openaxiom-c-macros.h"3738#include <string.h>39#include <math.h>40#include <stdlib.h>4142#include "header.h"43#include "draw.h"44#include "volume.h"45#include "mode.h" /* for #define components */4647#include "spadcolors.h"48#include "Gfun.H1"49#include "util.H1"50#include "XSpadFill.h"51#include "all_3d.H1"5253#define SAFE_VALUE 89234754555657585960char61get_cBuffer_axes(int ix)62{63if( ix >=0 && ix <ARRAY_WIDTH) return (cBuffer[ix].axes);64return ('0');65}6667void68put_cBuffer_axes(int ix,char val)69{70if( ix >=0 && ix <ARRAY_WIDTH) cBuffer[ix].axes = val;71}7273int74get_cBuffer_indx(int ix)75{76if( ix >=0 && ix <ARRAY_WIDTH) return (cBuffer[ix].indx);77return (-1);78}7980void81put_cBuffer_indx(int ix,int val)82{83if( ix >=0 && ix <ARRAY_WIDTH) cBuffer[ix].indx = val;84}8586void87put_zBuffer(int ix,float val)88{89if (ix >=0 && ix <ARRAY_WIDTH) zBuffer[ix] = val;90}9192float93get_zBuffer(int ix)94{95return (zBuffer[ix]);96}9798void99put_imageX(int ix,char val)100{101if (ix <=0 && ix <vwInfo.width) imageX->data[ix] = val;102}103104105106107/***************************108* void drawPhongSpan() *109* *110* This routine sets the *111* buffer values for each *112* span of pixels which *113* intersect the current *114* scanline. *115***************************/116void117drawPhongSpan(triple pt,float N[3],int dFlag)118{119int xpixel,hue,shade;120float colorindx, col;121triple hs;122123124/* negative values of xleft and xright have been pushed to machine0 */125126xpixel = (int)xleft;127128129while (xpixel <= (int)xright) {130/* if z is closer to viewer than value in zBuffer continue */131if ( (zC < get_zBuffer(xpixel)) ) {132/* get the intensity for current point */133col = phong(pt,N);134put_cBuffer_axes(xpixel,'0');135put_zBuffer(xpixel,zC);136/* if mono (bw dsply) do black and white semi-random dithering */137if (mono || (dFlag == PSoption) || viewport->monoOn) {138if (get_random() < 100.0*exp((double)-1.3*(pi_sq*(col-.2)*(col-.2)))) {139put_cBuffer_indx(xpixel,black);140} else {141put_cBuffer_indx(xpixel,white);142}143} else {144/* glossy shading for one hue else dithered for many hues */145if (viewport->hueOffset == viewport->hueTop && !smoothError) {146colorindx = (float)(smoothConst+1) * col;147if (colorindx > (smoothConst+1)) colorindx = smoothConst+1;148put_cBuffer_indx(xpixel,XPixelColor((int)colorindx-1));149} else { /* probabalistic multi-hued dithering */150hs = norm_dist();151hue = (int)(intersectColor[0]+hs.x/20.0);152/* cannot dither out of color map range */153if (viewport->hueOffset < viewport->hueTop) {154if (hue < viewport->hueOffset)155hue = viewport->hueOffset;156else {157if (hue > viewport->hueTop)158hue = viewport->hueTop;159}160} else {161if (hue < viewport->hueTop)162hue = viewport->hueTop;163else {164if (hue > viewport->hueOffset)165hue = viewport->hueOffset;166}167}168col += hs.y/6.0; /* perturb intensity */169if (col > 1.0) put_cBuffer_indx(xpixel,white);170else {171if (col < 0.0) put_cBuffer_indx(xpixel,black);172else {173shade = (int)(col * 4.0);174put_cBuffer_indx(xpixel,XSolidColor(hue,shade));175}176}177}178}179} /* zC < zBuffer */180zC += dzdx;181if (viewport->hueOffset != viewport->hueTop || smoothError ||182viewport->monoOn)183intersectColor[0] += dcolor;184N[0] += dnorm.x; N[1] += dnorm.y; N[2] += dnorm.z;185pt.x += dpt.x; pt.y += dpt.y; pt.z += dpt.z;186xpixel++;187} /* while each pixel */188189}190191192/***************************193* void scanPhong() *194* *195* This routine takes all *196* polygons that intersect *197* with the current scan- *198* line and calculates the *199* intersecting x and z *200* points as well as the *201* color at each point. *202* Interpolation is done *203* according to Phong. *204***************************/205206void207scanPhong(int dFlag)208{209viewTriple *p1, *p2;210polyList *polygon;211poly *p;212int i,num,xtemp,numttt;213int *anIndex, *start, *end;214float x1,x2,y1,y2,z2,zright,wx1,wx2,wy1,wy2,wz1,wz2;215float intersectionx[2], intersectionz[2];216float c1,c2,colortemp,ztemp,dY,diffy,diffx,n1[3],n2[3],NV[3];217triple ntemp, intersectPt[2], ptemp, pt, intersectN[2];218219/* polygon list intersecting the current scanline, will be modified to220edge list structure */221polygon = scanList[scanline];222while (polygon != NIL(polyList) && polygon->polyIndx != NIL(poly) ) {223/* for each polygon in the list */224p = polygon->polyIndx;225/* don't include clipped polygons */226if ( ! ( p->partialClipPz ||227p->totalClipPz ||228(viewData.clipStuff && (p->partialClip || p->totalClip ) ) ) ) {229num = 0; /* 0 & 1, for the 2 edges of polygon that intersect scanline */230numttt =0;231232if ((scanline >= (int)p->pymin) && (scanline <= (int)p->pymax)) {233/* which edges of the polygon intersect the scanline */234for (i=0, anIndex=p->indexPtr; i<p->numpts; i++) {235start = anIndex + i;236p1 = refPt3D(viewData,*(start));237x1 = p1->px; y1 = p1->py; zC = p1->pz; c1 = p1->sc;238/* if (x1 < machine0){ x1 = machine0; } */239wx1 = p1->wx; wy1 = p1->wy; wz1 = p1->wz;240n1[0] = p1->norm[0]; n1[1] = p1->norm[1]; n1[2] = p1->norm[2];241end = (i != (p->numpts - 1)) ? anIndex + (i + 1) : anIndex;242p2 = refPt3D(viewData,*(end));243x2 = p2->px; y2 = p2->py; z2 = p2->pz; c2 = p2->sc;244/* if (x2 < machine0){ x2 = machine0; } */245wx2 = p2->wx; wy2 = p2->wy; wz2 = p2->wz;246n2[0] = p2->norm[0]; n2[1] = p2->norm[1]; n2[2] = p2->norm[2];247/* find beginning and end for intersecting edge */248if ((scanline < y1 && scanline >= y2) ||249(scanline >= y1 && scanline < y2)) {250dY = (float)scanline - y1;251diffy = y2 - y1;252if (absolute(diffy) < 0.01) diffy = 1.0;253intersectionx[num] = x1 + ((x2-x1)/diffy) * dY;254intersectionz[num] = zC + ((z2-zC)/diffy) * dY;255if (viewport->hueOffset != viewport->hueTop || smoothError ||256viewport->monoOn)257intersectColor[num] = c1 + ((c2 - c1)/diffy) * dY;258intersectN[num].x = n1[0] + ((n2[0] - n1[0])/diffy)*dY;259intersectN[num].y = n1[1] + ((n2[1] - n1[1])/diffy)*dY;260intersectN[num].z = n1[2] + ((n2[2] - n1[2])/diffy)*dY;261intersectPt[num].x = wx1 + ((wx2 - wx1)/diffy)*dY;262intersectPt[num].y = wy1 + ((wy2 - wy1)/diffy)*dY;263intersectPt[num].z = wz1 + ((wz2 - wz1)/diffy)*dY;264num = 1-num;265numttt++;266} /* if edge intersects scanline */267} /* for each edge */268if (numttt>=2) { /* if numttt 0 or 1 something has gone wrong */269xleft = intersectionx[0]; xright = intersectionx[1];270zC = intersectionz[0]; zright = intersectionz[1];271/* edges are drawn from left to right, so switch if necessary */272if (xright < xleft) {273xtemp = xright; xright = xleft; xleft = xtemp;274ztemp = zright; zright = zC; zC = ztemp;275if (viewport->hueOffset != viewport->hueTop || smoothError ||276viewport->monoOn) {277colortemp = intersectColor[1];278intersectColor[1] = intersectColor[0];279intersectColor[0] = colortemp;280}281ntemp = intersectN[1]; intersectN[1] = intersectN[0];282intersectN[0] = ntemp;283ptemp = intersectPt[1];284intersectPt[1] = intersectPt[0];285intersectPt[0] = ptemp;286}287diffx = xright - xleft;288if (absolute(diffx) > .01) {289if (viewport->hueOffset != viewport->hueTop || smoothError ||290viewport->monoOn)291dcolor = (intersectColor[1] - intersectColor[0]) / diffx;292dnorm.x = (intersectN[1].x - intersectN[0].x) / diffx;293dnorm.y = (intersectN[1].y - intersectN[0].y) / diffx;294dnorm.z = (intersectN[1].z - intersectN[0].z) / diffx;295dpt.x = (intersectPt[1].x - intersectPt[0].x) / diffx;296dpt.y = (intersectPt[1].y - intersectPt[0].y) / diffx;297dpt.z = (intersectPt[1].z - intersectPt[0].z) / diffx;298dzdx = (zright - zC) / diffx;299} else {300if (viewport->hueOffset != viewport->hueTop || smoothError ||301viewport->monoOn)302dcolor = intersectColor[1];303dnorm.x = 0.0; dnorm.y = 0.0; dnorm.z = 0.0;304dpt.x = 0.0; dpt.y = 0.0; dpt.z = 0.0;305dzdx = 0.0;306}307NV[0] = intersectN[0].x;308NV[1] = intersectN[0].y;309NV[2] = intersectN[0].z;310pt.x = intersectPt[0].x;311pt.y = intersectPt[0].y;312pt.z = intersectPt[0].z;313drawPhongSpan(pt,NV,dFlag);314} /* numttt guard */315} /* if scanline intersect */316} /* clipped */317polygon = polygon->next;318} /* while still polygons */319320}321322/********************************************323* boxTObuffer() writes the projection of *324* the x,y bounding box to the z-buffer. *325********************************************/326327void328boxTObuffer(void)329{330int xpix,i,j,k,count,decision;331int xA,xB,yA,yB;332float x,xend,y,yend,diffy,dX,dY,dXY,intersectionx;333334for (i=0;i<6;i++) {335if (box[i].inside) {336for (j=0; j<3; j++) {337quadMesh[j].x = box[i].pointsPtr[j]->px;338quadMesh[j].y = box[i].pointsPtr[j]->py;339}340341intersectionx = 0.0;342for (k=0; k<2; k++) {343xA = quadMesh[k].x; yA = quadMesh[k].y;344xB = quadMesh[k+1].x; yB = quadMesh[k+1].y;345346/*347if (xA > graphWindowAttrib.width+1) xA = graphWindowAttrib.width+1;348if (xB > graphWindowAttrib.width+1) xB = graphWindowAttrib.width+1;349if (yA > graphWindowAttrib.height) yA = graphWindowAttrib.height;350if (yB > graphWindowAttrib.height) yB = graphWindowAttrib.height;351if (xA < 0) xA = 0; if (xB < 0) xB = 0;352if (yA < 0) yA = 0; if (yB < 0) yB = 0;353*/354x = xA; xend = xB; y = yA; yend = yB;355diffy = (float)scanline - y;356dX = xend - x; dY = yend - y;357if (absolute(dY) > machine0) {358dXY = dX/dY;359} else {360dXY = dX;361}362363if (dXY < 0.0) dXY = -dXY;364365if ((scanline == (int)y) && (absolute(dY) <= 1.0)) {366if (x <= xend) {367for (xpix = (int)x; xpix <= (int)xend; xpix++) {368put_cBuffer_axes(xpix,'b');369}370} else {371for (xpix = (int)x; xpix >= (int)xend; xpix--) {372put_cBuffer_axes(xpix,'b');373}374}375} else {376if (xend < x)377decision = (scanline < y && scanline >= yend) ||378(scanline > y && scanline <= yend);379else380decision = (scanline <= y && scanline > yend) ||381(scanline >= y && scanline < yend);382if (decision) {383intersectionx = x + dX/dY * diffy;384for (count = (int)intersectionx;385count <= (int)intersectionx + (int)dXY; count++) {386put_cBuffer_axes(count,'b');387}388}389}390}391392}393}394395}396397/********************************************398* clipboxTObuffer() writes the projection *399* of the x,y,z clipping region box to the *400* z-buffer. *401********************************************/402403void404clipboxTObuffer(void)405{406int xpix,i,j,k,count,decision;407int xA,xB,yA,yB;408float x,xend,y,yend,diffy,dX,dY,dXY,intersectionx;409410for (i=0;i<6;i++) {411if (clipBox[i].inside) {412for (j=0; j<3; j++) {413quadMesh[j].x = clipBox[i].pointsPtr[j]->px;414quadMesh[j].y = clipBox[i].pointsPtr[j]->py;415}416417intersectionx = 0.0;418for (k=0; k<2; k++) {419xA = quadMesh[k].x; yA = quadMesh[k].y;420xB = quadMesh[k+1].x; yB = quadMesh[k+1].y;421/*422423if (xA > graphWindowAttrib.width+1) xA = graphWindowAttrib.width+1;424if (xB > graphWindowAttrib.width+1) xB = graphWindowAttrib.width+1;425if (yA > graphWindowAttrib.height) yA = graphWindowAttrib.height;426if (yB > graphWindowAttrib.height) yB = graphWindowAttrib.height;427if (xA < 0) xA = 0; if (xB < 0) xB = 0;428if (yA < 0) yA = 0; if (yB < 0) yB = 0;429*/430x = xA; xend = xB; y = yA; yend = yB;431diffy = (float)scanline - y;432dX = xend - x; dY = yend - y;433if (absolute(dY) > machine0) {434dXY = dX/dY;435} else {436dXY = dX;437}438if (dXY < 0.0) dXY = -dXY;439440if ((scanline == (int)y) && (absolute(dY) <= 1.0)) {441if (x <= xend) {442for (xpix = (int)x; xpix <= (int)xend; xpix++) {443put_cBuffer_axes(xpix,'c');444}445} else {446for (xpix = (int)x; xpix >= (int)xend; xpix--) {447put_cBuffer_axes(xpix,'c');448}449}450} else {451if (xend < x)452decision = (scanline < y && scanline >= yend) ||453(scanline > y && scanline <= yend);454else455decision = (scanline <= y && scanline > yend) ||456(scanline >= y && scanline < yend);457if (decision) {458intersectionx = x + dX/dY * diffy;459for (count = (int)intersectionx;460count <= (int)intersectionx + (int)dXY; count++) {461put_cBuffer_axes(count,'c');462}463}464}465}466467}468}469470}471472473474/********************************************475* axesTObuffer() writes the projection of *476* the x,y,z axes to the z-buffer. *477********************************************/478479void480axesTObuffer(void)481{482int xpix,i,count,decision;483int xA,xB,yA,yB;484float x,xend,y,yend,diffy,dX,dY,dXY,intersectionx;485float zA,zB,z,zend;486float dZ,dZX,dZY,intersectionz;487488intersectionz = 0.0; intersectionx = 0.0;489for (i=0; i<3; i++) {490xA = axesXY[i][0]; yA = axesXY[i][1]; zA = axesZ[i][0];491xB = axesXY[i][2]; yB = axesXY[i][3]; zB = axesZ[i][1];492/*493if (xA > graphWindowAttrib.width+1) xA = graphWindowAttrib.width+1;494if (xB > graphWindowAttrib.width+1) xB = graphWindowAttrib.width+1;495if (yA > graphWindowAttrib.height) yA = graphWindowAttrib.height;496if (yB > graphWindowAttrib.height) yB = graphWindowAttrib.height;497if (xA < 0) xA = 0; if (xB < 0) xB = 0;498if (yA < 0) yA = 0; if (yB < 0) yB = 0;499*/500x = xA; xend = xB; y = yA; yend = yB; z = zA; zend = zB;501diffy = (float)scanline - y;502dX = xend - x; dY = yend - y; dZ = zend - z;503dZY = dZ/dY;504dXY = dX/dY;505if (dXY < 0.0) dXY = -dXY;506dZX = dZ/dX;507508if ((scanline == (int)y) && (absolute(dY) <= 1.0)) {509if (x <= xend) {510for (xpix = (int)x; xpix <= (int)xend; xpix++) {511put_cBuffer_axes(xpix,'a');512put_zBuffer(xpix,z + dZY * diffy);513} /* for x */514} else {515for (xpix = (int)x; xpix >= (int)xend; xpix--) {516put_cBuffer_axes(xpix,'a');517put_zBuffer(xpix,z + dZY * diffy);518} /* for x */519}520} else {521if (xend < x)522decision = (scanline < y && scanline >= yend) ||523(scanline > y && scanline <= yend);524else525decision = (scanline <= y && scanline > yend) ||526(scanline >= y && scanline < yend);527if (decision) {528intersectionx = x + dX/dY * diffy;529intersectionz = z + dZY * diffy;530for (count = (int)intersectionx;531count <= (int)intersectionx + (int)dXY; count++) {532put_cBuffer_axes(count,'a');533put_zBuffer(count,intersectionz);534intersectionz += dZX;535}536} /* if edge intersects scanline */537}538} /* for each axes */539540}541542/********************************************543* scanLines() scanline z-buffer algorithm *544* initialize z-buffer and color buffer for *545* all scanlines. *546********************************************/547548void549scanLines(int dFlag)550{551unsigned long pixColor;552int i;553char tempA;554555if (dFlag == Xoption) {556if (viewmap_valid) {557XFreePixmap(dsply,viewmap);558viewmap_valid=0;559}560viewmap = XCreatePixmap(/* display */ dsply,561/* drawable */ viewport->viewWindow,562/* width */ vwInfo.width,563/* height */ vwInfo.height,564/* depth */ DefaultDepth(dsply,scrn));565viewmap_valid =1;566GSetForeground(trashGC,(float)backgroundColor,dFlag);567XFillRectangle(dsply,viewmap,trashGC,0,0,vwInfo.width,vwInfo.height);568XFillRectangle(dsply,viewport->viewWindow,trashGC,0,0,569vwInfo.width,vwInfo.height);570} else {571GSetForeground(GC9991,5721.0-(float)((int)(psShadeMax-0.3*psShadeMax)-1)*psShadeMul,dFlag);573quadMesh[0].x = 0; quadMesh[0].y = 0;574quadMesh[1].x = graphWindowAttrib.width+2;575quadMesh[1].y = 0;576quadMesh[2].x = graphWindowAttrib.width+2;577quadMesh[2].y = graphWindowAttrib.height;578quadMesh[3].x = 0;579quadMesh[3].y = graphWindowAttrib.height;580quadMesh[4].x = 0; quadMesh[4].y = 0;581PSFillPolygon(GC9991, quadMesh, 5);582}583584if (graphWindowAttrib.height >= physicalHeight)585graphWindowAttrib.height = physicalHeight - 1;586if (graphWindowAttrib.width >= physicalWidth)587graphWindowAttrib.width = physicalWidth - 1;588if (dFlag == Xoption)589strcpy(control->message," Display Scanlines ");590else591strcpy(control->message," Writing Output ");592writeControlMessage();593594scanline = graphWindowAttrib.height-1;595596imageX = XCreateImage(/* display */ dsply,597/* visual */ DefaultVisual(dsply,scrn),598/* depth */ DefaultDepth(dsply,scrn),599/* format */ ZPixmap,600/* offset */ 0,601/* data */ 0,602/* width */ vwInfo.width,603/* height */ 1,604/* bitmap_pad */ 32,605/* bytes_per_line */ 0);606imageX->data = (char *)malloc(imageX->bytes_per_line);607608609while (scanline >= 0 && keepDrawingViewport()) {610/* initialize buffer values for scanline */611pixColor = backgroundColor;612for (i=0; i < (int)graphWindowAttrib.width; i++) {613put_zBuffer(i,10000.0);614put_cBuffer_indx(i,-1);615put_cBuffer_axes(i,'0');616if (mono || viewport->monoOn)617if ((scanline % 2) == 0)618if ((i % 2) == 0) {619if (i>=0 && i<vwInfo.width) XPutPixel(imageX,i,0,backgroundColor);620}621else {622if (i>=0 && i<vwInfo.width) XPutPixel(imageX,i,0,foregroundColor);623}624else625if ((i % 2) == 0) {626if (i>=0 && i<vwInfo.width) XPutPixel(imageX,i,0,foregroundColor);627}628else {629if (i>=0 && i<vwInfo.width) XPutPixel(imageX,i,0,backgroundColor);630}631else {632if (i>=0 && i<vwInfo.width) XPutPixel(imageX,i,0,backgroundColor);633}634}635636/* writes the axes info to the buffers */637if (viewData.box) boxTObuffer();638if (viewData.clipbox) clipboxTObuffer();639if (viewport->axesOn) axesTObuffer();640641/* fill buffers for current scanline */642scanPhong(dFlag);643644for (i=0; i < (int)graphWindowAttrib.width; i++) {645/* include bounding region info */646if (viewData.box) {647if (get_cBuffer_axes(i) == 'b') {648if (dFlag==Xoption) {649if (mono || (viewport->monoOn)) pixColor = foregroundColor;650else pixColor = boxInline;651if (i >=0 && i<vwInfo.width) XPutPixel(imageX,i,0,pixColor);652} else {653GSetForeground(GC9991, psBlack, dFlag );654GDrawPoint(viewport->viewWindow, GC9991, i,scanline,dFlag);655}656}657}658/* include clipping box info */659if (viewData.clipbox) {660if (get_cBuffer_axes(i)== 'c') {661if (dFlag==Xoption) {662if (mono || (viewport->monoOn)) pixColor = foregroundColor;663else pixColor = clipBoxInline;664if (i >=0 && i<vwInfo.width) XPutPixel(imageX,i,0,pixColor);665} else {666GSetForeground(GC9991, psBlack, dFlag );667GDrawPoint(viewport->viewWindow, GC9991, i,scanline,dFlag);668}669}670}671/* include axes info */672if (viewport->axesOn) {673if (get_cBuffer_axes(i) == 'a') {674if (dFlag == Xoption) {675if (mono || (viewport->monoOn)) pixColor = foregroundColor;676else pixColor = monoColor(axesColor);677if (i >=0 && i<vwInfo.width) XPutPixel(imageX,i,0,pixColor);678} else {679GSetForeground(GC9991,psBlack,dFlag);680GDrawPoint(viewport->viewWindow, GC9991, i,scanline,dFlag);681}682} /* if buffer slot is an axes point */683tempA = get_cBuffer_axes(i);684} else tempA = '0'; /* else axes not on */685686if (get_cBuffer_indx(i) >= 0 && (tempA == '0')) {687if (dFlag == Xoption) {688GSetForeground(trashGC,(float)get_cBuffer_indx(i),dFlag);689pixColor = get_cBuffer_indx(i);690if (i >=0 && i<vwInfo.width) XPutPixel(imageX,i,0,pixColor);691}692else {693GSetForeground(GC9991,(float)get_cBuffer_indx(i),dFlag);694GDrawPoint(viewport->viewWindow, GC9991, i,scanline,dFlag);695}696}697} /* for each pixel in scanline */698699if (dFlag == Xoption) {700XPutImage(dsply,viewport->viewWindow,trashGC,imageX,0,0,0,701scanline,vwInfo.width,1);702XPutImage(dsply,viewmap,trashGC,imageX,0,0,0,703scanline,vwInfo.width,1);704}705706scanline--;707708} /* while each scanline */709XDestroyImage(imageX);710711}712713/*************************************714* void freePolyList(); *715* *716* frees up the global scanList l-l *717*************************************/718719void720freePolyList (void)721{722polyList *P, *nextP;723int i;724725for (i = 0; (i < ARRAY_HEIGHT); i++) {726P = scanList[i];727while((P != NIL(polyList))) {728nextP = P->next;729free(P);730P = nextP;731}732}733734} /* freePolyList() */735736737/********************************************738* showAxesLabels() writes the axes labels *739* onto the viewmap of a graph. *740********************************************/741742void743showAxesLabels(int dFlag)744{745int xcoord2,ycoord2;746747if (dFlag == Xoption)748if (mono || (viewport->monoOn))749GSetForeground(globGC,(float)foregroundColor,dFlag);750else751GSetForeground(globGC,(float)monoColor(labelColor),dFlag);752else GSetForeground(GC9991,psBlack,dFlag);753754/* axes label for X */755if ((int)axesZ[0][0] >= (int)axesZ[0][2]) {756if (axesXY[0][2] < axesXY[0][0]) xcoord2 = axesXY[0][2]-5;757else xcoord2 = axesXY[0][2] + 5;758if (axesXY[0][3] < axesXY[0][1]) ycoord2 = axesXY[0][3]-5;759else ycoord2 = axesXY[0][3] + 5;760if (!viewport->yzOn) {761if (dFlag == Xoption)762GDrawString(globGC,viewmap,xcoord2,ycoord2,"X",1,dFlag);763else764GDrawString(GC9991,viewport->viewWindow,xcoord2,ycoord2,"X",1,dFlag);765}766}767768/* axes label for Y */769if ((int)axesZ[1][0] >= (int)axesZ[1][1]) {770if (axesXY[1][2] < axesXY[1][0]) xcoord2 = axesXY[1][2]-5;771else xcoord2 = axesXY[1][2] + 5;772if (axesXY[1][3] < axesXY[1][1]) ycoord2 = axesXY[1][3]-5;773else ycoord2 = axesXY[1][3] + 5;774if (!viewport->xzOn) {775if (dFlag == Xoption)776GDrawString(globGC,viewmap,xcoord2,ycoord2,"Y",1,dFlag);777else778GDrawString(GC9991,viewport->viewWindow,xcoord2,ycoord2,"Y",1,dFlag);779}780}781782/* axes label for Z */783if ((int)axesZ[2][0] >= (int)axesZ[2][1]) {784if (axesXY[2][2] < axesXY[2][0]) xcoord2 = axesXY[2][2]-5;785else xcoord2 = axesXY[2][2] + 5;786if (axesXY[2][3] < axesXY[2][1]) ycoord2 = axesXY[2][3]-5;787else ycoord2 = axesXY[2][3] + 5;788if (!viewport->xyOn) {789if (dFlag == Xoption)790GDrawString(globGC,viewmap,xcoord2,ycoord2,"Z",1,dFlag);791else792GDrawString(GC9991,viewport->viewWindow,xcoord2,ycoord2,"Z",1,dFlag);793}794}795}796797798799/********************************************800* changeColorMap() modifies the color map *801* for moving in and out of smooth shading. *802********************************************/803804void805changeColorMap(void)806{807int okay, i, hue, *index;808poly *cp;809viewTriple *pt;810811strcpy(control->message," Make New Color Map ");812writeControlMessage();813if ((viewport->hueOffset == viewport->hueTop) &&814!mono && !viewport->monoOn) {815816/* colormap is not an even distribution across spectrum */817/* see spadcolors.c code to understand why this is done */818819if (viewport->hueTop < 11) smoothHue = viewport->hueTop * 6;820else821if (viewport->hueTop > 10 && viewport->hueTop < 16) {822smoothHue = viewport->hueTop*20 - 140;823}824else {825smoothHue = viewport->hueTop*12 - 12;826}827828if (redoColor) {829/* reallocate colormap for new hue */830redoColor = no;831if (pixelSetFlag) {832FreePixels(dsply,colorMap,smoothConst+1);833}834okay = makeNewColorMap(dsply,colorMap,smoothHue);835if (okay) {836pixelSetFlag = yes;837smoothError = no; }838else {839pixelSetFlag = no;840smoothError = yes; }841} /* if redoColor */842} else {843redoDither = no;844if (pixelSetFlag && !mono) {845FreePixels(dsply,colorMap,smoothConst);846pixelSetFlag = no;847redoColor = no;848multiColorFlag = yes;849}850if (!mono && !viewport->monoOn) {851cp = quickList;852while (cp != NIL(poly) && keepDrawingViewport()) {853for (i = 0, index = cp->indexPtr;854i < cp->numpts; i++, index++) {855pt = refPt3D(viewData,*(index));856/* get hue for each point if multi-dithering is used */857if (absolute(cp->color) > 1.0)858hue = floor(absolute(cp->color));859else860hue = floor(absolute(cp->color) * viewport->numberOfHues) +861viewport->hueOffset;862pt->sc = (float)hue;863} /* for each point in polygon */864cp = cp->next;865}866} /* multi-color dither */867} /* else hueOffset != hueTop */868}869870871/***********************872* void drawPhong() *873* *874* A general routine *875* for displaying a *876* list of polygons *877* using a simple *878* scanline z-buffer *879* algorithm with *880* phong shading. *881***********************/882883void884drawPhong(int dFlag)885{886887poly *p, *head;888polyList *s;889int i,j,hue;890int *anIndex, redo;891viewTriple *aPoint, *polyPt;892893redo = (recalc || redoSmooth);894if (redo || redoColor || redoDither) {895rotated = no; zoomed = no; translated = no;896switchedPerspective = no; changedEyeDistance = no;897redoSmooth = no; movingLight = no;898899/* If only a color change don't recalculate polygon info. */900if (!redo) {901/* glossy shading if a single hue is indicated */902changeColorMap();903scanLines(dFlag);904/* if axes are on then show axes labels */905if (viewport->axesOn) showAxesLabels(dFlag);906907/* show pixmap of image */908XCopyArea(dsply,viewmap,viewport->viewWindow,trashGC,0,0,909vwInfo.width,vwInfo.height,0,0);910} else {911if (keepDrawingViewport()) {912if (!firstTime && !(scanline > 0)) {913strcpy(control->message," Freeing Polygons ");914writeControlMessage();915freeListOfPolygons(quickList);916freePointResevoir();917}918if (keepDrawingViewport()) {919strcpy(control->message," Collecting Polygons ");920writeControlMessage();921quickList = copyPolygons(viewData.polygons);922923if (keepDrawingViewport()) {924strcpy(control->message," Projecting Polygons ");925writeControlMessage();926projectAllPolys(quickList);927if (keepDrawingViewport()) {928strcpy(control->message,929" Setting Polygon Extremes ");930writeControlMessage();931minMaxPolygons(quickList);932if (keepDrawingViewport()) {933strcpy(control->message,934" Sorting Polygons ");935writeControlMessage();936quickList = msort(quickList,0,viewData.numPolygons,937polyCompare);938calcEyePoint();939head = p = quickList;940941/* glossy shading if a single hue is indicated */942changeColorMap();943944for (i=0, aPoint=viewData.points;945i<viewData.numOfPoints; i++,aPoint++) {946aPoint->norm[0]= 0.0;947aPoint->norm[1]= 0.0;948aPoint->norm[2]= 0.0;949}950freePolyList();951for (i = 0; i < ARRAY_HEIGHT; i++)952scanList[i] = NIL(polyList);953/* for each polygon */954/* calculate average normal for each vertex */955strcpy(control->message,956" Build Polygon Lists ");957writeControlMessage();958p = head;959while ((p != NIL(poly)) && keepDrawingViewport()) {960961for (j = 0, anIndex = p->indexPtr;962j < p->numpts; j++, anIndex++) {963polyPt = refPt3D(viewData,*(anIndex));964polyPt->norm[0] += p->N[0];965polyPt->norm[1] += p->N[1];966polyPt->norm[2] += p->N[2];967normalizeVector(polyPt->norm);968/* get hue for each point if multi-dithering is used */969if ((viewport->hueOffset != viewport->hueTop ||970smoothError) && !mono) {971if (absolute(p->color) > 1.0) {972hue = floor(absolute(p->color));973} else {974hue = floor(absolute(p->color) *975viewport->numberOfHues) +976viewport->hueOffset;977}978polyPt->sc = (float)hue;979} /* multi-color dither */980} /* for each point in polygon */981982if ( ! ( p->partialClipPz ||983p->totalClipPz ||984(viewData.clipStuff && (p->partialClip || p->totalClip ) ) ) ) {985/* put polygon in each scanline list it intersects */986for (i=(int)p->pymin; i<= (int)p->pymax; i++) {987if ( (i>=0) && (i<ARRAY_HEIGHT ) ){988s = (polyList *)saymem("smoothShade.c",1,sizeof(polyList));989s->polyIndx = p;990s->next = scanList[i];991scanList[i] = s;992}993} /* put polygon in each scanline it intersects */994} /* if polygon not clipped */995p = p->next;996} /* while still polygons */997998scanLines(dFlag);9991000/* if axes are on then show axes labels */1001if (viewport->axesOn) showAxesLabels(dFlag);10021003/* show pixmap of image */1004XCopyArea(dsply,viewmap,viewport->viewWindow,trashGC,0,0,1005vwInfo.width,vwInfo.height,0,0);1006/* freePolyList(scanList); */10071008} /* keepDrawingViewport() after setting extreme values */1009} /* keepDrawingViewport() after projecting all polygons */1010} /* keepDrawingViewport() after collecting polygons */1011} /* keepDrawingViewport() after freeing polygons */1012} /* keepDrawingViewport() after recalc */1013finishedList = !(scanline>0);1014if (firstTime) firstTime = no;1015} /* not only a color change */10161017} else { /* else just redisplay current pixmap of image */1018XCopyArea(dsply,viewmap,viewport->viewWindow,trashGC,0,0,1019vwInfo.width,vwInfo.height,0,0);1020}1021clearControlMessage();1022strcpy(control->message,viewport->title);1023writeControlMessage();10241025} /* drawPhong */1026102710281029103010311032103310341035103610371038