54
54
#include "../../Execution/X3DExecutionContext.h"
55
55
#include <iostream>
60
#include <glibmm/dispatcher.h>
57
62
namespace titania {
69
typedef size_t size_type;
71
Texture (const std::string & data) :
72
image (getImage (data)),
83
{ return image .size () .width (); }
87
{ return image .size () .height (); }
90
getComponents () const
91
{ return components; }
95
{ return blob .data (); }
98
process (const Color4f & borderColor, size_type borderWidth,
99
size_type minTextureSize, size_type maxTextureSize)
101
addBorder (borderColor, borderWidth);
103
tryScaleImage (minTextureSize, maxTextureSize);
105
refineImageFormat ();
119
getImage (const std::string & data)
121
std::list <Magick::Image> images;
122
Magick::readImages (&images, Magick::Blob (data .c_str (), data .length ()));
124
switch (images .size ())
126
case 0: // I have no idea what to do now.
127
throw std::domain_error ("Image contains nothing.");
131
// Image with one layer image.
132
return images .back ();
136
// Flatten image with more than one layer.
138
Magick::flattenImages (&image, images .begin (), images .end ());
145
addBorder (const Color4f & borderColor, size_type borderWidth)
149
std::ostringstream color;
154
<< std::setfill ('0')
155
<< std::setw (2) << (int) (uint8_t) (borderColor .r () * 255)
156
<< std::setw (2) << (int) (uint8_t) (borderColor .g () * 255)
157
<< std::setw (2) << (int) (uint8_t) (borderColor .b () * 255)
158
<< std::setw (2) << (int) (uint8_t) (borderColor .a () * 255);
160
image .borderColor (Magick::Color (color .str ()));
162
image .border (Magick::Geometry (borderWidth, borderWidth));
167
tryScaleImage (size_type minTextureSize, size_type maxTextureSize)
169
size_t width = getWidth ();
170
size_t height = getHeight ();
172
if (std::max (width, height) < minTextureSize)
175
bool needsScaling = false;
177
if (not math::is_power_of_two (width))
179
width = std::min (math::next_power_of_two (width), maxTextureSize);
183
if (not math::is_power_of_two (height))
185
height = std::min (math::next_power_of_two (height), maxTextureSize);
192
<< "Warning: Texture needs scaling: scaling texture from "
193
<< getWidth () << " x " << getHeight ()
194
<< " to " << width << " x " << height << " pixel."
197
scaleImage (width, height);
202
scaleImage (size_type width, size_type height)
204
Magick::Geometry geometry (width, height);
206
geometry .aspect (true);
207
image .filterType (Magick::LanczosFilter);
208
image .zoom (geometry);
214
switch (image .type ())
216
case Magick::GrayscaleType:
218
if (not image .matte ())
220
image .colorSpace (Magick::GRAYColorspace);
221
image .magick ("GRAY");
222
format = GL_LUMINANCE;
227
case Magick::GrayscaleMatteType:
229
image .colorSpace (Magick::GRAYColorspace);
230
image .type (Magick::TrueColorMatteType);
231
image .magick ("RGBA");
236
case Magick::TrueColorType:
238
if (not image .matte ())
240
image .colorSpace (Magick::RGBColorspace);
241
image .magick ("RGB");
247
case Magick::TrueColorMatteType:
249
image .colorSpace (Magick::RGBColorspace);
250
image .magick ("RGBA");
259
image .type (Magick::TrueColorMatteType);
260
refineImageFormat ();
265
image .type (Magick::TrueColorType);
266
refineImageFormat ();
276
image .interlaceType (Magick::NoInterlace);
277
image .endian (Magick::LSBEndian);
279
image .write (&blob);
286
size_type components;
291
class ImageTexture::Thread :
296
typedef Texture::size_type size_type;
298
Thread (ImageTexture* const imageTexture) :
299
imageTexture (imageTexture),
300
future (std::async (std::launch::async, std::mem_fn (&Thread::loadAsync), this,
301
imageTexture -> url (),
302
imageTexture -> getTextureProperties () -> borderColor (),
303
imageTexture -> getTextureProperties () -> borderWidth (),
305
imageTexture -> getBrowser () -> getRenderingProperties () -> maxTextureSize ()))
307
imageTexture -> getBrowser () -> prepareEvents .addInterest (this, &Thread::prepareEvents);
308
imageTexture -> getBrowser () -> notify ();
314
if (future .valid ())
323
imageTexture -> getBrowser () -> notify ();
325
if (future .valid ())
327
auto status = future .wait_for (std::chrono::milliseconds (0));
329
if (status == std::future_status::ready)
331
imageTexture -> getBrowser () -> prepareEvents .removeInterest (this, &Thread::prepareEvents);
332
imageTexture -> set_image (future .get ());
338
loadAsync (const MFString & url,
339
const Color4f & borderColor, size_type borderWidth,
340
size_type minTextureSize, size_type maxTextureSize)
342
std::lock_guard <std::mutex> lock (getThread ());
344
for (const auto & URL : url)
348
TexturePtr texture (new Texture (imageTexture -> loadDocument (URL)));
350
texture -> process (borderColor, borderWidth, minTextureSize, maxTextureSize);
354
catch (const X3DError & error)
356
std::clog << "ImageTexture: " << error .what () << std::endl;
358
catch (const std::exception & error)
360
std::clog << "Bad Image: " << error .what () << ", in URL '" << imageTexture -> getWorldURL () << "'" << std::endl;
370
std::lock_guard <std::mutex> lock (mutex);
371
threadIndex = (threadIndex + 1) % threads .size ();
372
return threads [threadIndex];
376
static size_t threadIndex;
377
static std::deque <std::mutex> threads;
380
ImageTexture* const imageTexture;
381
std::future <TexturePtr> future;
385
size_t ImageTexture::Thread::threadIndex = 0;
386
std::deque <std::mutex> ImageTexture::Thread::threads (4);
60
388
ImageTexture::ImageTexture (X3DExecutionContext* const executionContext) :
61
389
X3DBaseNode (executionContext -> getBrowser (), executionContext),
62
390
X3DTexture2DNode (),
65
394
setComponent ("Texturing");
66
395
setTypeName ("ImageTexture");
105
452
setLoadState (IN_PROGRESS_STATE);
109
for (const auto & URL : url ())
113
setImage (loadDocument (URL));
115
setLoadState (COMPLETE_STATE);
118
catch (const X3DError & error)
120
std::clog << "ImageTexture: " << error .what () << std::endl;
122
catch (const std::exception & error)
124
std::clog << "Bad Image: " << error .what () << ", in URL '" << getWorldURL () << "'" << std::endl;
128
setLoadState (FAILED_STATE);
454
thread .reset (new Thread (this));
456
// if (checkLoadState () == COMPLETE_STATE or checkLoadState () == IN_PROGRESS_STATE)
459
// setLoadState (IN_PROGRESS_STATE);
463
// for (const auto & URL : url ())
467
// setImage (loadDocument (URL));
469
// setLoadState (COMPLETE_STATE);
472
// catch (const X3DError & error)
474
// std::clog << "ImageTexture: " << error .what () << std::endl;
476
// catch (const std::exception & error)
478
// std::clog << "Bad Image: " << error .what () << ", in URL '" << getWorldURL () << "'" << std::endl;
482
// setLoadState (FAILED_STATE);