/* * QT AGI Studio :: Copyright (C) 2000 Helen Zommer * * A big part of this code is adapted from the original (MSDOS) * Picedit developed by Lance Ewing. * * 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 #include #include #include #include #ifndef _WIN32 #include #endif #include #include "linklist.h" #include "picture.h" #include "menu.h" static bool picDrawEnabled0,priDrawEnabled0; static int picColour0,priColour0; //********************************************************* Picture::Picture() { picPos=picStart=picLast=NULL; this->freeList(); bg_on = false; } //********************************************************* char *Picture::showPos(int *code,int *val) //show current picture buffer position { char tmp1[6]; tmp[0]=0; struct picCodeNode *temp; int count; if(picPos){ *code=picPos->node; if(picPos->next){ *val=picPos->next->node; } } for (temp=picPos, count=0; ((count<6)&&(temp!=NULL)); count++, temp=temp->next) { sprintf(tmp1, "%02X", temp->node); strcat(tmp,tmp1); } return tmp; } //********************************************************* int Picture::setBufPos(int inputValue) //set current picture buffer position to inputValue { if ((inputValue < 0) || (inputValue > bufLen)) return 1; if (inputValue == bufLen) { picPos = NULL; bufPos = inputValue; } else{ /* Find given location */ while (bufPos != inputValue) { if (inputValue < bufPos) { if (picPos == NULL) picPos = picLast; else picPos = picPos->prior; bufPos--; } else { picPos = picPos->next; bufPos++; } } /* Find current action position */ while (picPos->node < 0xF0) { picPos = picPos->prior; bufPos--; } } draw(); init_tool(); return 0; } //********************************************************* void Picture::qstore(byte q) { if (spos+1==rpos || (spos+1==QUMAX && !rpos)) { return; } buf[spos] = q; spos++; if (spos==QUMAX) spos = 0; /* loop back */ } //********************************************************* byte Picture::qretrieve() { if (rpos==QUMAX) rpos=0; /* loop back */ if (rpos==spos) { return EMPTY; } rpos++; return buf[rpos-1]; } /************************************************************************** ** getCode ** ** Gets the next picture code from the linked list. **************************************************************************/ byte Picture::getCode(struct picCodeNode **temp) { byte retVal; if (*temp == NULL) return 0xFF; retVal = (*temp)->node; *temp = (*temp)->next; return retVal; } byte Picture::testCode(struct picCodeNode **temp) { byte retVal; if (*temp == NULL) return 0xFF; retVal = (*temp)->node; return retVal; } /************************************************************************** ** picPSet ** ** Draws a pixel in the picture screen. **************************************************************************/ void Picture::picPSet(word x, word y) { x<<=1; if (x >= MAX_W) return; if (y >= MAX_H) return; picture[y*MAX_W+x] = picColour; picture[y*MAX_W+x+1] = picColour; } /************************************************************************** ** priPSet ** ** Draws a pixel in the priority screen. **************************************************************************/ void Picture::priPSet(word x, word y) { x<<=1; if (x >= MAX_W) return; if (y >= MAX_H) return; priority[y*MAX_W+x] = priColour; priority[y*MAX_W+x+1] = priColour; } /************************************************************************** ** pset ** ** Draws a pixel in each screen depending on whether drawing in that ** screen is enabled or not. **************************************************************************/ void Picture::pset(word x, word y) { if (picDrawEnabled) picPSet(x, y); if (priDrawEnabled) priPSet(x, y); } /************************************************************************** ** picGetPixel ** ** Get colour at x,y on the picture page. **************************************************************************/ byte Picture::picGetPixel(word x, word y) { x <<= 1; if (x >= MAX_W) return 4; if (y >= MAX_H) return 4; return (picture[y*MAX_W+x]); } /************************************************************************** ** priGetPixel ** ** Get colour at x,y on the priority page. **************************************************************************/ byte Picture::priGetPixel(word x, word y) { x <<= 1; if (x >= MAX_W) return 4; if (y >= MAX_H) return 4; return (priority[y*MAX_W+x]); } /************************************************************************** ** round ** ** Rounds a float to the closest int. Takes into actions which direction ** the current line is being drawn when it has a 50:50 decision about ** where to put a pixel. **************************************************************************/ int Picture::round(float aNumber, float dirn) { if (dirn < 0) return ((aNumber - floor(aNumber) <= 0.501)? (int)floor(aNumber) : (int)ceil(aNumber)); return ((aNumber - floor(aNumber) < 0.499)? (int)floor(aNumber) : (int)ceil(aNumber)); } /************************************************************************** ** drawline ** ** Draws an AGI line. **************************************************************************/ void Picture::drawline(word x1, word y1, word x2, word y2) { int height, width; float x, y, addX, addY; height = (y2 - y1); width = (x2 - x1); addX = (height==0?height:(float)width/abs(height)); addY = (width==0?width:(float)height/abs(width)); if (abs(width) > abs(height)) { y = y1; addX = (width == 0? 0 : (width/abs(width))); for (x=x1; x!=x2; x+=addX) { pset(round(x, addX), round(y, addY)); y+=addY; } pset(x2,y2); } else { x = x1; addY = (height == 0? 0 : (height/abs(height))); for (y=y1; y!=y2; y+=addY) { pset(round(x, addX), round(y, addY)); x+=addX; } pset(x2,y2); } } /************************************************************************** ** okToFill **************************************************************************/ bool Picture::okToFill(byte x, byte y) { if (!picDrawEnabled && !priDrawEnabled) return false; if (picColour == 15) return false; if (!priDrawEnabled) return (picGetPixel(x, y) == 15); if (priDrawEnabled && !picDrawEnabled) return (priGetPixel(x, y) == 4); return (picGetPixel(x, y) == 15); } /************************************************************************** ** agiFill **************************************************************************/ void Picture::agiFill(word x, word y) { byte x1, y1; rpos = spos = 0; qstore(x); qstore(y); for (;;) { x1 = qretrieve(); y1 = qretrieve(); if ((x1 == EMPTY) || (y1 == EMPTY)) break; else { if (okToFill(x1,y1)) { pset(x1, y1); if (okToFill(x1, y1-1) && (y1!=0)) { qstore(x1); qstore(y1-1); } if (okToFill(x1-1, y1) && (x1!=0)) { qstore(x1-1); qstore(y1); } if (okToFill(x1+1, y1) && (x1!=159)) { qstore(x1+1); qstore(y1); } if (okToFill(x1, y1+1) && (y1!=167)) { qstore(x1); qstore(y1+1); } } } } } /************************************************************************** ** xCorner ** ** Draws an xCorner (drawing action 0xF5) **************************************************************************/ void Picture::xCorner(struct picCodeNode **temp) { byte x1, x2, y1, y2; x1 = getCode(temp); y1 = getCode(temp); pset(x1,y1); for (;;) { x2 = getCode(temp); if (x2 >= 0xF0) break; drawline(x1, y1, x2, y1); x1 = x2; y2 = getCode(temp); if (y2 >= 0xF0) break; drawline(x1, y1, x1, y2); y1 = y2; } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } /************************************************************************** ** yCorner ** ** Draws an yCorner (drawing action 0xF4) **************************************************************************/ void Picture::yCorner(struct picCodeNode **temp) { byte x1, x2, y1, y2; x1 = getCode(temp); y1 = getCode(temp); pset(x1, y1); for (;;) { y2 = getCode(temp); if (y2 >= 0xF0) break; drawline(x1, y1, x1, y2); y1 = y2; x2 = getCode(temp); if (x2 >= 0xF0) break; drawline(x1, y1, x2, y1); x1 = x2; } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } /************************************************************************** ** relativeDraw ** ** Draws short lines relative to last position. (drawing action 0xF7) **************************************************************************/ void Picture::relativeDraw(struct picCodeNode **temp) { byte x1, y1, disp; char dx, dy; x1 = getCode(temp); y1 = getCode(temp); pset(x1, y1); for (;;) { disp = getCode(temp); if (disp >= 0xF0) break; dx = ((disp & 0xF0) >> 4) & 0x0F; dy = (disp & 0x0F); if (dx & 0x08) dx = (-1)*(dx & 0x07); if (dy & 0x08) dy = (-1)*(dy & 0x07); drawline(x1, y1, x1 + dx, y1 + dy); x1 += dx; y1 += dy; } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } /************************************************************************** ** fill ** ** Agi flood fill. (drawing action 0xF8) **************************************************************************/ void Picture::fill(struct picCodeNode **temp) { byte x1, y1; for (;;) { if ((x1 = getCode(temp)) >= 0xF0) break; if ((y1 = getCode(temp)) >= 0xF0) break; agiFill(x1, y1); } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } /************************************************************************** ** absoluteLine ** ** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) **************************************************************************/ void Picture::absoluteLine(struct picCodeNode **temp) { byte x1, y1, x2, y2; x1 = getCode(temp); y1 = getCode(temp); pset(x1, y1); for (;;) { if ((x2 = getCode(temp)) >= 0xF0) break; if ((y2 = getCode(temp)) >= 0xF0) break; drawline(x1, y1, x2, y2); x1 = x2; y1 = y2; } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } #define plotPatternPoint() \ if (patCode & 0x20) { \ if ((splatterMap[bitPos>>3] >> (7-(bitPos&7))) & 1) pset(x1, y1); \ bitPos++; \ if (bitPos == 0xff) bitPos=0; \ } else pset(x1, y1) /************************************************************************** ** plotPattern ** ** Draws pixels, circles, squares, or splatter brush patterns depending ** on the pattern code. **************************************************************************/ void Picture::plotPattern(byte x, byte y) { static unsigned char circles[][15] = { /* agi circle bitmaps */ {0x80}, {0xfc}, {0x5f, 0xf4}, {0x66, 0xff, 0xf6, 0x60}, {0x23, 0xbf, 0xff, 0xff, 0xee, 0x20}, {0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00}, {0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80}, {0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x3c, 0x18} }; static byte splatterMap[32] = { /* splatter brush bitmaps */ 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 }; static byte splatterStart[128] = { /* starting bit position */ 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 }; int circlePos = 0; byte x1, y1, penSize, bitPos = splatterStart[patNum]; penSize = (patCode&7); if (x<((penSize/2)+1)) x=((penSize/2)+1); else if (x>160-((penSize/2)+1)) x=160-((penSize/2)+1); if (y=168-penSize) y=167-penSize; for (y1=y-penSize; y1<=y+penSize; y1++) { for (x1=x-((int)ceil((float)penSize/2)); x1<=x+((int)floor((float)penSize/2)); x1++) { if (patCode & 0x10) { /* Square */ plotPatternPoint(); } else { /* Circle */ if ((circles[patCode&7][circlePos>>3] >> (7-(circlePos&7)))&1) { plotPatternPoint(); } circlePos++; } } } } /************************************************************************** ** plotBrush ** ** Plots points and various brush patterns. **************************************************************************/ void Picture::plotBrush(struct picCodeNode **temp) { byte x1, y1; for (;;) { if (patCode & 0x20) { if ((patNum = getCode(temp)) >= 0xF0) break; patNum = (patNum >> 1 & 0x7f); } if ((x1 = getCode(temp)) >= 0xF0) break; if ((y1 = getCode(temp)) >= 0xF0) break; plotPattern(x1, y1); } if (*temp == NULL) *temp = NULL; else *temp = (*temp)->prior; } //******************************************************************** void Picture::load(byte *picdata,int picsize) { byte nodeData; struct picCodeNode *temp=NULL; bool stillLoading=true; //init link list picPos = picStart = picLast = NULL; addMode = INS_MODE; bufPos = bufLen = 0; do { nodeData = *picdata++; picsize--; if (nodeData != 0xFF) { temp = (struct picCodeNode *)malloc(sizeof(picCodes)); if (temp == NULL) { printf("Error allocating memory while loading picture.\n"); exit(1); } /* was in the original code but doesn't work if (isFirst) { picStart = temp; isFirst = false; } */ temp->node = nodeData; dlstore(temp); } else stillLoading = false; } while(picsize && stillLoading); picLast = temp; picPos = NULL; } //************************************************* int Picture::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); load(ResourceData.Data,ResourceData.Size); refill_pic = refill_pri = false; draw(); init(); return 0; } //************************************************* int Picture::open(int ResNum) { int err = game->ReadResource(PICTURE,ResNum); if(!err){ load(ResourceData.Data,ResourceData.Size); refill_pic = refill_pri = false; draw(); init(); } return err; } //************************************************* int Picture::save(int ResNum) { save(); return(game->AddResource(PICTURE,ResNum)); } //************************************************* int Picture::save(char *filename) { FILE *fptr = fopen(filename,"wb"); if(fptr==NULL){ menu->errmes("Can't open file %s ! ",filename); return 1; } save(); fwrite(ResourceData.Data,ResourceData.Size,1,fptr); fclose(fptr); return 0; } //************************************************* void Picture::save() { byte *ptr=ResourceData.Data; struct picCodeNode *temp; if (picStart == NULL) { /* Black picture */ *ptr = 0xFF; /* End of picture marker */ ResourceData.Size=1; return ; } temp = picStart; *ptr++ = temp->node; do { temp = temp->next; *ptr++ = temp->node; } while (temp->next != NULL); *ptr++ = 0xFF; /* End of picture marker */ ResourceData.Size = (int)(ptr-ResourceData.Data); } //************************************************* void Picture::refill( struct picCodeNode *temp_fill_start, struct picCodeNode *temp_fill_end,int refmode) { struct picCodeNode *temp,*picPos0,*temp_pic=0,*temp_pri=0; int col_pic_orig,col_pri_orig,col_pic_new,col_pri_new; bool picDrawEnabled_orig,priDrawEnabled_orig; bool draw_pic_orig,draw_pri_orig,draw_pic_new,draw_pri_new; picDrawEnabled_orig=priDrawEnabled_orig=false; col_pic_orig = col_pri_orig = -1; temp=temp_fill_start; draw_pic_orig=draw_pri_orig=false; do{ temp = temp->prior; if(temp==NULL)break; switch(temp->node){ case 0xf0: if(col_pic_orig==-1){ col_pic_orig = (temp->next)->node; picDrawEnabled_orig=true; temp_pic=temp; } break; case 0xf1: if(col_pic_orig==-1){ col_pic_orig=-2; temp_pic=temp; } break; case 0xf2: if(col_pri_orig==-1){ col_pri_orig = (temp->next)->node; priDrawEnabled_orig=true; temp_pri=temp; } break; case 0xf3: if(col_pri_orig==-1){ col_pri_orig=-2; temp_pri=temp; } break; default: if(temp->node >= 0xf4 && temp->node < 0xff){ if(col_pic_orig==-1)draw_pic_orig=true; if(col_pri_orig==-1)draw_pri_orig=true; } break; } }while(col_pic_orig==-1 || col_pri_orig==-1); //find the fill original color picPos0= picPos; picPos = temp_fill_start; if((refmode|1) && picDrawEnabled0){ if(picDrawEnabled_orig){ if(col_pic!=col_pic_orig){ if(col_pic==15){ if(draw_pic_orig){ addCode(0xf1); } else{ temp_pic->node=0xf1; picPos=temp_pic->next; dldelete(); } } else{//col_pic != 15 if(draw_pic_orig){ addCode(0xf0); addCode(col_pic); } else{ (temp_pic->next)->node=col_pic; } } } } else{//!picDrawEnabled_orig if(col_pic!=15){ addCode(0xf0); addCode(col_pic); } } } if((refmode|2) && priDrawEnabled0){ if(priDrawEnabled_orig){ if(col_pri!=col_pri_orig){ if(col_pri==4){ if(draw_pri_orig){ addCode(0xf3); } else{ temp_pri->node=0xf3; picPos=temp_pri->next; dldelete(); } } else{//col_pri != 4 if(draw_pri_orig){ addCode(0xf2); addCode(col_pri); } else{ (temp_pri->next)->node=col_pri; } } } } else{//!priDrawEnabled_orig if(col_pri!=4){ addCode(0xf2); addCode(col_pri); } } } temp = temp_fill_end; col_pic_new=col_pri_new=-1; draw_pic_new=draw_pri_new = false; if(temp){ do{ switch(temp->node){ case 0xf0: col_pic_new = (temp->next)->node; break; case 0xf1: col_pic_new = -2; break; case 0xf2: col_pri_new = (temp->next)->node; break; case 0xf3: col_pri_new = -2; break; default: if(temp->node >= 0xf4 && temp->node < 0xff){ if(col_pic_new==-1)draw_pic_new=true; if(col_pri_new==-1)draw_pri_new=true; } break; } temp = temp->next; }while(temp && (col_pic_orig==-1 || col_pri_orig==-1)); picPos = temp_fill_end; if((refmode|1) && picDrawEnabled0){ if(col_pic != col_pic_orig){ if(draw_pic_new){ if(picDrawEnabled_orig){ addCode(0xf0); addCode(col_pic_orig); } else{ if(col_pic!=0x15){ addCode(0xf1); } } } } } if((refmode|2) && priDrawEnabled0){ if(col_pri != col_pri_orig){ if(draw_pri_new){ if(priDrawEnabled_orig){ addCode(0xf2); addCode(col_pri_orig); } else{ if(col_pri!=0x4){ addCode(0xf3); } } } } } } picPos = picPos0; draw(); } //************************************************* void Picture::draw() { byte action; struct picCodeNode *temp,*temp_fill_start,*temp_fill_end; int refmode; bool finishedPic=false; int pC, pN; memset(picture, 15, MAX_W*MAX_H); /* Visual screen default, white */ memset(priority, 4, MAX_W*MAX_H); /* Priority screen default, red */ rpos = QUMAX; spos = 0; picDrawEnabled = false; priDrawEnabled = false; picColour = priColour = 0; tool=-1; if ((picStart != NULL) && (picLast != NULL)) { pC = patCode; pN = patNum; patCode = patNum = 0; temp = picStart; if (picPos != picStart) do { action = getCode(&temp); switch (action) { case 0xF0: picColour = getCode(&temp); picDrawEnabled = true; break; case 0xF1: picDrawEnabled = false; break; case 0xF2: priColour = getCode(&temp); priDrawEnabled = true; break; case 0xF3: priDrawEnabled = false; break; case 0xF4: tool=T_STEP; yCorner(&temp); break; case 0xF5: tool=T_STEP; xCorner(&temp); break; case 0xF6: tool=T_LINE; absoluteLine(&temp); break; case 0xF7: tool=T_PEN; relativeDraw(&temp); break; case 0xF8: tool=T_FILL; temp_fill_start = temp->prior; fill(&temp); temp_fill_end = temp; if(refill_pic || refill_pri){ //find which FILL filled the selected area refmode=0; if(refill_pic && picGetPixel(refill_x,refill_y)!=15){ refmode |= 1; refill_pic=false; } if(refill_pri && priGetPixel(refill_x,refill_y)!=4){ refill_pri=false; refmode |= 2; } if(refmode){ refill(temp_fill_start,temp_fill_end,refmode); } if(!refill_pic && !refill_pri)return; } break; case 0xF9: patCode = getCode(&temp); break; case 0xFA: tool=T_BRUSH; plotBrush(&temp); break; case 0xFF: finishedPic=true; break; default: printf("Unknown picture code : %X\n", action); printf("%p %p %p\n", picLast, picPos, temp); break; } } while((temp != picPos) && !finishedPic); patCode = pC; patNum = pN; } } //************************************************** void Picture::init() { clear_tools(); priDrawEnabled = picDrawEnabled = false; addMode = INS_MODE; curp = &points0; points0.n=points1.n=0; newp=&points; add_pic=add_pri=false; } //************************************************** void Picture::newpic() { freeList(); draw(); init(); } //************************************************** void Picture::addCode(byte code) /* To the list */ { struct picCodeNode *temp; temp = (struct picCodeNode *)malloc(sizeof(picCodes)); if (temp == 0) { printf("Memory allocation problem."); exit(0); } temp->node = code; dlstore(temp); } //************************************************** void Picture::replaceCode(byte code) { struct picCodeNode *temp; temp = (struct picCodeNode *)malloc(sizeof(picCodes)); if (temp == 0) { printf("Memory allocation problem."); exit(0); } temp->node = code; addMode = OVR_MODE; dlstore(temp); addMode = INS_MODE; } //************************************************** void Picture::addPatCode() { int pat=0; pat = (brushSize & 0x07); if (brushShape == SQUARE) pat |= 0x10; if (brushTexture == SPRAY) pat |= 0x20; addCode(pat); } //************************************************** void Picture::adjustDisp(int *dX, int *dY) //for pen { if (*dX > 6) *dX = 6; if (*dX < -6) *dX = -6; if (*dY > 7) *dY = 7; if (*dY < -7) *dY = -7; } //************************************************** void Picture::clear_tools() { numClicks=0; stepClicks=0; firstClick=true; tool=-1; } //************************************************** void Picture::init_tool() { numClicks=0; stepClicks=0; firstClick=true; } //************************************************** void Picture::home_proc() { moveToStart(); draw(); init_tool(); } //************************************************** void Picture::left_proc() { moveBackAction(); draw(); init_tool(); } //************************************************** void Picture::right_proc() { moveForwardAction(); draw(); init_tool(); } //************************************************** void Picture::end_proc() { moveToEnd(); draw(); init_tool(); } //************************************************** void Picture::del_proc() { removeAction(); draw(); init_tool(); } //************************************************** void Picture::wipe_proc() { wipeAction(); draw(); init_tool(); } //************************************************** void Picture::tool_proc(int k) { tool=k; numClicks=0; stepClicks=0; firstClick=true; } //************************************************** void Picture::set_brush(int mode,int val) { switch(mode){ case 0: brushSize = val; break; case 1: brushShape = val; break; case 2: brushTexture = val; break; } numClicks=0; } //************************************************** void Picture::choose_color(int button,int color) { if(button == M_LEFT){ add_pic=true; if(color==-1){ //off // addCode(0xF1); code_pic=0xF1; picDrawEnabled = false; } else{ picColour = color; // addCode(0xF0); //addCode(picColour); code_pic=0xF0; col_pic=picColour; picDrawEnabled = true; } } else{ add_pri=true; if(color==-1){ //off // addCode(0xF3); code_pri=0xF3; priDrawEnabled = false; } else{ priColour = color; //addCode(0xF2); //addCode(priColour); code_pri=0xF2; col_pri=priColour; priDrawEnabled = true; } } init_tool(); curcol=(drawing_mode)?priColour:picColour; } //************************************************** int Picture::move_action(int newX, int newY) { int ret=0; //1 - draw "temporary" line on screen switch(tool){ case T_LINE: if(numClicks==0)break; normline2(clickX>>1, clickY, newX>>1, newY); ret=1; break; case T_PEN: if(numClicks==0)break; dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); adjustDisp(&dX, &dY); normline2(clickX>>1, clickY,(clickX>>1)+dX, clickY+dY); ret=1; break; case T_STEP: if(stepClicks==0)break; switch (stepClicks) { case 1: dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); if (abs(dX) > abs(dY)) dY = 0; else dX = 0; normline2(clickX>>1, clickY, (clickX>>1)+dX, clickY+dY); ret=1; break; default: dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); if (stepClicks % 2) dX = 0; else dY = 0; normline2(clickX>>1, clickY, (clickX>>1)+dX, clickY+dY); ret=1; break; } break; } return ret; } //************************************************** int Picture::button_action(int newX, int newY) { int disp; int ret=0; if(!(tool == T_FILL && !okToFill(newX>>1, newY))){ if(add_pic){ addCode(code_pic); if(code_pic==0xf0){ addCode(col_pic); } add_pic=false; } if(add_pri){ addCode(code_pri); if(code_pri==0xf2){ addCode(col_pri); } add_pri=false; } } switch(tool){ case T_LINE: switch (numClicks++) { case 0: break; case 1: addCode(0xF6); addCode(clickX>>1); addCode(clickY); ret=1; [[fallthrough]]; default: addCode(newX>>1); addCode(newY); ret=1; drawline(clickX>>1, clickY, newX>>1, newY); break; } clickX = newX; clickY = newY; curp = &points0; points0.n=points1.n=0; break; case T_PEN: dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); adjustDisp(&dX, &dY); switch (numClicks++) { case 0: clickX = newX; clickY = newY; break; case 1: addCode(0xF7); addCode(clickX>>1); addCode(clickY); [[fallthrough]]; default: if (dX < 0) disp = (0x80 | ((((-1)*dX)-0) << 4)); else disp = (dX << 4); if (dY < 0) disp |= (0x08 | (((-1)*dY)-0)); else disp |= dY; addCode(disp); ret=1; drawline(clickX>>1, clickY, (clickX>>1)+dX, (clickY)+dY); clickX = clickX + (dX<<1); clickY = clickY + dY; break; } curp = &points0; points0.n=points1.n=0; break; case T_STEP: switch (stepClicks) { case 0: clickX = newX; clickY = newY; break; case 1: dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); if (abs(dX) > abs(dY)) { /* X or Y corner */ dY = 0; stepClicks++; addCode(0xF5); addCode(clickX>>1); addCode(clickY); addCode((clickX>>1)+dX); } else { dX = 0; addCode(0xF4); addCode(clickX>>1); addCode(clickY); addCode((clickY)+dY); } ret=1; drawline(clickX>>1, clickY, (clickX>>1)+dX, (clickY)+dY); clickX = clickX + (dX<<1); clickY = clickY + dY; break; default: dX = ((newX>>1) - (clickX>>1)); dY = ((newY) - (clickY)); if (stepClicks % 2) { dX = 0; addCode((clickY)+dY); } else { dY = 0; addCode((clickX>>1)+dX); } ret=1; drawline(clickX>>1, clickY, (clickX>>1)+dX, (clickY)+dY); clickX = clickX + (dX<<1); clickY = clickY + dY; break; } stepClicks++; curp = &points0; points0.n=points1.n=0; break; case T_FILL: if(!(okToFill(newX>>1, newY))){ status(0); refill_x = newX>>1; refill_y = newY; refill_pic = refill_pri = true; draw(); ret=1; init(); status(1); tool = T_FILL; init_tool(); break; } agiFill(newX>>1, newY); if (firstClick) { addCode(0xF8); firstClick = false; } addCode(newX>>1); addCode(newY); ret=1; break; case T_BRUSH: if (numClicks == 0) { addCode(0xF9); addPatCode(); addCode(0xFA); } numClicks++; patCode = brushSize; if (brushShape == SQUARE) patCode |= 0x10; if (brushTexture == SPRAY) patCode |= 0x20; patNum = ((rand() % 0xEE) >> 1) & 0x7F; plotPattern(newX>>1, newY); if (brushTexture == SPRAY) addCode(patNum<<1); addCode(newX>>1); addCode(newY); ret=1; } return ret; } //*************************************************** void Picture::set_mode(int mode) { drawing_mode=mode; if(mode==0){ pptr = picture; curcol = picColour; } else{ pptr = priority; curcol = priColour; } } //*************************************************** void Picture::putpix2(int x,int y) { byte c; QColor cc; if(x<0||y<0||x>=MAX_W||y>=MAX_HH){ return; } //save the pixels under the line to be drawn //so it can be restored when the line is moved if(bg_on){ //if background is on - must save the contents of the background image x<<=1; curp->p[curp->n].x=x; curp->p[curp->n].y=y; c=pptr[y*MAX_W+x]; if((c==15&&pptr==picture)||(c==4&&pptr==priority)){ curp->p[curp->n].cc=QColor(bgpix->pixel(x,y)); curp->n++; curp->p[curp->n].x=x+1; curp->p[curp->n].y=y; curp->p[curp->n].cc=QColor(bgpix->pixel(x+1,y)); curp->n++; } else{ cc=egacolor[c]; curp->p[curp->n].cc=cc; curp->n++; curp->p[curp->n].x=x+1; curp->p[curp->n].y=y; curp->p[curp->n].cc=cc; curp->n++; } x>>=1; } else{ //save the pixels curp->p[curp->n].x=x; curp->p[curp->n].y=y; curp->p[curp->n].c=pptr[y*MAX_W+(x<<1)]; curp->n++; } newp->p[newp->n].x=x; newp->p[newp->n].y=y; newp->p[newp->n].c=curcol; newp->n++; } //*************************************************** void Picture::normline2(int x1, int y1, int x2, int y2) { int height, width; float x, y, addX, addY; height = (y2 - y1); width = (x2 - x1); addX = (height==0?height:(float)width/abs(height)); addY = (width==0?width:(float)height/abs(width)); points.n=0; curp->n=0; if (abs(width) > abs(height)) { y = y1; addX = (width == 0? 0 : (width/abs(width))); for (x=x1; x!=x2; x+=addX) { putpix2(round(x, addX), round(y, addY)); y+=addY; } putpix2(x2,y2); } else { x = x1; addY = (height == 0? 0 : (height/abs(height))); for (y=y1; y!=y2; y+=addY) { putpix2(round(x, addX), round(y, addY)); x+=addX; } putpix2(x2,y2); } if(curp==&points0)curp= (&points1); else curp= (&points0); } //*************************************************** void Picture::viewData(TStringList *data) { struct picCodeNode *temp; byte c; char tmp1[6]; data->lfree(); if (picStart == NULL) { /* Black picture */ data->add("ff"); return ; } temp = picStart; tmp[0]=0; for(temp=picStart;temp!=NULL;temp=temp->next){ c = temp->node; if(c>=0xf0 && tmp[0]){ data->add(tmp); sprintf(tmp,"%02x ",c); } else{ sprintf(tmp1,"%02x ",c); strcat(tmp,tmp1); } } if(tmp1[0]!=0){ strcat(tmp,tmp1); data->add(tmp); } data->add("ff"); } //*************************************************** void Picture::status(int mode) { if(mode==0){ picDrawEnabled0 = picDrawEnabled; priDrawEnabled0 = priDrawEnabled; picColour0=picColour; priColour0=priColour; } else{ picDrawEnabled = picDrawEnabled0; priDrawEnabled = priDrawEnabled0; picColour=picColour0; priColour=priColour0; } }