/* * QT AGI Studio :: Copyright (C) 2000 Helen Zommer * * Part of this code is adapted from Peter Kelly's viewview.pas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "game.h" #include "view.h" #include "viewedit.h" #include "menu.h" #include #include #ifndef _WIN32 #include #endif #include #include #include #include static int ResPos,DescPos,ResSize; //************************************************** View::View() { Description = ""; loops = NULL; opened = false; } //************************************************** void View::init() { ReadViewInfo(); CurLoop = 0; CurCel = 0; opened = true; } //************************************************* int View::open(char *filename) { FILE *fptr = fopen(filename,"rb"); if(fptr==NULL){ menu->errmes("Can't open file %s ! ",filename); return 1; } struct stat buf; fstat(fileno(fptr),&buf); ResourceData.Size=buf.st_size; fread(ResourceData.Data,ResourceData.Size,1,fptr); fclose(fptr); init(); return 0; } //************************************************** int View::open(int ResNum) { int err = game->ReadResource(VIEW,ResNum); if(err)return 1; init(); return 0; } //************************************************* static byte ReadByte(void) { if(ResPos < ResourceData.Size){ return ResourceData.Data[ResPos++]; } return 0; } //************************************************** static int ReadLSMSWord(void) { byte MSbyte,LSbyte; LSbyte = ReadByte(); MSbyte = ReadByte(); return (LSbyte + MSbyte*256); } //************************************************** static void SeekRes(int seekpos) { if (seekpos>=0 && seekpos<=ResourceData.Size-1){ ResPos = seekpos; } } //************************************************* void View::ReadViewInfo() { int CurLoop,CurCel,NumCels,curbyte,i,cel_width,cel_height,cel_transcol; bool cel_mirror; NumLoops=0; CurLoop = 0; CurCel = 0; SeekRes(2); NumLoops = ReadByte(); loops = new Loop[NumLoops]; Description = ""; DescPos = ReadLSMSWord(); if (DescPos > 0){ SeekRes(DescPos); curbyte=1; while(curbyte != 0){ curbyte = ReadByte(); if(curbyte !=0){ if(curbyte==0x0a) Description.append("\\n"); else Description.append(1,(char)curbyte); } } } SeekRes(5); for(CurLoop=0;CurLoop= 0x80) cel_mirror= true; else cel_mirror = false; loops[CurLoop].cel(CurCel,cel_width,cel_height,cel_transcol,cel_mirror); LoadCel(CurLoop,CurCel); } } } //************************************************* void View::LoadCel(int loopno,int celno){ int i0,i1,celX,celY,ChunkLength,ChunkCol,Width, Height,transcol; byte k,curbyte; bool mirror; Width = loops[loopno].cels[celno].width; Height = loops[loopno].cels[celno].height; transcol = loops[loopno].cels[celno].transcol; mirror = loops[loopno].cels[celno].mirror; SeekRes(loops[loopno].LoopLoc+loops[loopno].CelLoc[celno]+3); celX = 0; celY = 0; while(celY != Height){ curbyte = ReadByte(); if (curbyte > 0){ ChunkCol = (curbyte & 0xF0) / 0x10; ChunkLength = curbyte & 0x0F; i0=celX; i1=i0+ChunkLength*2-1; for(celX=i0;celX<=i1;celX++){ loops[loopno].cels[celno].data[celY*Width*2+celX] = ChunkCol; } } else{ for(;celXerrmes("Can't open file %s ! ",filename); return 1; } save(); fwrite(ResourceData.Data,ResourceData.Size,1,fptr); fclose(fptr); return 0; } //************************************************* int View::save(int ResNum) { save(); return(game->AddResource(VIEW,ResNum)); } //************************************************* void WriteByte(byte b) { if(ResPos >= MaxResourceSize){ menu->errmes("Resource too big !"); return; } ResourceData.Data[ResPos++]=b; if(ResPos > ResSize)ResSize=ResPos; } //************************************************* void View::save() { byte c; int i,j,x,y,length,mirror,k,k1; int NumCels,CelSize,CelMirrorSize,DescLoc; bool ColDiff; short LoopLoc[MaxLoops]; short CelLoc[MaxLoops][MaxCels]; ResSize = 0; ResPos = 0; WriteByte(1); //what do these two bytes do? WriteByte(1); WriteByte((byte)NumLoops); WriteByte(0); //write description later, if it exists WriteByte(0); LoopLoc[0] = 5 + NumLoops*2; //fix mirroring so (according to the AGI specs) the loops>=8 do not use it, //and the mirroring loop number is always higher than the mirrored loop for (i = 0;i=8){ if(k!=-1)unsetMirror(k); if(k1!=-1)unsetMirror(k1); } else if(k!=-1){ if(k>i){ unsetMirror(i); setMirror(k,i); } } } for (i = 0;i=15 || x+length>=width)); if(x>0 || (x==0 && c!=transcol))CelMirrorSize++; x+=length; if(x=width && c!=transcol)){ WriteByte((c<<4)|length); CelSize++; } }while(xCurLoop) loops1[i]=loops[i-1]; else{ loops1[i]=Loop(); loops1[i].numcels(1); if(i>0){ w=loops[0].cels[0].width; h=loops[0].cels[0].height; c=loops[0].cels[0].transcol; } else{ w=loops[NumLoops-1].cels[0].width; h=loops[NumLoops-1].cels[0].height; c=loops[NumLoops-1].cels[0].transcol; } loops1[i].cel(0,w,h,c,false); } } delete [] loops; loops=loops1; NumLoops++;; for(i=0;i= CurLoop){ loops[i].mirror++; } } fixmirror(); } //************************************************* void View::insertLoop_after() //after current { int w,h,c,i; Loop *loops1 = new Loop[NumLoops+1]; for(i=0;iCurLoop+1) loops1[i]=loops[i-1]; else{ loops1[i]=Loop(); loops1[i].numcels(1); if(i>0){ w=loops[0].cels[0].width; h=loops[0].cels[0].height; c=loops[0].cels[0].transcol; } else{ w=loops[NumLoops-1].cels[0].width; h=loops[NumLoops-1].cels[0].height; c=loops[NumLoops-1].cels[0].transcol; } loops1[i].cel(0,w,h,c,false); } } delete [] loops; loops=loops1; NumLoops++;; for(i=0;i CurLoop){ loops[i].mirror++; } } fixmirror(); } //************************************************* void View::appendLoop() //append to end { Loop *loops1 = new Loop[NumLoops+1]; for(int i=0;i CurLoop){ loops[i].mirror--; } else if(loops[i].mirror == CurLoop){ unsetMirror(i); } } for(i=CurLoop;i1;x-=2){ data[y*width*2+x]=data[y*width*2+x-2]; data[y*width*2+x-1]=data[y*width*2+x-3]; } data[y*width*2+1]=k0; data[y*width*2]=k1; } } //************************************************* void Cel::left(){ int x,y; byte k0,k1; for(y=0;y0;y--){ data[y*width*2+x]=data[(y-1)*width*2+x]; } data[x]=k0; } } //************************************************* void Cel::mirrorh(){ int x,y; byte k0; for(y=0;ywidth-1||yn<0||yn>height-1)return 0; if(data[width*2*yn+xn*2]==c){ return 0; } if(data[width*2*yn+xn*2]==c0){ data[width*2*yn+xn*2]=c; data[width*2*yn+xn*2+1]=c; return 1; } else{ return 0; } } //************************************************* void Cel::fill1(int xn,int yn,byte c0,byte c){ if(setc(xn,yn-1,c0,c)==1){ fill1(xn,yn-1,c0,c); } if(setc(xn-1,yn,c0,c)==1){ fill1(xn-1,yn,c0,c); } if(setc(xn,yn,c0,c)==1){ fill1(xn,yn,c0,c); } if(setc(xn+1,yn,c0,c)==1){ fill1(xn+1,yn,c0,c); } if(setc(xn,yn+1,c0,c)==1){ fill1(xn,yn+1,c0,c); } } //************************************************* void Cel::fill(int xn,int yn,byte c){ byte c0; c0=data[width*2*yn+xn*2]; fill1(xn,yn,c0,c); } //************************************************** Loop::Loop() { mirror = mirror1 = -1; cels = NULL; CelLoc = NULL; } //************************************************** void Loop::numcels(int n) { NumCels = n; if(cels) delete [] cels; if(CelLoc) delete [] CelLoc; cels = new Cel[NumCels]; CelLoc = new int[NumCels]; } void Loop::cel(int n,int w,int h,int c,bool m) { cels[n]=Cel(w,h,c,m); } //************************************************** void Loop::insertCel_before(int n) //insert cell before 'n' { Cel *cels1 = new Cel[NumCels+1]; for(int i=0;in) cels1[i] = cels[i-1]; else{ if(i>0) cels1[i]=Cel(cels[i-1].width,cels[i-1].height,cels[i-1].transcol,cels[i-1].mirror); else //can't be NumCels==0 ! cels1[i]=Cel(cels[NumCels-1].width,cels[NumCels-1].height,cels[NumCels-1].transcol,cels[NumCels-1].mirror); cels1[i].clear(); } } delete [] cels; cels = cels1; NumCels++; } //************************************************** void Loop::insertCel_after(int n) //insert cell after 'n' { Cel *cels1 = new Cel[NumCels+1]; for(int i=0;in+1) cels1[i] = cels[i-1]; else{ if(i>0) cels1[i]=Cel(cels[i-1].width,cels[i-1].height,cels[i-1].transcol,cels[i-1].mirror); else //can't be NumCels==0! cels1[i]=Cel(cels[NumCels-1].width,cels[NumCels-1].height,cels[NumCels-1].transcol,cels[NumCels-1].mirror); cels1[i].clear(); } } delete [] cels; cels = cels1; NumCels++; } //************************************************** void Loop::appendCel() { Cel *cels1 = new Cel[NumCels+1]; for(int i=0;i