pipe2.c

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

C
1,160
字号
/****************************************************************************
*
*                            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:
 ============
 This module contains the second half of the 3d pipeline. It has the following
 components:
        1. Visible surface determination (excluding back face culling).
        2. Illumination.
        3. Display (using 2d world functions).

 NOTE: The second half of the pipline does not process solids. These must be
    broken up into polygons before being passed on. The rend_obj_add_to_list
    fuction takes care of this (i.e. call it at the end of the first half of
    the pipeline).
 NOTE: All references to pages or sections in this file refer to "Computer
    Graphics" by Foley et. al. unless otherwise noted.


 Visible Surface Determination
 -----------------------------
 The algorithm used is the depth-sort algorithm. See "Computer Graphics" by
 Foley, et. al. section 15.5.1. The routine is passed rend_list and it figures
 out which the order to display the elements of the list in and does so.

 Lighting
 --------
 The lighting model is Lambertian reflection (diffuse) with ambiant light and
 attentuation. See "Computer Graphics" by Foley, et. al. section 16.1 pp. 722
 to 726.

*/

#include "icgr.h"


/* 1 if x is positive, -1 if x is negitive, 0 if x = 0 */
/* if x is within fuzz of 0 then it is considered to be 0 */
#define _fuzzy_sign( x, fuzz ) ( (fabs(x) < fuzz) ? 0 : (((x) < 0) ? -1 : 1) )

#define _is_zero_norm( n ) ( fabs((n).v[0]) < FUZZY_ZERO && fabs((n).v[1]) \
                            < FUZZY_ZERO && fabs((n).v[2]) < FUZZY_ZERO )

/* unit vector along coordinate axies */
static const vector Xvect = { 1.0, 0.0, 0.0, 0.0 };
static const vector Yvect = { 0.0, 1.0, 0.0, 0.0 };
static const vector Zvect = { 0.0, 0.0, 1.0, 0.0 };

/* current illumination parameters */
static pipe_illum Illum_param;

static bool All_poly_convex = TRUE;

/* 2D display */
extern void project_pt(
/*********************/
/*to project a point take its x and y coords and map them from [-1,1] to [0,1]*/
    point   pt,             // 3d point
    float   *x,             // 2d point
    float   *y
) {
    *x = (pt.p[0] + 1.) / 2.;
    *y = (pt.p[1] + 1.) / 2.;
}

static void draw_projected_poly(
/******************************/
    rend_obj *  obj,
    hls_colour  edge_colour
) {
    wcoord *    pts_2d;         // array of 2d points
    int         num_pts;
    int         curr_pt;
    point       pt_3d;
    COLORREF    edge_rgb;
    polygon *   poly;

    poly = rend_obj_get_poly( obj );

    /* Draw the illuminated surface of the polygon */
    num_pts = _polygon_get_num_pts( *poly );
    _new( pts_2d, num_pts );

    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        pt_3d = _polygon_get_pt( *poly, curr_pt );
        project_pt( pt_3d,  &(pts_2d[ curr_pt ].xcoord),
                            &(pts_2d[ curr_pt ].ycoord) );
    }

    _wpolygon( FILL_INTERIOR, num_pts, pts_2d );


    /* Draw the hilit edges of the polygon and add rgn markers */
    hls_to_rgb( &edge_rgb, edge_colour );
    _wsetrgbcolor( edge_rgb );
    _wsetlinestyle( LINE_SOLID );
    _wsetlinewidth( WIDTH_SINGLE );

    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        if( _polygon_edge_hilight( *poly, curr_pt )) {
            _wmoveto( pts_2d[ curr_pt ].xcoord, pts_2d[ curr_pt ].ycoord );
            _wlineto( pts_2d[ (curr_pt+1) % num_pts ].xcoord,
                        pts_2d[ (curr_pt+1) % num_pts ].ycoord, TRUE );
        }
        if( _polygon_rgn_pt( *poly, curr_pt ) ) {
            wrgn_set_add( &pts_2d[ curr_pt ] );
        }
    }

    _free( pts_2d );
}

static void draw_projected_obj(
/*****************************/
    rend_obj *  obj,
    hls_colour  base,               // colour on which illum is based
    hls_colour  illum
) {
    point       pt1;
    point       pt2;
    float       x1,y1;
    float       x2,y2;
    COLORREF    rgb;

    hls_to_rgb( &rgb, illum );

    _wsetrgbcolor( rgb );
    _wsetfillstyle( FILL_SOLID );

    rend_obj_region_begin( obj );

    switch (_rend_obj_get_type( obj )) {
    case REND_OBJ_PT:
        pt1 = rend_obj_get_pt( obj, 0 );
        project_pt( pt1, &x1, &y1 );
        _wdot( x1, y1 );
        break;
    case REND_OBJ_LINE:
        pt1 = rend_obj_get_pt( obj, 0 );
        pt2 = rend_obj_get_pt( obj, 1 );
        project_pt( pt1, &x1, &y1 );
        project_pt( pt2, &x2, &y2 );
        _wsetlinestyle( _line_get_style( rend_obj_get_line( obj ) ) );
        _wsetlinewidth( WIDTH_SINGLE );
        _wmoveto( x1, y1 );
        _wlineto( x2, y2, FALSE );
        break;
    case REND_OBJ_POLY:
        draw_projected_poly( obj, base );
        break;
    }

    rend_obj_region_end( obj );
}


