/* surface.c */ #include "patch.h" #include "surface.h" #include "vertex.h" #include "ray.h" #include "pools.h" #include "error.h" #ifdef NOPOOLS #define NEWSURFACE() (SURFACE *)Alloc(sizeof(SURFACE)) #define DISPOSESURFACE(ptr) Free((char *)ptr, sizeof(SURFACE)) #else static POOL *surfacePool = (POOL *)NULL; #define NEWSURFACE() (SURFACE *)NewPoolCell(sizeof(SURFACE), 0, "surfaces", &surfacePool) #define DISPOSESURFACE(ptr) Dispose((char *)ptr, &surfacePool) #endif /* a static counter that is increased each time a surface is created. * for making unique SURFACE ids. */ static int surfID = 0; int nrsurfaces = 0; /* indicates whether or not, and if so, which, colors are given when creating * a new surface. */ enum COLORFLAGS colorflags = NO_COLORS; static void NormalizeVertexColor(VERTEX *vertex) { int nrpatches = 0; PATCHLIST *patches; for (patches=vertex->patches; patches; patches=patches->next) nrpatches++; if (nrpatches > 0) { vertex->color.r /= (float)nrpatches; vertex->color.g /= (float)nrpatches; vertex->color.b /= (float)nrpatches; } } /* Fills in the SURFACE backpointer of the face belonging to the given * surface. */ void SurfaceConnectFace(SURFACE *surf, PATCH *face) { int i; COLOR rho; face->surface = surf; /* also fill in a nicer default color for the patch */ switch (colorflags) { case FACE_COLORS: break; case VERTEX_COLORS: /* average color of the vertices */ RGBSET(face->color, 0, 0, 0); for (i=0; inrvertices; i++) { face->color.r += face->vertex[i]->color.r; face->color.g += face->vertex[i]->color.g; face->color.b += face->vertex[i]->color.b; } face->color.r /= (float)i; face->color.g /= (float)i; face->color.b /= (float)i; break; default: { rho = PatchAverageNormalAlbedo(face, BRDF_DIFFUSE_COMPONENT|BRDF_GLOSSY_COMPONENT); ColorToRGB(rho, &face->color); } } } /* This routine creates a SURFACE struct with given material, points, etc... */ SURFACE *SurfaceCreate(MATERIAL *material, VECTORLIST *points, VECTORLIST *normals, VECTORLIST *texCoords, VERTEXLIST *vertices, PATCHLIST *faces, enum COLORFLAGS flags) { SURFACE *surf; surf = NEWSURFACE(); nrsurfaces++; surf->id = surfID++; surf->material = material; surf->points = points; surf->normals = normals; surf->vertices = vertices; surf->texCoords = texCoords; surf->faces = faces; colorflags = flags; /* if colroflags == VERTEX_COLORS< the vertices are assumed to contain * the sum of the colors as used in each patch sharing the vertex. */ if (colorflags == VERTEX_COLORS) VertexListIterate(surf->vertices, NormalizeVertexColor); /* fill in the SURFACE backpointer of the FACEs in the SURFACE. */ ForAllPatches(face, surf->faces) { SurfaceConnectFace(surf, face); } EndForAll; /* compute vertex colors */ if (colorflags != VERTEX_COLORS) VertexListIterate(surf->vertices, ComputeVertexColor); colorflags = NO_COLORS; return surf; } /* This method will destroy the GEOMetry and it's children GEOMetries if * any */ void SurfaceDestroy(SURFACE *surf) { /* It is important that the patches be destroyed first and then the * vertices, because otherwise, the brep_data for the vertices would * still be used and thus not destroyed by the BREP library. */ PatchListIterate(surf->faces, PatchDestroy); PatchListDestroy(surf->faces); VertexListIterate(surf->vertices, VertexDestroy); VertexListDestroy(surf->vertices); VectorListIterate(surf->points, VectorDestroy); VectorListDestroy(surf->points); VectorListIterate(surf->normals, VectorDestroy); VectorListDestroy(surf->normals); VectorListIterate(surf->texCoords, VectorDestroy); VectorListDestroy(surf->texCoords); DISPOSESURFACE(surf); nrsurfaces--; } /* this method will print the GEOMetry to the file out */ void SurfacePrint(FILE *out, SURFACE *surface) { fprintf(out, "Surface id %d: material %s, patches ID: ", surface->id, surface->material->name); PatchListIterate1B(surface->faces, PatchPrintID, out); fprintf(out, "\n"); PatchListIterate1B(surface->faces, PatchPrint, out); } /* this method will compute a bounding box for a GEOMetry. The bounding box * is filled in in boundingbox and a pointer to the filled in boundingbox * returned. */ float *SurfaceBounds(SURFACE *surf, float *boundingbox) { return PatchListBounds(surf->faces, boundingbox); } /* returns the list of PATCHes making up a primitive GEOMetry. This * method is not implemented for aggregate GEOMetries. */ PATCHLIST *SurfacePatchlist(SURFACE *surf) { return surf->faces; } HITREC *SurfaceDiscretisationIntersect(SURFACE *surf, RAY *ray, float mindist, float *maxdist, int hitflags, HITREC *hitstore) { return PatchListIntersect(surf->faces, ray, mindist, maxdist, hitflags, hitstore); } HITLIST *SurfaceAllDiscretisationIntersections(HITLIST *hits, SURFACE *surf, RAY *ray, float mindist, float maxdist, int hitflags) { return PatchListAllIntersections(hits, surf->faces, ray, mindist, maxdist, hitflags); } GEOM_METHODS surfaceMethods = { (float *(*)(void *, float *))SurfaceBounds, (void (*)(void *))SurfaceDestroy, (void (*)(FILE *, void *))SurfacePrint, (GEOMLIST *(*)(void *))NULL, (PATCHLIST *(*)(void *))SurfacePatchlist, (HITREC *(*)(void *, RAY *, float, float *, int, HITREC *))SurfaceDiscretisationIntersect, (HITLIST *(*)(HITLIST *, void *, RAY *, float, float, int))SurfaceAllDiscretisationIntersections, (void *(*)(void *))NULL };