Rect SkeletonRenderer::getBoundingBox () const { float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; float scaleX = getScaleX(), scaleY = getScaleY(); for (int i = 0; i < _skeleton->slotsCount; ++i) { spSlot* slot = _skeleton->slots[i]; if (!slot->attachment) continue; int verticesCount; if (slot->attachment->type == SP_ATTACHMENT_REGION) { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); verticesCount = 8; } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices); verticesCount = mesh->super.worldVerticesLength; } else continue; for (int ii = 0; ii < verticesCount; ii += 2) { float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; minX = min(minX, x); minY = min(minY, y); maxX = max(maxX, x); maxY = max(maxY, y); } } Vec2 position = getPosition(); if (minX == FLT_MAX) minX = minY = maxX = maxY = 0; return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY); }
QRectF SkeletonAnimationFbo::calculateSkeletonRect() { if (!isSkeletonValid()) return QRectF(); float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; for (int i = 0; i < mspSkeleton->slotsCount; ++i) { spSlot* slot = mspSkeleton->slots[i]; if (!slot->attachment) continue; int verticesCount; if (slot->attachment->type == SP_ATTACHMENT_REGION) { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, mWorldVertices); verticesCount = 8; } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; spMeshAttachment_computeWorldVertices(mesh, slot, mWorldVertices); verticesCount = mesh->verticesCount; } else if (slot->attachment->type == SP_ATTACHMENT_SKINNED_MESH) { spSkinnedMeshAttachment* mesh = (spSkinnedMeshAttachment*)slot->attachment; spSkinnedMeshAttachment_computeWorldVertices(mesh, slot, mWorldVertices); verticesCount = mesh->uvsCount; } else continue; for (int ii = 0; ii < verticesCount; ii += 2) { float x = mWorldVertices[ii], y = mWorldVertices[ii + 1]; minX = qMin(minX, x); minY = qMin(minY, y); maxX = qMax(maxX, x); maxY = qMax(maxY, y); } } QRectF rect(minX, minY, maxX - minX, maxY - minY); return rect; }
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { SkeletonBatch* batch = SkeletonBatch::getInstance(); Color3B nodeColor = getColor(); _skeleton->r = nodeColor.r / (float)255; _skeleton->g = nodeColor.g / (float)255; _skeleton->b = nodeColor.b / (float)255; _skeleton->a = getDisplayedOpacity() / (float)255; Color4F color; AttachmentVertices* attachmentVertices = nullptr; for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) { spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment) continue; switch (slot->attachment->type) { case SP_ATTACHMENT_REGION: { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); attachmentVertices = getAttachmentVertices(attachment); color.r = attachment->r; color.g = attachment->g; color.b = attachment->b; color.a = attachment->a; break; } case SP_ATTACHMENT_MESH: { spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices); attachmentVertices = getAttachmentVertices(attachment); color.r = attachment->r; color.g = attachment->g; color.b = attachment->b; color.a = attachment->a; break; } default: continue; } color.a *= _skeleton->a * slot->a * 255; float multiplier = _premultipliedAlpha ? color.a : 255; color.r *= _skeleton->r * slot->r * multiplier; color.g *= _skeleton->g * slot->g * multiplier; color.b *= _skeleton->b * slot->b * multiplier; for (int v = 0, w = 0, vn = attachmentVertices->_triangles->vertCount; v < vn; ++v, w += 2) { V3F_C4B_T2F* vertex = attachmentVertices->_triangles->verts + v; vertex->vertices.x = _worldVertices[w]; vertex->vertices.y = _worldVertices[w + 1]; vertex->colors.r = (GLubyte)color.r; vertex->colors.g = (GLubyte)color.g; vertex->colors.b = (GLubyte)color.b; vertex->colors.a = (GLubyte)color.a; } BlendFunc blendFunc; switch (slot->data->blendMode) { case SP_BLEND_MODE_ADDITIVE: blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; blendFunc.dst = GL_ONE; break; case SP_BLEND_MODE_MULTIPLY: blendFunc.src = GL_DST_COLOR; blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; break; case SP_BLEND_MODE_SCREEN: blendFunc.src = GL_ONE; blendFunc.dst = GL_ONE_MINUS_SRC_COLOR; break; default: blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; } batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, *attachmentVertices->_triangles, transform, transformFlags); } if (_debugSlots || _debugBones) { drawDebug(renderer, transform, transformFlags); } }
void SkeletonAnimationFbo::renderToCache(Renderer* renderer, RenderCmdsCache* cache) { if (!cache) return; cache->clear(); if (!renderer) return; SkeletonRenderer* skeletonRenderer = (SkeletonRenderer*)renderer; if (mShouldRelaseCacheTexture){ mShouldRelaseCacheTexture = false; skeletonRenderer->releaseTextures(); } const QRectF rect = calculateSkeletonRect(); if (!isSkeletonValid()) return; cache->setSkeletonRect(rect); cache->bindShader(RenderCmdsCache::ShaderTexture); int additive = -1; Color color; const float* uvs = 0; int verticesCount = 0; const int* triangles = 0; int trianglesCount = 0; float r = 0, g = 0, b = 0, a = 0; for (int i = 0, n = mspSkeleton->slotsCount; i < n; i++) { spSlot* slot = mspSkeleton->drawOrder[i]; if (!slot->attachment) continue; Texture *texture = 0; switch (slot->attachment->type) { case SP_ATTACHMENT_REGION: { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, mWorldVertices); texture = getTexture(attachment); uvs = attachment->uvs; verticesCount = 8; triangles = quadTriangles; trianglesCount = 6; r = attachment->r; g = attachment->g; b = attachment->b; a = attachment->a; break; } case SP_ATTACHMENT_MESH: { spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; spMeshAttachment_computeWorldVertices(attachment, slot, mWorldVertices); texture = getTexture(attachment); uvs = attachment->uvs; verticesCount = attachment->verticesCount; triangles = attachment->triangles; trianglesCount = attachment->trianglesCount; r = attachment->r; g = attachment->g; b = attachment->b; a = attachment->a; break; } case SP_ATTACHMENT_SKINNED_MESH: { spSkinnedMeshAttachment* attachment = (spSkinnedMeshAttachment*)slot->attachment; spSkinnedMeshAttachment_computeWorldVertices(attachment, slot, mWorldVertices); texture = getTexture(attachment); uvs = attachment->uvs; verticesCount = attachment->uvsCount; triangles = attachment->triangles; trianglesCount = attachment->trianglesCount; r = attachment->r; g = attachment->g; b = attachment->b; a = attachment->a; break; } default: break; }// END switch (slot->attachment->type) if (texture) { if (slot->data->additiveBlending != additive) { cache->cacheTriangleDrawCall(); cache->blendFunc(GL_ONE, slot->data->additiveBlending ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA); additive = slot->data->additiveBlending; } color.a = mspSkeleton->a * slot->a * a * 255; float multiplier = mPremultipliedAlapha ? color.a : 255; color.r = mspSkeleton->r * slot->r * r * multiplier; color.g = mspSkeleton->g * slot->g * g * multiplier; color.b = mspSkeleton->b * slot->b * b * multiplier; cache->drawTriangles(skeletonRenderer->getGLTexture(texture, window()), mWorldVertices, uvs, verticesCount, triangles, trianglesCount, color); }// END if (texture) }// END for (int i = 0, n = skeleton->slotsCount; i < n; i++) cache->cacheTriangleDrawCall(); if (mDebugSlots || mDebugBones) { cache->bindShader(RenderCmdsCache::ShaderColor); if (mDebugSlots) { // Slots. cache->drawColor(0, 0, 255, 255); cache->lineWidth(1); Point points[4]; for (int i = 0, n = mspSkeleton->slotsCount; i < n; i++) { spSlot* slot = mspSkeleton->drawOrder[i]; if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, mWorldVertices); points[0] = Point(mWorldVertices[0], mWorldVertices[1]); points[1] = Point(mWorldVertices[2], mWorldVertices[3]); points[2] = Point(mWorldVertices[4], mWorldVertices[5]); points[3] = Point(mWorldVertices[6], mWorldVertices[7]); cache->drawPoly(points, 4); } }// END if (mDebugSlots) if (mDebugBones) { // Bone lengths. cache->lineWidth(2); cache->drawColor(255, 0, 0, 255); for (int i = 0, n = mspSkeleton->bonesCount; i < n; i++) { spBone *bone = mspSkeleton->bones[i]; float x = bone->data->length * bone->m00 + bone->worldX; float y = bone->data->length * bone->m10 + bone->worldY; cache->drawLine(Point(bone->worldX, bone->worldY), Point(x, y)); } // Bone origins. cache->pointSize(4.0); cache->drawColor(0, 0, 255, 255); // Root bone is blue. for (int i = 0, n = mspSkeleton->bonesCount; i < n; i++) { spBone *bone = mspSkeleton->bones[i]; cache->drawPoint(Point(bone->worldX, bone->worldY)); if (i == 0) cache->drawColor(0, 255, 0, 255); } }// END if (mDebugBones) }//END if (mDebugSlots || mDebugBones) }