From 6bd53158fb1a412a2d1fc98dca738b6a42690761 Mon Sep 17 00:00:00 2001 From: Shinya Kitaoka <skitaoka@gmail.com> Date: Apr 26 2016 15:58:01 +0000 Subject: Merge pull request #252 from opentoonz/fix/revert-to-fix-vector-rendering Revert refactoring for vector rendering --- diff --git a/toonz/sources/common/tvectorimage/tcomputeregions.cpp b/toonz/sources/common/tvectorimage/tcomputeregions.cpp index 6af75b2..9c9fa37 100644 --- a/toonz/sources/common/tvectorimage/tcomputeregions.cpp +++ b/toonz/sources/common/tvectorimage/tcomputeregions.cpp @@ -1817,7 +1817,12 @@ 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; @@ -2747,6 +2752,10 @@ void printStrokes1(vector<VIStroke *> &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 745ccb5..b51aaaa 100644 --- a/toonz/sources/common/tvectorimage/tvectorimage.cpp +++ b/toonz/sources/common/tvectorimage/tvectorimage.cpp @@ -86,7 +86,14 @@ 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(); } @@ -671,11 +678,13 @@ 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); } @@ -721,6 +730,15 @@ 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) @@ -734,7 +752,41 @@ 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; i<m_regions.size(); i++) + { + if (oddLevel) + m_regions[i]->setStyle(styleId); + m_regions[i]->autoFill(styleId, !oddLevel); + } +} +*/ +//----------------------------------------------------------------------------- +/* +void TRegion::autoFill(int styleId, bool oddLevel) +{ +for (UINT i = 0; i<getSubregionCount(); i++) + { + TRegion* r = getSubregion(i); + if (oddLevel) + r->setStyle(styleId); + r->autoFill(styleId, !oddLevel); + } +} +*/ //----------------------------------------------------------------------------- int TVectorImage::Imp::fill(const TPointD &p, int styleId) @@ -778,14 +830,12 @@ 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)) { @@ -793,8 +843,7 @@ 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; @@ -806,35 +855,40 @@ 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; - do { - index = m_regions[i]->getEdge(j++)->m_index; - } while ((index < 0) && (j < m_regions[i]->getEdgeCount())); + if (fillAreas) +#ifndef NEW_REGION_FILL + for (UINT i = 0; i < m_regions.size(); i++) { + int index, j = 0; - // 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)) { + 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)) continue; - } - if (onlyUnfilled && (m_regions[i]->getStyle() != 0)) { - } else { + if (!onlyUnfilled || m_regions[i]->getStyle() == 0) 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; @@ -846,8 +900,6 @@ 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 6fb06e9..faf64d6 100644 --- a/toonz/sources/common/tvectorimage/tvectorimageP.h +++ b/toonz/sources/common/tvectorimage/tvectorimageP.h @@ -199,6 +199,11 @@ 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 2eef5cc..b1b41eb 100644 --- a/toonz/sources/image/pli/tiio_pli.cpp +++ b/toonz/sources/image/pli/tiio_pli.cpp @@ -295,7 +295,9 @@ TImageP TImageReaderPli::load() void readRegionVersion4x(IntersectionDataTag *tag, TVectorImage *img) { +#ifndef NEW_REGION_FILL img->setFillData(tag->m_branchArray, tag->m_branchCount); +#endif } //----------------------------------------------------------------------------- @@ -359,34 +361,42 @@ TImageP TImageReaderPli::doLoad() CreateStrokeData strokeData; // preparo l'immagine da restituire - TSmartPointerT<TVectorImage> outVectImage(new TVectorImage(true)); + 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; outVectImage->setAutocloseTolerance(m_lrp->m_pli->getAutocloseTolerance()); - ImageTag* imageTag = m_lrp->m_pli->loadFrame(m_frameId); - if (!imageTag) { + ImageTag *imageTag; + + imageTag = m_lrp->m_pli->loadFrame(m_frameId); + if (!imageTag) throw TImageException(m_path, "Corrupted or invalid image data"); - } - m_lrp->m_mapOfImage[m_frameId].second = true; + + if (m_lrp->m_mapOfImage[m_frameId].second == false) + m_lrp->m_mapOfImage[m_frameId].second = true; // per tutti gli oggetti presenti nel tag - for (UINT i = 0; i < imageTag->m_numObjects; i++) { + for (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.getPointer(), strokeData); - break; - - case PliTag::INTERSECTION_DATA_GOBJ: - readRegionVersion4x((IntersectionDataTag *)imageTag->m_object[i], outVectImage.getPointer()); - break; + createGroup((GroupTag *)imageTag->m_object[i], outVectImage, strokeData); + } + CASE PliTag::INTERSECTION_DATA_GOBJ : readRegionVersion4x((IntersectionDataTag *)imageTag->m_object[i], outVectImage); - case PliTag::THICK_QUADRATIC_CHAIN_GOBJ: // aggiunge le stroke quadratiche - createStroke((ThickQuadraticChainTag *)imageTag->m_object[i], outVectImage.getPointer(), strokeData); - break; + CASE PliTag::THICK_QUADRATIC_CHAIN_GOBJ : createStroke((ThickQuadraticChainTag *)imageTag->m_object[i], outVectImage, strokeData); - case PliTag::COLOR_NGOBJ: // aggiunge curve quadratiche con spessore costante + CASE PliTag::COLOR_NGOBJ: { ColorTag *colorTag = (ColorTag *)imageTag->m_object[i]; @@ -395,20 +405,29 @@ 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 - strokeData.m_options = ((StrokeOutlineOptionsTag *)imageTag->m_object[i])->m_options; - break; - } - } + 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; i<imageTag->m_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) #ifdef _DEBUG outVectImage->checkIntersections(); #endif - return TImageP(outVectImage.releasePointer()); + return TImageP(outVectImage); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/include/ext/meshtexturizer.h b/toonz/sources/include/ext/meshtexturizer.h index 99fadbe..99724e2 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() { - for (auto const& tile : m_tileDatas) { - glDeleteTextures(1, &tile.m_textureId); - } + int t, tilesCount = m_tileDatas.size(); + for (t = 0; t < tilesCount; ++t) + glDeleteTextures(1, &m_tileDatas[t].m_textureId); } private: // Not copyable - TextureData(const TextureData &) = delete; - TextureData &operator=(const TextureData &) = delete; + TextureData(const TextureData &); + TextureData &operator=(const TextureData &); }; #endif // MESHTEXTURIZER_H diff --git a/toonz/sources/include/tgl.h b/toonz/sources/include/tgl.h index 1a4f7e7..d54f644 100644 --- a/toonz/sources/include/tgl.h +++ b/toonz/sources/include/tgl.h @@ -3,10 +3,13 @@ #ifndef TGL_INCLUDED #define TGL_INCLUDED +//#include "tgeometry.h" #include "tmachine.h" #ifdef _WIN32 #include <windows.h> +//#endif + #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> diff --git a/toonz/sources/include/tpixelutils.h b/toonz/sources/include/tpixelutils.h index b10e15c..96b2975 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 = static_cast<TPixel64::Channel>(pix.r * pix.m / 65535.0); - pix.g = static_cast<TPixel64::Channel>(pix.g * pix.m / 65535.0); - pix.b = static_cast<TPixel64::Channel>(pix.b * pix.m / 65535.0); + pix.r = pix.r * pix.m / 65535.0; + pix.g = pix.g * pix.m / 65535.0; + pix.b = pix.b * pix.m / 65535.0; } DVAPI inline void depremult(TPixel32 &pix) { float fac = 255.0f / pix.m; - pix.r = static_cast<TPixel32::Channel>(tmin(pix.r * fac, 255.0f)); - pix.g = static_cast<TPixel32::Channel>(tmin(pix.g * fac, 255.0f)); - pix.b = static_cast<TPixel32::Channel>(tmin(pix.b * fac, 255.0f)); + pix.r = tmin(pix.r * fac, 255.0f); + pix.g = tmin(pix.g * fac, 255.0f); + pix.b = tmin(pix.b * fac, 255.0f); } DVAPI inline void depremult(TPixel64 &pix) { double fac = 65535.0 / pix.m; - pix.r = static_cast<TPixel64::Channel>(tmin(pix.r * fac, 65535.0)); - pix.g = static_cast<TPixel64::Channel>(tmin(pix.g * fac, 65535.0)); - pix.b = static_cast<TPixel64::Channel>(tmin(pix.b * fac, 65535.0)); + pix.r = tmin(pix.r * fac, 65535.0); + pix.g = tmin(pix.g * fac, 65535.0); + pix.b = 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( - static_cast<TPixel64::Channel>(pix.r * pix.m / 65535.0), - static_cast<TPixel64::Channel>(pix.g * pix.m / 65535.0), - static_cast<TPixel64::Channel>(pix.b * pix.m / 65535.0), + pix.r * pix.m / 65535.0, + pix.g * pix.m / 65535.0, + pix.b * pix.m / 65535.0, pix.m); } DVAPI inline TPixel32 depremultiply(const TPixel32 &pix) { return TPixel32( - static_cast<TPixel32::Channel>(pix.r * 255.0 / pix.m), - static_cast<TPixel32::Channel>(pix.g * 255.0 / pix.m), - static_cast<TPixel32::Channel>(pix.b * 255.0 / pix.m), + pix.r * 255.0 / pix.m, + pix.g * 255.0 / pix.m, + pix.b * 255.0 / pix.m, pix.m); } DVAPI inline TPixel64 depremultiply(const TPixel64 &pix) { return TPixel64( - static_cast<TPixel64::Channel>(pix.r * 65535.0 / pix.m), - static_cast<TPixel64::Channel>(pix.g * 65535.0 / pix.m), - static_cast<TPixel64::Channel>(pix.b * 65535.0 / pix.m), + pix.r * 65535.0 / pix.m, + pix.g * 65535.0 / pix.m, + pix.b * 65535.0 / pix.m, pix.m); } diff --git a/toonz/sources/include/tsmartpointer.h b/toonz/sources/include/tsmartpointer.h index 14e3cfb..346f1c0 100644 --- a/toonz/sources/include/tsmartpointer.h +++ b/toonz/sources/include/tsmartpointer.h @@ -167,12 +167,6 @@ 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 56a3b47..c9cd769 100644 --- a/toonz/sources/include/tvectorimage.h +++ b/toonz/sources/include/tvectorimage.h @@ -21,6 +21,7 @@ #define DVVAR DV_IMPORT_VAR #endif +//#define NEW_REGION_FILL #define DISEGNO_OUTLINE 0 //============================================================================= @@ -350,6 +351,10 @@ 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 e1fddf3..16f8557 100644 --- a/toonz/sources/tnzext/meshtexturizer.cpp +++ b/toonz/sources/tnzext/meshtexturizer.cpp @@ -158,16 +158,15 @@ void MeshTexturizer::Imp::allocateTextures(int groupIdx, const TRaster32P &ras, // Test the specified texture allocation if (testTextureAlloc(textureLx, textureLy)) { - TPointD const scale( - data->m_geom.getLx() / ras->getLx(), - data->m_geom.getLy() / ras->getLy()); - TRectD const tileGeom( + TPointD scale(data->m_geom.getLx() / (double)ras->getLx(), + data->m_geom.getLy() / (double)ras->getLy()); + TRectD 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 const texId = textureAlloc(ras, aux, x, y, textureLx, textureLy, premultiplied); + GLuint 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 52d4e16..4580bf2 100644 --- a/toonz/sources/tnzext/meshutils.cpp +++ b/toonz/sources/tnzext/meshutils.cpp @@ -12,8 +12,6 @@ #include "ext/meshutils.h" -#include <array> - //******************************************************************************************** // Templated drawing functions //******************************************************************************************** @@ -65,24 +63,23 @@ inline void tglDrawFaces(const TMeshImage &meshImage, ColorFunction colorFunctio { glBegin(GL_TRIANGLES); - int i = 0; - for (auto const& mesh : meshImage.meshes()) { - tcg::list<TTextureVertex> const & vertices = mesh->vertices(); - int const m = i++; + int m, mCount = meshImage.meshes().size(); + for (m = 0; m != mCount; ++m) { + const TTextureMesh &mesh = *meshImage.meshes()[m]; + const tcg::list<TTextureVertex> &vertices = mesh.vertices(); // Draw the mesh wireframe - int j = 0; - for (auto const& ft : mesh->faces()) { - int const index = j++; + TTextureMesh::faces_container::const_iterator ft, fEnd = mesh.faces().end(); + for (ft = mesh.faces().begin(); ft != fEnd; ++ft) { int v0, v1, v2; - mesh->faceVertices(index, v0, v1, v2); + mesh.faceVertices(ft.index(), v0, v1, v2); - TTextureVertex const& p0 = vertices[v0]; - TTextureVertex const& p1 = vertices[v1]; - TTextureVertex const& p2 = vertices[v2]; + const TTextureVertex &p0 = vertices[v0]; + const TTextureVertex &p1 = vertices[v1]; + const TTextureVertex &p2 = vertices[v2]; - colorFunction.faceColor(index, m); + colorFunction.faceColor(ft.index(), m); colorFunction.vertexColor(v0, m), glVertex2d(p0.P().x, p0.P().y); colorFunction.vertexColor(v1, m), glVertex2d(p1.P().x, p1.P().y); @@ -101,33 +98,39 @@ inline void tglDrawFaces(const TMeshImage &meshImage, const PlasticDeformerDataG { glBegin(GL_TRIANGLES); + // Draw faces according to the group's sorted faces list + typedef std::vector<std::pair<int, int>> SortedFacesVector; + + const SortedFacesVector &sortedFaces = group->m_sortedFaces; const std::vector<TTextureMeshP> &meshes = meshImage.meshes(); - // Draw faces according to the group's sorted faces list - // Draw each face individually. Change tile and mesh data only if they change int m = -1; - for (auto const& sft : group->m_sortedFaces) { - TTextureMesh const* mesh = nullptr; - double const* dstCoords = nullptr; + const TTextureMesh *mesh; + const double *dstCoords; + + int v0, v1, v2; + + // 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_; - if (m != sft.second) { - m = sft.second; mesh = meshes[m].getPointer(); dstCoords = group->m_datas[m].m_output.get(); } - int v0, v1, v2; - mesh->faceVertices(sft.first, v0, v1, v2); + mesh->faceVertices(f, v0, v1, v2); - double const * const d0 = dstCoords + (v0 << 1); - double const * const d1 = dstCoords + (v1 << 1); - double const * const d2 = dstCoords + (v2 << 1); + const double *d0 = dstCoords + (v0 << 1), *d1 = dstCoords + (v1 << 1), *d2 = dstCoords + (v2 << 1); - colorFunction.faceColor(sft.first, m); + colorFunction.faceColor(f, m); - 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]); + colorFunction.vertexColor(v0, m), glVertex2d(*d0, *(d0 + 1)); + colorFunction.vertexColor(v1, m), glVertex2d(*d1, *(d1 + 1)); + colorFunction.vertexColor(v2, m), glVertex2d(*d2, *(d2 + 1)); } glEnd(); @@ -319,135 +322,189 @@ void tglDraw(const TMeshImage &meshImage, const DrawableTextureData &texData, const TAffine &meshToTexAff, const PlasticDeformerDataGroup &group) { -#ifdef _WIN32 - typedef void (*PFNGLBLENDFUNCSEPARATEPROC)(GLenum, GLenum, GLenum, GLenum); - static PFNGLBLENDFUNCSEPARATEPROC const glBlendFuncSeparate = - reinterpret_cast<PFNGLBLENDFUNCSEPARATEPROC>(::wglGetProcAddress("glBlendFuncSeparate")); -#endif + typedef MeshTexturizer::TextureData::TileData TileData; // 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); - glBlendFuncSeparate( - GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE , GL_ONE_MINUS_SRC_ALPHA); + // Prepare variables + const std::vector<TTextureMeshP> &meshes = meshImage.meshes(); + const TTextureMesh *mesh; + + typedef std::vector<std::pair<int, int>> 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; - auto const& tiles = texData.m_textureData->m_tileDatas; + int v0, v1, v2; + int e1ovi, e2ovi; // Edge X's Other Vertex Index (see below) // Prepare each tile's affine - std::unique_ptr<TAffine[]> 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; - } + std::vector<TAffine> 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; } // Draw each face individually, according to the group's sorted faces list. // Change tile and mesh data only if they change - improves performance - 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) { + + SortedFacesVector::const_iterator sft, sfEnd(sortedFaces.end()); + for (sft = sortedFaces.begin(); sft != sfEnd; ++sft) { + int f = sft->first, m_ = sft->second; + + if (m != m_) { // Change mesh if different from current - m = sft.second; - mesh = meshImage.meshes()[m].getPointer(); + m = m_; + + mesh = meshes[m].getPointer(); dstCoords = group.m_datas[m].m_output.get(); } // Draw each face - 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) { + 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]; + // Map each face vertex to tile coordinates - std::array<TPointD, 3> const s = { - tileAff[i] * p0, - tileAff[i] * p1, - tileAff[i] * p2, - }; - ++i; + TPointD s[3] = {tileAff[t] * p0, tileAff[t] * p1, tileAff[t] * p2}; // 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 (texId != tileData.m_textureId) { + if (tileData.m_textureId != texId) { texId = tileData.m_textureId; - // This must be OUTSIDE a glBegin/glEnd block - glBindTexture(GL_TEXTURE_2D, texId); + glBindTexture(GL_TEXTURE_2D, tileData.m_textureId); // This must be OUTSIDE a glBegin/glEnd block } - std::array<double const *, 3> const d = { - dstCoords + (v0 << 1), - dstCoords + (v1 << 1), - dstCoords + (v2 << 1), - }; + 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. + */ // 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 (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 (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 (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 (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 (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]); + 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(); // 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][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]); + 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(); } diff --git a/toonz/sources/toonzlib/imagebuilders.cpp b/toonz/sources/toonzlib/imagebuilders.cpp index e56994f..508cd6d 100644 --- a/toonz/sources/toonzlib/imagebuilders.cpp +++ b/toonz/sources/toonzlib/imagebuilders.cpp @@ -40,8 +40,6 @@ extern TOfflineGL *currentOfflineGL; -//----------------------------------------------------------------------------- - //*************************************************************************************** // ImageLoader implementation //*************************************************************************************** diff --git a/toonz/sources/toonzlib/textureutils.cpp b/toonz/sources/toonzlib/textureutils.cpp index 1d4affe..9a84030 100644 --- a/toonz/sources/toonzlib/textureutils.cpp +++ b/toonz/sources/toonzlib/textureutils.cpp @@ -29,6 +29,7 @@ namespace { + TRasterImageP convert32(const TImageP &img) { struct locals { @@ -95,10 +96,12 @@ TRasterImageP getTexture(const TXshSimpleLevel *sl, const TFrameId &fid, int sub } // Vector case - std::string const id = sl->getImageId(fid) + "_rasterized"; + std::string id = sl->getImageId(fid) + "_rasterized"; ImageLoader::BuildExtData extData(sl, fid); - return ImageManager::instance()->getImage(id, ImageManager::dontPutInCache, &extData); + TRasterImageP ri(ImageManager::instance()->getImage(id, ImageManager::dontPutInCache, &extData)); + + return ri; } } // namespace @@ -127,10 +130,10 @@ DrawableTextureDataP texture_utils::getTextureData( TRaster32P ras(ri->getRaster()); assert(ras); - TRectD const geom - = TScale(ri->getSubsampling()) - * TTranslation(convert(ri->getOffset()) - ras->getCenterD()) - * TRectD(0, 0, ras->getLx(), ras->getLy()); + TRectD geom(0, 0, ras->getLx(), ras->getLy()); + geom = TScale(ri->getSubsampling()) * + TTranslation(convert(ri->getOffset()) - ras->getCenterD()) * + geom; return TTexturesStorage::instance()->loadTexture(texId, ras, geom); } diff --git a/toonz/sources/toonzqt/icongenerator.cpp b/toonz/sources/toonzqt/icongenerator.cpp index e27f9e4..ea21027 100644 --- a/toonz/sources/toonzqt/icongenerator.cpp +++ b/toonz/sources/toonzqt/icongenerator.cpp @@ -199,13 +199,16 @@ void makeChessBackground(const TRaster32P &ras) namespace { -TRaster32P convertToIcon(TVectorImageP vimage, int frame, - TDimension const& iconSize, IconGenerator::Settings const& settings) +TRaster32P convertToIcon( + TVectorImageP vimage, + int frame, + const TDimension &iconSize, + const IconGenerator::Settings &settings) { if (!vimage) return TRaster32P(); - std::unique_ptr<TPalette> plt(vimage->getPalette()->clone()); + TPalette *plt = vimage->getPalette()->clone(); if (!plt) return TRaster32P(); plt->setFrame(frame); @@ -234,31 +237,42 @@ TRaster32P convertToIcon(TVectorImageP vimage, int frame, TAffine aff = TScale(sc).place(imageCenter, iconCenter); // RenderData - TVectorRenderData rd(aff, TRect(iconSize), plt.get(), 0, true); + TVectorRenderData rd( + aff, + TRect(iconSize), + plt, + 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 ? TPixel32::Black : TPixel32::White); + glContext->clear(rd.m_blackBgEnabled ? TPixel::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, - TDimension const& iconSize, IconGenerator::Settings const& settings) +TRaster32P convertToIcon( + TToonzImageP timage, + int frame, + const TDimension &iconSize, + const IconGenerator::Settings &settings) { if (!timage) return TRaster32P();