world3.c

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

C
853
字号
/****************************************************************************
*
*                            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:
 ============
 These are the 3d drawing primitives used in other parts of cgr. The 3d
 pipeline should not be accessed by any part of cgr except this one.
*/

#include "icgr.h"

static hls_colour   Curr_colour = { 0., 0., 0. };
static w3coord      Curr_line_pt = { 0., 0., 0. };
static line_style   Curr_line_style = LINE_SOLID;
static bool         Black_edges = FALSE;
static region_info  Region = { USE_RGN_NONE };

#define _range_constrain( val, low, high ) _max( _min( (val), (high) ), (low) )

/* mathematical constant e */
#define E       2.7182818

/* constants for the simple to real perspective conversion */
#define SIMP_PERSP_MIN  0.
#define SIMP_PERSP_MAX  100.
#define REAL_PERSP_MIN  0.5
#define REAL_PERSP_MAX  40.

static void set_vpn_vup(
/**********************/
/* set the vecotors ViewPlNorm and VUp based on h_angle and v_angle */
    int         h_angle,
    int         v_angle,
    vector *    vpn,
    vector *    vup
) {
    float       sintheta, costheta;     /* h_angle values */
    float       sinphi, cosphi;         /* v_angle values */

    /* calculate the view plane normal */
    sintheta = sin( _deg_to_rad( h_angle ) );
    costheta = cos( _deg_to_rad( h_angle ) );
    cosphi   = cos( _deg_to_rad( v_angle ) );
    sinphi   = sin( _deg_to_rad( v_angle ) );
    vpn->v[0] = cosphi * sintheta;
    vpn->v[1] = sinphi;
    vpn->v[2] = cosphi * costheta;
    vpn->v[3] = 0;

    /* set the up vector to (0,1,0) if  -45 < v_angle < 45 otherwise */
    /* set it according to h_angle */
    if (v_angle >= 45) {
        vup->v[0] = - sintheta;
        vup->v[1] = 0.;
        vup->v[2] = - costheta;
        vup->v[3] = 0.;
    } else if (v_angle <= -45) {
        vup->v[0] = sintheta;
        vup->v[1] = 0.;
        vup->v[2] = costheta;
        vup->v[3] = 0.;
    } else {
        vup->v[0] = 0.;
        vup->v[1] = 1.;
        vup->v[2] = 0.;
        vup->v[3] = 0.;
    }
}

static float calculate_real_perspective(
/**************************************/
    int     simp_persp
) {
    float   x;

    /* set x to be simp_persp capped to SIMP_PERSP_MIN/MAX */
    if( simp_persp < SIMP_PERSP_MIN ) {
        x = SIMP_PERSP_MIN;
    } else if( simp_persp > SIMP_PERSP_MAX ) {
        x = SIMP_PERSP_MAX;
    } else {
        x = simp_persp;
    }

    /* scale x into [0,1] and reverse the direction */
    x = 1 - (x - SIMP_PERSP_MIN)/(SIMP_PERSP_MAX - SIMP_PERSP_MIN);

    /* apply exp to linearize the perspective, then scale into [0,1] */
    x = exp( x );
    x = (x - 1.) / (E - 1.);

    /* futher linearize the perspective */
    x = exp( x );
    x = (x - 1.) / (E - 1.);

    /* scale x into [REAL_PERSP_MIN, REAL_PERSP_MAX] */
    x = x * (REAL_PERSP_MAX - REAL_PERSP_MIN) + REAL_PERSP_MIN;

    return( x );
}

