pipeobj.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,446 行 · 第 1/3 页

C
1,446
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


/*
 Description:
 ============
 Routines to manipulate rend_obj's.
*/


#include "icgr.h"
#include <string.h>

#ifndef PROD
#define INCLUDE_DEBUG_ROUTINES
#endif


static point invalid_pt = { 0., 0., 0., 0. };

typedef struct face_pts {       // used for calculating normal of a face
    face *      side;
    point *     pts;
} face_pts;


extern rend_obj * rend_obj_new_poly(
/**********************************/
    void
) {
    rend_obj *  new;
    polygon *   poly;

    _new( new, 1 );
    new->type = REND_OBJ_POLY;
    poly = &(new->obj.poly);        // shorthand
    poly->num_pts = 0;
    poly->index = NULL;
    _new( poly->pts, 1 );
    poly->pts->num_pts = 0;
    poly->pts->pts = NULL;

    return( new );
}

static index_elt * identity_index(
/********************************/
    int         num_elt,
    bool *      edges
) {
    index_elt * index;
    int         curr_elt;

    _new( index, num_elt );
    if( index != NULL ) {
        for( curr_elt = 0; curr_elt < num_elt; curr_elt++ ) {
            index[ curr_elt ].pt_num = curr_elt;
            if( edges != NULL ) {
                index[ curr_elt ].hilight_edge = edges[ curr_elt ];
            } else {
                index[ curr_elt ].hilight_edge = TRUE;
            }
            index[ curr_elt ].force_rgn_pt = FALSE;
        }
    }

    return( index );
}

extern rend_obj * rend_obj_create_poly(
/*************************************/
    int             num_pts,
    point *         pts,
    hls_colour      base,
    bool            black_edges,
    region_info *   rgn,
    bool *          edges,
    int             rgn_pt_iter
) {
    rend_obj *      new;
    polygon *       poly;

    new = rend_obj_new_poly();
    if( new != NULL ) {
        new->base_colour = base;
        new->black_edges = black_edges;
        new->rgn = *rgn;
        poly = &new->obj.poly;      // shorthand
        poly->pts->num_pts = num_pts;
        poly->pts->pts = pts;
        poly->rgn_pt_iter = rgn_pt_iter;
        poly->num_pts = num_pts;
        poly->index = identity_index( num_pts, edges );
    }

    return( new );
}

extern rend_obj * rend_obj_create_line(
/*************************************/
    point           start,
    point           end,
    hls_colour      colour,
    line_style      style,
    region_info *   rgn
) {
    rend_obj *  obj;

    _new( obj, 1 );
    if( obj != NULL ) {
        obj->type = REND_OBJ_LINE;
        obj->base_colour = colour;
        obj->black_edges = FALSE;
        obj->rgn = *rgn;
        obj->obj.line.start = start;
        obj->obj.line.end = end;
        obj->obj.line.style = style;
    }

    return( obj );
}

static vertex_list * dup_vertex_list(
/***********************************/
    vertex_list *   old
) {
    vertex_list *   new;

    _pipenew( new, 1 );
    new->num_pts = old->num_pts;
    _pipenew( new->pts, new->num_pts );
    memcpy( new->pts, old->pts, new->num_pts * sizeof(point) );

    return( new );
}

static index_elt * dup_index(
/***************************/
    index_elt * old,
    int         num_entries
) {
    index_elt * new;

    _pipenew( new, num_entries );
    memcpy( new, old, num_entries * sizeof(*new) );

    return( new );
}

static void copy_poly(
/********************/
    polygon *   old,
    polygon *   new
) {
    new->normal = old->normal;
    new->num_pts = old->num_pts;
    new->index = dup_index( old->index, old->num_pts );
    new->pts = dup_vertex_list( old->pts );
}

static void point_min(
/********************/
    point       pt1,
    point       pt2,
    point *     min
) {
    min->p[0] = _min( pt1.p[0], pt2.p[0] );
    min->p[1] = _min( pt1.p[1], pt2.p[1] );
    min->p[2] = _min( pt1.p[2], pt2.p[2] );
    min->p[3] = _min( pt1.p[3], pt2.p[3] );
}

