void ofApp::mapData() { //map the data for (int j = 0; j < _csv.data.size(); j++) { float myX = ofMap(ofToFloat(_csv.data[j][0]), -180, 180, 2000, -2000); float myY = ofMap(ofToFloat(_csv.data[j][1]), -90, 90, -1000, 1000); ofVec3f thisPoint(myY, myX, 0.0f); _mesh.addVertex(thisPoint); _mesh.addColor(ofFloatColor(1, 1)); } }
void Circle3DOverlay::render(RenderArgs* args) { if (!_visible) { return; // do nothing if we're not visible } float alpha = getAlpha(); if (alpha == 0.0f) { return; // do nothing if our alpha is 0, we're not visible } // Create the circle in the coordinates origin float outerRadius = getOuterRadius(); float innerRadius = getInnerRadius(); // only used in solid case float startAt = getStartAt(); float endAt = getEndAt(); bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); const float FULL_CIRCLE = 360.0f; const float SLICES = 180.0f; // The amount of segment to create the circle const float SLICE_ANGLE = FULL_CIRCLE / SLICES; //const int slices = 15; xColor colorX = getColor(); const float MAX_COLOR = 255.0f; glm::vec4 color(colorX.red / MAX_COLOR, colorX.green / MAX_COLOR, colorX.blue / MAX_COLOR, alpha); bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; _lastColor = colorX; auto geometryCache = DependencyManager::get<GeometryCache>(); Q_ASSERT(args->_batch); auto& batch = *args->_batch; batch._glLineWidth(_lineWidth); auto transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch.setModelTransform(transform); DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getIsSolid()) { if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { _quadVerticesID = geometryCache->allocateID(); } if (geometryChanged || colorChanged) { QVector<glm::vec2> points; float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 mostRecentInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); glm::vec2 mostRecentOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); while (angle < endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << mostRecentInnerPoint << mostRecentOuterPoint << thisOuterPoint; // first triangle points << mostRecentInnerPoint << thisInnerPoint << thisOuterPoint; // second triangle angle += SLICE_ANGLE; mostRecentInnerPoint = thisInnerPoint; mostRecentOuterPoint = thisOuterPoint; } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << mostRecentInnerPoint << mostRecentOuterPoint << lastOuterPoint; // first triangle points << mostRecentInnerPoint << lastInnerPoint << lastOuterPoint; // second triangle geometryCache->updateVertices(_quadVerticesID, points, color); } geometryCache->renderVertices(batch, gpu::TRIANGLES, _quadVerticesID); } else { if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { _lineVerticesID = geometryCache->allocateID(); } if (geometryChanged || colorChanged) { QVector<glm::vec2> points; float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << firstPoint; while (angle < endAt) { angle += SLICE_ANGLE; angleInRadians = glm::radians(angle); glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << thisPoint; if (getIsDashedLine()) { angle += SLICE_ANGLE / 2.0f; // short gap angleInRadians = glm::radians(angle); glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << dashStartPoint; } } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); points << lastPoint; geometryCache->updateVertices(_lineVerticesID, points, color); } if (getIsDashedLine()) { geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); } else { geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); } } // draw our tick marks // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getHasTickMarks()) { if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _majorTicksVerticesID = geometryCache->allocateID(); } if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _minorTicksVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> majorPoints; QVector<glm::vec2> minorPoints; // draw our major tick marks if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { float tickMarkAngle = getMajorTickMarksAngle(); float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMajorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); majorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } // draw our minor tick marks if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { float tickMarkAngle = getMinorTickMarksAngle(); float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMinorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); minorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } xColor majorColorX = getMajorTickMarksColor(); glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); xColor minorColorX = getMinorTickMarksColor(); glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); } geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID); geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID); } if (geometryChanged) { _lastStartAt = startAt; _lastEndAt = endAt; _lastInnerRadius = innerRadius; _lastOuterRadius = outerRadius; } }
void urgTimelapse::run(float speed, float periodSize, bool bClockwise, float alignmentAngle, float startPeriod) { // exit function if frame number is -1 if (frameNum == -1) return; // reset frame (MUST DO THIS) renderedFrame.clear(); // ------------------------------------ // ------------ FILL FRAME ------------ // ------------------------------------ // reset counter int scanNum = 0; // add scans to the mesh as dictated by the frames ofBuffer::Line it = buffer.getLines().begin(); advance(it, frames[frameNum].start); ofBuffer::Line end = buffer.getLines().end(); for (it, end; it != end; ++it) { // get line string line = *it; vector<string> values = ofSplitString(line, ","); // put all the points in a scan in the mesh for (int i = minIndex; i < maxIndex; i++) { // find the x and y coordinates float px = ofToFloat(values[2 * i + 1]); float py = ofToFloat(values[2 * i + 2]); // find the vector to this point ofVec3f thisPoint(px, py, 0.); // remove points too close double sqDist = thisPoint.distanceSquared(ofVec3f(0.,0.,0.)); if (sqDist < minSqDist2Cam) continue; // rotate this point 90 degrees about the z axis to orient it upwards thisPoint.rotate(90., ofVec3f(0., 0., 1.)); // apply the alignment angle stretch or compression to realign the two chuncks float alignmentFactor = (float)i / 682. * alignmentAngle; thisPoint.rotate(alignmentFactor, ofVec3f(0., 0., 1.)); // rotate this point about the y axis an amount proportional to this scanNumber and the number of scans in this frame (since this changes) float rotationAmt = (float)scanNum / (float)frames[frameNum].length * periodSize; // if clockwise is true, rotate in negative direction if (bClockwise) rotationAmt *= -1.; // if period is 180 and frame is odd, rotate 180 degrees if ((int)periodSize == 180 && (frameNum % 2)) rotationAmt += 180.; thisPoint.rotate(rotationAmt, ofVec3f(0., 1., 0.)); // add the point to the mesh with a color renderedFrame.addVertex(thisPoint); renderedFrame.addColor(ofFloatColor(1.)); } scanNum++; if (scanNum >= frames[frameNum].length) break; } cout << "rendered frame # " << frameNum << endl; // increment the frame number frameNum++; if (frameNum >= frames.size()) { // stop running this operation frameNum = -1; } // NOW RENDER ofPushMatrix(); // rotate the original frame ofRotate(startRotateX, 1, 0, 0); ofRotate(startRotateY, 0, 1, 0); ofRotate(startRotateZ, 0, 0, 1); renderedFrame.drawVertices(); ofPopMatrix(); // SAVE IMAGE ofSaveFrame(); }
// fill mesh with the first capture // scans are spaced out according to the speed of the rotations (degrees/sec; default = 225/64) and the timestamp of each step // each period is 180 degrees since we're recording both sides of the lidar every scan void urgTimelapse::fillFirstFrame(float speed, float periodSize, bool bClockwise, float alignmentAngle, float startPeriod) { // clear mesh for good measure firstFrame.clear(); // ------------------------------------ // ------- FIND SCANS IN FRAME -------- // ------------------------------------ // holds first time (in seconds) float timeZero; // interval of interest of the scans long frameStart = -1; long frameLength = -1; // find max interval within which to search one period float overfillAmt = 1.25; long maxSearchInterval = long(periodSize * 1/speed * 10. * overfillAmt); // overfillAmt times ideal number of scans in one frame // start and stop times to search for float startTime = startPeriod * periodSize / speed * 1000.; float stopTime = (startPeriod * periodSize + periodSize) / speed * 1000.; // For the first frame, find the start and stop scans // Note: last line may be empty long thisScanNumber = 0; for (ofBuffer::Line it = buffer.getLines().begin(), end = buffer.getLines().end(); it != end; ++it) { // get the first number (time) in this line string line = *it; if (line.empty()) { cout << "Skipping empty line" << endl; // increment counter here? continue; } line.resize((int)line.find_first_of(',')); float timeNow = ofToFloat(line); // in milliseconds // cout << timeNow << endl; // check if this scan is the start of the frame so long as it has not yet been found if (frameStart == -1) { if (timeNow >= startTime) { frameStart = thisScanNumber; timeZero = timeNow / 1000.; } } // check if it's the end of the interval if (frameStart != -1) { if (timeNow >= stopTime) { frameLength = thisScanNumber - frameStart; break; } } // increment the counter thisScanNumber++; if (thisScanNumber > frameStart + maxSearchInterval) { cout << "Couldn't find end of first frame. Try increasing search interval." << endl; break; } } // ------------------------------------ // --------- FILL FIRST FRAME --------- // ------------------------------------ // reset counter thisScanNumber = 0; // add all scans to the mesh ofBuffer::Line it = buffer.getLines().begin(); advance(it, frameStart); ofBuffer::Line end = buffer.getLines().begin(); advance(end, frameStart + frameLength); for (it; it != end; ++it) { // get this line and split up the measurements string line = *it; if (line.empty()) { cout << "Skipping empty line" << endl; continue; } vector<string> values = ofSplitString(line, ","); // get timeNow float timeNow = ofToFloat(values[0]) / 1000. - timeZero; // in seconds // put all the points in a scan in the mesh for (int i = minIndex; i < maxIndex; i++) { // find the x and y coordinates float px = ofToFloat(values[2 * i + 1]); float py = ofToFloat(values[2 * i + 2]); // find the vector to this point ofVec3f thisPoint(px, py, 0.); // remove points too close double sqDist = thisPoint.distanceSquared(ofVec3f(0.,0.,0.)); if (sqDist < minSqDist2Cam) continue; // rotate this point 90 degrees about the z axis to orient it upwards thisPoint.rotate(90., ofVec3f(0., 0., 1.)); // apply the alignment angle stretch or compression to realign the two chuncks float alignmentFactor = (float)i / 682. * alignmentAngle; thisPoint.rotate(alignmentFactor, ofVec3f(0., 0., 1.)); // rotate this point about the y axis an amount proportional to this scanNumber and the number of scans in this frame (since this changes) float rotationAmt = (float)thisScanNumber / (float)frameLength * periodSize; // cout << rotationAmt << endl; // if clockwise is true, rotate in negative direction if (bClockwise) rotationAmt *= -1.; thisPoint.rotate(rotationAmt, ofVec3f(0., 1., 0.)); // add the point to the mesh with a color firstFrame.addVertex(thisPoint); firstFrame.addColor(ofFloatColor(1.)); } thisScanNumber++; } }
// fill mesh with a spherical capture // scans are spaced out according to the speed of the rotations (degrees/sec; default = 225/64) and the timestamp of each step // each period is 180 degrees since we're recording both sides of the lidar every scan void urgDisplay::fillPointMeshTXYSpherical(float speed, float period, bool bClockwise, float startingPeriod, float numPeriods, float alignmentAngle) { // clear the mesh pointMesh.clear(); // if either variable is -1, set it to default or max if (startingPeriod == -1.) startingPeriod = 0; if (numPeriods == -1.) numPeriods = 99999.; // ------------------------------------------ // ------- FIND INTERVAL OF INTEREST -------- // ------------------------------------------ // set time zero float timeZero; // interval of interest of the scans int startIndex = -1; int endIndex = -1; // first, find the starting points and ending points for the sphere for (int i = 0; i < nScans; i++) { // find the current time float timeNow = csv.getFloat(i, 0) / 1000.; // in seconds // check if this scan is the start of the interval of interest so long as it has not yet been found if (startIndex == -1) { if ((timeNow * speed) >= (startingPeriod * period)) { startIndex = i; timeZero = timeNow; } } // check if it's the end of the interval if (startIndex != -1) { if ((timeNow * speed) >= ((startingPeriod + numPeriods) * period)) { endIndex = i; break; } } } // if endIndex wasn't assigned, assign it to the total number of scans if (endIndex == -1) endIndex = nScans; // ------------------------------------------ // ---------- FILL THE POINT MESH ----------- // ------------------------------------------ // for every scan within the interval, add it to the mesh for (int i = startIndex; i < endIndex; i++) { // get the current time float timeNow = csv.getFloat(i, 0) / 1000. - timeZero; // put all the points in a scan in the mesh for (int j = minIndex; j < maxIndex; j++) { // NOTE: I've been doing this wrong (i.e. wrong order of operations... this is why there are so many points at zero, zero)... it's right here now // find the x and y coordinates float px = csv.getFloat(i, 2 * j + 1); float py = csv.getFloat(i, 2 * j + 2); // find the vector to this point ofVec3f thisPoint(px, py, 0.); // remove points too close double sqDist = thisPoint.distanceSquared(ofVec3f(0.,0.,0.)); // cout << sqDist << endl; if (sqDist < minSqDist2Cam) continue; // if (px < 100. && py < 100.) continue; // rotate this point 90 degrees about the z axis to orient it upwards thisPoint.rotate(90., ofVec3f(0., 0., 1.)); // apply the alignment angle stretch or compression to realign the two chuncks float alignmentFactor = (float)j / 682. * alignmentAngle; thisPoint.rotate(alignmentFactor, ofVec3f(0., 0., 1.)); // rotate the point about the y axis an amount proportional to the elapsed time and the speed float rotationAmt = timeNow * speed; // if clockwise is true, rotate in negative direction if (bClockwise) rotationAmt *= -1.; thisPoint.rotate(rotationAmt, ofVec3f(0., 1., 0.)); // add the point to the mesh with a color pointMesh.addVertex(thisPoint); pointMesh.addColor(ofFloatColor(1.)); } } }
void Circle3DOverlay::render(RenderArgs* args) { if (!_visible) { return; // do nothing if we're not visible } float alpha = getAlpha(); if (alpha == 0.0f) { return; // do nothing if our alpha is 0, we're not visible } bool geometryChanged = _dirty; _dirty = false; const float FULL_CIRCLE = 360.0f; const float SLICES = 180.0f; // The amount of segment to create the circle const float SLICE_ANGLE = FULL_CIRCLE / SLICES; const float MAX_COLOR = 255.0f; auto geometryCache = DependencyManager::get<GeometryCache>(); Q_ASSERT(args->_batch); auto& batch = *args->_batch; if (args->_pipeline) { batch.setPipeline(args->_pipeline->pipeline); } // FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround auto transform = getTransform(); transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch.setModelTransform(transform); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getIsSolid()) { if (!_quadVerticesID) { _quadVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> points; QVector<glm::vec4> colors; float pulseLevel = updatePulse(); vec4 pulseModifier = vec4(1); if (_alphaPulse != 0.0f) { pulseModifier.a = (_alphaPulse >= 0.0f) ? pulseLevel : (1.0f - pulseLevel); } if (_colorPulse != 0.0f) { float pulseValue = (_colorPulse >= 0.0f) ? pulseLevel : (1.0f - pulseLevel); pulseModifier = vec4(vec3(pulseValue), pulseModifier.a); } vec4 innerStartColor = vec4(toGlm(_innerStartColor), _innerStartAlpha) * pulseModifier; vec4 outerStartColor = vec4(toGlm(_outerStartColor), _outerStartAlpha) * pulseModifier; vec4 innerEndColor = vec4(toGlm(_innerEndColor), _innerEndAlpha) * pulseModifier; vec4 outerEndColor = vec4(toGlm(_outerEndColor), _outerEndAlpha) * pulseModifier; if (_innerRadius <= 0) { _solidPrimitive = gpu::TRIANGLE_FAN; points << vec2(); colors << innerStartColor; for (float angle = _startAt; angle <= _endAt; angle += SLICE_ANGLE) { float range = (angle - _startAt) / (_endAt - _startAt); float angleRadians = glm::radians(angle); points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius); colors << glm::mix(outerStartColor, outerEndColor, range); } } else { _solidPrimitive = gpu::TRIANGLE_STRIP; for (float angle = _startAt; angle <= _endAt; angle += SLICE_ANGLE) { float range = (angle - _startAt) / (_endAt - _startAt); float angleRadians = glm::radians(angle); points << glm::vec2(cosf(angleRadians) * _innerRadius, sinf(angleRadians) * _innerRadius); colors << glm::mix(innerStartColor, innerEndColor, range); points << glm::vec2(cosf(angleRadians) * _outerRadius, sinf(angleRadians) * _outerRadius); colors << glm::mix(outerStartColor, outerEndColor, range); } } geometryCache->updateVertices(_quadVerticesID, points, colors); } geometryCache->renderVertices(batch, _solidPrimitive, _quadVerticesID); } else { if (!_lineVerticesID) { _lineVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> points; float angle = _startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius); points << firstPoint; while (angle < _endAt) { angle += SLICE_ANGLE; angleInRadians = glm::radians(angle); glm::vec2 thisPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius); points << thisPoint; if (getIsDashedLine()) { angle += SLICE_ANGLE / 2.0f; // short gap angleInRadians = glm::radians(angle); glm::vec2 dashStartPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius); points << dashStartPoint; } } // get the last slice portion.... angle = _endAt; angleInRadians = glm::radians(angle); glm::vec2 lastPoint(cosf(angleInRadians) * _outerRadius, sinf(angleInRadians) * _outerRadius); points << lastPoint; geometryCache->updateVertices(_lineVerticesID, points, vec4(toGlm(getColor()), getAlpha())); } if (getIsDashedLine()) { geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); } else { geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); } } // draw our tick marks // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getHasTickMarks()) { if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _majorTicksVerticesID = geometryCache->allocateID(); } if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _minorTicksVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> majorPoints; QVector<glm::vec2> minorPoints; // draw our major tick marks if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { float tickMarkAngle = getMajorTickMarksAngle(); float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMajorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= _endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); majorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } // draw our minor tick marks if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { float tickMarkAngle = getMinorTickMarksAngle(); float angle = _startAt - fmodf(_startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMinorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? _innerRadius : _outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= _endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); minorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } xColor majorColorX = getMajorTickMarksColor(); glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); xColor minorColorX = getMinorTickMarksColor(); glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); } geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID); geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID); } }
int PointPrototype::y() const { return thisPoint()->y(); }
void PointPrototype::setY(int y) { thisPoint()->setY(y); }
void PointPrototype::setX(int x) { thisPoint()->setX(x); }
int PointPrototype::x() const { return thisPoint()->x(); }
int QWzmViewer::savePIE(const char *filename, const MODEL *psModel, int pieVersion, int type) { std::fstream file; int i, j, k; /* variable ptOffset: Temporary storage of calculated index * for a give face OR vertex in the WZM vertex array. */ /* variable ptSetIndex: Index of a vertex in the set * of PIE points for a given PIE level. */ // variable polyFlag: Use to compose the flag for a PIE polygon unsigned int ptOffset, ptSetIndex, polyFlag; /* Temporary stringstream used to accomodate * the order PIE polygon data is written */ std::stringstream animTmpSs; MESH *mesh; /* variable unitW: Width of the bounding box for * a single tex. anim. "frame" of a polygon. * variable unitH: Same as unitW except represents * the height. */ /* variable t: represents the top of the bounding box * when estimating the tex. anim.'s * height. * variable b: Same as t except represents the * bottom. */ double unitW, unitH, t, b; /* variable ptSet: for creating a unique set * of PIE points for a given PIE level. */ std::set< pie_Point> ptSet; /* variable textures: Temporary storage of * texture coordinates to avoid redundant * ptOffset calculations. */ std::queue< textCoords, std::list<textCoords> > textures; file.open(filename, std::fstream::out); if (!file.is_open()) { qWarning("QWzmViewer::savePIE - Failed to open file."); return -1; } file << "PIE " << pieVersion << '\n'; file << "TYPE " << std::hex << type << std::dec << "\n"; // Texture directive: file << "TEXTURE 0 " << psModel->texPath; switch (pieVersion) { case 2: if (psModel->pixmap != NULL) { file << ' ' << psModel->pixmap->h << ' ' << psModel->pixmap->w << '\n'; } else { file << " 256 256\n"; } break; case 3: file << " 0 0\n"; break; default: file.close(); qWarning("QWzmViewer::savePIE - Unsupported pie version"); return -1; } // LEVELS directive file << "LEVELS " << psModel->meshes << '\n'; // For each WZM mesh a PIE level. for (i = 0; i < psModel->meshes; i++) { ptSet.clear(); mesh = &(psModel->mesh[i]); // LEVEL directive file << "LEVEL " << i + 1 << "\n"; // Create the set of unique points. for (j = 0; j < mesh->vertices; j++) { ptSet.insert(pie_Point(mesh->vertexArray[j*VERTICES_PER_TRIANGLE], mesh->vertexArray[j*VERTICES_PER_TRIANGLE+1], mesh->vertexArray[j*VERTICES_PER_TRIANGLE+2])); } if (ptSet.size() > pie_MAX_POLYGONS) { file.close(); qWarning("QWzmViewer::savePIE - Model has too many vertices to save as PIE."); return -1; } // POINTS directive file << "POINTS " << ptSet.size() << '\n'; // print out all the points in the set std::set< pie_Point>::iterator it; for (it = ptSet.begin(); it != ptSet.end(); it++) { GLfloat x, y, z; it->getXYZ(x, y, z); switch (pieVersion) { case 2: file << '\t' << (int)rintf(x) << ' ' << (int)rintf(y) << ' ' << (int)rintf(z) << '\n'; break; case 3: file << '\t' << x << ' ' << y << ' ' << z << '\n'; break; } } // POLYGONS directive file << "POLYGONS " << mesh->faces << '\n'; for (j = 0; j < mesh->faces; j++) { polyFlag = iV_IMD_TEX; // Default flag animTmpSs.str(std::string()); if (mesh->textureArrays > 1) { ptOffset = mesh->indexArray[j*VERTICES_PER_TRIANGLE]; /* * TODO: * This _if_ statement isn't a robust way of checking * for animations or team colours. */ if ((mesh->textureArray[0][ptOffset*2] < mesh->textureArray[1][ptOffset*2]) || (mesh->textureArray[0][ptOffset*2+1] < mesh->textureArray[mesh->textureArrays-1][ptOffset*2+1])) { /* Find height and width for team colours * and animations. * TODO: Check that the animations are legal * for the PIE format. */ unitH = 0; // Try to find width the easy way unitW = mesh->textureArray[1][ptOffset*2] - mesh->textureArray[0][ptOffset*2]; // Try to find height the easy way for (k = 0; k < mesh->textureArrays - 1; k++) { // Look for wrap around if (mesh->textureArray[k+1][ptOffset*2+1] > mesh->textureArray[k][ptOffset*2+1]) { unitH = mesh->textureArray[k+1][ptOffset*2+1] - mesh->textureArray[k][ptOffset*2+1]; break; } } // If the easy way failed if ( unitH <= 0) { // Find top and bottom, add pixels to the difference for good luck. b = 0; // Search for the bottom starting from the top t = 1; // Search for the top starting from the bottom // Try every V to find the min and max for (k = 0; k < VERTICES_PER_TRIANGLE; k++) { ptOffset = mesh->indexArray[j*VERTICES_PER_TRIANGLE+k]; if (mesh->textureArray[0][ptOffset*2+1] < t) { t = mesh->textureArray[0][ptOffset*2+1]; } if (mesh->textureArray[0][ptOffset*2+1] > b) { b = mesh->textureArray[0][ptOffset*2+1]; } } unitH = fabs(b - t); if (psModel->pixmap != NULL && psModel->pixmap->h != 0) { unitH += 2 / psModel->pixmap->h; } else if (pieVersion == 2) { unitH += 2 / OLD_TEXTURE_SIZE_FIX; } } /* If the animations wraps around for each frame * then the easy way of finding width would fail. */ if (unitW <= 0 && unitH ==0) { qWarning("QWzmViewer::savePIE - Texture animation appears to be illegal for PIE format."); file.close(); return -1; } else if ( unitW <=0) { unitW = 1; } switch (pieVersion) { // TODO: Get playback rate and replace the literal " 1 " with it. case 2: animTmpSs << mesh->textureArrays << " 1 " << (int)rintf(OLD_TEXTURE_SIZE_FIX*unitW) << ' ' << (int)rintf(OLD_TEXTURE_SIZE_FIX*unitH); break; case 3: animTmpSs << mesh->textureArrays << " 1 " << (GLfloat)unitW << ' ' << (GLfloat)unitH; break; } polyFlag |= iV_IMD_TEXANIM; } } // Write out the flag followed by the number of vertices file << "\t" << std::hex << polyFlag << std::dec << ' ' << VERTICES_PER_TRIANGLE; // Triangles only // Write the three polygon indices for (k = 0; k < VERTICES_PER_TRIANGLE; k++) { ptOffset = mesh->indexArray[j*VERTICES_PER_TRIANGLE+k]; pie_Point thisPoint(mesh->vertexArray[ptOffset*VERTICES_PER_TRIANGLE], mesh->vertexArray[ptOffset*VERTICES_PER_TRIANGLE+1], mesh->vertexArray[ptOffset*VERTICES_PER_TRIANGLE+2]); ptSetIndex = distance(ptSet.begin(), ptSet.find(thisPoint)); if (ptSetIndex == ptSet.size()) { file.close(); qWarning("QWzmViewer::savePIE - Internal error: Failed to find vertex in set."); return -1; } else { file << ' ' << ptSetIndex; // Store the texture coordinates for later textures.push(textCoords(mesh->textureArray[0][ptOffset*2], mesh->textureArray[0][ptOffset*2+1])); } } // If the polygon has team colours or animations, write that data now if (polyFlag & iV_IMD_TEXANIM) { file << ' ' << animTmpSs.str(); } // Write out all the texture coordinates while (!textures.empty()) { switch (pieVersion) { case 2: file << ' ' << (int)rintf(OLD_TEXTURE_SIZE_FIX*textures.front().u); file << ' ' << (int)rintf(OLD_TEXTURE_SIZE_FIX*textures.front().v); break; case 3: file << ' ' << textures.front().u << ' ' << textures.front().v; break; } textures.pop(); } file << '\n'; } // In PIE the CONNECTORS directive is optional if (mesh->connectors > 0) { // CONNECTORS directive file << "CONNECTORS " << mesh->connectors << "\n"; for (j = 0; j < mesh->connectors; j++) { switch (pieVersion) { case 2: file << "\t" << (int)rintf(mesh->connectorArray[j].pos.x) << ' ' << (int)rintf(mesh->connectorArray[j].pos.y) << ' ' << (int)rintf(mesh->connectorArray[j].pos.z) << '\n'; break; case 3: file << "\t" << mesh->connectorArray[j].pos.x << ' ' << mesh->connectorArray[j].pos.y << ' ' << mesh->connectorArray[j].pos.z << '\n'; break; } } } } if(file.bad()) { file.close(); return -1; } file.close(); return 0; }
void Circle3DOverlay::render(RenderArgs* args) { if (!_visible) { return; // do nothing if we're not visible } float alpha = getAlpha(); if (alpha == 0.0) { return; // do nothing if our alpha is 0, we're not visible } const float FULL_CIRCLE = 360.0f; const float SLICES = 180.0f; // The amount of segment to create the circle const float SLICE_ANGLE = FULL_CIRCLE / SLICES; //const int slices = 15; xColor color = getColor(); const float MAX_COLOR = 255.0f; glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); glDisable(GL_LIGHTING); glm::vec3 position = getPosition(); glm::vec3 center = getCenter(); glm::vec2 dimensions = getDimensions(); glm::quat rotation = getRotation(); float glowLevel = getGlowLevel(); Glower* glower = NULL; if (glowLevel > 0.0f) { glower = new Glower(glowLevel); } glPushMatrix(); glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glScalef(dimensions.x, dimensions.y, 1.0f); // Create the circle in the coordinates origin float outerRadius = getOuterRadius(); float innerRadius = getInnerRadius(); // only used in solid case float startAt = getStartAt(); float endAt = getEndAt(); glLineWidth(_lineWidth); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getIsSolid()) { glBegin(GL_QUAD_STRIP); float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(firstInnerPoint.x, firstInnerPoint.y); glVertex2f(firstOuterPoint.x, firstOuterPoint.y); while (angle < endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(thisOuterPoint.x, thisOuterPoint.y); glVertex2f(thisInnerPoint.x, thisInnerPoint.y); angle += SLICE_ANGLE; } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glVertex2f(lastInnerPoint.x, lastInnerPoint.y); glEnd(); } else { if (getIsDashedLine()) { glBegin(GL_LINES); } else { glBegin(GL_LINE_STRIP); } float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(firstPoint.x, firstPoint.y); while (angle < endAt) { angle += SLICE_ANGLE; angleInRadians = glm::radians(angle); glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(thisPoint.x, thisPoint.y); if (getIsDashedLine()) { angle += SLICE_ANGLE / 2.0f; // short gap angleInRadians = glm::radians(angle); glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(dashStartPoint.x, dashStartPoint.y); } } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glEnd(); } // draw our tick marks // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getHasTickMarks()) { glBegin(GL_LINES); // draw our major tick marks if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { xColor color = getMajorTickMarksColor(); glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); float tickMarkAngle = getMajorTickMarksAngle(); float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMajorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); glVertex2f(thisPointA.x, thisPointA.y); glVertex2f(thisPointB.x, thisPointB.y); angle += tickMarkAngle; } } // draw our minor tick marks if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { xColor color = getMinorTickMarksColor(); glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); float tickMarkAngle = getMinorTickMarksAngle(); float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMinorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); glVertex2f(thisPointA.x, thisPointA.y); glVertex2f(thisPointB.x, thisPointB.y); angle += tickMarkAngle; } } glEnd(); } glPopMatrix(); glPopMatrix(); if (glower) { delete glower; } }
void Circle3DOverlay::render(RenderArgs* args) { if (!_visible) { return; // do nothing if we're not visible } float alpha = getAlpha(); if (alpha == 0.0) { return; // do nothing if our alpha is 0, we're not visible } // Create the circle in the coordinates origin float outerRadius = getOuterRadius(); float innerRadius = getInnerRadius(); // only used in solid case float startAt = getStartAt(); float endAt = getEndAt(); bool geometryChanged = (startAt != _lastStartAt || endAt != _lastEndAt || innerRadius != _lastInnerRadius || outerRadius != _lastOuterRadius); const float FULL_CIRCLE = 360.0f; const float SLICES = 180.0f; // The amount of segment to create the circle const float SLICE_ANGLE = FULL_CIRCLE / SLICES; //const int slices = 15; xColor color = getColor(); const float MAX_COLOR = 255.0f; glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); glDisable(GL_LIGHTING); glm::vec3 position = getPosition(); glm::vec3 center = getCenter(); glm::vec2 dimensions = getDimensions(); glm::quat rotation = getRotation(); float glowLevel = getGlowLevel(); Glower* glower = NULL; if (glowLevel > 0.0f) { glower = new Glower(glowLevel); } glPushMatrix(); glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glScalef(dimensions.x, dimensions.y, 1.0f); glLineWidth(_lineWidth); auto geometryCache = DependencyManager::get<GeometryCache>(); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getIsSolid()) { if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { _quadVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> points; float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 firstOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << firstInnerPoint << firstOuterPoint; while (angle < endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 thisOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << thisOuterPoint << thisInnerPoint; angle += SLICE_ANGLE; } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastInnerPoint(cos(angleInRadians) * innerRadius, sin(angleInRadians) * innerRadius); glm::vec2 lastOuterPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << lastOuterPoint << lastInnerPoint; geometryCache->updateVertices(_quadVerticesID, points); } geometryCache->renderVertices(GL_QUAD_STRIP, _quadVerticesID); } else { if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { _lineVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> points; float angle = startAt; float angleInRadians = glm::radians(angle); glm::vec2 firstPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << firstPoint; while (angle < endAt) { angle += SLICE_ANGLE; angleInRadians = glm::radians(angle); glm::vec2 thisPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << thisPoint; if (getIsDashedLine()) { angle += SLICE_ANGLE / 2.0f; // short gap angleInRadians = glm::radians(angle); glm::vec2 dashStartPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << dashStartPoint; } } // get the last slice portion.... angle = endAt; angleInRadians = glm::radians(angle); glm::vec2 lastPoint(cos(angleInRadians) * outerRadius, sin(angleInRadians) * outerRadius); points << lastPoint; geometryCache->updateVertices(_lineVerticesID, points); } if (getIsDashedLine()) { geometryCache->renderVertices(GL_LINES, _lineVerticesID); } else { geometryCache->renderVertices(GL_LINE_STRIP, _lineVerticesID); } } // draw our tick marks // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... if (getHasTickMarks()) { if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _majorTicksVerticesID = geometryCache->allocateID(); } if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { _minorTicksVerticesID = geometryCache->allocateID(); } if (geometryChanged) { QVector<glm::vec2> majorPoints; QVector<glm::vec2> minorPoints; // draw our major tick marks if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { float tickMarkAngle = getMajorTickMarksAngle(); float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMajorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); majorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } // draw our minor tick marks if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { float tickMarkAngle = getMinorTickMarksAngle(); float angle = startAt - fmod(startAt, tickMarkAngle) + tickMarkAngle; float angleInRadians = glm::radians(angle); float tickMarkLength = getMinorTickMarksLength(); float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; float endRadius = startRadius + tickMarkLength; while (angle <= endAt) { angleInRadians = glm::radians(angle); glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); minorPoints << thisPointA << thisPointB; angle += tickMarkAngle; } } geometryCache->updateVertices(_majorTicksVerticesID, majorPoints); geometryCache->updateVertices(_minorTicksVerticesID, minorPoints); } xColor majorColor = getMajorTickMarksColor(); glColor4f(majorColor.red / MAX_COLOR, majorColor.green / MAX_COLOR, majorColor.blue / MAX_COLOR, alpha); geometryCache->renderVertices(GL_LINES, _majorTicksVerticesID); xColor minorColor = getMinorTickMarksColor(); glColor4f(minorColor.red / MAX_COLOR, minorColor.green / MAX_COLOR, minorColor.blue / MAX_COLOR, alpha); geometryCache->renderVertices(GL_LINES, _minorTicksVerticesID); } glPopMatrix(); glPopMatrix(); if (geometryChanged) { _lastStartAt = startAt; _lastEndAt = endAt; _lastInnerRadius = innerRadius; _lastOuterRadius = outerRadius; } if (glower) { delete glower; } }