void SkyColor::getVertexColor(float th, float phi, float sunphi, vec4* color){ float x, y, Y; float cosTheta, cosGamma; float gm = angle(th, phi, suntheta, sunphi); float das = fabs(th - (pi / 2.0f)); if (fabs(th - (pi / 2.0f)) < 0.001f) cosTheta = 0.00001f; else cosTheta = cos(th); cosGamma = cos(gm); cosSTheta = cos(suntheta); x = xz * perezFunction_x(cosTheta, cosGamma, gm); y = yz * perezFunction_y(cosTheta, cosGamma, gm); Y = Yz * perezFunction_Y(cosTheta, cosGamma, gm); toRGBA(x, y, Y, color); // Include alpha transparency to fade out skydome on sunset to see the stars. // Comment these if fading needed is not needed. cosSTheta is the angle of the Sun from the Horizon. if (cosSTheta<=0.1) color->w = cosSTheta/0.1; if (cosSTheta < 0.04) // Dont let it get completely transparent color->w = 0.4; }
void DecodeBufferWorker::Execute () { CImg<unsigned char> * img = NULL; string err; char * metadata = NULL; err = _decoder(_buffer, _buffsize, &img, &metadata); if (img == NULL) { SetErrorMessage(err.c_str()); return; } _trans = img->spectrum() == 2 || img->spectrum() == 4; err = toRGBA(&img); if (err != "") { if (img) delete img; SetErrorMessage(err.c_str()); return; } img->_is_shared = true; // don't free image data. need it for callback. _pixbuf = img->data(); _width = img->width(); _height = img->height(); _channels = 4; _metadata = metadata; delete img; return; }
static void addLine(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, AnimDebugDrawData::Vertex*& v) { uint32_t colorInt = toRGBA(color); v->pos = start; v->rgba = colorInt; v++; v->pos = end; v->rgba = colorInt; v++; }
Subtitles::Subtitles() : current_id(-1) , visible(false) , background(NULL) , background_color(0,0,0,200) , visible_ticks(0) { FileParser infile; // @CLASS Subtitles|Description of soundfx/subtitles.txt if (infile.open("soundfx/subtitles.txt")) { while (infile.next()) { if (infile.new_section && infile.section == "subtitle") { filename.resize(filename.size()+1); text.resize(text.size()+1); } else if (infile.section == "style") { if (infile.key == "text_pos") { // @ATTR style.text_pos|label|Position and style of the subtitle text. text_pos = eatLabelInfo(infile.val); } else if (infile.key == "pos") { // @ATTR style.pos|point|Position of the subtitle text relative to alignment. label_pos = toPoint(infile.val); } else if (infile.key == "align") { // @ATTR style.align|alignment|Alignment of the subtitle text. label_alignment = parse_alignment(infile.val); } else if (infile.key == "background_color") { // @ATTR style.background_color|color, int : Color, Alpha|Color and alpha of the subtitle background rectangle. background_color = toRGBA(infile.val); } } if (filename.empty() || text.empty()) continue; if (infile.key == "id") { // @ATTR subtitle.id|filename|Filename of the sound file that will trigger this subtitle. std::locale loc; const std::collate<char>& coll = std::use_facet<std::collate<char> >(loc); const std::string realfilename = mods->locate(infile.val); unsigned long sid = coll.hash(realfilename.data(), realfilename.data()+realfilename.length()); filename.back() = sid; } else if (infile.key == "text") { // @ATTR subtitle.text|string|The subtitle text that will be displayed. text.back() = msg->get(infile.val); } } } assert(filename.size() == text.size()); }
void ParticleParameters::ApplyChanges() { math::vec2f pos(ui->PosXSpin->value(), ui->PosYSpin->value()); math::vec2f grav(ui->GravXSpin->value(), ui->GravYSpin->value()); double frequency = ui->FrequencySpin->value(); int numParticle = ui->NumPartSpin->value(); if (numParticle == -1 && frequency == 0) numParticle = 1; m_parameters.setAngle(ui->ApertureSpin->value() * DEG2RAD); m_parameters.setDirection(ui->DirectionSpin->value() * DEG2RAD); m_parameters.setPosition(pos); m_parameters.setGravity(grav); m_parameters.setFrequency(frequency); m_parameters.setParticleColor(toRGBA(StartColor), toRGBA(EndColor)); m_parameters.setParticleLive(ui->MinLiveSpin->value(), ui->MaxLiveSpin->value()); m_parameters.setParticleNumber(numParticle); m_parameters.setParticleSpeed(ui->MinSpeedSpin->value(), ui->MaxSpeedSpin->value()); m_parameters.setParticleSize(ui->StartSizeSpin->value(), ui->EndSizeSpin->value()); m_parameters.setParticleAccumulativeColor(ui->AccumColorCheckbox->isChecked()); m_parameters.setParticleMaterial(ui->MaterialLineEdit->text().toStdString()); }
void Map::loadHeader(FileParser &infile) { if (infile.key == "title") { // @ATTR title|string|Title of map this->title = msg->get(infile.val); } else if (infile.key == "width") { // @ATTR width|int|Width of map this->w = static_cast<unsigned short>(std::max(toInt(infile.val), 1)); } else if (infile.key == "height") { // @ATTR height|int|Height of map this->h = static_cast<unsigned short>(std::max(toInt(infile.val), 1)); } else if (infile.key == "tileset") { // @ATTR tileset|filename|Filename of a tileset definition to use for map this->tileset = infile.val; } else if (infile.key == "music") { // @ATTR music|filename|Filename of background music to use for map music_filename = infile.val; } else if (infile.key == "hero_pos") { // @ATTR hero_pos|point|The player will spawn in this location if no point was previously given. hero_pos.x = static_cast<float>(popFirstInt(infile.val)) + 0.5f; hero_pos.y = static_cast<float>(popFirstInt(infile.val)) + 0.5f; hero_pos_enabled = true; } else if (infile.key == "parallax_layers") { // @ATTR parallax_layers|filename|Filename of a parallax layers definition. parallax_filename = infile.val; } else if (infile.key == "background_color") { // @ATTR background_color|color, int : Color, alpha|Background color for the map. background_color = toRGBA(infile.val); } else if (infile.key == "tilewidth") { // @ATTR tilewidth|int|Inherited from Tiled map file. Unused by engine. } else if (infile.key == "tileheight") { // @ATTR tileheight|int|Inherited from Tiled map file. Unused by engine. } else if (infile.key == "orientation") { // this is only used by Tiled when importing Flare maps } else { infile.error("Map: '%s' is not a valid key.", infile.key.c_str()); } }
AnimDebugDraw::AnimDebugDraw() : _itemID(0) { auto state = std::make_shared<gpu::State>(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); auto vertShader = gpu::Shader::createVertex(std::string(animdebugdraw_vert)); auto fragShader = gpu::Shader::createPixel(std::string(animdebugdraw_frag)); auto program = gpu::Shader::createProgram(vertShader, fragShader); _pipeline = gpu::Pipeline::create(program, state); _animDebugDrawData = std::make_shared<AnimDebugDrawData>(); _animDebugDrawPayload = std::make_shared<AnimDebugDrawPayload>(_animDebugDrawData); _animDebugDrawData->_pipeline = _pipeline; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { _itemID = scene->allocateID(); render::PendingChanges pendingChanges; pendingChanges.resetItem(_itemID, _animDebugDrawPayload); scene->enqueuePendingChanges(pendingChanges); } // HACK: add red, green and blue axis at (1,1,1) _animDebugDrawData->_vertexBuffer->resize(sizeof(Vertex) * 6); Vertex* data = (Vertex*)_animDebugDrawData->_vertexBuffer->editData(); data[0].pos = glm::vec3(1.0, 1.0f, 1.0f); data[0].rgba = toRGBA(255, 0, 0, 255); data[1].pos = glm::vec3(2.0, 1.0f, 1.0f); data[1].rgba = toRGBA(255, 0, 0, 255); data[2].pos = glm::vec3(1.0, 1.0f, 1.0f); data[2].rgba = toRGBA(0, 255, 0, 255); data[3].pos = glm::vec3(1.0, 2.0f, 1.0f); data[3].rgba = toRGBA(0, 255, 0, 255); data[4].pos = glm::vec3(1.0, 1.0f, 1.0f); data[4].rgba = toRGBA(0, 0, 255, 255); data[5].pos = glm::vec3(1.0, 1.0f, 2.0f); data[5].rgba = toRGBA(0, 0, 255, 255); _animDebugDrawData->_indexBuffer->resize(sizeof(uint16_t) * 6); uint16_t* indices = (uint16_t*)_animDebugDrawData->_indexBuffer->editData(); for (int i = 0; i < 6; i++) { indices[i] = i; } }
AnimDebugDraw::AnimDebugDraw() : _itemID(0) { auto state = std::make_shared<gpu::State>(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); auto vertShader = animdebugdraw_vert::getShader(); auto fragShader = animdebugdraw_frag::getShader(); auto program = gpu::Shader::createProgram(vertShader, fragShader); _pipeline = gpu::Pipeline::create(program, state); _animDebugDrawData = std::make_shared<AnimDebugDrawData>(); _animDebugDrawPayload = std::make_shared<AnimDebugDrawPayload>(_animDebugDrawData); _animDebugDrawData->_pipeline = _pipeline; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { _itemID = scene->allocateID(); render::Transaction transaction; transaction.resetItem(_itemID, _animDebugDrawPayload); scene->enqueueTransaction(transaction); } // HACK: add red, green and blue axis at (1,1,1) _animDebugDrawData->_vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * 6); static std::vector<AnimDebugDrawData::Vertex> vertices({ AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(255, 0, 0, 255) }, AnimDebugDrawData::Vertex { glm::vec3(2.0, 1.0f, 1.0f), toRGBA(255, 0, 0, 255) }, AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(0, 255, 0, 255) }, AnimDebugDrawData::Vertex { glm::vec3(1.0, 2.0f, 1.0f), toRGBA(0, 255, 0, 255) }, AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(0, 0, 255, 255) }, AnimDebugDrawData::Vertex { glm::vec3(1.0, 1.0f, 2.0f), toRGBA(0, 0, 255, 255) }, }); static std::vector<uint16_t> indices({ 0, 1, 2, 3, 4, 5 }); _animDebugDrawData->_vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices); _animDebugDrawData->_indexBuffer->setSubData<uint16_t>(0, indices); }
RGBA toRGBA (DataType const& data) const { return toRGBA(data, gamma); }
bool operator==(const cocos2d::Color4F& a, const cocos2d::extension::HSV& b) { return (a == toRGBA(b)); }
void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; } // make a copy of each particle's details std::vector<ParticleDetails> particleDetails; particleDetails.reserve(getLivingParticleCount()); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { auto xcolor = _particleColors[i]; auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba)); } // sort particles back to front // NOTE: this is view frustum might be one frame out of date. auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); ::zSortAxis = frustum->getDirection(); qSort(particleDetails.begin(), particleDetails.end(), zSort); // allocate vertices _vertices.clear(); // build vertices from particle positions and radiuses glm::vec3 frustumPosition = frustum->getPosition(); for (auto&& particle : particleDetails) { glm::vec3 particleDirection = particle.position - frustumPosition; glm::vec3 right = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), particleDirection)); glm::vec3 up = glm::normalize(glm::cross(right, particleDirection)); glm::vec3 upOffset = up * particle.radius; glm::vec3 rightOffset = right * particle.radius; // generate corners of quad aligned to face the camera. _vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), particle.rgba); _vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), particle.rgba); _vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), particle.rgba); _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), particle.rgba); } render::PendingChanges pendingChanges; pendingChanges.updateItem<ParticlePayload>(_renderItemId, [this](ParticlePayload& payload) { // update vertex buffer auto vertexBuffer = payload.getVertexBuffer(); size_t numBytes = sizeof(Vertex) * _vertices.size(); if (numBytes == 0) { vertexBuffer->resize(0); auto indexBuffer = payload.getIndexBuffer(); indexBuffer->resize(0); return; } vertexBuffer->resize(numBytes); gpu::Byte* data = vertexBuffer->editData(); memcpy(data, &(_vertices[0]), numBytes); // FIXME, don't update index buffer if num particles has not changed. // update index buffer auto indexBuffer = payload.getIndexBuffer(); const size_t NUM_VERTS_PER_PARTICLE = 4; const size_t NUM_INDICES_PER_PARTICLE = 6; auto numQuads = (_vertices.size() / NUM_VERTS_PER_PARTICLE); numBytes = sizeof(uint16_t) * numQuads * NUM_INDICES_PER_PARTICLE; indexBuffer->resize(numBytes); data = indexBuffer->editData(); auto indexPtr = reinterpret_cast<uint16_t*>(data); for (size_t i = 0; i < numQuads; ++i) { indexPtr[i * NUM_INDICES_PER_PARTICLE + 0] = i * NUM_VERTS_PER_PARTICLE + 0; indexPtr[i * NUM_INDICES_PER_PARTICLE + 1] = i * NUM_VERTS_PER_PARTICLE + 1; indexPtr[i * NUM_INDICES_PER_PARTICLE + 2] = i * NUM_VERTS_PER_PARTICLE + 3; indexPtr[i * NUM_INDICES_PER_PARTICLE + 3] = i * NUM_VERTS_PER_PARTICLE + 1; indexPtr[i * NUM_INDICES_PER_PARTICLE + 4] = i * NUM_VERTS_PER_PARTICLE + 2; indexPtr[i * NUM_INDICES_PER_PARTICLE + 5] = i * NUM_VERTS_PER_PARTICLE + 3; } // update transform glm::quat rot = _transform.getRotation(); glm::vec3 pos = _transform.getTranslation(); Transform t; t.setRotation(rot); payload.setModelTransform(t); // transform _particleMinBound and _particleMaxBound corners into world coords glm::vec3 d = _particleMaxBound - _particleMinBound; const size_t NUM_BOX_CORNERS = 8; glm::vec3 corners[NUM_BOX_CORNERS] = { pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, d.z)), pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, d.z)), pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, d.z)), pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, d.z)) }; glm::vec3 min(FLT_MAX, FLT_MAX, FLT_MAX); glm::vec3 max = -min; for (size_t i = 0; i < NUM_BOX_CORNERS; i++) { min.x = std::min(min.x, corners[i].x); min.y = std::min(min.y, corners[i].y); min.z = std::min(min.z, corners[i].z); max.x = std::max(max.x, corners[i].x); max.y = std::max(max.y, corners[i].y); max.z = std::max(max.z, corners[i].z); } AABox bound(min, max - min); payload.setBound(bound); bool textured = _texture && _texture->isLoaded(); if (textured) { payload.setTexture(_texture->getGPUTexture()); payload.setPipeline(_texturedPipeline); } else { payload.setTexture(nullptr); payload.setPipeline(_untexturedPipeline); } }); _scene->enqueuePendingChanges(pendingChanges); }
bool Document::saveMOJ(QString fileName) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } QXmlStreamWriter writer; writer.setAutoFormatting(true); writer.setDevice(&file); writer.writeStartDocument("1.0", false); writer.writeStartElement("MrWriter"); QString version; version.append(QString::number(MAJOR_VERSION)).append(".").append(QString::number(MINOR_VERSION)).append(QString::number(PATCH_VERSION)); writer.writeAttribute(QXmlStreamAttribute("version", version)); QString docVersion = QString::number(DOC_VERSION); writer.writeAttribute(QXmlStreamAttribute("docversion", docVersion)); writer.writeStartElement("title"); writer.writeCharacters("MrWriter document - see http://unruhschuh.com/mrwriter/"); writer.writeEndElement(); for (int i = 0; i < pages.size(); ++i) { writer.writeStartElement("page"); writer.writeAttribute(QXmlStreamAttribute("width", QString::number(pages[i].width()))); writer.writeAttribute(QXmlStreamAttribute("height", QString::number(pages[i].height()))); writer.writeEmptyElement("background"); writer.writeAttribute(QXmlStreamAttribute("type", "solid")); writer.writeAttribute(QXmlStreamAttribute("color", toRGBA(pages[i].backgroundColor().name(QColor::HexArgb)))); writer.writeAttribute(QXmlStreamAttribute("style", "plain")); writer.writeStartElement("layer"); // for (int j = 0; j < pages[i].m_strokes.size(); ++j) for (auto strokes : pages[i].strokes()) { writer.writeStartElement("stroke"); writer.writeAttribute(QXmlStreamAttribute("tool", "pen")); writer.writeAttribute(QXmlStreamAttribute("color", toRGBA(strokes.color.name(QColor::HexArgb)))); QString patternString; if (strokes.pattern == MrDoc::solidLinePattern) { patternString = "solid"; } else if (strokes.pattern == MrDoc::dashLinePattern) { patternString = "dash"; } else if (strokes.pattern == MrDoc::dashDotLinePattern) { patternString = "dashdot"; } else if (strokes.pattern == MrDoc::dotLinePattern) { patternString = "dot"; } else { patternString = "solid"; } writer.writeAttribute(QXmlStreamAttribute("style", patternString)); qreal width = strokes.penWidth; writer.writeAttribute(QXmlStreamAttribute("width", QString::number(width))); QString pressures; for (int k = 0; k < strokes.pressures.length(); ++k) { pressures.append(QString::number(strokes.pressures[k])).append(" "); } writer.writeAttribute((QXmlStreamAttribute("pressures", pressures.trimmed()))); QString points; for (int k = 0; k < strokes.points.size(); ++k) { points.append(QString::number(strokes.points[k].x())); points.append(" "); points.append(QString::number(strokes.points[k].y())); points.append(" "); } writer.writeCharacters(points.trimmed()); writer.writeEndElement(); // closing "stroke" } writer.writeEndElement(); // closing "layer" writer.writeEndElement(); // closing "page" } writer.writeEndDocument(); QFileInfo fileInfo(file); file.close(); if (writer.hasError()) { return false; } else { setDocumentChanged(false); m_path = fileInfo.absolutePath(); m_docName = fileInfo.completeBaseName(); return true; } }
bool Document::saveXOJ(QString fileName) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { return false; } QXmlStreamWriter writer; writer.setAutoFormatting(true); writer.setDevice(&file); writer.writeStartDocument("1.0", false); writer.writeStartElement("xournal"); writer.writeAttribute(QXmlStreamAttribute("version", "0.4.8")); writer.writeStartElement("title"); writer.writeCharacters("Xournal document - see http://math.mit.edu/~auroux/software/xournal/"); writer.writeEndElement(); for (int i = 0; i < pages.size(); ++i) { writer.writeStartElement("page"); writer.writeAttribute(QXmlStreamAttribute("width", QString::number(pages[i].width()))); writer.writeAttribute(QXmlStreamAttribute("height", QString::number(pages[i].height()))); writer.writeEmptyElement("background"); writer.writeAttribute(QXmlStreamAttribute("type", "solid")); writer.writeAttribute(QXmlStreamAttribute("color", toRGBA(pages[i].backgroundColor().name(QColor::HexArgb)))); writer.writeAttribute(QXmlStreamAttribute("style", "plain")); writer.writeStartElement("layer"); // for (int j = 0; j < pages[i].m_strokes.size(); ++j) for (auto strokes : pages[i].strokes()) { writer.writeStartElement("stroke"); writer.writeAttribute(QXmlStreamAttribute("tool", "pen")); writer.writeAttribute(QXmlStreamAttribute("color", toRGBA(strokes.color.name(QColor::HexArgb)))); qreal width = strokes.penWidth; QString widthString; widthString.append(QString::number(width)); for (int k = 0; k < strokes.pressures.size() - 1; ++k) { qreal p0 = strokes.pressures[k]; qreal p1 = strokes.pressures[k + 1]; widthString.append(' '); widthString.append(QString::number(0.5 * (p0 + p1) * width)); } writer.writeAttribute(QXmlStreamAttribute("width", widthString)); for (int k = 0; k < strokes.points.size(); ++k) { writer.writeCharacters(QString::number(strokes.points[k].x())); writer.writeCharacters(" "); writer.writeCharacters(QString::number(strokes.points[k].y())); writer.writeCharacters(" "); } writer.writeEndElement(); // closing "stroke" } writer.writeEndElement(); // closing "layer" writer.writeEndElement(); // closing "page" } writer.writeEndDocument(); QFileInfo fileInfo(file); file.close(); if (writer.hasError()) { return false; } else { return true; } }
render::Transaction transaction; transaction.removeItem(_itemID); render::Item::clearID(_itemID); scene->enqueueTransaction(transaction); } } void AnimDebugDraw::addAbsolutePoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color) { _absolutePoses[key] = PosesInfo(skeleton, poses, rootPose, color); } void AnimDebugDraw::removeAbsolutePoses(const std::string& key) { _absolutePoses.erase(key); } static const uint32_t red = toRGBA(255, 0, 0, 255); static const uint32_t green = toRGBA(0, 255, 0, 255); static const uint32_t blue = toRGBA(0, 0, 255, 255); const int NUM_CIRCLE_SLICES = 24; static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius, glm::vec4& vecColor, AnimDebugDrawData::Vertex*& v) { const float XYZ_AXIS_LENGTH = radius * 4.0f; const uint32_t color = toRGBA(vecColor); AnimPose finalPose = rootPose * pose; glm::vec3 base = rootPose * pose.trans(); glm::vec3 xRing[NUM_CIRCLE_SLICES + 1]; // one extra for last index. glm::vec3 yRing[NUM_CIRCLE_SLICES + 1];
static uint32_t toRGBA(const glm::vec4& v) { return toRGBA(static_cast<uint8_t>(v.r * 255.0f), static_cast<uint8_t>(v.g * 255.0f), static_cast<uint8_t>(v.b * 255.0f), static_cast<uint8_t>(v.a * 255.0f)); }
static void addBone(const AnimPose& rootPose, const AnimPose& pose, float radius, glm::vec4& vecColor, AnimDebugDrawData::Vertex*& v) { const float XYZ_AXIS_LENGTH = radius * 4.0f; const uint32_t color = toRGBA(vecColor); AnimPose finalPose = rootPose * pose; glm::vec3 base = rootPose * pose.trans(); glm::vec3 xRing[NUM_CIRCLE_SLICES + 1]; // one extra for last index. glm::vec3 yRing[NUM_CIRCLE_SLICES + 1]; glm::vec3 zRing[NUM_CIRCLE_SLICES + 1]; const float dTheta = (2.0f * (float)M_PI) / NUM_CIRCLE_SLICES; for (int i = 0; i < NUM_CIRCLE_SLICES + 1; i++) { float rCosTheta = radius * cosf(dTheta * i); float rSinTheta = radius * sinf(dTheta * i); xRing[i] = finalPose * glm::vec3(0.0f, rCosTheta, rSinTheta); yRing[i] = finalPose * glm::vec3(rCosTheta, 0.0f, rSinTheta); zRing[i] = finalPose * glm::vec3(rCosTheta, rSinTheta, 0.0f); } // x-axis v->pos = base; v->rgba = red; v++; v->pos = finalPose * glm::vec3(XYZ_AXIS_LENGTH, 0.0f, 0.0f); v->rgba = red; v++; // x-ring for (int i = 0; i < NUM_CIRCLE_SLICES; i++) { v->pos = xRing[i]; v->rgba = color; v++; v->pos = xRing[i + 1]; v->rgba = color; v++; } // y-axis v->pos = base; v->rgba = green; v++; v->pos = finalPose * glm::vec3(0.0f, XYZ_AXIS_LENGTH, 0.0f); v->rgba = green; v++; // y-ring for (int i = 0; i < NUM_CIRCLE_SLICES; i++) { v->pos = yRing[i]; v->rgba = color; v++; v->pos = yRing[i + 1]; v->rgba = color; v++; } // z-axis v->pos = base; v->rgba = blue; v++; v->pos = finalPose * glm::vec3(0.0f, 0.0f, XYZ_AXIS_LENGTH); v->rgba = blue; v++; // z-ring for (int i = 0; i < NUM_CIRCLE_SLICES; i++) { v->pos = zRing[i]; v->rgba = color; v++; v->pos = zRing[i + 1]; v->rgba = color; v++; } }
static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPose& parentPose, float radius, const glm::vec4& colorVec, AnimDebugDrawData::Vertex*& v) { uint32_t color = toRGBA(colorVec); AnimPose pose0 = rootPose * parentPose; AnimPose pose1 = rootPose * pose; glm::vec3 boneAxisWorld = glm::normalize(pose1.trans() - pose0.trans()); glm::vec3 boneAxis0 = glm::normalize(pose0.inverse().xformVector(boneAxisWorld)); glm::vec3 boneAxis1 = glm::normalize(pose1.inverse().xformVector(boneAxisWorld)); glm::vec3 boneBase = pose0 * (boneAxis0 * radius); glm::vec3 boneTip = pose1 * (boneAxis1 * -radius); const int NUM_BASE_CORNERS = 4; // make sure there's room between the two bones to draw a nice bone link. if (glm::dot(boneTip - pose0.trans(), boneAxisWorld) > glm::dot(boneBase - pose0.trans(), boneAxisWorld)) { // there is room, so lets draw a nice bone glm::vec3 uAxis, vAxis, wAxis; generateBasisVectors(boneAxis0, glm::vec3(1.0f, 0.0f, 0.0f), uAxis, vAxis, wAxis); glm::vec3 boneBaseCorners[NUM_BASE_CORNERS]; boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius)); boneBaseCorners[1] = pose0 * ((uAxis * radius) - (vAxis * radius) + (wAxis * radius)); boneBaseCorners[2] = pose0 * ((uAxis * radius) - (vAxis * radius) - (wAxis * radius)); boneBaseCorners[3] = pose0 * ((uAxis * radius) + (vAxis * radius) - (wAxis * radius)); for (int i = 0; i < NUM_BASE_CORNERS; i++) { v->pos = boneBaseCorners[i]; v->rgba = color; v++; v->pos = boneBaseCorners[(i + 1) % NUM_BASE_CORNERS]; v->rgba = color; v++; } for (int i = 0; i < NUM_BASE_CORNERS; i++) { v->pos = boneBaseCorners[i]; v->rgba = color; v++; v->pos = boneTip; v->rgba = color; v++; } } else { // There's no room between the bones to draw the link. // just draw a line between the two bone centers. // We add the same line multiple times, so the vertex count is correct. for (int i = 0; i < NUM_BASE_CORNERS * 2; i++) { v->pos = pose0.trans(); v->rgba = color; v++; v->pos = pose1.trans(); v->rgba = color; v++; } } }