home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 March
/
VPR9703A.ISO
/
VPR_DATA
/
DOGA
/
SOURCES
/
REND.LZH
/
REND
/
VIEWCONV.C
< prev
Wrap
C/C++ Source or Header
|
1996-07-29
|
16KB
|
714 lines
/*
透視変換関数
1989.6.18
Copyright T.Kobayashi
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#ifdef FLOAT
/*(2^24-1)<<7*/
#define MAXLONGF 2147483520.0
#else
/*(2^31-1)*/
#define MAXLONGF 2147483647.0
#endif
#include "reader.h"
#include "glib.h"
static Matrix view ; /* 視点変換行列 */
static Matrix world ; /* ワールド座標変換行列 */
static Matrix worldit ; /* ワールド座標変換転置逆行列 */
static Matrix conv ; /* 座標変換行列 */
static Float fxpixel ;
static Float fypixel ; /* ピクセル数 */
static long polynum ; /* 登録したポリゴンの数 */
static Point *convbuf ; /* ワーク領域 */
static Point *clipbuf ; /* ワーク領域(クリッピング用) */
static AtrTable *atrconvbuf ; /* アトリビュートデータバッファ */
static AtrTable *atrclipbuf ; /* アトリビュートデータバッファ */
static int bufsize = 0 ; /* 領域のサイズ */
/*static int inbg = FALSE;*/
/*
proto -s viewconv.c > temp
*/
static void conv_poly( Poly*, Frame* );
static int clipcheck( Point*, int );
static int screenclip( Point*, AtrTable*, int );
static int clip( Point*, AtrTable*, int, int, Float, int );
static void lineclip( int, Point*, AtrTable*, int, int, int, Float);
static void viewconvbg(Frame *frame);
/*
視点座標変換(エッジリストの作成)
戻り値 プリミティブの数
-1:エラー
*/
long ViewConv( frame )
Frame *frame ;
{
int i, j, n ;
int lockop, lockpoly ;
Matrix m ;
ObjPos *op ;
Object *obj ;
Poly *poly ;
Point bound[8*2] ; /* バウンディングポックス */
#ifdef MOB
extern int TimeAnti;
static int tpos = 0;
static int ax[16] = {0,2,2,0,1,3,3,1,1,3,3,1,0,2,2,0};
static int ay[16] = {0,2,0,2,1,3,1,3,0,2,0,2,1,3,1,3};
#endif
fxpixel = (Float)XPixel ;
fypixel = (Float)YPixel ;
/* 視点変換行列の生成 奥行き方向はzに変換 */
m_inv( view, frame->eye.mat );
/* 奥行き座標軸の変更 */
m_unit( m );
m[0][0] = m[1][1] = m[2][2] = 0.0 ;
m[0][2] = m[1][0] = m[2][1] = 1.0 ;
m_mult( view, view, m );
/* スクリーン座標変換 */
m_unit( m );
m[2][0] = fxpixel / 2.0 ;
m[2][1] = fypixel / 2.0 ;
m[0][0] = - frame->eye.dist * fxpixel ;
m[1][1] = - frame->eye.dist * fxpixel / PixelRatio ;
#ifdef MOB
if (TimeAnti > 1) {
m[2][0] -= 0.25 * (Float)ax[tpos];
m[2][1] -= 0.25 * (Float)ay[tpos];
if (TimeAnti == 2) {
if (++tpos == 4) {
tpos = 0;
}
} else {
if (++tpos == 16) {
tpos = 0;
}
}
}
#endif
m_mult( view, view, m );
#ifdef STAR
Star(frame->env.star, view, frame->eye.dist);
#endif
/* 初期化 */
InitEdgeList() ; /* エッジリストの初期化 */
polynum = 0 ;
#ifdef BGMAKE
if (BgMake && ShadingModel == GOURAUD_SHADE ) {
viewconvbg(frame);
}
#endif
op = pointer( frame->objpos );
if ( op == NULL )
return 0;
/* メインループ */
for( ; op != NULL ; op = pointer( op->next ) )
{
lockop = datalock() ;
/* 行列のセット */
m_copy( world, op->mat );
m_inv( m, world );
m_trans( worldit, m );
m_mult( conv, world, view );
/* 物体のクリッピング */
obj = pointer( op->obj );
for( i = 0 ; i < 8 ; ++i )
{
for( j = 0 ; j < 3 ; ++j )
{
if ( i & ( 1 << j ) )
bound[i][j] = obj->max[j] ;
else
bound[i][j] = obj->min[j] ;
}
}
/* 座標変換 */
vec_mult_mat( bound, bound, conv, 8, 1 );
/* クリッピングチェック */
if ( clipcheck( bound, 8 ) == 0 ) {
continue ;
}
/* 物体の描画 */
n = obj->polynum ;
poly = pointer( obj->poly );
for( i = 0 ; i < n ; ++i )
{
assert( poly != NULL );
lockpoly = datalock();
conv_poly( poly, frame );
dataunlock( lockpoly );
poly = pointer( poly->next );
}
dataunlock( lockop );
}
return( polynum );
}
#ifdef BGMAKE
static void viewconvbg(Frame *frame)
{
int x, y;
int px, py;
Poly pol;
Point point[4];
Vector uv[4];
double theta, phi, nphi;
pol.type = UVPOLY;
pol.atr = NULL;
pol.atrid = 0;
pol.pointnum = 4;
pol.point = point;
pol.vec = NULL;
pol.uv = uv;
pol.coe[0] = pol.coe[1] = pol.coe[2] = pol.coe[3] = 0.0;
pol.next = NULL;
m_unit(world);
world[3][0] = frame->eye.mat[3][0];
world[3][1] = frame->eye.mat[3][1];
world[3][2] = frame->eye.mat[3][2];
m_unit(worldit);
m_mult( conv, world, view );
/*#define RADIUS ((double)FrontClip * (double)(MAXLONGF/8))*/
#define RADIUS (MAXLONGF/1024)
#define STEPX 8
#define STEPY 8
#define PI 3.14159265358979
#define STEPPHI (PI/(3*STEPY))
#define STEPTHETA (PI * 2 / (4*STEPX))
/* inbg = TRUE;*/
/* phi = 0.0; */
#define STEPPHI (PI * 3 / 8 / STEPY)
phi = (PI - STEPPHI * 3 * STEPY) * 0.5;
for (y = 0; y < 3*STEPY; y++, phi = nphi) {
nphi = phi + STEPPHI;
if (nphi < 0.0) {
continue;
} else if (phi >= PI) {
break;
} else if (phi < 0.0) {
phi = 0;
} else if (nphi >= PI) {
nphi = PI;
}
py = y / STEPY;
theta = - (PI/4);
point[0][0] = RADIUS * sin(phi) * cos(theta);
point[0][1] = -RADIUS * sin(phi) * sin(theta);
point[0][2] = RADIUS * cos(phi);
point[1][0] = RADIUS * sin(nphi) * cos(theta);
point[1][1] = -RADIUS * sin(nphi) * sin(theta);
point[1][2] = RADIUS * cos(nphi);
point[2][2] = point[1][2];
point[3][2] = point[0][2];
pol.coe[0] = - point[0][0];
pol.coe[1] = - point[0][1];
pol.coe[2] = - point[0][2];
v_unit(pol.coe, pol.coe);
pol.coe[3] = point[0][0] + point[0][1] + point[0][2];
for (x = 0; x < 4*STEPX; x++) {
px = x / STEPX;
theta += STEPTHETA;
point[3][0] = RADIUS * sin(phi) * cos(theta);
point[3][1] = -RADIUS * sin(phi) * sin(theta);
point[2][0] = RADIUS * sin(nphi) * cos(theta);
point[2][1] = -RADIUS * sin(nphi) * sin(theta);
uv[0][0] = uv[1][0] = (double)((x%STEPX) )/(double)STEPX;
uv[2][0] = uv[3][0] = (double)((x%STEPX)+1)/(double)STEPX;
uv[0][1] = uv[3][1] = (double)((y%STEPY) )/(double)STEPY;
uv[1][1] = uv[2][1] = (double)((y%STEPY)+1)/(double)STEPY;
if (BgMake == 12) {
pol.atr = BgMakeAtr[px + 4 * py];
} else if (BgMake == 6) {
pol.atr = BgMakeAtr[(px % 2) + 2 * py];
} else if (BgMake == 4) {
pol.atr = BgMakeAtr[px];
if (py == 0) {
uv[0][1] = uv[1][1] = uv[2][1] = uv[3][1] = 0.0;
} else if (py == 2) {
uv[0][1] = uv[1][1] = uv[2][1] = uv[3][1] = 1.0;
}
} else if (BgMake == 2) {
pol.atr = BgMakeAtr[px % 2];
if (py == 0) {
uv[0][1] = uv[1][1] = uv[2][1] = uv[3][1] = 0.0;
} else if (py == 2) {
uv[0][1] = uv[1][1] = uv[2][1] = uv[3][1] = 1.0;
}
} else if (BgMake == 1) {
pol.atr = BgMakeAtr[0];
uv[0][0] = uv[1][0] = (double)(x )/(double)(STEPX*4);
uv[2][0] = uv[3][0] = (double)(x+1)/(double)(STEPX*4);
uv[0][1] = uv[3][1] = (double)(y )/(double)(STEPY*3);
uv[1][1] = uv[2][1] = (double)(y+1)/(double)(STEPY*3);
}
conv_poly( &pol, frame );
point[1][0] = point[2][0];
point[1][1] = point[2][1];
point[1][2] = point[2][2];
point[0][0] = point[3][0];
point[0][1] = point[3][1];
point[0][2] = point[3][2];
}
/* phi += STEPPHI;*/
}
/* inbg = FALSE;*/
}
#endif
/* ポリゴンの視点変換 */
static void conv_poly( poly, frame )
Poly *poly ;
Frame *frame ;
{
int i, n, ch ;
static AtrTable atrbuf ;
n = poly->pointnum ;
/* ワークサイズのチェック&更新 */
if ( n > bufsize )
{
if ( bufsize > 0 )
{
tempfree( convbuf );
tempfree( clipbuf );
if ( ShadingModel == GOURAUD_SHADE )
{
tempfree( atrconvbuf );
tempfree( atrclipbuf );
}
}
bufsize = n ;
convbuf = (Point*)tempalloc( bufsize * 2 * sizeof( Point ) );
clipbuf = (Point*)tempalloc( bufsize * 2 * sizeof( Point ) );
if ( ShadingModel == GOURAUD_SHADE )
{
atrconvbuf = tempalloc( bufsize * 2 * sizeof( AtrTable ) );
atrclipbuf = tempalloc( bufsize * 2 * sizeof( AtrTable ) );
}
else
atrconvbuf = & atrbuf ;
}
/* 座標変換 */
vec_mult_mat( convbuf, (Point*)pointer(poly->point), conv, n, 1 );
/* クリッピングチェック */
ch = clipcheck( convbuf, n ) ;
if ( ch == 0 )
return ;
/* 光度計算 */
#ifdef BACKFACE
if (GetAtrTable( atrconvbuf, frame, poly, world, worldit ) == FALSE) {
return;
}
#else
GetAtrTable( atrconvbuf, frame, poly, world, worldit );
#endif
/* クリッピング */
if ( ch == 1 )
{
n = screenclip( convbuf, atrconvbuf, n );
if ( n == 0 )
return ;
}
#if 0
else if (inbg) {
/* 透視変換 */
for( i = 0 ; i < n ; ++i )
{
convbuf[i][0] /= convbuf[i][2] ;
convbuf[i][1] /= convbuf[i][2] ;
convbuf[i][2] = FrontClip;
}
#endif
else
{
/* 透視変換 */
for( i = 0 ; i < n ; ++i )
{
convbuf[i][0] /= convbuf[i][2] ;
convbuf[i][1] /= convbuf[i][2] ;
convbuf[i][2] = FrontClip * MAXLONGF / convbuf[i][2] ;
}
}
/* エッジリストに登録 */
SetEdgeList( convbuf, atrconvbuf, n, poly->atr );
polynum++ ;
}
/*
クリッピングのチェック
戻り値 0 すべてビューポート外
1 クリッピングの必要あり
2 すべてビューポート内
*/
static int clipcheck( buf, n )
Point *buf ;
int n ;
{
int i, flag, isin, isout ;
Float x, y ;
isin = 31 ;
isout = 0 ;
for( i = 0 ; i < n ; ++i )
{
#if 0
x = buf[i][0] / buf[i][2] ;
y = buf[i][1] / buf[i][2] ;
flag = 0 ;
if ( FrontClip <= buf[i][2] )
flag += 16 ;
else
{
x = - x ;
y = - y ;
}
if ( 0.0 <= x )
flag += 1 ;
if ( x < fxpixel )
flag += 2 ;
if ( 0.0 <= y )
flag += 4 ;
if ( y < fypixel )
flag += 8 ;
isin &= flag ;
isout |= flag ;
#endif
if (buf[i][2] == 0.0) {
x = 0;
y = 0;
} else {
x = buf[i][0] / buf[i][2] ;
y = buf[i][1] / buf[i][2] ;
}
flag = 0 ;
if ( FrontClip <= buf[i][2] )
flag += 16 ;
else
{
x = - x ;
y = - y ;
}
if ( 0.0 <= x )
flag += 1 ;
if ( x < fxpixel )
flag += 2 ;
if ( 0.0 <= y )
flag += 4 ;
if ( y < fypixel )
flag += 8 ;
isin &= flag ;
isout |= flag ;
#if 0
if ( FrontClip > buf[i][2] ) {
flag = 0;
} else {
x = buf[i][0] / buf[i][2] ;
y = buf[i][1] / buf[i][2] ;
flag = 16 ;
if ( 0.0 <= x )
flag += 1 ;
if ( x < fxpixel )
flag += 2 ;
if ( 0.0 <= y )
flag += 4 ;
if ( y < fypixel )
flag += 8 ;
}
isin &= flag ;
isout |= flag ;
#endif
}
if ( isout != 31 )
return( 0 );
if ( isin == 31 )
return( 2 );
return( 1 );
}
/*
スクリーンクリッピング
戻り値 クリッピング後の頂点数
*/
static int screenclip( buf, atrbuf, n )
Point *buf ;
AtrTable *atrbuf ;
int n ;
{
int i ;
int isin, isout, flags ;
/* 前面クリッピング */
isin = 1 ;
isout = 0 ;
for( i = 0 ; i < n ; ++i )
{
flags = ( buf[i][2] > FrontClip ) ;
isin &= flags ;
isout |= flags ;
}
if ( isout == 0 ) /* すべてビューポート外 */
return( 0 );
if ( isin != 1 ) /* すべてビューポート内ではない */
{
n = clip( buf, atrbuf, n, 2, FrontClip, TRUE );
}
/* 透視変換 */
for( i = 0 ; i < n ; ++i )
{
buf[i][0] /= buf[i][2] ;
buf[i][1] /= buf[i][2] ;
buf[i][2] = FrontClip * MAXLONGF / buf[i][2] ;
}
/* スクリーンクリッピング */
isin = 0x0f ;
isout = 0 ;
for( i = 0 ; i < n ; ++i )
{
flags = 0 ;
if ( buf[i][0] >= 0.0 )
flags += 1 ;
if ( buf[i][0] < fxpixel )
flags += 2 ;
if ( buf[i][1] >= 0.0 )
flags += 4 ;
if ( buf[i][1] < fypixel )
flags += 8 ;
isin &= flags ;
isout |= flags ;
}
if ( isout != 0x0f ) /* すべてスクリーン外 */
return( 0 );
if ( isin != 0x0f ) /* すべてスクリーンの中にあるわけではない */
{
/* クリッピングの必要あり */
if ( ( isin & 1 ) == 0 ) /* 左にはずれている */
{
n = clip( buf, atrbuf, n, 0, 0.0, TRUE );
if ( n == 0 )
return( 0 ) ;
}
if ( ( isin & 2 ) == 0 ) /* 右にはずれている */
{
n = clip( buf, atrbuf, n, 0, fxpixel, FALSE );
if ( n == 0 )
return( 0 ) ;
}
if ( ( isin & 4 ) == 0 ) /* 上にはずれている */
{
n = clip( buf, atrbuf, n, 1, 0.0, TRUE );
if ( n == 0 )
return( 0 ) ;
}
if ( ( isin & 8 ) == 0 ) /* 下にはずれている */
{
n = clip( buf, atrbuf, n, 1, fypixel, FALSE );
if ( n == 0 )
return( 0 ) ;
}
}
return( n );
}
/*
クリッピング
ワーク領域 clipbuf, scclipbuf を使用
戻り値 クリッピング後の頂点の数
すべてビューポート内にない場合は0
引数
n 頂点の数
(*inview)( point )
1:point がビューポート内にある。
0:point がビューポート内にない。
(*lineclip)( point, point1, point2 )
point1 と point2 を結んだ線分とビューポートの境界線との交点を
求める
*/
static int clip( Point *buf, AtrTable *atrbuf, int n, int axis, Float border, int sw )
{
int i, j, flag, f ;
int last ; /* ひとつ前の配列要素 */
int lastflag ; /* ひとつ前の頂点の状態 */
if ( axis == 2 )
f = FALSE ;
else
f = TRUE ;
/* クリッピング */
j = 0 ; /* clipbuf のカウンタ */
last = n - 1 ;
if ( sw )
lastflag = ( buf[last][axis] > border );
else
lastflag = ( border > buf[last][axis] );
for( i = 0 ; i < n ; ++i )
{
if ( sw )
flag = ( buf[i][axis] > border );
else
flag = ( border > buf[i][axis] );
if ( flag )
{
if ( lastflag ) /* 中にいたまま */
{
v_copy( clipbuf[j], buf[i] ) ;
if ( ShadingModel == GOURAUD_SHADE )
atrclipbuf[j] = atrbuf[i] ;
j++ ;
}
else
{
/* 外から中に */
lineclip( j++, buf, atrbuf, i, last, axis, border );
v_copy( clipbuf[j], buf[i] );
if ( ShadingModel == GOURAUD_SHADE )
atrclipbuf[j] = atrbuf[i] ;
j++ ;
}
}
else
{
if ( lastflag )
{
/* 中から外に */
lineclip( j++, buf, atrbuf, i, last, axis, border );
}
/* 外にいたままのときはなにもしない */
}
last = i ;
lastflag = flag ;
}
memcpy( (char *)buf, (char *)clipbuf, j * sizeof( Point ) );
if ( ShadingModel == GOURAUD_SHADE )
memcpy( (char*)atrbuf, (char*)atrclipbuf, j * sizeof( AtrTable ) );
return( j );
}
/* 線分のクリッピング */
static void lineclip( int n, Point *buf, AtrTable *atrbuf, int cur, int last, int axis, Float border )
{
int i ;
Float t ;
AtrTable *a1, *a2, *ap ;
t = ( border - buf[last][axis] ) / ( buf[cur][axis] - buf[last][axis] ) ;
clipbuf[n][0] = ( buf[cur][0] - buf[last][0] ) * t + buf[last][0] ;
clipbuf[n][1] = ( buf[cur][1] - buf[last][1] ) * t + buf[last][1] ;
clipbuf[n][2] = ( buf[cur][2] - buf[last][2] ) * t + buf[last][2] ;
if ( ShadingModel == GOURAUD_SHADE )
{
a1 = atrbuf + last ;
a2 = atrbuf + cur ;
ap = atrclipbuf + n ;
/* 線形補間 */
for( i = 0 ; i < 3 ; ++i )
{
ap->shade.curcolor[i]
= (long)(
(Float)( a2->shade.curcolor[i] -
a1->shade.curcolor[i] ) * t
)
+ a1->shade.curcolor[i] ;
#ifdef SPEC
ap->shade.curspecular[i]
= (long)(
(Float)( a2->shade.curspecular[i] -
a1->shade.curspecular[i] ) * t
)
+ a1->shade.curspecular[i] ;
ap->shade.depthcolor[i] = a1->shade.depthcolor[i];
#endif
}
#ifdef REFMAP
if (RefMap) {
double len = 0.0;
for (i = 0; i < 3; ++i) {
ap->shade.refcolor[i] = a1->shade.refcolor[i];
ap->shade.currefdir[i]
= (long)((Float)(a2->shade.currefdir[i] - a1->shade.currefdir[i]) * t)
+ a1->shade.currefdir[i];
}
#if 0
len += (Float)ap->shade.currefdir[i] * (Float)ap->shade.currefdir[i];
if (len >= 1.0) {
for (i = 0; i < 3; ++i) {
ap->shade.currefdir[i] = (Float)(ap->shade.currefdir[i]) / len * SHADE_POINT;
}
}
#endif
}
#endif
#ifdef SPEC
ap->shade.depthrate
= (long)((Float)(a2->shade.depthrate - a1->shade.depthrate)*t)
+ a1->shade.depthrate;
#endif
if (axis != 2) {
t = t * buf[cur][2] /
(buf[last][2] + (buf[cur][2]-buf[last][2])*t);
}
for( i = 0 ; i < 2 ; ++i )
{
ap->map.curuv[i]
= (long)(
(Float)( a2->map.curuv[i] -
a1->map.curuv[i] ) * t
)
+ a1->map.curuv[i] ;
}
ap->map.map = a1->map.map ;
}
}