home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 March
/
VPR9703A.ISO
/
VPR_DATA
/
DOGA
/
SOURCES
/
REND.LZH
/
REND
/
DISPLAY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-13
|
15KB
|
696 lines
/*
*
* 画面表示
*
* CopyRight T.Kobayashi
* 1989.4.28
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "reader.h"
#include "glib.h"
#define ERROR_LEVEL 200L
typedef enum _EdgeStaus {
STAT_WAIT,
STAT_LEFTEDGE,
STAT_CENTER,
STAT_CURRENT,
STAT_TRANS
}
EdgeStatus ;
typedef struct {
EdgeStatus stat ;
short startx, xcount ;
long z, dzdx ;
char traflag ;
unsigned char tra[3] ;
ColorCode code ;
ShadeTable shade ;
MapTable map ;
}
ActiveBuf ;
#define FLAT_ACTIVE_SIZE ( sizeof( ActiveBuf ) - sizeof( ShadeTable ) \
- sizeof( MapTable ) )
#define GOURAUD_ACTIVE_SIZE ( sizeof( ActiveBuf ) )
#define active_comp( a1, a2 ) ( (long)(a1) - (long)(a2) )
#if defined(X68000) || defined(DJ) || defined(UNIX) || defined(__WIN32__)
#define _inc_active( ac ) (char*)ac += sizeof_active
#elif defined(MSC) || defined(__BORLANDC__)
#define _inc_active( ac )\
{\
ac = (Pointer(ActiveBuf*))( (char*)ac + sizeof_active );\
nomalize_pointer( ac );\
}
#else
#error "MACHINE TYPE UNKNOWN!"
#endif /* MSC */
#ifdef VIRTUAL
#define inc_active( ac ) \
{ \
if ( virtualmode ) \
ac = virarynext( ac, sizeof_active ); \
else \
_inc_active( ac ); \
}
#else
#define inc_active( ac ) _inc_active( ac )
#endif /* VIRTUAL */
static Pointer(EdgeList*) ae ; /* アクティブエッジリスト */
static ColorCode *framebuf = NULL ; /* フレームバッファ */
static ColorCode back ; /* バックのカラーコード */
static Pointer(ActiveBuf*) active = NULL ; /* アクティブエッジバッファ */
static int activecount = 0 ; /* アクティブバッファ数 */
static int sizeof_active; /* アクティブバッファのサイズ */
static Pointer(void*) mark ; /* マーク */
/*
proto -s display.c > temp
*/
static void scanline( int );
static Pointer(ActiveBuf*) initactivebuf( int );
static ColorCode transparent( int, Pointer(ActiveBuf*), Pointer(ActiveBuf*), Pointer(ActiveBuf*) );
static EdgeList *getedge( EdgeList* );
static void DDAinc( DDA* );
/* 表示ルーチン */
void Display( frame, n )
Frame *frame ;
int n ; /* プリミティブの数 */
{
int x, y, edgelock ;
REGISTER int edgenum, flag ;
REGISTER Pointer(EdgeList*) *pp;
REGISTER Pointer(EdgeList*) p1;
REGISTER Pointer(EdgeList*) p2 ;
REGISTER EdgeList *edge1, *edge2 ;
if ( ShadingModel == GOURAUD_SHADE )
sizeof_active = GOURAUD_ACTIVE_SIZE ;
else
sizeof_active = FLAT_ACTIVE_SIZE ;
/* アクティブエッジリストの初期化 */
ae = NULL ;
edgenum = 0 ;
activecount = 0 ;
mark = datamark();
/* フレームバッファ確保 */
if ( framebuf == NULL )
framebuf = (ColorCode*)tempalloc( sizeof( ColorCode ) * XPixel );
/* バックの計算 */
if ( BackLoad )
{
BackOpen( BackFile );
}
else
{
#ifdef FULLCOLOR
back = ColorToCode( frame->env.back ) & 0xf8f8f8ffL;
#else
back = ColorToCode( frame->env.back ) ;
#endif
if ( back == 0 || TraBack )
back += 255 ;
}
/* メインループ */
for( y = 0 ; y < YPixel ; ++y )
{
/* アクティブエッジリストの追加 */
for( p1 = EdgeBuf[y] ; p1 != NULL ; p1 = p2 )
{
edge1 = (EdgeList*)pointer( p1 );
edgelock = datalock();
p2 = edge1->next ;
x = edge1->dxdy.x ;
pp = & ae ;
while( *pp != NULL )
{
edge2 = pointer( *pp );
if ( edge2->dxdy.x > x )
break ;
pp = &( edge2->next );
}
edge1->next = *pp ;
*pp = p1 ;
dataunlock( edgelock );
edgenum ++ ;
}
/* 描画 */
scanline( edgenum ) ;
/* アクティブエッジリストの更新、削除 */
pp = & ae ;
edgelock = -1 ;
while( *pp != NULL )
{
edge1 = pointer( *pp );
if ( -- ( edge1->n ) == 0 )
{
*pp = edge1->next ;
edgenum -- ;
}
else
{
/* x,z座標の更新 */
DDAinc( &( edge1->dxdy ) );
edge1->z += edge1->dzdy ;
if ( ShadingModel == GOURAUD_SHADE )
{
if ( edge1->mapflag )
IncAtrTable( &( edge1->shade ), &( edge1->map ) );
else
IncAtrTable( &( edge1->shade ), NULL );
}
#ifdef VIRTUAL
if ( edgelock != -1 )
dataunlock( edgelock );
edgelock = datalock();
#endif
pp = &( edge1->next );
}
}
#ifdef VIRTUAL
if ( edgelock != -1 )
dataunlock( edgelock );
#endif
/* アクティブエッジリストのソート */
if ( ae != NULL )
{
flag = TRUE ;
while( flag )
{
flag = FALSE ;
pp = & ae ;
edge1 = pointer( *pp );
while( edge1->next != NULL )
{
p2 = edge1->next ;
edge2 = pointer( p2 );
if ( edge1->dxdy.x > edge2->dxdy.x )
{
/* 入れ替え */
flag = TRUE ;
edge1->next = edge2->next ;
edge2->next = *pp ;
*pp = p2 ;
}
else
pp = &( edge1->next );
edge1 = pointer( *pp );
}
}
}
}
if ( BackLoad )
BackClose();
}
/* 描画ルーチン */
static void scanline( edgenum )
int edgenum ;
{
int i, n ;
int px ;
Pointer(ActiveBuf*) start;
Pointer(ActiveBuf*) end;
Pointer(ActiveBuf*) bufend;
REGISTER long z, dzdx ;
REGISTER Pointer(ActiveBuf*) pac;
REGISTER Pointer(ActiveBuf*) maxac ;
REGISTER ActiveBuf *ac ;
/* 背景処理 */
if ( BackLoad )
{
BackCopy( framebuf );
}
else
{
for( i = 0 ; i < XPixel ; ++i )
framebuf[i] = back ;
}
#ifdef STAR
StarCopy(framebuf);
#endif
if ( edgenum == 0 )
{
(*PictureOutput)( framebuf );
return ;
}
/* バッファの初期化 */
assert( ( edgenum % 2 ) == 0 );
if ( edgenum / 2 + 1 > activecount )
{
if ( activecount > 0 )
datarelease( mark );
activecount = edgenum / 2 + 1 ;
active = dataaryalloc( activecount, sizeof_active );
}
bufend = initactivebuf( edgenum );
/* メインループ */
start = active ;
end = active ;
for( px = 0 ; px < XPixel ; ++px )
{
/* 削除 */
pac = start ;
while( active_comp( pac, end ) < 0L )
{
ac = pointer( pac );
if ( ac->stat != STAT_WAIT )
{
if ( -- (ac->xcount) == 0 )
{
ac->stat = STAT_WAIT ;
if ( start == pac )
{
do
{
inc_active( pac );
ac = pointer( pac );
}
while( ac->stat == STAT_WAIT &&
active_comp( pac, end ) < 0L );
start = pac ;
continue ;
}
}
else
ac->z += ac->dzdx ;
}
inc_active( pac );
}
/* 登録 */
ac = pointer( pac );
while( ac->startx == px && active_comp( pac, bufend ) < 0L )
{
ac->stat = STAT_LEFTEDGE ;
inc_active( pac );
ac = pointer( pac );
}
end = pac ;
/* 表示色決定 */
z = 0L ;
dzdx = 0L ;
pac = start ;
while( active_comp( pac, end ) < 0L )
{
ac = pointer( pac );
switch( ac->stat )
{
case STAT_LEFTEDGE :
ac->stat = STAT_CENTER ;
if ( ( ac->z - ERROR_LEVEL > z ) ||
( ac->z + ERROR_LEVEL > z &&
/* ac->z + ac->dzdx > z + dzdx ) )*/
ac->dzdx > dzdx ) )
{ z = ac->z ;
dzdx = ac->dzdx ;
maxac = pac ;
}
break ;
case STAT_TRANS :
case STAT_CURRENT :
(int)(ac->stat) -- ;
case STAT_CENTER :
if ( ac->z > z )
{
z = ac->z ;
dzdx = ac->dzdx ;
maxac = pac ;
}
break ;
}
inc_active( pac );
}
if ( z != 0L )
{
ac = pointer( maxac );
if ( ac->traflag || ( ShadingModel == GOURAUD_SHADE && ac->map.map != NULL ) )
{
/* 半透明処理 */
framebuf[px] = transparent( px, maxac, start, end );
}
else
{
if ( ShadingModel == GOURAUD_SHADE )
{
if ( ac->stat != STAT_CURRENT )
AddAtrTable( &(ac->shade), &(ac->map), px - ac->startx );
#ifdef SPEC
framebuf[px] = GetColorAllCode( &(ac->shade), &(ac->map) );
#else
framebuf[px] = GetColorCode( &(ac->shade), &(ac->map) );
#endif
/* バッファの更新 */
IncAtrTable( &(ac->shade), &(ac->map) );
ac->stat = STAT_TRANS ;
ac->startx = px + 1 ;
#if 0
#ifdef SPEC
framebuf[px] = GetColorAllCode( &(ac->shade), &(ac->map) );
#else
framebuf[px] = GetColorCode( &(ac->shade), &(ac->map) );
#endif
/* バッファの更新 */
if ( ac->stat == STAT_CURRENT )
{
IncAtrTable( &(ac->shade), &(ac->map) );
}
else
{
AddAtrTable( &(ac->shade), &(ac->map),
px - ac->startx + 1 );
}
ac->stat = STAT_TRANS ;
ac->startx = px + 1 ;
#endif
}
else
framebuf[px] = ac->code ;
}
}
}
/* 画面出力 */
(*PictureOutput)( framebuf );
}
/* アクティブエッジバッファの初期化 */
static Pointer(ActiveBuf*) initactivebuf( edgenum )
int edgenum ;
{
int n, edgelock, aclock ;
REGISTER int i, dx ;
REGISTER Pointer(EdgeList*) p;
REGISTER Pointer(ActiveBuf*) pac ;
REGISTER EdgeList *edge1, *edge2 ;
REGISTER ActiveBuf *ac ;
pac = active ;
n = 0 ;
for( p = ae ; p != NULL ; p = edge1->next )
{
ac = pointer( pac );
aclock = datalock();
edge1 = pointer( p );
if ( edge1->flag == FALSE )
{
edgelock = datalock();
edge2 = getedge( edge1 );
edge2->flag = TRUE ;
dx = edge2->dxdy.x - edge1->dxdy.x ;
if ( dx == 0 )
{
dataunlock( edgelock );
dataunlock( aclock );
continue ;
}
ac->stat = STAT_WAIT ;
ac->startx = edge1->dxdy.x ;
ac->xcount = dx ;
ac->z = edge1->z ;
ac->dzdx = ( edge2->z - edge1->z + dx / 2 ) / dx ;
ac->traflag = edge2->traflag ;
for( i = 0 ; i < 3 ; ++i )
ac->tra[i] = edge1->tra[i] ;
if ( ShadingModel == GOURAUD_SHADE )
{
ac->shade = edge1->shade ;
if ( edge1->mapflag)
ac->map = edge1->map ;
else
ac->map.map = NULL ;
if ( dx != 0 )
{
SetAtrStep( &( ac->shade ), &( edge2->shade ),
&( ac->map ), &( edge2->map ), dx );
#ifdef EXTENDMAP
if (edge1->mapflag) {
SetAtrStepMap(ac->z, edge2->z,
&( ac->map ), &( edge2->map ), dx );
}
#endif
}
}
else
ac->code = edge1->code ;
inc_active( pac );
dataunlock( edgelock );
n ++ ;
}
else
edge1->flag = FALSE ;
dataunlock( aclock );
}
assert( n <= edgenum / 2 );
return( pac );
}
/* 半透明処理 */
static ColorCode transparent( px, maxac, start, end )
int px ;
Pointer(ActiveBuf*) start;
Pointer(ActiveBuf*) end ;
REGISTER Pointer(ActiveBuf*) maxac ;
{
int i ;
#ifdef SPEC
ColorCode cc, spec;
unsigned short code[4], tmpcode;
#else
REGISTER ColorCode code, cc ;
#endif
REGISTER long z ;
REGISTER ActiveBuf *ac ;
REGISTER Pointer (ActiveBuf*) pac ;
static unsigned char tra[3] ;
static int shift[] = { 16, 24, 8, 0} ; /* r g b のシフト数 */
int maptra;
#define COLORBITS 8
tra[0] = tra[1] = tra[2] = 128;
#ifdef SPEC
code[0] = 0; code[1] = 0; code[2] = 0; code[3] = 0;
#else
code = 0 ;
#endif
for(;;)
{
ac = pointer( maxac );
if ( ShadingModel == GOURAUD_SHADE )
{
if ( ac->stat != STAT_CURRENT )
AddAtrTable( &(ac->shade), &(ac->map), px - ac->startx );
cc = GetColorCode( &(ac->shade), &(ac->map) );
#ifdef SPEC
spec = GetSpecularColorCode( &(ac->shade));
#endif
/* バッファの更新 */
IncAtrTable( &(ac->shade), &(ac->map) );
ac->startx = px + 1 ;
#if 0
cc = GetColorCode( &(ac->shade), &(ac->map) );
#ifdef SPEC
spec = GetSpecularColorCode( &(ac->shade), &(ac->map) );
#endif
/* バッファの更新 */
if ( ac->stat == STAT_CURRENT )
IncAtrTable( &(ac->shade), &(ac->map) );
else
AddAtrTable( &(ac->shade), &(ac->map),
px - ac->startx + 1 );
ac->startx = px + 1 ;
#endif
}
else
{
cc = ac->code ;
#ifdef SPEC
spec = 0;
#endif
}
ac->stat = STAT_TRANS ;
if ((ShadingModel != GOURAUD_SHADE || ac->map.map == NULL)
|| (cc & 255) != 255) {
if ((maptra = (int)(cc & 255U)) > 128) {
maptra++;
}
for( i = 0 ; i < 3 ; ++i )
{
#ifdef SPEC
long plus;
#if 0
plus =
(
( ( (long)cc >> shift[i] ) & 255 )
* (long)tra[i] * ( 128 - (long)ac->tra[i] )
* (256-maptra) / (long)(128*128*256)
) + (
( ( (long)spec >> shift[i]) & 255)
* (long)tra[i] / (long)(128)
);
#else
plus =
(
( ( (long)cc >> shift[i] ) & 255 )
* (long)tra[i] * ( 128 - (long)ac->tra[i] )
/ (long)(128*128)
) + (
( ( (long)spec >> shift[i]) & 255)
* (long)tra[i] / (long)(128)
);
#endif
if (ac->shade.depthrate > 0) {
plus = ( plus * (SHADE_POINT - ac->shade.depthrate)
+ (ac->shade.depthcolor[i] >> (SHADE_SHIFT - COLORBITS))
* ac->shade.depthrate / 128 * tra[i]) / SHADE_POINT;
}
code[i] += (unsigned short)plus;
#else
#if 0
code +=
(
( ( (long)cc >> shift[i] ) & 255 )
* (long)tra[i] * ( 128 - (long)ac->tra[i] )
* (256-maptra) / (long)(128*128*256)
) << (long)shift[i] ;
#else
code +=
(
( ( (long)cc >> shift[i] ) & 255 )
* (long)tra[i] * ( 128 - (long)ac->tra[i] )
/ (long)(128*128)
) << (long)shift[i] ;
#endif
#endif
tra[i] = (int)tra[i] *
((int)ac->tra[i] * 256 + (128 - (int)ac->tra[i]) * maptra)
/ (128*256);
}
}
if ( ! ( tra[0] || tra[1] || tra[2] ) )
#ifdef SPEC
{
for (i = 0; i < 3; ++i) {
if (code[i] > 255) code[i] = 255;
}
return( (code[0] << shift[0])
+ (code[1] << shift[1])
+ (code[2] << shift[2]));
}
#else
return( code );
#endif
z = 0L ;
maxac = NULL ;
pac = start ;
while( active_comp( pac, end ) < 0L )
{
ac = pointer( pac );
if ( ac->stat != STAT_WAIT && ac->stat != STAT_TRANS )
{
if ( ac->z > z )
{
z = ac->z ;
maxac = pac ;
}
}
inc_active( pac );
}
if ( maxac == NULL )
{
for( i = 0 ; i < 3 ; ++i )
{
#ifdef SPEC
code[i] +=
(unsigned short)(
( ( (long)framebuf[px] >> shift[i] ) & 255 )
* tra[i] / 128
);
#else
code +=
(ColorCode)(
( ( (long)framebuf[px] >> shift[i] ) & 255 )
* tra[i] / 128
) << (long)shift[i] ;
#endif
}
#ifdef SPEC
for (i = 0; i < 3; ++i) {
if (code[i] > 255) code[i] = 255;
}
return (code[0] << shift[0])
+ (code[1] << shift[1])
+ (code[2] << shift[2])
+ (framebuf[px] & 255) * (tra[0]+tra[1]) / 256;
#else
code += (framebuf[px] & 255) * (tra[0]+tra[1]) / 256;
return( code );
#endif
}
}
}
/* 1辺からもう1辺を検索する */
static EdgeList *getedge( edge )
REGISTER EdgeList *edge ;
{
REGISTER int id ;
REGISTER Pointer(EdgeList*) p ;
id = edge->polyid ;
p = edge->next ;
while( p != NULL )
{
edge = pointer( p );
if ( edge->polyid == id )
return( edge );
p = edge->next ;
}
assert( FALSE );
return NULL;
}
/* DDA のインクリメント */
static void DDAinc( dda )
REGISTER DDA *dda ;
{
dda->x += dda->dxdy ;
dda->totalmod += dda->mod ;
if ( dda->totalmod >= dda->dy )
{
dda->totalmod -= dda->dy ;
dda->x ++ ;
}
}