2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
15 #include <boost/random/uniform_smallint.hpp>
22 using namespace boost
;
24 struct ExplosionFragment
{
28 ExplosionFragment() : m_pcount(0) {}
31 /* inherit instead of typedef to ease forward declaration :) */
32 class SpriteExplosion
: public std::vector
<ExplosionFragment
> {
36 Sprite::Sprite(const QPixmap
& pix
, KGameCanvasAbstract
* canvas
,
37 const QPoint
& location
)
38 : KGameCanvasPixmap(pix
, canvas
)
45 , m_dummy_opacity(255)
46 , m_dummy_visible(false)
62 Sprite
* Sprite::duplicate() const {
63 return new Sprite(pixmap(), canvas(), pos() );
66 void Sprite::setThumb(const QImage
& thumb
) {
67 std::cout
<< "setting thumb" << std::endl
;
68 QPixmap pix
= m_pixmap
;
69 int width
= pix
.width() / 2;
70 int height
= pix
.height() / 2;
71 QPixmap thumb_pix
= QPixmap::fromImage(
72 thumb
.scaled(width
, height
,
73 Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
));
76 QPainter
painter(&pix
);
77 painter
.drawPixmap(pix
.width() - width
, 0, thumb_pix
);
80 KGameCanvasPixmap::setPixmap(pix
);
83 void Sprite::removeThumb() {
84 KGameCanvasPixmap::setPixmap(m_pixmap
);
87 void Sprite::setPixmap(const QPixmap
& pix
) {
89 KGameCanvasPixmap::setPixmap(pix
);
92 void Sprite::setMovementAnimation(const shared_ptr
<Animation
>& animation
) {
93 m_movement_animation
= animation
;
96 weak_ptr
<Animation
> Sprite::movementAnimation() const {
97 return m_movement_animation
;
100 void Sprite::setFadeAnimation(const shared_ptr<FadeAnimation>& animation) {
101 m_fade_animation = animation;
104 weak_ptr<FadeAnimation> Sprite::fadeAnimation() const {
105 return m_fade_animation;
108 void Sprite::setExplosionStep(float f
) {
113 void Sprite::setupExplosion(Random
& random
) {
118 m_explosion
= createExplosion(random
);
122 * this function generate many polygons that fill the image, + their random speeds
124 * Split points are some random point on the border (ordered accordin to the angle).
125 * The generated polygons are created cutting from each split point to (according
126 * to random's will) the center -or- a point in the mid way from the center to the
127 * previous or next split point.
129 SpriteExplosion
* Sprite::createExplosion(Random
& random
) {
130 SpriteExplosion
* retv
= new SpriteExplosion
;
131 int w
= pixmap().width();
132 int h
= pixmap().height();
136 int split_side
[40]; // the side of the image, 0 to 3
137 int split_start
[40]; // -1 to 1
138 QPoint split_point
[40];
139 QPoint split_start_point
[40];
145 /* generate few subsequent angles */
146 Random::RealGenerator random_float
= random
.rand(0.4, 0.7);
147 for(float s
= 0; s
< 2*M_PI
-0.3; s
+= random_float()) {
148 splits
[num_splits
] = s
;
149 splits_r
[num_splits
] = cos(s
);
150 splits_i
[num_splits
] = sin(s
);
154 /* generate the random center and calculate the relative corners */
155 random_float
= random
.rand(0.4, 0.6);
156 QPoint
center(int(w
* random_float()), int(h
* random_float()));
157 QPoint corners
[4] = { -center
, QPoint(w
,0)-center
,
158 QPoint(w
,h
)-center
, QPoint(0,h
)-center
};
160 /* for each split angle, find the size of the rect that contains the split point */
161 for(int i
=0;i
<num_splits
;i
++) {
164 for(int j
=0;j
<4;j
++) {
167 /* the imaginary part of the products (as complex numbers) must be >0 and <0 */
168 if(corners
[j
].x()*splits_i
[i
]-corners
[j
].y()*splits_r
[i
] >= 0
169 && corners
[j1
].x()*splits_i
[i
]-corners
[j1
].y()*splits_r
[i
] < 0 ) {
172 float fact
= (corners
[j
].x()*corners
[j1
].y()-corners
[j
].y()*corners
[j1
].x())/
173 (splits_r
[i
]*(corners
[j1
].y()-corners
[j
].y())-
174 splits_i
[i
]*(corners
[j1
].x()-corners
[j
].x()));
175 float x
= splits_r
[i
]*fact
;
176 float y
= splits_i
[i
]*fact
;
177 split_point
[i
] = QPoint(int(x
+0.5), int(y
+0.5));
182 /* there should really be one :) */
183 Q_ASSERT(split_side
[i
] != -1);
186 /* generate the split points connections. Some will be connected with the center (0),
187 others will be connected to a mid-way point of the previous or next points (-1/+1) */
188 Random::IntegerGenerator coin
= random
.rand(0, 1);
189 Random::IntegerGenerator die3
= random
.rand(0, 2);
191 for(int i
=1;i
<num_splits
;i
++) {
192 if(split_start
[i
-1]==1)
194 else if(split_start
[i
-1]==-1)
195 split_start
[i
] = coin();
197 split_start
[i
] = die3() - 1;
200 /* calculate such mid-way points */
201 random_float
= random
.rand(0.1, 0.3);
202 for(int i
=0;i
<num_splits
;i
++) {
203 int r
= (i
+split_start
[i
]);
204 r
= r
<0 ? num_splits
-1 : r
>=num_splits
? 0 : r
;
206 split_start_point
[i
] = QPoint();
208 split_start_point
[i
] = split_point
[r
] * random_float();
211 random_float
= random
.rand(0.5, 1.2);
212 for(int i
=0;i
<num_splits
;i
++) {
214 int i1
= (i
+1 == num_splits
) ? 0 : i
+1;
216 /* generate polygons, they have at most 6 sides */
217 f
.m_polygon
[f
.m_pcount
++] = center
+ split_point
[i
];
218 if(split_side
[i
] != split_side
[i1
])
219 f
.m_polygon
[f
.m_pcount
++] = center
+ corners
[split_side
[i1
]];
220 f
.m_polygon
[f
.m_pcount
++] = center
+ split_point
[i1
];
222 if(split_start
[i1
]==+1)
223 f
.m_polygon
[f
.m_pcount
++] = center
+ split_start_point
[i1
];
225 if(split_start
[i1
]==-1)
226 f
.m_polygon
[f
.m_pcount
++] = center
+ split_start_point
[i1
];
227 else if(split_start
[i
]==+1)
228 f
.m_polygon
[f
.m_pcount
++] = center
+ split_start_point
[i
];
230 f
.m_polygon
[f
.m_pcount
++] = center
;
232 if(split_start
[i
]==-1)
233 f
.m_polygon
[f
.m_pcount
++] = center
+ split_start_point
[i
];
235 /* generate a random speed */
236 f
.m_speed
= (split_point
[i
]+split_point
[i1
]) * random_float();
244 void Sprite::setRotation(float f
) {
249 void Sprite::setScale(float f
) {
254 void Sprite::paint(QPainter
* p
) {
257 /* if scale/rotate change the painter matrix */
258 if(m_rotation
!= 0.0 || m_scale
!= 1.0) {
259 QRectF rect
= pixmap().rect();
260 QPointF
center(rect
.width()*0.5, rect
.height()*0.5);
262 p
->translate(center
+pos());
263 p
->rotate(m_rotation
*180.0/M_PI
);
264 p
->scale(m_scale
, m_scale
);
265 p
->translate(-center
-pos());
269 p
->setPen(Qt::NoPen
);
270 p
->setBrush(pixmap());
273 for(int i
=0;i
<int(m_explosion
->size());i
++) {
274 ExplosionFragment
& f
= (*m_explosion
)[i
];
275 QPoint delta
= f
.m_speed
*m_explode_step
;
278 p
->drawConvexPolygon(f
.m_polygon
, f
.m_pcount
);
279 p
->translate(-delta
);
281 p
->translate(-pos());
284 KGameCanvasPixmap::paint(p
);
286 if(m_rotation
!= 0.0 || m_scale
!= 1.0)
290 QRect
Sprite::rect() const {
293 /* if exploding, set the rect to the bounding rect of the pieces */
295 int x1
=99999, x2
=-99999, y1
=99999, y2
=-99999;
297 for(int i
=0;i
<int(m_explosion
->size());i
++) {
298 ExplosionFragment
& f
= (*m_explosion
)[i
];
299 QPoint delta
= f
.m_speed
*m_explode_step
;
301 for(int j
=0;j
<f
.m_pcount
;j
++) {
302 x1
= std::min(x1
, f
.m_polygon
[j
].x()+delta
.x());
303 y1
= std::min(y1
, f
.m_polygon
[j
].y()+delta
.y());
304 x2
= std::max(x2
, f
.m_polygon
[j
].x()+delta
.x());
305 y2
= std::max(y2
, f
.m_polygon
[j
].y()+delta
.y());
309 retv
= QRect(x1
,y1
,x2
-x1
,y2
-y1
).translated(pos());
312 retv
= KGameCanvasPixmap::rect();
314 /* transform the rectangle as needed */
315 if(m_rotation
!= 0.0 || m_scale
!= 1.0) {
316 QRectF rect
= pixmap().rect();
317 QPointF
center(rect
.width()*0.5, rect
.height()*0.5);
319 transf
.translate(+center
.x()+pos().x(), +center
.y()+pos().y());
320 transf
.rotate(m_rotation
*180.0/M_PI
);
321 transf
.scale(m_scale
, m_scale
);
322 transf
.translate(-center
.x()-pos().x(), -center
.y()-pos().y());
323 return transf
.mapRect( retv
);