You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/kmahjongg/Tileset.cpp

282 lines
8.4 KiB

#include <stdlib.h>
#include "Tileset.h"
#include <qimage.h>
#define mini_width 20
#define mini_height 28
static unsigned char mini_bits[] = {
0xfc, 0xff, 0x0f, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f,
0xff, 0xff, 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x07, 0xff, 0xff, 0x03,
};
#define mask_width 40
#define mask_height 56
static unsigned char mask_bits[] = {
0xf0, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff,
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
0xff, 0xff, 0xff, 0x0f, };
// ---------------------------------------------------------
Tileset::Tileset(bool scale):
maskBits(mask_width, mask_height, mask_bits, true),
maskBitsMini(mini_width, mini_height, mini_bits, true)
{
isScaled = scale;
divisor = (isScaled) ? 2 : 1;
// set up tile metrics (fixed for now)
ss = 4; // left/bottom shadow width
bs = 1; // tile boarder width
w = 40; // tile width (inc boarder & shadow)
h = 56; // tile height (inc boarder and shadow)
s = w*h; // RGBA's required per tile
// Allocate memory for the 9*5 tile arrays
tiles = new QRgb [9*5*s];
selectedTiles = new QRgb [9*5*s];
// allocate memory for single tile storage
selectedFace = new QRgb [s];
unselectedFace = new QRgb [s];
// quarter widths are used as an offset when
// overlaying tiles in 3 dimensions.
qw = ((w-ss)/2) ;
qh = ((h-ss)/2) ;
filename = "";
}
// ---------------------------------------------------------
Tileset::~Tileset() {
// deallocate all memory
delete [] tiles;
delete [] selectedTiles;
delete [] selectedFace;
delete [] unselectedFace;
}
// ---------------------------------------------------------
// copy a tile from a qimage into a linear array of bytes. This
// method returns the address of the byte after the copied image
// and can be used to fill a larger array of tiles.
QRgb *Tileset::copyTileImage(short tileX, short tileY, QRgb *to, QImage &from) {
QRgb *dest = to;
QRgb *src;
src = (QRgb *) from.scanLine(tileY * h)
+(tileX * w);
for (short pos=0; pos < h; pos++) {
memcpy(dest, src, w*sizeof(QRgb));
dest+=w;
src += from.width();
}
return(dest);
}
// ----------------------------------------------------------
// Create a tile. Take a specified tile background a tile face
// (specified as an x,y coord) and a destination buffer (location
// in which is calculated from the x,y) and copy in the
// tile background, overlaying the foreground with transparency
// (the foregrounds top/left pixel is taken as the transparent
// color).
QRgb *Tileset::createTile(short x, short y,
QRgb *det, QImage &allTiles , QRgb *face) {
QRgb *image ;
QRgb *to = det;
// Alloc the space
image = new QRgb[s];
// copy in the background
memcpy(to, face, s*sizeof(QRgb));
// get the tile gylph
copyTileImage(x, y , image, allTiles);
// copy the image over the background using the
// top left colour as the transparency. We step over
// the shadow and the boarder
QRgb* src = image+ // image
ss+ // past the left shadow
bs+ // then the tile border
(bs * w); // then step past the top border
to += (((ss+bs))+(bs*w));
QRgb trans = *src;
// start after the top border rows and go through all rows
for( short YP=0; YP < h-ss - (2*bs); YP++) {
// start after the shadow and border and iterate over x
for (short xpos=0; xpos < w-ss -(2*bs) ; xpos++) {
// skip transparent pixels
if (*src != trans)
*to = *src;
src++;
to++;
}
// step over the border to get to the next row
src += ss + (2 * bs);
to += ss + (2 * bs);
}
// Free allocated space
delete [] image;
// calculate the address of the next tile
return(det+s);
}
// --------------------------------------------------------
// create a pixmap for a tile. Optionally create a scalled
// version, which can be used for mini tile requirements.
// this gives us a small tile for previews and showing
// removed tiles.
void Tileset::createPixmap(QRgb *src, QPixmap &dest, bool scale, bool shadow)
{
QImage buff;
QRgb *line;
buff.create(w, h, 32);
for (int y=0; y<h; y++) {
line = (QRgb *) buff.scanLine(y);
memcpy( line, src, w*sizeof(QRgb));
if (shadow) {
for (int spos=0; spos <w; spos++) {
line[spos] = QColor(line[spos]).dark(133).rgb();
}
}
src += w;
}
// create the pixmap and initialise the drawing mask
if (!scale) {
dest.convertFromImage(buff);
dest.setMask(maskBits);
} else {
dest.convertFromImage(buff.smoothScale(w/2, h/2));
dest.setMask(maskBitsMini);
}
}
// ---------------------------------------------------------
bool Tileset::loadTileset( const QString& tilesetPath, const bool isPreview)
{
QImage qiTiles;
QRgb *unsel;
QRgb *sel;
QRgb *nextSel=0;
QRgb *nextUnsel=0;
if (filename == tilesetPath) {
return true;
}
// try to load it
if( ! qiTiles.load( tilesetPath) )
return( false );
// we deal only with 32 bit images
if (qiTiles.depth() != 32)
qiTiles = qiTiles.convertDepth(32);
// Read in the unselected and selected tile backgrounds
copyTileImage(7, 4 , unselectedFace, qiTiles);
copyTileImage(8, 4, selectedFace, qiTiles);
// Read in the 9*5 tiles. Each tile is overlayed onto
// the selected and unselected tile backgrounds and
// stored.
sel = selectedTiles;
unsel = tiles;
for (short atY=0; atY<5; atY++) {
for (short atX=0; atX<9; atX++) {
nextUnsel = createTile(atX, atY, unsel , qiTiles, unselectedFace);
// for the preview dialog we do not create selected tiles
if (!isPreview)
nextSel = createTile(atX, atY, sel , qiTiles, selectedFace);
int pixNo = atX+(atY*9);
// for the preview dialog we only create the unselected mini pix
if (!isPreview) {
createPixmap(sel, selectedPix[pixNo], false, false);
createPixmap(unsel, unselectedPix[pixNo], false, false);
createPixmap(sel, selectedMiniPix[pixNo], true, false);
createPixmap(sel, selectedShadowPix[pixNo], false, true);
createPixmap(unsel, unselectedShadowPix[pixNo], false, true);
createPixmap(sel, selectedShadowMiniPix[pixNo], true, true);
createPixmap(unsel, unselectedShadowMiniPix[pixNo], true, true);
}
createPixmap(unsel, unselectedMiniPix[pixNo], true, false);
sel = nextSel;
unsel= nextUnsel;
}
}
filename = tilesetPath;
return( true );
}