]> git.lizzy.rs Git - dragonfireclient.git/blob - src/irrlichtwrapper.cpp
new hotbar, more minecraft-like
[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_running = true;
9         m_main_thread = get_current_thread_id();
10         m_device_mutex.Init();
11         m_device = device;
12 }
13
14 IrrlichtWrapper::~IrrlichtWrapper()
15 {
16 #if 0
17         // Clear image cache
18         for(core::map<std::string, video::IImage*>::Iterator
19                         i = m_imagecache.getIterator();
20                         i.atEnd() == false; i++)
21         {
22                 i.getNode()->getValue()->drop();
23         }
24 #endif
25 }
26
27 void IrrlichtWrapper::Run()
28 {
29 #if 0
30         /*
31                 Fetch textures
32         */
33         if(m_get_texture_queue.size() > 0)
34         {
35                 GetRequest<TextureSpec, video::ITexture*, u8, u8>
36                                 request = m_get_texture_queue.pop();
37
38                 dstream<<"got texture request with"
39                                 <<" key.tids[0]="<<request.key.tids[0]
40                                 <<" [1]="<<request.key.tids[1]
41                                 <<std::endl;
42
43                 GetResult<TextureSpec, video::ITexture*, u8, u8>
44                                 result;
45                 result.key = request.key;
46                 result.callers = request.callers;
47                 result.item = getTextureDirect(request.key);
48
49                 request.dest->push_back(result);
50         }
51 #endif
52 }
53
54 void IrrlichtWrapper::Shutdown(bool shutdown)
55 {
56         m_running = !shutdown;
57 }
58
59 IrrlichtDevice* IrrlichtWrapper::getDevice()
60 {
61         if(get_current_thread_id() != m_main_thread)
62         {
63                 dstream<<"WARNING: IrrlichtWrapper::getDevice() called "
64                                 "not from main thread"<<std::endl;
65                 return NULL;
66         }
67         return m_device;
68 }
69
70 #if 0
71 textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
72 {
73         u32 id = m_namecache.getId(name);
74         return id;
75 }
76
77 std::string IrrlichtWrapper::getTextureName(textureid_t id)
78 {
79         std::string name("");
80         m_namecache.getValue(id, name);
81         // In case it was found, return the name; otherwise return an empty name.
82         return name;
83 }
84
85 video::ITexture* IrrlichtWrapper::getTexture(const std::string &filename)
86 {
87         TextureSpec spec(getTextureId(filename));
88         return getTexture(spec);
89 }
90
91 video::ITexture* IrrlichtWrapper::getTexture(const TextureSpec &spec)
92 {
93         if(spec.empty())
94                 return NULL;
95         
96         video::ITexture *t = m_texturecache.get(spec);
97         if(t != NULL)
98                 return t;
99         
100         if(get_current_thread_id() == m_main_thread)
101         {
102                 dstream<<"Getting texture directly: spec.tids[0]="
103                                 <<spec.tids[0]<<std::endl;
104                                 
105                 t = getTextureDirect(spec);
106         }
107         else
108         {
109                 // If irrlicht has shut down, just return NULL
110                 if(m_running == false)
111                         return NULL;
112
113                 // We're gonna ask the result to be put into here
114                 ResultQueue<TextureSpec, video::ITexture*, u8, u8> result_queue;
115                 
116                 // Throw a request in
117                 m_get_texture_queue.add(spec, 0, 0, &result_queue);
118                 
119                 dstream<<"Waiting for texture from main thread: spec.tids[0]="
120                                 <<spec.tids[0]<<std::endl;
121                 
122                 try
123                 {
124                         // Wait result for a second
125                         GetResult<TextureSpec, video::ITexture*, u8, u8>
126                                         result = result_queue.pop_front(1000);
127                 
128                         // Check that at least something worked OK
129                         assert(result.key == spec);
130
131                         t = result.item;
132                 }
133                 catch(ItemNotFoundException &e)
134                 {
135                         dstream<<"Waiting for texture timed out."<<std::endl;
136                         t = NULL;
137                 }
138         }
139
140         // Add to cache and return
141         m_texturecache.set(spec, t);
142         return t;
143 }
144
145 // Draw a progress bar on the image
146 void make_progressbar(float value, video::IImage *image);
147
148 /*
149         Texture fetcher/maker function, called always from the main thread
150 */
151
152 video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
153 {
154         // This would result in NULL image
155         if(spec.empty())
156                 return NULL;
157         
158         // Don't generate existing stuff
159         video::ITexture *t = m_texturecache.get(spec);
160         if(t != NULL)
161         {
162                 dstream<<"WARNING: Existing stuff requested from "
163                                 "getTextureDirect()"<<std::endl;
164                 return t;
165         }
166         
167         video::IVideoDriver* driver = m_device->getVideoDriver();
168
169         /*
170                 An image will be built from files and then converted into a texture.
171         */
172         video::IImage *baseimg = NULL;
173
174         /*
175                 Irrlicht requires a name for every texture, with which it
176                 will be stored internally in irrlicht.
177         */
178         std::string texture_name;
179
180         for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
181         {
182                 textureid_t tid = spec.tids[i];
183                 if(tid == 0)
184                         continue;
185
186                 std::string name = getTextureName(tid);
187                 
188                 // Add something to the name so that it is a unique identifier.
189                 texture_name += "[";
190                 texture_name += name;
191                 texture_name += "]";
192                 
193                 /*
194                         Try to get image from image cache
195                 */
196                 {
197                         core::map<std::string, video::IImage*>::Node *n;
198                         n = m_imagecache.find(texture_name);
199                         if(n != NULL)
200                         {
201                                 video::IImage *image = n->getValue();
202
203                                 core::dimension2d<u32> dim = image->getDimension();
204                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
205                                 image->copyTo(baseimg);
206
207                                 dstream<<"INFO: getTextureDirect(): Loaded \""
208                                                 <<texture_name<<"\" from image cache"
209                                                 <<std::endl;
210                                 
211                                 // Do not process any further.
212                                 continue;
213                         }
214                 }
215
216                 // Stuff starting with [ are special commands
217                 if(name[0] != '[')
218                 {
219                         // A normal texture; load it from a file
220                         std::string path = porting::getDataPath(name.c_str());
221                         dstream<<"INFO: getTextureDirect(): Loading path \""<<path
222                                         <<"\""<<std::endl;
223                         
224                         // DEBUG
225                         /*{
226                                 dstream<<"DEBUG CODE: Loading base image "
227                                                 "directly to texture"<<std::endl;
228                                 t = driver->getTexture(path.c_str());
229                                 driver->renameTexture(t, texture_name.c_str());
230                                 return t;
231                         }*/
232                         
233                         video::IImage *image = driver->createImageFromFile(path.c_str());
234
235                         if(image == NULL)
236                         {
237                                 dstream<<"WARNING: Could not load image \""<<name
238                                                 <<"\" from path \""<<path<<"\""
239                                                 <<" while building texture"<<std::endl;
240                                 continue;
241                         }
242
243                         // If base image is NULL, load as base.
244                         if(baseimg == NULL)
245                         {
246                                 dstream<<"INFO: Setting "<<name<<" as base"<<std::endl;
247                                 /*
248                                         Copy it this way to get an alpha channel.
249                                         Otherwise images with alpha cannot be blitted on 
250                                         images that don't have alpha in the original file.
251                                 */
252                                 // This is a deprecated method
253                                 //baseimg = driver->createImage(video::ECF_A8R8G8B8, image);
254                                 core::dimension2d<u32> dim = image->getDimension();
255                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
256                                 image->copyTo(baseimg);
257                                 image->drop();
258                                 //baseimg = image;
259                         }
260                         // Else blit on base.
261                         else
262                         {
263                                 dstream<<"INFO: Blitting "<<name<<" on base"<<std::endl;
264                                 // Size of the copied area
265                                 core::dimension2d<u32> dim = image->getDimension();
266                                 //core::dimension2d<u32> dim(16,16);
267                                 // Position to copy the blitted to in the base image
268                                 core::position2d<s32> pos_to(0,0);
269                                 // Position to copy the blitted from in the blitted image
270                                 core::position2d<s32> pos_from(0,0);
271                                 // Blit
272                                 image->copyToWithAlpha(baseimg, pos_to,
273                                                 core::rect<s32>(pos_from, dim),
274                                                 video::SColor(255,255,255,255),
275                                                 NULL);
276                                 // Drop image
277                                 image->drop();
278                         }
279                 }
280                 else
281                 {
282                         // A special texture modification
283                         dstream<<"INFO: getTextureDirect(): generating \""<<name<<"\""
284                                         <<std::endl;
285                         if(name.substr(0,6) == "[crack")
286                         {
287                                 u16 progression = stoi(name.substr(6));
288                                 // Size of the base image
289                                 core::dimension2d<u32> dim_base = baseimg->getDimension();
290                                 // Crack will be drawn at this size
291                                 u32 cracksize = 16;
292                                 // Size of the crack image
293                                 core::dimension2d<u32> dim_crack(cracksize,cracksize);
294                                 // Position to copy the crack from in the crack image
295                                 core::position2d<s32> pos_other(0, 16 * progression);
296
297                                 video::IImage *crackimage = driver->createImageFromFile(
298                                                 porting::getDataPath("crack.png").c_str());
299                         
300                                 if(crackimage)
301                                 {
302                                         /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
303                                                         core::rect<s32>(pos_other, dim_base),
304                                                         video::SColor(255,255,255,255),
305                                                         NULL);*/
306
307                                         for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
308                                         for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
309                                         {
310                                                 // Position to copy the crack to in the base image
311                                                 core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
312                                                 crackimage->copyToWithAlpha(baseimg, pos_base,
313                                                                 core::rect<s32>(pos_other, dim_crack),
314                                                                 video::SColor(255,255,255,255),
315                                                                 NULL);
316                                         }
317
318                                         crackimage->drop();
319                                 }
320                         }
321                         else if(name.substr(0,8) == "[combine")
322                         {
323                                 // "[combine:16x128:0,0=stone.png:0,16=grass.png"
324                                 Strfnd sf(name);
325                                 sf.next(":");
326                                 u32 w0 = stoi(sf.next("x"));
327                                 u32 h0 = stoi(sf.next(":"));
328                                 dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
329                                 core::dimension2d<u32> dim(w0,h0);
330                                 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
331                                 while(sf.atend() == false)
332                                 {
333                                         u32 x = stoi(sf.next(","));
334                                         u32 y = stoi(sf.next("="));
335                                         std::string filename = sf.next(":");
336                                         dstream<<"INFO: Adding \""<<filename
337                                                         <<"\" to combined ("<<x<<","<<y<<")"
338                                                         <<std::endl;
339                                         video::IImage *img = driver->createImageFromFile(
340                                                         porting::getDataPath(filename.c_str()).c_str());
341                                         if(img)
342                                         {
343                                                 core::dimension2d<u32> dim = img->getDimension();
344                                                 dstream<<"INFO: Size "<<dim.Width
345                                                                 <<"x"<<dim.Height<<std::endl;
346                                                 core::position2d<s32> pos_base(x, y);
347                                                 video::IImage *img2 =
348                                                                 driver->createImage(video::ECF_A8R8G8B8, dim);
349                                                 img->copyTo(img2);
350                                                 img->drop();
351                                                 img2->copyToWithAlpha(baseimg, pos_base,
352                                                                 core::rect<s32>(v2s32(0,0), dim),
353                                                                 video::SColor(255,255,255,255),
354                                                                 NULL);
355                                                 img2->drop();
356                                         }
357                                         else
358                                         {
359                                                 dstream<<"WARNING: img==NULL"<<std::endl;
360                                         }
361                                 }
362                         }
363                         else if(name.substr(0,12) == "[progressbar")
364                         {
365                                 float value = stof(name.substr(12));
366                                 make_progressbar(value, baseimg);
367                         }
368                         else
369                         {
370                                 dstream<<"WARNING: getTextureDirect(): Invalid "
371                                                 " texture: \""<<name<<"\""<<std::endl;
372                         }
373                 }
374                 
375                 /*
376                         Add to image cache
377                 */
378                 if(baseimg != NULL)
379                 {
380                         core::map<std::string, video::IImage*>::Node *n;
381                         n = m_imagecache.find(texture_name);
382                         if(n != NULL)
383                         {
384                                 video::IImage *img = n->getValue();
385                                 if(img != baseimg)
386                                 {
387                                         img->drop();
388                                 }
389                         }
390                         
391                         m_imagecache[texture_name] = baseimg;
392                 }
393         }
394
395         // If no resulting image, return NULL
396         if(baseimg == NULL)
397         {
398                 dstream<<"WARNING: getTextureDirect(): baseimg is NULL (attempted to"
399                                 " create texture \""<<texture_name<<"\""<<std::endl;
400                 return NULL;
401         }
402         
403         /*// DEBUG: Paint some pixels
404         video::SColor c(255,255,0,0);
405         baseimg->setPixel(1,1, c);
406         baseimg->setPixel(1,14, c);
407         baseimg->setPixel(14,1, c);
408         baseimg->setPixel(14,14, c);*/
409
410         // Create texture from resulting image
411         t = driver->addTexture(texture_name.c_str(), baseimg);
412
413         dstream<<"INFO: getTextureDirect(): created texture \""<<texture_name
414                         <<"\""<<std::endl;
415
416         return t;
417
418 }
419
420 void make_progressbar(float value, video::IImage *image)
421 {
422         if(image == NULL)
423                 return;
424         
425         core::dimension2d<u32> size = image->getDimension();
426
427         u32 barheight = 1;
428         u32 barpad_x = 1;
429         u32 barpad_y = 1;
430         u32 barwidth = size.Width - barpad_x*2;
431         v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
432
433         u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
434
435         video::SColor active(255,255,0,0);
436         video::SColor inactive(255,0,0,0);
437         for(u32 x0=0; x0<barwidth; x0++)
438         {
439                 video::SColor *c;
440                 if(x0 < barvalue_i)
441                         c = &active;
442                 else
443                         c = &inactive;
444                 u32 x = x0 + barpos.X;
445                 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
446                 {
447                         image->setPixel(x,y, *c);
448                 }
449         }
450 }
451 #endif
452