]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGUISpriteBank.cpp
SpriteBank: error check on non existing textureNumber
[irrlicht.git] / source / Irrlicht / CGUISpriteBank.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CGUISpriteBank.h"\r
6 \r
7 #include "IGUIEnvironment.h"\r
8 #include "IVideoDriver.h"\r
9 #include "ITexture.h"\r
10 \r
11 namespace irr\r
12 {\r
13 namespace gui\r
14 {\r
15 \r
16 CGUISpriteBank::CGUISpriteBank(IGUIEnvironment* env) :\r
17         Environment(env), Driver(0)\r
18 {\r
19         #ifdef _DEBUG\r
20         setDebugName("CGUISpriteBank");\r
21         #endif\r
22 \r
23         if (Environment)\r
24         {\r
25                 Driver = Environment->getVideoDriver();\r
26                 if (Driver)\r
27                         Driver->grab();\r
28         }\r
29 }\r
30 \r
31 \r
32 CGUISpriteBank::~CGUISpriteBank()\r
33 {\r
34         clear();\r
35 \r
36         // drop video driver\r
37         if (Driver)\r
38                 Driver->drop();\r
39 }\r
40 \r
41 \r
42 core::array< core::rect<s32> >& CGUISpriteBank::getPositions()\r
43 {\r
44         return Rectangles;\r
45 }\r
46 \r
47 \r
48 core::array< SGUISprite >& CGUISpriteBank::getSprites()\r
49 {\r
50         return Sprites;\r
51 }\r
52 \r
53 \r
54 u32 CGUISpriteBank::getTextureCount() const\r
55 {\r
56         return Textures.size();\r
57 }\r
58 \r
59 \r
60 video::ITexture* CGUISpriteBank::getTexture(u32 index) const\r
61 {\r
62         if (index < Textures.size())\r
63                 return Textures[index];\r
64         else\r
65                 return 0;\r
66 }\r
67 \r
68 \r
69 void CGUISpriteBank::addTexture(video::ITexture* texture)\r
70 {\r
71         if (texture)\r
72                 texture->grab();\r
73 \r
74         Textures.push_back(texture);\r
75 }\r
76 \r
77 \r
78 void CGUISpriteBank::setTexture(u32 index, video::ITexture* texture)\r
79 {\r
80         while (index >= Textures.size())\r
81                 Textures.push_back(0);\r
82 \r
83         if (texture)\r
84                 texture->grab();\r
85 \r
86         if (Textures[index])\r
87                 Textures[index]->drop();\r
88 \r
89         Textures[index] = texture;\r
90 }\r
91 \r
92 \r
93 //! clear everything\r
94 void CGUISpriteBank::clear()\r
95 {\r
96         // drop textures\r
97         for (u32 i=0; i<Textures.size(); ++i)\r
98         {\r
99                 if (Textures[i])\r
100                         Textures[i]->drop();\r
101         }\r
102         Textures.clear();\r
103         Sprites.clear();\r
104         Rectangles.clear();\r
105 }\r
106 \r
107 //! Add the texture and use it for a single non-animated sprite.\r
108 s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture)\r
109 {\r
110         if ( !texture )\r
111                 return -1;\r
112 \r
113         addTexture(texture);\r
114         u32 textureIndex = getTextureCount() - 1;\r
115 \r
116         u32 rectangleIndex = Rectangles.size();\r
117         Rectangles.push_back( core::rect<s32>(0,0, texture->getOriginalSize().Width, texture->getOriginalSize().Height) );\r
118 \r
119         SGUISprite sprite;\r
120         sprite.frameTime = 0;\r
121 \r
122         SGUISpriteFrame frame;\r
123         frame.textureNumber = textureIndex;\r
124         frame.rectNumber = rectangleIndex;\r
125         sprite.Frames.push_back( frame );\r
126 \r
127         Sprites.push_back( sprite );\r
128 \r
129         return Sprites.size() - 1;\r
130 }\r
131 \r
132 // get FrameNr for time. return true on exisiting frame\r
133 inline bool CGUISpriteBank::getFrameNr(u32& frame,u32 index, u32 time, bool loop) const\r
134 {\r
135         frame = 0;\r
136         if (index >= Sprites.size())\r
137                 return false;\r
138 \r
139         const SGUISprite& sprite = Sprites[index];\r
140         const u32 frameSize = sprite.Frames.size();\r
141         if (frameSize < 1)\r
142                 return false;\r
143 \r
144         if (sprite.frameTime)\r
145         {\r
146                 u32 f = (time / sprite.frameTime);\r
147                 if (loop)\r
148                         frame = f % frameSize;\r
149                 else\r
150                         frame = (f >= frameSize) ? frameSize - 1 : f;\r
151         }\r
152         return true;\r
153 }\r
154 \r
155 //! draws a sprite in 2d with scale and color\r
156 void CGUISpriteBank::draw2DSprite(u32 index, const core::position2di& pos,\r
157                 const core::rect<s32>* clip, const video::SColor& color,\r
158                 u32 starttime, u32 currenttime, bool loop, bool center)\r
159 {\r
160         u32 frame = 0;\r
161         if (!getFrameNr(frame, index, currenttime - starttime, loop))\r
162                 return;\r
163 \r
164         const video::ITexture* tex = getTexture(Sprites[index].Frames[frame].textureNumber);\r
165         if (!tex)\r
166                 return;\r
167 \r
168         const u32 rn = Sprites[index].Frames[frame].rectNumber;\r
169         if (rn >= Rectangles.size())\r
170                 return;\r
171 \r
172         const core::rect<s32>& r = Rectangles[rn];\r
173         core::position2di p(pos);\r
174         if (center)\r
175         {\r
176                 p -= r.getSize() / 2;\r
177         }\r
178         Driver->draw2DImage(tex, p, r, clip, color, true);\r
179 }\r
180 \r
181 void CGUISpriteBank::draw2DSprite(u32 index, const core::rect<s32>& destRect,\r
182                 const core::rect<s32>* clip, const video::SColor * const colors,\r
183                 u32 timeTicks, bool loop)\r
184 {\r
185         u32 frame = 0;\r
186         if (!getFrameNr(frame,index, timeTicks, loop))\r
187                 return;\r
188 \r
189         const video::ITexture* tex = getTexture(Sprites[index].Frames[frame].textureNumber);\r
190         if (!tex)\r
191                 return;\r
192 \r
193         const u32 rn = Sprites[index].Frames[frame].rectNumber;\r
194         if (rn >= Rectangles.size())\r
195                 return;\r
196 \r
197         Driver->draw2DImage(tex, destRect, Rectangles[rn], clip, colors, true);\r
198 }\r
199 \r
200 void CGUISpriteBank::draw2DSpriteBatch( const core::array<u32>& indices,\r
201                                                                                 const core::array<core::position2di>& pos,\r
202                                                                                 const core::rect<s32>* clip,\r
203                                                                                 const video::SColor& color,\r
204                                                                                 u32 starttime, u32 currenttime,\r
205                                                                                 bool loop, bool center)\r
206 {\r
207         const irr::u32 drawCount = core::min_<u32>(indices.size(), pos.size());\r
208 \r
209         if (!getTextureCount())\r
210                 return;\r
211         core::array<SDrawBatch> drawBatches(getTextureCount());\r
212         for (u32 i=0; i < Textures.size(); ++i)\r
213         {\r
214                 drawBatches.push_back(SDrawBatch());\r
215                 drawBatches[i].positions.reallocate(drawCount);\r
216                 drawBatches[i].sourceRects.reallocate(drawCount);\r
217         }\r
218 \r
219         for (u32 i = 0; i < drawCount; ++i)\r
220         {\r
221                 const u32 index = indices[i];\r
222 \r
223                 // work out frame number\r
224                 u32 frame = 0;\r
225                 if (!getFrameNr(frame, index, currenttime - starttime, loop))\r
226                         return;\r
227 \r
228                 const u32 texNum = Sprites[index].Frames[frame].textureNumber;\r
229                 if (texNum >= drawBatches.size())\r
230                 {\r
231                         continue;\r
232                 }\r
233                 SDrawBatch& currentBatch = drawBatches[texNum];\r
234 \r
235                 const u32 rn = Sprites[index].Frames[frame].rectNumber;\r
236                 if (rn >= Rectangles.size())\r
237                         return;\r
238 \r
239                 const core::rect<s32>& r = Rectangles[rn];\r
240 \r
241                 if (center)\r
242                 {\r
243                         core::position2di p = pos[i];\r
244                         p -= r.getSize() / 2;\r
245 \r
246                         currentBatch.positions.push_back(p);\r
247                         currentBatch.sourceRects.push_back(r);\r
248                 }\r
249                 else\r
250                 {\r
251                         currentBatch.positions.push_back(pos[i]);\r
252                         currentBatch.sourceRects.push_back(r);\r
253                 }\r
254         }\r
255 \r
256         for(u32 i = 0;i < drawBatches.size();i++)\r
257         {\r
258                 if(!drawBatches[i].positions.empty() && !drawBatches[i].sourceRects.empty())\r
259                         Driver->draw2DImageBatch(getTexture(i), drawBatches[i].positions,\r
260                                 drawBatches[i].sourceRects, clip, color, true);\r
261         }\r
262 }\r
263 \r
264 } // namespace gui\r
265 } // namespace irr\r