#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" #include #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; //----------------------------------------------------------------------------- /* DV_EXPORT_API void mylog(std::string s) { static TThread::Mutex mutex; QMutexLocker sl(mutex); std::ofstream os("C:\\gmt\\buttami\\bu.txt", std::ios::app); LARGE_INTEGER ticksPerSecond; LARGE_INTEGER tick; static LARGE_INTEGER firstTick; static bool firstTime = true; long dt = 0; QueryPerformanceFrequency(&ticksPerSecond); QueryPerformanceCounter(&tick); if(firstTime) {firstTick = tick;firstTime=false;} else { dt = (long)(1000000*(tick.QuadPart-firstTick.QuadPart)/ticksPerSecond.QuadPart); } os << dt << ":" << s << std::endl; } */ //============================================================================= #ifdef _DEBUG bool checkQuadraticDistance(TStroke *stroke, bool checkThickness) { UINT i, qCount = stroke->getChunkCount(); const TThickQuadratic *q; TThickPoint p1, p2, p3; // se i punti coincidono e' una stroke puntiforme ed e' ammessa 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 void drawArrows(TStroke *stroke, bool onlyFirstPoint) { double length = stroke->getLength(0.0, 1.0); int points = length / 20; if (points < 2) points += 1; double currentPosition = 0.0; TPointD prePoint, point, postPoint; glColor3d(1.0, 0.0, 0.0); for (int i = 0; i <= points; i++) { currentPosition = i / (double)points; point = stroke->getPointAtLength(length * currentPosition); prePoint = (i == 0) ? point : stroke->getPointAtLength(length * (currentPosition - 0.02)); postPoint = (i == points) ? point : stroke->getPointAtLength(length * (currentPosition + 0.02)); if (prePoint == postPoint) continue; double radian = std::atan2(postPoint.y - prePoint.y, postPoint.x - prePoint.x); double degree = radian * 180.0 / 3.14159265; glPushMatrix(); glTranslated(point.x, point.y, 0); glRotated(degree, 0, 0, 1); glBegin(GL_LINES); glVertex2d(0, 0); glVertex2d(-3, -3); glVertex2d(0, 0); glVertex2d(-3, 3); glEnd(); glPopMatrix(); if (onlyFirstPoint) break; // make the arrow blue from the second one glColor3d(0.0, 0.0, 1.0); } } //----------------------------------------------------------------------------- // Used for Guided Drawing static void drawFirstControlPoint(const TVectorRenderData &rd, TStroke *stroke) { TPointD p = stroke->getPoint(0.0); double length = stroke->getLength(0.0, 1.0); int msecs = QTime::currentTime().msec(); double modifier = (msecs / 100) * 0.1; TPointD startPoint = stroke->getPointAtLength(length * modifier); TPointD endPoint = stroke->getPointAtLength(length * 0.10); double j = 0.025; glPushMatrix(); tglMultMatrix(rd.m_aff); if (!rd.m_animatedGuidedDrawing) glLineWidth(2.0f); glColor3d(0.0, 1.0, 0.0); if (!rd.m_animatedGuidedDrawing) { drawArrows(stroke, false); } if (rd.m_animatedGuidedDrawing) { drawArrows(stroke, true); glColor3d(0.0, 1.0, 0.0); j = 0.025 + modifier; glBegin(GL_LINES); // draw the first animated section for (int i = 0; i < 8; i++) { endPoint = stroke->getPointAtLength(length * j); glVertex2d(startPoint.x, startPoint.y); glVertex2d(endPoint.x, endPoint.y); startPoint = endPoint; j += 0.025; if (j > 1) { j -= 1; startPoint = stroke->getPointAtLength(length * j); } } modifier = modifier + 0.5; if (modifier >= 1) modifier -= 1; startPoint = stroke->getPointAtLength(length * modifier); j = 0.025 + modifier; // draw another animated section for (int i = 0; i < 8; i++) { endPoint = stroke->getPointAtLength(length * j); glVertex2d(startPoint.x, startPoint.y); glVertex2d(endPoint.x, endPoint.y); startPoint = endPoint; j += 0.025; if (j > 1) { j -= 1; startPoint = stroke->getPointAtLength(length * j); } } glEnd(); } glLineWidth(1.0f); glPopMatrix(); } //============================================================================= /*TPixel TransparencyCheckBlackBgInk = TPixel(255,255,255); TPixel TransparencyCheckWhiteBgInk = TPixel(0,0,0); TPixel TransparencyCheckPaint = TPixel(127,127,127);*/ 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) { // for example texture 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(/*rd.m_palette*/); /// questo codice satva dentro tregion::getprop///// int styleId = r->getStyle(); if (styleId) { // TColorStyle * style = rd.m_palette->getStyle(styleId); if (!style->isRegionStyle() || style->isEnabled() == false) { prop = 0; } else { // Warning: The same remark of stroke props holds here. if (!prop || style.getPointer() != prop->getColorStyle()) { r->setProp(style->makeRegionProp(r)); prop = r->getProp(); } } } ////// draw if (prop) { if (pushAttribs) glPushAttrib(GL_ALL_ATTRIB_BITS); tglEnableLineSmooth(true); //#define DRAW_EDGE_NUMBERS #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); // Draw RGB channels tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColorMask(red, green, blue, GL_FALSE); prop->draw(rd); // Draw Matte channel 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 { // pezza: in render, le aree fillate dei custom styles sparivano. if (!rd.m_isOfflineRender || !rd.m_isImagePattern) tglRgbOnlyColorMask(); // RGB components only 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; } } // namespace 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(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_ink1CheckEnabled && s->getStyle() == 1) { // Ink #1 Check. // Could possibly merge with above. 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( style.getPointer()) // This is probably to exclude // TCenterlineStrokeStyle-like styles && !rd.m_tcheckEnabled) // I wonder why this? return; // const TStroke& stroke = *s; //serve??? assert(rd.m_palette); prop = s->getProp(/*rd.m_palette*/); /////questo codice stava dentro tstroke::getprop///////// if (prop) prop->getMutex()->lock(); if (!style->isStrokeStyle() || style->isEnabled() == false) { if (prop) prop->getMutex()->unlock(); prop = 0; } else { // Warning: the following pointers check is conceptually wrong - we // keep it because the props maintain SMART POINTER-like reference to // the associated style. This prevents the style from being destroyed // while still referenced by the prop. if (!prop || style.getPointer() != prop->getColorStyle()) { if (prop) prop->getMutex()->unlock(); stroke->setProp(style->makeStrokeProp(stroke)); prop = stroke->getProp(); if (prop) prop->getMutex()->lock(); } } //--------- draw ------------ 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(prop); if (aux) // gli image pattern vettoriali tornano in questa funzione....non // facendo il corpo dell'else'si evita di disegnarli due volte! prop->draw(rd); else { if (antialias) tglEnableLineSmooth(true); else tglEnableLineSmooth(false); if (alphaChannel) { GLboolean red, green, blue, alpha; tglGetColorMask(red, green, blue, alpha); // Draw RGB channels tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColorMask(red, green, blue, GL_FALSE); prop->draw(rd); // Draw Matte channel 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(); } } //------------------------------------------------------------------------------------ static 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) // for example texture 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); } //------------------------------------------------------------------------------------ static bool tglDoDraw(const TVectorRenderData &rd, const TStroke *s) { bool visible = false; int colorCount = 0; const TPalette *palette = rd.m_palette; int styleId = s->getStyle(); // assert(0<=styleId && styleIdgetStyle(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; } } bool ret = false; if (visible) { // Change stroke color to blue if guided drawing if (rd.m_showGuidedDrawing && rd.m_highLightNow) { TVectorRenderData *newRd = new TVectorRenderData( rd, rd.m_aff, rd.m_clippingRect, rd.m_palette, rd.m_guidedCf); tglDraw(*newRd, s, false); delete newRd; TStroke *new_s = (TStroke *)s; drawFirstControlPoint(rd, new_s); ret = rd.m_animatedGuidedDrawing; } else { tglDraw(rd, s, false); } } #ifdef _DEBUG // drawControlPoints(rd, vim->getStroke(i), sqrt(tglGetPixelSize2()), true); // assert(checkQuadraticDistance(vim->getStroke(i),true)); #endif return ret; } //------------------------------------------------------------------------------------ namespace { void doDraw(const TVectorImage *vim, const TVectorRenderData &_rd, bool drawEnteredGroup, TStroke **guidedStroke = 0) { 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; /*if (rd.m_drawRegions && rd.m_isImagePattern)//gli image pattern hanno bisogno dell'antialiasig per le linee, ma sulle aree ci sarebbero un sacco di assert rdRegions.m_alphaChannel = rdRegions.m_antiAliasing = false;*/ UINT strokeIndex = 0; Index = 0; while (strokeIndex < vim->getStrokeCount()) // ogni ciclo di while disegna un gruppo { 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 (rd.m_indexToHighlight != strokeIndex) { rd.m_highLightNow = false; } else { rd.m_highLightNow = true; } #if DISEGNO_OUTLINE == 1 CurrStrokeIndex = strokeIndex; CurrVimg = vim; #endif bool isGuided = tglDoDraw(rd, vim->getStroke(strokeIndex)); if (isGuided && guidedStroke) *guidedStroke = vim->getStroke(strokeIndex); strokeIndex++; } } } } // namespace //------------------------------------------------------------------------------------ void tglDraw(const TVectorRenderData &rd, const TVectorImage *vim, TStroke **guidedStroke) { assert(vim); if (!vim) return; QMutexLocker sl(vim->getMutex()); checkErrorsByGL; checkErrorsByGL; glPushAttrib(GL_ALL_ATTRIB_BITS); // if(!rd.m_palette) rd.m_palette = vim->getPalette(); // mylog("tglDraw start; mutex=" + toString((unsigned long)&vim->getMutex())); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); doDraw(vim, rd, false, guidedStroke); if (!rd.m_isIcon && vim->isInsideGroup() > 0) doDraw(vim, rd, true, guidedStroke); glDisable(GL_ALPHA_TEST); glPopAttrib(); #ifdef _DEBUG vim->drawAutocloses(rd); #endif checkErrorsByGL; // mylog("tglDraw stop"); } //----------------------------------------------------------------------------- //-----------------------------------------------------------------------------