注释是我加上去的,不知道不明确的正确与否,请指正。
/***********************************************************************************************
// 单扫描线内容拷贝函数,desc与src均使用相对偏移,mode值意义如下:
// 值 意义
// -----------------------------
// 1 EMS屏幕 ---> VRAM屏幕
// -1 VRAM屏幕 ---> EMS屏幕
***********************************************************************************************/
void scanline_copy(unsigned long desc,unsigned long src,unsigned int length,char mode)
{
char pagetype1,pagetype2;
char far* descPoint; // 局部变量:目标拷贝起始地址
char far* srcPoint; // 局部变量:源拷贝起始地址
unsigned int descpage=desc>>16, // 目标转换得到BIOS Video(VRAM)页
descoffset=desc&0xffff,// 目标相对VRAM页的偏移
srcpage=src>>16, // 源转换得到BIOS Video(VRAM)页
srcoffset=src&0xffff; // 源相对VRAM页的偏移
if (mode == 1) // EMS ---> VRAM 拷贝
{
descPoint=VPoint; // 目标基地址 = 0xa000
srcPoint=EmsPoint; // 源基地址 = EMS映射内存基地址
pagetype1=1;
pagetype2=0;
}
else // VRAM ---> EMS 拷贝
{
descPoint=EmsPoint; // 目标基地址 = EMS映射内存基地址
srcPoint=VPoint; // 源基地址 = 0xa000
pagetype1=0;
pagetype2=1;
}
/*----------------------------------------------------------------------------------------------------------------
// 如果 EMS ---> VRAM 拷贝:目标BIOS Video换页, 源EMS逻辑页换页
// 如果 VRAM ---> EMS 拷贝:目标EMS逻辑页换页, 源BIOS Video换页
------------------------------------------------------------------------------------------------------------------*/
MySelectpage1(descpage,pagetype1);
MySelectpage1(srcpage,pagetype2);
/*----------------------------------------------------------------------------------------------------------------
// 如果源复制区域及目标复制区域都未超过BIOS Video(VRAM)当前页(1页=65535)
------------------------------------------------------------------------------------------------------------------*/
if ((long)srcoffset+length<=65536L && (long)descoffset+length<=65536L)
{
memcpy(descPoint+descoffset,srcPoint+srcoffset,length);
return;
}
/*----------------------------------------------------------------------------------------------
// 跨页处理(源复制区域或目标复制区域超过BIOS Video(VRAM)当前页,需作跨页处理)
-----------------------------------------------------------------------------------------------*/
else
{
unsigned int passed_length;
if (descoffset == srcoffset) // 传输块与源的offset相同的情况
{
passed_length=65536L-descoffset;//当前页可Copy字节
memcpy(descPoint+descoffset,srcPoint+srcoffset,passed_length);
MySelectpage1(descpage+1,pagetype1);// 目标换至下页
MySelectpage1(srcpage+1,pagetype2); // 源换至下页
memcpy(descPoint,srcPoint,length-passed_length);// 复制跨页剩余内容
}
else // 传输块与源的offset不同的情况
{
while (length>0)
{
if ((long)srcoffset+length<=65536L && (long)descoffset+length<=65536L)
{
memcpy(descPoint+descoffset,srcPoint+srcoffset,length);
break;
}
/*----------------------------------------------------------------------------------------------
// 目标offset剩余的比源offset多,即源指针比目标指针先到达VRAM页(1页=65535)的尾部
-----------------------------------------------------------------------------------------------*/
if (srcoffset>descoffset)// 说明目标offset剩余的比源offset多
{
passed_length=65536L-srcoffset;// 当前页Copy长度
memcpy(descPoint+descoffset,srcPoint+srcoffset,passed_length);
srcpage++; // 源页号+1
MySelectpage1(srcpage,pagetype2);// 源换至下页
descoffset+=passed_length;// 修正目标偏移
srcoffset=0; // 修正源偏移:由于源已经换页,因此偏移从0重新开始。
// 由于拷贝passed_length长度后,源指针已经到达VRAM页尾部,因此必须将源指针重新修正为0,并换到下页,而目标指针还未到达VRAM尾部,因此,只需修正目标指针即可。
}
/*----------------------------------------------------------------------------------------------
// 源offset剩余的比目标offset多,即目标指针比源指针到达VRAM页(1页=65535)的尾部
-----------------------------------------------------------------------------------------------*/
else // 说明源offset剩余的比目标offset多
{
passed_length=65536L-descoffset;// 当前页Copy长度
memcpy(descPoint+descoffset,srcPoint+srcoffset,passed_length);
descpage++; // 目标页号+1
MySelectpage1(descpage,pagetype1);// 目标换至下页
srcoffset+=passed_length;// 修正源偏移
descoffset=0; // 修正目标偏移:由于目标已经换页,因此偏移从0重新开始。
// 由于拷贝passed_length长度后,目标指针已经到达VRAM页尾部,因此必须将目标指针重新修正为0,并换到下页,而源指针还未到达VRAM尾部,因此,只需修正源指针即可。
}
length-=passed_length; // 剩余待Copy长度
}
}
}
}
/***********************************************************************************************
// 常规内存与EMS或VRAM间的拷贝函数,不带屏幕剪切。
// 入口参数:
// (1).mempos为常规内存指针 (2).destoffset为EMS或VRAM起始点偏移.
// (3).length为待复制长度 (4).mode为数据移动方向
// -----------------------------------------------------------
// 0 常规内存->EMS屏幕 例如:MemCopy256(BmpStackPos,buffer,length,0);
// 将常规内存数组buffer数据移至EMS
// 1 常规内存->VRAM屏幕
// 2 EMS屏幕->常规内存 例如:MemCopy256(HZK_DATA+position,mat,th*2,2);
// 将汉字库汉字字模从EMS拷贝到常规内存数组mat中。
// 3 VRAM屏幕->常规内存
// memcpy函数格式:memcpy(void *dest , void *src , int length)
***********************************************************************************************/
void MemCopy256(unsigned long descoffset,char *mempos,unsigned int length,char mode)
{
unsigned int page=descoffset>>16, // 目标转换成BIOS Video页号
offset=descoffset&0xffff, // 目标相对VRAM页的偏移
part1; // 局部变量
char far* descPoint; // 局部变量:目标拷贝起始地址
if (mode%2) // mode = 1,3 常规内存 <---> VRAM屏幕
descPoint=VPoint; // 目标基地址 = 0xa000
else // mode = 0,2 常规内存 <---> EMS屏幕
descPoint=EmsPoint; // 目标基地址 = EMS映射基地址
MySelectpage1(page,mode%2); // 目标BIOS Video换页或者目标EMS换页
/*----------------------------------------------------------------------------------------------------------------
// 如果复制区域未超出BIOS Video当前页(1页=65535)
------------------------------------------------------------------------------------------------------------------*/
if ((long)offset+length<=65536L)
{
if (mode/2) // mode = 2,3 EMS屏幕->常规内存或VRAM屏幕->常规内存
memcpy(mempos,descPoint+offset,length);
else // mode = 0,1 常规内存->EMS屏幕或常规内存->VRAM屏幕
memcpy(descPoint+offset,mempos,length);
return;
}
/*----------------------------------------------------------------------------------------------
// 跨页处理
-----------------------------------------------------------------------------------------------*/
else
{
part1 = 65536L-offset; // 当前页需Copy内容
if (mode/2)
memcpy(mempos,descPoint+offset,part1);
else
memcpy(descPoint+offset,mempos,part1);
MySelectpage1(page+1,mode%2); // 目标BIOS Video或者目标EMS换至下页
length-=part1; // 跨页剩余待Copy内容
if (mode/2)
memcpy(mempos+part1,descPoint,length);
else
memcpy(descPoint,mempos+part1,length);
}
}
/***********************************************************************************************
// 常规内存与绘图屏幕间的水平线拷贝函数,带屏幕剪切。
// (1).mempos为常规内存指针
// (2).(x,y)为屏幕上水平数据线的左起始点
// (3).length为
// (4).mode为数据移动方向
// ------------------------
// 0 常规内存->EMS屏幕
// 1 常规内存->VRAM屏幕
// 2 EMS屏幕->常规内存
// 3 VRAM屏幕->常规内存
***********************************************************************************************/
void screenline_copy(int x,int y,char *mempos,unsigned int length,char mode)
{
unsigned int scan_seek=0,scan_length;
unsigned long descoffset;
if (x+length<screen_cut.left||x>screen_cut.right||y<screen_cut.top||y>screen_cut.bottom)
return;
/*---------------------------------------------------------------------------------------------
// screen_cut.left ================================== screen_cut.right
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [copy line]
// x x+length
-----------------------------------------------------------------------------------------------*/
if (x<screen_cut.left) // 如果线的首端超出裁减窗口的左端
scan_seek=screen_cut.left-x;
if (x+length>screen_cut.right) // 如果线的尾端超出裁减窗口右端
scan_length=screen_cut.right-(scan_seek+x)+1;
else // 线的尾端未超出裁减窗口的右端
scan_length=length-scan_seek;
//descoffset=y*640l+x+scan_seek;// 为了提高运算速度,将乘法运算改为移位运算
descoffset=(((unsigned long)y<<9L)+((unsigned long)y<<7L)+((unsigned long)x))+scan_seek;
MemCopy256(descoffset,mempos+scan_seek,scan_length,mode);
}