SkeletonRenderer.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #include <spine/spine-cocos2dx.h>
  30. #include <spine/extension.h>
  31. #include <spine/AttachmentVertices.h>
  32. #include <algorithm>
  33. USING_NS_CC;
  34. namespace spine {
  35. namespace {
  36. Cocos2dTextureLoader textureLoader;
  37. int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex);
  38. cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount);
  39. void interleaveCoordinates(float* dst, const float* src, int vertexCount, int dstStride);
  40. BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha);
  41. void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex);
  42. bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect);
  43. Color4B ColorToColor4B(const Color& color);
  44. bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex);
  45. }
  46. // C Variable length array
  47. #ifdef _MSC_VER
  48. // VLA not supported, use _malloca
  49. #define VLA(type, arr, count) \
  50. type* arr = static_cast<type*>( _malloca(sizeof(type) * count) )
  51. #define VLA_FREE(arr) do { _freea(arr); } while(false)
  52. #else
  53. #define VLA(type, arr, count) \
  54. type arr[count]
  55. #define VLA_FREE(arr)
  56. #endif
  57. SkeletonRenderer* SkeletonRenderer::createWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData) {
  58. SkeletonRenderer* node = new SkeletonRenderer(skeleton, ownsSkeleton, ownsSkeletonData);
  59. node->autorelease();
  60. return node;
  61. }
  62. SkeletonRenderer* SkeletonRenderer::createWithData (SkeletonData* skeletonData, bool ownsSkeletonData) {
  63. SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData);
  64. node->autorelease();
  65. return node;
  66. }
  67. SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
  68. SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale);
  69. node->autorelease();
  70. return node;
  71. }
  72. SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
  73. SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale);
  74. node->autorelease();
  75. return node;
  76. }
  77. void SkeletonRenderer::initialize () {
  78. _clipper = new (__FILE__, __LINE__) SkeletonClipping();
  79. _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
  80. setOpacityModifyRGB(true);
  81. setTwoColorTint(false);
  82. _skeleton->setToSetupPose();
  83. _skeleton->updateWorldTransform();
  84. }
  85. void SkeletonRenderer::setupGLProgramState (bool twoColorTintEnabled) {
  86. if (twoColorTintEnabled) {
  87. #if COCOS2D_VERSION < 0x00040000
  88. setGLProgramState(SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState());
  89. #endif
  90. return;
  91. }
  92. Texture2D *texture = nullptr;
  93. for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) {
  94. Slot* slot = _skeleton->getDrawOrder()[i];
  95. Attachment* const attachment = slot->getAttachment();
  96. if (!attachment) continue;
  97. if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
  98. RegionAttachment* regionAttachment = static_cast<RegionAttachment*>(attachment);
  99. texture = static_cast<AttachmentVertices*>(regionAttachment->getRendererObject())->_texture;
  100. } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
  101. MeshAttachment* meshAttachment = static_cast<MeshAttachment*>(attachment);
  102. texture = static_cast<AttachmentVertices*>(meshAttachment->getRendererObject())->_texture;
  103. }
  104. else {
  105. continue;
  106. }
  107. if (texture != nullptr) {
  108. break;
  109. }
  110. }
  111. #if COCOS2D_VERSION < 0x00040000
  112. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture));
  113. #endif
  114. }
  115. void SkeletonRenderer::setSkeletonData (SkeletonData *skeletonData, bool ownsSkeletonData) {
  116. _skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
  117. _ownsSkeletonData = ownsSkeletonData;
  118. }
  119. SkeletonRenderer::SkeletonRenderer ()
  120. : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits<int>::max()) {
  121. }
  122. SkeletonRenderer::SkeletonRenderer(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas)
  123. : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits<int>::max()) {
  124. initWithSkeleton(skeleton, ownsSkeleton, ownsSkeletonData, ownsAtlas);
  125. }
  126. SkeletonRenderer::SkeletonRenderer (SkeletonData *skeletonData, bool ownsSkeletonData)
  127. : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits<int>::max()) {
  128. initWithData(skeletonData, ownsSkeletonData);
  129. }
  130. SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, Atlas* atlas, float scale)
  131. : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits<int>::max()) {
  132. initWithJsonFile(skeletonDataFile, atlas, scale);
  133. }
  134. SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
  135. : _atlas(nullptr), _attachmentLoader(nullptr), _timeScale(1), _debugSlots(false), _debugBones(false), _debugMeshes(false), _debugBoundingRect(false), _effect(nullptr), _startSlotIndex(0), _endSlotIndex(std::numeric_limits<int>::max()) {
  136. initWithJsonFile(skeletonDataFile, atlasFile, scale);
  137. }
  138. SkeletonRenderer::~SkeletonRenderer () {
  139. if (_ownsSkeletonData && _skeleton) delete _skeleton->getData();
  140. if (_ownsSkeleton) delete _skeleton;
  141. if (_ownsAtlas && _atlas) delete _atlas;
  142. if (_attachmentLoader) delete _attachmentLoader;
  143. delete _clipper;
  144. }
  145. void SkeletonRenderer::initWithSkeleton(Skeleton* skeleton, bool ownsSkeleton, bool ownsSkeletonData, bool ownsAtlas) {
  146. _skeleton = skeleton;
  147. _ownsSkeleton = ownsSkeleton;
  148. _ownsSkeletonData = ownsSkeletonData;
  149. _ownsAtlas = ownsAtlas;
  150. initialize();
  151. }
  152. void SkeletonRenderer::initWithData (SkeletonData* skeletonData, bool ownsSkeletonData) {
  153. _ownsSkeleton = true;
  154. setSkeletonData(skeletonData, ownsSkeletonData);
  155. initialize();
  156. }
  157. void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
  158. _atlas = atlas;
  159. _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
  160. SkeletonJson json(_attachmentLoader);
  161. json.setScale(scale);
  162. SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str());
  163. CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data.");
  164. _ownsSkeleton = true;
  165. setSkeletonData(skeletonData, true);
  166. initialize();
  167. }
  168. void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
  169. _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true);
  170. CCASSERT(_atlas, "Error reading atlas file.");
  171. _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
  172. SkeletonJson json(_attachmentLoader);
  173. json.setScale(scale);
  174. SkeletonData* skeletonData = json.readSkeletonDataFile(skeletonDataFile.c_str());
  175. CCASSERT(skeletonData, !json.getError().isEmpty() ? json.getError().buffer() : "Error reading skeleton data.");
  176. _ownsSkeleton = true;
  177. _ownsAtlas = true;
  178. setSkeletonData(skeletonData, true);
  179. initialize();
  180. }
  181. void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, Atlas* atlas, float scale) {
  182. _atlas = atlas;
  183. _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
  184. SkeletonBinary binary(_attachmentLoader);
  185. binary.setScale(scale);
  186. SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str());
  187. CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data.");
  188. _ownsSkeleton = true;
  189. setSkeletonData(skeletonData, true);
  190. initialize();
  191. }
  192. void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
  193. _atlas = new (__FILE__, __LINE__) Atlas(atlasFile.c_str(), &textureLoader, true);
  194. CCASSERT(_atlas, "Error reading atlas file.");
  195. _attachmentLoader = new (__FILE__, __LINE__) Cocos2dAtlasAttachmentLoader(_atlas);
  196. SkeletonBinary binary(_attachmentLoader);
  197. binary.setScale(scale);
  198. SkeletonData* skeletonData = binary.readSkeletonDataFile(skeletonDataFile.c_str());
  199. CCASSERT(skeletonData, !binary.getError().isEmpty() ? binary.getError().buffer() : "Error reading skeleton data.");
  200. _ownsSkeleton = true;
  201. _ownsAtlas = true;
  202. setSkeletonData(skeletonData, true);
  203. initialize();
  204. }
  205. void SkeletonRenderer::update (float deltaTime) {
  206. Node::update(deltaTime);
  207. if (_ownsSkeleton) _skeleton->update(deltaTime * _timeScale);
  208. }
  209. void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
  210. // Early exit if the skeleton is invisible
  211. if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) {
  212. return;
  213. }
  214. const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex);
  215. if (coordCount == 0) {
  216. return;
  217. }
  218. assert(coordCount % 2 == 0);
  219. VLA(float, worldCoords, coordCount);
  220. transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex);
  221. #if CC_USE_CULLING
  222. const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2);
  223. if (cullRectangle(renderer, transform, bb)) {
  224. VLA_FREE(worldCoords);
  225. return;
  226. }
  227. #endif
  228. const float* worldCoordPtr = worldCoords;
  229. SkeletonBatch* batch = SkeletonBatch::getInstance();
  230. SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance();
  231. const bool hasSingleTint = (isTwoColorTint() == false);
  232. if (_effect) {
  233. _effect->begin(*_skeleton);
  234. }
  235. const Color3B displayedColor = getDisplayedColor();
  236. Color nodeColor;
  237. nodeColor.r = displayedColor.r / 255.f;
  238. nodeColor.g = displayedColor.g / 255.f;
  239. nodeColor.b = displayedColor.b / 255.f;
  240. nodeColor.a = getDisplayedOpacity() / 255.f;
  241. Color color;
  242. Color darkColor;
  243. const float darkPremultipliedAlpha = _premultipliedAlpha ? 1.f : 0;
  244. AttachmentVertices* attachmentVertices = nullptr;
  245. TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr;
  246. for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) {
  247. Slot* slot = _skeleton->getDrawOrder()[i];;
  248. if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) {
  249. _clipper->clipEnd(*slot);
  250. continue;
  251. }
  252. if (!slot->getAttachment()) {
  253. _clipper->clipEnd(*slot);
  254. continue;
  255. }
  256. // Early exit if slot is invisible
  257. if (slot->getColor().a == 0 || !slot->getBone().isActive()) {
  258. _clipper->clipEnd(*slot);
  259. continue;
  260. }
  261. cocos2d::TrianglesCommand::Triangles triangles;
  262. TwoColorTriangles trianglesTwoColor;
  263. if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) {
  264. RegionAttachment* attachment = static_cast<RegionAttachment*>(slot->getAttachment());
  265. attachmentVertices = static_cast<AttachmentVertices*>(attachment->getRendererObject());
  266. // Early exit if attachment is invisible
  267. if (attachment->getColor().a == 0) {
  268. _clipper->clipEnd(*slot);
  269. continue;
  270. }
  271. float* dstTriangleVertices = nullptr;
  272. int dstStride = 0; // in floats
  273. if (hasSingleTint) {
  274. triangles.indices = attachmentVertices->_triangles->indices;
  275. triangles.indexCount = attachmentVertices->_triangles->indexCount;
  276. triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
  277. triangles.vertCount = attachmentVertices->_triangles->vertCount;
  278. assert(triangles.vertCount == 4);
  279. memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
  280. dstStride = sizeof(V3F_C4B_T2F) / sizeof(float);
  281. dstTriangleVertices = reinterpret_cast<float*>(triangles.verts);
  282. } else {
  283. trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
  284. trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
  285. trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
  286. trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
  287. assert(trianglesTwoColor.vertCount == 4);
  288. for (int v = 0; v < trianglesTwoColor.vertCount; v++) {
  289. trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords;
  290. }
  291. dstTriangleVertices = reinterpret_cast<float*>(trianglesTwoColor.verts);
  292. dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float);
  293. }
  294. // Copy world vertices to triangle vertices
  295. interleaveCoordinates(dstTriangleVertices, worldCoordPtr, 4, dstStride);
  296. worldCoordPtr += 8;
  297. color = attachment->getColor();
  298. }
  299. else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) {
  300. MeshAttachment* attachment = (MeshAttachment*)slot->getAttachment();
  301. attachmentVertices = (AttachmentVertices*)attachment->getRendererObject();
  302. float* dstTriangleVertices = nullptr;
  303. int dstStride = 0; // in floats
  304. int dstVertexCount = 0;
  305. if (hasSingleTint) {
  306. triangles.indices = attachmentVertices->_triangles->indices;
  307. triangles.indexCount = attachmentVertices->_triangles->indexCount;
  308. triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
  309. triangles.vertCount = attachmentVertices->_triangles->vertCount;
  310. memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
  311. dstTriangleVertices = (float*)triangles.verts;
  312. dstStride = sizeof(V3F_C4B_T2F) / sizeof(float);
  313. dstVertexCount = triangles.vertCount;
  314. } else {
  315. trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
  316. trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
  317. trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
  318. trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
  319. for (int v = 0; v < trianglesTwoColor.vertCount; v++) {
  320. trianglesTwoColor.verts[v].texCoords = attachmentVertices->_triangles->verts[v].texCoords;
  321. }
  322. dstTriangleVertices = (float*)trianglesTwoColor.verts;
  323. dstStride = sizeof(V3F_C4B_C4B_T2F) / sizeof(float);
  324. dstVertexCount = trianglesTwoColor.vertCount;
  325. }
  326. // Copy world vertices to triangle vertices
  327. //assert(dstVertexCount * 2 == attachment->super.worldVerticesLength);
  328. interleaveCoordinates(dstTriangleVertices, worldCoordPtr, dstVertexCount, dstStride);
  329. worldCoordPtr += dstVertexCount * 2;
  330. color = attachment->getColor();
  331. }
  332. else if (slot->getAttachment()->getRTTI().isExactly(ClippingAttachment::rtti)) {
  333. ClippingAttachment* clip = (ClippingAttachment*)slot->getAttachment();
  334. _clipper->clipStart(*slot, clip);
  335. continue;
  336. } else {
  337. _clipper->clipEnd(*slot);
  338. continue;
  339. }
  340. if (slot->hasDarkColor()) {
  341. darkColor = slot->getDarkColor();
  342. } else {
  343. darkColor.r = 0;
  344. darkColor.g = 0;
  345. darkColor.b = 0;
  346. }
  347. darkColor.a = darkPremultipliedAlpha;
  348. color.a *= nodeColor.a * _skeleton->getColor().a * slot->getColor().a;
  349. // skip rendering if the color of this attachment is 0
  350. if (color.a == 0){
  351. _clipper->clipEnd(*slot);
  352. continue;
  353. }
  354. color.r *= nodeColor.r * _skeleton->getColor().r * slot->getColor().r;
  355. color.g *= nodeColor.g * _skeleton->getColor().g * slot->getColor().g;
  356. color.b *= nodeColor.b * _skeleton->getColor().b * slot->getColor().b;
  357. if (_premultipliedAlpha)
  358. {
  359. color.r *= color.a;
  360. color.g *= color.a;
  361. color.b *= color.a;
  362. }
  363. const cocos2d::Color4B color4B = ColorToColor4B(color);
  364. const cocos2d::Color4B darkColor4B = ColorToColor4B(darkColor);
  365. const BlendFunc blendFunc = makeBlendFunc(slot->getData().getBlendMode(), attachmentVertices->_texture->hasPremultipliedAlpha());
  366. _blendFunc = blendFunc;
  367. if (hasSingleTint) {
  368. if (_clipper->isClipping()) {
  369. _clipper->clipTriangles((float*)&triangles.verts[0].vertices, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, sizeof(cocos2d::V3F_C4B_T2F) / 4);
  370. batch->deallocateVertices(triangles.vertCount);
  371. if (_clipper->getClippedTriangles().size() == 0){
  372. _clipper->clipEnd(*slot);
  373. continue;
  374. }
  375. triangles.vertCount = _clipper->getClippedVertices().size() / 2;
  376. triangles.verts = batch->allocateVertices(triangles.vertCount);
  377. triangles.indexCount = _clipper->getClippedTriangles().size();
  378. triangles.indices =
  379. batch->allocateIndices(triangles.indexCount);
  380. memcpy(triangles.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size());
  381. #if COCOS2D_VERSION < 0x00040000
  382. cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
  383. #else
  384. cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags);
  385. #endif
  386. const float* verts = _clipper->getClippedVertices().buffer();
  387. const float* uvs = _clipper->getClippedUVs().buffer();
  388. if (_effect) {
  389. V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  390. Color darkTmp;
  391. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) {
  392. Color lightCopy = color;
  393. vertex->vertices.x = verts[vv];
  394. vertex->vertices.y = verts[vv + 1];
  395. vertex->texCoords.u = uvs[vv];
  396. vertex->texCoords.v = uvs[vv + 1];
  397. _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp);
  398. vertex->colors = ColorToColor4B(lightCopy);
  399. }
  400. } else {
  401. V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  402. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2, ++vertex) {
  403. vertex->vertices.x = verts[vv];
  404. vertex->vertices.y = verts[vv + 1];
  405. vertex->texCoords.u = uvs[vv];
  406. vertex->texCoords.v = uvs[vv + 1];
  407. vertex->colors = color4B;
  408. }
  409. }
  410. } else {
  411. // Not clipping
  412. #if COCOS2D_VERSION < 0x00040000
  413. cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
  414. #else
  415. cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, triangles, transform, transformFlags);
  416. #endif
  417. if (_effect) {
  418. V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  419. Color darkTmp;
  420. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
  421. Color lightCopy = color;
  422. _effect->transform(vertex->vertices.x, vertex->vertices.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkTmp);
  423. vertex->colors = ColorToColor4B(lightCopy);
  424. }
  425. } else {
  426. V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  427. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
  428. vertex->colors = color4B;
  429. }
  430. }
  431. }
  432. } else {
  433. // Two tints
  434. if (_clipper->isClipping()) {
  435. _clipper->clipTriangles((float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, sizeof(V3F_C4B_C4B_T2F) / 4);
  436. twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount);
  437. if (_clipper->getClippedTriangles().size() == 0){
  438. _clipper->clipEnd(*slot);
  439. continue;
  440. }
  441. trianglesTwoColor.vertCount = _clipper->getClippedVertices().size() / 2;
  442. trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount);
  443. trianglesTwoColor.indexCount = _clipper->getClippedTriangles().size();
  444. trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount);
  445. memcpy(trianglesTwoColor.indices, _clipper->getClippedTriangles().buffer(), sizeof(unsigned short) * _clipper->getClippedTriangles().size());
  446. #if COCOS2D_VERSION < 0x00040000
  447. TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
  448. #else
  449. TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags);
  450. #endif
  451. const float* verts = _clipper->getClippedVertices().buffer();
  452. const float* uvs = _clipper->getClippedUVs().buffer();
  453. if (_effect) {
  454. V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  455. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) {
  456. Color lightCopy = color;
  457. Color darkCopy = darkColor;
  458. vertex->position.x = verts[vv];
  459. vertex->position.y = verts[vv + 1];
  460. vertex->texCoords.u = uvs[vv];
  461. vertex->texCoords.v = uvs[vv + 1];
  462. _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
  463. vertex->color = ColorToColor4B(lightCopy);
  464. vertex->color2 = ColorToColor4B(darkCopy);
  465. }
  466. } else {
  467. V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  468. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2, ++vertex) {
  469. vertex->position.x = verts[vv];
  470. vertex->position.y = verts[vv + 1];
  471. vertex->texCoords.u = uvs[vv];
  472. vertex->texCoords.v = uvs[vv + 1];
  473. vertex->color = color4B;
  474. vertex->color2 = darkColor4B;
  475. }
  476. }
  477. } else {
  478. #if COCOS2D_VERSION < 0x00040000
  479. TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
  480. #else
  481. TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, blendFunc, trianglesTwoColor, transform, transformFlags);
  482. #endif
  483. if (_effect) {
  484. V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  485. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
  486. Color lightCopy = color;
  487. Color darkCopy = darkColor;
  488. _effect->transform(vertex->position.x, vertex->position.y, vertex->texCoords.u, vertex->texCoords.v, lightCopy, darkCopy);
  489. vertex->color = ColorToColor4B(lightCopy);
  490. vertex->color2 = ColorToColor4B(darkCopy);
  491. }
  492. } else {
  493. V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts;
  494. for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v, ++vertex) {
  495. vertex->color = color4B;
  496. vertex->color2 = darkColor4B;
  497. }
  498. }
  499. }
  500. }
  501. _clipper->clipEnd(*slot);
  502. }
  503. _clipper->clipEnd();
  504. if (lastTwoColorTrianglesCommand) {
  505. Node* parent = this->getParent();
  506. // We need to decide if we can postpone flushing the current
  507. // batch. We can postpone if the next sibling node is a
  508. // two color tinted skeleton with the same global-z.
  509. // The parent->getChildrenCount() > 100 check is a hack
  510. // as checking for a sibling is an O(n) operation, and if
  511. // all children of this nodes parent are skeletons, we
  512. // are in O(n2) territory.
  513. if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) {
  514. lastTwoColorTrianglesCommand->setForceFlush(true);
  515. } else {
  516. const cocos2d::Vector<Node*>& children = parent->getChildren();
  517. Node* sibling = nullptr;
  518. for (ssize_t i = 0; i < children.size(); i++) {
  519. if (children.at(i) == this) {
  520. if (i < children.size() - 1) {
  521. sibling = children.at(i+1);
  522. break;
  523. }
  524. }
  525. }
  526. if (!sibling) {
  527. lastTwoColorTrianglesCommand->setForceFlush(true);
  528. } else {
  529. SkeletonRenderer* siblingSkeleton = dynamic_cast<SkeletonRenderer*>(sibling);
  530. if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer
  531. !siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted
  532. !siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible
  533. (siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs
  534. lastTwoColorTrianglesCommand->setForceFlush(true);
  535. }
  536. }
  537. }
  538. }
  539. if (_effect) _effect->end();
  540. for (SlotNodeIter iter=m_slotNodes.begin(), end=m_slotNodes.end(); iter!=end; ++iter) {
  541. sSlotNode& slot_node = iter->second;
  542. Slot* slot = slot_node.slot;
  543. Node* node = slot_node.node;
  544. Bone bone = slot->getBone();
  545. if(bone.isAppliedValid()){
  546. node->setPosition(Vec2(bone.getWorldX(), bone.getWorldY()));
  547. float scaleX = bone.getWorldScaleX();
  548. float scaleY = bone.getWorldScaleY();
  549. node->setScaleX(scaleX);
  550. node->setScaleY(scaleY);
  551. }
  552. node->setOpacity(255*slot->getColor().a);
  553. node->setColor(Color3B(255*slot->getColor().r, 255*slot->getColor().g, 255*slot->getColor().b));
  554. }
  555. if (_debugBoundingRect || _debugSlots || _debugBones || _debugMeshes) {
  556. drawDebug(renderer, transform, transformFlags);
  557. }
  558. VLA_FREE(worldCoords);
  559. }
  560. void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) {
  561. #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY)
  562. Director* director = Director::getInstance();
  563. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  564. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
  565. #endif
  566. DrawNode* drawNode = DrawNode::create();
  567. // Draw bounding rectangle
  568. if (_debugBoundingRect) {
  569. #if COCOS2D_VERSION < 0x00040000
  570. glLineWidth(2);
  571. #else
  572. drawNode->setLineWidth(2.0f);
  573. #endif
  574. const cocos2d::Rect brect = getBoundingBox();
  575. const Vec2 points[4] =
  576. {
  577. brect.origin,
  578. { brect.origin.x + brect.size.width, brect.origin.y },
  579. { brect.origin.x + brect.size.width, brect.origin.y + brect.size.height },
  580. { brect.origin.x, brect.origin.y + brect.size.height }
  581. };
  582. drawNode->drawPoly(points, 4, true, Color4F::GREEN);
  583. }
  584. if (_debugSlots) {
  585. // Slots.
  586. // DrawPrimitives::setDrawColor4B(0, 0, 255, 255);
  587. #if COCOS2D_VERSION < 0x00040000
  588. glLineWidth(2);
  589. #else
  590. drawNode->setLineWidth(2.0f);
  591. #endif
  592. V3F_C4B_T2F_Quad quad;
  593. for (int i = 0, n = _skeleton->getSlots().size(); i < n; i++) {
  594. Slot* slot = _skeleton->getDrawOrder()[i];
  595. if (!slot->getBone().isActive()) continue;
  596. if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) continue;
  597. if (slotIsOutRange(*slot, _startSlotIndex, _endSlotIndex)) {
  598. continue;
  599. }
  600. RegionAttachment* attachment = (RegionAttachment*)slot->getAttachment();
  601. float worldVertices[8];
  602. attachment->computeWorldVertices(slot->getBone(), worldVertices, 0, 2);
  603. const Vec2 points[4] =
  604. {
  605. { worldVertices[0], worldVertices[1] },
  606. { worldVertices[2], worldVertices[3] },
  607. { worldVertices[4], worldVertices[5] },
  608. { worldVertices[6], worldVertices[7] }
  609. };
  610. drawNode->drawPoly(points, 4, true, Color4F::BLUE);
  611. }
  612. }
  613. if (_debugBones) {
  614. // Bone lengths.
  615. #if COCOS2D_VERSION < 0x00040000
  616. glLineWidth(2);
  617. #else
  618. drawNode->setLineWidth(2.0f);
  619. #endif
  620. for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) {
  621. Bone *bone = _skeleton->getBones()[i];
  622. if (!bone->isActive()) continue;
  623. float x = bone->getData().getLength() * bone->getA() + bone->getWorldX();
  624. float y = bone->getData().getLength() * bone->getC() + bone->getWorldY();
  625. drawNode->drawLine(Vec2(bone->getWorldX(), bone->getWorldY()), Vec2(x, y), Color4F::RED);
  626. }
  627. // Bone origins.
  628. auto color = Color4F::BLUE; // Root bone is blue.
  629. for (int i = 0, n = _skeleton->getBones().size(); i < n; i++) {
  630. Bone *bone = _skeleton->getBones()[i];
  631. if (!bone->isActive()) continue;
  632. drawNode->drawPoint(Vec2(bone->getWorldX(), bone->getWorldY()), 4, color);
  633. if (i == 0) color = Color4F::GREEN;
  634. }
  635. }
  636. if (_debugMeshes) {
  637. // Meshes.
  638. #if COCOS2D_VERSION < 0x00040000
  639. glLineWidth(2);
  640. #else
  641. drawNode->setLineWidth(2.0f);
  642. #endif
  643. for (int i = 0, n = _skeleton->getSlots().size(); i < n; ++i) {
  644. Slot* slot = _skeleton->getDrawOrder()[i];
  645. if (!slot->getBone().isActive()) continue;
  646. if (!slot->getAttachment() || !slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) continue;
  647. MeshAttachment* const mesh = static_cast<MeshAttachment*>(slot->getAttachment());
  648. VLA(float, worldCoord, mesh->getWorldVerticesLength());
  649. mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), worldCoord, 0, 2);
  650. for (size_t t = 0; t < mesh->getTriangles().size(); t += 3) {
  651. // Fetch triangle indices
  652. const int idx0 = mesh->getTriangles()[t + 0];
  653. const int idx1 = mesh->getTriangles()[t + 1];
  654. const int idx2 = mesh->getTriangles()[t + 2];
  655. const Vec2 v[3] =
  656. {
  657. worldCoord + (idx0 * 2),
  658. worldCoord + (idx1 * 2),
  659. worldCoord + (idx2 * 2)
  660. };
  661. drawNode->drawPoly(v, 3, true, Color4F::YELLOW);
  662. }
  663. VLA_FREE(worldCoord);
  664. }
  665. }
  666. drawNode->draw(renderer, transform, transformFlags);
  667. #if !defined(USE_MATRIX_STACK_PROJECTION_ONLY)
  668. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  669. #endif
  670. }
  671. cocos2d::Rect SkeletonRenderer::getBoundingBox () const {
  672. const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex);
  673. if (coordCount == 0) return { 0, 0, 0, 0 };
  674. VLA(float, worldCoords, coordCount);
  675. transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex);
  676. const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2);
  677. VLA_FREE(worldCoords);
  678. return bb;
  679. }
  680. // --- Convenience methods for Skeleton_* functions.
  681. void SkeletonRenderer::updateWorldTransform() {
  682. _skeleton->updateWorldTransform();
  683. }
  684. void SkeletonRenderer::setToSetupPose () {
  685. _skeleton->setToSetupPose();
  686. }
  687. void SkeletonRenderer::setBonesToSetupPose () {
  688. _skeleton->setBonesToSetupPose();
  689. }
  690. void SkeletonRenderer::setSlotsToSetupPose () {
  691. _skeleton->setSlotsToSetupPose();
  692. }
  693. Bone* SkeletonRenderer::findBone (const std::string& boneName) const {
  694. return _skeleton->findBone(boneName.c_str());
  695. }
  696. Slot* SkeletonRenderer::findSlot (const std::string& slotName) const {
  697. return _skeleton->findSlot( slotName.c_str());
  698. }
  699. void SkeletonRenderer::setSkin (const std::string& skinName) {
  700. _skeleton->setSkin(skinName.empty() ? 0 : skinName.c_str());
  701. }
  702. void SkeletonRenderer::setSkin (const char* skinName) {
  703. _skeleton->setSkin(skinName);
  704. }
  705. Attachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const {
  706. return _skeleton->getAttachment(slotName.c_str(), attachmentName.c_str());
  707. }
  708. bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) {
  709. bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false;
  710. _skeleton->setAttachment(slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str());
  711. return result;
  712. }
  713. bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) {
  714. bool result = _skeleton->getAttachment(slotName.c_str(), attachmentName) ? true : false;
  715. _skeleton->setAttachment(slotName.c_str(), attachmentName);
  716. return result;
  717. }
  718. void SkeletonRenderer::setTwoColorTint(bool enabled) {
  719. #if COCOS2D_VERSION >= 0x00040000
  720. _twoColorTint = enabled;
  721. #endif
  722. setupGLProgramState(enabled);
  723. }
  724. bool SkeletonRenderer::isTwoColorTint() {
  725. #if COCOS2D_VERSION < 0x00040000
  726. return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState();
  727. #else
  728. return _twoColorTint;
  729. #endif
  730. }
  731. void SkeletonRenderer::setVertexEffect(VertexEffect *effect) {
  732. this->_effect = effect;
  733. }
  734. void SkeletonRenderer::setSlotsRange(int startSlotIndex, int endSlotIndex) {
  735. _startSlotIndex = startSlotIndex == -1 ? 0 : startSlotIndex;
  736. _endSlotIndex = endSlotIndex == -1 ? std::numeric_limits<int>::max() : endSlotIndex;
  737. }
  738. Skeleton* SkeletonRenderer::getSkeleton () const {
  739. return _skeleton;
  740. }
  741. void SkeletonRenderer::setTimeScale (float scale) {
  742. _timeScale = scale;
  743. }
  744. float SkeletonRenderer::getTimeScale () const {
  745. return _timeScale;
  746. }
  747. void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) {
  748. _debugSlots = enabled;
  749. }
  750. bool SkeletonRenderer::getDebugSlotsEnabled () const {
  751. return _debugSlots;
  752. }
  753. void SkeletonRenderer::setDebugBonesEnabled (bool enabled) {
  754. _debugBones = enabled;
  755. }
  756. bool SkeletonRenderer::getDebugBonesEnabled () const {
  757. return _debugBones;
  758. }
  759. void SkeletonRenderer::setDebugMeshesEnabled (bool enabled) {
  760. _debugMeshes = enabled;
  761. }
  762. bool SkeletonRenderer::getDebugMeshesEnabled () const {
  763. return _debugMeshes;
  764. }
  765. void SkeletonRenderer::setDebugBoundingRectEnabled(bool enabled) {
  766. _debugBoundingRect = enabled;
  767. }
  768. bool SkeletonRenderer::getDebugBoundingRectEnabled() const {
  769. return _debugBoundingRect;
  770. }
  771. void SkeletonRenderer::onEnter () {
  772. #if CC_ENABLE_SCRIPT_BINDING
  773. if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return;
  774. #endif
  775. Node::onEnter();
  776. scheduleUpdate();
  777. }
  778. void SkeletonRenderer::onExit () {
  779. #if CC_ENABLE_SCRIPT_BINDING
  780. if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return;
  781. #endif
  782. Node::onExit();
  783. unscheduleUpdate();
  784. }
  785. // --- CCBlendProtocol
  786. const BlendFunc& SkeletonRenderer::getBlendFunc () const {
  787. return _blendFunc;
  788. }
  789. void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) {
  790. _blendFunc = blendFunc;
  791. }
  792. void SkeletonRenderer::setOpacityModifyRGB (bool value) {
  793. _premultipliedAlpha = value;
  794. }
  795. bool SkeletonRenderer::isOpacityModifyRGB () const {
  796. return _premultipliedAlpha;
  797. }
  798. cocos2d::Node* SkeletonRenderer::getNodeForSlot(std::string slotName){
  799. SlotNodeIter iter = m_slotNodes.find(slotName);
  800. if (iter!=m_slotNodes.end()) {
  801. sSlotNode& slot_node = iter->second;
  802. return slot_node.node;
  803. }
  804. else{
  805. Slot* slot = findSlot(slotName);
  806. if(slot!=NULL){
  807. Node* node = new Node();
  808. if(node->init()){
  809. node->autorelease();
  810. }
  811. Bone bone = slot->getBone();
  812. if(bone.isAppliedValid()){
  813. node->setPosition(Vec2(bone.getWorldX(), bone.getWorldY()));
  814. float scaleX = bone.getWorldScaleX();
  815. float scaleY = bone.getWorldScaleY();
  816. node->setScaleX(scaleX);
  817. node->setScaleY(scaleY);
  818. }
  819. node->setCascadeOpacityEnabled(true);
  820. node->setOpacity(255*slot->getColor().a);
  821. node->setColor(Color3B(255*slot->getColor().r, 255*slot->getColor().g, 255*slot->getColor().b));
  822. this->addChild(node);
  823. sSlotNode slot_node;
  824. slot_node.slot = slot;
  825. slot_node.node = node;
  826. m_slotNodes.insert(SlotNodeMap::value_type(slotName,slot_node));
  827. return node;
  828. }
  829. else{
  830. return NULL;
  831. }
  832. }
  833. }
  834. namespace {
  835. cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) {
  836. assert(coords);
  837. assert(vertexCount > 0);
  838. const float* v = coords;
  839. float minX = v[0];
  840. float minY = v[1];
  841. float maxX = minX;
  842. float maxY = minY;
  843. for (int i = 1; i < vertexCount; ++i) {
  844. v += 2;
  845. float x = v[0];
  846. float y = v[1];
  847. minX = std::min(minX, x);
  848. minY = std::min(minY, y);
  849. maxX = std::max(maxX, x);
  850. maxY = std::max(maxY, y);
  851. }
  852. return { minX, minY, maxX - minX, maxY - minY };
  853. }
  854. bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) {
  855. const int index = slot.getData().getIndex();
  856. return startSlotIndex > index || endSlotIndex < index;
  857. }
  858. int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
  859. int coordCount = 0;
  860. for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
  861. Slot& slot = *skeleton.getSlots()[i];
  862. Attachment* const attachment = slot.getAttachment();
  863. if (!attachment) {
  864. continue;
  865. }
  866. if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
  867. continue;
  868. }
  869. // Early exit if slot is invisible
  870. if (slot.getColor().a == 0) {
  871. continue;
  872. }
  873. if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
  874. coordCount += 8;
  875. }
  876. else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
  877. MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment);
  878. coordCount += mesh->getWorldVerticesLength();
  879. }
  880. }
  881. return coordCount;
  882. }
  883. void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
  884. float* dstPtr = dstCoord;
  885. #ifndef NDEBUG
  886. float* const dstEnd = dstCoord + coordCount;
  887. #endif
  888. for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
  889. /*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw
  890. Attachment* const attachment = slot.getAttachment();
  891. if (!attachment) {
  892. continue;
  893. }
  894. if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
  895. continue;
  896. }
  897. if (slot.getColor().a == 0) {
  898. continue;
  899. }
  900. if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
  901. RegionAttachment* const regionAttachment = static_cast<RegionAttachment*>(attachment);
  902. assert(dstPtr + 8 <= dstEnd);
  903. regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2);
  904. dstPtr += 8;
  905. } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
  906. MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment);
  907. assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd);
  908. mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2);
  909. dstPtr += mesh->getWorldVerticesLength();
  910. }
  911. }
  912. assert(dstPtr == dstEnd);
  913. }
  914. void interleaveCoordinates(float* dst, const float* src, int count, int dstStride) {
  915. if (dstStride == 2) {
  916. memcpy(dst, src, sizeof(float) * count * 2);
  917. } else {
  918. for (int i = 0; i < count; ++i) {
  919. dst[0] = src[0];
  920. dst[1] = src[1];
  921. dst += dstStride;
  922. src += 2;
  923. }
  924. }
  925. }
  926. BlendFunc makeBlendFunc(BlendMode blendMode, bool premultipliedAlpha) {
  927. BlendFunc blendFunc;
  928. #if COCOS2D_VERSION < 0x00040000
  929. switch (blendMode) {
  930. case BlendMode_Additive:
  931. blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
  932. blendFunc.dst = GL_ONE;
  933. break;
  934. case BlendMode_Multiply:
  935. blendFunc.src = GL_DST_COLOR;
  936. blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
  937. break;
  938. case BlendMode_Screen:
  939. blendFunc.src = GL_ONE;
  940. blendFunc.dst = GL_ONE_MINUS_SRC_COLOR;
  941. break;
  942. default:
  943. blendFunc.src = premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
  944. blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
  945. break;
  946. }
  947. #else
  948. switch (blendMode) {
  949. case BlendMode_Additive:
  950. blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA;
  951. blendFunc.dst = backend::BlendFactor::ONE;
  952. break;
  953. case BlendMode_Multiply:
  954. blendFunc.src = backend::BlendFactor::DST_COLOR;
  955. blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA;
  956. break;
  957. case BlendMode_Screen:
  958. blendFunc.src = backend::BlendFactor::ONE;
  959. blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_COLOR;
  960. break;
  961. default:
  962. blendFunc.src = premultipliedAlpha ? backend::BlendFactor::ONE : backend::BlendFactor::SRC_ALPHA;
  963. blendFunc.dst = backend::BlendFactor::ONE_MINUS_SRC_ALPHA;
  964. }
  965. #endif
  966. return blendFunc;
  967. }
  968. bool cullRectangle(Renderer* renderer, const Mat4& transform, const cocos2d::Rect& rect) {
  969. if (Camera::getVisitingCamera() == nullptr)
  970. return false;
  971. auto director = Director::getInstance();
  972. auto scene = director->getRunningScene();
  973. if (!scene || (scene && Camera::getDefaultCamera() != Camera::getVisitingCamera()))
  974. return false;
  975. Rect visibleRect(director->getVisibleOrigin(), director->getVisibleSize());
  976. // transform center point to screen space
  977. float hSizeX = rect.size.width/2;
  978. float hSizeY = rect.size.height/2;
  979. Vec3 v3p(rect.origin.x + hSizeX, rect.origin.y + hSizeY, 0);
  980. transform.transformPoint(&v3p);
  981. Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p);
  982. // convert content size to world coordinates
  983. float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4]));
  984. float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5]));
  985. // enlarge visible rect half size in screen coord
  986. visibleRect.origin.x -= wshw;
  987. visibleRect.origin.y -= wshh;
  988. visibleRect.size.width += wshw * 2;
  989. visibleRect.size.height += wshh * 2;
  990. return !visibleRect.containsPoint(v2p);
  991. }
  992. Color4B ColorToColor4B(const Color& color) {
  993. return { (uint8_t)(color.r * 255.f), (uint8_t)(color.g * 255.f), (uint8_t)(color.b * 255.f), (uint8_t)(color.a * 255.f) };
  994. }
  995. }
  996. }