📄 images.cpp
字号:
// *************************************************************************
// set the pixel at coordinate x,y to color
// This could be translated into assembler, but is probably fast enough
// *************************************************************************
void writepixel(int x, int y, int color)
{
*(char far *)MK_FP(GRAPH_SEG,(y*320)+x)=color;
}
// *************************************************************************
// read the color of the pixel at coordinate x,y
// Could also be done in assembler, but may be fast enough as is
// *************************************************************************
char readpixel(int x, int y)
{
return(*(char far *)MK_FP(GRAPH_SEG,(y*320)+x));
}
// *************************************************************************
// returns a void type pointer to video memory at pixel coordinate x,y
// *************************************************************************
void far *xy_to_ptr(int x, int y)
{
return((char *)MK_FP(GRAPH_SEG,(y*320)+x));
}
// *************************************************************************
// The following three functions make up the line drawing routine
//
// Draws a line in vga mode 13h only from (x0,y0) to (x1,y1) in color color.
// Drawing code adapted from Power Graphics Programming, Michael Abrash
// *************************************************************************
// *************************************************************************
// Octant0() and Octant1() are support functions for line()
// Adapted from "Power Graphics Programming", Michael Abrash.
// *************************************************************************
void static near Octant0(unsigned int x0,unsigned int y0,unsigned int deltaX,
unsigned int deltaY, int Xdirection, int color)
{
int deltaYx2;
int deltaYx2minusdeltaXx2;
int errorterm;
deltaYx2 = deltaY*2;
deltaYx2minusdeltaXx2=deltaYx2-(int)(deltaX*2);
errorterm=deltaYx2-(int)deltaX;
writepixel(x0,y0,color);
while (deltaX--)
{
if (errorterm>=0)
{
y0++;
errorterm+=deltaYx2minusdeltaXx2;
}
else
errorterm+=deltaYx2;
x0+=Xdirection;
writepixel(x0,y0,color);
}
}
void static near Octant1(unsigned int x0,unsigned int y0,unsigned int deltaX,
unsigned int deltaY, int Xdirection, int color)
{
int deltaXx2;
int deltaXx2minusdeltaYx2;
int errorterm;
deltaXx2=deltaX*2;
deltaXx2minusdeltaYx2=deltaXx2-(int)(deltaY*2);
errorterm=deltaXx2-(int)deltaY;
writepixel(x0,y0,color);
while (deltaY--)
{
if (errorterm>=0)
{
x0+=Xdirection;
errorterm+=deltaXx2minusdeltaYx2;
}
else
errorterm+=deltaXx2;
y0++;
writepixel(x0,y0,color);
}
}
// **************************************************************************
// takes the initial call and manages the line drawing
// Adapted from "Power Graphics Programming", Michael Abrash
// **************************************************************************
void line(int x0, int y0, int x1, int y1, int color)
{
int deltaX, deltaY;
int temp;
if (y0>y1)
{
temp=y0;
y0=y1;
y1=temp;
temp=x0;
x0=x1;
x1=temp;
}
deltaX=x1-x0;
deltaY=y1-y0;
if (deltaX > 0)
{
if (deltaX>deltaY)
Octant0(x0,y0,deltaX,deltaY,1,color);
else
Octant1(x0,y0,deltaX,deltaY,1,color);
}
else
{
deltaX= -deltaX;
if (deltaX > deltaY)
Octant0(x0,y0,deltaX,deltaY,-1,color);
else
Octant1(x0,y0,deltaX,deltaY,-1,color);
}
}
// **************************************************************************
// getimage() grabs the pixel values in the rectangle marked by (x0,y0) on
// the top left, and (x1,y1) on the bottom right. The data is placed in buff.
//
// NOTE: This function needs translating into assembler
// **************************************************************************
void getimage(int x0, int y0, int x1, int y1, char far *buff)
{
int i;
int deltaY=(y1-y0);
int xdim=(x1-x0);
for (i=0;i<=deltaY;i++)
{
_fmemcpy((void *)&buff[i*xdim],xy_to_ptr(x0,(y0+i)),xdim);
}
}
// **************************************************************************
// putimage() copies the data in *buff to a rectangular area of the screen
// marked by (x0,y0) on the top left, and (x1,y1) on the bottom right.
//
// NOTE: This function needs translating into assembler
// **************************************************************************
void putimage(int x0, int y0, int x1, int y1, char far *buff)
{
int i;
int deltaY=(y1-y0);
int xdim=(x1-x0);
for (i=0;i<=deltaY;i++)
{
_fmemcpy(xy_to_ptr(x0,(y0+i)),(void *)&buff[i*xdim],xdim);
}
}
// *************************************************************************
// copyimage copies a rectangular image bounded by (x0, y0) at top left, and
// (x1, y1) at bottom right, to the video buffer at (putx, puty). The func-
// tion is very fast, suitable for copying blocks of a virtual screen into
// the physical screen for animation. It does no clipping, or checking for
// the vertical blanking interval. If using it to copy from system ram to
// the video buffer, make sure to pass a pointer to the buffer in src_buff,
// and set GRAPH_SEG = to the video buffer before the call.
// *************************************************************************
void copyimage(int x0, int y0, int x1, int y1, int putx, int puty,
void far *src_buf)
{
int deltaY=(y1-y0);
int xdim=(x1-x0);
asm {
mov es, GRAPH_SEG // establish GRAPH_SEG as destination seg
mov bx, 320 // increment value to move down one line
mov ax, puty // calculate the start of the first line
mul bx // for the destination
add ax, putx
mov di, ax
mov ax, y0 // caluclate the start of the first line
mul bx // for the source
add ax, x0
push ds
lds si, src_buf
add si, ax
mov dx, deltaY // set dx up as loop counter
cld // clear the direction flag
}
mainloop: // frame drawing loop
asm {
mov cx, xdim // cx == frame width in pixels
push si // save the line pointers
push di
shr cx, 1 // optimized copy
rep movsw
rcl cx, 1
rep movsb
pop di // restore the line pointers
pop si
add di, 320 // point to next line in source, dest
add si, 320
dec dx // adjust the loop counter
jnz mainloop
pop ds
}
}
// *************************************************************************
// doSplitVerticalWipe causes the picture in pic_buf to be displayed by
// wiping from left and right to the center. If called with a null pointer
// it will clear the screen using palette register 0. Waits for the vertical
// blanking interval, producing a smooth motion. This function really doesn't
// need to be done in assembler, as the vbi test is the limiting factor (see
// below)
// *************************************************************************
void doSplitVerticalWipe(void far *pic_buf)
{
unsigned leftx = 0;
unsigned rightx = 319;
unsigned run_y; // counts rows
char far *lsrc_ptr; // pointer to left column in source
char far *ldst_ptr; // pointer to left column in dest
char far *rsrc_ptr; // pointer to right column in source
char far *rdst_ptr; // pointer to right column in dest
if (pic_buf != NULL)
{
while (rightx > leftx)
{
ldst_ptr = (char far *)xy_to_ptr(leftx, 0);
lsrc_ptr = (char far *)pic_buf+leftx;
rdst_ptr = (char far *)xy_to_ptr(rightx, 0);
rsrc_ptr = (char far *)pic_buf+rightx;
wait_vbi();
for (run_y = 0; run_y < 200; run_y++)
{
*ldst_ptr = *lsrc_ptr;
*rdst_ptr = *rsrc_ptr;
ldst_ptr += 320;
lsrc_ptr += 320;
rdst_ptr += 320;
rsrc_ptr += 320;
}
leftx++;
rightx--;
}
}
else
{
while (rightx > leftx)
{
ldst_ptr = (char far *)xy_to_ptr(leftx, 0);
rdst_ptr = (char far *)xy_to_ptr(rightx, 0);
wait_vbi();
for (run_y = 0; run_y < 200; run_y++)
{
*ldst_ptr = 0;
*rdst_ptr = 0;
ldst_ptr += 320;
rdst_ptr += 320;
}
leftx++;
rightx--;
}
}
}
// **************************************************************************
// doSplitHorizWipe displays the picture in pic_buf by wiping it down from
// top and bottom. If it's called with a null pointer it clears the screen
// with palette register 0. Waits for vertical blanking interval, producing
// a smooth wipe. This function really didn't need to be done in assembler.
// I realized after I did it that the test for the vertical blanking interval
// was the limiting factor, not the execution time. Lessons learned! <g>.
//
// This function moves the image data by copying lines to the top and bottom
// of the screen alternately. The key to this process is the value in the
// unsigned integer adjust. In the setup es:di and ds:si are set up to point
// to the first line of the dest and source memory areas respectively. The
// adjust variable is intialized to 64000, which, when added to the offset of
// the first line, yields the offset of the last. Then adjust is decremented,
// and subtracted from the offset of the last line to get the offset of the
// second, and so on. The value of adjust is not used directly, but is loaded
// into the bx register. Keep an eye on si and di, as they are saved and
// restored quite often in all of these dissolve functions.
// **************************************************************************
void doSplitHorizWipe(void far *pic_buf)
{
unsigned adjust = 64000U; // used to adjust di and si
asm {
mov dx, input_status_1 // used to test for vbi later
mov cx, 200 // line counter
mov bx, adjust // bx stores adjust value
mov es, GRAPH_SEG // else get video segment into es
xor di, di // zero out the offset
push ds
lds si, pic_buf // get pic_buf into es:di
mov ax, ds // check for a null pointer
cmp ax,0
je clearscr // if it's null clear the screen
cld // clear the direction flag
}
mainloop1: // outer line loop
asm {
push cx // save loop counter
mov cx, 160 // move 160 words
push si // save offsets
push di
}
test_11: // these lines wait for vbi
asm {
in al, dx // first test, out of vbi
test al,0x8
jnz test_11
}
test_12:
asm {
in al, dx // second test, in vbi
test al,0x8
jz test_12
rep movsw // copy words to video segment
pop di // restore the original offsets
pop si
sub bx, 320 // take one line off of bx
add si, bx // add it to the offsets
add di, bx
mov cx, 160 // move 160 more words
push si // save the offsets
push di
rep movsw // copy the data to video seg
pop di // restore the offsets
pop si
sub bx, 320 // take 1 line off of bx
sub si, bx // subtract it from the offsets
sub di, bx
pop cx // restore the outer loop counter
loop mainloop1 // do next two lines
jmp done // skip the next part
}
clearscr:
asm cld; // clear the direction flag
mainloop2:
asm {
push cx // save the loop counter
mov cx, 160 // move 160 words
push di // save the offset
}
test_21: // these lines test for vbi
asm {
in al, dx // first test, out of vbi
test al,0x8
jnz test_21
}
test_22:
asm {
in al, dx // second test, in vbi
test al,0x8
jz test_22
xor ax, ax // clear ax, value to be stored==0
rep stosw // clear the line
pop di // restore the offset
sub bx, 320 // take one line from bx
add di, bx // add it to the offset
mov cx, 160 // mov 160 more words
push di // save the offset
rep stosw // copy the data to video buff
pop di // restore the offset
sub bx, 320 // take one line from bx
sub di, bx // subtract it from the offset
pop cx // restore the loop counter
loop mainloop2
}
done:
asm pop ds;
}
// **************************************************************************
// doSlideVerticalWipe causes the image in pic_buf to be displayed by sliding
// it in from both sides toward the center. Does not check pic_buff for a non
// null address. Waits for vertical blanking interval between writes, produc-
// ing a smooth image motion.
//
// This function basically captures frames from the left and right sides of
// the source image and displays them in the video buffer so that the image
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -