]> git.lizzy.rs Git - dragonfireclient.git/blob - src/irrlichtwrapper.cpp
Now texture handling is fast. Also now players are saved on disk.
[dragonfireclient.git] / src / irrlichtwrapper.cpp
1 #include "irrlichtwrapper.h"
2 #include "constants.h"
3 #include "string.h"
4 #include "strfnd.h"
5
6 IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
7 {
8         m_main_thread = get_current_thread_id();
9         m_device_mutex.Init();
10         m_device = device;
11 }
12
13 void IrrlichtWrapper::Run()
14 {
15         /*
16                 Fetch textures
17         */
18         if(m_get_texture_queue.size() > 0)
19         {
20                 GetRequest<TextureSpec, video::ITexture*, u8, u8>
21                                 request = m_get_texture_queue.pop();
22
23                 dstream<<"got texture request with"
24                                 <<" key.tids[0]="<<request.key.tids[0]
25                                 <<" [1]="<<request.key.tids[1]
26                                 <<std::endl;
27
28                 GetResult<TextureSpec, video::ITexture*, u8, u8>
29                                 result;
30                 result.key = request.key;
31                 result.callers = request.callers;
32                 result.item = getTextureDirect(request.key);
33
34                 request.dest->push_back(result);
35         }
36 }
37
38 textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
39 {
40         u32 id = m_namecache.getId(name);
41         return id;
42 }
43
44 std::string IrrlichtWrapper::getTextureName(textureid_t id)
45 {
46         std::string name("");
47         m_namecache.getValue(id, name);
48         // In case it was found, return the name; otherwise return an empty name.
49         return name;
50 }
51
52 video::ITexture* IrrlichtWrapper::getTexture(const std::string &name)
53 {
54         TextureSpec spec(getTextureId(name));
55         return getTexture(spec);
56 }
57
58 video::ITexture* IrrlichtWrapper::getTexture(const TextureSpec &spec)
59 {
60         if(spec.empty())
61                 return NULL;
62         
63         video::ITexture *t = m_texturecache.get(spec);
64         if(t != NULL)
65                 return t;
66         
67         if(get_current_thread_id() == m_main_thread)
68         {
69                 dstream<<"Getting texture directly: spec.tids[0]="
70                                 <<spec.tids[0]<<std::endl;
71                                 
72                 t = getTextureDirect(spec);
73         }
74         else
75         {
76                 // We're gonna ask the result to be put into here
77                 ResultQueue<TextureSpec, video::ITexture*, u8, u8> result_queue;
78                 
79                 // Throw a request in
80                 m_get_texture_queue.add(spec, 0, 0, &result_queue);
81                 
82                 dstream<<"Waiting for texture from main thread: spec.tids[0]="
83                                 <<spec.tids[0]<<std::endl;
84                 
85                 try
86                 {
87                         // Wait result for a second
88                         GetResult<TextureSpec, video::ITexture*, u8, u8>
89                                         result = result_queue.pop_front(1000);
90                 
91                         // Check that at least something worked OK
92                         assert(result.key == spec);
93
94                         t = result.item;
95                 }
96                 catch(ItemNotFoundException &e)
97                 {
98                         dstream<<"Waiting for texture timed out."<<std::endl;
99                         t = NULL;
100                 }
101         }
102
103         // Add to cache and return
104         m_texturecache.set(spec, t);
105         return t;
106 }
107
108 // Draw a progress bar on the image
109 void make_progressbar(float value, video::IImage *image);
110
111 /*
112         Texture fetcher/maker function, called always from the main thread
113 */
114
115 video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
116 {
117         // This would result in NULL image
118         if(spec.empty())
119                 return NULL;
120         
121         // Don't generate existing stuff
122         video::ITexture *t = m_texturecache.get(spec);
123         if(t != NULL)
124         {
125                 dstream<<"WARNING: Existing stuff requested from "
126                                 "getTextureDirect()"<<std::endl;
127                 return t;
128         }
129         
130         video::IVideoDriver* driver = m_device->getVideoDriver();
131
132         /*
133                 An image will be built from files and then converted into a texture.
134         */
135         video::IImage *baseimg = NULL;
136
137         /*
138                 Irrlicht requires a name for every texture, with which it
139                 will be stored internally in irrlicht.
140         */
141         std::string texture_name;
142
143         for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
144         {
145                 textureid_t tid = spec.tids[i];
146                 if(tid == 0)
147                         continue;
148
149                 std::string name = getTextureName(tid);
150                 
151                 // Add something to the name so that it is a unique identifier.
152                 texture_name += "[";
153                 texture_name += name;
154                 texture_name += "]";
155
156                 if(name[0] != '[')
157                 {
158                         // A normal texture; load it from a file
159                         std::string path = porting::getDataPath(name.c_str());
160                         dstream<<"getTextureDirect(): Loading path \""<<path
161                                         <<"\""<<std::endl;
162                         video::IImage *image = driver->createImageFromFile(path.c_str());
163
164                         if(image == NULL)
165                         {
166                                 dstream<<"WARNING: Could not load image \""<<name
167                                                 <<"\" from path \""<<path<<"\""
168                                                 <<" while building texture"<<std::endl;
169                                 continue;
170                         }
171
172                         // If base image is NULL, load as base.
173                         if(baseimg == NULL)
174                         {
175                                 dstream<<"Setting "<<name<<" as base"<<std::endl;
176                                 /*
177                                         Copy it this way to get an alpha channel.
178                                         Otherwise images with alpha cannot be blitted on 
179                                         images that don't have alpha in the original file.
180                                 */
181                                 // This is a deprecated method
182                                 //baseimg = driver->createImage(video::ECF_A8R8G8B8, image);
183                                 core::dimension2d<u32> dim = image->getDimension();
184                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
185                                 image->copyTo(baseimg);
186                                 image->drop();
187                                 //baseimg = image;
188                         }
189                         // Else blit on base.
190                         else
191                         {
192                                 dstream<<"Blitting "<<name<<" on base"<<std::endl;
193                                 // Size of the copied area
194                                 core::dimension2d<u32> dim = image->getDimension();
195                                 //core::dimension2d<u32> dim(16,16);
196                                 // Position to copy the blitted to in the base image
197                                 core::position2d<s32> pos_to(0,0);
198                                 // Position to copy the blitted from in the blitted image
199                                 core::position2d<s32> pos_from(0,0);
200                                 // Blit
201                                 image->copyToWithAlpha(baseimg, pos_to,
202                                                 core::rect<s32>(pos_from, dim),
203                                                 video::SColor(255,255,255,255),
204                                                 NULL);
205                                 // Drop image
206                                 image->drop();
207                         }
208                 }
209                 else
210                 {
211                         // A special texture modification
212                         dstream<<"getTextureDirect(): generating \""<<name<<"\""
213                                         <<std::endl;
214                         if(name.substr(0,6) == "[crack")
215                         {
216                                 u16 progression = stoi(name.substr(6));
217                                 // Size of the base image
218                                 core::dimension2d<u32> dim(16, 16);
219                                 // Size of the crack image
220                                 //core::dimension2d<u32> dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
221                                 // Position to copy the crack to in the base image
222                                 core::position2d<s32> pos_base(0, 0);
223                                 // Position to copy the crack from in the crack image
224                                 core::position2d<s32> pos_other(0, 16 * progression);
225
226                                 video::IImage *crackimage = driver->createImageFromFile(
227                                                 porting::getDataPath("crack.png").c_str());
228                                 crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
229                                                 core::rect<s32>(pos_other, dim),
230                                                 video::SColor(255,255,255,255),
231                                                 NULL);
232                                 crackimage->drop();
233                         }
234                         else if(name.substr(0,12) == "[progressbar")
235                         {
236                                 float value = stof(name.substr(12));
237                                 make_progressbar(value, baseimg);
238                         }
239                         else
240                         {
241                                 dstream<<"WARNING: getTextureDirect(): Invalid "
242                                                 " texture: \""<<name<<"\""<<std::endl;
243                         }
244                 }
245         }
246
247         // If no resulting image, return NULL
248         if(baseimg == NULL)
249         {
250                 dstream<<"getTextureDirect(): baseimg is NULL (attempted to"
251                                 " create texture \""<<texture_name<<"\""<<std::endl;
252                 return NULL;
253         }
254         
255         /*// DEBUG: Paint some pixels
256         video::SColor c(255,255,0,0);
257         baseimg->setPixel(1,1, c);
258         baseimg->setPixel(1,14, c);
259         baseimg->setPixel(14,1, c);
260         baseimg->setPixel(14,14, c);*/
261
262         // Create texture from resulting image
263         t = driver->addTexture(texture_name.c_str(), baseimg);
264         baseimg->drop();
265
266         dstream<<"getTextureDirect(): created texture \""<<texture_name
267                         <<"\""<<std::endl;
268
269         return t;
270
271 }
272
273 void make_progressbar(float value, video::IImage *image)
274 {
275         if(image == NULL)
276                 return;
277         
278         core::dimension2d<u32> size = image->getDimension();
279
280         u32 barheight = 1;
281         u32 barpad_x = 1;
282         u32 barpad_y = 1;
283         u32 barwidth = size.Width - barpad_x*2;
284         v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
285
286         u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
287
288         video::SColor active(255,255,0,0);
289         video::SColor inactive(255,0,0,0);
290         for(u32 x0=0; x0<barwidth; x0++)
291         {
292                 video::SColor *c;
293                 if(x0 < barvalue_i)
294                         c = &active;
295                 else
296                         c = &inactive;
297                 u32 x = x0 + barpos.X;
298                 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
299                 {
300                         image->setPixel(x,y, *c);
301                 }
302         }
303 }
304
305