static void simple_to_pipe_view(
/******************************/
    view_3d *   simp,
    pipe_view * view,
    float       base_zoom
) {
    float       zoom;

    /* calculate the view plane normal and vup */
    set_vpn_vup( simp->h_angle, simp->v_angle, &view->ViewPlNorm, &view->VUp );

    /* calculate the view ref pt. */
    view->ViewRefPt.p[0] = 0.5 + view->ViewPlNorm.v[0]/2.;
    view->ViewRefPt.p[1] = 0.5 + view->ViewPlNorm.v[1]/2.;
    view->ViewRefPt.p[2] = 0.5 + view->ViewPlNorm.v[2]/2.;
    view->ViewRefPt.p[3] = 1.0;

    /* set the window */
    if( simp->zoom <= 0 ) {
        zoom = 100. / base_zoom;
    } else {
        zoom = 100. / (simp->zoom * base_zoom);
    }
    view->vmin = - zoom;
    view->vmax = zoom;
    view->umin = - zoom;
    view->umax = zoom;

    /* set the projection ref. pt. */
    view->ProjRefPt.p[0] = 0.;
    view->ProjRefPt.p[1] = 0.;
    view->ProjRefPt.p[2] = calculate_real_perspective( simp->perspective );
    view->ProjRefPt.p[3] = 1.;

    /* set the front and back clipping planes */
    view->FrontClip = 0.;           /* note FrontClip > BackClip */
    view->BackClip = -1.;

    view->type = simp->type;
}

static void set_light_dir(
/************************/
    vector *            dir,
    light_vert_pos      vert,
    light_horz_pos      horz,
    light_depth_pos     depth
) {
    float               len;
    int                 i;

    switch( horz ) {
    case LIGHT_HORZ_LEFT:
        dir->v[0] = -1.;
        break;
    case LIGHT_HORZ_MID:
        dir->v[0] = 0.;
        break;
    case LIGHT_HORZ_RIGHT:
        dir->v[0] = 1.;
        break;
    }
    switch( vert ) {
    case LIGHT_VERT_TOP:
        dir->v[1] = 1.;
        break;
    case LIGHT_VERT_MID:
        dir->v[1] = 0.;
        break;
    case LIGHT_VERT_BOTTOM:
        dir->v[1] = -1.;
        break;
    }
    switch( depth ) {
    case LIGHT_DEPTH_FRONT:
        dir->v[2] = 1.;
        break;
    case LIGHT_DEPTH_MID:
        dir->v[2] = 0.;
        break;
    case LIGHT_DEPTH_BACK:
        dir->v[2] = -1.;
        break;
    }

    dir->v[3] = 0;

    len = norm( *dir );
    /* test for the middle, middle middle case */
    if( len == 0. ) {
        dir->v[2] = 1.;         // make this middle, middle, front
    } else {
        /* otherwise normalize the vector */
        for( i = 0; i < 4; i++ ) {
            dir->v[i] /= len;
        }
    }
}

static void simple_to_pipe_illum(
/*******************************/
/*
NOTE: that since the lighting model is applied after the viewing
transformation has been performed the fact that h_angle and v_angle are
relitive to the viewing parameters is taken care of automagiclly.
NOTE: the centre of attention for the illumination model, relitive to which
the light source will be placed, is at (.5, .5, .5).
*/
    light_3d *      simp,
    pipe_illum *    pipe,
    float           distance,
    light_vert_pos  auto_pos
) {
    vector          dir;
    float           contrast;
    float           brightness;

    pipe->at_infinity = (distance == 0.);

    /* set the illumination point */
    if( simp->type == LIGHT_AUTO ) {
        set_light_dir( &dir, auto_pos, LIGHT_HORZ_LEFT,
                                LIGHT_DEPTH_FRONT );
    } else {
        set_light_dir( &dir, simp->vert, simp->horz, simp->depth );
    }
    if( pipe->at_infinity ) {
        pipe->source.light_dir = dir;
    } else {
        pipe->source.light_pt.p[0] = .5 + distance * dir.v[0];
        pipe->source.light_pt.p[1] = .5 + distance * dir.v[1];
        pipe->source.light_pt.p[2] = .5 + distance * dir.v[2];
        pipe->source.light_pt.p[3] = 1.;
    }

    contrast = _range_constrain( simp->contrast, 0, 100 ) / 100.;
    brightness = _range_constrain( simp->brightness, 0, 100 ) / 50.;

    pipe->amb_intensity = (1. - contrast) * brightness;
    pipe->pt_intensity = contrast * brightness;
}

