void Viewport::continueDrawing(int buffer) { renderbuffer &b = buffers[buffer]; if (b.dirty) return; SharedDataLock ctxlock(ctx->mutex); SharedDataLock setslock(sets->mutex); if ((*sets)->empty() || (*ctx)->wait) return; setslock.unlock(); ctxlock.unlock(); QPainter painter(b.fbo); if (drawingState == HIGH_QUALITY) painter.setRenderHint(QPainter::Antialiasing); painter.save(); painter.setWorldTransform(modelview); drawBins(painter, b.renderTimer, b.renderedLines, b.renderStep, (buffer == 1)); painter.restore(); update(); }
void Viewport::prepareLines() { if (!ctx) { GGDBGM("no ctx" << endl); return; } if (!sets) { GGDBGM("no sets" << endl); return; } // lock context and sets SharedDataLock ctxlock(ctx->mutex); SharedDataLock setslock(sets->mutex); (*ctx)->wait.fetch_and_store(0); // set to zero: our data will be usable if ((*ctx)->reset.fetch_and_store(0)) // is true if it was 1 before reset(); // first step (cpu only) Compute::preparePolylines(**ctx, **sets, shuffleIdx); // second step (cpu -> gpu) target->makeCurrent(); Compute::storeVertices(**ctx, **sets, shuffleIdx, vb, drawMeans->isChecked(), illuminantAppl); }
void Viewport::updateBuffers(RenderMode spectrum, RenderMode highlight) { if (!buffers[0].fbo || !buffers[1].fbo) return; { SharedDataLock ctxlock(ctx->mutex); SharedDataLock setslock(sets->mutex); if ((*sets)->empty() || (*ctx)->wait) return; } // even if we had HQ last time, this time it will be dirty! if (drawingState == HIGH_QUALITY_QUICK) drawingState = QUICK; // array for convenience RenderMode mode[2] = { spectrum, highlight }; QRect rect(0, 0, width, height); for (int i = 0; i < 2; ++i) { renderbuffer &b = buffers[i]; if (mode[i] == RM_SKIP) continue; b.renderTimer.stop(); b.renderedLines = 0; if (!(b.fbo->isValid() && b.blit->isValid())) { GerbilApplication::internalError( "Framebuffer not valid in viewport updateBuffers().", false); return; } // does not make much sense here, but seems to help with no/partial update problems target->makeCurrent(); QPainter painter(b.fbo); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(rect, Qt::transparent); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); if (drawingState == HIGH_QUALITY) painter.setRenderHint(QPainter::Antialiasing); painter.save(); painter.setWorldTransform(modelview); drawBins(painter, b.renderTimer, b.renderedLines, (mode[i] == RM_FULL) ? std::numeric_limits<int>::max() : b.renderStep, (i == 1)); painter.restore(); b.dirty = false; } update(); }
void Viewport::rebuild() { // guess: we want the lock to carry over both methods.. SharedDataLock ctxlock(ctx->mutex); SharedDataLock setslock(sets->mutex); prepareLines(); // will also call reset() if indicated by ctx updateBuffers(); }
void Viewport::setLimiters(int label) { if (label < 1) { // not label SharedDataLock ctxlock(ctx->mutex); limiters.assign((*ctx)->dimensionality, std::make_pair(0, (*ctx)->nbins-1)); if (label == -1) { // use hover data int b = selection; int h = hover; limiters[b] = std::make_pair(h, h); } } else { // label holds data SharedDataLock setslock(sets->mutex); if ((int)(*sets)->size() > label && (**sets)[label].totalweight > 0) { // use range from this label const std::vector<std::pair<int, int> > &b = (**sets)[label].boundary; limiters.assign(b.begin(), b.end()); } else { setLimiters(0); } } }
void Viewport::drawBins(QPainter &painter, QTimer &renderTimer, unsigned int &renderedLines, unsigned int renderStep, bool highlight) { SharedDataLock ctxlock(ctx->mutex); // TODO: this also locks shuffleIdx implicitely, better do it explicitely? SharedDataLock setslock(sets->mutex); // Stopwatch watch("drawBins"); /* initialize painting in GL, vertex buffer */ target->makeCurrent(); painter.beginNativePainting(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); bool success = vb.bind(); if (!success) { GerbilApplication::internalError( "Vertex buffer could not be bound in viewport drawBins().", false); painter.endNativePainting(); return; } glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, 0); size_t iD = renderedLines * (*ctx)->dimensionality; /* determine drawing range. could be expanded to only draw spec. labels */ // make sure that viewport draws "unlabeled" data in ignore-label case int start = ((showUnlabeled || (*ctx)->ignoreLabels == 1) ? 0 : 1); int end = (showLabeled ? (int)(*sets)->size() : 1); size_t total = shuffleIdx.size(); size_t first = renderedLines; size_t last = std::min((size_t)(renderedLines + renderStep), total); // loop over all elements in vertex index, update element and vector indices for (size_t i = first; i < last; ++i, iD += (*ctx)->dimensionality) { std::pair<int, BinSet::HashKey> &idx = shuffleIdx[i]; // filter out according to label bool filter = ((idx.first < start || idx.first >= end)); // do not filter out highlighted label(s) if (!(*ctx)->ignoreLabels) { filter = filter && !highlightLabels.contains(idx.first); } if (filter) { // increase loop count to achieve renderStep if (last < total) ++last; continue; } BinSet::HashKey &K = idx.second; // highlight mode (foreground buffer) if (highlight) { //test if we are part of the highlight bool highlighted = false; if (limiterMode) { highlighted = true; for (size_t i = 0; i < (*ctx)->dimensionality; ++i) { unsigned char k = K[i]; if (k < limiters[i].first || k > limiters[i].second) highlighted = false; } } else if ((unsigned char)K[selection] == hover) { highlighted = true; } // filter out if (!highlighted) { // increase loop count to achieve renderStep if (last < total) ++last; continue; } } // grab binset and bin according to key BinSet &s = (**sets)[idx.first]; std::pair<BinSet::HashMap::const_iterator, BinSet::HashMap::const_iterator> binitp = s.bins.equal_range(K); if (s.bins.end() == binitp.first) { // FIXME this is an error and should be treated accordingly GGDBGM("no bin"<< endl); return; } Bin const &b = s.bins.equal_range(K).first->second; // set color QColor color = determineColor((drawRGB->isChecked() ? b.rgb : s.label), b.weight, s.totalweight, highlight, highlightLabels.contains(idx.first)); target->qglColor(color); // draw polyline glDrawArrays(GL_LINE_STRIP, (GLsizei)iD, (GLint)(*ctx)->dimensionality); } vb.release(); painter.endNativePainting(); // setup succeeding incremental drawing renderedLines += (unsigned int)(last - first); if (renderedLines < total) { if (renderedLines <= renderStep) { renderTimer.start(150); } else { renderTimer.start(0); } } }
bool Viewport::drawScene(QPainter *painter, bool withDynamics) { bool disabled = false; { /* TODO: disabled member state instead? */ SharedDataLock ctxlock(ctx->mutex); SharedDataLock setslock(sets->mutex); if ((*sets)->empty() || (*ctx)->wait) disabled = true; } target->makeCurrent(); /* draw background */ QRect rect(0, 0, width, height); /* Hack: without dynamics, we typically also want a boring background */ if (withDynamics) painter->fillRect(rect, QColor(15, 7, 15)); else painter->fillRect(rect, Qt::black); painter->setRenderHint(QPainter::Antialiasing); if (disabled) { drawWaitMessage(painter); return false; } painter->save(); painter->setWorldTransform(modelview); drawAxesBg(painter); painter->restore(); /* determine if we draw the highlight part */ // only draw when active and dynamic content is desired bool drawHighlight = active && withDynamics; // only draw if not implicitely empty drawHighlight = drawHighlight && (hover > -1 || limiterMode); // do not draw when in single pixel overlay mode drawHighlight = drawHighlight && (!overlayMode); // do not draw when in single label mode drawHighlight = drawHighlight && (highlightLabels.empty()); for (int i = 0; i < (drawHighlight ? 2 : 1); ++i) { renderbuffer &b = buffers[i]; if (b.dirty) { drawWaitMessage(painter); // nothing to draw yet, don't even bother with other buffer, disabled = true; break; } // blit first to get from multisample to regular buffer. then draw that QGLFramebufferObject::blitFramebuffer(b.blit, rect, b.fbo, rect); target->drawTexture(rect, b.blit->texture()); } // only provide selection for view with dynamic components (selected band) if (withDynamics) drawLegend(painter, selection); else drawLegend(painter); // foreground axes are a dynamic part if (withDynamics) { painter->save(); painter->setWorldTransform(modelview); drawAxesFg(painter); painter->restore(); } if (overlayMode && withDynamics) drawOverlay(painter); // return success if nothing was omited return !disabled; }