////////////////////////////////////////////////////////////////////////////// // // This file is part of the Atari Machine Specific Library, // and is Copyright 1992 by Warwick W. Allison. // // You are free to copy and modify these sources, provided you acknoledge // the origin by retaining this notice, and adhere to the conditions // described in the file COPYING. // ////////////////////////////////////////////////////////////////////////////// // I/O return values need work. Sorry - hacky 'game' mentality. #ifndef __OPTIMIZE__ #error "Due to register restrictions, this file must be optimized (-O)" #endif #include "sprite.h" #include "doublebuffer.h" #include Incarnation::Incarnation(short h, int b) : height(h), Backing(b) { } void Incarnation::SetHotSpot(short x, short y) { HotX=x; HotY=y; } void Sprite::Draw() { long* Back=BackingStore[Pages->Pulse]; *Back++=(long)Inca[shape]; Inca[shape]->Draw(x >> Shift,y >> Shift,Back); } int Sprite::TouchDraw() { long* Back=BackingStore[Pages->Pulse]; *Back++=(long)Inca[shape]; return Inca[shape]->TouchDraw(x >> Shift,y >> Shift,Back); } void Sprite::Wipe() { long *Back=BackingStore[Pages->Pulse]; Incarnation* OldInca=(Incarnation*)*Back; if (OldInca) { *Back++=0; OldInca->Wipe(Back); } } short LeftBits(unsigned short x) { for (int i=0; x; x<<=1) i++; return i; } short LongLeftBits(unsigned long x) { for (int i=0; x; x<<=1) i++; return i; } Sprite::Sprite(Sprite& Copy) { *this=Copy; BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; ExternalInca=TRUE; } Sprite::Sprite(Incarnation **List,int Count) { x=50; y=50; shape=0; BackingSize=2; // Nothing really for (int i=0; iBackingRequired() > BackingSize) BackingSize=List[i]->BackingRequired(); } BackingSize++; // For OldInca BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; OverlayMask=0; MaxInca=Count; Inca=List; ExternalInca=TRUE; } Sprite::Sprite(Incarnation *OnlyOne) { x=50; y=50; shape=0; BackingSize=OnlyOne->BackingRequired()+1; BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; OverlayMask=0; MaxInca=1; Inca=new Incarnation*[1]; Inca[0]=OnlyOne; ExternalInca=FALSE; } Sprite::Sprite(FILE *fp) : Inca(0) { if (!fget(fp)) { // ? } } Sprite::Sprite(const char *filename) { FILE* fp=fopen(filename,"rb"); fget(fp); if (!fclose(fp)) { // ? } } Sprite::Sprite(short maxinca) { x=50; y=50; shape=0; BackingSize=2; // Nothing really BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; OverlayMask=0; MaxInca=maxinca; Inca=new Incarnation*[MaxInca]; for (int i=0; iBackingRequired()+1) { BackingSize=In->BackingRequired()+1; delete BackingStore[0]; delete BackingStore[1]; BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; } Inca[i]=In; } #define READ(x) fread(&x,sizeof(x),1,fp) #define WRITE(x) fwrite(&x,sizeof(x),1,fp) Incarnation* IncarnationReader(FILE *fp) { short Tag; fread(&Tag,sizeof(Tag),1,fp); switch (Tag) { case 0: return new MonochromeIncarnation(fp); break; case 1: return new ColourIncarnation(fp); break; case 2: return new WideMonochromeIncarnation(fp); break; case 3: return new WideColourIncarnation(fp); break; case 4: return new PreshiftedMonochromeIncarnation(fp); break; case 5: return new PreshiftedColourIncarnation(fp); break; default: return 0; } } int Sprite::fget(FILE *fp) { fread(&x,sizeof(x),1,fp); fread(&y,sizeof(y),1,fp); fread(&shape,sizeof(shape),1,fp); fread(&Shift,sizeof(Shift),1,fp); if (Inca && !ExternalInca) { for (int i=0; iBackingRequired() > BackingSize) BackingSize=Inca[i]->BackingRequired(); } BackingSize++; // For OldInca BackingStore[0]=new long[BackingSize]; BackingStore[1]=new long[BackingSize]; BackingStore[0][0]=0; BackingStore[1][0]=0; ExternalInca=FALSE; return 1; } int Sprite::fput(FILE *fp) { fwrite(&x,sizeof(x),1,fp); fwrite(&y,sizeof(y),1,fp); fwrite(&shape,sizeof(shape),1,fp); fwrite(&Shift,sizeof(Shift),1,fp); fwrite(&MaxInca,sizeof(MaxInca),1,fp); for (int i=0; ifput(fp); } return 1; } int Sprite::Load(const char *filename) { FILE* fp=fopen(filename,"rb"); if (!fp) return 0; fget(fp); return fclose(fp); } int Sprite::Save(const char *filename) { FILE* fp=fopen(filename,"wb"); if (!fp) return 0; fput(fp); return fclose(fp); } MonochromeIncarnation::MonochromeIncarnation(int h) : Incarnation(h,h+2), Data(new unsigned short[h]), Mask(new unsigned short[h]) { } MonochromeIncarnation::~MonochromeIncarnation() { delete Data; delete Mask; } int Incarnation::fput(FILE *fp) { fwrite(&width,sizeof(width),1,fp); fwrite(&height,sizeof(height),1,fp); fwrite(&HotX,sizeof(HotX),1,fp); return (fwrite(&HotY,sizeof(HotY),1,fp)==1); } Incarnation::Incarnation(FILE *fp) { READ(width); READ(height); READ(HotX); READ(HotY); } int MonochromeIncarnation::fput(FILE *fp) { short tag=0; fwrite(&tag,sizeof(tag),1,fp); Incarnation::fput(fp); fwrite(Data,sizeof(*Data),height,fp); return (fwrite(Mask,sizeof(*Mask),height,fp)==height); } MonochromeIncarnation::MonochromeIncarnation(FILE *fp) : Incarnation(fp), Data(new unsigned short[height]), Mask(new unsigned short[height]) { Backing=height+2; fread(Data,sizeof(*Data),height,fp); fread(Mask,sizeof(*Mask),height,fp); } int MonochromeIncarnation::TouchDraw(short x, short y, long *Store) { return 0; } void MonochromeIncarnation::Draw(short x, short y, long *Store) { x-=HotX; y-=HotY; short LineSpacing=BytesPerLine[Pages->Current().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing + ((x>>4)<<1)); unsigned short shift = 16-(x&15); #ifdef NOASM unsigned short *D=Data; unsigned short *M=Mask; *(Store++)=(long)At; *(Store++)=(long)height-1; for (int h=0; hCurrent().Rez()]; #ifdef NOASM if (*Store) { long *At = (long*)*Store; *(Store++) = 0; for (int h=1+*(Store++); h; h--) { *At=*(Store++); At=(long*)((long)At+LineSpacing); } } #else asm(" movel %0@,d0 | Since moves to address regs don't change Z flag beq 1f movel d0,a0 clrl %0@+ movel %0@+,d0 0: movel %0@+,a0@ addl %1,a0 | next line on screen dbra d0,0b 1: " : : "a" (Store), "d" ((long)LineSpacing) : "d0", "a0" ); #endif } void MonochromeIncarnation::Wipe(long *Store) { SimpleMonoWipe(Store); } void MonochromeIncarnation::GetImage(Screen& S, int x, int y) { short LineSpacing=BytesPerLine[S.Rez()]; unsigned short *At=(unsigned short*)(S.Location()+y*LineSpacing+x/16*2); unsigned short *D,*M; unsigned short or=0; D=Data; M=Mask; for (int h=0; hCurrent().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing + x/16*2); #ifdef NOASM error("This is too hard to do without assembler"); #else short rshift=x&15; short lshift=16-rshift; asm(" movel %5,%2@+ | Save output address subl #1,%6 movel %6,%2@+ | Save Height-1 0: | Save scanline: movel %5@,%2@+ movew %5@(4),%2@+ | Get mask movel %1@+,d3 movew d3,d4 lsrl %4,d3 aslw %3,d4 notl d3 notw d4 | Draw scanline: movel %0@+,d1 movew d1,d2 lsrl %4,d1 aslw %3,d2 movew %5@(4),d0 | First the right end word andw d4,d0 orw d2,d0 movew d0,%5@(4) movel %5@,d0 | Then the left end long andl d3,d0 orl d1,d0 movel d0,%5@ addl %7,%5 | next line on screen dbra %6,0b " : : "a" (Data), "a" (Mask), "a" (Store), "d" (lshift), "d" (rshift), "a" (At), "d" ((long)height), "a" ((long)LineSpacing) : "d0", "d1", "d2", "d3", "d4" ); #endif } void WideMonochromeIncarnation::Wipe(long *Store) { short LineSpacing=BytesPerLine[Pages->Current().Rez()]; #ifdef NOASM error("Too hairy mixing long and short without ASM"); #else asm(" movel %0@,d0 | Since moves to address regs don't change Z flag beq 1f movel d0,a0 clrl %0@+ movel %0@+,d0 subl #4,%1 0: movel %0@+,a0@+ movew %0@+,a0@ addl %1,a0 | next line on screen dbra d0,0b 1: " : : "a" (Store), "d" ((long)LineSpacing) : "d0", "a0" ); #endif } void WideMonochromeIncarnation::GetImage(Screen& S, int x, int y) { short LineSpacing=BytesPerLine[S.Rez()]; unsigned long *At=(unsigned long*)(S.Location()+y*LineSpacing+x/16*2); unsigned long or=0,*D,*M; D=Data; M=Mask; for (int h=0; h>s; *SM++=~(*M++>>s); } } M=Mask[0]; for (int h=0; hCurrent().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing+((x>>4)<<1)); #ifdef NOASM unsigned long *D=Data[shift]; unsigned long *M=Mask[shift]; unsigned long m; *(Store++)=(long)At; *(Store++)=(long)height-1; for (int h=0; h>s; *SM++=~(*M++>>s); } } M=Mask[0]; for (h=0; hCurrent().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing+((x>>4)<<3)); #ifdef NOASM error("This is too hard to do without assembler"); #else short rshift=x&15; short lshift=16-rshift; asm(" movel %5,%2@+ | Save output address subl #1,%6 movel %6,%2@+ | Save Height-1 0: | Save scanline: movel %5@,%2@+ movel %5@(4),%2@+ movel %5@(8),%2@+ movel %5@(12),%2@+ movel %5@(16),%2@+ movel %5@(20),%2@+ | Get mask movel %1@+,d3 movew d3,d4 lsrl %4,d3 aslw %3,d4 notl d3 notw d4 | Draw scanline: movel %0@+,d1 movew d1,d2 lsrl %4,d1 aslw %3,d2 movew %5@(16),d0 | First the right end word andw d4,d0 orw d2,d0 movew d0,%5@(16) movew %5@,d0 | Then the left end long swap d0 movew %5@(8),d0 andl d3,d0 orl d1,d0 movew d0,%5@(8) swap d0 movew d0,%5@+ | Draw scanline: movel %0@+,d1 movew d1,d2 lsrl %4,d1 aslw %3,d2 movew %5@(16),d0 | First the right end word andw d4,d0 orw d2,d0 movew d0,%5@(16) movew %5@,d0 | Then the left end long swap d0 movew %5@(8),d0 andl d3,d0 orl d1,d0 movew d0,%5@(8) swap d0 movew d0,%5@+ | Draw scanline: movel %0@+,d1 movew d1,d2 lsrl %4,d1 aslw %3,d2 movew %5@(16),d0 | First the right end word andw d4,d0 orw d2,d0 movew d0,%5@(16) movew %5@,d0 | Then the left end long swap d0 movew %5@(8),d0 andl d3,d0 orl d1,d0 movew d0,%5@(8) swap d0 movew d0,%5@+ | Draw scanline: movel %0@+,d1 movew d1,d2 lsrl %4,d1 aslw %3,d2 movew %5@(16),d0 | First the right end word andw d4,d0 orw d2,d0 movew d0,%5@(16) movew %5@,d0 | Then the left end long swap d0 movew %5@(8),d0 andl d3,d0 orl d1,d0 movew d0,%5@(8) swap d0 movew d0,%5@+ addl %7,%5 | next line on screen subl #8,%5 dbra %6,0b " : : "a" (Data), "a" (Mask), "a" (Store), "d" (lshift), "d" (rshift), "a" (At), "d" ((long)height), "a" ((long)LineSpacing) : "d0", "d1", "d2", "d3", "d4" ); #endif } void WideColourIncarnation::Wipe(long *Store) { short LineSpacing=BytesPerLine[Pages->Current().Rez()]; #ifdef NOASM if (*Store) { long *At = (long*) *Store; *(Store++) = 0; for (int h=1+*(Store++); h; h--) { *At=*(Store++); At[1]=*(Store++); At[2]=*(Store++); At[3]=*(Store++); At[4]=*(Store++); At[5]=*(Store++); At=(long*)((long)At+LineSpacing); } } #else asm(" movel %0@,d0 | Since moves to address regs don't change Z flag beq 1f movel d0,a0 clrl %0@+ movel %0@+,d0 subl #20,%1 0: movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@ addl %1,a0 | next line on screen dbra d0,0b 1: " : : "a" (Store), "d" ((long)LineSpacing) : "d0", "a0" ); #endif } void WideColourIncarnation::GetImage(Screen& S, int x, int y) { short LineSpacing=BytesPerLine[S.Rez()]; unsigned short *At=(unsigned short*)(S.Location()+y*LineSpacing+x/16*8); unsigned long or=0,*D,*M; D=Data; M=Mask; for (int h=0; hCurrent().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing+((x>>4)<<3)); #ifdef NOASM unsigned short *D=Data; unsigned short *M=Mask; unsigned long m1,m2,d1,d2,t1,t2,t3,t4; *(Store++)=(long)At; *(Store++)=(long)height-1; for (int h=0; h> 16); m2=((t1 & 0x0000ffff) << 16) | (t1 & 0x0000ffff); *(Store++)=*At; *(Store++)=At[1]; *(Store++)=At[2]; *(Store++)=At[3]; t1=((long)*(D++)) << shift; t2=((long)*(D++)) << shift; t3=((long)*(D++)) << shift; t4=((long)*(D++)) << shift; d1=(t1 & 0xffff0000) | ((t2 & 0xffff0000) >> 16); d2=((t1 & 0x0000ffff) << 16) | (t2 & 0x0000ffff); At[0]=(At[0] & m1) | d1; At[2]=(At[2] & m2) | d2; d1=(t3 & 0xffff0000) | ((t4 & 0xffff0000) >> 16); d2=((t3 & 0x0000ffff) << 16) | (t4 & 0x0000ffff); At[1]=(At[1] & m1) | d1; At[3]=(At[3] & m2) | d2; At=(long*)((long)At+LineSpacing); } #else asm(" movel %4,%2@+ | Save output address subl #1,%5 movel %5,%2@+ | Save Height-1 0: | Save scanline: movel %4@,%2@+ movel %4@(4),%2@+ movel %4@(8),%2@+ movel %4@(12),%2@+ | Get mask clrl d1 movew %1@+,d1 asll %3,d1 notl d1 | Draw scanline: Word 1 clrl d0 movew %0@+,d0 asll %3,d0 movew %4@,d4 swap d4 movew %4@(8),d4 andl d1,d4 orl d0,d4 movew d4,%4@(8) swap d4 movew d4,%4@+ | Draw scanline: Word 2 clrl d0 movew %0@+,d0 asll %3,d0 movew %4@,d4 swap d4 movew %4@(8),d4 andl d1,d4 orl d0,d4 movew d4,%4@(8) swap d4 movew d4,%4@+ | Draw scanline: Word 3 clrl d0 movew %0@+,d0 asll %3,d0 movew %4@,d4 swap d4 movew %4@(8),d4 andl d1,d4 orl d0,d4 movew d4,%4@(8) swap d4 movew d4,%4@+ | Draw scanline: Word 4 clrl d0 movew %0@+,d0 asll %3,d0 movew %4@,d4 swap d4 movew %4@(8),d4 andl d1,d4 orl d0,d4 movew d4,%4@(8) swap d4 movew d4,%4@+ addl %6,%4 | next line on screen subl #8,%4 dbra %5,0b " : : "a" (Data), "a" (Mask), "a" (Store), "d" (shift), "a" (At), "d" ((long)height), "d" ((long)LineSpacing) : "d0", "d1", "d4" ); #endif } void SimpleWipe(long *Store) { short LineSpacing=BytesPerLine[Pages->Current().Rez()]; #ifdef NOASM if (*Store) { long *At = (long*) *Store; *(Store++) = 0; for (int h=1+*(Store++); h; h--) { *At=*(Store++); At[1]=*(Store++); At[2]=*(Store++); At[3]=*(Store++); At=(long*)((long)At+LineSpacing); } } #else asm(" movel %0@,d0 | Since moves to address regs don't change Z flag beq 1f movel d0,a0 clrl %0@+ movel %0@+,d0 subl #12,%1 0: movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@+ movel %0@+,a0@ addl %1,a0 | next line on screen dbra d0,0b 1: " : : "a" (Store), "d" ((long)LineSpacing) : "d0", "a0" ); #endif } void ColourIncarnation::Wipe(long *Store) { SimpleWipe(Store); } void ColourIncarnation::GetImage(Screen& S, int x, int y) { short LineSpacing=BytesPerLine[S.Rez()]; unsigned short *At=(unsigned short*)(S.Location()+y*LineSpacing+x/16*8); unsigned short or=0,*D,*M; D=Data; M=Mask; for (int h=0; h>16; SD[bp+4]=t&0xffff; } SD+=8; D+=8; t=((unsigned long)*M++ << (16-s)); M++; *SM++=~(t>>16); *SM++=~(t&0xffff); } } M=Mask[0]; for (h=0; hCurrent().Rez()]; long *At = (long*)(Pages->Location() + y*LineSpacing+((x>>4)<<3)); #ifdef NOASM unsigned short *D=Data[shift]; unsigned short *M=Mask[shift]; unsigned long m; *(Store++)=(long)At; *(Store++)=(long)height-1; for (int h=0; h>16; SD[bp+4]=t&0xffff; } SD+=8; D+=8; t=((unsigned long)*M++ << (16-s)); M++; *SM++=~(t>>16); *SM++=~(t&0xffff); } } M=Mask[0]; for (h=0; h> 8; } break; case Wrap: if (X()MaxX) { switch (AtEdge[2]) { case Bounce: xi=-xi; MoveTo(MaxX-Width(),Y()); if (Bounciness!=256) { xi=long(xi*Bounciness) >> 8; } break; case Wrap: if (X()> 8; } break; case Wrap: if (Y()MaxY) { switch (AtEdge[1]) { case Bounce: yi=-yi; MoveTo(X(),MaxY-Height()); if (Bounciness!=256) { yi=long(yi*Bounciness) >> 8; } break; case Wrap: if (Y()0 || Walls&HitWest && xi<0) { xi=-xi; MoveBy(xi,0); if (Bounciness!=256) { xi=long(xi*Bounciness) >> 8; } } if (Walls&HitNorth && yi<0 || Walls&HitSouth && yi>0) { yi=-yi; MoveBy(0,yi); if (Bounciness!=256) { yi=long(yi*Bounciness) >> 8; } } } void MobileSprite::AtBoundary(BoundaryEffect b, short Bouncy=256) { for (int i=0; i<4; i++) AtEdge[i]=b; Bounciness=Bouncy; } void MobileSprite::AtBoundary(BoundaryEffect N, BoundaryEffect S, BoundaryEffect E, BoundaryEffect W, short Bouncy=256) { AtEdge[0]=N; AtEdge[1]=S; AtEdge[2]=E; AtEdge[3]=W; Bounciness=Bouncy; }