~ubuntu-branches/ubuntu/precise/tetzle/precise

« back to all changes in this revision

Viewing changes to src/piece.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bart Martens
  • Date: 2011-06-02 02:51:09 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20110602025109-6jmxy9wekpwlrkw6
Tags: 2.0.0-1
* Synced with https://launchpad.net/~gottcode/+archive/gcppa/
* debian/control: Fixed "dpkg-source: warning: unknown information field
  'Suggests' in input data in general section of control info file".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/***********************************************************************
2
2
 *
3
 
 * Copyright (C) 2008 Graeme Gott <graeme@gottcode.org>
 
3
 * Copyright (C) 2008, 2010, 2011 Graeme Gott <graeme@gottcode.org>
4
4
 *
5
5
 * This program is free software: you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License as published by
22
22
#include "board.h"
23
23
#include "tile.h"
24
24
 
25
 
#include <QSet>
26
 
 
27
25
#include <cmath>
28
26
 
29
 
/*****************************************************************************/
30
 
// Lightwheight Piece-lookalike.
31
 
// Used for collision detection. Supports slicing in half to sub-pieces.
32
 
// Collision-detection works by slicing and bounds-checking halves until either
33
 
// no collision, or we've found single Tiles that actually collide
34
 
struct PieceHelper {
35
 
        QRect m_rect;
36
 
        QList<Tile*> m_children;
37
 
        const Piece * m_piece;
38
 
        const Board * m_board;
39
 
 
40
 
        PieceHelper(const PieceHelper &p) {
41
 
                m_piece = p.m_piece;
42
 
                m_board = p.m_board;
43
 
        }
44
 
 
45
 
        PieceHelper(const Piece *piece, const Board * board) {
46
 
                m_piece = piece;
47
 
                m_board = board;
48
 
                m_children = m_piece->children();
49
 
                foreach (Tile* tile, m_children) {
50
 
                        m_rect = m_rect.united(tile->rect().translated(tile->pos()).translated(m_piece->position()));
51
 
                }
52
 
        }
53
 
 
54
 
        void split(PieceHelper &a, PieceHelper &b) const
55
 
        {
56
 
                Q_ASSERT(m_children.size() > 1);
57
 
                bool is_fat = m_rect.width() > m_rect.height();
58
 
                int splitline;
59
 
                if (is_fat)
60
 
                        splitline = m_rect.center().x() - m_piece->position().x();
61
 
                else
62
 
                        splitline = m_rect.center().y() - m_piece->position().y();
63
 
 
64
 
                foreach (Tile* tile, m_children) {
65
 
                        PieceHelper *target = &a;
66
 
                        if (is_fat) {
67
 
                                if (tile->pos().x() >= splitline)
68
 
                                        target = &b;
69
 
                        } else {
70
 
                                if (tile->pos().y() >= splitline)
71
 
                                        target = &b;
72
 
                        }
73
 
                        target->m_children.append(tile);
74
 
                        target->m_rect = target->m_rect.united(tile->rect().translated(tile->pos()).translated(m_piece->position()));
75
 
                }
76
 
        }
77
 
 
78
 
        bool collidesWith(const PieceHelper &other) const
79
 
        {
80
 
                int margin = m_board->margin();
81
 
                QRect other_rect = other.m_rect.adjusted(-margin, -margin, margin, margin);
82
 
                if (m_children.size() <= 1) {
83
 
                        if (other.m_children.size() <= 1)
84
 
                                return m_rect.intersects(other_rect);
85
 
                        else
86
 
                                return other.collidesWith(*this);
87
 
                } else {
88
 
                        PieceHelper a(*this), b(*this);
89
 
                        split(a,b);
90
 
                        if (a.m_rect.intersects(other_rect)) {
91
 
                                if (other.collidesWith(a))
92
 
                                        return true;
93
 
                        }
94
 
                        if (b.m_rect.intersects(other_rect)) {
95
 
                                if (other.collidesWith(b))
96
 
                                        return true;
97
 
                        }
98
 
                }
99
 
                return false;
100
 
        }
101
 
};
102
 
 
103
 
/*****************************************************************************/
104
 
 
105
 
inline float roundUp(float value)
106
 
