|

楼主 |
发表于 2006-5-14 17:41:00
|
显示全部楼层
第十五讲+:如何绘制mir3的图像
/*
用于压缩图像的绘制,绘制mir3的图像。
该函数使用pwSrc所指向的压缩图像数据,rcSrc所指示的源图像矩形,
给定用于保存源图像的矩形的左上角由nX, nY 定位。
压缩的图像文件映像中图像数据区的格式:
标志,如果是C0 00 表示是透明像素,如果是C1 00表示是正常像素,
如果是C2 00函数使用wChooseColor1进行像素处理, 如果是C3 00 函数使用wChooseColor2进行像素处理,
注意: 1、函数的参数有默认值: wChooseColor1 = 0XFFFF, wChooseColor2 = 0XFFFF 这是白色。
2、注意存在屏幕、显示区域、和目标矩形三个区域,屏幕坐标系作为显示区域和目标矩形定位的区域。
+++++++++++++++++++++++++++++++++++++++++++++++++++
+ | | nY +
+---------------|-----------nX ++++++++++++++++ +
+ |nStartY + + +
+-----nStartX---++++++++++++++++++++++++++++ + +
+ + m_stDisplayInfo.wWidth + + +
+ + + + + +
+ + + + + +
+ + ++++++++++++++++ +
+ + m_stDisplayInfo.wHeight + +
+ + + +
+ ++++++++++++++++++++++++++++ +
+ +
+ +
+ +
+++++++++++++++++++++++++++++++++++++++++++++++++++
*/
BOOL CWHDXGraphicWindow: rawWithImageForComp
(INT nX, INT nY, //源图像的左上角绘制到屏幕上时的屏幕坐标
RECT rcSrc, //源图像矩形
WORD* pwSrc, //源图像数据
WORD wChooseColor1, //选择的混合颜色1
WORD wChooseColor2 //选择的混合颜色2
)
{
RECT rc; //实际绘制矩形
DDSURFACEDESC2 ddsd; //dd表面特性描述结构
//////////////////////////////////////////////////////////////////////////////
//在屏幕坐标系上(或窗口的客户坐标系上)定位源图像的矩形(目标矩形)
//实际绘制矩形的宽高初始化为源图像矩形的高宽
INT nWidth = rcSrc.right-rcSrc.left;
INT nHeight = rcSrc.bottom-rcSrc.top;
//实际绘制矩形的左上角相对位置
INT nXOffset = rcSrc.left;
INT nYOffset = rcSrc.top;
//在显示区域上定位一个供图像显示的区域,这就像定义一个视口,这里与显示屏幕同。
//这个区域的左上角被定位在显示区的左上角,右下角定位在显示区的右下角。
//注意当这个视口与显示屏幕不一致时,仅仅视口之内的图像才需要绘制。
INT nStartX = 0;
INT nStartY = 0;
INT nEndX = m_stDisplayInfo.wWidth -1;
INT nEndY = m_stDisplayInfo.wHeight-1;
//如果后缓冲区存在,则进行将当前图像的压缩数据解析绘制到显示区的工作。
if ( m_pddsBackBuffer != NULL )
{
//确定绘制的范围,目标矩形落在视口的部分才需要绘制,视口之外被剪切掉。
//如果目标矩形有区域落在视口左边线之左
if (nX < nStartX )
{
nXOffset += nStartX - nX;
nWidth = rcSrc.right - nXOffset;
}
//如果目标矩形有区域落在视口右边线之右
if ( (nX+rcSrc.right-rcSrc.left-1) > nEndX )
nWidth = nEndX - nX - nXOffset + 1;
//如果目标矩形有区域落在视口上边线之上
if ( nY < nStartY )
{
nYOffset += nStartY - nY;
nHeight = rcSrc.bottom - nYOffset;
}
//如果目标矩形有区域落在视口下边线之下
if ( (nY+rcSrc.bottom-rcSrc.top-1) > nEndY )
nHeight = nEndY - nY - nYOffset + 1;
//以上计算出需要绘制的图像部分的矩形
//剪切的结果是一个正矩形,说明目标矩形与视口有重叠部分,这就可以进行绘制了。
if ( (nWidth > 0) && (nHeight > 0) )
{
//定位绘制区域
rc.left = nXOffset;
rc.right = nXOffset+nWidth;
rc.top = nYOffset;
rc.bottom = nYOffset+nHeight;
//初始化dd表面特性描述结构
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.lpSurface = NULL;
//锁定后缓冲区表面,获取直接访问表面内存所必须的信息
m_pddsBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
//如果没有获取表面的基地址,则调用返回失败。
if ( !ddsd.lpSurface ) return FALSE;
//将表面内存的基地址转换为字指针(每像素16位色深)
WORD* pwdDst;
pwdDst = (WORD*)ddsd.lpSurface; //获取dd表面的基地址
//将格式图像处理为每像素16位色深的位图数据阵列时
//在逐像素处理过程中要使用的一些临时变量,坐标原点在图像的几何中心。
INT nWidthStart = 0; //宽度方向开始处理的像素坐标
INT nWidthEnd = 0; //累计处理完毕的像素数目
INT nCurrWidth = 0; //当前正在处理的像素的宽度坐标
INT nCntCopyWord = 0; //需要拷贝的图像像素数目(每像素两个字节)
INT nYCnt =0; //累计表面上不包含本图像像素的显示表面的像素行的数量
INT nLastWidth = 0; //最近一次处理的像素宽度方向的像素坐标
//解析格式图像数据时,根据格式标识进行图像像素的光栅操作时要使用的临时变量。
FLOAT rBlueRate, rGreenRate, bRedRate; //用于保存565数据中的各个彩色分量的比率
BYTE bRedSrc, bGreenSrc, bBlueSrc; //用于保存源图像数据的各个彩色分量值
BYTE bRedWantedColor, bGreenWantedColor, bBlueWantedColor; //用于保存光栅操作后图像数据的各个彩色分量值
WORD wPixel; //用于保存选择的用于对图像某些像素进行光栅操作的一个565彩色值
//LYF:这里是如何定位源图像数据中要处理的数据的呢?
//使用nYCnt计算出显示表面上不包含本图像像素的像素行的数量,
//表面的nYCnt行的下一行将包含本图像的首行。
for ( nYCnt=0 ; nYCnt < rc.top ; nYCnt++ )
{
nWidthEnd += pwSrc[nWidthStart]; //表面上一行已经处理完的字节数
nWidthStart++; //LYF:这一句无用?
nWidthEnd++; //处理包含图像数据的下一个表面行
nWidthStart = nWidthEnd; //得到要开始处理的像素的屏幕坐标
}
//对图像上从图像顶到图像底的每一行像素,逐行处理
for ( nYCnt=rc.top ; nYCnt < rc.bottom ; nYCnt++ )
{
// 计算出开始绘制的像素的结束地址和开始地址
nWidthEnd += pwSrc[nWidthStart];
nWidthStart++;
//按源图像格式解析并逐像素绘制
for ( INT x = nWidthStart; x < nWidthEnd ; )
{
//0xC0是作透明处理的像素的标记
if ( pwSrc[x] == 0xC0 )
{
//透明像素不拷贝到目表表面,仅仅计算所占位置
x++;
nCntCopyWord = pwSrc[x]; //获得要拷贝的作透明处理像素的数量
x++;
nCurrWidth += nCntCopyWord; //计算以像素表示的当前宽度
}
//0xC1是正常的图像数据的标记
else if ( pwSrc[x] == 0xC1 )
{
x++;
nCntCopyWord = pwSrc[x]; //获得要拷贝的正常处理像素的数量
x++;
nLastWidth = nCurrWidth; //最近的像素表示的宽度
nCurrWidth += nCntCopyWord; //计算以像素表示的当前宽度
//当前像素落在绘制矩形之外不绘制
if ( rc.left > nCurrWidth || rc.right < nLastWidth )
{
x += nCntCopyWord;
}
//当前像素落在绘制矩形之内就进行正常像素的拷贝
//注意由中心向左边拷贝,再向右边拷贝,这样第一时间出现有效的像素。
//因为是绘制矩形的左半边,故表面每行的字节数(表面节距)要除以2即右移一位。
//正要绘制的表面像素的偏移量(字节) = 已经绘制的表面像素的行坐标(Y)* 表面的节距 + 已经绘制的表面像素的列坐标(X)*每像素字节数
else
{
// 实际绘制矩形的左半边
if ( nLastWidth < rc.left && rc.left <= nCurrWidth )
{
x += (rc.left-nLastWidth);
memcpy(&pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (rc.left+nX)], &pwSrc[x], sizeof(WORD)*(nCurrWidth-rc.left));
x += (nCurrWidth-rc.left);
}
// 实际绘制矩形的右半边
else if ( nLastWidth <= rc.right && rc.right < nCurrWidth )
{
memcpy(&pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (nLastWidth+nX)], &pwSrc[x], sizeof(WORD)*(rc.right-nLastWidth));
x += nCntCopyWord;
}
else
{
memcpy(&pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (nLastWidth+nX)], &pwSrc[x], sizeof(WORD)*nCntCopyWord);
x += nCntCopyWord;
}
}
}
//0xC2、0xC3 是使用选择的颜色对图像进行滤镜处理的标记,
//往往用于角色垂死的变色镜效果的处理。
else if ( pwSrc[x] == 0xC2 || pwSrc[x] == 0xC3 )
{
WORD wDyingKind, wChooseColor; //垂死种类、选择的变色颜色
wDyingKind = pwSrc[x];
//根据垂死种类选择变色颜色
switch ( wDyingKind )
{
//使用参数wChooseColor1设定的颜色
case 0xC2:
wChooseColor = wChooseColor1;
break;
//使用参数wChooseColor2设定的颜色
case 0xC3:
wChooseColor = wChooseColor2;
break;
}
x++;
nCntCopyWord = pwSrc[x]; //获得需要进行垂死颜色处理的像素的数量
x++;
nLastWidth = nCurrWidth;
nCurrWidth += nCntCopyWord;
//如果当前像素落在绘制矩形之外则不绘制
if ( rc.left > nCurrWidth || rc.right < nLastWidth )
{
x += nCntCopyWord;
}
// 绘制矩形之内的像素就要对该像素进行光栅处理,
//注意是由中心向左右两边分别绘制,先向左绘制,再向右绘制。
else
{
//绘制矩形的左半边
if ( nLastWidth < rc.left && rc.left <= nCurrWidth )
{
x += (rc.left-nLastWidth);
//逐个处理该图像行的每个像素
for ( INT nCheck = 0; nCheck < nCurrWidth-rc.left; nCheck++ )
{
//解析选择的颜色的BGR分量
wPixel = wChooseColor;
bBlueWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
//解析源像素的BGR分量
wPixel = pwSrc[x+nCheck];
bBlueSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
//计算源像素BGR分量的比率
rBlueRate = (FLOAT)((FLOAT)bBlueSrc / (FLOAT)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift));
rGreenRate = (FLOAT)((FLOAT)bGreenSrc / (FLOAT)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift));
bRedRate = (FLOAT)((FLOAT)bRedSrc / (FLOAT)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift));
//计算出希望得到的像素的BGR分量的值
bBlueWantedColor = (BYTE)(((FLOAT)bBlueWantedColor*rBlueRate));
bGreenWantedColor = (BYTE)(((FLOAT)bGreenWantedColor*rGreenRate));
bRedWantedColor = (BYTE)(((FLOAT)bRedWantedColor*bRedRate));
//计算出的像素的BGR分量的值不可能大于相应分量的最大值
if ( bBlueWantedColor > (m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift) )
bBlueWantedColor = (BYTE)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift);
if ( bGreenWantedColor > (m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift) )
bGreenWantedColor = (BYTE)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift);
if ( bRedWantedColor > (m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift) )
bRedWantedColor = (BYTE)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift);
//用逻辑与来构造表示一个像素的数据,并且直接写入表面内存。
//因为是绘制矩形的左半边,故表面每行的字节数(表面节距)要除以2即右移一位。
//正要绘制的表面像素的偏移量(字节) = 已经绘制的表面像素的行坐标(Y)* 表面的节距 + 已经绘制的表面像素的列坐标(X)*每像素字节数
pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (nLastWidth+nX+nCheck)] = ((bRedWantedColor <<m_stBitsMaskInfo.bRShift) |
(bGreenWantedColor<<m_stBitsMaskInfo.bGShift) |
(bBlueWantedColor <<m_stBitsMaskInfo.bBShift));
}
//本行由中心向左的下一个像素
x += (nCurrWidth-rc.left);
}
// 由中心向右处理
else if ( nLastWidth <= rc.right && rc.right < nCurrWidth )
{
for ( INT nCheck = 0; nCheck < rc.right-nLastWidth; nCheck++ )
{
wPixel = wChooseColor;
bBlueWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
wPixel = pwSrc[x+nCheck];
bBlueSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
rBlueRate = (FLOAT)((FLOAT)bBlueSrc / (FLOAT)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift));
rGreenRate = (FLOAT)((FLOAT)bGreenSrc / (FLOAT)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift));
bRedRate = (FLOAT)((FLOAT)bRedSrc / (FLOAT)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift));
bBlueWantedColor = (BYTE)(((FLOAT)bBlueWantedColor*rBlueRate));
bGreenWantedColor = (BYTE)(((FLOAT)bGreenWantedColor*rGreenRate));
bRedWantedColor = (BYTE)(((FLOAT)bRedWantedColor*bRedRate));
if ( bBlueWantedColor > (m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift) )
bBlueWantedColor = (BYTE)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift);
if ( bGreenWantedColor > (m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift) )
bGreenWantedColor = (BYTE)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift);
if ( bRedWantedColor > (m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift) )
bRedWantedColor = (BYTE)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift);
pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (nLastWidth+nX+nCheck)] = ((bRedWantedColor <<m_stBitsMaskInfo.bRShift) |
(bGreenWantedColor<<m_stBitsMaskInfo.bGShift) |
(bBlueWantedColor <<m_stBitsMaskInfo.bBShift));
}
x += nCntCopyWord;
}
else
{
for ( INT nCheck = 0; nCheck < nCntCopyWord; nCheck++ )
{
wPixel = wChooseColor;
bBlueWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedWantedColor = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
wPixel = pwSrc[x+nCheck];
bBlueSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwBMask) >> m_stBitsMaskInfo.bBShift);
bGreenSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwGMask) >> m_stBitsMaskInfo.bGShift);
bRedSrc = (BYTE)((wPixel & m_stBitsMaskInfo.dwRMask) >> m_stBitsMaskInfo.bRShift);
rBlueRate = (FLOAT)((FLOAT)bBlueSrc / (FLOAT)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift));
rGreenRate = (FLOAT)((FLOAT)bGreenSrc / (FLOAT)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift));
bRedRate = (FLOAT)((FLOAT)bRedSrc / (FLOAT)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift));
bBlueWantedColor = (BYTE)(((FLOAT)bBlueWantedColor*rBlueRate));
bGreenWantedColor = (BYTE)(((FLOAT)bGreenWantedColor*rGreenRate));
bRedWantedColor = (BYTE)(((FLOAT)bRedWantedColor*bRedRate));
if ( bBlueWantedColor > (m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift) )
bBlueWantedColor = (BYTE)(m_stBitsMaskInfo.dwBMask>>m_stBitsMaskInfo.bBShift);
if ( bGreenWantedColor > (m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift) )
bGreenWantedColor = (BYTE)(m_stBitsMaskInfo.dwGMask>>m_stBitsMaskInfo.bGShift);
if ( bRedWantedColor > (m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift) )
bRedWantedColor = (BYTE)(m_stBitsMaskInfo.dwRMask>>m_stBitsMaskInfo.bRShift);
pwdDst[((nYCnt+nY) * (ddsd.lPitch >> 1)) + (nLastWidth+nX+nCheck)] = ((bRedWantedColor <<m_stBitsMaskInfo.bRShift) |
(bGreenWantedColor<<m_stBitsMaskInfo.bGShift) |
(bBlueWantedColor <<m_stBitsMaskInfo.bBShift));
}
x += nCntCopyWord;
}
}
}
}
//由中心向左右处理完成后,处理完毕的图像行增加一行。
nWidthEnd++;
nWidthStart = nWidthEnd; //
nCurrWidth = 0;
}
}
//解除dd表面的锁定,函数调用成功。
m_pddsBackBuffer->Unlock(NULL);
return TRUE;
}
return FALSE; //如果后缓冲区不存在或者目标矩形不在显示区域之内则本绘制函数调用失败。
} |
|