/* * QT AGI Studio :: Copyright (C) 2000 Helen Zommer * * Almost all of the picture processing code is taken from showpic.c * 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 "game.h" #include "menu.h" #include "picture.h" #include #include #ifndef _WIN32 #include #endif #include #include #include #include BPicture *ppicture; //******************************************** //"bytemap" picture for preview - it is not going to be edited, //so there is no need for the linked list and other things from the Picture class BPicture::BPicture() { picture = (byte **)malloc(MAX_H*sizeof(byte *)); priority = (byte **)malloc(MAX_H*sizeof(byte *)); for(int i=0;i 319) return; if (vy > 199) return; picture[vy][vx] = picColour; picture[vy][vx+1] = picColour; } /************************************************************************** ** priPSet ** ** Draws a pixel in the priority screen. **************************************************************************/ void BPicture::priPSet(word x, word y) { word vx, vy; vx = (x << 1); vy = y; if (vx > 319) return; if (vy > 199) return; priority[vy][vx] = priColour; priority[vy][vx+1] = priColour; } /************************************************************************** ** pset ** ** Draws a pixel in each screen depending on whether drawing in that ** screen is enabled or not. **************************************************************************/ void BPicture::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 BPicture::picGetPixel(word x, word y) { word vx, vy; vx = (x << 1); vy = y; if (vx > 319) return(4); if (vy > 199) return(4); return (picture[vy][vx]); } /************************************************************************** ** priGetPixel ** ** Get colour at x,y on the priority page. **************************************************************************/ byte BPicture::priGetPixel(word x, word y) { word vx, vy; vx = (x << 1); vy = y; if (vx > 319) return(4); if (vy > 199) return(4); return (priority[vy][vx]); } /************************************************************************** ** 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 BPicture::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 BPicture::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 BPicture::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 BPicture::agiFill(word x, word y) { byte x1, y1; rpos = spos = 0; qstore(x); qstore(y); // printf("fill %d %d\n",x,y); for (;;) { x1 = qretrieve(); y1 = qretrieve(); // printf("x1=%d y1=%d\n"); 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 BPicture::xCorner(byte **data) { byte x1, x2, y1, y2; x1 = *((*data)++); y1 = *((*data)++); pset(x1,y1); for (;;) { x2 = *((*data)++); if (x2 >= 0xF0) break; drawline(x1, y1, x2, y1); x1 = x2; y2 = *((*data)++); if (y2 >= 0xF0) break; drawline(x1, y1, x1, y2); y1 = y2; } (*data)--; } /************************************************************************** ** yCorner ** ** Draws an yCorner (drawing action 0xF4) **************************************************************************/ void BPicture::yCorner(byte **data) { byte x1, x2, y1, y2; x1 = *((*data)++); y1 = *((*data)++); pset(x1, y1); for (;;) { y2 = *((*data)++); if (y2 >= 0xF0) break; drawline(x1, y1, x1, y2); y1 = y2; x2 = *((*data)++); if (x2 >= 0xF0) break; drawline(x1, y1, x2, y1); x1 = x2; } (*data)--; } /************************************************************************** ** relativeDraw ** ** Draws short lines relative to last position. (drawing action 0xF7) **************************************************************************/ void BPicture::relativeDraw(byte **data) { byte x1, y1, disp; char dx, dy; x1 = *((*data)++); y1 = *((*data)++); pset(x1, y1); for (;;) { disp = *((*data)++); 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; } (*data)--; } /************************************************************************** ** fill ** ** Agi flood fill. (drawing action 0xF8) **************************************************************************/ void BPicture::fill(byte **data) { byte x1, y1; for (;;) { if ((x1 = *((*data)++)) >= 0xF0) break; if ((y1 = *((*data)++)) >= 0xF0) break; agiFill(x1, y1); } (*data)--; } /************************************************************************** ** absoluteLine ** ** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) **************************************************************************/ void BPicture::absoluteLine(byte **data) { byte x1, y1, x2, y2; x1 = *((*data)++); y1 = *((*data)++); pset(x1, y1); for (;;) { if ((x2 = *((*data)++)) >= 0xF0) break; if ((y2 = *((*data)++)) >= 0xF0) break; drawline(x1, y1, x2, y2); x1 = x2; y1 = y2; } (*data)--; } #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 BPicture::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 BPicture::plotBrush(byte **data) { byte x1, y1; for (;;) { if (patCode & 0x20) { if ((patNum = *((*data)++)) >= 0xF0) break; patNum = (patNum >> 1 & 0x7f); } if ((x1 = *((*data)++)) >= 0xF0) break; if ((y1 = *((*data)++)) >= 0xF0) break; plotPattern(x1, y1); } (*data)--; } //**************************************************** void BPicture::show(byte *picdata,int picsize) { byte *data = picdata; bool stillDrawing = true; byte action; for(int i=0;i