/******************************************************************************* * Screamer.CPP source code... * Mode 0x13 graphics library... * Written by S. Cartwright 1997... * Updates... * 25/9/97 Remove CPP class's to increase speed of exe. * 28/9/97 Redundant code removed from source code. * 30/10/97 Added screen_buffer to _frame commands to allow output to * something other than the screen. * 10/12/97 Fixed bug for variable declarations... * E.g. char huge* a,* b; to... char huge* a, huge* b; * 11/12/98 Fixed screen corruption of _frame commands by +4 due to the 32bit block_screen alteration. *******************************************************************************/ #include "screamer.h" //#define _FRAME 0 //A place for storing different pages of video RAM. unsigned char huge *buffers=0,huge *buffbak=0; //Makes *screen a huge ptr to the screen RAM. //static char huge *screen=(char huge*)MK_FP(0xA000,0); unsigned char far *screen=(unsigned char far*)MK_FP(0xA000,0); //Sprites . . . unsigned char huge *spdata=0; static unsigned long int sprptr=0; spritedata *SPRITE,*_SPRITE; /* For SPRITE DELETE....... Store size of SAT somewhere, so we can search it for sprites stored after the one we deleted! e.g, (here) static unsigned int SAT_size=0; (then in ini_sprite): SAT_size=number; (and in del_sprite) for(int a=0;a>8; if((dir&1)==1) {left[0]=1;}else{left[0]=0;} if((dir&2)==2) {right[0]=1;}else{right[0]=0;} if((acce&2)==2) {acc[0]=1;}else{acc[0]=0;} if((dir&8)==8) {left[1]=1;}else{left[1]=0;} if((dir&4)==4) {right[1]=1;}else{right[1]=0;} if((acce&1)==1) {acc[1]=1;}else{acc[1]=0;} } void set_mode(byte mode) { asm mov ah,0x00 asm mov al,mode asm int 0x10 } void ppixelxor(int x,long int y,byte color,unsigned char huge *address) { short unsigned int xcol,ncol; ncol=color; y=((y << 8) + (y << 6) + x); // y=((y<<2)+y)<<6; // y+=x; xcol=*(address+y); asm mov xcol,ax asm xor ax,ncol asm mov ncol,ax *(address+y)=ncol; } void ppixel(int x,long int y,byte color,unsigned char huge *address) { // y=((y<<2)+y)<<6; // y+=x; *(address+(((y)<<8)+((y)<<6) + (x)))=color; } int gpixel(int x,long int y,unsigned char huge *address) { // y=((y<<2)+y)<<6; // y+=x; return(*(address+(((y)<<8)+((y)<<6)+(x)))); } void swap(int *f, int *s) { int t; t=*f; *f=*s; *s=t; } void circle(word x,word y,word radius,byte col,int page) { int a, af, b, bf, target, r2, asp; unsigned char huge *add=buffers; if(page==255){add=screen;}else{add+=(page*64000l);} asp=120; target=0; a=radius; b=0; r2=Sqr(radius); while(a>=b) { b=Round(sqrt(r2-Sqr(a))); swap(&target,&b); while(b> 1; while(x1 != x2) { ppixel(x1, y1, col,add); Cycle+=ShDelta; if(Cycle>LgDelta) { Cycle-=LgDelta; y1+=ShStep; } x1+=LgStep; } ppixel(x1, y1, col,add); } else { Cycle=ShDelta >> 1; swap(&LgDelta, &ShDelta); swap(&LgStep, &ShStep); while(y1 != y2) { ppixel(x1, y1, col,add); Cycle+=ShDelta; if(Cycle>LgDelta) { Cycle-=LgDelta; x1+=ShStep; } y1+=LgStep; } ppixel(x1, y1, col,add); } } void triangle_noclip(int x1,int y1,int x2,int y2,int x3,int y3,int col,int page) { float xstep1,xstep2,xstep3,xpos1,xpos2,xx1,xx2,di1=0,di2=0,di3=0; float xx[3]={x1,x2,x3},yy[3]={y1,y2,y3}; int yloop,tmp; int top=0,mid=1,bot=2,x; unsigned char huge *add=buffers; if(page==255){add=screen;}else{add+=(page*64000l);} if(yy[top]>yy[mid]) {tmp=mid; mid=top; top=tmp;} if(yy[top]>yy[bot]) {tmp=bot; bot=top; top=tmp;} if(yy[mid]>yy[bot]) {tmp=bot; bot=mid; mid=tmp;} xpos1=xx[top]; xpos2=xx[top]; di1=yy[top]-yy[bot]; di2=yy[top]-yy[mid]; di3=yy[mid]-yy[bot]; if(di1!=0) xstep1=(xx[top]-xx[bot])/di1; if(di2!=0) {xstep2=(xx[top]-xx[mid])/di2;} else {xpos2-=xx[top]-xx[mid];} if(di3!=0) xstep3=(xx[mid]-xx[bot])/di3; add+=(((long int)yy[top]<<2)+(long int)yy[top])<<6; for(yloop=yy[top];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} for(x=xx1;x<=xx2;x++) { *(add+x)=col; } add+=320; xpos1+=xstep1; xpos2+=xstep2; } for(yloop=yy[mid];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} for(x=xx1;x<=xx2;x++) { *(add+x)=col; } add+=320; xpos1+=xstep1; xpos2+=xstep3; } } void triangle(int x1,int y1,int x2,int y2,int x3,int y3,int col,int page) { float xstep1,xstep2,xstep3,xpos1,xpos2,xx1,xx2,di1=0,di2=0,di3=0; float xx[3]={x1,x2,x3},yy[3]={y1,y2,y3}; int yloop,tmp,trans=0; int top=0,mid=1,bot=2,x; unsigned char huge *add=buffers; if(col<0) {col=col*-1; trans=1;} if(page==255){add=screen;}else{add+=(page*64000l);} if(yy[top]>yy[mid]) {tmp=mid; mid=top; top=tmp;} if(yy[top]>yy[bot]) {tmp=bot; bot=top; top=tmp;} if(yy[mid]>yy[bot]) {tmp=bot; bot=mid; mid=tmp;} xpos1=xx[top]; xpos2=xx[top]; di1=yy[top]-yy[bot]; di2=yy[top]-yy[mid]; di3=yy[mid]-yy[bot]; if(di1!=0) xstep1=(xx[top]-xx[bot])/di1; else xstep1=0; if(di2!=0) { xstep2=(xx[top]-xx[mid])/di2; } else { xpos2-=xx[top]-xx[mid]; xstep2=0; } if(di3!=0) xstep3=(xx[mid]-xx[bot])/di3; else xstep3=0; if(yy[bot]>200) yy[bot]=200; if(yy[mid]>200) yy[mid]=200; if(yy[top]<0) { if(yy[mid]<0) { xpos1+=(yy[top]*-1)*xstep1; xpos2+=(di2*-1)*xstep2; xpos2+=(yy[mid]*-1)*xstep3; yy[top]=0; yy[mid]=0; } else { xpos1+=(yy[top]*-1)*xstep1; xpos2+=(yy[top]*-1)*xstep2; yy[top]=0; } } add+=(((long int)yy[top]<<2)+(long int)yy[top])<<6; if(trans==0) { for(yloop=yy[top];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} if(xx1<0) xx1=0; if(xx2>319) xx2=319; if(xx1<=xx2) { for(x=xx1;x<=xx2;x++) { *(add+x)=col; } } add+=320; xpos1+=xstep1; xpos2+=xstep2; } if(yy[mid]==200) return; for(yloop=yy[mid];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} if(xx1<0) xx1=0; if(xx2>319) xx2=319; if(xx1<=xx2) { for(x=xx1;x<=xx2;x++) { *(add+x)=col; } } add+=320; xpos1+=xstep1; xpos2+=xstep3; } } else { for(yloop=yy[top];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} if(xx1<0) xx1=0; if(xx2>319) xx2=319; if(xx1<=xx2) { for(x=xx1;x<=xx2;x++) { if((((int)(x+yloop)/2)*2==(int)(x+yloop))) *(add+x)=col; } } add+=320; xpos1+=xstep1; xpos2+=xstep2; } if(yy[mid]==200) return; for(yloop=yy[mid];yloopxx2){tmp=xx1; xx1=xx2; xx2=tmp;} if(xx1<0) xx1=0; if(xx2>319) xx2=319; if(xx1<=xx2) { for(x=xx1;x<=xx2;x++) { if((((int)(x+yloop)/2)*2==(int)(x+yloop)))*(add+x)=col; } } add+=320; xpos1+=xstep1; xpos2+=xstep3; } } } void plot(int op,int xplot,int yplot,int col,int page) { static px[3]={0,0,0}, py[3]={0,0,0}; px[0]=px[1]; py[0]=py[1]; px[1]=px[2]; py[1]=py[2]; px[2]=xplot ; py[2]=yplot; switch(op) { case 5: draw(px[2],py[2],px[1],py[1],col,page);break; case 85: triangle(px[0],py[0],px[1],py[1],px[2],py[2],col,page); break; case 89: draw(px[0],py[0],px[1],py[1],col,page); draw(px[1],py[1],px[2],py[2],col,page); draw(px[2],py[2],px[0],py[0],col,page); break; default: ;break;// Do nothing!!! } } void change_col(unsigned int cc,unsigned int cr,unsigned int cg,unsigned int cb) { outp(0x3c6,0xfff); outp(0x3c8,cc);outp(0x3c9,cr);outp(0x3c9,cg);outp(0x3c9,cb); } void exitgraph() { set_mode(3); } void movedw(void *a, void *b, int l) { asm CLI asm CLD asm PUSH DS asm LDS SI, a asm LES DI, b asm MOV CX, l asm DB 0x66; asm REP MOVSW asm POP DS asm STI } void clear_screen(unsigned int col,int page) { unsigned char huge *saddr1, huge* saddr2; unsigned long int p=page*64000l; if(page==255) {saddr1=screen;saddr2=screen+4;} else {saddr1=buffers+p;saddr2=buffers+p+4;} *(saddr1)=col; *(saddr1+1)=col; *(saddr1+2)=col; *(saddr1+3)=col; movedw(saddr1,saddr2,15999); /* asm CLI asm CLD asm PUSH DS asm LDS SI, saddr1 asm LES DI, saddr2 asm MOV CX, xlen asm DB 0x66; asm REP MOVSW asm POP DS asm STI */ /*asm CLI asm CLD asm LES DI, addr asm MOV CX, 16000 asm DB 0x66 asm MOV AX, WORD PTR c1 asm DB 0x66 asm REP STOSW asm STI*/ //for(pos=0;pos<64000l;pos++) *(add+pos)=col; } void ini_screen(int buff,int quiet) { int c=0; unsigned long int memb=0; if(quiet==0) printf("\nInitialising screen buffers; %d @ 64000 bytes...",buff); memb=64000l*buff; if((buffers=(unsigned char huge*) farmalloc(memb))==NULL) { printf("\nNot enough memory for screen pages!");getch;exit(1); } buffbak=buffers; if(quiet==0) printf("O.K!...\nClearing buffer: "); for(c=0;c=0;y--) { pos-=640; for(x=0;x<320;x++) { col=(int) fgetc(stream); *(buffers+pos++)=col; } } fclose(stream); buffers=buffbak; } void compress_screen(char *name,int page1,int page2,int seed) { //The picture to 0 compress goes in screen 0, output in 1. FILE *out,*in; unsigned long int off1=page1*64000l; unsigned long int off2=page2*64000l; unsigned char huge *sadd1, huge *sadd2; char loadname[15],savename[15],handle[32]="ASS File Format (C)1999 Lab_Rat"; long int read=0,write=0,store=0; int counter=0,xor=0; unsigned int byte; sadd1=buffers+off1; sadd2=buffers+off2; if(page1==255) sadd1=screen; if(page2==255) sadd2=screen; srand(seed); strcpy(loadname,name); strcpy(savename,name); strcat(loadname,".TGA"); strcat(savename,".ASS"); load_screen(loadname,0,0); for(read;read<64000l;read++) { byte=*(sadd1+read); //Is it a zero? if(byte==0) { //The byte==0, so check if it is the first one weve found, if it is, store it. if(counter==0) { *(sadd2+write)=xor;//Byte or 0, doesnt matter. xor=rand()%256; write++; if(write==64000l) {printf("Unable to compress picture!");getch();exit(1);} } counter++; //Does counter== maximum allowed or the end of the file? if((counter==255)||(read==63999l)) { //Yes, so store the number of zeros counted, and reset counter *(sadd2+write)=counter^xor; xor=rand()%256; write++; if(write==64000l) {printf("Unable to compress picture!");getch();exit(1);} counter=0; } //Otherwise ignore... } else { //Byte is not a zero, but have we been counting zeros? if(counter!=0) { //Yes! //Store the number of zeros, and reset counter *(sadd2+write)=counter^xor; xor=rand()%256; write++; if(write==64000l) {printf("Unable to compress picture!");getch();exit(1);} counter=0; } //No, so just store the byte *(sadd2+write)=byte^xor; xor=rand()%256; write++; if(write==64000l) {printf("Unable to compress picture!");getch();exit(1);} } } //Now write stores the length of the compressed image. //So save it to disc with pallette information. if((out=fopen(savename, "wb"))==NULL) {printf("cant open to save\n");getch();exit(1);} if((in=fopen(loadname, "rb"))==NULL) {printf("cant open to load\n");getch();exit(1);} if(fseek(in, 18, SEEK_SET)!=0) {printf("Cant seek!");getch();exit(1);} fwrite(handle,32,1,out); //First store colours... srand(seed); for(store=0;store<256;store++) { fputc(fgetc(in),out); fputc(fgetc(in),out); fputc(fgetc(in),out); } for(store=0;store=0;y--) { pos-=640; for(x=0;x<320;x++) { col=*(buffers+pos++); ppixel(x,y,col,screen); lin[x]=col; } for(y2=y;y2>=0;y2--) { for(x=0;x<320;x++) { ppixel(x,y2,lin[x],screen); } } delay(10); } } void ig_slide_col(int x,int topy,int pixel) { register y; unsigned long int pos=64000l-(320-x); unsigned char far *splodge = screen; // This is used with the pixel move statement inside the for loop if it is new line - IforG for( y=199; y>topy; y-- ) // Alteration we talked about where the number of pixels moved decreases - IforG { *(splodge+(int)pos)=*((splodge+(int)pos)-320); // Use this line instead of above line so that it use far pointers not huge pointers pos-=320; // this makes the calculations alot quicker - IforG } *(splodge+(int)pos)=pixel; //if(topy==199) {*(splodge+(int)pos)=rand()%10;getch();} } void slide_screen(int effect,int from_page) { int a; float sinf,ang; int sini,maxcount[320],count[320]; int moved[320]; int col[320]; int left = 0; unsigned char huge *colpos; // if(from_page==255) // { // printf("\nTrying to pour screen onto itself!");getch;exit(1); // } colpos=buffers+(64000l*from_page); // for(a=0;a<320;a++) // { // ppixel(a, (long) 0, (long) 0,screen); // } randomize(); switch(effect) { case 0: for(a=0;a<320;a++) { ang=a*2; ang/=180; ang*=3.141; sinf=sin(ang); sini=(int)abs((sinf*10)); maxcount[a]=10+(rand() % (sini+1)); count[a]=maxcount[a]; moved[a]=0; col[a] = a; } break; case 1:for(a=0;a<320;a++) { sinf=sin(a*2.0/180*3.141); sini=(int)abs((sinf*20.0)); maxcount[a]=sini+10; count[a]=maxcount[a]; moved[a]=0; col[a] = a; } break; default:for(a=0;a<160;a++) { count[a+160]=160-a; maxcount[a+160]=160-a; count[a]=a+1; maxcount[a]=a+1; moved[a]=0; col[a] = a; moved[a+160]=0; col[a+160] = a+160; } } if(from_page!=255) { while ( left < 320 ) { for ( a = left; a < 320; a++ ) { if ( count[a]-- == 0 ) { ig_slide_col(col[a], moved[a],*(colpos+(unsigned long int)col[a]+(unsigned long int)(moved[a]*320l))); count[a] = maxcount[a]; if ( ++moved[a] == 200 ) { col[a] = col[left]; count[a]=count[left]; maxcount[a]=maxcount[left]; moved[a] = moved[left++]; }//End if moved<200 }//End if count[a]==0 }// Next A }// End While }// End func() else { while ( left < 320 ) { for ( a = left; a < 320; a++ ) { if ( count[a]-- == 0 ) { ig_slide_col(col[a], moved[a],0); count[a] = maxcount[a]; if ( ++moved[a] == 200 ) { col[a] = col[left]; count[a]=count[left]; maxcount[a]=maxcount[left]; moved[a] = moved[left++]; }//End if moved<200 }//End if count[a]==0 }// Next A }// End While }//End if } void end_screen(void) { farfree(buffers); exitgraph(); } void end_sprite(void) { farfree(spdata); free(_SPRITE); } void end_pal(void) { farfree(palpos); } void ini_sprite(int number,int quiet) { int a; if(quiet==0) printf("\nCreating Sprite Allocation Table for %d sprites...",number); if((_SPRITE=(spritedata*) calloc(number,sizeof(spritedata)))==NULL) { printf("\nUnable to claim memory for SAT!");getch();exit(1); } SPRITE=_SPRITE; for(a=0;axlen=-1; SPRITE->ylen=-1; SPRITE->len=-1; SPRITE->add=-1; SPRITE++; } if(quiet==0) printf("O.K!"); } void add_sprite(int x,long int y,int xlen,int ylen,int sprite,int page) { unsigned char huge *add,huge *oldptr; unsigned long int p=page*64000l,oldsprptr; long int xpos,ypos; int length; add=buffers+p; if(page==255) add=screen; //'add' now points to page position of sprite...(Vid RAM, Or normal RAM) //Find out how big our sprite is... length=xlen*ylen; //Update the SAT (Sprite Allocation Table) SPRITE=_SPRITE; SPRITE+=sprite; SPRITE->xlen=xlen; SPRITE->ylen=ylen; SPRITE->len=length; SPRITE->add=sprptr; //Allocate memory for sprite... oldsprptr=sprptr; sprptr+=length; if((spdata=(unsigned char huge*)farrealloc(spdata,sprptr))==NULL) { printf("\nRequest: add_sprite(%p",SPRITE); printf(",%d",x); printf(",%d",y); printf(",%d",xlen); printf(",%d",ylen); printf(",%d,",sprite); if(page==255) printf("screen"); else printf("%d",page); printf(") failed!\nUnable to allocate memory!\a");getch();exit(1); } oldptr=spdata+oldsprptr; //Actually place the sprite into the sprite pool... p=0; add+=((y<<2)+y)<<6; add+=x; for(ypos=y;yposxlen; ylen=SPRITE->ylen; oldptr=buffers+SPRITE->add; //Actually replace the sprite into the sprite pool... p=0; add+=((y<<2)+y)<<6; add+=x; for(ypos=y;yposxlen; if(page==255) add=screen; add+=((y<<2)+y)<<6; add+=x; spradd=spdata+SPRITE->add; for(ypos=0;yposylen;ypos++) { for(xpos=0;xposxlen;xpos++) { *(add++)=*(spradd++); } add+=length; } } //Put an unclipped MASKED sprite to a page... void putm_sprite(int x,long int y,int sprite,int page) { unsigned char huge *add,huge *spradd; long int length=0; long int xpos,ypos; unsigned long int p=page*64000l; add=buffers+p; SPRITE=_SPRITE; SPRITE+=sprite; length=320-SPRITE->xlen; if(page==255) add=screen; add+=((y<<2)+y)<<6; add+=x; spradd=spdata+SPRITE->add; for(ypos=0;yposylen;ypos++) { for(xpos=0;xposxlen;xpos++) { if(*(spradd)!=0) *(add)=*(spradd); add++;spradd++; } add+=length; } } //Put an unclipped MASKED sprite to a page, behind things... void putmb_sprite(int x,long int y,int sprite,int page) { unsigned char huge *add,huge *spradd; long int length=0; long int xpos,ypos; unsigned long int p=page*64000l; add=buffers+p; SPRITE=_SPRITE; SPRITE+=sprite; length=320-SPRITE->xlen; if(page==255) add=screen; add+=((y<<2)+y)<<6; add+=x; spradd=spdata+SPRITE->add; for(ypos=0;yposylen;ypos++) { for(xpos=0;xposxlen;xpos++) { if(*(add)==0) *(add)=*(spradd); add++;spradd++; } add+=length; } } //Put a CLIPPED UNMASKED sprite to a page... void putc_sprite(int screenx,int screeny,int screenxend,int screenyend,int spritex,int spritey,int sprite,int page) { long int spritexend,spriteyend; long int clipx,clipxend,clipyend; long int clipy; long int xx,yy; long int leftinc=0,rightinc=0,screeninc; unsigned char huge *add,huge *spradd; unsigned long int p=page*64000l; SPRITE=_SPRITE; SPRITE+=sprite; spritexend=spritex+SPRITE->xlen; spriteyend=spritey+SPRITE->ylen; clipx=spritex; clipxend=spritexend; clipyend=spriteyend; clipy=spritey; screeninc=320-SPRITE->xlen; spradd=spdata+SPRITE->add; screenxend++;screenyend++; if(spritexxlen-leftinc); } if(spriteyxlen; clipy=screeny; } if(spritexend>screenxend) { rightinc=spritexend-screenxend; clipxend=screenxend; screeninc=320-(SPRITE->xlen-rightinc); } if(spriteyend>screenyend) clipyend=screenyend; if(page==255) {add=screen;} else {add=buffers+p;} add+=((clipy<<2)+clipy)<<6; add+=clipx; for(yy=clipy;yyxlen; spriteyend=spritey+SPRITE->ylen; clipx=spritex; clipxend=spritexend; clipyend=spriteyend; clipy=spritey; screeninc=320-SPRITE->xlen; spradd=spdata+SPRITE->add; screenxend++;screenyend++; if(spritexxlen-leftinc); } if(spriteyxlen; clipy=screeny; } if(spritexend>screenxend) { rightinc=spritexend-screenxend; clipxend=screenxend; screeninc=320-(SPRITE->xlen-rightinc); } if(spriteyend>screenyend) clipyend=screenyend; if(page==255) {add=screen;} else {add=buffers+p;} add+=((clipy<<2)+clipy)<<6; add+=clipx; for(yy=clipy;yyxlen*scalex)+0.5); spriteyend=spritey+int((SPRITE->ylen*scaley)-0.5); clipx=spritex; clipxend=spritexend; clipyend=spriteyend; clipy=spritey; screeninc=320-int((SPRITE->xlen*scalex)+0.5); spradd=spdata+SPRITE->add; screenxend++;screenyend++; if(spritexxlen*scalex)-(screenx-spritex))); } if(spriteyscreenxend) { rightinc=int((float)(spritexend-screenxend)*(1.0/scalex)); clipxend=screenxend; screeninc=320-((int(0.5+SPRITE->xlen*scalex)-(spritexend-screenxend))); } if((spritexscreenxend)) screeninc=0; if(spriteyend>screenyend) clipyend=screenyend; if(page==255) {add=screen;} else {add=buffers+p;} add+=((clipy<<2)+clipy)<<6; add+=clipx; for(yy=clipy;yyxlen*int(posy/scaley)); scalepos+=leftinc; for(xx=clipx;xxlen; sprite_block_length=sprptr; sprite_image_start=SPRITE->add; // sprite_block_length = LENGTH OF THE SPRITE BLOCK. // spdata = MEMORY ADDRESS OF SPRITE BLOCK. // sprite_image_length = LENGTH IN BYTES OF SPRITE IMAGE. // sprite_image_start = START OFFSET IN BYTES FOR SPRITE IMAGE. //Step 1: Physically remove sprite from sprite block. for(long int index=sprite_image_start;index