{
107
 
        return value >= 0.0f ? ceil(value) : floor(value);
108
 
}
109
 
 
110
 
/*****************************************************************************/
111
 
 
112
 
Piece::Piece(int rotation, const QPoint& pos, Board* board)
113
 
:       m_rotation(rotation),
 
27
//-----------------------------------------------------------------------------
 
28
 
 
29
Piece::Piece(const QPoint& pos, int rotation, const QList<Tile*>& tiles, Board* board)
 
30
        : m_board(board),
114
31
        m_pos(pos),
115
 
        m_rect(0, 0, 0, 0),
116
 
        m_board(board)
 
32
        m_tiles(tiles),
 
33
        m_shadow(tiles),
 
34
        m_rotation(0),
 
35
        m_depth(2),
 
36
        m_selected(true),
 
37
        m_changed(false)
117
38
{
 
39
        updateTiles();
 
40
        updateShadow();
 
41
 
 
42
        // Add bevels to tiles
 
43
        if (m_tiles.first()->bevel().y() == -1) {
 
44
                int count = m_tiles.count();
 
45
                for (int i = 0; i < count; ++i) {
 
46
                        Tile* tile = m_tiles.at(i);
 
47
                        int sides = 0;
 
48
                        sides |= containsTile(tile->column() - 1, tile->row());
 
49
                        sides |= containsTile(tile->column() + 1, tile->row()) << 1;
 
50
                        sides |= containsTile(tile->column(), tile->row() - 1) << 2;
 
51
                        sides |= containsTile(tile->column(), tile->row() + 1) << 3;
 
52
                        static const int bevels[14] = {13, 15, 11, 12, 5, 4, 1, 14, 6, 7, 3, 8, 2, 0};
 
53
                        tile->setBevel(bevels[sides - 1]);
 
54
                }
 
55
        }
 
56
 
 
57
        // Rotate
 
58
        rotate(rotation);
 
59
 
 
60
        setSelected(false);
118
61
}
119
62
 
120
 
/*****************************************************************************/
 
63
//-----------------------------------------------------------------------------
121
64
 
122
65
Piece::~Piece()
123
66
{
124
 
        qDeleteAll(m_children);
125
 
}
126
 
 
127
 
/*****************************************************************************/
128
 
 
129
 
QPoint Piece::scenePos() const
130
 
{
131
 
        return m_pos;
132
 
}
133
 
 
134
 
/*****************************************************************************/
135
 
 
136
 
QRect Piece::marginRect() const
137
 
{
138
 
        int margin = m_board->margin();
139
 
        return m_rect.translated(m_pos).adjusted(-margin, -margin, margin, margin);
140
 
}
141
 
 
142
 
/*****************************************************************************/
143
 
 
144
 
bool Piece::collidesWith(const Piece * other) const
145
 