static void point_max(
/********************/
    point       pt1,
    point       pt2,
    point *     max
) {
    max->p[0] = _max( pt1.p[0], pt2.p[0] );
    max->p[1] = _max( pt1.p[1], pt2.p[1] );
    max->p[2] = _max( pt1.p[2], pt2.p[2] );
    max->p[3] = _max( pt1.p[3], pt2.p[3] );
}

static bool face_visible(
/***********************/
    face *          curr_face,
    vertex_list *   pts_list,
    visible_info *  vis
) {
    point *         min;
    point *         max;
    float           x1, y1;
    float           x2, y2;
    index_elt *     index;      // shorthand
    int             num_pts;    // shorthand
    point *         pts;        // shorthand
    int             curr_pt;

    index = curr_face->index;
    num_pts = curr_face->num_pts;
    pts = pts_list->pts;
    min = &vis->min;
    max = &vis->max;

    vis->mark = FALSE;

    *min = pts[ index[0].pt_num ];
    *max = pts[ index[0].pt_num ];

    for( curr_pt = 1; curr_pt < num_pts; curr_pt++ ) {
        point_min( *min, pts[ index[ curr_pt ].pt_num ], min );
        point_max( *max, pts[ index[ curr_pt ].pt_num ], max );
    }

    project_pt( *min, &x1, &y1 );
    project_pt( *max, &x2, &y2 );

    return( _wrectvisible( x1, y1, x2, y2 ) );
}

static void add_solid_to_list(
/****************************/
/* solids are not added to the list directly, instead they are broken up */
/* into their component faces and these are added as polygons */
/* NOTE: The memory that is occupied by the points list of the polygon becomes*/
/* shared by the component polygons after this call. This doesn't present a */
/* problem in the pipemem memory manager since it is allocate only. If a real */
/* memory manager is being used then either a reference count would have to */
/* be maintained or each polygon could get a copy of the points that they */
/* reference. */
    rend_obj *      obj,
    rend_list *     list
) {
    rend_obj *      new;
    polygon *       new_poly;
    vertex_list *   pts;
    face *          curr_face;
    face_list *     old_faces;
    visible_info    vis;

    old_faces = &(obj->obj.solid.faces);        // shorthand

    /* All the polygons will refer to the same vertex list. This is OK */
    /* if the solid is consitent */
    pts = dup_vertex_list( &(obj->obj.solid.pts) );

    for (curr_face = old_faces->faces;
            curr_face < old_faces->faces + old_faces->num_faces; curr_face++ ) {
        /* back face culling */
        if( curr_face->normal.v[2] > FUZZY_ZERO &&
                        face_visible( curr_face, pts, &vis ) ) {
            _pipenew( new, 1 );
            new->type = REND_OBJ_POLY;
            new->vis = vis;
            if( curr_face->black ) {
                new->base_colour = Black_hls;
            } else {
                new->base_colour = obj->base_colour;
            }
            new->black_edges = obj->black_edges;
            new->rgn = obj->rgn;
            new_poly = &(new->obj.poly);                // shorthand
            new_poly->normal = curr_face->normal;
            new_poly->num_pts = curr_face->num_pts;
            new_poly->index = dup_index( curr_face->index, curr_face->num_pts );
            new_poly->rgn_pt_iter = curr_face->rgn_pt_iter;
            new_poly->pts = pts;                // use the common vertex list

            rend_list_add( list, new );
        }
    }
}

extern rend_obj * rend_obj_dup(
/*****************************/
/* duplicates obj into pipe_mem memory */
    rend_obj *  obj
) {
    rend_obj *  new_obj;

    switch (obj->type) {
    case REND_OBJ_PT:
    case REND_OBJ_LINE:
        _pipenew( new_obj, 1 );
        *new_obj = *obj;    // point and line structures don't have pointers
        break;

    case REND_OBJ_POLY:
        _pipenew( new_obj, 1 );
        *new_obj = *obj;
        copy_poly( &(obj->obj.poly), &(new_obj->obj.poly) );
        break;

    case REND_OBJ_SOLID:
        new_obj = NULL;
        break;
    }

    return( new_obj );
}


