1 #include "irrlichtwrapper.h"
6 IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
9 m_main_thread = get_current_thread_id();
10 m_device_mutex.Init();
14 IrrlichtWrapper::~IrrlichtWrapper()
18 for(core::map<std::string, video::IImage*>::Iterator
19 i = m_imagecache.getIterator();
20 i.atEnd() == false; i++)
22 i.getNode()->getValue()->drop();
27 void IrrlichtWrapper::Run()
33 if(m_get_texture_queue.size() > 0)
35 GetRequest<TextureSpec, video::ITexture*, u8, u8>
36 request = m_get_texture_queue.pop();
38 dstream<<"got texture request with"
39 <<" key.tids[0]="<<request.key.tids[0]
40 <<" [1]="<<request.key.tids[1]
43 GetResult<TextureSpec, video::ITexture*, u8, u8>
45 result.key = request.key;
46 result.callers = request.callers;
47 result.item = getTextureDirect(request.key);
49 request.dest->push_back(result);
54 void IrrlichtWrapper::Shutdown(bool shutdown)
56 m_running = !shutdown;
59 IrrlichtDevice* IrrlichtWrapper::getDevice()
61 if(get_current_thread_id() != m_main_thread)
63 dstream<<"WARNING: IrrlichtWrapper::getDevice() called "
64 "not from main thread"<<std::endl;
71 textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
73 u32 id = m_namecache.getId(name);
77 std::string IrrlichtWrapper::getTextureName(textureid_t id)
80 m_namecache.getValue(id, name);
81 // In case it was found, return the name; otherwise return an empty name.
85 video::ITexture* IrrlichtWrapper::getTexture(const std::string &filename)
87 TextureSpec spec(getTextureId(filename));
88 return getTexture(spec);
91 video::ITexture* IrrlichtWrapper::getTexture(const TextureSpec &spec)
96 video::ITexture *t = m_texturecache.get(spec);
100 if(get_current_thread_id() == m_main_thread)
102 dstream<<"Getting texture directly: spec.tids[0]="
103 <<spec.tids[0]<<std::endl;
105 t = getTextureDirect(spec);
109 // If irrlicht has shut down, just return NULL
110 if(m_running == false)
113 // We're gonna ask the result to be put into here
114 ResultQueue<TextureSpec, video::ITexture*, u8, u8> result_queue;
116 // Throw a request in
117 m_get_texture_queue.add(spec, 0, 0, &result_queue);
119 dstream<<"Waiting for texture from main thread: spec.tids[0]="
120 <<spec.tids[0]<<std::endl;
124 // Wait result for a second
125 GetResult<TextureSpec, video::ITexture*, u8, u8>
126 result = result_queue.pop_front(1000);
128 // Check that at least something worked OK
129 assert(result.key == spec);
133 catch(ItemNotFoundException &e)
135 dstream<<"Waiting for texture timed out."<<std::endl;
140 // Add to cache and return
141 m_texturecache.set(spec, t);
145 // Draw a progress bar on the image
146 void make_progressbar(float value, video::IImage *image);
149 Texture fetcher/maker function, called always from the main thread
152 video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
154 // This would result in NULL image
158 // Don't generate existing stuff
159 video::ITexture *t = m_texturecache.get(spec);
162 dstream<<"WARNING: Existing stuff requested from "
163 "getTextureDirect()"<<std::endl;
167 video::IVideoDriver* driver = m_device->getVideoDriver();
170 An image will be built from files and then converted into a texture.
172 video::IImage *baseimg = NULL;
175 Irrlicht requires a name for every texture, with which it
176 will be stored internally in irrlicht.
178 std::string texture_name;
180 for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
182 textureid_t tid = spec.tids[i];
186 std::string name = getTextureName(tid);
188 // Add something to the name so that it is a unique identifier.
190 texture_name += name;
194 Try to get image from image cache
197 core::map<std::string, video::IImage*>::Node *n;
198 n = m_imagecache.find(texture_name);
201 video::IImage *image = n->getValue();
203 core::dimension2d<u32> dim = image->getDimension();
204 baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
205 image->copyTo(baseimg);
207 dstream<<"INFO: getTextureDirect(): Loaded \""
208 <<texture_name<<"\" from image cache"
211 // Do not process any further.
216 // Stuff starting with [ are special commands
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
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());
233 video::IImage *image = driver->createImageFromFile(path.c_str());
237 dstream<<"WARNING: Could not load image \""<<name
238 <<"\" from path \""<<path<<"\""
239 <<" while building texture"<<std::endl;
243 // If base image is NULL, load as base.
246 dstream<<"INFO: Setting "<<name<<" as base"<<std::endl;
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.
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);
260 // Else blit on base.
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);
272 image->copyToWithAlpha(baseimg, pos_to,
273 core::rect<s32>(pos_from, dim),
274 video::SColor(255,255,255,255),
282 // A special texture modification
283 dstream<<"INFO: getTextureDirect(): generating \""<<name<<"\""
285 if(name.substr(0,6) == "[crack")
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
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);
297 video::IImage *crackimage = driver->createImageFromFile(
298 porting::getDataPath("crack.png").c_str());
302 /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
303 core::rect<s32>(pos_other, dim_base),
304 video::SColor(255,255,255,255),
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++)
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),
321 else if(name.substr(0,8) == "[combine")
323 // "[combine:16x128:0,0=stone.png:0,16=grass.png"
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)
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<<")"
339 video::IImage *img = driver->createImageFromFile(
340 porting::getDataPath(filename.c_str()).c_str());
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);
351 img2->copyToWithAlpha(baseimg, pos_base,
352 core::rect<s32>(v2s32(0,0), dim),
353 video::SColor(255,255,255,255),
359 dstream<<"WARNING: img==NULL"<<std::endl;
363 else if(name.substr(0,12) == "[progressbar")
365 float value = stof(name.substr(12));
366 make_progressbar(value, baseimg);
370 dstream<<"WARNING: getTextureDirect(): Invalid "
371 " texture: \""<<name<<"\""<<std::endl;
380 core::map<std::string, video::IImage*>::Node *n;
381 n = m_imagecache.find(texture_name);
384 video::IImage *img = n->getValue();
391 m_imagecache[texture_name] = baseimg;
395 // If no resulting image, return NULL
398 dstream<<"WARNING: getTextureDirect(): baseimg is NULL (attempted to"
399 " create texture \""<<texture_name<<"\""<<std::endl;
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);*/
410 // Create texture from resulting image
411 t = driver->addTexture(texture_name.c_str(), baseimg);
413 dstream<<"INFO: getTextureDirect(): created texture \""<<texture_name
420 void make_progressbar(float value, video::IImage *image)
425 core::dimension2d<u32> size = image->getDimension();
430 u32 barwidth = size.Width - barpad_x*2;
431 v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
433 u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
435 video::SColor active(255,255,0,0);
436 video::SColor inactive(255,0,0,0);
437 for(u32 x0=0; x0<barwidth; x0++)
444 u32 x = x0 + barpos.X;
445 for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
447 image->setPixel(x,y, *c);