{
146
 
        if (marginRect().intersects(other->boundingRect())) {
147
 
                PieceHelper a(this, this->m_board), b(other, other->m_board);
148
 
                bool retVal = a.collidesWith(b);
149
 
                return retVal;
 
67
        graphics_layer->removeArray(m_tile_array);
 
68
        graphics_layer->removeArray(m_shadow_array);
 
69
 
 
70
        qDeleteAll(m_tiles);
 
71
}
 
72
 
 
73
//-----------------------------------------------------------------------------
 
74
 
 
75
bool Piece::collidesWith(const Piece* other) const
 
76
{
 
77
        if (m_board->marginRect(boundingRect()).intersects(other->boundingRect())) {
 
78
                return m_collision_region_expanded.intersects(other->m_collision_region);
150
79
        } else {
151
80
                return false;
152
81
        }
153
82
}
154
83
 
155
 
/*****************************************************************************/
156
 
 
157
 
void Piece::rotateAround(Tile* tile)
158
 
{
159
 
        m_rect.setRect(-m_rect.bottom() - 1 + m_board->tileSize(), m_rect.left(), m_rect.height(), m_rect.width());
160
 
 
161
 
        if (tile) {
162
 
                QPoint pos = tile->scenePos() - scenePos();
163
 
                m_pos += QPoint(pos.x() + pos.y(), pos.y() - pos.x());
164
 
        }
165
 
 
166
 
        m_rotation += 1;
167
 
        if (m_rotation > 3)
168
 
                m_rotation = 0;
169
 
 
170
 
        QPoint pos;
171
 
        foreach (Tile* tile, m_children) {
172
 
                pos = tile->pos();
173
 
                qSwap(pos.rx(), pos.ry());
174
 
                pos.setX(-pos.x());
175
 
                tile->setPos(pos);
176
 
        }
177
 
}
178
 
 
179
 
/*****************************************************************************/
180
 
 
181
 
void Piece::attach(Tile* tile)
182
 
{
183
 
        tile->setParent(this);
184
 
        m_children.append(tile);
185
 
        m_rect = m_rect.united(tile->rect().translated(tile->pos()));
186
 
}
187
 
 
188
 
/*****************************************************************************/
189
 
 
190
 
void Piece::attach(Piece* piece)
191
 
{
192
 
        Q_ASSERT(piece != this);
193
 
 
194
 
        QPoint delta = piece->m_pos - m_pos;
195
 
 
196
 
        // Change parent of piece's children
197
 
        QList<Tile*> tiles = piece->m_children;
198
 
        foreach (Tile* tile, tiles) {
199
 
                tile->setPos(tile->pos() + delta);
200
 
                tile->setParent(this);
201
 
        }
202
 
        m_children += tiles;
203
 
        piece->m_children.clear();
204
 
 
205
 
        // Update bounding rectangle
206
 
        m_rect = m_rect.united(piece->m_rect.translated(delta));
207
 
 
208
 
        // Remove old parent
209
 
        m_board->removePiece(piece);
210
 
}
211
 
 
212
 
/*****************************************************************************/
 
84
//-----------------------------------------------------------------------------
 
85
 
 
86
QPoint Piece::randomPoint() const
 
87
{
 
88
        Tile* tile = m_tiles.at(rand() % m_tiles.count());
 
89
        return tile->scenePos() + QPoint(rand() % Tile::size, rand() % Tile::size);
 
90
}
 
91
 
 
92
//-----------------------------------------------------------------------------
213
93
 
214
94
void Piece::attachNeighbors()
215
95
{
216
 
        int margin = m_board->margin();
217
 
 
218
 
        // Create offset vectors
219
 
        int cos_size = 0;
220
 
        int sin_size = 0;
221
 
        switch (m_rotation) {
222
 
        case 0:
223
 
                cos_size = m_board->tileSize();
224
 
                break;
225
 
        case 1:
226
 
                sin_size = -m_board->tileSize();
227
 
                break;
228
 
        case 2:
229
 
                cos_size = -m_board->tileSize();
230
 
                break;
231
 
        case 3:
232
 
                sin_size = m_board->tileSize();
233
 
                break;
234
 
        }
235
 
        QPoint left(-cos_size, sin_size);
236
 
        QPoint right(cos_size, -sin_size);
237
 
        QPoint above(-sin_size, -cos_size);
238
 
        QPoint below(sin_size, cos_size);
239
 
 
240
 
        // Find closest tiles
241
 
        QSet<Piece*> closest_pieces;
242
 
        QPoint delta;
243
 
        int row, column;
244
 
        foreach (Piece* piece, m_board->findCollidingPieces(this)) {
245
 
                if (piece->m_rotation != m_rotation)
 
96
        foreach (Piece* piece, m_neighbors) {
 
97
                if (piece->m_rotation != m_rotation) {
246
98
                        continue;
247
 
 
248
 
                foreach (Tile* child, m_children) {
249
 
                        foreach (Tile* tile, piece->children()) {
250
 
                                delta = tile->scenePos() - child->scenePos();
251
 
 
252
 
                                // Determine which neighbor the child is of the tile
253
 
                                column = tile->column() - child->column() + 2;
254
 
                                row = tile->row() - child->row() + 2;
255
 
                                switch ((column * 1000) + row) {
256
 
                                case 1002:
257
 
                                        delta -= left;
258
 
                                        break;
259
 
                                case 3002:
260
 
                                        delta -= right;
261
 
                                        break;
262
 
                                case 2001:
263
 
                                        delta -= above;
264
 
                                        break;
265
 
                                case 2003:
266
 
                                        delta -= below;
267
 
                                        break;
268
 
                                default:
269
 
                                        continue;
270
 
                                }
271
 
 
272
 
                                if (delta.manhattanLength() <= margin) {
273
 
                                        closest_pieces.insert(piece);
274
 
                                        piece->moveBy(-delta);
275
 
                                        break;
276
 
                                }
277
 
                        }
278
 
                }
279
 
        }
280
 
 
281
 
        // Attach to closest pieces
282
 
        foreach (Piece* piece, closest_pieces) {
283
 
                attach(piece);
284
 
        }
285
 
}
286
 
 
287
 
/*****************************************************************************/
 
99
                }
 
100
 
 
101
                Tile* tile = m_tiles.first();
 
102
                Tile* piece_tile = piece->m_tiles.first();
 
103
                QPoint grid_delta = piece_tile->gridPos() - tile->gridPos();
 
104
                for (int i = 0; i < m_rotation; ++i) {
 
105
                        QPoint pos = grid_delta;
 
106
                        grid_delta.setX( -pos.y() );
 
107
                        grid_delta.setY( pos.x() );
 
108
                }
 
109
                QPoint top_left = tile->scenePos() + grid_delta;
 
110
                QPoint delta = top_left - piece_tile->scenePos();
 
111
 
 
112
                if (delta.manhattanLength() <= m_board->margin()) {
 
113
                        piece->moveBy(delta);
 
114
                        attach(piece);
 
115
                }
 
116
        }
 
117
}
 
