1
2
3 // TnzCore includes
4 #include "tcommon.h"
5
6 #include "timageinfo.h"
7 #include "timage_io.h"
8 #include "tlevel_io.h"
9
10 #include "ttoonzimage.h"
11 #include "tvectorimage.h"
12 #include "trastercm.h"
13 #include "tvectorrenderdata.h"
14 #include "tpalette.h"
15
16 #include "tgl.h"
17 #include "tvectorgl.h"
18 #include "tofflinegl.h"
19
20 #include "timagecache.h"
21
22 // TnzLib includes
23 #include "toonz/txshleveltypes.h"
24 #include "toonz/levelproperties.h"
25 #include "toonz/txshsimplelevel.h"
26 #include "toonz/fill.h"
27
28 // Qt includes
29 #include <QImage>
30 #include <QThread>
31 #include <QOpenGLContext>
32 #include <QOffscreenSurface>
33 #include <QOpenGLFramebufferObject>
34
35 #include "imagebuilders.h"
36
37 //***************************************************************************************
38 // Global stuff
39 //***************************************************************************************
40
41 extern TOfflineGL *currentOfflineGL;
42
43 //***************************************************************************************
44 // ImageLoader implementation
45 //***************************************************************************************
46
ImageLoader(const TFilePath & path,const TFrameId & fid)47 ImageLoader::ImageLoader(const TFilePath &path, const TFrameId &fid)
48 : m_path(path), m_fid(fid), m_subsampling(0), m_64bitCompatible(false) {}
49
50 //-------------------------------------------------------------------------
51
getInfo(TImageInfo & info,int imFlags,void * extData)52 bool ImageLoader::getInfo(TImageInfo &info, int imFlags, void *extData) {
53 try {
54 TLevelReaderP lr(m_path);
55 TImageReaderP fr = lr->getFrameReader(m_fid);
56
57 // NOTE: Currently not changing imageInfo's bpp stuff...
58 // Ignoring subsampling too...
59
60 return ImageBuilder::setImageInfo(info, fr.getPointer());
61 } catch (TException &e) {
62 QString msg = QString::fromStdWString(e.getMessage());
63 if (msg == QString("Old 4.1 Palette")) throw;
64
65 return false;
66 }
67 }
68
69 //-------------------------------------------------------------------------
70
buildSubsampling(int imFlags,BuildExtData * data)71 inline int ImageLoader::buildSubsampling(int imFlags, BuildExtData *data) {
72 return (imFlags & ImageManager::toBeModified)
73 ? 1
74 : (data->m_subs > 0)
75 ? data->m_subs
76 : (m_subsampling > 0)
77 ? m_subsampling
78 : data->m_sl->getProperties()->getSubsampling();
79 }
80
81 //-------------------------------------------------------------------------
82
build(int imFlags,void * extData)83 TImageP ImageLoader::build(int imFlags, void *extData) {
84 assert(extData);
85
86 // Extract external data
87 BuildExtData *data = static_cast<BuildExtData *>(extData);
88
89 int subsampling = buildSubsampling(imFlags, data);
90
91 try {
92 // Initialize level reader
93 TLevelReaderP lr(m_path);
94 if (!lr) return TImageP();
95
96 // Load info in cases where it's required first
97 lr->doReadPalette(false);
98
99 if ((m_path.getType() == "pli") || (m_path.getType() == "svg") ||
100 (m_path.getType() == "psd"))
101 lr->loadInfo();
102
103 bool isTlvIcon = data->m_icon && m_path.getType() == "tlv";
104
105 // for TLV icons, palettes will be applied in IconGenerator later
106 if (!isTlvIcon) lr->doReadPalette(true); // Allow palette loading
107
108 TImageReaderP ir = lr->getFrameReader(m_fid);
109
110 bool enable64bit = (imFlags & ImageManager::is64bitEnabled);
111 ir->enable16BitRead(enable64bit); // Set 64-bit loading if required
112
113 // Load the image
114 TImageP img;
115
116 if (isTlvIcon)
117 img = ir->loadIcon(); // TODO: Why just in the tlv case??
118 else {
119 ir->setShrink(subsampling);
120 img = ir->load();
121 }
122
123 ir->enable16BitRead(false);
124
125 if (!img) return img; // There was an error loading the image.
126
127 TPalette *palette = data->m_sl->getPalette();
128 if (palette) img->setPalette(palette);
129
130 if (subsampling > 1) {
131 // Store the subsampling info in the image
132 if (TRasterImageP ri = img)
133 ri->setSubsampling(subsampling);
134 else if (TToonzImageP ti = img)
135 ti->setSubsampling(subsampling);
136 }
137
138 // In case the image will be cached, store its subsampling and 64 bit
139 // compatibility
140 if (!(imFlags & ImageManager::dontPutInCache)) {
141 m_subsampling = subsampling;
142 m_64bitCompatible =
143 data->m_sl->is16BitChannelLevel() ? enable64bit : true;
144 }
145
146 return img;
147 } catch (...) {
148 return TImageP();
149 }
150 }
151
152 //-------------------------------------------------------------------------
153
isImageCompatible(int imFlags,void * extData)154 bool ImageLoader::isImageCompatible(int imFlags, void *extData) {
155 assert(extData);
156
157 BuildExtData *data = static_cast<BuildExtData *>(extData);
158 const TXshSimpleLevel *sl = data->m_sl;
159
160 // NOTE: Vector and Mesh dont care about sub sampling rate and bit depth
161 // compatibility.
162 // They are property of Raster.
163 if (sl->getType() == PLI_XSHLEVEL || sl->getType() == MESH_XSHLEVEL)
164 return true;
165
166 int subsampling = buildSubsampling(imFlags, data);
167
168 if (m_subsampling <= 0 || subsampling != m_subsampling) return false;
169
170 if (m_64bitCompatible || !(imFlags & ImageManager::is64bitEnabled)) {
171 return true;
172 } else {
173 return false;
174 }
175 }
176
177 //-------------------------------------------------------------------------
178
invalidate()179 void ImageLoader::invalidate() {
180 ImageBuilder::invalidate();
181 m_subsampling = 0;
182 m_64bitCompatible = false;
183 }
184
185 //-------------------------------------------------------------------------
186 /*--
187 * ImageBuilder仮想関数の実装。アイコン、画像をLoad時に全てキャッシュに格納する
188 * --*/
189
buildAllIconsAndPutInCache(TXshSimpleLevel * level,std::vector<TFrameId> fids,std::vector<std::string> iconIds,bool cacheImagesAsWell)190 void ImageLoader::buildAllIconsAndPutInCache(TXshSimpleLevel *level,
191 std::vector<TFrameId> fids,
192 std::vector<std::string> iconIds,
193 bool cacheImagesAsWell) {
194 if (m_path.getType() != "tlv") return;
195 if (fids.empty() || iconIds.empty()) return;
196 /*- fidとアイコンidの数は同じはず -*/
197 if ((int)fids.size() != (int)iconIds.size()) return;
198
199 try {
200 TLevelReaderP lr(m_path);
201 if (!lr) return;
202
203 for (int i = 0; i < (int)fids.size(); i++) {
204 lr->doReadPalette(false);
205 TImageReaderP ir = lr->getFrameReader(fids[i]);
206 lr->doReadPalette(true);
207
208 TImageInfo info;
209 TPalette *palette = level->getPalette();
210 std::string fullImgId = level->getImageId(fids[i]);
211
212 /*- 画像データも一緒にキャッシュする場合 -*/
213 if (cacheImagesAsWell) {
214 ir->enable16BitRead(m_64bitCompatible);
215 ir->setShrink(1);
216 TImageP fullImg = ir->load();
217 if (fullImg) {
218 if (palette) fullImg->setPalette(palette);
219 TImageCache::instance()->add(fullImgId, fullImg, true);
220 setImageInfo(info, fullImg.getPointer());
221 }
222 }
223
224 /*- アイコンのロード -*/
225 TImageP img = ir->loadIcon();
226 ir->enable16BitRead(false);
227 if (img) {
228 if (palette) img->setPalette(palette);
229 TImageCache::instance()->add(iconIds[i], img, true);
230 }
231 }
232 } catch (...) {
233 return;
234 }
235 }
236
setFid(const TFrameId & fid)237 void ImageLoader::setFid(const TFrameId &fid) { m_fid = fid; }
238
239 //***************************************************************************************
240 // ImageRasterizer implementation
241 //***************************************************************************************
242
getInfo(TImageInfo & info,int imFlags,void * extData)243 bool ImageRasterizer::getInfo(TImageInfo &info, int imFlags, void *extData) {
244 assert(false); // None should get these... in case, TODO
245 return false;
246 }
247
248 //-------------------------------------------------------------------------
249
build(int imFlags,void * extData)250 TImageP ImageRasterizer::build(int imFlags, void *extData) {
251 assert(!(imFlags &
252 ~(ImageManager::dontPutInCache | ImageManager::forceRebuild)));
253
254 TDimension d(10, 10);
255 TPoint off(0, 0);
256
257 // Fetch image
258 assert(extData);
259 ImageLoader::BuildExtData *data = (ImageLoader::BuildExtData *)extData;
260
261 const std::string &srcImgId = data->m_sl->getImageId(data->m_fid);
262
263 TImageP img = ImageManager::instance()->getImage(srcImgId, imFlags, extData);
264 if (img) {
265 TVectorImageP vi = img;
266 if (vi) {
267 TRectD bbox = vi->getBBox();
268
269 d = TDimension(tceil(bbox.getLx()) + 1, tceil(bbox.getLy()) + 1);
270 off = TPoint((int)bbox.x0, (int)bbox.y0);
271
272 TPalette *vpalette = vi->getPalette();
273 TVectorRenderData rd(TTranslation(-off.x, -off.y), TRect(TPoint(0, 0), d),
274 vpalette, 0, true, true);
275
276 // this is too slow.
277 {
278 QSurfaceFormat format;
279 format.setProfile(QSurfaceFormat::CompatibilityProfile);
280
281 std::unique_ptr<QOffscreenSurface> surface(new QOffscreenSurface());
282 surface->setFormat(format);
283 surface->create();
284
285 TRaster32P ras(d);
286
287 glPushAttrib(GL_ALL_ATTRIB_BITS);
288 glMatrixMode(GL_MODELVIEW), glPushMatrix();
289 glMatrixMode(GL_PROJECTION), glPushMatrix();
290 {
291 std::unique_ptr<QOpenGLFramebufferObject> fb(
292 new QOpenGLFramebufferObject(d.lx, d.ly));
293
294 fb->bind();
295
296 glViewport(0, 0, d.lx, d.ly);
297 glClearColor(0, 0, 0, 0);
298 glClear(GL_COLOR_BUFFER_BIT);
299
300 glMatrixMode(GL_PROJECTION);
301 glLoadIdentity();
302 gluOrtho2D(0, d.lx, 0, d.ly);
303
304 glMatrixMode(GL_MODELVIEW);
305 glLoadIdentity();
306 glTranslatef(0.375, 0.375, 0.0);
307
308 tglDraw(rd, vi.getPointer());
309
310 glFlush();
311
312 QImage img =
313 fb->toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio,
314 Qt::SmoothTransformation);
315
316 int wrap = ras->getLx() * sizeof(TPixel32);
317 uchar *srcPix = img.bits();
318 uchar *dstPix = ras->getRawData() + wrap * (d.ly - 1);
319 for (int y = 0; y < d.ly; y++) {
320 memcpy(dstPix, srcPix, wrap);
321 dstPix -= wrap;
322 srcPix += wrap;
323 }
324 fb->release();
325 }
326 glMatrixMode(GL_MODELVIEW), glPopMatrix();
327 glMatrixMode(GL_PROJECTION), glPopMatrix();
328
329 glPopAttrib();
330
331 TRasterImageP ri = TRasterImageP(ras);
332 ri->setOffset(off + ras->getCenter());
333
334 assert(glGetError() == 0);
335
336 return ri;
337 }
338 }
339 }
340
341 // Error case: return a dummy image (is it really required?)
342
343 TRaster32P ras(d);
344 ras->fill(TPixel32(127, 0, 127, 127));
345
346 return TRasterImageP(ras);
347 }
348
349 //***************************************************************************************
350 // ImageFiller implementation
351 //***************************************************************************************
352
getInfo(TImageInfo & info,int imFlags,void * extData)353 bool ImageFiller::getInfo(TImageInfo &info, int imFlags, void *extData) {
354 assert(false); // None should get these... in case, TODO
355 return false;
356 }
357
358 //-------------------------------------------------------------------------
359
build(int imFlags,void * extData)360 TImageP ImageFiller::build(int imFlags, void *extData) {
361 assert(imFlags == ImageManager::none);
362
363 // Fetch image
364 assert(extData);
365
366 ImageLoader::BuildExtData *data = (ImageLoader::BuildExtData *)extData;
367 assert(data->m_subs == 0);
368
369 const std::string &srcImgId = data->m_sl->getImageId(data->m_fid);
370
371 TImageP img = ImageManager::instance()->getImage(srcImgId, imFlags, extData);
372 if (img) {
373 TRasterImageP ri = img;
374 if (ri) {
375 TRaster32P ras = ri->getRaster();
376 if (ras) {
377 TRaster32P newRas = ras->clone();
378 FullColorAreaFiller filler(newRas);
379
380 TPaletteP palette = new TPalette();
381 int styleId = palette->getPage(0)->addStyle(TPixel32::White);
382
383 FillParameters params;
384 params.m_palette = palette.getPointer();
385 params.m_styleId = styleId;
386 params.m_minFillDepth = 0;
387 params.m_maxFillDepth = 15;
388 filler.rectFill(newRas->getBounds(), params, false);
389
390 TRasterImageP ri = TRasterImageP(newRas);
391 return ri;
392 }
393 }
394 }
395
396 // Error case: return a dummy image (is it really required?)
397
398 TRaster32P ras(10, 10);
399 ras->fill(TPixel32(127, 0, 127, 127));
400
401 return TRasterImageP(ras);
402 }
403