extern void rend_obj_add_to_list(
/*******************************/
    rend_obj *      obj,
    rend_list *     list
) {
    rend_obj *      new_obj;

    if (obj->type == REND_OBJ_SOLID) {
        add_solid_to_list( obj, list );
    } else {
        new_obj = rend_obj_dup( obj );
        rend_obj_compute_vis_info( new_obj );
        rend_list_add( list, new_obj );
    }
}

extern void rend_obj_lfree(
/*************************/
/* free a rend_obj from local memory */
/* NOTE: do not call this function for rend_obj's that have been added */
/* to the rend_list via a rend_obj_add_to_list call; they are not in */
/* local memory. */
    rend_obj *      obj
) {
    polygon *       poly;
    vertex_list *   pts;
    face_list *     faces;
    face *          curr_face;

    switch (obj->type) {
    case REND_OBJ_POLY:
        poly = &(obj->obj.poly);        // shorthand
        pts = poly->pts;                // shorthand
        _free( pts->pts );
        _free( pts );
        _free( poly->index );
        break;
    case REND_OBJ_SOLID:
        pts = &(obj->obj.solid.pts);        // shorthand
        faces = &(obj->obj.solid.faces);    // shorthand

        _free( pts->pts );
        for (curr_face = faces->faces;
                curr_face < faces->faces + faces->num_faces; curr_face++ ) {
            _free( curr_face->index );
        }
        _free( faces->faces );
        break;
    }

    _free( obj );
}

static void compute_poly_vis_info(
/********************************/
    polygon *       poly,
    visible_info *  ext
) {
    int             curr_pt;

    ext->min = _polygon_get_pt( *poly, 0 );
    ext->max = _polygon_get_pt( *poly, 0 );

    for (curr_pt = 1; curr_pt < poly->num_pts; curr_pt++) {
        point_min( ext->min, _polygon_get_pt( *poly, curr_pt ), &ext->min );
        point_max( ext->max, _polygon_get_pt( *poly, curr_pt ), &ext->max );
    }
}

static void compute_solid_vis_info(
/*********************************/
/* assume that all points mentioned in the vertex_list are reference by at */
/* at least one face */
    polyhedron *    solid,
    visible_info *  ext
) {
    point *         pt;

    pt = solid->pts.pts;
    ext->min = *pt;
    ext->max = *pt;

    while (pt < solid->pts.pts + solid->pts.num_pts) {
        point_min( ext->min, *pt, &ext->min );
        point_max( ext->max, *pt, &ext->max );

        pt++;
    }
}

extern void rend_obj_compute_vis_info(
/************************************/
    rend_obj *      obj
) {
    switch (obj->type) {
    case REND_OBJ_PT:
        obj->vis.min = obj->obj.pt;
        obj->vis.max = obj->obj.pt;
        break;
    case REND_OBJ_LINE:
        point_min( obj->obj.line.start, obj->obj.line.end, &obj->vis.min );
        point_max( obj->obj.line.start, obj->obj.line.end, &obj->vis.max );
        break;
    case REND_OBJ_POLY:
        compute_poly_vis_info( &(obj->obj.poly), &(obj->vis) );
        break;
    case REND_OBJ_SOLID:
        compute_solid_vis_info( &(obj->obj.solid), &(obj->vis) );
        break;
    }
    obj->vis.mark = FALSE;
}

#if 0
/* macroed */
extern visible_info * rend_obj_get_vis(
/*************************************/
    rend_obj *      obj
) {
    return( &(obj->vis) );
}
#endif

extern vector rend_obj_get_norm(
/******************************/
    rend_obj *  obj
) {
    vector      norm;

    if (obj->type == REND_OBJ_POLY) {
        norm = obj->obj.poly.normal;
    } else {
        norm.v[0] = 0.;
        norm.v[1] = 0.;
        norm.v[2] = 0.;
        norm.v[3] = 0.;
    }

    return( norm );
}

extern int rend_obj_get_num_pts(
/******************************/
    rend_obj *  obj
) {
    switch (obj->type) {
    case REND_OBJ_SOLID:
        return( obj->obj.solid.pts.num_pts );
        break;
    case REND_OBJ_POLY:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?