/* Lighting model */
static point calculate_poly_centre(
/********************************/
/* The centre is the averaged in each coefficient of the points of the poly */
    rend_obj    *obj
) {
    point       centre;
    point       curr;
    int         num_pts;
    int         curr_pt;
    int         i;

    for (i = 0; i < 4; i++) {
        centre.p[i] = 0.;
    }

    num_pts = rend_obj_get_num_pts( obj );
    if (num_pts == 0) {
        return( centre );
    }

    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        curr = rend_obj_get_pt( obj, curr_pt );
        for (i = 0; i < 4; i++) {
            centre.p[i] += curr.p[i];
        }
    }

    for (i = 0; i < 4; i++) {
        centre.p[i] /= num_pts;
    }

    return( centre );
}

static hls_colour illuminate_poly(
/********************************/
    rend_obj    *obj,
    hls_colour  base
) {
    point       centre;
    vector      light_dir;          // from centre of poly to point light source
    float       len;                // norm of light_dir
    vector      normal;
    float       dot;                // dot product of normal and light_dir
    hls_colour  final_col;

    centre = calculate_poly_centre( obj );
    if( Illum_param.at_infinity ) {
        light_dir = Illum_param.source.light_dir;
    } else {
        light_dir = point_diff( centre, Illum_param.source.light_pt );
    }
    len = norm( light_dir );

    /* calculate the dot product */
    normal = rend_obj_get_norm( obj );
    dot = _dot_prod_vv( normal, light_dir );
    /* if the dot product is negative the point light source has no effect */
    /* since surfaces are self-occluding */
    if (dot < 0.) {
        dot = 0.;
    }

    final_col.h = base.h;
    final_col.s = base.s;

    final_col.l = Illum_param.amb_intensity * base.l +
                    Illum_param.pt_intensity * base.l * dot / len;

    /* l must in range [0,1] */
    if (final_col.l < 0.) {
        final_col.l = 0.;
    } else if (final_col.l > 1.) {
        final_col.l = 1.;
    }


    return( final_col );
}

extern void draw_illuminated_obj(
/*******************************/
    rend_obj    *obj
) {
    hls_colour  edge;
    hls_colour  illum;

    illum = rend_obj_get_base_colour( obj );

    if( _rend_obj_black_edges( obj ) ) {
        edge = Black_hls;
    } else {
        edge = illum;
    }

    if (_rend_obj_get_type( obj ) == REND_OBJ_POLY) {
        illum = illuminate_poly( obj, illum );
    }

    draw_projected_obj( obj, edge, illum );
}

extern void set_poly_convex_info(
/*******************************/
    bool        all_poly_convex
) {
    All_poly_convex = all_poly_convex;
}

extern void set_illumination(
/***************************/
    pipe_illum  *illum
) {
    Illum_param = *illum;
}

/* Visible surface determination */
#if 0
static void compute_extents(
/**************************/
    rend_list *     list
) {
    rend_list_ref   ref;
    rend_obj *      obj;

    _rend_list_first( list, &ref );
    while (! _rend_list_is_after_last( list, ref )) {
        obj = _rend_list_get_obj( list, ref );
        rend_obj_compute_vis_info( obj );

        _rend_list_next( list, &ref );
    }
}
#endif

static int compare_zmin(
/**********************/
    const rend_obj **     obj1,
    const rend_obj **     obj2
) {
    visible_info *  vis1;
    visible_info *  vis2;
    float           zmin1;
    float           zmin2;

    vis1 = _rend_obj_get_vis( (rend_obj *)(*obj1) );
    vis2 = _rend_obj_get_vis( (rend_obj *)(*obj2) );
    zmin1 = vis1->min.p[2];
    zmin2 = vis2->min.p[2];

    if (zmin1 < zmin2) {
        return( -1 );       // 1 here so the sort is in increasing order
    } else if (zmin1 == zmin2) {
        return( 0 );
    } else {
        return( 1 );        // -1 here so the sort is in increasing order
    }
}

#if 0
static bool extent_overlap(
/*************************/
    visible_info *  vis1,
    visible_info *  vis2,
    int             component
) {
    float           min1;
    float           min2;
    float           max1;
    float           max2;

    min1 = vis1->min.p[component];
    min2 = vis2->min.p[component];
    max1 = vis1->max.p[component];
    max2 = vis2->max.p[component];

    return( min1 < max2 && min2 < max1 );
}
#endif

#define _extent_overlap( vis1, vis2, i ) \
            ((vis1)->min.p[i] < (vis2)->max.p[i] && \
             (vis2)->min.p[i] < (vis1)->max.p[i] )

static vector calc_pt_norm(
/*************************/
    rend_obj *  obj,            // obj is a point object
    rend_obj *  other
) {
    vector      norm;
    vector      a;
    point       pt;
    point       start;
    point       end;

    switch( _rend_obj_get_type( other ) ) {
    case REND_OBJ_PT:
        norm = Zvect;
        break;
    case REND_OBJ_LINE:

⌨️ 快捷键说明

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