home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume21
/
rayshade
/
part16
< prev
next >
Wrap
Text File
|
1991-07-21
|
39KB
|
1,500 lines
Newsgroups: comp.sources.misc
From: Rayshade Construction Co. <rayshade@weedeater.math.YALE.EDU>
Subject: v21i019: rayshade - A raytracing package for UNIX, Part16/19
Message-ID: <1991Jul21.223347.3819@sparky.IMD.Sterling.COM>
X-Md4-Signature: efda1f5851c6f429b69764464f3e1055
Date: Sun, 21 Jul 1991 22:33:47 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: Rayshade Construction Co. <rayshade@weedeater.math.YALE.EDU>
Posting-number: Volume 21, Issue 19
Archive-name: rayshade/part16
Environment: UNIX, !16BIT
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 16 (of 19)."
# Contents: libray/libobj/hf.c raypaint/render.c
# Wrapped by kolb@woody on Wed Jul 17 17:56:55 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'libray/libobj/hf.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'libray/libobj/hf.c'\"
else
echo shar: Extracting \"'libray/libobj/hf.c'\" \(17333 characters\)
sed "s/^X//" >'libray/libobj/hf.c' <<'END_OF_FILE'
X/*
X * hf.c
X *
X * Copyright (C) 1989, 1991, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose. It is provided solely "as is".
X *
X * $Id: hf.c,v 4.0 91/07/17 14:38:15 kolb Exp Locker: kolb $
X *
X * $Log: hf.c,v $
X * Revision 4.0 91/07/17 14:38:15 kolb
X * Initial version.
X *
X */
X#include "geom.h"
X#include "hf.h"
X
Xstatic Methods *iHfMethods = NULL;
Xstatic char hfName[] = "heighfield";
X
Xstatic void integrate_grid(), QueueTri();
Xstatic int DDA2D(), CheckCell();
Xstatic Float intHftri();
Xstatic float minalt(), maxalt();
X
Xtypedef struct {
X int stepX, stepY;
X Float tDX, tDY;
X float minz, maxz;
X int outX, outY;
X Vector cp, pDX, pDY;
X} Trav2D;
X
XhfTri *CreateHfTriangle(), *GetQueuedTri();
X
Xunsigned long HFTests, HFHits;
X
XHf *
XHfCreate(filename)
Xchar *filename;
X{
X Hf *hf;
X FILE *fp;
X float val, *maxptr, *minptr;
X int i, j;
X
X fp = fopen(filename, "r");
X if (fp == (FILE *)NULL) {
X RLerror(RL_ABORT, "Cannot open heightfield file \"%s\".",
X filename);
X return (Hf *)NULL;
X }
X
X hf = (Hf *)Malloc(sizeof(Hf));
X /*
X * Make the following an option someday.
X */
X hf->BestSize = BESTSIZE;
X /*
X * Store the inverse for faster computation.
X */
X hf->iBestSize = 1. / (float)hf->BestSize;
X /*
X * Get HF size.
X */
X if (fread((char *)&hf->size, sizeof(int), 1, fp) == 0) {
X RLerror(RL_ABORT, "Cannot read height field size.");
X return (Hf *)NULL;
X }
X
X hf->data = (float **)share_malloc(hf->size * sizeof(float *));
X for (i = 0; i < hf->size; i++) {
X hf->data[i] = (float *)share_malloc(hf->size * sizeof(float));
X /*
X * Read in row of HF data.
X */
X if (fread((char *)hf->data[i],sizeof(float),hf->size,fp)
X != hf->size) {
X RLerror(RL_ABORT, "Not enough heightfield data.");
X return (Hf *)NULL;
X }
X for (j = 0; j < hf->size; j++) {
X val = hf->data[i][j];
X if (val <= HF_UNSET) {
X hf->data[i][j] = HF_UNSET;
X /*
X * Don't include the point in min/max
X * calculations.
X */
X continue;
X }
X if (val > hf->maxz)
X hf->maxz = val;
X if (val < hf->minz)
X hf->minz = val;
X }
X }
X (void)fclose(fp);
X /*
X * Allocate levels of grid. hf->levels = log base BestSize of hf->size
X */
X for (i = hf->size, hf->levels = 0; i > hf->BestSize; i /= hf->BestSize,
X hf->levels++)
X ;
X hf->levels++;
X hf->qsize = CACHESIZE;
X hf->q = (hfTri **)Calloc((unsigned)hf->qsize, sizeof(hfTri *));
X hf->qtail = 0;
X
X hf->lsize = (int *)share_malloc(hf->levels * sizeof(int));
X hf->spacing = (float *)share_malloc(hf->levels * sizeof(float));
X hf->boundsmax = (float ***)share_malloc(hf->levels * sizeof(float **));
X hf->boundsmin = (float ***)share_malloc(hf->levels * sizeof(float **));
X
X hf->spacing[0] = hf->size -1;
X hf->lsize[0] = (int)hf->spacing[0];
X hf->boundsmax[0] = (float **)share_malloc(hf->lsize[0]*sizeof(float *));
X hf->boundsmin[0] = (float **)share_malloc(hf->lsize[0]*sizeof(float *));
X /*
X * Compute initial bounding boxes
X */
X for (i = 0; i < hf->lsize[0]; i++) {
X hf->boundsmax[0][i]=(float *)share_malloc(hf->lsize[0]*sizeof(float));
X hf->boundsmin[0][i]=(float *)share_malloc(hf->lsize[0]*sizeof(float));
X maxptr = hf->boundsmax[0][i];
X minptr = hf->boundsmin[0][i];
X for (j = 0; j < hf->lsize[0]; j++) {
X *maxptr++ = maxalt(i, j, hf->data) + EPSILON;
X *minptr++ = minalt(i, j, hf->data) - EPSILON;
X }
X }
X
X for (i = 1; i < hf->levels; i++) {
X hf->spacing[i] = hf->spacing[i-1] * hf->iBestSize;
X hf->lsize[i] = (int)hf->spacing[i];
X if ((Float)hf->lsize[i] != hf->spacing[i])
X hf->lsize[i]++;
X hf->boundsmax[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
X hf->boundsmin[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
X for (j = 0; j < hf->lsize[i]; j++) {
X hf->boundsmax[i][j] = (float *)share_malloc(hf->lsize[i] *
X sizeof(float));
X hf->boundsmin[i][j] = (float *)share_malloc(hf->lsize[i] *
X sizeof(float));
X }
X integrate_grid(hf, i);
X }
X
X hf->boundbox[LOW][X] = hf->boundbox[LOW][Y] = 0;
X hf->boundbox[HIGH][X] = hf->boundbox[HIGH][Y] = 1;
X hf->boundbox[LOW][Z] = hf->minz;
X hf->boundbox[HIGH][Z] = hf->maxz;
X
X return hf;
X}
X
XMethods *
XHfMethods()
X{
X if (iHfMethods == (Methods *)NULL) {
X iHfMethods = MethodsCreate();
X iHfMethods->create = (GeomCreateFunc *)HfCreate;
X iHfMethods->methods = HfMethods;
X iHfMethods->name = HfName;
X iHfMethods->intersect = HfIntersect;
X iHfMethods->normal = HfNormal;
X iHfMethods->uv = HfUV;
X iHfMethods->bounds = HfBounds;
X iHfMethods->stats = HfStats;
X iHfMethods->checkbounds = TRUE;
X iHfMethods->closed = FALSE;
X }
X return iHfMethods;
X}
X
X/*
X * Intersect ray with height field.
X */
Xint
XHfIntersect(hf, ray, mindist, maxdist)
XHf *hf;
XRay *ray;
XFloat mindist, *maxdist;
X{
X Vector hitpos;
X Float offset;
X Trav2D trav;
X
X HFTests++;
X
X /*
X * Find where we hit the hf cube.
X */
X VecAddScaled(ray->pos, mindist, ray->dir, &hitpos);
X if (OutOfBounds(&hitpos, hf->boundbox)) {
X offset = *maxdist;
X if (!BoundsIntersect(ray, hf->boundbox, mindist, &offset))
X return FALSE;
X hitpos.x = ray->pos.x + ray->dir.x * offset;
X hitpos.y = ray->pos.y + ray->dir.y * offset;
X hitpos.z = ray->pos.z + ray->dir.z * offset;
X } else
X hitpos = ray->pos;
X /*
X * Find out in which cell "hitpoint" is.
X */
X if (equal(hitpos.x, 1.))
X hitpos.x -= EPSILON;
X if (equal(hitpos.y, 1.))
X hitpos.y -= EPSILON;
X
X if (ray->dir.x < 0.) {
X trav.stepX = trav.outX = -1;
X trav.tDX = -1. / (ray->dir.x * hf->spacing[hf->levels -1]);
X } else if (ray->dir.x > 0.) {
X trav.stepX = 1;
X trav.outX = hf->lsize[hf->levels -1];
X /*
X * (1./size) / ray
X */
X trav.tDX = 1. / (ray->dir.x * hf->spacing[hf->levels -1]);
X }
X
X if (ray->dir.y < 0.) {
X trav.stepY = trav.outY = -1;
X trav.tDY = -1. / (ray->dir.y * hf->spacing[hf->levels -1]);
X } else if (ray->dir.y > 0.) {
X trav.stepY = 1;
X trav.outY = hf->lsize[hf->levels -1];
X trav.tDY = 1. / (ray->dir.y * hf->spacing[hf->levels -1]);
X }
X
X trav.pDX.x = ray->dir.x * trav.tDX;
X trav.pDX.y = ray->dir.y * trav.tDX;
X trav.pDX.z = ray->dir.z * trav.tDX;
X trav.pDY.x = ray->dir.x * trav.tDY;
X trav.pDY.y = ray->dir.y * trav.tDY;
X trav.pDY.z = ray->dir.z * trav.tDY;
X
X trav.cp = hitpos;
X trav.minz = hf->minz;
X trav.maxz = hf->maxz;
X if (DDA2D(hf, &ray->pos, &ray->dir, hf->levels -1, &trav, maxdist)) {
X HFHits++;
X return TRUE;
X }
X return FALSE;
X}
X
X/*
X * Traverse the grid using a modified DDA algorithm. If the extent of
X * the ray over a cell intersects the bounding volume defined by the
X * four corners of the cell, either recurse or perform ray/surface
X * intersection test.
X */
Xstatic int
XDDA2D(hf, pos, ray, level, trav, maxdist)
XHf *hf;
XVector *pos, *ray;
Xint level;
XTrav2D *trav;
XFloat *maxdist;
X{
X int x, y, size, posZ;
X float **boundsmin, **boundsmax, spacing;
X Float tX, tY;
X Trav2D newtrav;
X Vector nxp, nyp;
X
X size = hf->lsize[level];
X spacing = hf->spacing[level];
X
X posZ = (ray->z > 0.);
X
X x = trav->cp.x * hf->spacing[level];
X if (x == size)
X x--;
X y = trav->cp.y * hf->spacing[level];
X if (y == size)
X y--;
X boundsmax = hf->boundsmax[level];
X boundsmin = hf->boundsmin[level];
X
X if (trav->outX > size) trav->outX = size;
X if (trav->outY > size) trav->outY = size;
X if (trav->outX < 0) trav->outX = -1;
X if (trav->outY < 0) trav->outY = -1;
X
X if (ray->x < 0.) {
X tX = (x /spacing - trav->cp.x) / ray->x;
X } else if (ray->x > 0.)
X tX = ((x+1)/spacing - trav->cp.x) / ray->x;
X else
X tX = FAR_AWAY;
X if (ray->y < 0.) {
X tY = (y /spacing - trav->cp.y) / ray->y;
X } else if (ray->y > 0.)
X tY = ((y+1)/spacing - trav->cp.y) / ray->y;
X else
X tY = FAR_AWAY;
X
X nxp.x = trav->cp.x + tX * ray->x;
X nxp.y = trav->cp.y + tX * ray->y;
X nxp.z = trav->cp.z + tX * ray->z;
X
X nyp.x = trav->cp.x + tY * ray->x;
X nyp.y = trav->cp.y + tY * ray->y;
X nyp.z = trav->cp.z + tY * ray->z;
X
X do {
X if (tX < tY) {
X if ((posZ && trav->cp.z <= boundsmax[y][x] &&
X nxp.z >= boundsmin[y][x]) ||
X (!posZ && trav->cp.z >= boundsmin[y][x] &&
X nxp.z <= boundsmax[y][x])) {
X if (level) {
X /*
X * Recurse -- compute constants
X * needed for next level.
X * Nicely enough, this just
X * involves a few multiplications.
X */
X newtrav = *trav;
X newtrav.tDX *= hf->iBestSize;
X newtrav.tDY *= hf->iBestSize;
X newtrav.maxz = boundsmax[y][x];
X newtrav.minz = boundsmin[y][x];
X if (ray->x < 0.)
X newtrav.outX=hf->BestSize*x-1;
X else
X newtrav.outX=hf->BestSize*(x+1);
X if (ray->y < 0.)
X newtrav.outY=hf->BestSize*y-1;
X else
X newtrav.outY=hf->BestSize*(y+1);
X newtrav.pDX.x *= hf->iBestSize;
X newtrav.pDX.y *= hf->iBestSize;
X newtrav.pDX.z *= hf->iBestSize;
X newtrav.pDY.x *= hf->iBestSize;
X newtrav.pDY.y *= hf->iBestSize;
X newtrav.pDY.z *= hf->iBestSize;
X if (DDA2D(hf,pos,ray,level-1,
X &newtrav, maxdist))
X return TRUE;
X } else if (CheckCell(x,y,hf,ray,pos,maxdist))
X return TRUE;
X }
X x += trav->stepX; /* Move in X */
X if (*maxdist < tX || x == trav->outX)
X /* If outside, quit */
X return FALSE;
X tX += trav->tDX; /* Update position on ray */
X trav->cp = nxp; /* cur pos gets next pos */
X nxp.x += trav->pDX.x; /* Compute next pos */
X nxp.y += trav->pDX.y;
X nxp.z += trav->pDX.z;
X } else {
X if ((posZ && trav->cp.z <= boundsmax[y][x] &&
X nyp.z >= boundsmin[y][x]) ||
X (!posZ && trav->cp.z >= boundsmin[y][x] &&
X nyp.z <= boundsmax[y][x])) {
X if (level) {
X /* Recurse */
X newtrav = *trav;
X newtrav.tDX *= hf->iBestSize;
X newtrav.tDY *= hf->iBestSize;
X newtrav.maxz = boundsmax[y][x];
X newtrav.minz = boundsmin[y][x];
X if (ray->x < 0.)
X newtrav.outX=hf->BestSize*x-1;
X else
X newtrav.outX=hf->BestSize*(x+1);
X if (ray->y < 0.)
X newtrav.outY=hf->BestSize*y-1;
X else
X newtrav.outY=hf->BestSize*(y+1);
X newtrav.pDX.x *= hf->iBestSize;
X newtrav.pDX.y *= hf->iBestSize;
X newtrav.pDX.z *= hf->iBestSize;
X newtrav.pDY.x *= hf->iBestSize;
X newtrav.pDY.y *= hf->iBestSize;
X newtrav.pDY.z *= hf->iBestSize;
X if (DDA2D(hf,pos,ray,level-1,
X &newtrav, maxdist))
X return TRUE;
X } else if (CheckCell(x,y,hf,ray,pos,maxdist))
X return TRUE;
X }
X y += trav->stepY;
X if (*maxdist < tY || y == trav->outY)
X return FALSE;
X tY += trav->tDY;
X trav->cp = nyp;
X nyp.x += trav->pDY.x;
X nyp.y += trav->pDY.y;
X nyp.z += trav->pDY.z;
X }
X } while ((trav->cp.x <= 1. && trav->cp.y <= 1.) &&
X ((posZ && trav->cp.z <= trav->maxz) ||
X (!posZ && trav->cp.z >= trav->minz)));
X
X /*
X * while ((we're inside the horizontal bounding box)
X * (usually caught by outX & outY, but
X * it's possible to go "too far" due to
X * the fact that our levels of grids do
X * not "nest" exactly if gridsize%BestSize != 0)
X * and
X * ((if ray->z is positive and we haven't gone through
X * the upper bounding plane) or
X * (if ray->z is negative and we haven't gone through
X * the lower bounding plane)));
X */
X
X return FALSE;
X}
X
X/*
X * Check for ray/cell intersection
X */
Xstatic int
XCheckCell(x, y, hf, ray, pos, maxdist)
Xint x, y;
XHf *hf;
XVector *ray, *pos;
XFloat *maxdist;
X{
X hfTri *tri1, *tri2;
X Float d1, d2;
X
X d1 = d2 = FAR_AWAY;
X
X if (tri1 = CreateHfTriangle(hf, x, y, x+1, y, x, y+1, TRI1))
X d1 = intHftri(ray, pos, tri1);
X if (tri2 = CreateHfTriangle(hf, x+1, y, x+1, y+1, x, y+1, TRI2))
X d2 = intHftri(ray, pos, tri2);
X
X if (d1 == FAR_AWAY && d2 == FAR_AWAY)
X return FALSE;
X
X if (d1 < d2) {
X if (d1 < *maxdist) {
X hf->hittri = *tri1;
X *maxdist = d1;
X return TRUE;
X }
X return FALSE;
X }
X
X if (d2 < *maxdist) {
X hf->hittri = *tri2;
X *maxdist = d2;
X return TRUE;
X }
X return FALSE;
X}
X
Xstatic hfTri *
XCreateHfTriangle(hf, x1, y1, x2, y2, x3, y3, which)
XHf *hf;
Xint x1, y1, x2, y2, x3, y3, which;
X{
X hfTri *tri;
X Float xid, yid;
X Vector tmp1, tmp2;
X
X /*
X * Don't use triangles with "unset" vertices.
X */
X if (hf->data[y1][x1] == HF_UNSET ||
X hf->data[y2][x2] == HF_UNSET ||
X hf->data[y3][x3] == HF_UNSET)
X return (hfTri *)0;
X
X xid = (Float)x1 / (Float)(hf->size -1);
X yid = (Float)y1 / (Float)(hf->size -1);
X
X if ((tri = GetQueuedTri(hf, xid, yid, which)) != (hfTri *)0)
X return tri;
X
X tri = (hfTri *)Malloc(sizeof(hfTri));
X
X tri->type = which;
X tri->v1.x = xid;
X tri->v1.y = yid;
X tri->v1.z = hf->data[y1][x1];
X tri->v2.x = (Float)x2 / (Float)(hf->size-1);
X tri->v2.y = (Float)y2 / (Float)(hf->size-1);
X tri->v2.z = hf->data[y2][x2];
X tri->v3.x = (Float)x3 / (Float)(hf->size-1);
X tri->v3.y = (Float)y3 / (Float)(hf->size-1);
X tri->v3.z = hf->data[y3][x3];
X
X tmp1.x = tri->v2.x - tri->v1.x;
X tmp1.y = tri->v2.y - tri->v1.y;
X tmp1.z = tri->v2.z - tri->v1.z;
X tmp2.x = tri->v3.x - tri->v1.x;
X tmp2.y = tri->v3.y - tri->v1.y;
X tmp2.z = tri->v3.z - tri->v1.z;
X
X (void)VecNormCross(&tmp1, &tmp2, &tri->norm);
X
X tri->d = -dotp(&tri->v1, &tri->norm);
X
X QueueTri(hf, tri);
X return tri;
X}
X
X/*
X * Intersect ray with right isoscoles triangle, the hypotenuse of which
X * has slope of -1.
X */
Xstatic Float
XintHftri(ray, pos, tri)
XhfTri *tri;
XVector *pos, *ray;
X{
X Float u, v, dist, xpos, ypos;
X
X u = dotp(&tri->norm, pos) + tri->d;
X v = dotp(&tri->norm, ray);
X
X if ((u <= 0. || v > -EPSILON) && (u >= 0. && v < EPSILON))
X return FAR_AWAY;
X
X dist = -u / v;
X
X if (dist < EPSILON)
X return FAR_AWAY;
X
X xpos = pos->x + dist*ray->x;
X ypos = pos->y + dist*ray->y;
X
X if (tri->type == TRI1 && xpos >= tri->v1.x && ypos >= tri->v1.y &&
X xpos + ypos <= tri->v2.x + tri->v2.y)
X return dist;
X if (tri->type == TRI2 && xpos <= tri->v2.x && ypos <= tri->v2.y &&
X xpos + ypos >= tri->v1.x + tri->v1.y)
X return dist;
X return FAR_AWAY;
X}
X
X/*
X * Compute normal to height field.
X */
X/*ARGSUSED*/
Xint
XHfNormal(hf, pos, nrm, gnrm)
XHf *hf;
XVector *pos, *nrm, *gnrm;
X{
X *gnrm = *nrm = hf->hittri.norm;
X return FALSE;
X}
X
X/*ARGSUSED*/
Xvoid
XHfUV(hf, pos, norm, uv, dpdu, dpdv)
XHf *hf;
XVector *pos, *norm, *dpdu, *dpdv;
XVec2d *uv;
X{
X uv->u = pos->x;
X uv->v = pos->y;
X if (dpdu) {
X dpdu->x = 1.;
X dpdu->y = dpdv->z = 0.;
X dpdv->x = dpdv->z = 0.;
X dpdv->y = 1.;
X }
X}
X
X/*
X * Compute heightfield bounding box.
X */
Xvoid
XHfBounds(hf, bounds)
XHf *hf;
XFloat bounds[2][3];
X{
X /*
X * By default, height fields are centered at (0.5, 0.5, 0.)
X */
X bounds[LOW][X] = bounds[LOW][Y] = 0;
X bounds[HIGH][X] = bounds[HIGH][Y] = 1;
X bounds[LOW][Z] = hf->minz;
X bounds[HIGH][Z] = hf->maxz;
X}
X
X/*
X * Build min/max altitude value arrays for the given grid level.
X */
Xstatic void
Xintegrate_grid(hf, level)
XHf *hf;
Xint level;
X{
X int i, j, k, l, ii, ji;
X float max_alt, min_alt;
X float **maxinto, **mininto, **frommax, **frommin, *minptr, *maxptr;
X int insize, fromsize, fact;
X
X maxinto = hf->boundsmax[level];
X mininto = hf->boundsmin[level];
X insize = hf->lsize[level];
X frommax = hf->boundsmax[level-1];
X frommin = hf->boundsmin[level-1];
X fact = hf->BestSize;
X fromsize = hf->lsize[level-1];
X
X ii = 0;
X
X for (i = 0; i < insize; i++) {
X ji = 0;
X for (j = 0; j < insize; j++) {
X max_alt = HF_UNSET;
X min_alt = -HF_UNSET;
X for (k = 0; k <= fact; k++) {
X if (ii+k >= fromsize)
X continue;
X maxptr = &frommax[ii+k][ji];
X minptr = &frommin[ii+k][ji];
X for (l = 0; l <= fact; l++,maxptr++,minptr++) {
X if (ji+l >= fromsize)
X continue;
X if (*maxptr > max_alt)
X max_alt = *maxptr;
X if (*minptr < min_alt)
X min_alt = *minptr;
X }
X }
X maxinto[i][j] = max_alt + EPSILON;
X mininto[i][j] = min_alt - EPSILON;
X ji += fact;
X }
X ii += fact;
X }
X}
X
X/*
X * Place the given triangle in the triangle cache.
X */
Xstatic void
XQueueTri(hf, tri)
XHf *hf;
XhfTri *tri;
X{
X if (hf->q[hf->qtail]) /* Free old triangle data */
X free((voidstar)hf->q[hf->qtail]);
X hf->q[hf->qtail] = tri; /* Put on tail */
X hf->qtail = (hf->qtail + 1) % hf->qsize; /* Increment tail */
X}
X
X/*
X * Search list of cached trianges to see if this triangle has been
X * cached. If so, return a pointer to it. If not, return null pointer.
X */
Xstatic hfTri *
XGetQueuedTri(hf, x, y, flag)
XHf *hf;
XFloat x, y;
Xint flag;
X{
X register int i;
X register hfTri **tmp;
X
X for (i = 0, tmp = hf->q; i < hf->qsize; i++, tmp++) {
X if (*tmp && (*tmp)->v1.x == x && (*tmp)->v1.y == y &&
X (*tmp)->type == flag)
X return *tmp; /* vertices & flag match, return it */
X }
X
X return (hfTri *)0;
X}
X
X/*
X * Return maximum height of cell indexed by y,x. This could be done
X * as a macro, but many C compliers will choke on it.
X */
Xstatic float
Xminalt(y,x,data)
Xint x, y;
Xfloat **data;
X{
X float min_alt;
X
X min_alt = min(data[y][x], data[y+1][x]);
X min_alt = min(min_alt, data[y][x+1]);
X min_alt = min(min_alt, data[y+1][x+1]);
X return min_alt;
X}
X
X/*
X * Return maximum cell height, as above.
X */
Xstatic float
Xmaxalt(y,x,data)
Xint x, y;
Xfloat **data;
X{
X float max_alt;
X
X max_alt = max(data[y][x], data[y+1][x]);
X max_alt = max(max_alt, data[y][x+1]);
X max_alt = max(max_alt, data[y+1][x+1]);
X return max_alt;
X}
X
Xchar *
XHfName()
X{
X return hfName;
X}
X
Xvoid
XHfStats(tests, hits)
Xunsigned long *tests, *hits;
X{
X *tests = HFTests;
X *hits = HFHits;
X}
X
Xvoid
XHfMethodRegister(meth)
XUserMethodType meth;
X{
X if (iHfMethods)
X iHfMethods->user = meth;
X}
END_OF_FILE
if test 17333 -ne `wc -c <'libray/libobj/hf.c'`; then
echo shar: \"'libray/libobj/hf.c'\" unpacked with wrong size!
fi
# end of 'libray/libobj/hf.c'
fi
if test -f 'raypaint/render.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'raypaint/render.c'\"
else
echo shar: Extracting \"'raypaint/render.c'\" \(17440 characters\)
sed "s/^X//" >'raypaint/render.c' <<'END_OF_FILE'
X/*
X * render.c
X *
X * Copyright (C) 1989, 1991 Craig E. Kolb, Rod G. Bogart
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose. It is provided solely "as is".
X *
X * $Id: render.c,v 4.0 91/07/17 17:37:09 kolb Exp Locker: kolb $
X *
X * $Log: render.c,v $
X * Revision 4.0 91/07/17 17:37:09 kolb
X * Initial version.
X *
X */
X
X#include "rayshade.h"
X#include "libcommon/sampling.h"
X#include "libsurf/atmosphere.h"
X#include "viewing.h"
X#include "options.h"
X#include "stats.h"
X#include "picture.h"
X
X/*
X * "Dither matrices" used to encode the 'number' of a ray that samples a
X * particular portion of a pixel. Hand-coding is ugly, but...
X */
Xstatic int *SampleNumbers;
Xstatic int OneSample[1] = {0};
Xstatic int TwoSamples[4] = {0, 2,
X 3, 1};
Xstatic int ThreeSamples[9] = {0, 2, 7,
X 6, 5, 1,
X 3, 8, 4};
Xstatic int FourSamples[16] = { 0, 8, 2, 10,
X 12, 4, 14, 6,
X 3, 11, 1, 9,
X 15, 7, 13, 5};
Xstatic int FiveSamples[25] = { 0, 8, 23, 17, 2,
X 19, 12, 4, 20, 15,
X 3, 21, 16, 9, 6,
X 14, 10, 24, 1, 13,
X 22, 7, 18, 11, 5};
Xstatic int SixSamples[36] = { 6, 32, 3, 34, 35, 1,
X 7, 11, 27, 28, 8, 30,
X 24, 14, 16, 15, 23, 19,
X 13, 20, 22, 21, 17, 18,
X 25, 29, 10, 9, 26, 12,
X 36, 5, 33, 4, 2, 31};
Xstatic int SevenSamples[49] = {22, 47, 16, 41, 10, 35, 4,
X 5, 23, 48, 17, 42, 11, 29,
X 30, 6, 24, 49, 18, 36, 12,
X 13, 31, 7, 25, 43, 19, 37,
X 38, 14, 32, 1, 26, 44, 20,
X 21, 39, 8, 33, 2, 27, 45,
X 46, 15, 40, 9, 34, 3, 28};
Xstatic int EightSamples[64] = { 8, 58, 59, 5, 4, 62, 63, 1,
X 49, 15, 14, 52, 53, 11, 10, 56,
X 41, 23, 22, 44, 45, 19, 18, 48,
X 32, 34, 35, 29, 28, 38, 39, 25,
X 40, 26, 27, 37, 36, 30, 31, 33,
X 17, 47, 46, 20, 21, 43, 42, 24,
X 9, 55, 54, 12, 13, 51, 50, 16,
X 64, 2, 3, 61, 60, 6, 7, 57};
X#define RFAC 0.299
X#define GFAC 0.587
X#define BFAC 0.114
X
X#define NOT_CLOSED 0
X#define CLOSED_PARTIAL 1
X#define CLOSED_SUPER 2
X/*
X * If a region has area < MINAREA, it is considered to be "closed",
X * (a permanent leaf). Regions that meet this criterion
X * are drawn pixel-by-pixel rather.
X */
X#define MINAREA 9
X
X#define SQ_AREA(s) (((s)->xsize+1)*((s)->ysize+1))
X
X#define PRIORITY(s) ((s)->var * SQ_AREA(s))
X
X#define INTENSITY(p) ((RFAC*(p)[0] + GFAC*(p)[1] + BFAC*(p)[2])/255.)
X
X#define OVERLAPS_RECT(s) (!Rectmode || \
X ((s)->xpos <= Rectx1 && \
X (s)->ypos <= Recty1 && \
X (s)->xpos+(s)->xsize >= Rectx0 && \
X (s)->ypos+(s)->ysize >= Recty0))
X
Xtypedef unsigned char RGB[3];
X
Xstatic RGB **Image;
Xstatic char **SampleMap;
X
X/*
X * Sample square
X */
Xtypedef struct SSquare {
X short xpos, ypos, xsize, ysize;
X short depth;
X short leaf, closed;
X float mean, var, prio;
X struct SSquare *child[4], *parent;
X} SSquare;
X
XSSquare *SSquares, *SSquareCreate(), *SSquareInstall(), *SSquareSelect(),
X *SSquareFetchAtMouse();
X
XFloat SSquareComputeLeafVar();
X
XRay TopRay; /* Top-level ray. */
Xint Rectmode = FALSE,
X Rectx0, Recty0, Rectx1, Recty1;
Xint SuperSampleMode = 0;
X#define SSCLOSED (SuperSampleMode + 1)
X
XRender(argc, argv)
Xint argc;
Xchar **argv;
X{
X /*
X * Do an adaptive trace, displaying results in a
X * window as we go.
X */
X SSquare *cursq;
X Pixel *pixelbuf;
X int y, x;
X
X /*
X * The top-level ray TopRay always has as its origin the
X * eye position and as its medium NULL, indicating that it
X * is passing through a medium with index of refraction
X * equal to DefIndex.
X */
X TopRay.pos = Camera.pos;
X TopRay.media = (Medium *)0;
X TopRay.depth = 0;
X /*
X * Doesn't handle motion blur yet.
X */
X TopRay.time = Options.framestart;
X
X GraphicsInit(Screen.xsize, Screen.ysize, "rayview");
X /*
X * Allocate array of samples.
X */
X Image=(RGB **)Malloc(Screen.ysize*sizeof(RGB *));
X SampleMap = (char **)Malloc(Screen.ysize * sizeof(char *));
X for (y = 0; y < Screen.ysize; y++) {
X Image[y]=(RGB *)Calloc(Screen.xsize, sizeof(RGB));
X SampleMap[y] = (char *)Calloc(Screen.xsize, sizeof(char));
X }
X switch (Sampling.sidesamples) {
X case 1:
X SampleNumbers = OneSample;
X break;
X case 2:
X SampleNumbers = TwoSamples;
X break;
X case 3:
X SampleNumbers = ThreeSamples;
X break;
X case 4:
X SampleNumbers = FourSamples;
X break;
X case 5:
X SampleNumbers = FiveSamples;
X break;
X case 6:
X SampleNumbers = SixSamples;
X break;
X case 7:
X SampleNumbers = SevenSamples;
X break;
X case 8:
X SampleNumbers = EightSamples;
X break;
X default:
X RLerror(RL_PANIC,
X "Sorry, %d rays/pixel not supported.\n",
X Sampling.totsamples);
X }
X /*
X * Take initial four samples
X */
X SSquareSample(0, 0, FALSE);
X SSquareSample(Screen.xsize -1, 0, FALSE);
X SSquareSample(Screen.xsize -1, Screen.ysize -1, FALSE);
X SSquareSample(0, Screen.ysize -1, FALSE);
X SSquares = SSquareInstall(0, 0, Screen.xsize -1, Screen.ysize -1,
X 0, (SSquare *) NULL);
X
X for (y = 1; y <= 5; y++) {
X /*
X * Create and draw every region at depth y.
X */
X SSquareDivideToDepth(SSquares, y);
X }
X
X
X while ((cursq = SSquareSelect(SSquares)) != (SSquare *)NULL) {
X SSquareDivide(cursq);
X if (GraphicsRedraw())
X SSquareDraw(SSquares);
X if (GraphicsMiddleMouseEvent())
X SSetRectMode();
X }
X
X /*
X * Finished the image; write to image file.
X */
X pixelbuf = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
X PictureStart(argv);
X for (y = 0; y < Screen.ysize; y++) {
X /*
X * This is really disgusting.
X */
X for (x = 0; x < Screen.xsize; x++) {
X pixelbuf[x].r = Image[y][x][0] / 255.;
X pixelbuf[x].g = Image[y][x][1] / 255.;
X pixelbuf[x].b = Image[y][x][2] / 255.;
X pixelbuf[x].alpha = SampleMap[y][x];
X }
X PictureWriteLine(pixelbuf);
X }
X PictureEnd();
X free((voidstar)pixelbuf);
X}
X
XFloat
XSampleTime(sampnum)
Xint sampnum;
X{
X Float window, jitter = 0.0, res;
X
X if (Options.shutterspeed <= 0.)
X return Options.framestart;
X if (Options.jitter)
X jitter = nrand();
X window = Options.shutterspeed / Sampling.totsamples;
X res = Options.framestart + window * (sampnum + jitter);
X TimeSet(res);
X return res;
X}
X
XSSetRectMode()
X{
X int x1,y1,x2,y2;
X
X if (Rectmode) {
X Rectmode = FALSE;
X RecomputePriority(SSquares);
X }
X GraphicsGetMousePos(&x1, &y1);
X while (GraphicsMiddleMouseEvent())
X ;
X GraphicsGetMousePos(&x2, &y2);
X if (x1 < x2) {
X Rectx0 = (x1 < 0) ? 0 : x1;
X Rectx1 = (x2 >= Screen.xsize) ? Screen.xsize - 1 : x2;
X } else {
X Rectx0 = (x2 < 0) ? 0 : x2;
X Rectx1 = (x1 >= Screen.xsize) ? Screen.xsize - 1 : x1;
X } if (y1 < y2) {
X Recty0 = (y1 < 0) ? 0 : y1;
X Recty1 = (y2 >= Screen.ysize) ? Screen.ysize - 1 : y2;
X } else {
X Recty0 = (y2 < 0) ? 0 : y2;
X Recty1 = (y1 >= Screen.ysize) ? Screen.ysize - 1 : y1;
X }
X Rectmode = TRUE;
X /* setup current rect */
X (void)RecomputePriority(SSquares);
X}
X
XRecomputePriority(sq)
XSSquare *sq;
X{
X Float maxp;
X
X if (!OVERLAPS_RECT(sq)) {
X sq->closed = SSCLOSED;
X return FALSE;
X }
X
X if (sq->leaf) {
X if (SQ_AREA(sq) >= MINAREA)
X sq->closed = NOT_CLOSED;
X return TRUE;
X }
X maxp = 0.;
X if (RecomputePriority(sq->child[0]))
X maxp = max(maxp, sq->child[0]->prio);
X if (RecomputePriority(sq->child[1]))
X maxp = max(maxp, sq->child[1]->prio);
X if (RecomputePriority(sq->child[2]))
X maxp = max(maxp, sq->child[2]->prio);
X if (RecomputePriority(sq->child[3]))
X maxp = max(maxp, sq->child[3]->prio);
X sq->prio = maxp;
X#if 0
X if ((sq->child[0]->closed == CLOSED_SUPER) &&
X (sq->child[1]->closed == CLOSED_SUPER) &&
X (sq->child[2]->closed == CLOSED_SUPER) &&
X (sq->child[3]->closed == CLOSED_SUPER))
X sq->closed = CLOSED_SUPER;
X else if (sq->child[0]->closed && sq->child[1]->closed &&
X sq->child[2]->closed && sq->child[3]->closed)
X sq->closed = CLOSED_PARTIAL;
X else
X sq->closed = NOT_CLOSED;
X#else
X if ((sq->child[0]->closed >= SSCLOSED) &&
X (sq->child[1]->closed >= SSCLOSED) &&
X (sq->child[2]->closed >= SSCLOSED) &&
X (sq->child[3]->closed >= SSCLOSED))
X sq->closed = SSCLOSED;
X else
X sq->closed = NOT_CLOSED;
X#endif
X return TRUE;
X}
X
XSSquareSample(x, y, supersample)
Xint x, y, supersample;
X{
X Float upos, vpos, u, v;
X int xx, yy, xp, sampnum, usamp, vsamp;
X Pixel ctmp;
X Pixel p;
X extern unsigned char correct();
X
X if (SampleMap[y][x] >= 128 + supersample)
X /* already a sample there */
X return;
X SampleMap[y][x] = 128 + supersample;
X if (supersample) {
X p.r = p.g = p.b = p.alpha = 0;
X sampnum = 0;
X xp = x + Screen.minx;
X vpos = Screen.miny + y - 0.5*Sampling.filterwidth;
X for (yy = 0; yy < Sampling.sidesamples; yy++,
X vpos += Sampling.filterdelta) {
X upos = xp - 0.5*Sampling.filterwidth;
X for (xx = 0; xx < Sampling.sidesamples; xx++,
X upos += Sampling.filterdelta) {
X if (Options.jitter) {
X u = upos + nrand()*Sampling.filterdelta;
X v = vpos + nrand()*Sampling.filterdelta;
X } else {
X u = upos;
X v = vpos;
X }
X TopRay.time = SampleTime(SampleNumbers[sampnum]);
X SampleScreen(u, v, &TopRay, &ctmp,
X SampleNumbers[sampnum]);
X p.r += ctmp.r*Sampling.filter[xx][yy];
X p.g += ctmp.g*Sampling.filter[xx][yy];
X p.b += ctmp.b*Sampling.filter[xx][yy];
X if (++sampnum == Sampling.totsamples)
X sampnum = 0;
X }
X }
X }
X else {
X sampnum = nrand() * Sampling.totsamples;
X usamp = sampnum % Sampling.sidesamples;
X vsamp = sampnum / Sampling.sidesamples;
X
X vpos = Screen.miny + y - 0.5*Sampling.filterwidth
X + vsamp * Sampling.filterdelta;
X upos = x + Screen.minx - 0.5*Sampling.filterwidth +
X usamp*Sampling.filterdelta;
X if (Options.jitter) {
X vpos += nrand()*Sampling.filterdelta;
X upos += nrand()*Sampling.filterdelta;
X }
X TopRay.time = SampleTime(SampleNumbers[sampnum]);
X SampleScreen(upos, vpos, &TopRay, &p, SampleNumbers[sampnum]);
X }
X Image[y][x][0] = CORRECT(p.r);
X Image[y][x][1] = CORRECT(p.g);
X Image[y][x][2] = CORRECT(p.b);
X}
X
XSSquare *
XSSquareCreate(xp, yp, xs, ys, d, parent)
Xint xp, yp, xs, ys, d;
XSSquare *parent;
X{
X SSquare *new;
X Float i1, i2, i3, i4;
X
X new = (SSquare *)Calloc(1, sizeof(SSquare));
X new->xpos = xp; new->ypos = yp;
X new->xsize = xs; new->ysize = ys;
X new->depth = d;
X new->parent = parent;
X i1 = INTENSITY(Image[new->ypos][new->xpos]);
X i2 = INTENSITY(Image[new->ypos+new->ysize][new->xpos]);
X i3 = INTENSITY(Image[new->ypos+new->ysize][new->xpos+new->xsize]);
X i4 = INTENSITY(Image[new->ypos][new->xpos+new->xsize]);
X new->mean = 0.25 * (i1+i2+i3+i4);
X if (SQ_AREA(new) < MINAREA) {
X new->prio = 0;
X new->closed = SSCLOSED;
X } else {
X new->var = SSquareComputeLeafVar(new, i1, i2, i3, i4);
X new->prio = PRIORITY(new);
X new->closed = NOT_CLOSED;
X }
X new->leaf = TRUE;
X return new;
X}
X
XFloat
XSSquareComputeLeafVar(sq, i1, i2, i3, i4)
XSSquare *sq;
XFloat i1, i2, i3, i4;
X{
X Float res, diff;
X
X diff = i1 - sq->mean;
X res = diff*diff;
X diff = i2 - sq->mean;
X res += diff*diff;
X diff = i3 - sq->mean;
X res += diff*diff;
X diff = i4 - sq->mean;
X return res + diff*diff;
X}
X
XSSquareDivideToDepth(sq, d)
XSSquare *sq;
Xint d;
X{
X if (sq->depth == d)
X return;
X if (sq->leaf)
X SSquareDivide(sq);
X SSquareDivideToDepth(sq->child[0], d);
X SSquareDivideToDepth(sq->child[1], d);
X SSquareDivideToDepth(sq->child[2], d);
X SSquareDivideToDepth(sq->child[3], d);
X}
X
XSSquareDivide(sq)
XSSquare *sq;
X{
X int lowx, lowy, midx, midy, hix, hiy;
X int newxsize, newysize, ndepth, supersample;
X /*
X * Divide the square into fourths by tracing 12
X * new samples if necessary.
X */
X newxsize = sq->xsize / 2;
X newysize = sq->ysize / 2;
X lowx = sq->xpos; lowy = sq->ypos;
X midx = sq->xpos + newxsize;
X midy = sq->ypos + newysize;
X hix = sq->xpos + sq->xsize;
X hiy = sq->ypos + sq->ysize;
X ndepth = sq->depth + 1;
X /* create new samples */
X supersample = FALSE;
X SSquareSample(midx, lowy, supersample);
X SSquareSample(lowx, midy, supersample);
X SSquareSample(midx, midy, supersample);
X SSquareSample(hix, midy, supersample);
X SSquareSample(midx, hiy, supersample);
X#ifdef SHARED_EDGES
X /* create and draw new squares */
X sq->child[0] = SSquareInstall(lowx,lowy,newxsize,newysize,ndepth,sq);
X sq->child[1] = SSquareInstall(midx, lowy, sq->xsize - newxsize,
X newysize, ndepth,sq);
X sq->child[2] = SSquareInstall(lowx, midy, newxsize,
X sq->ysize - newysize, ndepth,sq);
X sq->child[3] = SSquareInstall(midx, midy, sq->xsize - newxsize,
X sq->ysize - newysize, ndepth,sq);
X#else
X /*
X * draw additional samples in order to subdivide such that
X * edges of regions do not overlap
X */
X SSquareSample(midx +1, lowy, supersample);
X SSquareSample(midx +1, midy, supersample);
X SSquareSample(lowx, midy +1, supersample);
X SSquareSample(midx, midy +1, supersample);
X SSquareSample(midx +1, midy +1, supersample);
X SSquareSample(hix, midy +1, supersample);
X SSquareSample(midx +1, hiy, supersample);
X
X /* create and draw new squares */
X sq->child[0] = SSquareInstall(lowx,lowy,
X newxsize,newysize,ndepth,sq);
X sq->child[1] = SSquareInstall(midx+1, lowy, sq->xsize - newxsize -1,
X newysize, ndepth,sq);
X sq->child[2] = SSquareInstall(lowx, midy+1, newxsize,
X sq->ysize - newysize-1, ndepth,sq);
X sq->child[3] = SSquareInstall(midx+1, midy+1, sq->xsize - newxsize-1,
X sq->ysize - newysize-1, ndepth,sq);
X#endif
X sq->leaf = FALSE;
X /*
X * Recompute parent's mean and variance.
X */
X if (OVERLAPS_RECT(sq))
X SSquareRecomputeStats(sq);
X}
X
XSSquareRecomputeStats(sq)
XSSquare *sq;
X{
X Float maxp;
X int in[4], closeflag;
X
X in[0] = OVERLAPS_RECT(sq->child[0]);
X in[1] = OVERLAPS_RECT(sq->child[1]);
X in[2] = OVERLAPS_RECT(sq->child[2]);
X in[3] = OVERLAPS_RECT(sq->child[3]);
X
X if ((in[0] && (sq->child[0]->closed < SSCLOSED)) ||
X (in[1] && (sq->child[1]->closed < SSCLOSED)) ||
X (in[2] && (sq->child[2]->closed < SSCLOSED)) ||
X (in[3] && (sq->child[3]->closed < SSCLOSED))) {
X maxp = 0.;
X if (in[0])
X maxp = max(maxp, sq->child[0]->prio);
X if (in[1])
X maxp = max(maxp, sq->child[1]->prio);
X if (in[2])
X maxp = max(maxp, sq->child[2]->prio);
X if (in[3])
X maxp = max(maxp, sq->child[3]->prio);
X sq->closed = NOT_CLOSED;
X sq->prio = maxp;
X } else if ((sq->child[0]->closed == CLOSED_SUPER) &&
X (sq->child[1]->closed == CLOSED_SUPER) &&
X (sq->child[2]->closed == CLOSED_SUPER) &&
X (sq->child[3]->closed == CLOSED_SUPER)) {
X sq->closed = CLOSED_SUPER;
X sq->prio = 0;
X#if 0
X } else if ((!in[0] || sq->child[0]->closed >= SSCLOSED) &&
X (!in[1] || sq->child[1]->closed >= SSCLOSED) &&
X (!in[2] || sq->child[2]->closed >= SSCLOSED) &&
X (!in[3] || sq->child[3]->closed >= SSCLOSED)) {
X sq->closed = SSCLOSED;
X sq->prio = 0;
X#endif
X } else {
X sq->closed = SSCLOSED;
X sq->prio = 0;
X }
X if (sq->parent)
X SSquareRecomputeStats(sq->parent);
X}
X
XSSquare *
XSSquareInstall(xp, yp, xs, ys, d, parent)
Xint xp, yp, xs, ys, d;
XSSquare *parent;
X{
X SSquare *new;
X
X new = SSquareCreate(xp, yp, xs, ys, d, parent);
X SSquareDraw(new);
X return new;
X}
X
XSSquare *
XSSquareSelect(list)
XSSquare *list;
X{
X int i;
X SSquare *res, *which;
X
X /*
X * If mousebutton is pressed,
X * find the square in which the mouse is located and
X * return that if not a leaf (pixel-sized square).
X */
X if (GraphicsLeftMouseEvent()) {
X SuperSampleMode = 0;
X if ((res = SSquareFetchAtMouse(list)) != (SSquare *)NULL)
X return res;
X }
X else if (GraphicsRightMouseEvent()) {
X SuperSampleMode = 1;
X if ((res = SSquareFetchAtMouse(list)) != (SSquare *)NULL) {
X return res;
X }
X }
X if (list->closed >= SSCLOSED) {
X if (Rectmode) {
X Rectmode = FALSE;
X RecomputePriority(SSquares);
X return SSquareSelect(list);
X }
X return (SSquare *)NULL;
X }
X /*
X * Otherwise, find the square with the greatest
X * 'priority'.
X */
X res = list;
X while (res && !res->leaf) {
X which = (SSquare *)NULL;
X for (i = 0; i < 4; i++) {
X if ((res->child[i]->closed < SSCLOSED) &&
X OVERLAPS_RECT(res->child[i])) {
X which = res->child[i];
X break;
X }
X }
X while (++i < 4) {
X if ((res->child[i]->closed < SSCLOSED) &&
X which->prio < res->child[i]->prio &&
X OVERLAPS_RECT(res->child[i]))
X which = res->child[i];
X }
X res = which;
X }
X return res;
X}
X
XSSquare *
XSSquareFetchAtMouse(list)
XSSquare *list;
X{
X SSquare *res;
X int x, y;
X
X /*
X * Get mouse position.
X */
X GraphicsGetMousePos(&x, &y);
X res = list;
X while (!res->leaf && (res->closed < SSCLOSED)) {
X /*
X * Find in which child the mouse is located.
X */
X if (x < res->child[1]->xpos) {
X if (y < res->child[2]->ypos)
X res = res->child[0];
X else
X res = res->child[2];
X } else if (y < res->child[3]->ypos)
X res = res->child[1];
X else
X res = res->child[3];
X }
X if (res->closed >= SSCLOSED)
X return (SSquare *)NULL;
X return res;
X}
X
XSSquareDraw(sq)
XSSquare *sq;
X{
X if (SQ_AREA(sq) >= MINAREA)
X GraphicsDrawRectangle(sq->xpos, sq->ypos, sq->xsize, sq->ysize,
X Image[sq->ypos][sq->xpos],
X Image[sq->ypos][sq->xpos+sq->xsize],
X Image[sq->ypos+sq->ysize][sq->xpos+sq->xsize],
X Image[sq->ypos+sq->ysize][sq->xpos]);
X else
X DrawPixels(sq->xpos, sq->ypos, sq->xsize, sq->ysize);
X if (!sq->leaf) {
X SSquareDraw(sq->child[0]);
X SSquareDraw(sq->child[1]);
X SSquareDraw(sq->child[2]);
X SSquareDraw(sq->child[3]);
X }
X}
X
XDrawPixels(xp, yp, xs, ys)
Xint xp, yp, xs, ys;
X{
X int x, y, xi, yi;
X
X yi = yp;
X for (y = 0; y <= ys; y++, yi++) {
X xi = xp;
X for (x = 0; x <= xs; x++, xi++) {
X SSquareSample(xi, yi, SuperSampleMode);
X GraphicsDrawPixel(xi, yi, Image[yi][xi]);
X }
X }
X}
END_OF_FILE
if test 17440 -ne `wc -c <'raypaint/render.c'`; then
echo shar: \"'raypaint/render.c'\" unpacked with wrong size!
fi
# end of 'raypaint/render.c'
fi
echo shar: End of archive 16 \(of 19\).
cp /dev/null ark16isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 19 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...