kent@sparky.IMD.Sterling.COM (Kent Landfield) (01/03/91)
Submitted-by: ingwa@isy.liu.se (Inge Wallin) Posting-number: Volume 16, Issue 7 Archive-name: sipp2.0/part03 #!/bin/sh # This is part 03 of sipp-2.0 # ============= libsipp/sipp.c ============== if test ! -d 'libsipp'; then echo 'x - creating directory libsipp' mkdir 'libsipp' fi if test -f 'libsipp/sipp.c' -a X"$1" != X"-c"; then echo 'x - skipping libsipp/sipp.c (File already exists)' else echo 'x - extracting libsipp/sipp.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'libsipp/sipp.c' && /* X * sipp - SImple Polygon Processor X * X * A general 3d graphic package X * X * Copyright Jonas Yngvesson (jonas-y@isy.liu.se) 1988/89/90 X * Inge Wallin (ingwa@isy.liu.se) 1990 X * X * This program is free software; you can redistribute it and/or modify X * it under the terms of the GNU General Public License as published by X * the Free Software Foundation; either version 1, or any later version. X * This program is distributed in the hope that it will be useful, X * but WITHOUT ANY WARRANTY; without even the implied warranty of X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X * GNU General Public License for more details. X * You can receive a copy of the GNU General Public License from the X * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X * See the README for more information. X * X * Revision history: X * X * 901219 At last! 2.0 is out of the bag. And right in time for X-mas :-) X * *Major* rewrite. A new level in the object hierarchy introduced. X * An object is now a collection of surfaces and other objects X * (subobjects). This allows creation of complex composite objects. X * Objects in the hierarchy have coupled transformations. X * The old "Object" is now, more appropriately, called Surface. X * A fatal bug in the viewing transformation fixed. X * Objects and surfaces have internal reference counters so deletion X * won't leave dangling references in an hierachy. X * The code is now almost readable. X * Images format changed to PPM since much more applications X * exists that can handle that format. X * The shader package is extended and a package with functions X * to create geometric primitives as objects is provided. X * X * 901030 More general shader interface. The simple internal shader X * was moved out of sipp into its own file. Several shaders X * provided together with it in a "shader package". X * X * 900712 Major code beautifying, quite a lot left to do though... X * Typedefs instead of raw structures, X * much better typenames, lots of comments added (probably X * not enough though). Split into a few header files and X * a source file. More portable interface. X * X * 891124 Made the object representation independent of the X * illumination model used. A user can now supply his X * own surface description and shading function. X * Added support for texture mapping (both solid and 2d). X * No texture mapping is built into the internal shader though. X * X * 891120 Added colour. New illumination model. Simple antialiasing X * with double oversampling and a box filter. X * X * 891028 Converted from sippuz to sipp. Z-buffer changed X * to scan-line z-buffer. X * Phong-shading. X * The stack notion introduced. X * Changed fixed viewpoint to a user defined one. X * World coordinates and picture resolution can be chosen X * freely. X * X * 881128 Converted from Pascal to C. Gouraud shading. Redesign of the X * data structures. X * X * 88???? Original program "sippuz - simple polygon processing using a X * z-buffer", written in Hedrick Pascal on a DEC-20 system X * running TOPS-20. Greyscales only. Flat shading. X */ X X #include <stdio.h> #include <math.h> #include <malloc.h> #ifndef NOMEMCPY #include <memory.h> #endif #include <xalloca.h> X #include <sipp.h> #include <sipptypes.h> #include <geometric.h> X X #define VERSION "2.0" X #define ZCLIPF 100.0 /* Magic number used when defining hither & yon */ X X X /* X * Global variables. X */ static Vertex *vertex_tree; /* Vertex tree for current object. */ static Vertex_ref *vertex_stack; /* Vertex stack for current polygon. */ static Vertex_ref *vstack_bottom; /* Last entry in vertex stack. */ static Polygon *poly_stack; /* Polygon stack for current object. */ static Inst_object *object_db; /* Object database. */ static Lightsource *lightsrc_stack; /* Lightsource list. */ static Bucket *y_bucket; /* Y-bucket for edge lists. */ static double dist_limit; /* Minimal distance between two */ X /* vertices without them being */ X /* considered to be the same vertex. */ static int first_vertex; /* Used when determining if we are */ X /* installing the first vertex in an */ X /* object. *Not* a boolean! */ X /* X * Stack of transformation matrices used X * when traversing an object hierarchy. X */ static struct tm_stack_t { X Transf_mat mat; X struct tm_stack_t *next; } *tm_stack; X static Transf_mat curr_mat; /* Current transformation matrix */ X static Transf_mat ident_matrix = {{ /* Unit tranfs. matrix */ X { 1.0, 0.0, 0.0 }, X { 0.0, 1.0, 0.0 }, X { 0.0, 0.0, 1.0 }, X { 0.0, 0.0, 0.0 } X }}; X X /* X * Viewpoint definition X */ static struct { X double x0, y0, z0; /* viewpoint position */ X double x, y, z; /* point to look at */ X Vector vec; /* vector from point to eye, used in shading calc. */ X Vector up; /* Up direction in the view */ X double focal_ratio; } camera; X X X /*======================== "Safe" malloc ================================*/ static char * smalloc(size) X int size; { X char *p; X X p = (char *)malloc(size); X if (p == NULL) { X fprintf(stderr, "Out of virtual memory.\n"); X exit(1); X } X X return p; } X X X /*================ Functions that handles lightsources ==================*/ X /* X * Define a new lightsource in the scene. X */ void lightsource_push(x, y, z, intensity) X double x, y, z, intensity; { X double norm; X Lightsource *lp; X X norm = sqrt(x * x + y * y + z * z); X lp = (Lightsource *)smalloc(sizeof(Lightsource)); X lp->dir.x = x / norm; X lp->dir.y = y / norm; X lp->dir.z = z / norm; X lp->intensity = intensity; X lp->next = lightsrc_stack; X lightsrc_stack = lp; } X X X /*================ Functions that handles the viewpoint ==================*/ X /* X * Calculate the vector from the point of interest X * to the viewpoint. The shaders needs this vector normalized X * while the view coordinate transformation needs it X * non normalized, therefore we need this routine to X * recalculate the non normalized value. X */ static void view_vec_eval() { X MakeVector(camera.vec, X camera.x0 - camera.x, X camera.y0 - camera.y, X camera.z0 - camera.z); } X X X /* X * Define the viewpoint. X */ void view_from(x0, y0, z0) X double x0, y0, z0; { X camera.x0 = x0; X camera.y0 = y0; X camera.z0 = z0; X view_vec_eval(); } X X /* X * Define the point that we are looking at. X */ void view_at(x, y, z) X double x, y, z; { X camera.x = x; X camera.y = y; X camera.z = z; X view_vec_eval(); } X X /* X * Define the "up" direction of the view (well, rather the y-z plane). X */ void view_up(x, y, z) X double x, y, z; { X MakeVector(camera.up, x, y, z); } X X /* X * Set the focal ratio for the "camera". X */ void view_focal(ratio) X double ratio; { X camera.focal_ratio = ratio; } X X /* X * Set all viewpoint parameters in one call. X */ void viewpoint(x0, y0, z0, x, y, z, ux, uy, uz, ratio) X double x0, y0, z0, x, y, z, ux, uy, uz, ratio; { X camera.x0 = x0; X camera.y0 = y0; X camera.z0 = z0; X camera.x = x; X camera.y = y; X camera.z = z; X MakeVector(camera.up, ux, uy, uz); X camera.focal_ratio = ratio; X view_vec_eval(); } X X X /*============= Functions that handles the object database ================*/ X /* X * Search for a vertex in a vertex tree. Vertices are asumed X * to be equal if they differ less than dist_limit in all directions. X * X * If the vertex is not found, install it in the tree. X */ static Vertex * vertex_lookup(x, y, z, u, v, w, p) X double x, y, z, u, v, w; X Vertex **p; { X double xdist, ydist, zdist; X X if (*p == NULL) { X *p = (Vertex *)smalloc(sizeof(Vertex)); X (*p)->x = x; X (*p)->y = y; X (*p)->z = z; X (*p)->a = 0; X (*p)->b = 0; X (*p)->c = 0; X (*p)->u = u; X (*p)->v = v; X (*p)->w = w; X (*p)->big = NULL; X (*p)->sml = NULL; X return *p; X } else if ((xdist = x - ((*p)->x)) > dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->big))); X } else if (xdist < -dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->sml))); X } else if ((ydist = y - ((*p)->y)) > dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->big))); X } else if (ydist < -dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->sml))); X } else if ((zdist = z - ((*p)->z)) > dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->big))); X } else if (zdist < -dist_limit) { X return (vertex_lookup(x, y, z, u, v, w, &((*p)->sml))); X } else { X return *p; X } } X X /* X * Push a vertex on the vertex stack (without texture coordinates). X */ void vertex_push(x, y, z) X double x, y, z; { X vertex_tx_push(x, y, z, (double)0.0, (double)0.0, (double)0.0); } X X /* X * Push a vertex on the vertex stack (with texture coordinates). X */ void vertex_tx_push(x, y, z, u, v, w) X double x, y, z, u, v, w; { X Vertex_ref *vref; X X /* X * To get a reasonable dist_limit we use the following "heuristic" X * value: X * The distance between the first two vertices installed in X * the scene, multiplied by the magic number 1e-10, unless X * they are the same vertex. In that case 1e-10 is used until X * we get a vertex that differs from the first. X */ X if (!first_vertex) X first_vertex++; X else if (first_vertex == 1) { X dist_limit = sqrt((x - vertex_tree->x) * (x - vertex_tree->x) X + (y - vertex_tree->y) * (y - vertex_tree->y) X + (z - vertex_tree->z) * (z - vertex_tree->z)) X * 1e-10; /* Magic!!! */ X if (dist_limit != 0.0) X first_vertex++; X else X dist_limit = 1e-10; /* More Magic */ X } X vref = (Vertex_ref *)smalloc(sizeof(Vertex_ref)); X if (vertex_stack == NULL) { X vertex_stack = vref; X } else { X vstack_bottom->next = vref; X } X vstack_bottom = vref; X vref->vertex = vertex_lookup(x, y, z, u, v, w, &vertex_tree); X vref->next = NULL; } X X /* X * Push a polygon on the polygon stack. Empty the vertex stack afterwards. X */ void polygon_push() { X Polygon *polyref; X X if (vertex_stack != NULL) { X polyref = (Polygon *)smalloc(sizeof(Polygon)); X polyref->vertices = vertex_stack; X polyref->backface = 0; X polyref->next = poly_stack; X poly_stack = polyref; X vertex_stack = NULL; X } } X X /* X * Create a surface of all polygons in the polygon stack. X * Empty the polygon stack afterwards. X */ Surface * surface_create(surf_desc, shader) X void *surf_desc; X Shader *shader; { X Surface *surfref; X X if (poly_stack != NULL) { X surfref = (Surface *)smalloc(sizeof(Surface)); X surfref->vertices = vertex_tree; X surfref->polygons = poly_stack; X surfref->surface = surf_desc; X surfref->shader = shader; X surfref->ref_count = 0; X surfref->next = NULL; X vertex_tree = NULL; X poly_stack = NULL; X first_vertex = 0; X return surfref; X } else X return NULL; } X X /* X * Create a surface to be shaded with the simple shader. X */ Surface * surface_basic_create(ambient, red, grn, blu, specular, c3) X double ambient, red, grn, blu, specular, c3; { X Surf_desc *surf_desc; X X surf_desc = (Surf_desc *)smalloc(sizeof(Surf_desc)); X surf_desc->ambient = ambient; X surf_desc->color.red = red; X surf_desc->color.grn = grn; X surf_desc->color.blu = blu; X surf_desc->specular = specular; X surf_desc->c3 = c3; X return surface_create(surf_desc, basic_shader); } X X /* X * Set SURFACE to be shaded with the shading function SHADER X * using the surface description SURF_DESC. X */ void surface_set_shader(surface, surf_desc, shader) X Surface *surface; X void *surf_desc; X Shader *shader; { X X if (surface != NULL) { X surface->surface = surf_desc; X surface->shader = shader; X } } X X /* X * Set SURFACE to be shaded with the simple shader. X */ void surface_basic_shader(surface, ambient, red, grn, blu, specular, c3) X Surface *surface; X double ambient, red, grn, blu, specular, c3; { X Surf_desc *surf_desc; X X surf_desc = (Surf_desc *)smalloc(sizeof(Surf_desc)); X surf_desc->ambient = ambient; X surf_desc->color.red = red; X surf_desc->color.grn = grn; X surf_desc->color.blu = blu; X surf_desc->specular = specular; X surf_desc->c3 = c3; X surface_set_shader(surface, surf_desc, basic_shader); } X X X /* X * Copy a vertex tree. X */ static Vertex * copy_vertices(vp) X Vertex *vp; { X Vertex *tmp; X X if (vp == NULL) X return NULL; X tmp = (Vertex *)smalloc(sizeof(Vertex)); X *tmp = *vp; X tmp->big = copy_vertices(vp->big); X tmp->sml = copy_vertices(vp->sml); X return tmp; } X X /* X * We have a list of vertes references, each pointing into a certain X * vertex tree. Create a new list with pointers into a copy of the X * first vertex tree. X */ static Vertex_ref * copy_vlist(vp, surface) X Vertex_ref *vp; X Surface *surface; { X Vertex_ref *tmp; X X if (vp == NULL) X return NULL; X tmp = (Vertex_ref *)smalloc(sizeof(Vertex_ref)); X tmp->vertex = vertex_lookup(vp->vertex->x, vp->vertex->y, vp->vertex->z, X vp->vertex->u, vp->vertex->v, vp->vertex->w, X &(surface->vertices)); X tmp->next = copy_vlist(vp->next, surface); X return tmp; } X X /* X * Copy a list of polygons. X */ static Polygon * copy_polygons(pp, surface) X Polygon *pp; X Surface *surface; { X Polygon *tmp; X X if (pp == NULL) X return NULL; X tmp = (Polygon *)smalloc(sizeof(Polygon)); X tmp->vertices = copy_vlist(pp->vertices, surface); X tmp->next = copy_polygons(pp->next, surface); X return tmp; } X X /* X * Copy a list of surfaces. All polygons and vertices are copied but X * the shader and surface descriptions are the same as in the X * original surfaces. X */ static Surface * surface_copy(surface) X Surface *surface; { X Surface *newsurf; X X if (surface != NULL) { X newsurf = (Surface *)smalloc(sizeof(Surface)); X if (newsurf == NULL) { X return NULL; X } X memcpy(newsurf, surface, sizeof(Surface)); X newsurf->vertices = copy_vertices(surface->vertices); X newsurf->polygons = copy_polygons(surface->polygons, newsurf); X newsurf->ref_count = 1; X newsurf->next = surface_copy(surface->next); X return newsurf; X } else { X return NULL; X } } X X /* X * Delete a vertex tree. X */ static void delete_vertices(vtree) X Vertex **vtree; { X if (*vtree != NULL) { X delete_vertices(&((*vtree)->big)); X delete_vertices(&((*vtree)->sml)); X free(*vtree); X *vtree = NULL; X } } X X /* X * Delete a surface list. X */ static void surface_delete(surface) X Surface *surface; { X Vertex_ref *vref1, *vref2; X Polygon *polyref1, *polyref2; X X if (surface != NULL) { X if (--surface->ref_count == 0) { X if (surface->next != NULL) { X surface_delete(surface->next); X } X polyref2 = surface->polygons; X while (polyref2 != NULL) { X vref2 = polyref2->vertices; X while (vref2 != NULL) { X vref1 = vref2; X vref2 = vref2->next; X free(vref1); X } X polyref1 = polyref2; X polyref2 = polyref2->next; X free(polyref1); X } X delete_vertices(&(surface->vertices)); X free(surface); X } X } } X X /* X * Install an object in the rendering database. X */ static void r_object_install(obj, obj_tree) X Object *obj; X Inst_object **obj_tree; { X if (obj != NULL) { X obj->ref_count++; X if (*obj_tree == NULL) { X *obj_tree = (Inst_object *)smalloc(sizeof(Inst_object)); X (*obj_tree)->object = obj; X (*obj_tree)->big = NULL; X (*obj_tree)->sml = NULL; X } else if (obj > (*obj_tree)->object) { X r_object_install(obj, &(*obj_tree)->big); X } else if (obj < (*obj_tree)->object) { X r_object_install(obj, &(*obj_tree)->sml); X } X } } X X /* X * Interface to r_object_install(). (Why is there no X * subfunctions in C?...) X */ void object_install(obj) X Object *obj; { X r_object_install(obj, &object_db); } X X X /* X * Subfunction to r_object_uninstall. X */ static void r_del(r, q) X Inst_object **r; X Inst_object *q; { X if ((*r)->big != NULL) { X r_del(&((*r)->big), q); X } else { X q->object = (*r)->object; X q = *r; X *r = (*r)->sml; X free(q); X } } X X /* X * Delete an object from the rendering database. X * The object itself is not deleted of course. X */ static void r_object_uninstall(obj, root) X Object *obj; X Inst_object **root; { X Inst_object *ptr; X X if (*root == NULL) { X return; /* Object is not in the tree */ X } else if (obj < (*root)->object) { X r_object_uninstall(obj, &(*root)->sml); X } else if (obj > (*root)->object) { X r_object_uninstall(obj, &(*root)->big); X } else { X obj->ref_count--; X ptr = *root; X if (ptr->big == NULL) { X *root = ptr->sml; X } else if (ptr->sml == NULL) { X *root = ptr->big; X } else { X r_del(&ptr->sml, ptr); X } X } } X X /* X * Interface to r_object_uninstall. X */ void object_uninstall(obj) X Object *obj; { X r_object_uninstall(obj, &object_db); } X X X /* X * Create an empty object. Before it is rendered it X * must get a surface or a subobject. X */ Object * object_create() { X Object *obj; X X obj = (Object *)smalloc(sizeof(Object)); X obj->surfaces = NULL; X obj->sub_obj = NULL; X MatCopy(&obj->transf, &ident_matrix); X obj->ref_count = 0; X obj->next = NULL; X X return obj; } X X X /* X * Copy the top object in an object hierarchy. X * The new object will reference the same X * subobjects and surfaces as the original object. X * if REF_COUNT_UPDATE is true, the reference counts X * in the surfaces and subobjects will be incremented. X */ static Object * object_copy(object, ref_count_update) X Object *object; X bool ref_count_update; { X Object *newobj; X X if (object == NULL) { X return NULL; X } X X if ((newobj = (Object *)smalloc(sizeof(Object))) != NULL) { X memcpy(newobj, object, sizeof(Object)); X if (ref_count_update) { X if (newobj->sub_obj != NULL) { X newobj->sub_obj->ref_count++; X } X if (newobj->surfaces != NULL) { X newobj->surfaces->ref_count++; X } X } X MatCopy(&newobj->transf, &ident_matrix); X newobj->ref_count = 0; X newobj->next = NULL; X } X X return newobj; } X X /* X * Copy a list of objects. If SURF_COPY is true X * the surfaces in the objects will be copied too. X */ static Object * object_list_copy(object, surf_copy) X Object *object; X bool surf_copy; { X Object *newobj; X X if (object == NULL) { X return NULL; X } X X if ((newobj = (Object *)smalloc(sizeof(Object))) != NULL) { X memcpy(newobj, object, sizeof(Object)); X newobj->ref_count = 0; X } else { X return NULL; X } X X if (surf_copy) { X newobj->surfaces = surface_copy(object->surfaces); X } else if (newobj->surfaces != NULL){ X newobj->surfaces->ref_count++; X } X X newobj->sub_obj = object_list_copy(object->sub_obj, surf_copy); X if (newobj->sub_obj != NULL) { X newobj->sub_obj->ref_count++; X } X newobj->next = object_list_copy(object->next, surf_copy); X if (newobj->next != NULL) { X newobj->next->ref_count++; X } X X return newobj; } X X X /* X * Copy the top node of an object hierarchy. The X * subobjects and surface references will be the X * same as in the original. X */ Object * object_instance(obj) X Object *obj; { X return object_copy(obj, TRUE); } X X X /* X * Copy an object hierarchy. The objects in X * the new hierarchy will reference the same X * surfaces as the object in X * the old hierarchy, but all object nodes X * will be duplicated. X */ Object * object_dup(object) X Object *object; { X Object *newobj; X X if ((newobj = object_copy(object, FALSE)) == NULL) { X return NULL; X } X X newobj->sub_obj = object_list_copy(object->sub_obj, FALSE); X newobj->next = NULL; X X return newobj; } X X X /* X * Copy an object hierarchy. All object nodes X * and surfaces in the old hierarchy X * will be duplicated. X */ Object * object_deep_dup(object) X Object *object; { X Object *newobj; X X if ((newobj = object_copy(object, FALSE)) == NULL) { X return NULL; X } X X newobj->surfaces = surface_copy(object->surfaces); X newobj->sub_obj = object_list_copy(object->sub_obj, TRUE); X newobj->next = NULL; X X return newobj; } X X X /* X * Recursively delete an object hierarchy. Reference X * counts are decremented and if the result is zero X * the recursion continues and the memory used is freed. X */ static void r_object_delete(object) X Object * object; { X if (object != NULL) { X if (--object->ref_count == 0) { X surface_delete(object->surfaces); X r_object_delete(object->sub_obj); X r_object_delete(object->next); X free(object); X } X } } X X X /* X * Delete an object hierarchy. This is only possible X * to do on a top level object. X */ void object_delete(object) X Object * object; { X if (object != NULL) { X if (object->ref_count == 0) { /* Is it a top level object? */ X surface_delete(object->surfaces); X r_object_delete(object->sub_obj); X r_object_delete(object->next); X free(object); X } X } } X X X /* X * Add SUBOBJ as a subobject in OBJECT. SUBOBJ is appended X * on the *end* of OBJECT's subobject list, X * so that if SUBOBJ, for some obscure reason, X * were the head of an object list, we don't loose X * the rest of that list. X * Remove SUBOBJ from the rendering database since it is no X * longer a root object in an hierarchy. X */ void object_add_subobj(object, subobj) X Object *object, *subobj; { X Object *oref; X X if (object == NULL || subobj == NULL) { X return; X } X X if (object->sub_obj == NULL) { X object->sub_obj = subobj; X } else { X oref = object->sub_obj; X while (oref->next != NULL) { X oref = oref->next; X } X oref->next = subobj; X } X X subobj->ref_count++; X object_uninstall(subobj); } X X X /* X * Add SURFACE to the list of surfaces belonging X * to OBJECT. SURFACE is appended on the *end* of the X * list for the same reasons as in object_add_subobj. X */ void object_add_surface(object, surface) X Object *object; X Surface *surface; { X Surface *sref; X X if (object == NULL || surface == NULL) { X return; X } X X if (object->surfaces == NULL) { X object->surfaces = surface; X } else { X sref = object->surfaces; X while (sref->next != NULL) { X sref = sref->next; X } X sref->next = surface; X } X X surface->ref_count++; } X X X X /*============= Functions that handles object transformations==============*/ X /* X * Set the transformation matrix of OBJ to MATRIX. X */ void object_set_transf(obj, matrix) X Object *obj; X Transf_mat *matrix; { X MatCopy(&obj->transf, matrix); } X X /* X * Set the transformation matrix of OBJ to the identity matrix. X */ void object_clear_transf(obj) X Object *obj; { X MatCopy(&obj->transf, &ident_matrix); } X X /* X * Post multiply MATRIX into the transformation matrix of OBJ. X */ void object_transform(obj, matrix) X Object *obj; X Transf_mat *matrix; { X mat_mul(&obj->transf, &obj->transf, matrix); } X X /* X * Rotate the object OBJ ANG radians about the x-axis. X */ void object_rot_x(obj, ang) X Object *obj; X double ang; { X mat_rotate_x(&obj->transf, ang); } X X /* X * Rotate the object OBJ ANG radians about the y-axis. X */ void object_rot_y(obj, ang) X Object *obj; X double ang; { X mat_rotate_y(&obj->transf, ang); } X X /* X * Rotate the object OBJ ANG radians about the z-axis. X */ void object_rot_z(obj, ang) X Object *obj; X double ang; { X mat_rotate_z(&obj->transf, ang); } X X /* X * Rotate the object OBJ ANG radians about the line defined X * by POINT and VEC. X */ void object_rot(obj, point, vec, ang) X Object *obj; X Vector *point; X Vector *vec; X double ang; { X mat_rotate(&obj->transf, point, vec, ang); } X X /* X * Scale the object OBJ with respect to the origin. X */ void object_scale(obj, xscale, yscale, zscale) X Object *obj; X double xscale, yscale, zscale; { X mat_scale(&obj->transf, xscale, yscale, zscale); } X X /* X * Translate the object OBJ. X */ void object_move(obj, dx, dy, dz) X Object *obj; X double dx, dy, dz; { X mat_translate(&obj->transf, dx, dy, dz); } X X X X /*============= Functions that handles rendering of the scene==============*/ X X /* X * Calculate the normal vector for all polygons in the polygon list PSTART. X * X * Check if the polygon is backfacing with respect to the current X * viewpoint. X * X * The normalized normal is added to a normal kept at each vertex X * in the polygon. This will produce, at each vertex, an average of the X * normals of the adjectent plygons. X */ static void calc_normals(pstart, eyepoint) X Polygon *pstart; /* Head of polygon list */ X Vector eyepoint; /* Viewpoint transformed to local coordinate system */ { X Vector normal; X Vertex_ref *vref1, *vref2; X Polygon *polyref; X double plane_const; X X for (polyref = pstart; polyref != NULL; polyref = polyref->next) { X vref1 = polyref->vertices; X vref2 = vref1->next; X X normal.x = normal.y = normal.z = 0.0; X do { X normal.x += ((vref1->vertex->y - vref2->vertex->y) X * (vref1->vertex->z + vref2->vertex->z)); X normal.y += ((vref1->vertex->z - vref2->vertex->z) X * (vref1->vertex->x + vref2->vertex->x)); X normal.z += ((vref1->vertex->x - vref2->vertex->x) X * (vref1->vertex->y + vref2->vertex->y)); X vref1 = vref1->next; X vref2 = ((vref2->next == NULL)?polyref->vertices:vref2->next); X } while (vref1 != NULL); X vecnorm(&normal); X X plane_const = -(normal.x * vref2->vertex->x X + normal.y * vref2->vertex->y X + normal.z * vref2->vertex->z); X if (VecDot(eyepoint, normal) + plane_const <= 0.0) { X polyref->backface = TRUE; X } else { X polyref->backface = FALSE; X } X X for (vref1 = polyref->vertices; vref1 != NULL; vref1 = vref1->next) { X vref1->vertex->a += normal.x; X vref1->vertex->b += normal.y; X vref1->vertex->c += normal.z; X } X } } X X X /* X * Walk around a polygon, create the surrounding X * edges and sort them into the y-bucket. X * Clip polygons in y at the same time. X */ static void create_edges(view_vert, yres, polygon, surface) X View_coord *view_vert; X int yres; X int polygon; X Surface *surface; { X Edge *edge; X View_coord *view_ref, *last; X int nderiv, y1, y2, ymax; X int clip1, clip2; X double deltay, ratio; X double x1, x2, xstep; X double z1, z2, zstep; X double nx1, nx2, nxstep; X double ny1, ny2, nystep; X double nz1, nz2, nzstep; X double u1, u2, ustep; X double v1, v2, vstep; X double w1, w2, wstep; X X view_ref = last = view_vert; X ymax = yres - 1; X do { X view_ref = view_ref->next; X x1 = view_ref->x; X x2 = view_ref->next->x; X y1 = view_ref->y; X y2 = view_ref->next->y; X z1 = view_ref->z; X z2 = view_ref->next->z; X nx1 = view_ref->nx; X nx2 = view_ref->next->nx; X ny1 = view_ref->ny; X ny2 = view_ref->next->ny; X nz1 = view_ref->nz; X nz2 = view_ref->next->nz; X u1 = view_ref->u; X u2 = view_ref->next->u; X v1 = view_ref->v; X v2 = view_ref->next->v; X w1 = view_ref->w; X w2 = view_ref->next->w; X clip1 = (y1 < 0) + ((y1 > ymax) << 1); X clip2 = (y2 < 0) + ((y2 > ymax) << 1); X if (!(clip1 & clip2)) { X if (clip1 != 0) { X if (clip1 == 1) X ratio = (0.0 - (double)y1) / (double)(y2 - y1); X else X ratio = (double)(ymax - y1) / (double)(y2 - y1); X x1 = x1 + ratio * (x2 - x1); X y1 = y1 + ratio * (y2 - y1); X z1 = z1 + ratio * (z2 - z1); X nx1 = nx1 + ratio * (nx2 - nx1); X ny1 = ny1 + ratio * (ny2 - ny1); X nz1 = nz1 + ratio * (nz2 - nz1); X u1 = u1 + ratio * (u2 - u1); X v1 = v1 + ratio * (v2 - v1); X w1 = w1 + ratio * (w2 - w1); X } X if (clip2 != 0) { X if (clip2 == 1) X ratio = (0.0 - (double)y2) / (double)(y1 - y2); X else X ratio = (double)(ymax - y2) / (double)(y1 - y2); X x2 = x2 + ratio * (x1 - x2); X y2 = y2 + ratio * (y1 - y2); X z2 = z2 + ratio * (z1 - z2); X nx2 = nx2 + ratio * (nx1 - nx2); X ny2 = ny2 + ratio * (ny1 - ny2); X nz2 = nz2 + ratio * (nz1 - nz2); X u2 = u2 + ratio * (u1 - u2); X v2 = v2 + ratio * (v1 - v2); X w2 = w2 + ratio * (w1 - w2); X } X deltay = (double)(y2 - y1); X if (deltay > 0.0) X nderiv = 1; X else if (deltay < 0.0) X nderiv = -1; X else X nderiv = 0; X if (nderiv) { X deltay = fabs(deltay); X xstep = (x2 - x1) / deltay; X zstep = (z2 - z1) / deltay; X nxstep = (nx2 - nx1) / deltay; X nystep = (ny2 - ny1) / deltay; X nzstep = (nz2 - nz1) / deltay; X ustep = (u2 - u1) / deltay; X vstep = (v2 - v1) / deltay; X wstep = (w2 - w1) / deltay; X edge = (Edge *)smalloc(sizeof(Edge)); X if (nderiv > 0) { X edge->y = y2; X edge->y_stop = y1; X edge->x = x2; X edge->z = z2; X edge->nx = nx2; X edge->ny = ny2; X edge->nz = nz2; X edge->u = u2; X edge->v = v2; X edge->w = w2; X edge->xstep = -xstep; X edge->zstep = -zstep; X edge->nxstep = -nxstep; X edge->nystep = -nystep; X edge->nzstep = -nzstep; X edge->ustep = -ustep; X edge->vstep = -vstep; X edge->wstep = -wstep; X } else { X edge->y = y1; X edge->y_stop = y2; X edge->x = x1; X edge->z = z1; X edge->nx = nx1; X edge->ny = ny1; X edge->nz = nz1; X edge->u = u1; X edge->v = v1; X edge->w = w1; X edge->xstep = xstep; X edge->zstep = zstep; X edge->nxstep = nxstep; X edge->nystep = nystep; X edge->nzstep = nzstep; X edge->ustep = ustep; X edge->vstep = vstep; X edge->wstep = wstep; X } X } else { X zstep = (z2 - z1) / fabs(x2 - x1); X edge = (Edge *)smalloc(sizeof(Edge)); X edge->y = y2; X edge->y_stop = y1; X if (x1 < x2) { X edge->x = x1; X edge->z = z1; X edge->xstep = x2; X edge->zstep = zstep; X } else { X edge->x = x2; X edge->z = z2; X edge->xstep = x1; X edge->zstep = -zstep; X } X } X edge->polygon = polygon; X edge->surface = surface; X edge->next = NULL; X if (y_bucket[edge->y].last == NULL) { X y_bucket[edge->y].first = edge; X y_bucket[edge->y].last = edge; X } else { X y_bucket[edge->y].last->next = edge; X y_bucket[edge->y].last = edge; X } X } X } while (view_ref != last); } X X /* X * Transform vertices into view coordinates. The transform is X * defined in MATRIX. Store the transformed vertices in a X * temporary list, create edges in the y_bucket. X */ static void transf_vertices(vertex_list, surface, matrix, tr_mat, xsiz, ysiz) X Vertex_ref *vertex_list; X Surface *surface; X double matrix[4][4]; X Transf_mat *tr_mat; X double xsiz, ysiz; { X static int polygon = 0; /* incremented for each call to provide */ X /* unique polygon id numbers */ X Vertex_ref *vref; X View_coord *view_ref, *nhead, *ntail; X double minsize; X double w, tmp; X bool first, last; X X first = TRUE; X last = FALSE; X vref = vertex_list; X nhead = NULL; X X minsize = ((xsiz > ysiz) ? ysiz : xsiz); X X while ((vref != NULL) && !last) { X X view_ref = (View_coord *)alloca(sizeof(View_coord)); X last = (vref->next == NULL); X X view_ref->nx = (vref->vertex->a * tr_mat->mat[0][0] X + vref->vertex->b * tr_mat->mat[1][0] X + vref->vertex->c * tr_mat->mat[2][0]); X view_ref->ny = (vref->vertex->a * tr_mat->mat[0][1] X + vref->vertex->b * tr_mat->mat[1][1] X + vref->vertex->c * tr_mat->mat[2][1]); X view_ref->nz = (vref->vertex->a * tr_mat->mat[0][2] X + vref->vertex->b * tr_mat->mat[1][2] X + vref->vertex->c * tr_mat->mat[2][2]); X X w = vref->vertex->x * matrix[0][3] + vref->vertex->y * matrix[1][3] + X vref->vertex->z * matrix[2][3] + matrix[3][3]; X view_ref->x = ((vref->vertex->x * matrix[0][0] X + vref->vertex->y * matrix[1][0] X + vref->vertex->z * matrix[2][0] X + matrix[3][0]) * minsize / w + xsiz); X tmp = ((vref->vertex->x * matrix[0][1] X + vref->vertex->y * matrix[1][1] X + vref->vertex->z * matrix[2][1] X + matrix[3][1]) * minsize / w + ysiz) ; X X view_ref->y = (int)(tmp + 0.5); X view_ref->z = (vref->vertex->x * matrix[0][2] + vref->vertex->y * X matrix[1][2] + vref->vertex->z * matrix[2][2] + X matrix[3][2]) / w; X X view_ref->u = vref->vertex->u; X view_ref->v = vref->vertex->v; X view_ref->w = vref->vertex->w; X view_ref->next = nhead; X nhead = view_ref; X X if (first) { X ntail = view_ref; X first = FALSE; X } X if (!last) X vref = vref->next; X } X X ntail->next = nhead; X create_edges(nhead, (int)ysiz << 1, polygon++, surface); } X X /* X * Initialize the scanline z-buffer and the actual picture X * scanline buffer. X */ static void init_buffers(res, z_buffer, scanline) X int res; X double *z_buffer; X unsigned char *scanline; { X int i; X #ifdef NOMEMCPY X bzero(scanline, res * 3); #else X memset(scanline, 0, res * 3); #endif X for (i = 0; i < res; i++) X z_buffer[i] = 2.0; } X X /* X * Read edge pairs from the edge list EDGE_LIST. Walk along the scanline X * and interpolate z value, texture coordinates and normal vector as X * we go. Call the shader and write into scanline buffer according to X * result on z-buffer test. X */ static void render_line(res, z_buffer, scanline, edge_list) X int res; X double *z_buffer; X unsigned char *scanline; X Edge *edge_list; { X double z, zstep; X double nx, nxstep; X double ny, nystep; X double nz, nzstep; X double u, ustep; X double v, vstep; X double w, wstep; X double ratio; X Color color; X int i, j, x, xstop; X Edge *edgep, *next; X X edgep = edge_list; X next = NULL; X while (edgep != NULL) { X if (edgep->y != edgep->y_stop) { X next = edgep->next; X while (next->y == next->y_stop) X next = next->next; X x = (int)(edgep->x + 0.5); X xstop = (int)(next->x + 0.5); X z = edgep->z; X nx = edgep->nx; X ny = edgep->ny; X nz = edgep->nz; X u = edgep->u; X v = edgep->v; X w = edgep->w; X if (x < xstop) { X ratio = (double)(xstop - x); X zstep = (next->z - z) / ratio; X nxstep = (next->nx - nx) / ratio; X nystep = (next->ny - ny) / ratio; X nzstep = (next->nz - nz) / ratio; X ustep = (next->u - u) / ratio; X vstep = (next->v - v) / ratio; X wstep = (next->w - w) / ratio; X } else { X zstep = 0.0; X nxstep = nystep = nzstep = 0.0; X ustep = vstep = wstep = 0.0; X } X for (i = x, j = i * 3; i <= xstop; i++) { X if ((i >= 0) && (i < res) && (z >= 0.0) && (z <= 1.0) X && (z < z_buffer[i])) { X (*edgep->surface->shader) X (nx, ny, nz, u, v, w, X camera.vec, lightsrc_stack, X edgep->surface->surface, &color); X scanline[j++] = (unsigned char)(color.red * 255.0 + 0.5); X scanline[j++] = (unsigned char)(color.grn * 255.0 + 0.5); X scanline[j++] = (unsigned char)(color.blu * 255.0 + 0.5); X z_buffer[i] = z; X } else if (i >= res) { X break; X } else { X j += 3; X } X z += zstep; X nx += nxstep; X ny += nystep; X nz += nzstep; X u += ustep; X v += vstep; X w += wstep; X } X } X edgep = edgep->next; X if ((edgep == next) && (next != NULL)) X edgep = edgep->next; X } } X X X /* X * Insert an edge into an edge list. Edges belonging to the same X * polygon must be inserted sorted in x, so that edge pairs are X * created. X */ static Edge * insert_edge(edge_list, edge, poly_found) X Edge *edge_list, *edge; X bool poly_found; { X if (edge_list == NULL) { X edge_list = edge; X edge->next = NULL; X } else if (edge_list->polygon == edge->polygon) { X if (edge_list->x > edge->x) { X edge->next = edge_list; X edge_list = edge; X } else if ((((int)(edge_list->x + 0.5)) == ((int)(edge->x + 0.5))) X && (edge_list->xstep > edge->xstep)) { X edge->next = edge_list; X edge_list = edge; X } else { X edge_list->next = insert_edge(edge_list->next, edge, TRUE); X } X } else if (poly_found) { X edge->next = edge_list; X edge_list = edge; X } else { X edge_list->next = insert_edge(edge_list->next, edge, FALSE); X } X X return edge_list; } X X X /* X * Merge two edge lists. X */ static Edge * merge_edge_lists(list1, list2) X Edge *list1, *list2; { X Edge *eref1, *eref2, *next; X X if (list2 == NULL) X return NULL; X eref1 = list1; X eref2 = list2; X do { X next = eref2->next; X eref1 = insert_edge(eref1, eref2, FALSE); X eref2 = next; X } while (eref2 != NULL); X return eref1; } X X X /* X * Allocate the needed buffers. Create a list of active edges and X * move down the y-bucket, inserting and deleting edges from this X * active list as we go. Call render_line for each scanline and X * do an average filtering before writing the scanline to the result X * file descriptor. X */ static void scan_and_render(xres, yres, image_file) X int xres, yres; X FILE *image_file; { X Edge *active_list, *edgep, *edgep2; X double *z_buffer; X unsigned char *scanline1, *scanline2, *stmp; X int i, y, next_edge; X X z_buffer = (double *)calloc(xres, sizeof(double)); X scanline1 = (unsigned char *)calloc(xres * 3, sizeof(unsigned char)); X scanline2 = (unsigned char *)calloc(xres * 3, sizeof(unsigned char)); X X fprintf(image_file, "P6\n"); X fprintf(image_file, "#Image rendered with SIPP %s\n", VERSION); X fprintf(image_file, "%d\n%d\n255\n", xres >> 1, yres >> 1); X X y = yres - 1; X active_list = NULL; X stmp = scanline1; X X while (y >= 0) { X active_list = merge_edge_lists(active_list, y_bucket[y].first); X next_edge = y - 1; X while (next_edge >=0 && y_bucket[next_edge].first == NULL) X next_edge--; X while (y > next_edge) { X init_buffers(xres, z_buffer, stmp); X render_line(xres, z_buffer, stmp, active_list); X if (stmp == scanline1) X stmp = scanline2; X else { X for (i = 0; i < (xres * 3); i += 6) { X scanline1[i >> 1] = (scanline1[i] + X scanline1[i + 3] + X scanline2[i] + X scanline2[i + 3]) >> 2; X scanline1[(i >> 1) + 1] = (scanline1[i + 1] + X scanline1[i + 4] + X scanline2[i + 1] + X scanline2[i + 4]) >> 2; X scanline1[(i >> 1) + 2] = (scanline1[i + 2] + X scanline1[i + 5] + X scanline2[i + 2] + X scanline2[i + 5]) >> 2; X } X fwrite(scanline1, (xres >> 1) * 3, 1, image_file); X fflush(image_file); X stmp = scanline1; X } X if (active_list != NULL) { X edgep2 = active_list; X edgep = active_list->next; X while (edgep != NULL) X if (edgep->y <= (edgep->y_stop + 1)) { X edgep2->next = edgep->next; X free(edgep); X edgep = edgep2->next; X } else { X edgep2 = edgep; X edgep = edgep->next; X } X if (active_list->y <= (active_list->y_stop + 1)) { X edgep = active_list; X active_list = active_list->next; X free(edgep); X } X edgep = active_list; X while (edgep != NULL) { X edgep->y--; X edgep->x += edgep->xstep; X edgep->z += edgep->zstep; X edgep->nx += edgep->nxstep; X edgep->ny += edgep->nystep; X edgep->nz += edgep->nzstep; X edgep->u += edgep->ustep; X edgep->v += edgep->vstep; X edgep->w += edgep->wstep; X edgep = edgep->next; X } X } X y--; X } X } X free(z_buffer); X free(scanline1); X free(scanline2); } X X X /* X * Reset the averaged normals in the vertex tree P. X */ static void reset_normals(vref) X Vertex *vref; { X if (vref != NULL) { X vref->a = 0; X vref->b = 0; X vref->c = 0; X reset_normals(vref->big); X reset_normals(vref->sml); X } } X X X /* X * Build a transformation matrix for transformation X * into view coordinates. Perpective transformation X * is also included X */ static void get_view_transf(mat) X double mat[4][4]; { X Vector tmp; X double transl[3]; X double vy, vz; X double hither, yon; X double alfa, beta; X int i, j; X X /* X * First we need a translation so the origo X * of the view coordinat system is placed X * in the viewpoint. X */ X transl[0] = -camera.x0; X transl[1] = -camera.y0; X transl[2] = -camera.z0; X X /* X * Then we need a rotation that makes the X * up-vector point up, and alignes the sightline X * with the z-axis. X * This code might seem magic but the algebra behind X * it can be found in Jim Blinn's Corner in IEEE CG&A July 1988 X */ X VecCopy(tmp, camera.vec); X VecNegate(tmp); X vecnorm(&tmp); X vecnorm(&camera.up); X vz = VecDot(tmp, camera.up); X if ((vz * vz) > 1.0) { /* this should not happen, but... */ X vz = 1.0; X } else { X vy = sqrt(1.0 - vz * vz); X if (vy == 0.0) { /* oops, the world collapses... */ X vy = 1.0e10; X vz = 1.0; X } else { X vy = 1.0 / vy; X } X } X X mat[0][2] = tmp.x; X mat[1][2] = tmp.y; X mat[2][2] = tmp.z; X X VecScalMul(tmp, vz, tmp); X VecSub(tmp, camera.up, tmp); X mat[0][1] = tmp.x * vy; X mat[1][1] = tmp.y * vy; X mat[2][1] = tmp.z * vy; X X mat[0][0] = mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]; X mat[1][0] = mat[2][1] * mat[0][2] - mat[2][2] * mat[0][1]; X mat[2][0] = mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]; X X /* X * Install the translation into the matrix. X * Note that it is PRE-multiplied into the matrix. X */ X for (i = 0; i < 3; i++) { X mat[3][i] = 0.0; X for (j = 0; j < 3; j++) { X mat[3][i] += transl[j] * mat[j][i]; X } X } X X /* X * Include the perspective transformation X * using heuristic values for hither and yon. X */ X hither = VecLen(camera.vec) / ZCLIPF; X yon = VecLen(camera.vec) * ZCLIPF; X alfa = camera.focal_ratio / (1.0 - hither / yon); X beta = -hither * alfa; X X mat[0][3] = mat[0][2] * camera.focal_ratio; X mat[0][2] *= alfa; X mat[1][3] = mat[1][2] * camera.focal_ratio; X mat[1][2] *= alfa; X mat[2][3] = mat[2][2] * camera.focal_ratio; X mat[2][2] *= alfa; X mat[3][3] = mat[3][2] * camera.focal_ratio; X mat[3][2] = mat[3][2] * alfa + beta; X X /* X * Since the screen coordinates are defined in a left handed X * coordinate system, we must switch the sign of the first X * column in the matrix to get appropriate signs of x-values. X */ X mat[0][0] = -mat[0][0]; X mat[1][0] = -mat[1][0]; X mat[2][0] = -mat[2][0]; X mat[3][0] = -mat[3][0]; } X X /* X * Free the memory used by an edge list. X */ static void delete_edges(edge_list) X Edge *edge_list; { X Edge *edgeref1, *edgeref2; X X edgeref1 = edge_list; X while (edgeref1 != NULL) { X edgeref2 = edgeref1->next; X free(edgeref1); X edgeref1 = edgeref2; X } } X X X /* X * Push the current transformation matrix on the matrix stack. X */ static void matrix_push() { X struct tm_stack_t *new_tm; X X new_tm = (struct tm_stack_t *)smalloc(sizeof(struct tm_stack_t)); X MatCopy(&new_tm->mat, &curr_mat); X new_tm->next = tm_stack; X tm_stack = new_tm; } X X /* X * Pop the top of the matrix stack and make X * it the new current transformation matrix. X */ static void matrix_pop() { X struct tm_stack_t *tmp; X X MatCopy(&curr_mat, &tm_stack->mat); X tmp = tm_stack; X tm_stack = tm_stack->next; X free(tmp); } X X X /* X * Traverse an object hierarchy, transform each object X * according to its transformation matrix. X * Transform all polygons in the object to view coordinates. X * Build the edge lists in y_bucket. X */ static void traverse_object_tree(object, glob_view_mat, xres, yres) X Object *object; X double glob_view_mat[4][4]; X int xres, yres; { X Object *objref; X Surface *surfref; X Polygon *polyref; X Vector eyepoint, tmp; X double loc_view_mat[4][4]; X X X if (object == NULL) { X return; X } X X for (objref = object; objref != NULL; objref = objref->next) { X X matrix_push(); X mat_mul(&curr_mat, &objref->transf, &curr_mat); X mat_mul34(loc_view_mat, &curr_mat, glob_view_mat); X X tmp.x = camera.x0; X tmp.y = camera.y0; X tmp.z = camera.z0; X X /* X * Do an inverse transformation of the viewpoint to use X * when doing backface culling (in calc_normals()). X */ X tmp.x -= curr_mat.mat[3][0]; X tmp.y -= curr_mat.mat[3][1]; X tmp.z -= curr_mat.mat[3][2]; X eyepoint.x = (tmp.x * curr_mat.mat[0][0] + tmp.y * curr_mat.mat[0][1] X + tmp.z * curr_mat.mat[0][2]); X eyepoint.y = (tmp.x * curr_mat.mat[1][0] + tmp.y * curr_mat.mat[1][1] X + tmp.z * curr_mat.mat[1][2]); X eyepoint.z = (tmp.x * curr_mat.mat[2][0] + tmp.y * curr_mat.mat[2][1] X + tmp.z * curr_mat.mat[2][2]); X X for (surfref = objref->surfaces; surfref != NULL; X surfref = surfref->next) { X X calc_normals(surfref->polygons, eyepoint); X X for (polyref = surfref->polygons; polyref != NULL; X polyref = polyref->next) { X X if (!polyref->backface) { X transf_vertices(polyref->vertices, surfref, loc_view_mat, X &curr_mat, (double)xres, (double)yres); X } X X } X reset_normals(surfref->vertices); X X } X traverse_object_tree(objref->sub_obj, glob_view_mat, xres, yres); X matrix_pop(); X } } X X X /* X * Recursively traverse the rendering database (preorder). X * Call traverse_object_tree for each object. X */ static void traverse_object_db(obj_root, view_mat, xres, yres) X Inst_object *obj_root; X double view_mat[4][4]; X int xres, yres; { X if (obj_root != NULL) { X traverse_object_tree(obj_root->object, view_mat, xres, yres); X traverse_object_db(obj_root->sml, view_mat, xres, yres); X traverse_object_db(obj_root->big, view_mat, xres, yres); X } } X X X X /* X * "Main" function in rendering. Allocate y-bucket, transform vertices X * into viewing coordinates, make edges and sort them into the y-bucket. X * Call scan_and_render to do the real work. X */ void render_image(xres, yres, image_file) X int xres, yres; X FILE *image_file; { X double matrix[4][4]; X int i; X X y_bucket = (Bucket *)calloc(yres << 1, sizeof(Bucket)); X X get_view_transf(matrix); X MatCopy(&curr_mat, &ident_matrix); X X traverse_object_db(object_db, matrix, xres, yres); X X vecnorm(&camera.vec); X scan_and_render(xres << 1, yres << 1, image_file); X view_vec_eval(); X X for (i = 0; i < (yres << 1); i++) X delete_edges(y_bucket[i].first); X free(y_bucket); } X X X /*============= Functions that handles global initializations==============*/ X /* X * Necessary initializations. X */ void sipp_init() { X vertex_tree = NULL; X vertex_stack = NULL; X poly_stack = NULL; X object_db = NULL; X lightsrc_stack = NULL; X first_vertex = 0; X viewpoint(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.25); } SHAR_EOF chmod 0644 libsipp/sipp.c || echo 'restore of libsipp/sipp.c failed' Wc_c="`wc -c < 'libsipp/sipp.c'`" test 52154 -eq "$Wc_c" || echo 'libsipp/sipp.c: original size 52154, current size' "$Wc_c" fi true || echo 'restore of libsipp/sipp.h failed' echo End of part 3, continue with part 4 exit 0 -- Inge Wallin | Thus spake the master programmer: | | "After three days without programming, | ingwa@isy.liu.se | life becomes meaningless." | | Geoffrey James: The Tao of Programming. | exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.