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 + -
显示快捷键?