From 7bc90649550ca7fb6d6e19d6665640411bf9069d Mon Sep 17 00:00:00 2001 From: Shinya Kitaoka Date: Apr 26 2016 09:40:16 +0000 Subject: fix `convert vector image to raster image` issue - remove NEW_REGION_FILL macro - use glBlendFuncSeparate - some refactoring --- diff --git a/toonz/sources/common/tvectorimage/tcomputeregions.cpp b/toonz/sources/common/tvectorimage/tcomputeregions.cpp index 9c9fa37..6af75b2 100644 --- a/toonz/sources/common/tvectorimage/tcomputeregions.cpp +++ b/toonz/sources/common/tvectorimage/tcomputeregions.cpp @@ -1817,12 +1817,7 @@ void getClosingPoints(const TRectD &rect, double fac, const TVectorImageP &vi, if (s2->getChunkCount() == 1) continue; -#ifdef NEW_REGION_FILL - double autoTol = 0; -#else double autoTol = vi->getAutocloseTolerance(); -#endif - double enlarge1 = (autoTol + 0.7) * (s1->getMaxThickness() > 0 ? s1->getMaxThickness() : 2.5) + fac; double enlarge2 = (autoTol + 0.7) * (s2->getMaxThickness() > 0 ? s2->getMaxThickness() : 2.5) + fac; @@ -2752,10 +2747,6 @@ void printStrokes1(vector &v, int size); // Trova le regioni in una TVectorImage int TVectorImage::Imp::computeRegions() { -#ifdef NEW_REGION_FILL - return 0; -#endif - #if defined(_DEBUG) && !defined(MACOSX) TStopWatch stopWatch; stopWatch.start(true); diff --git a/toonz/sources/common/tvectorimage/tvectorimage.cpp b/toonz/sources/common/tvectorimage/tvectorimage.cpp index b51aaaa..745ccb5 100644 --- a/toonz/sources/common/tvectorimage/tvectorimage.cpp +++ b/toonz/sources/common/tvectorimage/tvectorimage.cpp @@ -86,14 +86,7 @@ TVectorImage::Imp: implementation of TVectorImage class TVectorImage::Imp::Imp(TVectorImage *vi) : m_areValidRegions(false), m_notIntersectingStrokes(false), m_computeRegions(true), m_autocloseTolerance(c_newAutocloseTolerance), m_maxGroupId(1), m_maxGhostGroupId(1), m_mutex(new TThread::Mutex()), m_vi(vi), m_intersectionData(0), m_computedAlmostOnce(false), m_justLoaded(false), m_insideGroup(TGroupId()), m_minimizeEdges(true) -#ifdef NEW_REGION_FILL - , - m_regionFinder(0) -#endif { -#ifdef NEW_REGION_FILL - resetRegionFinder(); -#endif initRegionsData(); } @@ -678,13 +671,11 @@ TRaster32P TVectorImage::render(bool onlyStrokes) TRegion *TVectorImage::getRegion(const TPointD &p) { -#ifndef NEW_REGION_FILL if (!isComputedRegionAlmostOnce()) return 0; if (!m_imp->m_areValidRegions) m_imp->computeRegions(); -#endif return m_imp->getRegion(p); } @@ -730,15 +721,6 @@ int TVectorImage::fillStrokes(const TPointD &p, int styleId) return -1; } -//----------------------------------------------------------------------------- - -#ifdef NEW_REGION_FILL - -void TVectorImage::resetRegionFinder() -{ - m_imp->resetRegionFinder(); -} -#else //------------------------------------------------------------------ int TVectorImage::fill(const TPointD &p, int newStyleId, bool onlyEmpty) @@ -752,41 +734,7 @@ int TVectorImage::fill(const TPointD &p, int newStyleId, bool onlyEmpty) m_imp->computeRegions(); return m_imp->fill(p, newStyleId); } -#endif - -//----------------------------------------------------------------------------- -/* -void TVectorImage::autoFill(int styleId) -{ -m_imp->autoFill(styleId, true); -} - -void TVectorImage::Imp::autoFill(int styleId, bool oddLevel) -{ -if (!m_areValidRegions) - computeRegions(); -for (UINT i = 0; isetStyle(styleId); - m_regions[i]->autoFill(styleId, !oddLevel); - } -} -*/ -//----------------------------------------------------------------------------- -/* -void TRegion::autoFill(int styleId, bool oddLevel) -{ -for (UINT i = 0; isetStyle(styleId); - r->autoFill(styleId, !oddLevel); - } -} -*/ //----------------------------------------------------------------------------- int TVectorImage::Imp::fill(const TPointD &p, int styleId) @@ -830,12 +778,14 @@ bool TVectorImage::Imp::selectFill(const TRectD &selArea, TStroke *s, int newSty aux.findRegions(); for (UINT j = 0; j < aux.getRegionCount(); j++) { TRegion *r0 = aux.getRegion(j); - if (fillAreas) + if (fillAreas) { for (UINT i = 0; i < m_regions.size(); i++) { TRegion *r1 = m_regions[i]; - if (m_insideGroup != TGroupId() && !m_insideGroup.isParentOf(m_strokes[r1->getEdge(0)->m_index]->m_groupId)) - continue; + if ((m_insideGroup != TGroupId()) + && !m_insideGroup.isParentOf(m_strokes[r1->getEdge(0)->m_index]->m_groupId)) { + continue; + } if ((!onlyUnfilled || r1->getStyle() == 0) && r0->contains(*r1)) { @@ -843,7 +793,8 @@ bool TVectorImage::Imp::selectFill(const TRectD &selArea, TStroke *s, int newSty hitSome = true; } } - if (fillLines) + } + if (fillLines) { for (UINT i = 0; i < m_strokes.size(); i++) { if (!inCurrentGroup(i)) continue; @@ -855,40 +806,35 @@ bool TVectorImage::Imp::selectFill(const TRectD &selArea, TStroke *s, int newSty hitSome = true; } } + } } aux.removeStroke(0); return hitSome; } // rect fill + if (fillAreas) { + for (std::size_t i = 0, size = m_regions.size(); i < size; i++) { + int index; + UINT j = 0; - if (fillAreas) -#ifndef NEW_REGION_FILL - for (UINT i = 0; i < m_regions.size(); i++) { - int index, j = 0; - - do + do { index = m_regions[i]->getEdge(j++)->m_index; - while (index < 0 && j < (int)m_regions[i]->getEdgeCount()); - //if index<0, means that the region is purely of autoclose strokes! - if (m_insideGroup != TGroupId() && index >= 0 && !m_insideGroup.isParentOf(m_strokes[index]->m_groupId)) + } while ((index < 0) && (j < m_regions[i]->getEdgeCount())); + + // if index<0, means that the region is purely of autoclose strokes! + if ((m_insideGroup != TGroupId()) + && (index >= 0) && !m_insideGroup.isParentOf(m_strokes[index]->m_groupId)) { continue; - if (!onlyUnfilled || m_regions[i]->getStyle() == 0) + } + if (onlyUnfilled && (m_regions[i]->getStyle() != 0)) { + } else { hitSome |= m_regions[i]->selectFill(selArea, newStyleId); + } } -#else - - findRegions(selArea); - - for (UINT i = 0; i < m_regions.size(); i++) { - if (m_insideGroup != TGroupId() && !m_insideGroup.isParentOf(m_strokes[m_regions[i]->getEdge(0)->m_index]->m_groupId)) - continue; - if (!onlyUnfilled || m_regions[i]->getStyle() == 0) - hitSome |= m_regions[i]->selectFill(selArea, newStyleId); } -#endif - if (fillLines) + if (fillLines) { for (UINT i = 0; i < m_strokes.size(); i++) { if (!inCurrentGroup(i)) continue; @@ -900,6 +846,8 @@ bool TVectorImage::Imp::selectFill(const TRectD &selArea, TStroke *s, int newSty hitSome = true; } } + } + return hitSome; } diff --git a/toonz/sources/common/tvectorimage/tvectorimageP.h b/toonz/sources/common/tvectorimage/tvectorimageP.h index faf64d6..6fb06e9 100644 --- a/toonz/sources/common/tvectorimage/tvectorimageP.h +++ b/toonz/sources/common/tvectorimage/tvectorimageP.h @@ -199,11 +199,6 @@ public: #endif -#ifdef NEW_REGION_FILL - TRegionFinder *m_regionFinder; - void resetRegionFinder(); -#endif - private: void findRegions(const TRectD &rect); int computeIntersections(); diff --git a/toonz/sources/image/pli/tiio_pli.cpp b/toonz/sources/image/pli/tiio_pli.cpp index b1b41eb..2eef5cc 100644 --- a/toonz/sources/image/pli/tiio_pli.cpp +++ b/toonz/sources/image/pli/tiio_pli.cpp @@ -295,9 +295,7 @@ TImageP TImageReaderPli::load() void readRegionVersion4x(IntersectionDataTag *tag, TVectorImage *img) { -#ifndef NEW_REGION_FILL img->setFillData(tag->m_branchArray, tag->m_branchCount); -#endif } //----------------------------------------------------------------------------- @@ -361,42 +359,34 @@ TImageP TImageReaderPli::doLoad() CreateStrokeData strokeData; // preparo l'immagine da restituire - TVectorImage - *outVectImage = new TVectorImage(true); - // fisso il colore di default a nero opaco - //TPixel currentColor=TPixel::Black; - //TStrokeStyle *currStyle = NULL; - // chiudo tutto dentro un blocco try per cautelarmi - // dalle eccezioni generate in lettura - //try - //{ - // un contatore - UINT i; + TSmartPointerT outVectImage(new TVectorImage(true)); outVectImage->setAutocloseTolerance(m_lrp->m_pli->getAutocloseTolerance()); - ImageTag *imageTag; - - imageTag = m_lrp->m_pli->loadFrame(m_frameId); - if (!imageTag) + ImageTag* imageTag = m_lrp->m_pli->loadFrame(m_frameId); + if (!imageTag) { throw TImageException(m_path, "Corrupted or invalid image data"); - - if (m_lrp->m_mapOfImage[m_frameId].second == false) - m_lrp->m_mapOfImage[m_frameId].second = true; + } + m_lrp->m_mapOfImage[m_frameId].second = true; // per tutti gli oggetti presenti nel tag - for (i = 0; i < imageTag->m_numObjects; i++) { + for (UINT i = 0; i < imageTag->m_numObjects; i++) { switch (imageTag->m_object[i]->m_type) { - case PliTag::GROUP_GOBJ: { + case PliTag::GROUP_GOBJ: assert(((GroupTag *)imageTag->m_object[i])->m_type == GroupTag::STROKE); - createGroup((GroupTag *)imageTag->m_object[i], outVectImage, strokeData); - } - CASE PliTag::INTERSECTION_DATA_GOBJ : readRegionVersion4x((IntersectionDataTag *)imageTag->m_object[i], outVectImage); + createGroup((GroupTag *)imageTag->m_object[i], outVectImage.getPointer(), strokeData); + break; + case PliTag::INTERSECTION_DATA_GOBJ: + readRegionVersion4x((IntersectionDataTag *)imageTag->m_object[i], outVectImage.getPointer()); + break; + + case PliTag::THICK_QUADRATIC_CHAIN_GOBJ: // aggiunge le stroke quadratiche - CASE PliTag::THICK_QUADRATIC_CHAIN_GOBJ : createStroke((ThickQuadraticChainTag *)imageTag->m_object[i], outVectImage, strokeData); + createStroke((ThickQuadraticChainTag *)imageTag->m_object[i], outVectImage.getPointer(), strokeData); + break; + case PliTag::COLOR_NGOBJ: // aggiunge curve quadratiche con spessore costante - CASE PliTag::COLOR_NGOBJ: { ColorTag *colorTag = (ColorTag *)imageTag->m_object[i]; @@ -405,29 +395,20 @@ TImageP TImageReaderPli::doLoad() // isSketch=(colorTag->m_color[0] < c_maxSketchColorNum); // isSketch=(colorTag->m_color[0] < c_maxSketchColorNum); } + break; + case PliTag::OUTLINE_OPTIONS_GOBJ: // adds outline options data - CASE PliTag::OUTLINE_OPTIONS_GOBJ : strokeData.m_options = ((StrokeOutlineOptionsTag *)imageTag->m_object[i])->m_options; - - DEFAULT:; - } // switch(groupTag->m_object[j]->m_type) - } // for (i=0; im_numObjects; i++) - -//} // try - -//catch(...) // cosi' e' inutile o raccolgo qualcosa prima di rilanciare o lo elimino -//{ -// throw; -// } - -// if (regionsComputed) //WARNING !!! la seedFill mette il flag a ValidRegion a TRUE -// outVectImage->seedFill(); //le vecchie immagini hanno il seed (version<3.1) + strokeData.m_options = ((StrokeOutlineOptionsTag *)imageTag->m_object[i])->m_options; + break; + } + } #ifdef _DEBUG outVectImage->checkIntersections(); #endif - return TImageP(outVectImage); + return TImageP(outVectImage.releasePointer()); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/include/ext/meshtexturizer.h b/toonz/sources/include/ext/meshtexturizer.h index 99724e2..99fadbe 100644 --- a/toonz/sources/include/ext/meshtexturizer.h +++ b/toonz/sources/include/ext/meshtexturizer.h @@ -117,7 +117,7 @@ private: struct MeshTexturizer::TextureData { struct TileData //! Data structure for a texture tile. - { + { GLuint m_textureId; //!< OpenGL texture identifier. TRectD m_tileGeometry; //!< The tile's world geometry. }; @@ -132,15 +132,15 @@ public: ~TextureData() { - int t, tilesCount = m_tileDatas.size(); - for (t = 0; t < tilesCount; ++t) - glDeleteTextures(1, &m_tileDatas[t].m_textureId); + for (auto const& tile : m_tileDatas) { + glDeleteTextures(1, &tile.m_textureId); + } } private: // Not copyable - TextureData(const TextureData &); - TextureData &operator=(const TextureData &); + TextureData(const TextureData &) = delete; + TextureData &operator=(const TextureData &) = delete; }; #endif // MESHTEXTURIZER_H diff --git a/toonz/sources/include/tgl.h b/toonz/sources/include/tgl.h index d54f644..980008e 100644 --- a/toonz/sources/include/tgl.h +++ b/toonz/sources/include/tgl.h @@ -3,16 +3,14 @@ #ifndef TGL_INCLUDED #define TGL_INCLUDED -//#include "tgeometry.h" #include "tmachine.h" #ifdef _WIN32 #include -//#endif - #include #include #include +#include #endif #ifdef MACOSX diff --git a/toonz/sources/include/tpixelutils.h b/toonz/sources/include/tpixelutils.h index 96b2975..b10e15c 100644 --- a/toonz/sources/include/tpixelutils.h +++ b/toonz/sources/include/tpixelutils.h @@ -356,25 +356,25 @@ DVAPI inline void premult(TPixel32 &pix) DVAPI inline void premult(TPixel64 &pix) { - pix.r = pix.r * pix.m / 65535.0; - pix.g = pix.g * pix.m / 65535.0; - pix.b = pix.b * pix.m / 65535.0; + pix.r = static_cast(pix.r * pix.m / 65535.0); + pix.g = static_cast(pix.g * pix.m / 65535.0); + pix.b = static_cast(pix.b * pix.m / 65535.0); } DVAPI inline void depremult(TPixel32 &pix) { float fac = 255.0f / pix.m; - pix.r = tmin(pix.r * fac, 255.0f); - pix.g = tmin(pix.g * fac, 255.0f); - pix.b = tmin(pix.b * fac, 255.0f); + pix.r = static_cast(tmin(pix.r * fac, 255.0f)); + pix.g = static_cast(tmin(pix.g * fac, 255.0f)); + pix.b = static_cast(tmin(pix.b * fac, 255.0f)); } DVAPI inline void depremult(TPixel64 &pix) { double fac = 65535.0 / pix.m; - pix.r = tmin(pix.r * fac, 65535.0); - pix.g = tmin(pix.g * fac, 65535.0); - pix.b = tmin(pix.b * fac, 65535.0); + pix.r = static_cast(tmin(pix.r * fac, 65535.0)); + pix.g = static_cast(tmin(pix.g * fac, 65535.0)); + pix.b = static_cast(tmin(pix.b * fac, 65535.0)); } //----------------------------------------------------------------------------- @@ -402,27 +402,27 @@ DVAPI inline TPixel32 premultiply(const TPixel32 &pix) DVAPI inline TPixel64 premultiply(const TPixel64 &pix) { return TPixel64( - pix.r * pix.m / 65535.0, - pix.g * pix.m / 65535.0, - pix.b * pix.m / 65535.0, + static_cast(pix.r * pix.m / 65535.0), + static_cast(pix.g * pix.m / 65535.0), + static_cast(pix.b * pix.m / 65535.0), pix.m); } DVAPI inline TPixel32 depremultiply(const TPixel32 &pix) { return TPixel32( - pix.r * 255.0 / pix.m, - pix.g * 255.0 / pix.m, - pix.b * 255.0 / pix.m, + static_cast(pix.r * 255.0 / pix.m), + static_cast(pix.g * 255.0 / pix.m), + static_cast(pix.b * 255.0 / pix.m), pix.m); } DVAPI inline TPixel64 depremultiply(const TPixel64 &pix) { return TPixel64( - pix.r * 65535.0 / pix.m, - pix.g * 65535.0 / pix.m, - pix.b * 65535.0 / pix.m, + static_cast(pix.r * 65535.0 / pix.m), + static_cast(pix.g * 65535.0 / pix.m), + static_cast(pix.b * 65535.0 / pix.m), pix.m); } diff --git a/toonz/sources/include/tsmartpointer.h b/toonz/sources/include/tsmartpointer.h index 346f1c0..14e3cfb 100644 --- a/toonz/sources/include/tsmartpointer.h +++ b/toonz/sources/include/tsmartpointer.h @@ -167,6 +167,12 @@ public: T *getPointer() const { return m_pointer; } + T* releasePointer() { + T* p = m_pointer; + m_pointer = nullptr; + return p; + } + bool operator!() const { return m_pointer == 0; } operator bool() const { return m_pointer != 0; } diff --git a/toonz/sources/include/tvectorimage.h b/toonz/sources/include/tvectorimage.h index c9cd769..56a3b47 100644 --- a/toonz/sources/include/tvectorimage.h +++ b/toonz/sources/include/tvectorimage.h @@ -21,7 +21,6 @@ #define DVVAR DV_IMPORT_VAR #endif -//#define NEW_REGION_FILL #define DISEGNO_OUTLINE 0 //============================================================================= @@ -351,10 +350,6 @@ public: void computeRegion(const TPointD &p, int styleId); -#ifdef NEW_REGION_FILL - void resetRegionFinder(); -#endif - private: //not implemented TVectorImage(const TVectorImage &); TVectorImage &operator=(const TVectorImage &); diff --git a/toonz/sources/tnzext/meshtexturizer.cpp b/toonz/sources/tnzext/meshtexturizer.cpp index 16f8557..e1fddf3 100644 --- a/toonz/sources/tnzext/meshtexturizer.cpp +++ b/toonz/sources/tnzext/meshtexturizer.cpp @@ -158,15 +158,16 @@ void MeshTexturizer::Imp::allocateTextures(int groupIdx, const TRaster32P &ras, // Test the specified texture allocation if (testTextureAlloc(textureLx, textureLy)) { - TPointD scale(data->m_geom.getLx() / (double)ras->getLx(), - data->m_geom.getLy() / (double)ras->getLy()); - TRectD tileGeom( + TPointD const scale( + data->m_geom.getLx() / ras->getLx(), + data->m_geom.getLy() / ras->getLy()); + TRectD const tileGeom( TRectD( - scale.x * (x - TOTAL_BORDER), scale.y * (y - TOTAL_BORDER), + scale.x * (x - TOTAL_BORDER), scale.y * (y - TOTAL_BORDER), scale.x * (x + textureLx + TOTAL_BORDER), scale.y * (y + textureLy + TOTAL_BORDER)) + data->m_geom.getP00()); - GLuint texId = textureAlloc(ras, aux, x, y, textureLx, textureLy, premultiplied); + GLuint const texId = textureAlloc(ras, aux, x, y, textureLx, textureLy, premultiplied); TextureData::TileData td = {texId, tileGeom}; data->m_tileDatas.push_back(td); diff --git a/toonz/sources/tnzext/meshutils.cpp b/toonz/sources/tnzext/meshutils.cpp index 4580bf2..3e65b8a 100644 --- a/toonz/sources/tnzext/meshutils.cpp +++ b/toonz/sources/tnzext/meshutils.cpp @@ -12,6 +12,8 @@ #include "ext/meshutils.h" +#include + //******************************************************************************************** // Templated drawing functions //******************************************************************************************** @@ -63,23 +65,24 @@ inline void tglDrawFaces(const TMeshImage &meshImage, ColorFunction colorFunctio { glBegin(GL_TRIANGLES); - int m, mCount = meshImage.meshes().size(); - for (m = 0; m != mCount; ++m) { - const TTextureMesh &mesh = *meshImage.meshes()[m]; - const tcg::list &vertices = mesh.vertices(); + int i = 0; + for (auto const& mesh : meshImage.meshes()) { + tcg::list const & vertices = mesh->vertices(); + int const m = i++; // Draw the mesh wireframe - TTextureMesh::faces_container::const_iterator ft, fEnd = mesh.faces().end(); + int j = 0; + for (auto const& ft : mesh->faces()) { + int const index = j++; - for (ft = mesh.faces().begin(); ft != fEnd; ++ft) { int v0, v1, v2; - mesh.faceVertices(ft.index(), v0, v1, v2); + mesh->faceVertices(index, v0, v1, v2); - const TTextureVertex &p0 = vertices[v0]; - const TTextureVertex &p1 = vertices[v1]; - const TTextureVertex &p2 = vertices[v2]; + TTextureVertex const& p0 = vertices[v0]; + TTextureVertex const& p1 = vertices[v1]; + TTextureVertex const& p2 = vertices[v2]; - colorFunction.faceColor(ft.index(), m); + colorFunction.faceColor(index, m); colorFunction.vertexColor(v0, m), glVertex2d(p0.P().x, p0.P().y); colorFunction.vertexColor(v1, m), glVertex2d(p1.P().x, p1.P().y); @@ -98,39 +101,33 @@ inline void tglDrawFaces(const TMeshImage &meshImage, const PlasticDeformerDataG { glBegin(GL_TRIANGLES); - // Draw faces according to the group's sorted faces list - typedef std::vector> SortedFacesVector; - - const SortedFacesVector &sortedFaces = group->m_sortedFaces; const std::vector &meshes = meshImage.meshes(); - int m = -1; - const TTextureMesh *mesh; - const double *dstCoords; - - int v0, v1, v2; - + // Draw faces according to the group's sorted faces list // Draw each face individually. Change tile and mesh data only if they change - SortedFacesVector::const_iterator sft, sfEnd(sortedFaces.end()); - for (sft = sortedFaces.begin(); sft != sfEnd; ++sft) { - int f = sft->first, m_ = sft->second; - - if (m != m_) { - m = m_; + int m = -1; + for (auto const& sft : group->m_sortedFaces) { + TTextureMesh const* mesh = nullptr; + double const* dstCoords = nullptr; + if (m != sft.second) { + m = sft.second; mesh = meshes[m].getPointer(); dstCoords = group->m_datas[m].m_output.get(); } - mesh->faceVertices(f, v0, v1, v2); + int v0, v1, v2; + mesh->faceVertices(sft.first, v0, v1, v2); - const double *d0 = dstCoords + (v0 << 1), *d1 = dstCoords + (v1 << 1), *d2 = dstCoords + (v2 << 1); + double const * const d0 = dstCoords + (v0 << 1); + double const * const d1 = dstCoords + (v1 << 1); + double const * const d2 = dstCoords + (v2 << 1); - colorFunction.faceColor(f, m); + colorFunction.faceColor(sft.first, m); - colorFunction.vertexColor(v0, m), glVertex2d(*d0, *(d0 + 1)); - colorFunction.vertexColor(v1, m), glVertex2d(*d1, *(d1 + 1)); - colorFunction.vertexColor(v2, m), glVertex2d(*d2, *(d2 + 1)); + colorFunction.vertexColor(v0, m), glVertex2d(d0[0], d0[1]); + colorFunction.vertexColor(v1, m), glVertex2d(d1[0], d1[1]); + colorFunction.vertexColor(v2, m), glVertex2d(d2[0], d2[1]); } glEnd(); @@ -322,189 +319,134 @@ void tglDraw(const TMeshImage &meshImage, const DrawableTextureData &texData, const TAffine &meshToTexAff, const PlasticDeformerDataGroup &group) { - typedef MeshTexturizer::TextureData::TileData TileData; +#ifdef _WIN32 + static PFNGLBLENDFUNCSEPARATEPROC const glBlendFuncSeparate = + reinterpret_cast(::wglGetProcAddress("glBlendFuncSeparate")); +#endif // Prepare OpenGL glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_HINT_BIT); // Preserve original status bits glEnable(GL_BLEND); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_LINE_SMOOTH); glLineWidth(1.0f); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - // Prepare variables - const std::vector &meshes = meshImage.meshes(); - const TTextureMesh *mesh; - - typedef std::vector> SortedFacesVector; - const SortedFacesVector &sortedFaces = group.m_sortedFaces; - - const MeshTexturizer::TextureData *td = texData.m_textureData; - int t, tCount = td->m_tileDatas.size(); - - GLuint texId = -1; - int m = -1; - const double *dstCoords; + glBlendFuncSeparate( + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE , GL_ONE_MINUS_SRC_ALPHA); - int v0, v1, v2; - int e1ovi, e2ovi; // Edge X's Other Vertex Index (see below) + auto const& tiles = texData.m_textureData->m_tileDatas; // Prepare each tile's affine - std::vector tileAff(tCount); - for (t = 0; t != tCount; ++t) { - const TileData &tileData = td->m_tileDatas[t]; - const TRectD &tileRect = tileData.m_tileGeometry; - - tileAff[t] = TScale(1.0 / (tileRect.x1 - tileRect.x0), 1.0 / (tileRect.y1 - tileRect.y0)) * - TTranslation(-tileRect.x0, -tileRect.y0) * - meshToTexAff; + std::unique_ptr tileAff(new TAffine[tiles.size()]); + { + std::size_t i = 0; + for (auto const& tile : tiles) { + TRectD const &rect = tile.m_tileGeometry; + TScale const scale( + 1.0 / (rect.x1 - rect.x0), + 1.0 / (rect.y1 - rect.y0)); + TTranslation const translate(-rect.x0, -rect.y0); + tileAff[i] = scale * translate * meshToTexAff; + } } // Draw each face individually, according to the group's sorted faces list. // Change tile and mesh data only if they change - improves performance - - SortedFacesVector::const_iterator sft, sfEnd(sortedFaces.end()); - for (sft = sortedFaces.begin(); sft != sfEnd; ++sft) { - int f = sft->first, m_ = sft->second; - - if (m != m_) { + int m = -1; + TTextureMesh const * mesh = nullptr; + double const * dstCoords = nullptr; + GLuint texId = -1; + for (auto const& sft : group.m_sortedFaces) { + if (m != sft.second) { // Change mesh if different from current - m = m_; - - mesh = meshes[m].getPointer(); + m = sft.second; + mesh = meshImage.meshes()[m].getPointer(); dstCoords = group.m_datas[m].m_output.get(); } // Draw each face - const TTextureMesh::face_type &fc = mesh->face(f); - - const TTextureMesh::edge_type &ed0 = mesh->edge(fc.edge(0)), - &ed1 = mesh->edge(fc.edge(1)), - &ed2 = mesh->edge(fc.edge(2)); - - { - v0 = ed0.vertex(0); - v1 = ed0.vertex(1); - v2 = ed1.vertex((ed1.vertex(0) == v0) | (ed1.vertex(0) == v1)); - - e1ovi = (ed1.vertex(0) == v1) | (ed1.vertex(1) == v1); // ed1 and ed2 will refer to vertexes - e2ovi = 1 - e1ovi; // with index 2 and these. - } - - const TPointD &p0 = mesh->vertex(v0).P(), &p1 = mesh->vertex(v1).P(), &p2 = mesh->vertex(v2).P(); - - for (t = 0; t != tCount; ++t) { - // Draw face against tile - const TileData &tileData = td->m_tileDatas[t]; - + TTextureMesh::face_type const& fc = mesh->face(sft.first); + TTextureMesh::edge_type const& ed0 = mesh->edge(fc.edge(0)); + TTextureMesh::edge_type const& ed1 = mesh->edge(fc.edge(1)); + TTextureMesh::edge_type const& ed2 = mesh->edge(fc.edge(2)); + + int const v0 = ed0.vertex(0); + int const v1 = ed0.vertex(1); + int const v2 = ed1.vertex((ed1.vertex(0) == v0) | (ed1.vertex(0) == v1)); + + // Edge X's Other Vertex Index (see below) + int const f = (ed1.vertex(0) == v1) | (ed1.vertex(1) == v1); // ed1 and ed2 will refer to vertexes + int const g = 1 - f; // with index 2 and these. + + TPointD const& p0 = mesh->vertex(v0).P(); + TPointD const& p1 = mesh->vertex(v1).P(); + TPointD const& p2 = mesh->vertex(v2).P(); + + // Draw face against tile + std::size_t i = 0; + for (auto const& tileData : tiles) { // Map each face vertex to tile coordinates - TPointD s[3] = {tileAff[t] * p0, tileAff[t] * p1, tileAff[t] * p2}; + std::array const s = { + tileAff[i] * p0, + tileAff[i] * p1, + tileAff[i] * p2, + }; + ++i; // Test the face bbox - tile intersection - if (tmin(s[0].x, s[1].x, s[2].x) > 1.0 || - tmin(s[0].y, s[1].y, s[2].y) > 1.0 || - tmax(s[0].x, s[1].x, s[2].x) < 0.0 || - tmax(s[0].y, s[1].y, s[2].y) < 0.0) + if ( (tmin(s[0].x, s[1].x, s[2].x) > 1.0) + || (tmin(s[0].y, s[1].y, s[2].y) > 1.0) + || (tmax(s[0].x, s[1].x, s[2].x) < 0.0) + || (tmax(s[0].y, s[1].y, s[2].y) < 0.0)) { continue; + } // If the tile has changed, interrupt the glBegin/glEnd block and bind the // OpenGL texture corresponding to the new tile - if (tileData.m_textureId != texId) { + if (texId != tileData.m_textureId) { texId = tileData.m_textureId; - glBindTexture(GL_TEXTURE_2D, tileData.m_textureId); // This must be OUTSIDE a glBegin/glEnd block + // This must be OUTSIDE a glBegin/glEnd block + glBindTexture(GL_TEXTURE_2D, texId); } - const double *d[3] = {dstCoords + (v0 << 1), - dstCoords + (v1 << 1), - dstCoords + (v2 << 1)}; - - /* - Now, draw primitives. A note about pixel arithmetic, here. - - Since line antialiasing in OpenGL just manipulates output fragments' alpha components, - we must require that the input texture is NONPREMULTIPLIED. - - Furthermore, this function does not rely on the assumption that the output alpha component - is discarded (as it happens when drawing on screen). This means that just using a simple - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) is not an option, since this way THE INPUT - SRC ALPHA GETS MULTIPLIED BY ITSELF - see glBlendFunc's docs - and that shows. - - The solution is to separate the rendering of RGB and M components - the formers use - GL_SRC_ALPHA, while the latter uses GL_ONE. The result is a PREMULTIPLIED image. - */ + std::array const d = { + dstCoords + (v0 << 1), + dstCoords + (v1 << 1), + dstCoords + (v2 << 1), + }; // First, draw antialiased face edges on the mesh border. - bool drawEd0 = (ed0.facesCount() < 2), - drawEd1 = (ed1.facesCount() < 2), - drawEd2 = (ed2.facesCount() < 2); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - - glBegin(GL_LINES); - { - if (drawEd0) { - glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1)); - glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1)); - } - - if (drawEd1) { - glTexCoord2d(s[e1ovi].x, s[e1ovi].y), glVertex2d(*d[e1ovi], *(d[e1ovi] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); - } - - if (drawEd2) { - glTexCoord2d(s[e2ovi].x, s[e2ovi].y), glVertex2d(*d[e2ovi], *(d[e2ovi] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); - } - } - glEnd(); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glBegin(GL_LINES); { - if (drawEd0) { - glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1)); - glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1)); + if (ed0.facesCount() < 2) { + glTexCoord2d(s[0].x, s[0].y), glVertex2d(d[0][0], d[0][1]); + glTexCoord2d(s[1].x, s[1].y), glVertex2d(d[1][0], d[1][1]); } - if (drawEd1) { - glTexCoord2d(s[e1ovi].x, s[e1ovi].y), glVertex2d(*d[e1ovi], *(d[e1ovi] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); + if (ed1.facesCount() < 2) { + glTexCoord2d(s[f].x, s[f].y), glVertex2d(d[f][0], d[f][1]); + glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]); } - if (drawEd2) { - glTexCoord2d(s[e2ovi].x, s[e2ovi].y), glVertex2d(*d[e2ovi], *(d[e2ovi] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); + if (ed2.facesCount() < 2) { + glTexCoord2d(s[g].x, s[g].y), glVertex2d(d[g][0], d[g][1]); + glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]); } } glEnd(); // Finally, draw the face - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - - glBegin(GL_TRIANGLES); - { - glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1)); - glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); - } - glEnd(); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glBegin(GL_TRIANGLES); { - glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1)); - glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1)); - glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1)); + glTexCoord2d(s[0].x, s[0].y), glVertex2d(d[0][0], d[0][1]); + glTexCoord2d(s[1].x, s[1].y), glVertex2d(d[1][0], d[1][1]); + glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]); } glEnd(); } diff --git a/toonz/sources/toonz/main.cpp b/toonz/sources/toonz/main.cpp index 3852d90..216228d 100644 --- a/toonz/sources/toonz/main.cpp +++ b/toonz/sources/toonz/main.cpp @@ -330,9 +330,6 @@ void initToonzEnv() if (cacheDir.isEmpty()) cacheDir = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheDir); - - DV_IMPORT_API void initializeImageRasterizer(); - initializeImageRasterizer(); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzlib/imagebuilders.cpp b/toonz/sources/toonzlib/imagebuilders.cpp index 0d7ccb3..e56994f 100644 --- a/toonz/sources/toonzlib/imagebuilders.cpp +++ b/toonz/sources/toonzlib/imagebuilders.cpp @@ -26,8 +26,11 @@ #include "toonz/fill.h" // Qt includes -#include -#include +#include +#include +#include +#include +#include #include "imagebuilders.h" @@ -39,18 +42,6 @@ extern TOfflineGL *currentOfflineGL; //----------------------------------------------------------------------------- -QGLPixelBuffer *imageRasterizerPixelBuffer = 0; - -void DV_EXPORT_API initializeImageRasterizer() -{ - assert(QGLPixelBuffer::hasOpenGLPbuffers()); - if (!QGLPixelBuffer::hasOpenGLPbuffers()) { - imageRasterizerPixelBuffer = 0; - } else { - imageRasterizerPixelBuffer = new QGLPixelBuffer(QSize(1024, 1024)); - } -} - //*************************************************************************************** // ImageLoader implementation //*************************************************************************************** @@ -281,54 +272,81 @@ TImageP ImageRasterizer::build(int imFlags, void *extData) TGlContext oldContext = tglGetCurrentContext(); - if (imageRasterizerPixelBuffer == 0) { + if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) { TRaster32P ras(d); TRasterImageP ri(ras); ri->setOffset(off + ras->getCenter()); return ri; } - QGLPixelBuffer *gl = imageRasterizerPixelBuffer; // (QSize(d.lx, d.ly)); - - gl->makeCurrent(); - assert(glGetError() == 0); - - glViewport(0, 0, 1024, 1024); // d.lx,d.ly); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0, d.lx, 0, d.ly); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.375, 0.375, 0.0); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - assert(glGetError() == 0); - tglDraw(rd, vi.getPointer()); - assert(glGetError() == 0); - - assert(glGetError() == 0); - glFlush(); - assert(glGetError() == 0); - - QImage img = gl->toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - TRaster32P ras(d); - - int wrap = ras->getLx() * sizeof(TPixel32); - uchar *srcPix = img.bits(); - uchar *dstPix = ras->getRawData() + wrap * (d.ly - 1); - for (int y = 0; y < d.ly; y++) { - memcpy(dstPix, srcPix, wrap); - dstPix -= wrap; - srcPix += wrap; - } - gl->doneCurrent(); + // this is too slow. + { + QSurfaceFormat format; + format.setProfile(QSurfaceFormat::CompatibilityProfile); + + std::unique_ptr surface(new QOffscreenSurface()); + surface->setFormat(format); + surface->create(); - tglMakeCurrent(oldContext); + std::unique_ptr context(new QOpenGLContext()); + context->moveToThread(QThread::currentThread()); + context->makeCurrent(surface.get()); + + TRaster32P ras(d); - TRasterImageP ri = TRasterImageP(ras); - ri->setOffset(off + ras->getCenter()); - return ri; + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_MODELVIEW), glPushMatrix(); + glMatrixMode(GL_PROJECTION), glPushMatrix(); + { + std::unique_ptr fb(new QOpenGLFramebufferObject(d.lx, d.ly)); + + fb->bind(); + assert(glGetError() == 0); + + glViewport(0, 0, d.lx, d.ly); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0, d.lx, 0, d.ly); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.375, 0.375, 0.0); + + assert(glGetError() == 0); + tglDraw(rd, vi.getPointer()); + assert(glGetError() == 0); + + assert(glGetError() == 0); + glFlush(); + assert(glGetError() == 0); + + QImage img = fb->toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + int wrap = ras->getLx() * sizeof(TPixel32); + uchar *srcPix = img.bits(); + uchar *dstPix = ras->getRawData() + wrap * (d.ly - 1); + for (int y = 0; y < d.ly; y++) { + memcpy(dstPix, srcPix, wrap); + dstPix -= wrap; + srcPix += wrap; + } + fb->release(); + } + glMatrixMode(GL_MODELVIEW), glPopMatrix(); + glMatrixMode(GL_PROJECTION), glPopMatrix(); + + glPopAttrib(); + + context->doneCurrent(); + + TRasterImageP ri = TRasterImageP(ras); + ri->setOffset(off + ras->getCenter()); + + return ri; + } } } diff --git a/toonz/sources/toonzlib/textureutils.cpp b/toonz/sources/toonzlib/textureutils.cpp index 9a84030..1d4affe 100644 --- a/toonz/sources/toonzlib/textureutils.cpp +++ b/toonz/sources/toonzlib/textureutils.cpp @@ -29,7 +29,6 @@ namespace { - TRasterImageP convert32(const TImageP &img) { struct locals { @@ -96,12 +95,10 @@ TRasterImageP getTexture(const TXshSimpleLevel *sl, const TFrameId &fid, int sub } // Vector case - std::string id = sl->getImageId(fid) + "_rasterized"; + std::string const id = sl->getImageId(fid) + "_rasterized"; ImageLoader::BuildExtData extData(sl, fid); - TRasterImageP ri(ImageManager::instance()->getImage(id, ImageManager::dontPutInCache, &extData)); - - return ri; + return ImageManager::instance()->getImage(id, ImageManager::dontPutInCache, &extData); } } // namespace @@ -130,10 +127,10 @@ DrawableTextureDataP texture_utils::getTextureData( TRaster32P ras(ri->getRaster()); assert(ras); - TRectD geom(0, 0, ras->getLx(), ras->getLy()); - geom = TScale(ri->getSubsampling()) * - TTranslation(convert(ri->getOffset()) - ras->getCenterD()) * - geom; + TRectD const geom + = TScale(ri->getSubsampling()) + * TTranslation(convert(ri->getOffset()) - ras->getCenterD()) + * TRectD(0, 0, ras->getLx(), ras->getLy()); return TTexturesStorage::instance()->loadTexture(texId, ras, geom); } diff --git a/toonz/sources/toonzqt/icongenerator.cpp b/toonz/sources/toonzqt/icongenerator.cpp index ea21027..e27f9e4 100644 --- a/toonz/sources/toonzqt/icongenerator.cpp +++ b/toonz/sources/toonzqt/icongenerator.cpp @@ -199,16 +199,13 @@ void makeChessBackground(const TRaster32P &ras) namespace { -TRaster32P convertToIcon( - TVectorImageP vimage, - int frame, - const TDimension &iconSize, - const IconGenerator::Settings &settings) +TRaster32P convertToIcon(TVectorImageP vimage, int frame, + TDimension const& iconSize, IconGenerator::Settings const& settings) { if (!vimage) return TRaster32P(); - TPalette *plt = vimage->getPalette()->clone(); + std::unique_ptr plt(vimage->getPalette()->clone()); if (!plt) return TRaster32P(); plt->setFrame(frame); @@ -237,42 +234,31 @@ TRaster32P convertToIcon( TAffine aff = TScale(sc).place(imageCenter, iconCenter); // RenderData - TVectorRenderData rd( - aff, - TRect(iconSize), - plt, - 0, true); - + TVectorRenderData rd(aff, TRect(iconSize), plt.get(), 0, true); rd.m_tcheckEnabled = settings.m_transparencyCheck; rd.m_blackBgEnabled = settings.m_blackBgCheck; rd.m_drawRegions = !settings.m_inksOnly; - rd.m_inkCheckEnabled = settings.m_inkIndex != -1; - rd.m_paintCheckEnabled = settings.m_paintIndex != -1; + rd.m_inkCheckEnabled = (settings.m_inkIndex != -1); + rd.m_paintCheckEnabled = (settings.m_paintIndex != -1); rd.m_colorCheckIndex = rd.m_inkCheckEnabled ? settings.m_inkIndex : settings.m_paintIndex; rd.m_isIcon = true; // disegno l'immagine glContext->makeCurrent(); - glContext->clear(rd.m_blackBgEnabled ? TPixel::Black : TPixel32::White); + glContext->clear(rd.m_blackBgEnabled ? TPixel32::Black : TPixel32::White); glContext->draw(vimage, rd); TRaster32P ras(iconSize); glContext->getRaster(ras); - glContext->doneCurrent(); - delete plt; - return ras; } //------------------------------------------------------------------------- -TRaster32P convertToIcon( - TToonzImageP timage, - int frame, - const TDimension &iconSize, - const IconGenerator::Settings &settings) +TRaster32P convertToIcon(TToonzImageP timage, int frame, + TDimension const& iconSize, IconGenerator::Settings const& settings) { if (!timage) return TRaster32P();