extern void _w3init(
/******************/
    three_d_op *    view,
    float           base_zoom,
    float           light_distance,         // if 0 light is at infinity
    light_vert_pos  auto_pos,
    bool            all_poly_convex
) {
    pipe_view *     pview;
    pipe_illum *    pillum;

    _new( pview, 1 );
    _new( pillum, 1 );
    simple_to_pipe_view( &view->view, pview, base_zoom );
    simple_to_pipe_illum( &view->lighting, pillum, light_distance, auto_pos );
    pipe3d_init( pview, pillum, all_poly_convex );
    _free( pillum );
    _free( pview );
}

extern void _w3shutdown(
/**********************/
    void
) {
    pipe3d_shutdown();
}

extern void _w3display_all(
/*************************/
    void
) {
    pipe3d_display();
}

extern void _w3get_view_dir(
/**************************/
/* Gets the viewing direction based on the angles given in view */
/* NOTE: The assumtion made in this routine are valid for the restricted */
/* viewing system employed in cgr but are not valid for the complete system */
/* as described in "Computer Graphics" by Foley et. al. */
    view_3d *   view,
    w3coord *   dir
) {
    vector      vpn;
    vector      dummy;
    float       len;

    set_vpn_vup( view->h_angle, view->v_angle, &vpn, &dummy );

    len = norm( vpn );
    dir->xcoord = - vpn.v[0] / len;
    dir->ycoord = - vpn.v[1] / len;
    dir->zcoord = - vpn.v[2] / len;
}

extern void _w3setcolour(
/***********************/
    COLORREF    rgb
) {
    rgb_to_hls( rgb, &Curr_colour );
}

extern void _w3setlinestyle(
/**************************/
    line_style  style
) {
    Curr_line_style = style;
}

extern void _w3setblackedges(
/***************************/
    bool    black_edges
) {
    Black_edges = black_edges;
}

static void rect_to_polar(
/************************/
    float       x,
    float       y,
    float       *r,
    float       *omega
) {
    *r = sqrt( x*x + y*y );
    if (*r == 0.) {
        *omega = 0.;        // this value is arbitrary
    } else {
        *omega = atan2( y, x );
    }
}

static void polar_to_rect(
/************************/
    float       r,
    float       omega,
    float       *x,
    float       *y
) {
    *x = r * cos( omega );
    *y = r * sin( omega );
}

extern void ellipse_pt(
/*********************/
/* Calculated the point on the ellipse at angle alpha */
    float       h_sqr,              // horizontal axis squared
    float       v_sqr,              // vertical axis squared
    float       cx,                 // centre
    float       cy,
    float       alpha,
    float *     x,
    float *     y
) {
    float       calpha;
    float       salpha;
    float       r;

    calpha = cos( alpha );
    salpha = sin( alpha );

    r = sqrt( 1./(calpha*calpha/h_sqr + salpha*salpha/v_sqr));
    polar_to_rect( r, alpha, x, y );
    *x += cx;
    *y += cy;
}

static pt_edge * pie_to_poly(
/***************************/
/* returns a polynomial approximation to the pie wedge given */
/* The points in the polygon approximation are layed out in counter clockwise */
/* order as seen from below so that the sweep by height will put the solid in */
/* the 0-1 cube */
    float       x1,
    float       z1,
    float       x2,
    float       z2,
    float       x3,
    float       z3,
    float       x4,
    float       z4,
    float       y,
    int         resolution,
    int *       num_pts,
    text_info * text,
    bool        all_pie
) {
    pt_edge     *pts;           // polygon that will approximate the pie
    int         num_regions;    // number of regions to devide the pie into
    float       cx, cz;         // centre of ellipse
    float       h_sqr, w_sqr;   // square of the half height & width
    float       alpha;          // angle of current point from x-axis
    float       omega;          // angle between start and end of pie
    float       beta;           // angle of mid point of pie
    float       dummy;

⌨️ 快捷键说明

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