| |
| |
| #include "tgl.h" |
| #include "tvectorgl.h" |
| #include "tregion.h" |
| #include "tregionprop.h" |
| #include "tstrokeutil.h" |
| #include "tvectorrenderdata.h" |
| #include "tvectorimage.h" |
| #include "tpalette.h" |
| #include "tcolorfunctions.h" |
| #include "tsimplecolorstyles.h" |
| #include "tthreadmessage.h" |
| #include "tstrokeprop.h" |
| |
| #include "tconvert.h" |
| #include "tcurves.h" |
| #include "tstrokeoutline.h" |
| |
| #ifndef _WIN32 |
| #define CALLBACK |
| #endif |
| |
| #ifndef checkErrorsByGL |
| #define checkErrorsByGL \ |
| { \ |
| GLenum err = glGetError(); \ |
| assert(err != GL_INVALID_ENUM); \ |
| assert(err != GL_INVALID_VALUE); \ |
| assert(err != GL_INVALID_OPERATION); \ |
| assert(err != GL_STACK_OVERFLOW); \ |
| assert(err != GL_STACK_UNDERFLOW); \ |
| assert(err != GL_OUT_OF_MEMORY); \ |
| assert(err == GL_NO_ERROR); \ |
| } |
| #endif |
| |
| #undef checkErrorsByGL |
| #define checkErrorsByGL |
| |
| using namespace std; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifdef _DEBUG |
| |
| bool checkQuadraticDistance(TStroke *stroke, bool checkThickness) |
| { |
| UINT i, qCount = stroke->getChunkCount(); |
| const TThickQuadratic *q; |
| TThickPoint p1, p2, p3; |
| |
| |
| if (qCount == 1) |
| return true; |
| |
| for (i = 0; i != qCount; i++) { |
| q = stroke->getChunk(i); |
| p1 = q->getThickP0(); |
| p2 = q->getThickP1(); |
| p3 = q->getThickP2(); |
| |
| if (areAlmostEqual(p1.x, p2.x) && areAlmostEqual(p2.x, p3.x) && |
| areAlmostEqual(p1.y, p2.y) && areAlmostEqual(p2.y, p3.y) && |
| (!checkThickness || |
| (areAlmostEqual(p1.thick, p2.thick) && areAlmostEqual(p2.thick, p3.thick)))) |
| return false; |
| } |
| return true; |
| } |
| |
| |
| |
| void drawControlPoints(const TVectorRenderData &rd, TStroke *stroke, double pixelSize, bool allPoints = true) |
| { |
| int i; |
| TPointD p; |
| glPushMatrix(); |
| |
| tglMultMatrix(rd.m_aff); |
| |
| glPointSize(2.0); |
| glBegin(GL_POINTS); |
| |
| if (allPoints) { |
| int n = stroke->getControlPointCount(); |
| for (i = 0; i < n; ++i) { |
| p = stroke->getControlPoint(i); |
| glColor3d((i + 1) & 1, i & 1, 0.0); |
| glVertex2d(p.x, p.y); |
| } |
| } else { |
| int n = stroke->getChunkCount(); |
| for (i = 0; i < n; ++i) { |
| const TThickQuadratic *chunk = stroke->getChunk(i); |
| p = chunk->getP0(); |
| glColor3d(1.0, 0.0, 0.0); |
| glVertex2d(p.x, p.y); |
| } |
| const TThickQuadratic *chunk = stroke->getChunk(n - 1); |
| glColor3d(1.0, 0.0, 0.0); |
| p = chunk->getP2(); |
| glVertex2d(p.x, p.y); |
| } |
| |
| glEnd(); |
| glPopMatrix(); |
| } |
| |
| #endif |
| |
| |
| |
| |
| |
| |
| static int Index = 0; |
| void tglDraw(const TVectorRenderData &rd, TRegion *r, bool pushAttribs) |
| { |
| checkErrorsByGL; |
| assert(r); |
| checkErrorsByGL; |
| if (!r) |
| return; |
| bool alphaChannel = rd.m_alphaChannel; |
| checkErrorsByGL; |
| |
| int j = 0; |
| bool visible = false; |
| int colorCount = 0; |
| |
| TColorStyleP style; |
| if (rd.m_paintCheckEnabled && r->getStyle() == rd.m_colorCheckIndex) { |
| static TSolidColorStyle *redColor = new TSolidColorStyle(); |
| redColor->addRef(); |
| redColor->setMainColor(TPixel::Red); |
| style = redColor; |
| } else if (rd.m_tcheckEnabled) { |
| static TSolidColorStyle *color = new TSolidColorStyle(); |
| color->addRef(); |
| color->setMainColor(rd.m_tCheckPaint); |
| style = color; |
| } else |
| style = rd.m_palette->getStyle(r->getStyle()); |
| |
| colorCount = style->getColorParamCount(); |
| if (colorCount == 0) { |
| visible = true; |
| } else { |
| visible = false; |
| for (j = 0; j < colorCount && !visible; j++) { |
| TPixel32 color = style->getColorParamValue(j); |
| if (rd.m_cf) |
| color = (*(rd.m_cf))(color); |
| if (color.m != 0) |
| visible = true; |
| } |
| } |
| if (visible) { |
| TRegionProp *prop = r->getProp(); |
| |
| int styleId = r->getStyle(); |
| if (styleId) { |
| |
| if (!style->isRegionStyle() || style->isEnabled() == false) { |
| prop = 0; |
| } else { |
| |
| if (!prop || style.getPointer() != prop->getColorStyle()) { |
| r->setProp(style->makeRegionProp(r)); |
| prop = r->getProp(); |
| } |
| } |
| } |
| |
| |
| if (prop) { |
| if (pushAttribs) |
| glPushAttrib(GL_ALL_ATTRIB_BITS); |
| |
| tglEnableLineSmooth(true); |
| |
| #ifdef DRAW_EDGE_NUMBERS |
| glPushMatrix(); |
| tglMultMatrix(rd.m_aff); |
| switch (Index % 7) { |
| case 0: |
| tglColor(TPixel::Red); |
| break; |
| case 1: |
| tglColor(TPixel::Green); |
| break; |
| case 2: |
| tglColor(TPixel::Blue); |
| break; |
| case 3: |
| tglColor(TPixel::Cyan); |
| break; |
| case 4: |
| tglColor(TPixel::Magenta); |
| break; |
| case 5: |
| tglColor(TPixel::Yellow); |
| break; |
| case 6: |
| tglColor(TPixel::Black); |
| break; |
| default: |
| tglColor(TPixel::Red); |
| break; |
| } |
| |
| Index++; |
| if (rIndex == 2) { |
| double y = r->getEdge(0)->m_s->getThickPoint((r->getEdge(0)->m_w0 + r->getEdge(0)->m_w1) / 2.0).y; |
| tglDrawSegment(TPointD(-1000, y), TPointD(1000, y)); |
| } |
| |
| for (int i = 0; i < (int)r->getEdgeCount(); i++) { |
| TEdge *e = r->getEdge(i); |
| TPointD p = e->m_s->getPoint(0.8 * e->m_w0 + 0.2 * e->m_w1); |
| if (i == 0) |
| tglDrawText(p, (QString::number(rIndex) + QString("-0")).toStdString()); |
| else |
| tglDrawText(p, QString::number(i).toStdString()); |
| if (e->m_index == 3) { |
| tglColor(TPixel::Black); |
| TStroke *s = e->m_s; |
| drawPoint(s->getChunk(0)->getP0(), .3); |
| tglColor(TPixel::Red); |
| tglDrawText(s->getChunk(0)->getP0(), QString::number(0).toStdString()); |
| for (int ii = 0; ii < s->getChunkCount(); ii++) { |
| drawPoint(s->getChunk(ii)->getP2(), .3); |
| if (ii < s->getChunkCount() - 1) { |
| tglColor(TPixel::Red); |
| tglDrawText(s->getChunk(ii)->getP2(), QString::number(ii + 1).toStdString()); |
| } |
| } |
| } |
| } |
| glPopMatrix(); |
| #endif |
| |
| if (alphaChannel) { |
| GLboolean red, green, blue, alpha; |
| tglGetColorMask(red, green, blue, alpha); |
| |
| |
| tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| glColorMask(red, green, blue, GL_FALSE); |
| prop->draw(rd); |
| |
| |
| tglEnableBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, alpha); |
| prop->draw(rd); |
| |
| glColorMask(red, green, blue, alpha); |
| } else { |
| |
| if (!rd.m_isOfflineRender || !rd.m_isImagePattern) |
| tglRgbOnlyColorMask(); |
| |
| prop->draw(rd); |
| } |
| |
| if (pushAttribs) |
| glPopAttrib(); |
| } |
| } |
| |
| for (UINT i = 0; i < r->getSubregionCount(); i++) |
| tglDraw(rd, r->getSubregion(i), pushAttribs); |
| checkErrorsByGL; |
| } |
| |
| |
| |
| void tglDrawMask(const TVectorRenderData &rd1, const TVectorImage *vim) |
| { |
| UINT i; |
| assert(vim); |
| if (!vim) |
| return; |
| TVectorRenderData rd(rd1); |
| |
| glPushAttrib(GL_ALL_ATTRIB_BITS); |
| |
| if (!rd.m_palette) { |
| TPalette *vPalette = vim->getPalette(); |
| assert(vPalette); |
| rd.m_palette = vPalette; |
| } |
| for (i = 0; i < vim->getRegionCount(); i++) |
| tglDraw(rd, vim->getRegion(i), false); |
| |
| glPopAttrib(); |
| } |
| |
| |
| |
| namespace |
| { |
| bool isOThick(const TStroke *s) |
| { |
| int i; |
| for (i = 0; i < s->getControlPointCount(); i++) |
| if (s->getControlPoint(i).thick != 0) |
| return false; |
| return true; |
| } |
| } |
| |
| void tglDraw(const TVectorRenderData &rd, const TStroke *s, bool pushAttribs) |
| { |
| assert(s); |
| if (!s) |
| return; |
| |
| TStrokeProp *prop = 0; |
| bool pushedAttribs = false; |
| |
| try { |
| TColorStyleP style; |
| TStroke *stroke = const_cast<TStroke *>(s); |
| if (rd.m_inkCheckEnabled && s->getStyle() == rd.m_colorCheckIndex) { |
| static TSolidColorStyle *redColor = new TSolidColorStyle(); |
| redColor->addRef(); |
| redColor->setMainColor(TPixel::Red); |
| style = redColor; |
| } else if (rd.m_tcheckEnabled) { |
| static TSolidColorStyle *color = new TSolidColorStyle(); |
| color->addRef(); |
| color->setMainColor(rd.m_tCheckInk); |
| style = color; |
| } else |
| style = rd.m_palette->getStyle(stroke->getStyle()); |
| |
| if (!rd.m_show0ThickStrokes && isOThick(s) && dynamic_cast<TSolidColorStyle *>(style.getPointer()) |
| && !rd.m_tcheckEnabled) |
| return; |
| |
| |
| |
| assert(rd.m_palette); |
| |
| prop = s->getProp(); |
| |
| if (prop) |
| prop->getMutex()->lock(); |
| |
| if (!style->isStrokeStyle() || style->isEnabled() == false) { |
| if (prop) |
| prop->getMutex()->unlock(); |
| |
| prop = 0; |
| } else { |
| |
| |
| |
| |
| if (!prop || style.getPointer() != prop->getColorStyle()) { |
| if (prop) |
| prop->getMutex()->unlock(); |
| |
| stroke->setProp(style->makeStrokeProp(stroke)); |
| prop = stroke->getProp(); |
| if (prop) |
| prop->getMutex()->lock(); |
| } |
| } |
| |
| |
| if (!prop) |
| return; |
| |
| if (pushAttribs) |
| glPushAttrib(GL_ALL_ATTRIB_BITS), pushedAttribs = true; |
| |
| bool alphaChannel = rd.m_alphaChannel, antialias = rd.m_antiAliasing; |
| TVectorImagePatternStrokeProp *aux = dynamic_cast<TVectorImagePatternStrokeProp *>(prop); |
| if (aux) |
| prop->draw(rd); |
| else { |
| if (antialias) |
| tglEnableLineSmooth(true); |
| else |
| tglEnableLineSmooth(false); |
| |
| if (alphaChannel) { |
| GLboolean red, green, blue, alpha; |
| tglGetColorMask(red, green, blue, alpha); |
| |
| |
| tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| glColorMask(red, green, blue, GL_FALSE); |
| prop->draw(rd); |
| |
| |
| tglEnableBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, alpha); |
| prop->draw(rd); |
| |
| glColorMask(red, green, blue, alpha); |
| } else { |
| tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| prop->draw(rd); |
| } |
| } |
| |
| if (pushAttribs) |
| glPopAttrib(), pushedAttribs = false; |
| |
| prop->getMutex()->unlock(); |
| |
| } catch (...) { |
| if (prop) |
| prop->getMutex()->unlock(); |
| if (pushedAttribs) |
| glPopAttrib(); |
| } |
| } |
| |
| |
| |
| void tglDoDraw(const TVectorRenderData &rd, TRegion *r) |
| { |
| bool visible = false; |
| int colorCount = 0; |
| if (!r) |
| return; |
| |
| TColorStyleP style = rd.m_palette->getStyle(r->getStyle()); |
| colorCount = style->getColorParamCount(); |
| if (colorCount == 0) |
| visible = true; |
| else { |
| visible = false; |
| for (int j = 0; j < colorCount && !visible; j++) { |
| TPixel32 color = style->getColorParamValue(j); |
| if (rd.m_cf) |
| color = (*(rd.m_cf))(color); |
| if (color.m != 0) |
| visible = true; |
| } |
| } |
| if (visible) |
| tglDraw(rd, r, false); |
| else |
| for (UINT j = 0; j < r->getSubregionCount(); j++) |
| tglDraw(rd, r->getSubregion(j), false); |
| } |
| |
| |
| |
| void tglDoDraw(const TVectorRenderData &rd, const TStroke *s) |
| { |
| bool visible = false; |
| int colorCount = 0; |
| |
| const TPalette *palette = rd.m_palette; |
| |
| int styleId = s->getStyle(); |
| |
| TColorStyleP style = palette->getStyle(styleId); |
| assert(style); |
| colorCount = style->getColorParamCount(); |
| if (colorCount == 0) |
| visible = true; |
| else { |
| visible = false; |
| for (int j = 0; j < style->getColorParamCount() && !visible; j++) { |
| TPixel32 color = style->getColorParamValue(j); |
| if (rd.m_cf) |
| color = (*(rd.m_cf))(color); |
| if (color.m != 0) |
| visible = true; |
| } |
| } |
| #if DISEGNO_OUTLINE == 0 |
| if (visible) |
| #endif |
| tglDraw(rd, s, false); |
| |
| #ifdef _DEBUG |
| |
| |
| #endif |
| } |
| |
| |
| |
| namespace |
| { |
| |
| void doDraw(const TVectorImage *vim, const TVectorRenderData &_rd, bool drawEnteredGroup) |
| { |
| static TOnionFader *fade = new TOnionFader(TPixel::White, 0.5); |
| |
| TVectorRenderData rd(_rd); |
| |
| if (!rd.m_palette) { |
| TPalette *vPalette = vim->getPalette(); |
| rd.m_palette = vPalette; |
| if (!vPalette) |
| return; |
| } |
| |
| if (!drawEnteredGroup && !rd.m_isIcon && vim->isInsideGroup() > 0) |
| rd.m_cf = fade; |
| |
| TVectorRenderData rdRegions = rd; |
| |
| |
| |
| UINT strokeIndex = 0; |
| Index = 0; |
| |
| while (strokeIndex < vim->getStrokeCount()) |
| { |
| int currStrokeIndex = strokeIndex; |
| if (!rd.m_isIcon && vim->isInsideGroup() > 0 && |
| ((drawEnteredGroup && !vim->isEnteredGroupStroke(strokeIndex)) || |
| !drawEnteredGroup && vim->isEnteredGroupStroke(strokeIndex))) { |
| while (strokeIndex < vim->getStrokeCount() && vim->sameGroup(strokeIndex, currStrokeIndex)) |
| strokeIndex++; |
| continue; |
| } |
| |
| if (rd.m_drawRegions) |
| for (UINT regionIndex = 0; regionIndex < vim->getRegionCount(); regionIndex++) |
| if (vim->sameGroupStrokeAndRegion(currStrokeIndex, regionIndex)) |
| tglDoDraw(rdRegions, vim->getRegion(regionIndex)); |
| while (strokeIndex < vim->getStrokeCount() && vim->sameGroup(strokeIndex, currStrokeIndex)) { |
| #if DISEGNO_OUTLINE == 1 |
| CurrStrokeIndex = strokeIndex; |
| CurrVimg = vim; |
| #endif |
| tglDoDraw(rd, vim->getStroke(strokeIndex)); |
| strokeIndex++; |
| } |
| } |
| } |
| } |
| |
| |
| |
| void tglDraw(const TVectorRenderData &rd, const TVectorImage *vim) |
| { |
| assert(vim); |
| if (!vim) |
| return; |
| |
| QMutexLocker sl(vim->getMutex()); |
| |
| checkErrorsByGL; |
| checkErrorsByGL; |
| |
| glPushAttrib(GL_ALL_ATTRIB_BITS); |
| |
| |
| |
| |
| glEnable(GL_ALPHA_TEST); |
| glAlphaFunc(GL_GREATER, 0); |
| |
| doDraw(vim, rd, false); |
| if (!rd.m_isIcon && vim->isInsideGroup() > 0) |
| doDraw(vim, rd, true); |
| |
| glDisable(GL_ALPHA_TEST); |
| |
| glPopAttrib(); |
| |
| #ifdef _DEBUG |
| vim->drawAutocloses(rd); |
| #endif |
| checkErrorsByGL; |
| |
| } |
| |
| |
| |
| |