home *** CD-ROM | disk | FTP | other *** search
- /*
- * fl.c
- *
- * fracland: a fractal landscape primitive for rayshade.
- *
- * Copyright (C) 1992, Lawrence K. Coffin.
- * Parts Copyright (C) 1989, 1991, Craig E. Kolb.
- * All rights reserved.
- *
- * Parts of this program are from "Numerical Recipes in C" by William H.
- * Press, Brian P. Flannery, Saul A. Teukolsky, and William T. Vetterling.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- */
-
- #include "geom.h"
- #include "hf.h"
- #include "fl.h"
- #include <math.h>
- #if defined(AMIGA) && defined(__GNUC__)
- #define pow mypow
- extern double mypow(const double x, const double y);
- #endif
- #include <stdlib.h>
-
- static Methods *iHfMethods = NULL;
- static char hfName[] = "heighfield";
-
- static void integrate_grid(), QueueTri();
- static int DDA2D(), CheckCell();
- static Float intHftri();
- static float minalt(), maxalt();
-
- typedef struct {
- int stepX, stepY;
- Float tDX, tDY;
- float minz, maxz;
- int outX, outY;
- Vector cp, pDX, pDY;
- } Trav2D;
-
- hfTri *CreateHfTriangle(), *GetQueuedTri();
-
- extern unsigned long HFTests, HFHits;
-
- float rv();
-
- Hf *
- FlCreate(seed,subdiv)
- long int seed;
- int subdiv;
- {
- Hf *hf;
- FILE *fp;
- float val, *maxptr, *minptr;
- int i, j, n;
- int in,i2,x,y;
- float rc, temp;
-
-
- seednrand(seed);
-
- hf = (Hf *)Malloc(sizeof(Hf));
- /*
- * Make the following an option someday.
- */
- hf->BestSize = BESTSIZE;
- /*
- * Store the inverse for faster computation.
- */
- hf->iBestSize = 1. / (float)hf->BestSize;
- /*
- * Get HF size.
- */
- n = pow(2.0,(double)subdiv);
- hf->size = n+1;
-
- hf->data = (float **)share_malloc(hf->size * sizeof(float *));
-
- for(i = 0; i < hf->size; i++){
- hf->data[i] = (float *)share_malloc(hf->size * sizeof(float));
- }
-
-
-
- hf->data[0][0] = 0;
- hf->data[0][n] = 0;
- hf->data[n][0] = 0;
- hf->data[n][n] = 0;
- for (i=0; i<subdiv; i++){
- in = (double)n/pow(2.0,(double)i);
- i2 = in/2;
- rc = 1.0/pow(2.0,(double)i);
- for (x=0; x<n; x+=in){
- for (y=0; y<n; y+=in){
- hf->data[x+i2][y ] = (hf->data[x ][y ] + hf->data[x+in][y ])/2 + rv()*rc;
- hf->data[x ][y+i2] = (hf->data[x ][y ] + hf->data[x ][y+in])/2 + rv()*rc;
- hf->data[x+in][y+i2] = (hf->data[x+in][y ] + hf->data[x+in][y+in])/2 + rv()*rc;
- hf->data[x+i2][y+in] = (hf->data[x ][y+in] + hf->data[x+in][y+in])/2 + rv()*rc;
- hf->data[x+i2][y+i2] = (hf->data[x][y] + hf->data[x+in][y] + hf->data[x][y+in] + hf->data[x+in][y+in])/4 + rv()*rc;
- }
- }
- }
- /*
- * This flips the points around so the surfaces created here are the same
- * as the surfaces created with the program "fracland".
- */
- for (x = 0; x < hf->size; x++){
- for (y = x; y < hf->size; y++){
- temp = hf->data[x][y];
- hf->data[x][y] = hf->data[y][x];
- hf->data[y][x] = temp;
- }
- }
-
- for (i = 0; i < hf->size; i++) {
- for (j = 0; j < hf->size; j++) {
- val = hf->data[i][j];
- if (val <= HF_UNSET) {
- hf->data[i][j] = HF_UNSET;
- /*
- * Don't include the point in min/max
- * calculations.
- */
- continue;
- }
- if (val > hf->maxz)
- hf->maxz = val;
- if (val < hf->minz)
- hf->minz = val;
- }
- }
-
- /*
- * Allocate levels of grid. hf->levels = log base BestSize of hf->size
- */
- for (i = hf->size, hf->levels = 0; i > hf->BestSize; i /= hf->BestSize,
- hf->levels++)
- ;
- hf->levels++;
- hf->qsize = CACHESIZE;
- hf->q = (hfTri **)Calloc((unsigned)hf->qsize, sizeof(hfTri *));
- hf->qtail = 0;
-
- hf->lsize = (int *)share_malloc(hf->levels * sizeof(int));
- hf->spacing = (float *)share_malloc(hf->levels * sizeof(float));
- hf->boundsmax = (float ***)share_malloc(hf->levels * sizeof(float **));
- hf->boundsmin = (float ***)share_malloc(hf->levels * sizeof(float **));
-
- hf->spacing[0] = hf->size -1;
- hf->lsize[0] = (int)hf->spacing[0];
- hf->boundsmax[0] = (float **)share_malloc(hf->lsize[0]*sizeof(float *));
- hf->boundsmin[0] = (float **)share_malloc(hf->lsize[0]*sizeof(float *));
- /*
- * Compute initial bounding boxes
- */
- for (i = 0; i < hf->lsize[0]; i++) {
- hf->boundsmax[0][i]=(float *)share_malloc(hf->lsize[0]*sizeof(float));
- hf->boundsmin[0][i]=(float *)share_malloc(hf->lsize[0]*sizeof(float));
- maxptr = hf->boundsmax[0][i];
- minptr = hf->boundsmin[0][i];
- for (j = 0; j < hf->lsize[0]; j++) {
- *maxptr++ = maxalt(i, j, hf->data) + EPSILON;
- *minptr++ = minalt(i, j, hf->data) - EPSILON;
- }
- }
-
- for (i = 1; i < hf->levels; i++) {
- hf->spacing[i] = hf->spacing[i-1] * hf->iBestSize;
- hf->lsize[i] = (int)hf->spacing[i];
- if ((Float)hf->lsize[i] != hf->spacing[i])
- hf->lsize[i]++;
- hf->boundsmax[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
- hf->boundsmin[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
- for (j = 0; j < hf->lsize[i]; j++) {
- hf->boundsmax[i][j] = (float *)share_malloc(hf->lsize[i] *
- sizeof(float));
- hf->boundsmin[i][j] = (float *)share_malloc(hf->lsize[i] *
- sizeof(float));
- }
- integrate_grid(hf, i);
- }
-
- hf->boundbox[LOW][X] = hf->boundbox[LOW][Y] = 0.0;
- hf->boundbox[HIGH][X] = hf->boundbox[HIGH][Y] = 1.0;
- hf->boundbox[LOW][Z] = hf->minz;
- hf->boundbox[HIGH][Z] = hf->maxz;
-
- return hf;
- }
- /*
- * Generate a random value from -0.5 to 0.5
- */
-
- float rv(){
- float y;
- y = (float) nrand() - 0.5;
- return (y);
- }
-
- Methods *
- FlMethods()
- {
- if (iHfMethods == (Methods *)NULL) {
- iHfMethods = MethodsCreate();
- iHfMethods->create = (GeomCreateFunc *)FlCreate;
- iHfMethods->methods = FlMethods;
- iHfMethods->name = HfName;
- iHfMethods->intersect = HfIntersect;
- iHfMethods->normal = HfNormal;
- iHfMethods->uv = HfUV;
- iHfMethods->bounds = HfBounds;
- iHfMethods->stats = HfStats;
- iHfMethods->checkbounds = TRUE;
- iHfMethods->closed = FALSE;
- }
-
- return iHfMethods;
- }
-
-
- /*
- * Build min/max altitude value arrays for the given grid level.
- */
- static void
- integrate_grid(hf, level)
- Hf *hf;
- int level;
- {
- int i, j, k, l, ii, ji;
- float max_alt, min_alt;
- float **maxinto, **mininto, **frommax, **frommin, *minptr, *maxptr;
- int insize, fromsize, fact;
-
- maxinto = hf->boundsmax[level];
- mininto = hf->boundsmin[level];
- insize = hf->lsize[level];
- frommax = hf->boundsmax[level-1];
- frommin = hf->boundsmin[level-1];
- fact = hf->BestSize;
- fromsize = hf->lsize[level-1];
-
- ii = 0;
-
- for (i = 0; i < insize; i++) {
- ji = 0;
- for (j = 0; j < insize; j++) {
- max_alt = HF_UNSET;
- min_alt = -HF_UNSET;
- for (k = 0; k <= fact; k++) {
- if (ii+k >= fromsize)
- continue;
- maxptr = &frommax[ii+k][ji];
- minptr = &frommin[ii+k][ji];
- for (l = 0; l <= fact; l++,maxptr++,minptr++) {
- if (ji+l >= fromsize)
- continue;
- if (*maxptr > max_alt)
- max_alt = *maxptr;
- if (*minptr < min_alt)
- min_alt = *minptr;
- }
- }
- maxinto[i][j] = max_alt + EPSILON;
- mininto[i][j] = min_alt - EPSILON;
- ji += fact;
- }
- ii += fact;
- }
- }
- /*
- * Return maximum height of cell indexed by y,x. This could be done
- * as a macro, but many C compliers will choke on it.
- */
- static float
- minalt(y,x,data)
- int x, y;
- float **data;
- {
- float min_alt;
-
- min_alt = min(data[y][x], data[y+1][x]);
- min_alt = min(min_alt, data[y][x+1]);
- min_alt = min(min_alt, data[y+1][x+1]);
- return min_alt;
- }
-
- /*
- * Return maximum cell height, as above.
- */
- static float
- maxalt(y,x,data)
- int x, y;
- float **data;
- {
- float max_alt;
-
- max_alt = max(data[y][x], data[y+1][x]);
- max_alt = max(max_alt, data[y][x+1]);
- max_alt = max(max_alt, data[y+1][x+1]);
- return max_alt;
- }
-