第九章开头就说,核心引擎要修改和添加的代码超过15000行,因此,先开始进行吧。幸好,看了下,大部分没动。主要是进行GOURAUD着色和基本纹理映射
因此,我觉得有必”?要再加个DDRAW_TEXTURE类。
//为帮助纹理应设函数分析三角形定义的常量
#define TRI_TYPE_NONE 0
#define TRI_TYPE_FLAT_TOP 1
#define TRI_TYPE_FLAT_BOTTOM 2
#define TRI_TYPE_FLAT_MASK 3
#define TRI_TYPE_GENERAL 4
#define INTERP_LHS 0
#define INTERP_RHS 1
#define MAX_VERTICES_PER_POLY 6
新的多边形顶点结构定义
//多边形和多边形的属性
#define POLY4DV2_ATTR_2SIDED 0x0001
#define POLY4DV2_ATTR_TRANSPARENT 0x0002
#define POLY4DV2_ATTR_8BITCOLOR 0x0004
#define POLY4DV2_ATTR_RGB16 0x0008
#define POLY4DV2_ATTR_RGB24 0x0010
#define POLY4DV2_ATTR_SHADE_MODE_PURE 0x0020
#define POLY4DV2_ATTR_SHADE_MODE_CONSTANT 0x0020
#define POLY4DV2_ATTR_SHADE_MODE_EMISSIVE 0x0020
#define POLY4DV2_ATTR_SHADE_MODE_FLAT 0x0040
#define POLY4DV2_ATTR_SHADE_MODE_GOURAUD 0x0080
#define POLY4DV2_ATTR_SHADE_MODE_PHONG 0x0100
#define POLY4DV2_ATTR_SHADE_MODE_FASTPHONG 0x0100
#define POLY4DV2_ATTR_SHADE_MODE_TEXTURE 0x0200
#define POLY4DV2_ATTR_ENABLE_MATERIAL 0x0800 //根据材质进行光照计算
#define POLY4DV2_ATTR_DISABLE_MATERIAL 0x1000 //根据多边形颜色进行光照
//多边形和多边形面的状态
#define POLY4DV2_STATE_NULL 0x0000
#define POLY4DV2_STATE_ACTIVE 0x0001
#define POLY4DV2_STATE_CLIPPED 0x0002
#define POLY4DV2_STATE_BACKFACE 0x0004
#define POLY4DV2_STATE_LIT 0x0008
//用于简单模型,指定着色模式
#define VERTEX_FLAGS_OVERRIDE_MASK 0xf000
#define VERTEX_FLAGS_OVERRIDE_CONSTANT 0x1000
#define VERTEX_FLAGS_OVERRIDE_PURE 0x1000
#define VERTEX_FLAGS_OVERRIDE_FLAT 0x2000
#define VERTEX_FLAGS_OVERRIDE_GOURAUD 0x4000
#define VERTEX_FLAGS_OVERRIDE_TEXTURE 0x8000
#define VERTEX_FLAGS_INVERT_TEXTURE_U 0x0080 //反转纹理坐标U
#define VERTEX_FLAGS_INVERT_TEXTURE_V 0x0100 //反转纹理坐标V
#define VERTEX_FLAGS_INVERT_SWAP_UV 0x0800 //将纹理坐标U和V互换
#define OBJECT4DV2_MAX_VERTICES 4096
#define OBJECT4DV2_MAX_POLYS 8192
#define OBJECT4DV2_STATE_NULL 0x0000
#define OBJECT4DV2_STATE_ACTIVE 0x0001
#define OBJECT4DV2_STATE_VISIBLE 0x0002
#define OBJECT4DV2_STATE_CULLED 0x0004
#define OBJECT4DV2_ATTR_SINGLE_FRAME 0x0001 //单帧物体
#define OBJECT4DV2_ATTR_MULTI_FRAME 0x0002 //多帧物体
#define OBJECT4DV2_ATTR_TEXTURES 0x0004 //指出物体是否包含带纹理的多边形
#define RENDERLIST4DV2_MAX_POLYS 32768
#define VERTEX4DTV1_ATTR_NULL 0x0000 //顶点为空
#define VERTEX4DTV1_ATTR_POINT 0x0001 //顶点
#define VERTEX4DTV1_ATTR_NORMAL 0x0002 //法线
#define VERTEX4DTV1_ATTR_TEXTURE 0x0004 //纹理坐标
新增的整型数学库
ypedef struct VECTOR2DI_TYP
{
union
{
int M[2];
struct
{
int x, y;
};
};
}VECTOR2DI ,POINT2DI, * VECTOR2DI_PTR, * POINT2DI_PTR;
typedef struct VECTOR3DI_TYP
{
union
{
int M[3];
struct
{
int x, y, z;
};
};
}VECTOR3DI ,POINT3DI, * VECTOR3DI_PTR, * POINT3DI_PTR;
typedef struct VECTOR4DI_TYP
{
union
{
int M[4];
struct
{
int x, y, z, w;
};
};
}VECTOR4DI ,POINT4DI, * VECTOR4DI_PTR, * POINT4DI_PTR;
加上一个宏,比较浮点数
#define FCMP( a,b ) (( fabs( a - b ) < EPSILON_E3) ? 1 : 0 )
能进行的,则先一步步来。
先加上个顶点数据结构
//包含两个纹理坐标和顶点法线的D齐次顶点
typedef struct VERTEX4DTV1_TYP
{
union
{
float M[12]; //以数组方式存储
};
//通过名称存取
struct
{
float x, y, z, w; //点
float nx, ny, nz, nw; //法线(向量或点)
float u0, v0; //纹理坐标
float color; //经过光照处理后的顶点颜色
int attr; //属性
};
//高级类型
struct
{
POINT4D v; //顶点
VECTOR4D n; //法线
POINT2D t; //纹理坐标
};
}VERTEX4DTV2, * VERTEX4DTV2_PTR;
接着进行复制和初始化,一样的。
void DDRAW_LIUSHUIXIAN_TEXTURE::VERTEX4DTV1_COPY( VERTEX4DTV1_PTR vdst, VERTEX4DTV1_PTR vsrc )
{
* vdst = * vsrc;
}
void DDRAW_LIUSHUIXIAN_TEXTURE::VERTEX4DTV1_Init( VERTEX4DTV1_PTR vdst, VERTEX4DTV1_PTR vsrc )
{
* vdst = * vsrc;
}
新增一个多变性结构2.0版本
//多边形结构
typedef struct POLY4DV2_TYP
{
int state; //状态信息
int attr; //多边形的物理属性,如材质等
int color; //多边形的颜色
int lit_color[3]; //用于存储经过光照处理后的顶点颜色,
//对于恒定着色,多边形颜色存储在第一个元素钟,
//对于GOURAUD颜色,顶点颜色分别存储在三个元素中
BITMAP_IMAGE_PTR texture; //指向纹理信息的指针,用于简单纹理映射
int material; //材质,-1表示无材质
VERTEX4DTV1_PTR vlist; //顶点列表
POINT2D_PTR tlist; //纹理坐标列表
int vert[3]; //顶点列表元素的索引
int text[3]; //指向纹理坐标列表的索引
float nlength; //法线长度
}POLY4DV2, * POLY4DV2_PTR;
类似地
//外部自包含结构
typedef struct POLYF4DV2_TYP
{
int state; //状态信息
int attr; //多边形的物理属性,如材质等
int color; //多边形的颜色
int lit_color[3]; //用于存储经过光照处理后的顶点颜色,
//对于恒定着色,多边形颜色存储在第一个元素钟,
//对于GOURAUD颜色,顶点颜色分别存储在三个元素中
BITMAP_IMAGE_PTR texture; //指向纹理信息的指针,用于简单纹理映射
int material; //材质,-1表示无材质
float nlength; //法线长度
VECTOR4D normal; //多边形法线
float avg_z; //平均Z值,用于简单排序
VERTEX4DTV1 vlist[3]; //顶点列表
VERTEX4DTV1 tvlist[3]; //变换后的顶点
POLYF4DV2_TYP * next; //指向列表中下一个多边形的指针
POLYF4DV2_TYP * prev; //指向列表中前一个多边形的指针
}POLYF4DV2, * POLYF4DV2_PTR;
//物体结构
typedef struct OBJECT4DV2_TYP
{
int id; //物体的数值ID
char name[64]; //物体的字符串名称
int state; //物体状态信息
int attr; //物体的物理属性,如材质等
int material; //材质,-1表示无材质
float * avg_radius; //物体的平均半径,用于碰撞检测,包含OBJECT4DV2_MAX_FRAMES个元素
float * max_radius; //物体的最大半径,包含OBJECT4DV2_MAX_FRAMES个元素
POINT4D world_pos; //物体在世界坐标系中的位置
VECTOR4D dir; //物体加载时在局部坐标系下的旋转角度,
VECTOR4D ux, uy, uz; //记录物体变换后的朝向
int num_vertices; //每帧物体包含的顶点数
int num_frames; //帧数
int total_vertices; //全部顶点
int curr_frame; //当前帧
VERTEX4DTV1_PTR vlist_local; //存储顶点局部坐标的数组
VERTEX4DTV1_PTR vlist_trans; //存储顶点交换后坐标的数组
//指向顶点列表的开头
VERTEX4DTV1_PTR head_vlist_local;
VERTEX4DTV1_PTR head_vlist_trans;
//纹理坐标列表
POINT2D_PTR tlist; //3*最大多边形
BITMAP_IMAGE_PTR texture; //指向纹理信息的指针,用于简单纹理映射
int num_polys; //物体的多边形数
POLY4DV2_PTR plist; //存储多边形数组
int ivar1, ivar2;
float fvar1, fvar2;
}OBJECT4DV2, * OBJECT4DV2_PTR;
还有个结构体的设定帧数,不在结构体内进行,
//指定当前帧
int DDRAW_LIUSHUIXIAN_TEXTURE::Set_OBJECT4DV2_Frame( OBJECT4DV2_PTR obj, int frame )
{
//检查物体是否有效
if ( ! obj )
{
return ( 0 );
}
//检查物体是否多帧
if ( ! ( obj->attr & OBJECT4DV2_ATTR_MULTI_FRAME))
{
return ( 0 );
}
//物体有效且多帧的,将指针指向当前帧数据
//检查frame是否越界
if ( frame < 0 )
{
frame = 0;
}
else
if ( frame >= obj->num_frames )
{
frame = obj->num_frames - 1;
}
//设置当前帧
obj->curr_frame = frame;
//让指针指向顶点列表中相应的帧
obj->vlist_local = & ( obj->head_vlist_local[frame * obj->num_vertices]);
obj->vlist_trans = & ( obj->head_vlist_trans[frame * obj->num_vertices]);
}
下面列出了一些函数,
要删除物体,
int DDRAW_LIUSHUIXIAN_TEXTURE::Destroy_OBJECT4DV2( OBJECT4DV2_PTR obj )
{
if ( obj->head_vlist_local)
{
free( obj->head_vlist_local );
}
if ( obj->head_vlist_trans)
{
free( obj->head_vlist_trans );
}
if ( obj->tlist)
{
free( obj->tlist );
}
if ( obj->plist)
{
free( obj->plist );
}
if ( obj->avg_radius)
{
free( obj->avg_radius );
}
if ( obj->max_radius)
{
free( obj->max_radius );
}
memset( ( void * ) obj, 0, sizeof( OBJECT4DV2) );
return ( 1 );
}
初始化OBJECT4DV2,新版本
int DDRAW_LIUSHUIXIAN_TEXTURE::Init_OBJECT4DV2( OBJECT4DV2_PTR obj, int num_vertices, int num_polys, int num_frames, int destroy )
{
if ( destroy )
{
Destroy_OBJECT4DV2(obj);
}
obj->vlist_local = ( VERTEX4DTV1_PTR ) malloc( sizeof( VERTEX4DTV1) * num_vertices * num_frames );
memset( ( void * ) obj->vlist_local, 0, sizeof( VERTEX4DTV1 ) * num_vertices * num_frames );
obj->vlist_trans = ( VERTEX4DTV1_PTR ) malloc( sizeof( VERTEX4DTV1) * num_vertices * num_frames );
memset( ( void * ) obj->vlist_trans, 0, sizeof( VERTEX4DTV1 ) * num_vertices * num_frames );
//纹理坐标数总是多边形数*3
obj->tlist = ( POINT2D_PTR) malloc( sizeof( POINT2D) * num_polys * 3 );
memset( ( void * ) obj->tlist, 0, sizeof( POINT2D) * num_polys * 3 );
obj->avg_radius = ( float * ) malloc( sizeof( float) * num_frames );
memset( ( void * ) obj->avg_radius, 0, sizeof( float) * num_frames );
obj->max_radius = ( float * ) malloc( sizeof( float) * num_frames );
memset( ( void * ) obj->max_radius, 0, sizeof( float) * num_frames );
//为多边形列表分配内存
obj->plist = ( POLY4DV2_PTR )malloc( sizeof( POLY4DV2 ) * num_polys );
memset( ( void * ) obj->plist, 0, sizeof( POLY4DV2 ) * num_polys );
//设置指针
obj->head_vlist_local = obj->vlist_local;
obj->head_vlist_trans = obj->vlist_trans;
//设置一些内部变量
obj->num_frames = num_frames;
obj->num_polys = num_polys;
obj->num_vertices = num_vertices;
obj->total_vertices = num_vertices * num_frames;
return ( 1 );
}
int DDRAW_LIUSHUIXIAN_TEXTURE::Compute_OBJECT4DV2_Poly_Normals( ddraw_math math, OBJECT4DV2_PTR obj )
{
if ( ! obj )
{
return 0;
}
//处理物体的每个多边形
for( int poly = 0; poly < obj->num_polys; poly ++ )
{
//获取多边形
POLY4DV2_PTR curr_poly = & obj->plist[poly];
//获取顶点列表中的顶点索引
int vindex_0 = curr_poly->vert[0];
int vindex_1 = curr_poly->vert[1];
int vindex_2 = curr_poly->vert[2];
//计算多边形的面法线,
//顶点是按照顺时针方向排列的,u=p0->p1,v=p0->p2,n=UXV;
VECTOR4D u, v, n;
//计算u和v
math.VECTOR4D_Build( & obj->vlist_local[vindex_0].v, & obj->vlist_local[vindex_1].v, & u );
math.VECTOR4D_Build( & obj->vlist_local[vindex_0].v, & obj->vlist_local[vindex_2].v, & v );
//计算叉积
math.VECTOR4D_CROSS( & u, &v, &n );
obj->plist[poly].nlength = math.VECTOR4D_length( & n);
}
return 1;
}
下面,进行GOURAUD光照处理的顶点法线,这个问题也困扰我很久了,就是由多个多边形和多个顶点组成的模型,如何求每个顶点的法线,其实很简单,就是根据各个多边形的面积加权求平均。每次对模型变换时,必须对顶点法线页进行变换
int DDRAW_LIUSHUIXIAN_TEXTURE::Compute_OBJECT4DV2_Vertex_Normals( ddraw_math math, OBJECT4DV2_PTR obj )
{
if ( ! obj )
{
return 0;
}
int polys_touch_vertex[OBJECT4DV2_MAX_VERTICES];
memset( ( void *) polys_touch_vertex, 0, sizeof( int ) * OBJECT4DV2_MAX_VERTICES );
//处理物体的每个多边形
for( int poly = 0; poly < obj->num_polys; poly ++ )
{
//获取多边形
POLY4DV2_PTR curr_poly = & obj->plist[poly];
//检查多变性是否需要顶点法线
if ( curr_poly.attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD )
{ //获取顶点列表中的顶点索引
int vindex_0 = curr_poly->vert[0];
int vindex_1 = curr_poly->vert[1];
int vindex_2 = curr_poly->vert[2];
//计算多边形的面法线,
//顶点是按照顺时针方向排列的,u=p0->p1,v=p0->p2,n=UXV;
VECTOR4D u, v, n;
//计算u和v
math.VECTOR4D_Build( & obj->vlist_local[vindex_0].v, & obj->vlist_local[vindex_1].v, & u );
math.VECTOR4D_Build( & obj->vlist_local[vindex_0].v, & obj->vlist_local[vindex_2].v, & v );
//计算叉积
math.VECTOR4D_CROSS( & u, &v, &n );
//将共用顶点的多边形数+1
polys_touch_vertex[vindex_0]++;
polys_touch_vertex[vindex_1]++;
polys_touch_vertex[vindex_2]++;
math.VECTOR4D_ADD( & obj->vlist_local[vindex_0].n, & n, & obj->vlist_local[vindex_0].n );
math.VECTOR4D_ADD( & obj->vlist_local[vindex_1].n, & n, & obj->vlist_local[vindex_1].n );
math.VECTOR4D_ADD( & obj->vlist_local[vindex_2].n, & n, & obj->vlist_local[vindex_2].n );
}
}
for ( int vertex = 0; vertex < obj->num_vertices; vertex ++ )
{
if ( polys_touch_vertex[vertex] >= 1)
{
obj->vlist_local[vertex].nx /= polys_touch_vertex[vertex];
obj->vlist_local[vertex].ny /= polys_touch_vertex[vertex];
obj->vlist_local[vertex].nz /= polys_touch_vertex[vertex];
//将法线归一化
math.VECTOR4D_Normalize( & obj->vlist_local[vertex].n );
}
}
return 1;
}
然后,在此基础上,是加载PLG/PLX函数的新版本。
int DDRAW_LIUSHUIXIAN_TEXTURE::Load_OBJECT4DV2_PLG( ddraw_math math, OBJECT4DV2_PTR obj, char * filename, VECTOR4D_PTR scale, VECTOR4D_PTR pos, VECTOR4D_PTR rot, int vertex_flags )
{
FILE * fp; //文件指针
char buffer[256]; //缓冲区
char * token_string; //指向要分析的物体数据文本的指针
//先找到物体描述符
//第一步清空和初始化OBJ
memset( obj, 0, sizeof(OBJECT4DV2) );
//将物体状态设置为可见和活动的
obj->state = OBJECT4DV2_STATE_ACTIVE | OBJECT4DV2_STATE_VISIBLE;
//设置物体的位置
obj->world_pos.x = pos->x;
obj->world_pos.y = pos->y;
obj->world_pos.z = pos->z;
obj->world_pos.w = pos->w;
//设置物体包含的帧数
obj->num_frames = 1;
obj->curr_frame = 0;
obj->attr = OBJECT4DV2_ATTR_SINGLE_FRAME;
//第步,读取文件
fp = fopen( filename, "r" );
//第步,读取物体描述符
token_string = Get_Line_PLG(buffer, 255, fp );
//分析物体描述符
sscanf(token_string, "%s %d %d", obj->name, & obj->num_vertices, & obj->num_polys );
//为存储顶点数和多边形数的变量分配内存
Init_OBJECT4DV2( obj, obj->num_vertices, obj->num_polys, obj->num_frames );
//第步:加载顶点列表
for ( int vertex = 0; vertex < obj->num_vertices; vertex++ )
{
token_string = Get_Line_PLG( buffer, 255, fp );
//分析顶点
sscanf( token_string, "%f %f %f", & obj->vlist_local[vertex].x, & obj->vlist_local[vertex].y, & obj->vlist_local[vertex].z );
obj->vlist_local[vertex].w = 1;
//缩放顶点坐标
obj->vlist_local[vertex].x *= scale->x;
obj->vlist_local[vertex].y *= scale->y;
obj->vlist_local[vertex].z *= scale->z;
//设置顶点的D点
SET_BIT( obj->vlist_local[vertex].attr, VERTEX4DTV1_ATTR_POINT );
}
//计算平均半径和最大半径
Compute_OBJECT4DV2_RADIUS(obj);
int poly_surface_desc = 0; //PLG/PLX多边形描述符
int poly_num_verts = 0; //当前多边形得顶点数(这里设定为)
char tmp_string[8]; //存储多边形描述符的字符串
//第步:加载多边形列表
for( int poly = 0; poly < obj->num_polys; poly++ )
{
token_string = Get_Line_PLG( buffer, 255,fp );
//假定所有模型都是由三角形组成,则每个多边形都有个顶点,将面描述符、顶点数和顶点列表存储到变量中
sscanf( token_string, "%s %d %d %d %d", tmp_string, & poly_num_verts, & obj->plist[poly].vert[0],
& obj->plist[poly].vert[1], & obj->plist[poly].vert[2]);
//对于x开头的进制进行检测
if ( tmp_string[0] == '0' && toupper( tmp_string[1]) == 'X' )
{
sscanf( tmp_string, "%x", & poly_surface_desc );
}
else
poly_surface_desc = atoi( tmp_string );
//让多边形顶点列表指向物体的顶点列表
obj->plist[poly].vlist = obj->vlist_local;
//存储顶点列表和多边形顶点索引值后,分析多边形描述符,并据此相应地设置多边形
//提取多边形描述符中的每个位字段
if( poly_surface_desc & PLX_2SIDED_FLAG )
{
SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_2SIDED );
}
//设置颜色模式
//如果是位
if ( poly_surface_desc & PLX_COLOR_MODE_RGB_FLAG)
{
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_RGB16 );
//提取RGB值
int red = ( ( poly_surface_desc & 0x0f00) >> 8 );
int greeen = ( ( poly_surface_desc & 0x00f0) >> 4 );
int blue = ( poly_surface_desc & 0x000f );
obj->plist[poly].color = _RGB16BIT565( red * 16, greeen * 16, blue * 16 );
}
else
{
//使用位颜色索引
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_8BITCOLOR );
//提取最后的位即可得到颜色索引
obj->plist[poly].color = ( poly_surface_desc & 0x00ff );
}
//处理着色模式
int shade_mode = ( poly_surface_desc & PLX_SHADE_MODE_MASK );
//设置多边形的着色模式
switch ( shade_mode )
{
case PLX_SHADE_MODE_PURE_FLAG:
{
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_SHADE_MODE_PURE );
}
break;
case PLX_SHADE_MODE_FLAT_FLAG:
{
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_SHADE_MODE_FLAT );
}
break;
case PLX_SHADE_MODE_GOURAUD_FLAG:
{
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_SHADE_MODE_GOURAUD );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[0]].attr, VERTEX4DTV1_ATTR_NORMAL );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[1]].attr, VERTEX4DTV1_ATTR_NORMAL );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[2]].attr, VERTEX4DTV1_ATTR_NORMAL );
}
break;
case PLX_SHADE_MODE_PHONG_FLAG:
{
SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_PHONG );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[0]].attr, VERTEX4DTV1_ATTR_NORMAL );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[1]].attr, VERTEX4DTV1_ATTR_NORMAL );
SET_BIT( obj->vlist_local[obj->plist[poly].vert[2]].attr, VERTEX4DTV1_ATTR_NORMAL );
}
break;
default:
break;
}
//设置材质模式
SET_BIT( obj->plist[poly].attr, POLY4DV2_ATTR_DISABLE_MATERIAL );
//最后将多边形设置为活动状态
obj->plist[poly].state = POLY4DV2_STATE_ACTIVE;
//将多边形的顶点列表指针指向物体的顶点列表
obj->plist[poly].vlist = obj->vlist_local;
obj->plist[poly].tlist = obj->tlist;
}
//计算多边形法线的长度
Compute_OBJECT4DV2_Poly_Normals( math, obj );
//计算使用GOURAUD着色的多边形,计算其顶点法线
Compute_OBJECT4DV2_Vertex_Normals( math, obj );
//关闭文件
fclose( fp );
return ( 1 );
}
先加入光栅化逻辑
#define RASTERIZER_ACCURATE 0
#define RASTERIZER_FAST 1
#define RASTERIZER_FASTEST 2
#define RASTERIZER_MODE RASTERIZER_ACCURATE
新的三角形渲染函数加入浮点数坐标
//绘制平底三角形
void ddraw_math::Draw_Bottom_Tri2_16( float x1, float y1, float x2, float y2, float x3, float y3, float color, UCHAR * _dest_buffer, int mempitch )
{
float dx_right, dx_left, xs, xe,height;
float temp_x, temp_y, right, left;
int iy1, iy3, loop_y;
//将目标缓存转换为USHORT类型
USHORT * dest_buffer = ( USHORT * )_dest_buffer;
//下一次扫描线的目标地址
USHORT * dest_addr = NULL;
mempitch = ( mempitch >> 1 );
if ( x3 < x2 )
{
SWAP( x2, x3, temp_x );
}
height = y3- y1;
dx_left = ( x2 - x1 ) / height;
dx_right = ( x3 - x1 ) / height;
xs = x1;
xe = x1;
#if( RASTERIZER_MODE == RASTERIZER_ACCURATE )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
iy1 = y1;
}
else
{
iy1 = ceil( y1 );
xs = xs + dx_left * ( -y1 + iy1 );
xe = xe + dx_right * ( -y1 + iy1 );
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
iy3 = y3 - y1;
}
else
{
iy3 = ceil( y3 ) - 1;
}
#endif
#if( ( RASTERIZER_MODE == RASTERIZER_FAST ) || ( RASTERIZER_MODE == RASTERIZER_FASTEST ) )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
}
iy1 = ceil( y1 );
iy3 = ceil( y3 ) - 1;
#endif
dest_addr = dest_buffer + iy1 * mempitch;
if ( x1 >= m_min_clip_x && x1 <= m_max_clip_x && x2 >= m_min_clip_x && x2 <= m_max_clip_x && x3 >= m_min_clip_x && x3 <= m_max_clip_x )
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
Mem_Set_WORD( dest_addr + ( unsigned int ) ( xs ), color, ( unsigned int ) ( ( int)xe -(int) xs + 1 ) );
xs += dx_left;
xe += dx_right;
}
}
else
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
left = xs;
right = xe;
xs += dx_left;
xe += dx_right;
if ( left < m_min_clip_x )
{
left = m_min_clip_x;
if ( right < m_min_clip_x )
{
return;
}
}
if ( right > m_max_clip_x )
{
right = m_max_clip_x;
if ( left > m_max_clip_x )
{
return;
}
}
Mem_Set_WORD( dest_addr + ( unsigned int ) left, color, ( unsigned int ) ( ( int)right -(int) left + 1 ) );
}
}
}
void ddraw_math::Draw_Bottom_Tri2( float x1, float y1, float x2, float y2, float x3, float y3, int color, UCHAR * _dest_buffer, int mempitch )
{
float dx_right, dx_left, xs, xe,height;
float temp_x, temp_y, right, left;
int iy1, iy3, loop_y;
//下一次扫描线的目标地址
UCHAR * dest_addr = NULL;
if ( x3 < x2 )
{
SWAP( x2, x3, temp_x );
}
height = y3- y1;
dx_left = ( x2 - x1 ) / height;
dx_right = ( x3 - x1 ) / height;
xs = x1;
xe = x1;
#if( RASTERIZER_MODE == RASTERIZER_ACCURATE )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
iy1 = y1;
}
else
{
iy1 = ceil( y1 );
xs = xs + dx_left * ( -y1 + iy1 );
xe = xe + dx_right * ( -y1 + iy1 );
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
iy3 = y3 - 1;
}
else
{
iy3 = ceil( y3 ) - 1;
}
#endif
#if( ( RASTERIZER_MODE == RASTERIZER_FAST ) || ( RASTERIZER_MODE == RASTERIZER_FASTEST ) )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
}
iy1 = ceil( y1 );
iy3 = ceil( y3 ) - 1;
#endif
dest_addr = _dest_buffer + iy1 * mempitch;
if ( x1 >= m_min_clip_x && x1 <= m_max_clip_x && x2 >= m_min_clip_x && x2 <= m_max_clip_x && x3 >= m_min_clip_x && x3 <= m_max_clip_x )
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
memset( ( UCHAR * )dest_addr + ( unsigned int ) ( xs ), color, ( unsigned int ) ( ( int)xe -(int) xs + 1 ) );
xs += dx_left;
xe += dx_right;
}
}
else
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
left = xs;
right = xe;
xs += dx_left;
xe += dx_right;
if ( left < m_min_clip_x )
{
left = m_min_clip_x;
if ( right < m_min_clip_x )
{
return;
}
}
if ( right > m_max_clip_x )
{
right = m_max_clip_x;
if ( left > m_max_clip_x )
{
return;
}
}
memset( ( UCHAR *) dest_addr + ( unsigned int ) left, color, ( unsigned int ) ( ( int)right -(int) left + 1 ) );
}
}
}
没有区别啊。
对于平顶三角形,
void ddraw_math::Draw_Top_Tri2( float x1, float y1, float x2, float y2, float x3, float y3, int color, UCHAR * _dest_buffer, int mempitch )
{
float dx_right, dx_left, xs, xe,height;
float temp_x, temp_y, right, left;
int iy1, iy3, loop_y;
UCHAR * dest_addr = NULL;
if ( x2 < x1 )
{
SWAP(x1, x2, temp_x );
}
height = y3- y1;
dx_left = ( x3 - x1 ) / height;
dx_right = ( x3 - x2 ) / height;
xs = x1;
xe = x2;
#if ( RASTERIZER_MODE == RASTERIZER_ACCURATE )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
iy1 = y1;
}
else
{
iy1 = ceil( y1 );
xs = xs + dx_left * ( -y1 + iy1 );
xe = xe + dx_right * ( -y1 + iy1 );
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
iy3 = y3 - 1;
}
else
{
iy3 = ceil( y3 ) - 1;
}
#endif
#if ( ( RASTERIZER_MODE == RASTERIZER_FAST ) || ( RASTERIZER_MODE == RASTERIZER_FASTEST ) )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
}
else
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
}
iy1 = ceil( y1 );
iy3 = ceil( y3 ) - 1;
#endif
dest_addr = _dest_buffer + iy1 * mempitch;
if ( x1 >= m_min_clip_x && x1 <= m_max_clip_x && x2 >= m_min_clip_x && x2 <= m_max_clip_x && x3 >= m_min_clip_x && x3 <= m_max_clip_x )
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
memset( ( UCHAR *) dest_addr + ( unsigned int ) xs, color, ( unsigned int ) ( (int) xe - ( int ) xs + 1 ) );
xs += dx_left;
xe += dx_right;
}
}
else
{
for( temp_y = iy1; temp_y<= iy3; temp_y++, dest_addr += mempitch )
{
left = xs;
right = xe;
xs += dx_left;
xe += dx_right;
if ( left < m_min_clip_x )
{
left = m_min_clip_x;
if ( right < m_min_clip_x )
{
continue;
}
}
if ( right > m_max_clip_x )
{
right = m_max_clip_x;
if ( left > m_max_clip_x )
{
continue;
}
}
memset( ( UCHAR * ) dest_addr + ( unsigned int ) left, color, ( unsigned int ) ( ( int ) right - (int )left + 1 ));
}
}
}
void ddraw_math::Draw_Top_Tri2_16( float x1, float y1, float x2, float y2, float x3, float y3, int color, UCHAR * _dest_buffer, int mempitch )
{
float dx_right, dx_left, xs, xe,height;
float temp_x, temp_y, right, left;
int iy1, iy3, loop_y;
USHORT * dest_buffer = ( USHORT * )_dest_buffer;
USHORT * dest_addr = NULL;
mempitch = ( mempitch >> 1 );
if ( x2 < x1 )
{
SWAP(x1, x2, temp_x );
}
height = y3- y1;
dx_left = ( x3 - x1 ) / height;
dx_right = ( x3 - x2 ) / height;
xs = x1;
xe = x2;
#if ( RASTERIZER_MODE == RASTERIZER_ACCURATE )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
iy1 = y1;
}
else
{
iy1 = ceil( y1 );
xs = xs + dx_left * ( -y1 + iy1 );
xe = xe + dx_right * ( -y1 + iy1 );
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
iy3 = y3 - 1;
}
else
{
iy3 = ceil( y3 ) - 1;
}
#endif
#if ( ( RASTERIZER_MODE == RASTERIZER_FAST ) || ( RASTERIZER_MODE == RASTERIZER_FASTEST ) )
if ( y1 < m_min_clip_y )
{
xs = xs + dx_left * ( -y1 + m_min_clip_y );
xe = xe + dx_right * ( -y1 + m_min_clip_y );
y1 = m_min_clip_y;
}
if ( y3 > m_max_clip_y )
{
y3 = m_max_clip_y;
}
iy1 = ceil( y1 );
iy3 = ceil( y3 ) - 1;
#endif
dest_addr = dest_buffer + iy1 * mempitch;
if ( x1 >= m_min_clip_x && x1 <= m_max_clip_x && x2 >= m_min_clip_x && x2 <= m_max_clip_x && x3 >= m_min_clip_x && x3 <= m_max_clip_x )
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
Mem_Set_WORD( dest_addr + ( unsigned int ) ( xs ), color, ( unsigned int ) ( (int) xe - ( int ) xs + 1 ) );
xs += dx_left;
xe += dx_right;
}
}
else
{
for( loop_y = iy1; loop_y<= iy3; loop_y++, dest_addr += mempitch )
{
left = xs;
right = xe;
xs += dx_left;
xe += dx_right;
if ( left < m_min_clip_x )
{
left = m_min_clip_x;
if ( right < m_min_clip_x )
{
continue;
}
}
if ( right > m_max_clip_x )
{
right = m_max_clip_x;
if ( left > m_max_clip_x )
{
continue;
}
}
Mem_Set_WORD( dest_addr + ( unsigned int ) ( left ), color, ( unsigned int ) ( ( int ) right - (int )left + 1 ));
}
}
}
下面,普通三角形,切割为平底和平顶
void ddraw_math::Draw_Triangle_2D2( float x1, float y1, float x2, float y2, float x3, float y3, int color, UCHAR * dest_buffer, int mempitch )
{
float temp_x, temp_y, new_x;
if( ( FCMP( x1, x2) && FCMP(x2, x3)) || ( FCMP( y1, y2) && FCMP( y2, y3)) )
return;
if ( y2 < y1 )
{
SWAP( x1, x2, temp_x );
SWAP( y1, y2, temp_y );
}
if ( y3 < y1 )
{
SWAP( x1, x3, temp_x );
SWAP( y1, y3, temp_y );
}
if ( y3 < y2 )
{
SWAP( x2, x3, temp_x );
SWAP( y2, y3, temp_y );
}
if ( y3 < m_min_clip_y || y1 > m_max_clip_y ||
( x1 < m_min_clip_x && x2 < m_min_clip_x && x3 < m_min_clip_x) ||
( x1 > m_max_clip_x && x2 > m_max_clip_x && x3 > m_max_clip_x )
)
{
return;
}
if ( FCMP( y1, y2 ) )
{
Draw_Top_Tri2( x1, y1, x2, y2, x3, y3, color, dest_buffer, mempitch );
}
else if( FCMP( y2, y3 ))
{
Draw_Bottom_Tri2( x1, y1, x2, y2, x3, y3, color, dest_buffer, mempitch );
}
else
{
new_x = x1 + ( y2 - y1) * ( x3 - x1 ) / ( y3 - y1);
Draw_Bottom_Tri2( x1, y1, new_x, y2, x2, y2, color, dest_buffer, mempitch );
Draw_Top_Tri2( x2, y2, new_x, y2, x3, y3, color, dest_buffer, mempitch );
}
}
16位版本
void ddraw_math::Draw_Triangle_2D2_16( float x1, float y1, float x2, float y2, float x3, float y3, int color, UCHAR * dest_buffer, int mempitch )
{
float temp_x, temp_y, new_x;
if( ( FCMP( x1, x2) && FCMP(x2, x3)) || ( FCMP( y1, y2) && FCMP( y2, y3)) )
return;
if ( y2 < y1 )
{
SWAP( x1, x2, temp_x );
SWAP( y1, y2, temp_y );
}
if ( y3 < y1 )
{
SWAP( x1, x3, temp_x );
SWAP( y1, y3, temp_y );
}
if ( y3 < y2 )
{
SWAP( x2, x3, temp_x );
SWAP( y2, y3, temp_y );
}
if ( y3 < m_min_clip_y || y1 > m_max_clip_y ||
( x1 < m_min_clip_x && x2 < m_min_clip_x && x3 < m_min_clip_x) ||
( x1 > m_max_clip_x && x2 > m_max_clip_x && x3 > m_max_clip_x )
)
{
return;
}
if ( FCMP( y1, y2 ) )
{
Draw_Top_Tri2_16( x1, y1, x2, y2, x3, y3, color, dest_buffer, mempitch );
}
else if( FCMP( y2, y3 ))
{
Draw_Bottom_Tri2_16( x1, y1, x2, y2, x3, y3, color, dest_buffer, mempitch );
}
else
{
new_x = x1 + ( y2 - y1) * ( x3 - x1 ) / ( y3 - y1);
Draw_Bottom_Tri2_16( x1, y1, new_x, y2, x2, y2, color, dest_buffer, mempitch );
Draw_Top_Tri2_16( x2, y2, new_x, y2, x3, y3, color, dest_buffer, mempitch );
}
}
2014年4月4日星期五(9-1,GOURAUD着色处理)
这章的前提引擎,除了3DSMAX和COB模型的载入代码外,都写完了,正式进入GOURAUD着色,
就是三角形每个顶点法线(而不是多边形法线)执行光照计算,,并将RGB颜色存储在顶点中。然后用线性插值计算三角形中各点颜色,
在扫描每行时,是按照梯度逐像素插值。
DEMO9-1没考虑光照因素,。
思路很简单,但是代码很长,
void ddraw_math::Draw_Gouraud_Triangle16( POLYF4DV2_PTR face, UCHAR * _dest_buffer, int mem_pitch )
{
int v0 = 0, v1 = 1, v2 = 2, temp = 0, tri_type = TRI_TYPE_NONE, irestart = INTERP_LHS;
int dx, dy, dyl, dyr, //存储差值
u, v, w, //RGB值
du, dv, dw,
xi, yi, //当前的x和y坐标
ui,vi,wi, //当前的RGB值
index_x, index_y, //循环变量
x, y, //存储一般性X和Y坐标
xstart, xend,ystart, yrestart, yend, xl,
dxdyl, xr, dxdyr, dudyl, ul, dvdyl, vl, dwdyl,
wl, dudyr, ur, dvdyr, vr, dwdyr, wr;
int x0, y0, tu0, tv0, tw0, //顶点的初始颜色
x1, y1, tu1, tv1, tw1,
x2, y2, tu2, tv2, tw2;
int r_base0, g_base0, b_base0, //顶点的初始颜色
r_base1, g_base1, b_base1,
r_base2, g_base2, b_base2;
USHORT * screen_ptr = NULL,
* screen_line = NULL,
* tempmap = NULL,
* dest_buffer = (USHORT * )_dest_buffer;;
//将内存跨距的单位调整为字
mem_pitch >>= 1;
//判断三角形是否在屏幕内
if ( ( ( face->tvlist[0].y < m_min_clip_y) &&
( face->tvlist[1].y < m_min_clip_y) &&
( face->tvlist[2].y < m_min_clip_y) ) ||
( ( face->tvlist[0].y > m_max_clip_y) &&
( face->tvlist[1].y > m_max_clip_y) &&
( face->tvlist[2].y > m_max_clip_y) ) ||
( ( face->tvlist[0].x < m_min_clip_x) &&
( face->tvlist[1].x < m_min_clip_x) &&
( face->tvlist[2].x < m_min_clip_x) ) ||
( ( face->tvlist[0].x > m_max_clip_x) &&
( face->tvlist[1].x > m_max_clip_x) &&
( face->tvlist[2].x > m_max_clip_x) ) )
{
return;
}
//判断三角形是否退化为直线
if ( ( ( face->tvlist[0].x == face->tvlist[1].x ) &&
( face->tvlist[1].x == face->tvlist[2].x ) ) ||
( ( face->tvlist[0].y == face->tvlist[1].y ) &&
( face->tvlist[1].y == face->tvlist[2].y ) ) )
{
return;
}
//对顶点进行排序
if ( face->tvlist[v1].y < face->tvlist[v0].y )
{
SWAP( v0, v1, temp );
}
if ( face->tvlist[v2].y < face->tvlist[v0].y )
{
SWAP( v0, v2, temp );
}
if ( face->tvlist[v2].y < face->tvlist[v1].y )
{
SWAP( v1, v2, temp );
}
//判断三角形是否平顶
if ( face->tvlist[v0].y == face->tvlist[v1].y )
{
//设置三角形类型
tri_type = TRI_TYPE_FLAT_TOP;
//将顶点从左到右的顺序排列
if ( face->tvlist[v1].x < face->tvlist[v0].x )
{
SWAP( v0, v1, temp );
}
}
else
//判断三角形是否平底
if ( face->tvlist[v1].y == face->tvlist[v2].y )
{
//设置三角形类型
tri_type = TRI_TYPE_FLAT_BOTTOM;
//将顶点从左到右的顺序排列
if ( face->tvlist[v2].x < face->tvlist[v1].x )
{
SWAP( v1, v2, temp );
}
}
else
//肯定是常规三角形
{
tri_type = TRI_TYPE_GENERAL;
}
_RGB565FROM16BIT( face->lit_color[v0], & r_base0, & g_base0, & b_base0 );
_RGB565FROM16BIT( face->lit_color[v1], & r_base1, & g_base1, & b_base1 );
_RGB565FROM16BIT( face->lit_color[v2], & r_base2, & g_base2, & b_base2 );
//扩展到位
r_base0 <<= 3;
g_base0 <<= 3;
b_base0 <<= 3;
r_base1 <<= 3;
g_base1 <<= 3;
b_base1 <<= 3;
r_base2 <<= 3;
g_base2 <<= 3;
b_base2 <<= 3;
//提取各个顶点的坐标值和RGB值
x0 = ( int ) ( face->tvlist[v0].x + 0.5 );
y0 = ( int ) ( face->tvlist[v0].y + 0.5 );
tu0 = r_base0;
tv0 = g_base0;
tw0 = b_base0;
x1 = ( int ) ( face->tvlist[v1].x + 0.5 );
y1 = ( int ) ( face->tvlist[v1].y + 0.5 );
tu1 = r_base1;
tv1 = g_base1;
tw1 = b_base1;
x2 = ( int ) ( face->tvlist[v2].x + 0.5 );
y2 = ( int ) ( face->tvlist[v2].y + 0.5 );
tu2 = r_base2;
tv2 = g_base2;
tw2 = b_base2;
//设置斜率转折点
yrestart = y1;
//判断三角形类型
if ( tri_type & TRI_TYPE_FLAT_MASK )
{
if ( tri_type & TRI_TYPE_FLAT_TOP )
{
//计算各种差值
dy = y2 - y0;
dxdyl = ( ( x2 - x0 ) << FIXP16_SHIFT ) / dy;
dudyl = ( ( tu2 - tu0 ) << FIXP16_SHIFT ) / dy;
dvdyl = ( ( tv2 - tv0 ) << FIXP16_SHIFT ) / dy;
dwdyl = ( ( tw2 - tw0 ) << FIXP16_SHIFT ) / dy;
dxdyr = ( ( x2 - x1 ) << FIXP16_SHIFT ) / dy;
dudyr = ( ( tu2 - tu1 ) << FIXP16_SHIFT ) / dy;
dvdyr = ( ( tv2 - tv1 ) << FIXP16_SHIFT ) / dy;
dwdyr = ( ( tw2 - tw1 ) << FIXP16_SHIFT ) / dy;
//垂直裁剪测试
if ( y0 < m_min_clip_y )
{
//垂直计算Y坐标差值
dy = ( m_min_clip_y - y0 );
//计算第一条扫描线起点的各种值
xl = dxdyl * dy + ( x0 << FIXP16_SHIFT );
ul = dudyl * dy + ( tu0 << FIXP16_SHIFT );
vl = dvdyl * dy + ( tv0 << FIXP16_SHIFT );
wl = dwdyl * dy + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线终点的各种值
xr = dxdyr * dy + ( x1 << FIXP16_SHIFT );
ur = dudyr * dy + ( tu1 << FIXP16_SHIFT );
vr = dvdyr * dy + ( tv1 << FIXP16_SHIFT );
wr = dwdyr * dy + ( tw1 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = m_min_clip_y;
}
else
{
//不用裁剪
//设置第一条扫描线起点和终点的各种值
xl = ( x0 << FIXP16_SHIFT );
ul = ( tu0 << FIXP16_SHIFT );
vl = ( tv0 << FIXP16_SHIFT );
wl = ( tw0 << FIXP16_SHIFT );
xr = ( x1 << FIXP16_SHIFT );
ur = ( tu1 << FIXP16_SHIFT );
vr = ( tv1 << FIXP16_SHIFT );
wr = ( tw1 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = y0;
}
}
else //肯定是平底三角形
{
//计算各种差值
dy = y1 - y0;
dxdyl = ( ( x1 - x0 ) << FIXP16_SHIFT ) / dy;
dudyl = ( ( tu1 - tu0 ) << FIXP16_SHIFT ) / dy;
dvdyl = ( ( tv1 - tv0 ) << FIXP16_SHIFT ) / dy;
dwdyl = ( ( tw1 - tw0 ) << FIXP16_SHIFT ) / dy;
dxdyr = ( ( x2 - x0 ) << FIXP16_SHIFT ) / dy;
dudyr = ( ( tu2 - tu0 ) << FIXP16_SHIFT ) / dy;
dvdyr = ( ( tv2 - tv0 ) << FIXP16_SHIFT ) / dy;
dwdyr = ( ( tw2 - tw0 ) << FIXP16_SHIFT ) / dy;
//垂直裁剪测试
if ( y0 < m_min_clip_y )
{
//垂直计算Y坐标差值
dy = ( m_min_clip_y - y0 );
//计算第一条扫描线起点的各种值
xl = dxdyl * dy + ( x0 << FIXP16_SHIFT );
ul = dudyl * dy + ( tu0 << FIXP16_SHIFT );
vl = dvdyl * dy + ( tv0 << FIXP16_SHIFT );
wl = dwdyl * dy + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线终点的各种值
xr = dxdyr * dy + ( x0 << FIXP16_SHIFT );
ur = dudyr * dy + ( tu0 << FIXP16_SHIFT );
vr = dvdyr * dy + ( tv0 << FIXP16_SHIFT );
wr = dwdyr * dy + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = m_min_clip_y;
}
else
{
//不用裁剪
//设置第一条扫描线起点和终点的各种值
xl = ( x0 << FIXP16_SHIFT );
ul = ( tu0 << FIXP16_SHIFT );
vl = ( tv0 << FIXP16_SHIFT );
wl = ( tw0 << FIXP16_SHIFT );
xr = ( x0 << FIXP16_SHIFT );
ur = ( tu0 << FIXP16_SHIFT );
vr = ( tv0 << FIXP16_SHIFT );
wr = ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = y0;
}
}
//总是检测三角形最下面的部分是否会被裁剪掉
if (( yend = y2 ) > m_max_clip_y )
{
yend = m_max_clip_y;
}
//水平裁剪测试
if ( ( x0 < m_min_clip_x ) || ( x0 > m_max_clip_x ) ||
( x1 < m_min_clip_x ) || ( x1 > m_max_clip_x ) ||
( x2 < m_min_clip_x ) || ( x2 > m_max_clip_x ) )
{
//裁剪版本
//让指screen_ptr指向第一条扫描线起点在缓存的位置
screen_ptr = dest_buffer + ( ystart * mem_pitch );
for ( yi = ystart; yi <= yend; yi++ )
{
//计算扫描线起点和终点的X坐标
xstart = ( ( xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
xend = ( ( xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
//计算扫描线起点和终点的坐标
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
wi = wl + FIXP16_ROUND_UP;
//计算扫描线上的RGB梯度
if ( ( dx = ( xend - xstart )) > 0 )
{
du = ( ur - ul ) / dx;
dv = ( vr - vl ) / dx;
dw = ( wr - wl ) / dx;
}
else
{
du = ( ur - ul );
dv = ( vr - vl );
dw = ( wr - wl );
}
//扫描线起点水平裁剪测试
if ( xstart < m_min_clip_x )
{
//计算起点移动距离
dx = m_min_clip_x - xstart;
//重新计算扫描线起点的RGB值
ui += dx * du;
vi += dx * dv;
wi += dx * dw;
//重新设置循环起始条件
xstart = m_min_clip_x;
}
//终点水平测试
if ( xend > m_max_clip_x )
{
xend = m_max_clip_x;
}
//绘制扫描线
for( xi = xstart; xi <= xend; xi ++ )
{
//绘制像素,假设格式为.6.5
screen_ptr[xi] = ( ( ui >> ( FIXP16_SHIFT + 3)) << 11 ) +
( ( vi >> ( FIXP16_SHIFT + 2)) << 5 ) +
( wi >> ( FIXP16_SHIFT + 3 ));
//计算下一个像素的RGB值
ui += du;
vi += dv;
wi += dw;
}
//计算下一条扫描线起点和终点的x坐标和RGB值
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
//让指针screen_ptr指向视频缓存的下一行
screen_ptr += mem_pitch;
}
}
//三角形没有被裁剪时的绘制代码
else
{
screen_ptr = dest_buffer + ( ystart * mem_pitch );
for ( yi = ystart; yi <= yend; yi++ )
{
//计算扫描线起点和终点的X坐标
xstart = ( ( xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
xend = ( ( xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
//计算扫描线起点和终点的坐标
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
wi = wl + FIXP16_ROUND_UP;
//计算扫描线上的RGB梯度
if ( ( dx = ( xend - xstart )) > 0 )
{
du = ( ur - ul ) / dx;
dv = ( vr - vl ) / dx;
dw = ( wr - wl ) / dx;
}
else
{
du = ( ur - ul );
dv = ( vr - vl );
dw = ( wr - wl );
}
//绘制扫描线
for( xi = xstart; xi <= xend; xi ++ )
{
//绘制像素,假设格式为.6.5
screen_ptr[xi] = ( ( ui >> ( FIXP16_SHIFT + 3)) << 11 ) +
( ( vi >> ( FIXP16_SHIFT + 2)) << 5 ) +
( wi >> ( FIXP16_SHIFT + 3 ));
//计算下一个像素的RGB值
ui += du;
vi += dv;
wi += dw;
}
//计算下一条扫描线起点和终点的x坐标和RGB值
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
//让指针screen_ptr指向视频缓存的下一行
screen_ptr += mem_pitch;
}
}
}
else
//绘制常规三角形
if ( tri_type == TRI_TYPE_GENERAL )
{
if (( yend = y2 ) > m_max_clip_y )
{
yend = m_max_clip_y;
}
if ( y1 < m_min_clip_y )
{
//垂直计算Y坐标差值
//左侧
dyl = ( y2 - y1 );
dxdyl = ( ( x2 - x1 ) << FIXP16_SHIFT ) / dyl;
dudyl = ( ( tu2 - tu1 ) << FIXP16_SHIFT ) / dyl;
dvdyl = ( ( tv2 - tv1 ) << FIXP16_SHIFT ) / dyl;
dwdyl = ( ( tw2 - tw1 ) << FIXP16_SHIFT ) / dyl;
//右侧
dyr = ( y2 - y0 );
dxdyr = ( ( x2 - x0 ) << FIXP16_SHIFT ) / dyr;
dudyr = ( ( tu2 - tu0 ) << FIXP16_SHIFT ) / dyr;
dvdyr = ( ( tv2 - tv0 ) << FIXP16_SHIFT ) / dyr;
dwdyr = ( ( tw2 - tw0 ) << FIXP16_SHIFT ) / dyr;
//垂直计算Y坐标差值
dyr = ( m_min_clip_y - y0 );
dyl = ( m_min_clip_y - y1 ) ;
//计算第一条扫描线起点的各种值
xl = dxdyl * dyl + ( xl << FIXP16_SHIFT );
ul = dudyl * dyl + ( tu1 << FIXP16_SHIFT );
vl = dvdyl * dyl + ( tv1 << FIXP16_SHIFT );
wl = dwdyl * dyl + ( tw1 << FIXP16_SHIFT );
//计算第一条扫描线终点的各种值
xr = dxdyr * dyr + ( x0 << FIXP16_SHIFT );
ur = dudyr * dyr + ( tu0 << FIXP16_SHIFT );
vr = dvdyr * dyr + ( tv0 << FIXP16_SHIFT );
wr = dwdyr * dyr + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = m_min_clip_y;
if ( dxdyr > dxdyl )
{
SWAP( dxdyl, dxdyr, temp );
SWAP( dudyl, dudyr, temp );
SWAP( dvdyl, dvdyr, temp );
SWAP( dwdyl, dwdyr, temp );
SWAP( xl, xr, temp );
SWAP( ul, ur, temp );
SWAP( vl, vr, temp );
SWAP( wl, wr, temp );
SWAP( x1, x2, temp );
SWAP( y1, y2, temp );
SWAP( tu1, tu2, temp );
SWAP( tv1, tv2, temp );
SWAP( tw1, tw2, temp );
irestart = INTERP_RHS;
}
}
else
if ( y0 < m_min_clip_y )
{
//垂直计算Y坐标差值
//左侧
dyl = ( y1 - y0 );
dxdyl = ( ( x1 - x0 ) << FIXP16_SHIFT ) / dyl;
dudyl = ( ( tu1 - tu0 ) << FIXP16_SHIFT ) / dyl;
dvdyl = ( ( tv1 - tv0 ) << FIXP16_SHIFT ) / dyl;
dwdyl = ( ( tw1 - tw0 ) << FIXP16_SHIFT ) / dyl;
//右侧
dyr = ( y2 - y0 );
dxdyr = ( ( x2 - x0 ) << FIXP16_SHIFT ) / dyr;
dudyr = ( ( tu2 - tu0 ) << FIXP16_SHIFT ) / dyr;
dvdyr = ( ( tv2 - tv0 ) << FIXP16_SHIFT ) / dyr;
dwdyr = ( ( tw2 - tw0 ) << FIXP16_SHIFT ) / dyr;
//垂直计算Y坐标差值
dy = ( m_min_clip_y - y0 );
//计算第一条扫描线起点的各种值
xl = dxdyl * dy + ( x0 << FIXP16_SHIFT );
ul = dudyl * dy + ( tu0 << FIXP16_SHIFT );
vl = dvdyl * dy + ( tv0 << FIXP16_SHIFT );
wl = dwdyl * dy + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线终点的各种值
xr = dxdyr * dy + ( x0 << FIXP16_SHIFT );
ur = dudyr * dy + ( tu0 << FIXP16_SHIFT );
vr = dvdyr * dy + ( tv0 << FIXP16_SHIFT );
wr = dwdyr * dy + ( tw0 << FIXP16_SHIFT );
//计算第一条扫描线的Y坐标
ystart = m_min_clip_y;
if ( dxdyr < dxdyl )
{
SWAP( dxdyl, dxdyr, temp );
SWAP( dudyl, dudyr, temp );
SWAP( dvdyl, dvdyr, temp );
SWAP( dwdyl, dwdyr, temp );
SWAP( xl, xr, temp );
SWAP( ul, ur, temp );
SWAP( vl, vr, temp );
SWAP( wl, wr, temp );
SWAP( x1, x2, temp );
SWAP( y1, y2, temp );
SWAP( tu1, tu2, temp );
SWAP( tv1, tv2, temp );
SWAP( tw1, tw2, temp );
irestart = INTERP_RHS;
}
}
else
{
dyl = ( y1 - y0 );
dxdyl = ( ( x1 - x0 ) << FIXP16_SHIFT ) / dyl;
dudyl = ( ( tu1 - tu0 ) << FIXP16_SHIFT ) / dyl;
dvdyl = ( ( tv1 - tv0 ) << FIXP16_SHIFT ) / dyl;
dwdyl = ( ( tw1 - tw0 ) << FIXP16_SHIFT ) / dyl;
//右侧
dyr = ( y2 - y0 );
dxdyr = ( ( x2 - x0 ) << FIXP16_SHIFT ) / dyr;
dudyr = ( ( tu2 - tu0 ) << FIXP16_SHIFT ) / dyr;
dvdyr = ( ( tv2 - tv0 ) << FIXP16_SHIFT ) / dyr;
dwdyr = ( ( tw2 - tw0 ) << FIXP16_SHIFT ) / dyr;
xl = ( x0 << FIXP16_SHIFT );
ul = ( tu0 << FIXP16_SHIFT );
vl = ( tv0 << FIXP16_SHIFT );
wl = ( tw0 << FIXP16_SHIFT );
xr = ( x0 << FIXP16_SHIFT );
ur = ( tu0 << FIXP16_SHIFT );
vr = ( tv0 << FIXP16_SHIFT );
wr = ( tw0 << FIXP16_SHIFT );
ystart = y0;
if ( dxdyr < dxdyl )
{
SWAP( dxdyl, dxdyr, temp );
SWAP( dudyl, dudyr, temp );
SWAP( dvdyl, dvdyr, temp );
SWAP( dwdyl, dwdyr, temp );
SWAP( xl, xr, temp );
SWAP( ul, ur, temp );
SWAP( vl, vr, temp );
SWAP( wl, wr, temp );
SWAP( x1, x2, temp );
SWAP( y1, y2, temp );
SWAP( tu1, tu2, temp );
SWAP( tv1, tv2, temp );
SWAP( tw1, tw2, temp );
irestart = INTERP_RHS;
}
}
//水平裁剪测试
if ( ( x0 < m_min_clip_x ) || ( x0 > m_max_clip_x ) ||
( x1 < m_min_clip_x ) || ( x1 > m_max_clip_x ) ||
( x2 < m_min_clip_x ) || ( x2 > m_max_clip_x ) )
{
//裁剪版本
//让指screen_ptr指向第一条扫描线起点在缓存的位置
screen_ptr = dest_buffer + ( ystart * mem_pitch );
for ( yi = ystart; yi <= yend; yi++ )
{
//计算扫描线起点和终点的X坐标
xstart = ( ( xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
xend = ( ( xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
//计算扫描线起点和终点的坐标
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
wi = wl + FIXP16_ROUND_UP;
//计算扫描线上的RGB梯度
if ( ( dx = ( xend - xstart )) > 0 )
{
du = ( ur - ul ) / dx;
dv = ( vr - vl ) / dx;
dw = ( wr - wl ) / dx;
}
else
{
du = ( ur - ul );
dv = ( vr - vl );
dw = ( wr - wl );
}
//扫描线起点水平裁剪测试
if ( xstart < m_min_clip_x )
{
//计算起点移动距离
dx = m_min_clip_x - xstart;
//重新计算扫描线起点的RGB值
ui += dx * du;
vi += dx * dv;
wi += dx * dw;
//重新设置循环起始条件
xstart = m_min_clip_x;
}
//终点水平测试
if ( xend > m_max_clip_x )
{
xend = m_max_clip_x;
}
//绘制扫描线
for( xi = xstart; xi <= xend; xi ++ )
{
//绘制像素,假设格式为.6.5
screen_ptr[xi] = ( ( ui >> ( FIXP16_SHIFT + 3)) << 11 ) +
( ( vi >> ( FIXP16_SHIFT + 2)) << 5 ) +
( wi >> ( FIXP16_SHIFT + 3 ));
//计算下一个像素的RGB值
ui += du;
vi += dv;
wi += dw;
}
//计算下一条扫描线起点和终点的x坐标和RGB值
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
//让指针screen_ptr指向视频缓存的下一行
screen_ptr += mem_pitch;
if ( yi == yrestart )
{
if ( irestart == INTERP_LHS )
{
dyl = ( y2 - y1 );
dxdyl = ( ( x2 - x1 ) << FIXP16_SHIFT ) / dyl;
dudyl = ( ( tu2 - tu1 ) << FIXP16_SHIFT ) / dyl;
dvdyl = ( ( tv2 - tv1 ) << FIXP16_SHIFT ) / dyl;
dwdyl = ( ( tw2 - tw1 ) << FIXP16_SHIFT ) / dyl;
xl = ( xl << FIXP16_SHIFT );
ul = ( tu1 << FIXP16_SHIFT );
vl = ( tv1 << FIXP16_SHIFT );
wl = ( tw1 << FIXP16_SHIFT );
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
}
else
{
dyr = ( y1 - y2 );
dxdyr = ( ( x1 - x2 ) << FIXP16_SHIFT ) / dyr;
dudyr = ( ( tu1 - tu2 ) << FIXP16_SHIFT ) / dyr;
dvdyr = ( ( tv1 - tv2 ) << FIXP16_SHIFT ) / dyr;
dwdyr = ( ( tw1 - tw2 ) << FIXP16_SHIFT ) / dyr;
xr = ( x2 << FIXP16_SHIFT );
ur = ( tu2 << FIXP16_SHIFT );
vr = ( tv2 << FIXP16_SHIFT );
wr = ( tw2 << FIXP16_SHIFT );
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
}
}
}
}
else
{
//裁剪版本
//让指screen_ptr指向第一条扫描线起点在缓存的位置
screen_ptr = dest_buffer + ( ystart * mem_pitch );
for ( yi = ystart; yi <= yend; yi++ )
{
//计算扫描线起点和终点的X坐标
xstart = ( ( xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
xend = ( ( xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT );
//计算扫描线起点和终点的坐标
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
wi = wl + FIXP16_ROUND_UP;
//计算扫描线上的RGB梯度
if ( ( dx = ( xend - xstart )) > 0 )
{
du = ( ur - ul ) / dx;
dv = ( vr - vl ) / dx;
dw = ( wr - wl ) / dx;
}
else
{
du = ( ur - ul );
dv = ( vr - vl );
dw = ( wr - wl );
}
//绘制扫描线
for( xi = xstart; xi <= xend; xi ++ )
{
//绘制像素,假设格式为.6.5
screen_ptr[xi] = ( ( ui >> ( FIXP16_SHIFT + 3)) << 11 ) +
( ( vi >> ( FIXP16_SHIFT + 2)) << 5 ) +
( wi >> ( FIXP16_SHIFT + 3 ));
//计算下一个像素的RGB值
ui += du;
vi += dv;
wi += dw;
}
//计算下一条扫描线起点和终点的x坐标和RGB值
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
//让指针screen_ptr指向视频缓存的下一行
screen_ptr += mem_pitch;
if ( yi == yrestart )
{
if ( irestart == INTERP_LHS )
{
dyl = ( y2 - y1 );
dxdyl = ( ( x2 - x1 ) << FIXP16_SHIFT ) / dyl;
dudyl = ( ( tu2 - tu1 ) << FIXP16_SHIFT ) / dyl;
dvdyl = ( ( tv2 - tv1 ) << FIXP16_SHIFT ) / dyl;
dwdyl = ( ( tw2 - tw1 ) << FIXP16_SHIFT ) / dyl;
xl = ( xl << FIXP16_SHIFT );
ul = ( tu1 << FIXP16_SHIFT );
vl = ( tv1 << FIXP16_SHIFT );
wl = ( tw1 << FIXP16_SHIFT );
xl += dxdyl;
ul += dudyl;
vl += dvdyl;
wl += dwdyl;
}
else
{
dyr = ( y1 - y2 );
dxdyr = ( ( x1 - x2 ) << FIXP16_SHIFT ) / dyr;
dudyr = ( ( tu1 - tu2 ) << FIXP16_SHIFT ) / dyr;
dvdyr = ( ( tv1 - tv2 ) << FIXP16_SHIFT ) / dyr;
dwdyr = ( ( tw1 - tw2 ) << FIXP16_SHIFT ) / dyr;
xr = ( x2 << FIXP16_SHIFT );
ur = ( tu2 << FIXP16_SHIFT );
vr = ( tv2 << FIXP16_SHIFT );
wr = ( tw2 << FIXP16_SHIFT );
xr += dxdyr;
ur += dudyr;
vr += dvdyr;
wr += dwdyr;
}
}
}
}
}
}
下面进行DEMO,绘制GOURAUD SHADER三角形
相比而言,调用的代码就简单多了,
在Game_Init()初始化中
ddraw->DDraw_Init( main_window_handle, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, WINDOWED_APP );
srand( mytool.Start_Clock() );
ddraw->DDraw_Fill_Surface( ddraw->getbackSurface(), 0 );
在每帧循环中GAME_MAIN()
int Game_Main(void *parms = NULL, int num_parms = 0)
{
// check of user is trying to exit
if (KEYDOWN(VK_ESCAPE) )
PostMessage(main_window_handle, WM_DESTROY,0,0);
srand( mytool.Start_Clock() );
ddraw->DDraw_Fill_Surface( ddraw->getbackSurface(), 0 );
ddraw->DDraw_Lock_Back_Surface();
POLYF4DV2 face;
face.tvlist[0].x = ( int ) RAND_RANGE( 0, SCREEN_WIDTH - 1 );
face.tvlist[0].y = ( int ) RAND_RANGE( 0, SCREEN_HEIGHT - 1 );
face.lit_color[0] = _RGB16BIT565( RAND_RANGE( 0, 255 ), RAND_RANGE( 0, 255), RAND_RANGE( 0, 255 ));
face.tvlist[1].x = ( int ) RAND_RANGE( 0, SCREEN_WIDTH - 1 );
face.tvlist[1].y = ( int ) RAND_RANGE( 0, SCREEN_HEIGHT - 1 );
face.lit_color[1] = _RGB16BIT565( RAND_RANGE( 0, 255 ), RAND_RANGE( 0, 255), RAND_RANGE( 0, 255 ));
face.tvlist[2].x = ( int ) RAND_RANGE( 0, SCREEN_WIDTH - 1 );
face.tvlist[2].y = ( int ) RAND_RANGE( 0, SCREEN_HEIGHT - 1 );
face.lit_color[2] = _RGB16BIT565( RAND_RANGE( 0, 255 ), RAND_RANGE( 0, 255), RAND_RANGE( 0, 255 ));
math->Draw_Gouraud_Triangle16( & face, ddraw->getbackbuffer(), ddraw->getbacklpitch());
ddraw->DDraw_Unlock_Back_Surface();
ddraw->DDraw_Flip();
mytool.Wait_Clock( 30 );
return(1);
} // end Game_Main
结果如下,OK了