118
 
 
119
//-----------------------------------------------------------------------------
 
120
 
 
121
void Piece::findNeighbors(const QList<Piece*>& pieces)
 
122
{
 
123
        // Find neighbor tiles
 
124
        static QList<QPoint> deltas = QList<QPoint>() << QPoint(-1,0) << QPoint(1,0) << QPoint(0,-1) << QPoint(0,1);
 
125
        QList<QPoint> tiles;
 
126
        foreach (Tile* tile, m_shadow) {
 
127
                QPoint pos(tile->column(), tile->row());
 
128
                foreach (const QPoint& delta, deltas) {
 
129
                        QPoint neighbor = pos + delta;
 
130
                        if (!containsTile(neighbor.x(), neighbor.y()) && !tiles.contains(neighbor)) {
 
131
                                tiles.append(neighbor);
 
132
                        }
 
133
                }
 
134
        }
 
135
 
 
136
        // Find neighbor pieces
 
137
        foreach (Piece* piece, pieces) {
 
138
                foreach (const QPoint& tile, tiles) {
 
139
                        if (piece->containsTile(tile.x(), tile.y())) {
 
140
                                m_neighbors.insert(piece);
 
141
                                break;
 
142
                        }
 
143
                }
 
144
        }
 
145
}
 
146
 
 
147
//-----------------------------------------------------------------------------
288
148
 
