📄 btriangle.cpp
字号:
/////////////////////////////////////////////////////////////////////////////////
//
// BTriangle.cpp: implementation of the CBTriangle class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming
#include "stdafx.h"
#include "BTriangle.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CBTriangle::CBTriangle()
{}
CBTriangle::~CBTriangle(){}
//获取直线边界上的点的x坐标,颜色和深度
//x1,y1,x2,y2----直线两端点坐标
//z1,z2----------端点深度值
//clr1,clr2------直线起点和终点颜色
//pnCoord--------记录扫描线与边的交点的x坐标,
//pnCoord--------pnCoord数组的长度应该是y坐标差的绝对值加1
//pColor---------记录各交点的颜色。
//pfDepth--------记录各交点的深度值
//pCB,pZB--------分别为颜色缓冲和深度缓冲
//dwFeature------是一个边界记录特征量。当其为TRIANGLE_AREA_ON_LINE_RIGHT时,表示区域在直线右侧;当其为TRIANGLE_AREA_ON_LINE_LEFT时,表示区域在其左侧。
//程序缺省设置为区域在边的右侧。
void CBTriangle::DealEdge(int x1, int y1, int x2, int y2, float z1, float z2, FLOATCOLORRGBA clr1, FLOATCOLORRGBA clr2, CColorBuffer* pCB, CZBuffer* pZB, int* pnCoord, FLOATCOLORRGBA* pColor, float* pfDepth, DWORD dwFeature)
{
//各数组的长度应该是y坐标差的绝对值加1,
ASSERT(pnCoord);
ASSERT(pColor);
ASSERT(pfDepth);
//对于一条水平直线,则简单地返回第一个点的坐标和颜色
//对于一条水平直线,我们不区分区域相对它的左右关系.
if(y1 == y2)
{
pnCoord[0] = x1;
pColor[0] = clr1;
pfDepth[0] = z1;
return;
}
//下面考查直线斜率不为0的情况:
//两端点间的水平偏移量和垂直偏移量
int nDx = x2 - x1;
int nDy = y2 - y1;
//两端点间的水平距离和垂直距离
int nIx = ABS(nDx);
int nIy = ABS(nDy);
//描点步数(增量总值)
int nInc = MAX(nIx,nIy);
//用于判断是否在nJudgeX,nJudgeY方向上向前进
int nJudgeX = -nIy, nJudgeY = -nIx;
//通过增量计算得到的当前点
int x = x1, y = y1;
//Bresenham算法
int nTwoIx = 2 * nIx, nTwoIy = 2 * nIy;
//直线当前点的颜色
float fPlotR = clr1.red, fPlotG = clr1.green, fPlotB = clr1.blue;
float fPlotA = clr1.alpha;
//颜色增量
float fIncR = (clr2.red - fPlotR) / nInc;
float fIncG = (clr2.green - fPlotG) / nInc;
float fIncB = (clr2.blue - fPlotB) / nInc;
float fIncA = (clr2.alpha - fPlotA) / nInc;
//水平边界段起点和终点
FLOATCOLORRGBA clrStart = {fPlotR,fPlotG,fPlotB,fPlotA};
FLOATCOLORRGBA clrEnd = clrStart;
//数组下标,水平边界段起点和终点的 x 坐标
int nIndex = 0, nStartX = x1, nEndX = x1;
//水平边界段起点和终点的 z 坐标,当前点的 z 坐标
//以及 z 坐标增量
float fStartZ = z1, fEndZ = z1, z = z1, fIncZ = (z2 - z1) / nInc;
//根据深度值绘制第一个点
//缓冲区中的深度
float zInBuffer = pZB->GetDepth(x1,y1);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(x1, y1, fPlotR, fPlotG, fPlotB, fPlotA);
//重置深度缓冲区的值
pZB->SetDepth(x1, y1, z);
}
//开始增量计算
for(int i = 0;i <= nInc; i++)
{
nJudgeX += nTwoIx;
nJudgeY += nTwoIy;
//通过增量法计算的当前点是否属于直线上的点
BOOL bRecord = FALSE;
//当前点是否为直线上的点
BOOL bPlot = FALSE;
//先检测 y 方向
if(nJudgeY >= 0)
{
bPlot = TRUE;
bRecord = TRUE;
nJudgeY -= nTwoIx;
//将任意走向的直线统一起来
if(nDy > 0)
{
nEndX = x;
y++;
//水平边界段终点的颜色
clrEnd.red = fPlotR;
clrEnd.green = fPlotG;
clrEnd.blue = fPlotB;
clrEnd.alpha = fPlotA;
//水平边界段终点的深度(沿边进行插值计算而获得)
fEndZ = z;
}
else if(nDy < 0)
{
nEndX = x;
y--;
//水平边界段终点的颜色
clrEnd.red = fPlotR;
clrEnd.green = fPlotG;
clrEnd.blue = fPlotB;
clrEnd.alpha = fPlotA;
//水平边界段终点的深度(沿边进行插值计算而获得)
fEndZ = z;
}
}//end if
//后检测 x 方向
if(nJudgeX >= 0)
{
bPlot = TRUE;
nJudgeX -= nTwoIy;
//将任意走向的直线统一起来
if(nDx > 0)x++;
else if(nDx < 0)x--;
}
if(bPlot)
{
fPlotR += fIncR;
fPlotG += fIncG;
fPlotB += fIncB;
fPlotA += fIncA;
z += fIncZ;
if(i < (nInc - 1))
{
//根据深度值绘制第一个点
zInBuffer = pZB->GetDepth(x,y);
//如果当前点的z坐标小于深度缓冲区中的相同位置z的坐标
if(z < zInBuffer)
{
//在颜色缓冲区中绘制第一个点
pCB->SetPixel(x, y, fPlotR, fPlotG, fPlotB, fPlotA);
//重置深度缓冲区的值
pZB->SetDepth(x, y, z);
}
}//end if(i < (nInc - 1))
}//end if(bPlot)
//如果当前点在直线上,则记录当前点
if(bRecord)
{
//取最左边点,区域在左侧
if(dwFeature == G3D_TRIANGLE_ON_LINE_LEFT)
{
//取x坐标最小者
if(nStartX < nEndX)
{
pnCoord[nIndex] = nStartX;
pColor[nIndex] = clrStart;
pfDepth[nIndex] = fStartZ;
}
else
{
pnCoord[nIndex] = nEndX;
pColor[nIndex] = clrEnd;
pfDepth[nIndex] = fEndZ;
}
}//end if
//取最右边点,区域在右侧
else
{
//取x坐标最大者
if(nStartX < nEndX)
{
pnCoord[nIndex] = nEndX;
pColor[nIndex] = clrEnd;
pfDepth[nIndex] = fEndZ;
}
else
{
pnCoord[nIndex] = nStartX;
pColor[nIndex] = clrStart;
pfDepth[nIndex] = fStartZ;
}
}//end else
nIndex++;
//下一个起点
nStartX = x;
//下一个起点的 z 坐标
fStartZ = z;
//下一个起点的颜色
clrStart.red = fPlotR;
clrStart.green = fPlotG;
clrStart.blue = fPlotB;
clrStart.alpha = fPlotA;
}//end if(bRecord)
}//end for
//当斜率的很小时,y坐标增长缓慢,这时需要特别处理
if(nIndex < (ABS(y2 - y1) + 1))
{
//取最左边点,区域在左侧
if(dwFeature == G3D_TRIANGLE_ON_LINE_LEFT)
{
//取x坐标最小者
if(nStartX < x2)
{
pnCoord[nIndex] = nStartX;
pColor[nIndex] = clrStart;
pfDepth[nIndex] = fStartZ;
}
else
{
pnCoord[nIndex] = x2;
pColor[nIndex] = clr2;
pfDepth[nIndex] = z2;
}
}//end if
//取最右边点,区域在右侧
else
{
//取x坐标最大者
if(nStartX < x2)
{
pnCoord[nIndex] = x2;
pColor[nIndex] = clr2;
pfDepth[nIndex] = z2;
}
else
{
pnCoord[nIndex] = nStartX;
pColor[nIndex] = clrStart;
pfDepth[nIndex] = fStartZ;
}
}//end else
}//end if(nIndex < (ABS(y2 - y1) + 1))
}
//着色一条扫描线,扫描坐标的x坐标为x1和x2, y坐标为nScanLine,
//z1,z2----------端点深度值
//clr1和clr2分别为起点和终点的颜色.
//pCB,pZB--------分别为颜色缓冲和深度缓冲
void CBTriangle::Scan(int x1, int x2, int nScanLine, float z1, float z2, FLOATCOLORRGBA clr1, FLOATCOLORRGBA clr2, CColorBuffer* pCB, CZBuffer* pZB)
{
//填充像素个数
int nFillPixels = ABS(x2 - x1);
//如果为同一个点或距离相差为0,则返回;
if(nFillPixels < 2) return;
//颜色增量(颜色差值 / 份数)
float fIncR = (clr2.red - clr1.red) / nFillPixels;
float fIncG = (clr2.green - clr1.green) / nFillPixels;
float fIncB = (clr2.blue - clr1.blue) / nFillPixels;
float fIncA = (clr2.alpha - clr1.alpha) / nFillPixels;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -