#include "solid.h"

void define_solid(int this_obj_type)
/*  Constructs solid descriptor */
{
    struct obj_defn *this_defn_ptr;
    struct facet *facet_ptr;
    struct vertex *vertex_ptr;
    int sweep_index; /* varies from 0 to "sweeps" - 1;
        0 and "sweeps" - 1 are polar sweeps */
    int facet_index; /* index of facets for each sweep;
        varies from 0 to facet_max */
    int sweep_count; /* number of sweeps to make */
    int facet_max; /* number of facets per sweep */
    int vertex_ref_index; /* index of current vertex */
    int vertex_s; /* index of 1st vertex for sweep */
    float vert_angle; /* angle first side of facet
        forms with positive x axis in x-y plane */
    float vert_angle_init; /* initial vert_angle */
    float vert_delta; /* angle formed by sides of
        current facet in x-y plane */
    float horiz_angle; /* angle 1st side of facet forms
        with positive x axis in x-z plane */
    float vert_scale; /* scaling factor in xy plane */
    float horiz_scale; /* scaling factor in xz plane */
    int num_vertices, num_facets, num_vertex_refs;
    int region; /* -1 = north polar, 1 = south polar,
        0 elsewhere */
    float sqrt2;

    sqrt2 = sqrt(2.0);
    switch(this_obj_type) {
        case CUBE_OBJ: {
            sweep_count = 3;
            facet_max = 4;
            vert_angle_init = PI / 4.0;
            vert_delta = PI / 2.0;
            vert_scale = 1.0 / sqrt2;
            horiz_scale = 2.0 / sqrt2;
            num_vertices = 8;
            num_facets = 6;
            num_vertex_refs = 24;
            break;
        }
        case SPHERE_OBJ: {
            sweep_count = sweeps;
            facet_max = facets;
            vert_angle_init = PI / (float)sweeps;
            vert_delta = PI / (float)sweeps;
            vert_scale = 0.5;
            horiz_scale = 1.0;
            num_vertices = (sweep_count - 1) *
                facet_max + 2;
            num_facets = sweep_count * facet_max;
            num_vertex_refs = (4 * sweep_count - 2) *
                facet_max;
            break;
        }
        case CYLIND_OBJ: {
            sweep_count = 3;
            facet_max = facets;
            vert_angle_init = PI / 4.0;
            vert_delta = PI / 2.0;
            vert_scale = 1.0 / sqrt2;
            horiz_scale = 2.0 / sqrt2;
            num_vertices = 2 * facet_max;
            num_facets = 2 + facet_max;
            num_vertex_refs = 6 * facet_max;
            break;
        }
        case CONE_OBJ: {
            sweep_count = 2;
            facet_max = facets;
            vert_angle_init = 3.0 * PI / 4.0;
            vert_scale = 1.0 / sqrt2;
            horiz_scale = 2.0 / sqrt2;
            num_vertices = facet_max + 1;
            num_facets = facet_max + 1;
            num_vertex_refs = 4 * facet_max;
            break;
        }
        default:
            quit(ERR_OBJTYPE, __FILE__, __LINE__);
    }
    if ((vertex_ptr = (struct vertex *)malloc(
        num_vertices * sizeof(struct vertex))) == NULL)
        /* allocate storage for vertices */
        quit(ERR_MEMORY, __FILE__, __LINE__);

    if ((facet_ptr = (struct facet *)malloc(num_facets
        * sizeof(struct facet) + num_vertex_refs *
        sizeof(INDEX))) == NULL) /* allocate storage
        for facet descriptors */
        quit(ERR_MEMORY, __FILE__, __LINE__);

    /* construct definition descriptor */
    if ((this_defn_ptr = (struct obj_defn *)malloc(
        sizeof(struct obj_defn))) == NULL)
        quit(ERR_MEMORY, __FILE__, __LINE__);
    this_defn_ptr->vertex_count = num_vertices;
    this_defn_ptr->vertex_first = vertex_ptr;
    this_defn_ptr->facet_count = num_facets;
    this_defn_ptr->facet_first = facet_ptr;

    /* fill in vertex coords and facet descriptors */
    vertex_s = 0;
    vert_angle = vert_angle_init;
    /* main loop; each execution performs one sweep */
    for (sweep_index = 0; sweep_index < sweep_count;
        ++sweep_index) {
        region = (sweep_index == 0) ? -1 :
            ((sweep_index == sweep_count - 1) ? 1 : 0);
        /* construct vertices */
        if ((region != 0 && this_obj_type ==
            SPHERE_OBJ) || (region == -1 &&
            this_obj_type == CONE_OBJ)) { /* construct
            polar vertex */
            vertex_ptr->coord[0] = vertex_ptr->coord[2]
                = 0.0;
            vertex_ptr->coord[1] = 0.5 * ((sweep_index
                == 0) ? 1 : -1);
            ++vertex_ptr; /* point to next vertex */
            ++vertex_s;
        }
        if (region != 1) { /* construct normal vertices
            counterclockwise along bottom edge of sweep
            as viewed from top of object */
            horiz_angle = 2.0 * PI - PI /
                (float)facet_max;
            for (facet_index = 0; facet_index <
                facet_max; ++facet_index) {
                vertex_ptr->coord[0] = vert_scale *
                    sin(vert_angle) * horiz_scale *
                    cos(horiz_angle); /* x-coord */
                vertex_ptr->coord[1] = vert_scale *
                    cos(vert_angle); /* y-coord */
                vertex_ptr->coord[2] = vert_scale *
                    sin(vert_angle) * horiz_scale *
                    sin(horiz_angle); /* z-coord */
                ++vertex_ptr; /* point to next */
                horiz_angle -= 2.0 * PI / (float)
                    facet_max;
            }
        }
        /* construct facet descriptors for sweep */
        switch (region) {
            case -1:
            case 1: { /* polar region: construct
                triangular facets of sphere or cone or
                top facet of cube or cylinder */
                if (this_obj_type == SPHERE_OBJ ||
                    (this_obj_type == CONE_OBJ &&
                    region == -1)) { /* polar
                    triangular facets of sphere or
                    cone */
                    for (facet_index = 0; facet_index <
                        facet_max; ++facet_index,
                        facet_ptr = ADV_FACET_PTR(3)) {
                        facet_ptr->vertex_count = 3;
                        facet_ptr->vertex_index[0] =
                            (region == -1) ? 0 :
                            (num_vertices - 1);
                            /* polar vertex */
                        facet_ptr->vertex_index[1] =
                            (region == -1) ?
                            ((facet_index == 0) ?
                            facet_max : facet_index) :
                            (num_vertices - facet_max -
                            1 + facet_index);
                        facet_ptr->vertex_index[2] =
                            (region == -1) ? (1 +
                            facet_index) :
                            ((num_vertices - facet_max
                            - 2) + ((facet_index == 0)
                            ? facet_max :
                            facet_index));
                    }
                }
                if (this_obj_type == CUBE_OBJ ||
                    this_obj_type == CYLIND_OBJ ||
                    (region == 1 && this_obj_type ==
                    CONE_OBJ)) { /* top or bottom facet
                    of cube or cylinder or bottom facet
                    of cone */
                    facet_ptr->vertex_count =
                        facet_max;
                    for (facet_index = 0; facet_index
                        < facet_max; ++facet_index)
                        facet_ptr->vertex_index
                        [facet_index] = (region == -1)
                        ? facet_index : (num_vertices -
                        facet_index - 1);
                    facet_ptr = ADV_FACET_PTR
                        (facet_max);
                }
                break;
            }
            case 0: { /* construct rectangular facets
                between lines of latitude */
                for (facet_index = 0; facet_index <
                    facet_max; ++facet_index, facet_ptr
                    = ADV_FACET_PTR(4)) {
                    facet_ptr->vertex_count = 4;
                    facet_ptr->vertex_index[0] =
                        vertex_s - facet_max +
                        facet_index; facet_ptr->
                        vertex_index[1] = vertex_s -
                        facet_max - 1 + ((facet_index
                        == 0) ? facet_max :
                        facet_index);
                    facet_ptr->vertex_index[2] =
                        (facet_index == 0) ? (vertex_s
                        + facet_max - 1) : (vertex_s -
                        1 + facet_index);
                    facet_ptr->vertex_index[3] =
                        vertex_s + facet_index;
                }
            }
        }
        vert_angle += vert_delta;
        vertex_s += facet_max;
    }
    defn_ptr[this_obj_type] = this_defn_ptr; /* save
        pointer to definition */
    return;
}