289
149
void Piece::pushNeighbors(const QPointF& inertia)
290
150
{
291
151
        while (Piece* neighbor = m_board->findCollidingPiece(this)) {
292
152
                // Determine which piece to move
293
153
                Piece *source, *target;
294
 
                if (m_rect.width() >= neighbor->m_rect.width() || m_rect.height() >= neighbor->m_rect.height()) {
 
154
                if (m_tiles.count() >= neighbor->m_tiles.count()) {
295
155
                        source = this;
296
156
                        target = neighbor;
297
157
                } else {
298
158
                        source = neighbor;
299
159
                        target = this;
300
160
                }
301
 
                QRect source_rect = source->marginRect();
 
161
                QRect source_rect = m_board->marginRect(source->boundingRect());
302
162
 
303
163
                // Calculate valid movement vector for target; preserve some motion from last move
304
164
                QPointF vector = target->boundingRect().center() - source_rect.center() + inertia;
305
 
                while (fabs(vector.x()) + fabs(vector.y()) < 1)
306
 
                        vector = QPointF(rand() - (RAND_MAX/2), rand() - (RAND_MAX/2));
 
165
                while (vector.manhattanLength() < 1.0) {
 
166
                        vector.setX( (rand() % Tile::size) - (Tile::size / 2) );
 
167
                        vector.setY( (rand() % Tile::size) - (Tile::size / 2) );
 
168
                }
307
169
 
308
170
                // Scale movement vector so that the largest dimension is 1
309
171
                QPointF direction = vector / qMax(fabs(vector.x()), fabs(vector.y()));
310
172
 
311
173
                // Push target until it is clear from current source
312
174
                // We use a binary-search, pushing away if collision, retracting otherwise
313
 
                QPoint orig = target->position();
 
175
                QPoint orig = target->m_pos;
314
176
                QRect united = source_rect.united(target->boundingRect());
315
177
                float min = 0.0f;
316
178
                float max = united.width() * united.height();
317
179
                while (true) {
318
180
                        float test = (min + max) / 2.0f;
319
 
                        float x = orig.x() + roundUp(test * direction.x());
320
 
                        float y = orig.y() + roundUp(test * direction.y());
321
 
                        target->moveTo(x, y);
322
 
                        if (source->collidesWith(target))
 
181
                        target->m_pos = orig + (test * direction).toPoint();
 
182
                        if (source->collidesWith(target)) {
323
183
                                min = test;
324
 
                        else {
 
184
                        } else {
325
185
                                max = test;
326
 
                                if (max - min < 1.0f)
 
186
                                if (max - min < 1.0f) {
327
187
                                        break;
 
188
                                }
328
189
                                Q_ASSERT(max - min > 0.01f);
329
190
                        }
330
191
                }
 
192
                target->updateVerts();
331
193
                Q_ASSERT(min < max);
332
194
                Q_ASSERT(!source->collidesWith(target));
333
195
 
336
198
        }
337
199
}
338
200
 
339
 
/*****************************************************************************/
 
201
//-----------------------------------------------------------------------------
 
202
 
 
203
void Piece::rotate(int rotations)
 
204
{
 
205
        if (rotations) {
 
206
                for (int i = 0; i < rotations; ++i) {
 
207
                        rotate();
 
208
                }
 
209
        } else {
 
210
                updateVerts();
 
211
        }
 
212
}
 
213
 
 
214
//-----------------------------------------------------------------------------
 
215
 
 
216
void Piece::rotate(const QPoint& origin)
 
217
{
 
218
        // Rotate 90 degrees counter-clockwise around origin
 
219
        if (!origin.isNull()) {
 
220
                QPoint pos = m_pos;
 
221
                pos.ry() += m_rect.height();
 
222
                m_pos.setX( origin.y() + origin.x() - pos.y() );
 
223
                m_pos.setY( origin.y() - origin.x() + pos.x() );
 
224
        }
 
225
        m_rect.setRect(0, 0, m_rect.height(), m_rect.width());
 
226
 
 
227
        // Rotate tiles 90 degrees counter-clockwise
 
228
        int count = m_tiles.count();
 
229
        for (int i = 0; i < count; ++i) {
 
230
                m_tiles.at(i)->rotate();
 
231
        }
 
232
 
 
233
        // Track how many rotations have occured
 
234
        m_rotation += 1;
 
235
        if (m_rotation > 3) {
 
236
                m_rotation = 0;
 
237
        }
 
238
 
 
239
        updateVerts();
 
240
}
 
241
 
 
242
//-----------------------------------------------------------------------------
 
243
 
 
244
void Piece::setDepth(int depth)
 
245
{
 
246
        m_depth = (depth + 1) * 2;
 
247
        updateVerts();
 
248
}
 
249
 
 
250
//-----------------------------------------------------------------------------
 
251
 
 
252
void Piece::setSelected(bool selected)
 
253
{
 
254
        m_selected = selected;
 
255
        if (!m_selected && m_changed) {
 
256
                updateCollisionRegions();
 
257
        }
 
258
}
 
259
 
 
260
//-----------------------------------------------------------------------------
340
261
 
341
262
void Piece::save(QXmlStreamWriter& xml) const
342
263
{
343
 
        xml.writeStartElement("group");
 
264
        xml.writeStartElement("piece");
 
265
        xml.writeAttribute("x", QString::number(m_pos.x()));
 
266
        xml.writeAttribute("y", QString::number(m_pos.y()));
344
267
        xml.writeAttribute("rotation", QString::number(m_rotation));
345
268
 
346
 
        m_children.at(0)->save(xml, true);
347
 
        for (int i = 1; i < m_children.count(); ++i)
348
 
                m_children.at(i)->save(xml);
 
269
        for (int i = 0; i < m_tiles.count(); ++i) {
 
270
                m_tiles.at(i)->save(xml);
 
271
        }
349
272
 
350
273
        xml.writeEndElement();
351
274
}
352
275
 
353
 
/*****************************************************************************/
 
276
//-----------------------------------------------------------------------------
 
277
 
 
278
void Piece::attach(Piece* piece)
 
279
{
 
280
        Q_ASSERT(piece != this);
 
281
 
 
282
        // Update position
 
283
        m_pos.setX(qMin(m_pos.x(), piece->m_pos.x()));
 
284
        m_pos.setY(qMin(m_pos.y(), piece->m_pos.y()));
 
285
 
 
286
        // Update position of attached tiles
 
287
        int rotation = m_rotation;
 
288
        for (int i = rotation; i < 4; ++i) {
 
289
                rotate();
 
290
                piece->rotate();
 
291
        }
 
292
        m_tiles += piece->m_tiles;
 
293
        piece->m_tiles.clear();
 
294
        updateTiles();
 
295
        rotate(rotation);
 
296
 
 
297
        // Update shadow
 
298
        m_shadow += piece->m_shadow;
 
299
        updateShadow();
 
300
 
 
301
        // Update neighbors
 
302
        m_neighbors += piece->m_neighbors;
 
303
        m_neighbors.remove(piece);
 
304
        m_neighbors.remove(this);
 
305
        foreach (Piece* neighbor, m_neighbors) {
 
306
                neighbor->m_neighbors.remove(piece);
 
307
                neighbor->m_neighbors.insert(this);
 
308
        }
 
309
 
 
310
        // Remove attached piece
 
311
        m_board->removePiece(piece);
 
312
}
 
313
 
 
314
//-----------------------------------------------------------------------------
 
315
 
 
316
bool Piece::containsTile(int column, int row)
 
317
{
 
318
        bool result = false;
 
319
        for (int i = 0; i < m_tiles.count(); ++i) {
 
320
                const Tile* tile = m_tiles.at(i);
 
321
                if (tile->column() == column && tile->row() == row) {
 
322
                        result = true;
 
323
                        break;
 
324
                }
 
325
        }
 
326
        return result;
 
327
}
 
328
 
 
329
//-----------------------------------------------------------------------------
 
330
 
 
331
void Piece::updateCollisionRegions()
 
332
{
 
333
        m_changed = false;
 
334
        m_collision_region = QRegion();
 
335
        m_collision_region_expanded = QRegion();
 
336
        QRect rect(0,0, Tile::size, Tile::size);
 
337
        for (int i = 0; i < m_tiles.count(); ++i) {
 
338
                rect.moveTo(m_tiles.at(i)->scenePos());
 
339
                m_collision_region += rect;
 
340
                m_collision_region_expanded += m_board->marginRect(rect);
 
341
        }
 
342
}
 
343
 
 
344
//-----------------------------------------------------------------------------
 
345
 
 
346
void Piece::updateShadow()
 
347
{
 
348
        QMutableListIterator<Tile*> i(m_shadow);
 
349
        while (i.hasNext()) {
 
350
                Tile* tile = i.next();
 
351
                if ( containsTile(tile->column() - 1, tile->row())
 
352
                        && containsTile(tile->column() + 1, tile->row())
 
353
                        && containsTile(tile->column(), tile->row() - 1)
 
354
                        && containsTile(tile->column(), tile->row() + 1) ) {
 
355
                        i.remove();
 
356
                }
 
357
        }
 
358
}
 
359
 
 
360
//-----------------------------------------------------------------------------
 
361
 
 
362
void Piece::updateTiles()
 
363
{
 
364
        int count = m_tiles.count();
 
365
 
 
366
        // Find bounding rectangle
 
367
        QPoint top_left = m_tiles.first()->gridPos();
 
368
        QPoint bottom_right = top_left + QPoint(Tile::size, Tile::size);
 
369
        QPoint pos;
 
370
        for (int i = 0; i < count; ++i) {
 
371
                pos = m_tiles.at(i)->gridPos();
 
372
                top_left.setX( qMin(pos.x(), top_left.x()) );
 
373
                top_left.setY( qMin(pos.y(), top_left.y()) );
 
374
                bottom_right.setX( qMax(pos.x() + Tile::size, bottom_right.x()) );
 
375
                bottom_right.setY( qMax(pos.y() + Tile::size, bottom_right.y()) );
 
376
        }
 
377
        m_rect.setRect(0, 0, bottom_right.x() - top_left.x(), bottom_right.y() - top_left.y());
 
378
 
 
379
        // Shift tiles to be inside rectangle
 
380
        Tile* tile;
 
381
        for (int i = 0; i < count; ++i) {
 
382
                tile = m_tiles.at(i);
 
383
                tile->setParent(this);
 
384
                tile->setPos(tile->gridPos() - top_left);
 
385
        }
 
386
}
 
387
 
 
388
//-----------------------------------------------------------------------------
 
389
 
 
390
void Piece::updateVerts()
 
391
{
 
392
        m_changed = true;
 
393
        if (!m_selected) {
 
394
                updateCollisionRegions();
 
395
        }
 
396
 
 
397
        QVector<Vertex> verts;
 
398
        int z = m_depth;
 
399
 
 
400
        // Update tile verts
 
401
        verts.reserve(m_tiles.count() * 4);
 
402
        for (int i = 0; i < m_tiles.count(); ++i) {
 
403
                Tile* tile = m_tiles.at(i);
 
404
 
 
405
                QPoint pos = tile->scenePos();
 
406
                int x1 = pos.x();
 
407
                int y1 = pos.y();
 
408
                int x2 = x1 + Tile::size;
 
409
                int y2 = y1 + Tile::size;
 
410
 
 
411
                const QPointF* corners = m_board->corners(rotation());
 
412
                float tx = tile->column() * m_board->tileTextureSize();
 
413
                float ty = tile->row() * m_board->tileTextureSize();
 
414
 
 
415
                float bx1 = tile->bevel().x();
 
416
                float by1 = tile->bevel().y();
 
417
                float bx2 = bx1 + 0.125;
 
418
                float by2 = by1 + 0.125;
 
419
 
 
420
                verts.append( Vertex(x1,y1,z, tx + corners[0].x(),ty + corners[0].y(), bx1,by1) );
 
421
                verts.append( Vertex(x1,y2,z, tx + corners[1].x(),ty + corners[1].y(), bx1,by2) );
 
422
                verts.append( Vertex(x2,y2,z, tx + corners[2].x(),ty + corners[2].y(), bx2,by2) );
 
423
                verts.append( Vertex(x2,y1,z, tx + corners[3].x(),ty + corners[3].y(), bx2,by1) );
 
424
        }
 
425
        graphics_layer->updateArray(m_tile_array, verts);
 
426
 
 
427
        // Update shadow verts
 
428
        z--;
 
429
        static const int offset = Tile::size / 2;
 
430
        static const int size = Tile::size * 2;
 
431
        verts.clear();
 
432
        verts.reserve(m_shadow.count() * 4);
 
433
        for (int i = 0; i < m_shadow.count(); ++i) {
 
434
                QPoint pos = m_shadow.at(i)->scenePos();
 
435
                int x1 = pos.x() - offset;
 
436
                int y1 = pos.y() - offset;
 
437
                int x2 = x1 + size;
 
438
                int y2 = y1 + size;
 
439
 
 
440
                verts.append( Vertex(x1,y1,z, 0,0) );
 
441
                verts.append( Vertex(x1,y2,z, 0,1) );
 
442
                verts.append( Vertex(x2,y2,z, 1,1) );
 
443
                verts.append( Vertex(x2,y1,z, 1,0) );
 
444
        }
 
445
        graphics_layer->updateArray(m_shadow_array, verts);
 
446
 
 
447
        // Update scene rectangle
 
448
        m_board->updateSceneRectangle(this);
 
449
}
 
450
 
 
451
//-----------------------------------------------------------------------------