From e63a2d0dc230221ed7709a4400a88f3f4ffcaf88 Mon Sep 17 00:00:00 2001 From: Ricardo Quesada Date: Wed, 23 Nov 2016 17:59:00 -0800 Subject: [PATCH] Scale9Sprite refactor (#16891) * Squashed commit of the following: commit 026eee59c9ece7fc59d71fead41104f375f72eb5 Author: Ricardo Quesada Date: Tue Nov 22 21:45:12 2016 -0800 yay! everything works! commit a645c99d44f0d7674e6238afae7628d8d2a030b1 Author: Ricardo Quesada Date: Tue Nov 22 14:55:31 2016 -0800 more fixes in Scale9Sprite commit 3a688f4ea70c0abe311232c65ed14a7e9acc7611 Author: Ricardo Quesada Date: Mon Nov 21 23:06:45 2016 -0800 rotated sprites commit 45e2085df3aa4b52236c817f7db7c1f6602c1e95 Author: Ricardo Quesada Date: Mon Nov 21 17:10:44 2016 -0800 android patch 9: fixes is not 100% backward compatible since the previous version had some artifacts. fixed the artifacts. now it renders ok commit 4655d894387fa40a7e63b074a36bfed20e41d5f9 Author: Ricardo Quesada Date: Mon Nov 21 16:31:29 2016 -0800 sprite: correct size for "fake scale9" commit cb98aba27cc1c82a986268d5b74afb55b6cca2f3 Author: Ricardo Quesada Date: Fri Nov 18 21:55:51 2016 -0800 sprite: adds setStrechEnabled for backward compatibility and other fixes commit c0fe67aac54cd62e3846810d56f87133f3a7343b Author: Ricardo Quesada Date: Fri Nov 18 18:49:42 2016 -0800 implemts missing functions in scale9sprite commit e471ef318725ccabc9eca2c062e285e9ca4f9a81 Author: Ricardo Quesada Date: Fri Nov 18 18:42:30 2016 -0800 "batched" works commit 33124bfb14d1f275d4b0ffca8989975625a8a76d Author: Ricardo Quesada Date: Wed Nov 16 18:59:38 2016 -0800 more fixes commit 149f8206269843af63a1739885c00ed8d94c239c Author: Ricardo Quesada Date: Wed Nov 16 18:37:12 2016 -0800 scale 9 rotated not fixed yet. but making progress commit 27f98275d94ce00c8d5ff0b6f74b5c22723cc3c3 Author: Ricardo Quesada Date: Wed Nov 16 15:32:57 2016 -0800 sprite: streching works ok with normal sprites commit 2519498cac8b77a32dee5bdf1805be56fbda5ed6 Author: Ricardo Quesada Date: Wed Nov 16 12:12:28 2016 -0800 somes fixes... still not working commit 43580d0b4aa976b0200717611a286bf1035c472d Author: Ricardo Quesada Date: Tue Nov 15 23:15:22 2016 -0800 more bug fixes related to untrimmed setCenterRect... ...in SCale9Sprite commit 407247616e506afaa0415c58ad7fce38efed0cd9 Author: Ricardo Quesada Date: Tue Nov 15 22:13:38 2016 -0800 spritecale9: untrimmed vs. trimmed capInsets WIP. there still a few bugs commit 3d845b2af3500be287fabb04bb6ba0ec04dbb401 Author: Ricardo Quesada Date: Mon Nov 14 23:11:17 2016 -0800 started progressbar commit 0a44b00daf723869b7105689890f29cd53a62608 Author: Ricardo Quesada Date: Mon Nov 14 17:43:23 2016 -0800 adds EditBox test commit 330304bd9b2e762de95c2f27f1ae3ceee83b2fbf Author: Ricardo Quesada Date: Wed Nov 9 16:57:08 2016 -0800 adds elastic to scroll view commit a06a35f8691ff56a143953c44acd947b519150b6 Author: Ricardo Quesada Date: Wed Nov 9 15:58:29 2016 -0800 yay! scrollview works commit 37748a885c62eca8c00d2c9c11ee103f1d95e71c Author: Ricardo Quesada Date: Wed Nov 9 15:33:58 2016 -0800 yet more scrollview fixes commit a6e563b497adef7b141ac7c92c844d479b244c59 Author: Ricardo Quesada Date: Wed Nov 9 14:48:28 2016 -0800 initial scroll view commit 4243edd7548e5533ca03c26d5042f8dc5517445a Author: Ricardo Quesada Date: Tue Nov 8 17:50:15 2016 -0800 sanity check in frames. missing files commit 159d88603ad22f3c01761b60bacec98d52b9041d Author: Ricardo Quesada Date: Mon Nov 7 19:21:00 2016 -0800 three buttons working commit 6764cfc7937a1a81d6993d5e32a21f17457b8e0d Author: Ricardo Quesada Date: Mon Nov 7 18:50:22 2016 -0800 missing files commit 11c1fa3812e706a7d34137fe2626f05ab73ee3e6 Author: Ricardo Quesada Date: Mon Nov 7 18:49:59 2016 -0800 button works! commit 26b6de4c28fc973e332dd51fcd763a6249c0b4c2 Author: Ricardo Quesada Date: Mon Nov 7 18:19:47 2016 -0800 Scale9: more fixes. complies with odd Rect::ZERO behavior commit ce561268096afe322f25034eeab3508a60027afd Author: Ricardo Quesada Date: Mon Nov 7 11:50:42 2016 -0800 label: setTitleLabel commit 51b5536cd2af36896002621f75c7310960c3f5e7 Author: Ricardo Quesada Date: Wed Nov 2 17:41:08 2016 -0700 UIButton kind of working commit 7562a49a761ef70c383a99d2addefc63d77e279f Author: Ricardo Quesada Date: Wed Nov 2 11:11:42 2016 -0700 missing resoruces commit a9890dee5da0104bff6872cc04e8786a6c0a9018 Author: Ricardo Quesada Date: Wed Nov 2 10:54:55 2016 -0700 setCenterRect to .cpp file commit c9c4bb55ed3fc55709eca46c43d1bfe5301c317f Author: Ricardo Quesada Date: Wed Nov 2 00:19:51 2016 -0700 removed unused paramter commit e47732934cca79c08e6fe96e46ebdf075508e568 Author: Ricardo Quesada Date: Fri Oct 28 18:19:31 2016 -0700 flipping works! commit c9769bacd321aeddf84e1772dd270f12194d2f04 Author: Ricardo Quesada Date: Fri Oct 28 17:57:53 2016 -0700 spirte flip fixes... not finished yet commit 1cbdc8e12cc6d0d2728c06dfabaada001784a178 Author: Ricardo Quesada Date: Fri Oct 28 09:53:16 2016 -0700 centerRect changes commit aeb1b14c00331dabba640f52d79ab0e255fa3407 Author: Ricardo Quesada Date: Fri Oct 28 09:10:41 2016 -0700 changes from v3 commit e7a61c4a20d786c2bc1d6f57e33bf3ac95cb6f21 Author: Ricardo Quesada Date: Wed Oct 26 17:01:15 2016 -0700 sprite: rotated slice 9 works as expected commit 91049389426051deb49a9d951364bf60abaf4532 Author: Ricardo Quesada Date: Wed Oct 26 15:39:54 2016 -0700 more bug fixes in scale9sprite support commit 9feb12449078441c439df16dc7bcfb4506c7a226 Author: Ricardo Quesada Date: Wed Oct 26 13:22:52 2016 -0700 Android's Patch 9 works as expected commit 1cf46afe3e7f7f5f714d30779caefc25a9bb1b3b Author: Ricardo Quesada Date: Wed Oct 26 10:18:47 2016 -0700 Sprite: uses capInsets instead of centerRect just to share the same API as Scale9Sprite commit e944fa0248a7eb58012aacb229de1a9b814e0aef Author: Ricardo Quesada Date: Tue Oct 25 18:59:42 2016 -0700 scale9sprite support fixes commit b08765740d480b6ae1491800161b40d88f458767 Author: Ricardo Quesada Date: Tue Oct 25 17:38:47 2016 -0700 more scale9sprite fixes commit 388a34d93de5e6007a2cecea959c929f26427cab Author: Ricardo Quesada Date: Tue Oct 25 17:20:01 2016 -0700 UI::Scale9Sprite refactoring subclass of Sprite... much cleaner! commit c84ec8ee654f74d4b38be2d0a3d7ffe6adbc6faf Author: Ricardo Quesada Date: Mon Oct 24 20:58:36 2016 -0700 supports tiled sprites commit d2b18eb47a647b29319488bd53edac9f304acb84 Author: Ricardo Quesada Date: Mon Oct 24 19:21:57 2016 -0700 testing tiled sprite commit b4832ab2facc01cbb624db587ede01fe7acf23e8 Author: Ricardo Quesada Date: Mon Oct 24 16:53:19 2016 -0700 using correct top-left coordinates for setCenterRect commit 29d8de86a71cc597b2338f59f7951a28ee0c93b2 Author: Ricardo Quesada Date: Mon Oct 24 16:46:13 2016 -0700 fixes from scale_sprite9 branch commit ccbe1063bea7db75397ecaf9046aac3dd977a621 Author: Ricardo Quesada Date: Thu Oct 20 19:01:50 2016 -0700 updated example commit 24f7f85d4eba80f8e543810dcbc1a02447900bdc Author: Ricardo Quesada Date: Thu Oct 20 18:47:28 2016 -0700 more fixes in nine slice commit df3358fae68f2d81baf3a8cbe033a4c400ea50da Author: Ricardo Quesada Date: Thu Oct 20 18:22:14 2016 -0700 anchor point fixes commit 4ac7409bc72425abb0dc747b956ec346fbd1b2fa Author: Ricardo Quesada Date: Thu Oct 20 17:01:48 2016 -0700 support for slice-9 from creator commit a3221375d3a9defc2e03df0b1c2da1b36dfdd491 Merge: 73e5389 d7490d9 Author: Ricardo Quesada Date: Thu Oct 20 14:13:38 2016 -0700 Merge branch 'sprite_scale9' into creator_cpp_support commit d7490d94896ad0ce8705dc0695252cee34329b5e Author: Ricardo Quesada Date: Thu Oct 13 14:34:52 2016 -0700 Adds slice9 support for Sprite. how to use it: // points coords sprite->setCenterRect(Rect(x,y,w,h)); // normalized coords sprite->setCenterRectNormalized(Rect(x,y,w,h)); starts scale9sprite in sprite more slice 9 changes sprite 9 slice works? kind of works correct anchor point slice 9 works, at least with non-rotated atlases streched works ok better Y invert code. cleaner, compatible with the previous code yay, scaling workings... need a better api now sets scale correctly yay! works as expected! more fixes and tests better test for box setContentSize() changes size in non-9-slice mode sprites as well setCenterRect() -> setCenterRectNormalized() yet another test adds setPositionNormalized() adds setCenterRect() tests remove devel team from xcode tests: add one more tests fun test! improved test yet another test for slice 9 commit 73e5389ef719880096067d0f7d0bffd6e1f3cfd1 Author: Ricardo Quesada Date: Sun Oct 9 18:54:22 2016 -0700 kind of ProgressBar support commit 4db5e9e7369e93ceba1d9512ab88c26b843c43d5 Author: Ricardo Quesada Date: Fri Oct 7 16:23:54 2016 -0700 new generatred ui files commit 75aa06f3d39df8c6aa898d5e6810b3cd8015c07b Author: Ricardo Quesada Date: Thu Oct 6 10:44:59 2016 -0700 bette canvas support commit 89beacac478fc7f58ef930963b6393f3da4a743c Author: Ricardo Quesada Date: Wed Oct 5 21:47:11 2016 -0700 sprites tests commit 5fe930ad50c2c1b6d868982709c7b659176f9889 Author: Ricardo Quesada Date: Wed Oct 5 18:35:44 2016 -0700 more label tests commit d3f615a097d080d78f2ebd95f3e2388da45f92db Author: Ricardo Quesada Date: Wed Oct 5 18:08:24 2016 -0700 label tests commit 2a4018922ce8d36117f7092fc324e37cf75fdeab Author: Ricardo Quesada Date: Tue Oct 4 21:52:56 2016 -0700 label fixes commit 41fafbd023de63e376d014311605f2b156add307 Author: Ricardo Quesada Date: Tue Oct 4 19:14:58 2016 -0700 updated test commit 06919fc28fffbc5a20cd14bdcc2ad2ff997e0da1 Author: Ricardo Quesada Date: Tue Oct 4 18:50:45 2016 -0700 creator tests: works commit 6e362e7cc7f68dc216b569a7f7f90aaa110c0e4a Author: Ricardo Quesada Date: Tue Sep 27 23:15:56 2016 -0700 autogen: new data commit e78078b2ad84b4e364827a66f1c459de7384a91d Author: Ricardo Quesada Date: Mon Sep 26 18:18:57 2016 -0700 fix: initial test for CPP support for Creator * adds more documentation * adds more documentation --- .../xcschemes/cpp-tests Mac.xcscheme | 1 + cocos/2d/CCSprite.cpp | 399 ++-- cocos/2d/CCSprite.h | 11 +- cocos/2d/CCSpriteFrame.cpp | 48 +- cocos/2d/CCSpriteFrameCache.cpp | 1 + .../cocosbuilder/CCScale9SpriteLoader.cpp | 2 +- cocos/ui/UIButton.cpp | 29 +- cocos/ui/UIButton.h | 7 + cocos/ui/UIScale9Sprite.cpp | 1859 ++++------------- cocos/ui/UIScale9Sprite.h | 344 +-- .../CocoStudioGUITest/UIScale9SpriteTest.cpp | 22 +- 11 files changed, 885 insertions(+), 1838 deletions(-) diff --git a/build/cocos2d_tests.xcodeproj/xcshareddata/xcschemes/cpp-tests Mac.xcscheme b/build/cocos2d_tests.xcodeproj/xcshareddata/xcschemes/cpp-tests Mac.xcscheme index fec318d27e..d513d72113 100644 --- a/build/cocos2d_tests.xcodeproj/xcshareddata/xcschemes/cpp-tests Mac.xcscheme +++ b/build/cocos2d_tests.xcodeproj/xcshareddata/xcschemes/cpp-tests Mac.xcscheme @@ -49,6 +49,7 @@ useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" + enableAddressSanitizer = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> getSpriteFrameByName(spriteFrameName); - + #if COCOS2D_DEBUG > 0 char msg[256] = {0}; sprintf(msg, "Invalid spriteFrameName: %s", spriteFrameName.c_str()); CCASSERT(frame != nullptr, msg); #endif - + return createWithSpriteFrame(frame); } @@ -143,7 +143,7 @@ Sprite* Sprite::create() bool Sprite::init() { initWithTexture(nullptr, Rect::ZERO); - + return true; } @@ -196,7 +196,7 @@ bool Sprite::initWithFile(const std::string &filename, const Rect& rect) { return false; } - + _fileName = filename; _fileType = 0; @@ -219,7 +219,7 @@ bool Sprite::initWithSpriteFrameName(const std::string& spriteFrameName) { return false; } - + _fileName = spriteFrameName; _fileType = 1; @@ -234,7 +234,7 @@ bool Sprite::initWithSpriteFrame(SpriteFrame *spriteFrame) { return false; } - + bool bRet = initWithTexture(spriteFrame->getTexture(), spriteFrame->getRect()); setSpriteFrame(spriteFrame); @@ -244,7 +244,7 @@ bool Sprite::initWithSpriteFrame(SpriteFrame *spriteFrame) bool Sprite::initWithPolygon(const cocos2d::PolygonInfo &info) { bool ret = false; - + Texture2D *texture = _director->getTextureCache()->addImage(info.getFilename()); if(texture && initWithTexture(texture)) { @@ -252,7 +252,7 @@ bool Sprite::initWithPolygon(const cocos2d::PolygonInfo &info) Node::setContentSize(_polyInfo.getRect().size / _director->getContentScaleFactor()); ret = true; } - + return ret; } @@ -263,25 +263,25 @@ bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) if (Node::init()) { _batchNode = nullptr; - + _recursiveDirty = false; setDirty(false); - + _opacityModifyRGB = true; - + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; - + _flippedX = _flippedY = false; - + // default transform anchor: center setAnchorPoint(Vec2::ANCHOR_MIDDLE); - + // zwoptex default values _offsetPosition.setZero(); // clean the Quad memset(&_quad, 0, sizeof(_quad)); - + // Atlas: Color _quad.bl.colors = Color4B::WHITE; _quad.br.colors = Color4B::WHITE; @@ -291,16 +291,16 @@ bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) // update texture (calls updateBlendFunc) setTexture(texture); setTextureRect(rect, rotated, rect.size); - + // by default use "Self Render". // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" setBatchNode(nullptr); result = true; } - + _recursiveDirty = true; setDirty(true); - + return result; } @@ -316,6 +316,7 @@ Sprite::Sprite(void) , _quads(nullptr) , _strechFactor(Vec2::ONE) , _originalContentSize(Size::ZERO) +, _strechEnabled(true) { #if CC_SPRITE_DEBUG_DRAW _debugDrawNode = DrawNode::create(); @@ -425,20 +426,87 @@ void Sprite::setTextureRect(const Rect& rect, bool rotated, const Size& untrimme void Sprite::updatePoly() { + // There are 3 cases: + // + // A) a non 9-sliced, non streched + // contentsize doesn't not affect the streching, since there is no streching + // this was the original behavior, and we keep it for backwards compatibility reasons + // When non-streching is enabled, we have to change the offset in order to "fill the empty" space at the + // left-top of the texture + // B) non 9-sliced, streched + // the texture is streched to the content size + // C) 9-sliced, streched + // the sprite is 9-sliced and streched. if (_numberOfSlices == 1) { setTextureCoords(_rect, &_quad); - const Rect copyRect(0, 0, _rect.size.width * _strechFactor.x, _rect.size.height * _strechFactor.y); - setVertexCoords(copyRect, _rect.size, &_quad); + Rect copyRect; + if (_strechEnabled) { + // case B) + copyRect = Rect(0, 0, _rect.size.width * _strechFactor.x, _rect.size.height * _strechFactor.y); + } else { + // case A) + // modify origin to put the sprite in the correct offset + copyRect = Rect((_contentSize.width - _originalContentSize.width) / 2.0f, + (_contentSize.height - _originalContentSize.height) / 2.0f, + _rect.size.width, + _rect.size.height); + } + setVertexCoords(copyRect, &_quad); _polyInfo.setQuad(&_quad); } else { + // case C) + // in theory it can support 3 slices as well, but let's stick to 9 only CCASSERT(_numberOfSlices == 9, "Invalid number of slices"); + + // How the texture is split + // + // u,v: are the texture coordinates + // w,h: are the width and heights + // + // w0 w1 w2 + // v2 +----+------+--+ + // | | | | + // | | | | + // | 6 | 7 | 8| h2 + // | | | | + // v1 +----+------+--| + // | | | | + // | 3 | 4 | 5| h1 + // v0 +----+------+--| + // | | | | + // | 0 | 1 | 2| h0 + // | | | | + // +----+------+--+ + // u0 u1 u2 + // + // + // and when the texture is rotated, it will get transformed. + // not only the rects have a different position, but also u,v + // points to the bottom-left and not top-right of the texture + // so some swaping/origin/reordering needs to be done in order + // to support rotated slice-9 correctly + // + // w0 w1 w2 + // v2 +------+----+--------+ + // | | | | + // | 0 | 3 | 6 | h2 + // v1 +------+----+--------+ + // | | | | + // | 1 | 4 | 7 | h1 + // | | | | + // v0 +------+----+--------+ + // | 2 | 5 | 8 | h0 + // +------+----+--------+ + // u0 u1 u2 + + // center rect - const float cx1 = _centerRectNormalized.origin.x; - const float cy1 = _centerRectNormalized.origin.y; - const float cx2 = _centerRectNormalized.origin.x + _centerRectNormalized.size.width; - const float cy2 = _centerRectNormalized.origin.y + _centerRectNormalized.size.height; + float cx1 = _centerRectNormalized.origin.x; + float cy1 = _centerRectNormalized.origin.y; + float cx2 = _centerRectNormalized.origin.x + _centerRectNormalized.size.width; + float cy2 = _centerRectNormalized.origin.y + _centerRectNormalized.size.height; // "O"riginal rect const float oox = _rect.origin.x; @@ -446,7 +514,20 @@ void Sprite::updatePoly() const float osw = _rect.size.width; const float osh = _rect.size.height; + if (_rectRotated) { + std::swap(cx1, cy1); + std::swap(cx2, cy2); + + // when the texture is rotated, then the centerRect starts from the "bottom" (left) + // but when it is not rotated, it starts from the top, so invert it + cy2 = 1 - cy2; + cy1 = 1 - cy1; + std::swap(cy1, cy2); + } + + // // textCoords Data: Y must be inverted. + // const float u0 = oox + osw * 0; const float u1 = oox + osw * cx1; const float u2 = oox + osw * cx2; @@ -454,21 +535,56 @@ void Sprite::updatePoly() const float v1 = ooy + osh * (1 - cy2); const float v2 = ooy + osh * 0; - const Rect texRects[9] = { - Rect(u0, v0, osw * cx1, osh * cy1), // bottom-left - Rect(u1, v0, osw * (cx2-cx1), osh * cy1), // bottom - Rect(u2, v0, osw * (1-cx2), osh * cy1), // bottom-right + const float w0 = osw * cx1; + const float w1 = osw * (cx2-cx1); + const float w2 = osw * (1-cx2); + const float h0 = osh * cy1; + const float h1 = osh * (cy2-cy1); + const float h2 = osh * (1-cy2); - Rect(u0, v1, osw * cx1, osh * (cy2-cy1)), // left - Rect(u1, v1, osw * (cx2-cx1), osh * (cy2-cy1)), // center - Rect(u2, v1, osw * (1-cx2), osh * (cy2-cy1)), // right + const Rect texRects_normal[9] = { + Rect(u0, v0, w0, h0), // bottom-left + Rect(u1, v0, w1, h0), // bottom + Rect(u2, v0, w2, h0), // bottom-right - Rect(u0, v2, osw * cx1, osh * (1-cy2)), // top-left - Rect(u1, v2, osw * (cx2-cx1), osh * (1-cy2)), // top - Rect(u2, v2, osw * (1-cx2), osh * (1-cy2)), // top-right + Rect(u0, v1, w0, h1), // left + Rect(u1, v1, w1, h1), // center + Rect(u2, v1, w2, h1), // right + + Rect(u0, v2, w0, h2), // top-left + Rect(u1, v2, w1, h2), // top + Rect(u2, v2, w2, h2), // top-right }; + // swap width and height because setTextureCoords() + // will expects the hight and width to be swapped + const Rect texRects_rotated[9] = { + Rect(u0, v2, h2, w0), // top-left + Rect(u0, v1, h1, w0), // left + Rect(u0, v0, h0, w0), // bottom-left + + Rect(u1, v2, h2, w1), // top + Rect(u1, v1, h1, w1), // center + Rect(u1, v0, h0, w1), // bottom + + Rect(u2, v2, h2, w2), // top-right + Rect(u2, v1, h1, w2), // right + Rect(u2, v0, h0, w2), // bottom-right + }; + + const Rect* texRects = _rectRotated ? texRects_rotated : texRects_normal; + + // // vertex Data. + // + + // reset center rect since it is altered when when the texture + // is rotated + cx1 = _centerRectNormalized.origin.x; + cy1 = _centerRectNormalized.origin.y; + cx2 = _centerRectNormalized.origin.x + _centerRectNormalized.size.width; + cy2 = _centerRectNormalized.origin.y + _centerRectNormalized.size.height; + // sizes float x0_s = osw * cx1; @@ -478,10 +594,8 @@ void Sprite::updatePoly() float y1_s = osh * (cy2-cy1) * _strechFactor.y; float y2_s = osh * (1-cy2); - // It is easier to call "updateXY", but it will be slower. - // so the flipping is calculated here at the cost of adding - // just a little bit more of complexity. + // is it flipped? // swap sizes to calculate offset correctly if (_flippedX) std::swap(x0_s, x2_s); @@ -520,21 +634,9 @@ void Sprite::updatePoly() Rect(x2, y2, x2_s, y2_s), // top-right }; - static const int normalIdx[] = { - 0, 1, 2, - 3, 4, 5, - 6, 7 ,8 - }; - static const int rotatedIdx[] = { - 6, 3, 0, - 7, 4, 1, - 8, 5, 2}; - const int* idx = _rectRotated ? rotatedIdx : normalIdx; - for (int i=0; i<_numberOfSlices; ++i) { - int texIdx = idx[i]; - setTextureCoords(texRects[texIdx], &_quads[i]); - setVertexCoords(verticesRects[i], _rect.size, &_quads[i]); + setTextureCoords(texRects[i], &_quads[i]); + setVertexCoords(verticesRects[i], &_quads[i]); } _polyInfo.setQuads(_quads, _numberOfSlices); } @@ -581,6 +683,7 @@ void Sprite::setCenterRect(const cocos2d::Rect &rectInPoints) if (!_originalContentSize.equals(Size::ZERO)) { Rect rect = rectInPoints; + const float x = rect.origin.x / _rect.size.width; const float y = rect.origin.y / _rect.size.height; const float w = rect.size.width / _rect.size.width; @@ -628,37 +731,52 @@ void Sprite::setTextureCoords(const Rect& rectInPoints, V3F_C4B_T2F_Quad* outQua return; } - auto rectInPixels = CC_RECT_POINTS_TO_PIXELS(rectInPoints); + const auto rectInPixels = CC_RECT_POINTS_TO_PIXELS(rectInPoints); - float atlasWidth = (float)tex->getPixelsWide(); - float atlasHeight = (float)tex->getPixelsHigh(); + const float atlasWidth = (float)tex->getPixelsWide(); + const float atlasHeight = (float)tex->getPixelsHigh(); - float left, right, top, bottom; + float rw = rectInPixels.size.width; + float rh = rectInPixels.size.height; + + // if the rect is rotated, it means that the frame is rotated 90 degrees (clockwise) and: + // - rectInpoints: origin will be the bottom-left of the frame (and not the top-right) + // - size: represents the unrotated texture size + // + // so what we have to do is: + // - swap texture width and height + // - take into account the origin + // - flip X instead of Y when flipY is enabled + // - flip Y instead of X when flipX is enabled + + if (_rectRotated) + std::swap(rw, rh); + +#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL + float left = (2*rectInPixels.origin.x+1) / (2*atlasWidth); + float right = left+(rw*2-2) / (2*atlasWidth); + float top = (2*rectInPixels.origin.y+1) / (2*atlasHeight); + float bottom = top+(rh*2-2) / (2*atlasHeight); +#else + float left = rectInPixels.origin.x / atlasWidth; + float right = (rectInPixels.origin.x + rw) / atlasWidth; + float top = rectInPixels.origin.y / atlasHeight; + float bottom = (rectInPixels.origin.y + rh) / atlasHeight; +#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL + + + if ((_flippedX && !_rectRotated) || (_flippedY && _rectRotated)) + { + std::swap(left, right); + } + + if ((_flippedY && !_rectRotated) || (_flippedX && _rectRotated)) + { + std::swap(top, bottom); + } if (_rectRotated) { -#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - left = (2*rectInPixels.origin.x+1) / (2*atlasWidth); - right = left+(rectInPixels.size.height*2-2) / (2*atlasWidth); - top = (2*rectInPixels.origin.y+1) / (2*atlasHeight); - bottom = top+(rectInPixels.size.width*2-2) / (2*atlasHeight); -#else - left = rectInPixels.origin.x / atlasWidth; - right = (rectInPixels.origin.x + rectInPixels.size.height) / atlasWidth; - top = rectInPixels.origin.y / atlasHeight; - bottom = (rectInPixels.origin.y + rectInPixels.size.width) / atlasHeight; -#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if (_flippedX) - { - std::swap(top, bottom); - } - - if (_flippedY) - { - std::swap(left, right); - } - outQuad->bl.texCoords.u = left; outQuad->bl.texCoords.v = top; outQuad->br.texCoords.u = left; @@ -670,28 +788,6 @@ void Sprite::setTextureCoords(const Rect& rectInPoints, V3F_C4B_T2F_Quad* outQua } else { -#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - left = (2*rectInPixels.origin.x+1) / (2*atlasWidth); - right = left + (rectInPixels.size.width*2-2) / (2*atlasWidth); - top = (2*rectInPixels.origin.y+1) / (2*atlasHeight); - bottom = top + (rectInPixels.size.height*2-2) / (2*atlasHeight); -#else - left = rectInPixels.origin.x / atlasWidth; - right = (rectInPixels.origin.x + rectInPixels.size.width) / atlasWidth; - top = rectInPixels.origin.y / atlasHeight; - bottom = (rectInPixels.origin.y + rectInPixels.size.height) / atlasHeight; -#endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if(_flippedX) - { - std::swap(left, right); - } - - if(_flippedY) - { - std::swap(top, bottom); - } - outQuad->bl.texCoords.u = left; outQuad->bl.texCoords.v = bottom; outQuad->br.texCoords.u = right; @@ -703,10 +799,8 @@ void Sprite::setTextureCoords(const Rect& rectInPoints, V3F_C4B_T2F_Quad* outQua } } -void Sprite::setVertexCoords(const Rect& rect, const Size& imageSize, V3F_C4B_T2F_Quad* outQuad) +void Sprite::setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad) { - // container size is the Size that contains the "unsliced" sprite - float relativeOffsetX = _unflippedOffsetPositionFromCenter.x; float relativeOffsetY = _unflippedOffsetPositionFromCenter.y; @@ -720,8 +814,15 @@ void Sprite::setVertexCoords(const Rect& rect, const Size& imageSize, V3F_C4B_T2 relativeOffsetY = -relativeOffsetY; } - _offsetPosition.x = relativeOffsetX + (_originalContentSize.width - imageSize.width) / 2; - _offsetPosition.y = relativeOffsetY + (_originalContentSize.height - imageSize.height) / 2; + _offsetPosition.x = relativeOffsetX + (_originalContentSize.width - _rect.size.width) / 2; + _offsetPosition.y = relativeOffsetY + (_originalContentSize.height - _rect.size.height) / 2; + + // FIXME: Streching should be applied to the "offset" as well + // but probably it should be calculated in the caller function. It will be tidier + if (_numberOfSlices == 1) { + _offsetPosition.x *= _strechFactor.x; + _offsetPosition.y *= _strechFactor.y; + } // rendering using batch node if (_batchNode) @@ -793,7 +894,7 @@ void Sprite::updateTransform(void) float x2 = x1 + size.width; float y2 = y1 + size.height; - + float x = _transformToBatch.m[12]; float y = _transformToBatch.m[13]; @@ -849,7 +950,7 @@ void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { return; } - + #if CC_USE_CULLING // Don't calculate the culling if the transform was not updated auto visitingCamera = Camera::getVisitingCamera(); @@ -866,16 +967,16 @@ void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) if(_insideBounds) #endif { - _trianglesCommand.init(_globalZOrder, - _texture, - getGLProgramState(), - _blendFunc, - _polyInfo.triangles, - transform, - flags); + _trianglesCommand.init(_globalZOrder, + _texture, + getGLProgramState(), + _blendFunc, + _polyInfo.triangles, + transform, + flags); renderer->addCommand(&_trianglesCommand); - + #if CC_SPRITE_DEBUG_DRAW _debugDrawNode->clear(); auto count = _polyInfo.triangles.indexCount/3; @@ -887,11 +988,11 @@ void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) Vec3 from =verts[indices[i*3]].vertices; Vec3 to = verts[indices[i*3+1]].vertices; _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); - + from =verts[indices[i*3+1]].vertices; to = verts[indices[i*3+2]].vertices; _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); - + from =verts[indices[i*3+2]].vertices; to = verts[indices[i*3]].vertices; _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); @@ -909,7 +1010,7 @@ void Sprite::addChild(Node *child, int zOrder, int tag) { return; } - + if (_batchNode) { Sprite* childSprite = dynamic_cast(child); @@ -934,7 +1035,7 @@ void Sprite::addChild(Node *child, int zOrder, const std::string &name) { return; } - + if (_batchNode) { Sprite* childSprite = dynamic_cast(child); @@ -943,7 +1044,7 @@ void Sprite::addChild(Node *child, int zOrder, const std::string &name) "childSprite's texture name should be equal to _textureAtlas's texture name."); //put it in descendants array of batch node _batchNode->appendChild(childSprite); - + if (!_reorderChildDirty) { setReorderChildDirtyRecursively(); @@ -1068,7 +1169,7 @@ void Sprite::setPosition(float x, float y) void Sprite::setRotation(float rotation) { Node::setRotation(rotation); - + SET_DIRTY_RECURSIVELY(); } @@ -1152,17 +1253,35 @@ void Sprite::setContentSize(const Size& size) updatePoly(); } +void Sprite::setStrechEnabled(bool enabled) +{ + if (_strechEnabled != enabled) { + _strechEnabled = enabled; + + // disabled centerrect / number of slices if disabled + if (!enabled) + setCenterRectNormalized(Rect(0,0,1,1)); + + updateStretchFactor(); + updatePoly(); + } +} + +bool Sprite::isStrechEnabled() const +{ + return _strechEnabled; +} + void Sprite::updateStretchFactor() { const Size size = getContentSize(); - const float adjustedWidth = size.width - (_originalContentSize.width - _rect.size.width); - const float adjustedHeight = size.height - (_originalContentSize.height - _rect.size.height); if (_numberOfSlices == 1) { - const float x_factor = adjustedWidth / _rect.size.width; - const float y_factor = adjustedHeight / _rect.size.height; - + // If strech is disabled, calculate the strech anyway + // since it is needed to calculate the offset + const float x_factor = size.width / _originalContentSize.width; + const float y_factor = size.height / _originalContentSize.height; _strechFactor = Vec2(x_factor, y_factor); } else @@ -1175,6 +1294,10 @@ void Sprite::updateStretchFactor() const float y2 = _rect.size.height * _centerRectNormalized.size.height; const float y3 = _rect.size.height * (1 - _centerRectNormalized.origin.y - _centerRectNormalized.size.height); + // adjustedSize = the new _rect size + const float adjustedWidth = size.width - (_originalContentSize.width - _rect.size.width); + const float adjustedHeight = size.height - (_originalContentSize.height - _rect.size.height); + const float x_factor = (adjustedWidth - x1 - x3) / x2; const float y_factor = (adjustedHeight - y1 - y3) / y2; @@ -1188,13 +1311,10 @@ void Sprite::setFlippedX(bool flippedX) { _flippedX = flippedX; - for (ssize_t i = 0; i < _polyInfo.triangles.vertCount; i++) { - auto& v = _polyInfo.triangles.verts[i].vertices; - v.x = _contentSize.width - v.x; - } - - if (_textureAtlas) { + if (_batchNode) { setDirty(true); + } else { + updatePoly(); } } } @@ -1210,13 +1330,10 @@ void Sprite::setFlippedY(bool flippedY) { _flippedY = flippedY; - for (ssize_t i = 0; i < _polyInfo.triangles.vertCount; i++) { - auto& v = _polyInfo.triangles.verts[i].vertices; - v.y = _contentSize.height - v.y; - } - - if (_textureAtlas) { + if (_batchNode) { setDirty(true); + } else { + updatePoly(); } } } @@ -1233,7 +1350,7 @@ bool Sprite::isFlippedY(void) const void Sprite::updateColor(void) { Color4B color4( _displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity ); - + // special opacity for premultiplied textures if (_opacityModifyRGB) { @@ -1288,7 +1405,7 @@ void Sprite::setSpriteFrame(const std::string &spriteFrameName) { return; } - + SpriteFrameCache *cache = SpriteFrameCache::getInstance(); SpriteFrame *spriteFrame = cache->getSpriteFrameByName(spriteFrameName); @@ -1319,7 +1436,7 @@ void Sprite::setSpriteFrame(SpriteFrame *spriteFrame) // update rect _rectRotated = spriteFrame->isRotated(); setTextureRect(spriteFrame->getRect(), _rectRotated, spriteFrame->getOriginalSize()); - + if (spriteFrame->hasPolygonInfo()) { _polyInfo = spriteFrame->getPolygonInfo(); @@ -1341,7 +1458,7 @@ void Sprite::setDisplayFrameWithAnimationName(const std::string& animationName, { return; } - + Animation *a = AnimationCache::getInstance()->getAnimation(animationName); CCASSERT(a, "CCSprite#setDisplayFrameWithAnimationName: Frame not found"); diff --git a/cocos/2d/CCSprite.h b/cocos/2d/CCSprite.h index 547b1e25b4..dca050f94c 100644 --- a/cocos/2d/CCSprite.h +++ b/cocos/2d/CCSprite.h @@ -451,6 +451,13 @@ public: * @param PolygonInfo the polygon information object */ void setPolygonInfo(const PolygonInfo& info); + + /** whether or not contentSize streches the sprite's texture */ + void setStrechEnabled(bool enabled); + + /** returns whether or not contentSize streches the sprite's texture */ + bool isStrechEnabled() const; + // // Overrides // @@ -623,7 +630,7 @@ protected: void updateColor() override; virtual void setTextureCoords(const Rect& rect); virtual void setTextureCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad); - virtual void setVertexCoords(const Rect& rect, const Size& imageSize, V3F_C4B_T2F_Quad* outQuad); + virtual void setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad); virtual void updateBlendFunc(); virtual void setReorderChildDirtyRecursively(); virtual void setDirtyRecursively(bool value); @@ -688,6 +695,8 @@ protected: std::string _fileName; int _fileType; + bool _strechEnabled; + private: CC_DISALLOW_COPY_AND_ASSIGN(Sprite); }; diff --git a/cocos/2d/CCSpriteFrame.cpp b/cocos/2d/CCSpriteFrame.cpp index 308610ff8b..c3fa2d81fe 100644 --- a/cocos/2d/CCSpriteFrame.cpp +++ b/cocos/2d/CCSpriteFrame.cpp @@ -28,6 +28,7 @@ THE SOFTWARE. #include "renderer/CCTextureCache.h" #include "2d/CCSpriteFrame.h" #include "base/CCDirector.h" +#include "platform/CCFileUtils.h" NS_CC_BEGIN @@ -54,19 +55,24 @@ SpriteFrame* SpriteFrame::createWithTexture(Texture2D *texture, const Rect& rect SpriteFrame* SpriteFrame::createWithTexture(Texture2D* texture, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize) { SpriteFrame *spriteFrame = new (std::nothrow) SpriteFrame(); - spriteFrame->initWithTexture(texture, rect, rotated, offset, originalSize); - spriteFrame->autorelease(); + if (spriteFrame && spriteFrame->initWithTexture(texture, rect, rotated, offset, originalSize)) { + spriteFrame->autorelease(); + return spriteFrame; + } - return spriteFrame; + delete spriteFrame; + return nullptr; } SpriteFrame* SpriteFrame::create(const std::string& filename, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize) { SpriteFrame *spriteFrame = new (std::nothrow) SpriteFrame(); - spriteFrame->initWithTextureFilename(filename, rect, rotated, offset, originalSize); - spriteFrame->autorelease(); - - return spriteFrame; + if (spriteFrame && spriteFrame->initWithTextureFilename(filename, rect, rotated, offset, originalSize)) { + spriteFrame->autorelease(); + return spriteFrame; + } + delete spriteFrame; + return nullptr; } SpriteFrame::SpriteFrame() @@ -111,19 +117,21 @@ bool SpriteFrame::initWithTexture(Texture2D* texture, const Rect& rect, bool rot bool SpriteFrame::initWithTextureFilename(const std::string& filename, const Rect& rect, bool rotated, const Vec2& offset, const Size& originalSize) { - _texture = nullptr; - _textureFilename = filename; - _rectInPixels = rect; - _rect = CC_RECT_PIXELS_TO_POINTS( rect ); - _offsetInPixels = offset; - _offset = CC_POINT_PIXELS_TO_POINTS( _offsetInPixels ); - _originalSizeInPixels = originalSize; - _originalSize = CC_SIZE_PIXELS_TO_POINTS( _originalSizeInPixels ); - _rotated = rotated; - _anchorPoint = Vec2(NAN, NAN); - _centerRect = Rect(NAN, NAN, NAN, NAN); - - return true; + if (FileUtils::getInstance()->isFileExist(filename)) { + _texture = nullptr; + _textureFilename = filename; + _rectInPixels = rect; + _rect = CC_RECT_PIXELS_TO_POINTS( rect ); + _offsetInPixels = offset; + _offset = CC_POINT_PIXELS_TO_POINTS( _offsetInPixels ); + _originalSizeInPixels = originalSize; + _originalSize = CC_SIZE_PIXELS_TO_POINTS( _originalSizeInPixels ); + _rotated = rotated; + _anchorPoint = Vec2(NAN, NAN); + _centerRect = Rect(NAN, NAN, NAN, NAN); + return true; + } + return false; } SpriteFrame::~SpriteFrame() diff --git a/cocos/2d/CCSpriteFrameCache.cpp b/cocos/2d/CCSpriteFrameCache.cpp index 89dc636faa..f585edf0f6 100644 --- a/cocos/2d/CCSpriteFrameCache.cpp +++ b/cocos/2d/CCSpriteFrameCache.cpp @@ -446,6 +446,7 @@ bool SpriteFrameCache::isSpriteFramesWithFileLoaded(const std::string& plist) co void SpriteFrameCache::addSpriteFrame(SpriteFrame* frame, const std::string& frameName) { + CCASSERT(frame, "frame should not be nil"); _spriteFrames.insert(frameName, frame); } diff --git a/cocos/editor-support/cocosbuilder/CCScale9SpriteLoader.cpp b/cocos/editor-support/cocosbuilder/CCScale9SpriteLoader.cpp index 61d89236d3..ad3463e4ab 100644 --- a/cocos/editor-support/cocosbuilder/CCScale9SpriteLoader.cpp +++ b/cocos/editor-support/cocosbuilder/CCScale9SpriteLoader.cpp @@ -25,7 +25,7 @@ ui::Scale9Sprite* Scale9SpriteLoader::createNode(cocos2d::Node* /*pParent*/, coc void Scale9SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_SPRITEFRAME) == 0) { - ((cocos2d::ui::Scale9Sprite *)pNode)->setSpriteFrame(pSpriteFrame); + static_cast(pNode)->setSpriteFrame(pSpriteFrame); } else { NodeLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, ccbReader); } diff --git a/cocos/ui/UIButton.cpp b/cocos/ui/UIButton.cpp index 8a62522ea7..32560d8c13 100644 --- a/cocos/ui/UIButton.cpp +++ b/cocos/ui/UIButton.cpp @@ -158,6 +158,25 @@ void Button::createTitleRenderer() addProtectedChild(_titleRenderer, TITLE_RENDERER_Z, -1); } +/** replaces the current Label node with a new one */ +void Button::setTitleLabel(Label* label) +{ + if (_titleRenderer != label) { + CC_SAFE_RELEASE(_titleRenderer); + _titleRenderer = label; + CC_SAFE_RETAIN(_titleRenderer); + + addProtectedChild(_titleRenderer, TITLE_RENDERER_Z, -1); + updateTitleLocation(); + } +} + +/** returns the current Label being used */ +Label* Button::getTitleLabel() const +{ + return _titleRenderer; +} + void Button::setScale9Enabled(bool able) { if (_scale9Enabled == able) @@ -453,7 +472,7 @@ void Button::onPressStateChangedToNormal() _buttonNormalRenderer->setScale(1.0); _buttonClickedRenderer->setScale(1.0); - if(nullptr != _titleRenderer) + if (nullptr != _titleRenderer) { _titleRenderer->stopAllActions(); if (_unifySize) @@ -474,7 +493,7 @@ void Button::onPressStateChangedToNormal() _buttonNormalRenderer->stopAllActions(); _buttonNormalRenderer->setScale(1.0); - if(nullptr != _titleRenderer) + if (nullptr != _titleRenderer) { _titleRenderer->stopAllActions(); _titleRenderer->setScaleX(1.0f); @@ -507,7 +526,7 @@ void Button::onPressStateChangedToPressed() _buttonNormalRenderer->setScale(1.0f + _zoomScale, 1.0f + _zoomScale); - if(nullptr != _titleRenderer) + if (nullptr != _titleRenderer) { _titleRenderer->stopAllActions(); Action *zoomTitleAction = ScaleTo::create(ZOOM_ACTION_TIME_STEP, @@ -525,7 +544,7 @@ void Button::onPressStateChangedToPressed() _buttonNormalRenderer->stopAllActions(); _buttonNormalRenderer->setScale(1.0f +_zoomScale, 1.0f + _zoomScale); - if(nullptr != _titleRenderer) + if (nullptr != _titleRenderer) { _titleRenderer->stopAllActions(); _titleRenderer->setScaleX(1.0f + _zoomScale); @@ -586,7 +605,7 @@ void Button::updateContentSize() void Button::onSizeChanged() { Widget::onSizeChanged(); - if(nullptr != _titleRenderer) + if (nullptr != _titleRenderer) { updateTitleLocation(); } diff --git a/cocos/ui/UIButton.h b/cocos/ui/UIButton.h index fcba44df5b..1a244735f7 100644 --- a/cocos/ui/UIButton.h +++ b/cocos/ui/UIButton.h @@ -263,6 +263,13 @@ public: */ void setTitleAlignment(TextHAlignment hAlignment, TextVAlignment vAlignment); + /** replaces the current Label node with a new one */ + void setTitleLabel(Label* label); + + /** returns the current Label being used */ + Label* getTitleLabel() const; + + /** @brief When user pressed the button, the button will zoom to a scale. * The final scale of the button equals (button original scale + _zoomScale) * @since v3.3 diff --git a/cocos/ui/UIScale9Sprite.cpp b/cocos/ui/UIScale9Sprite.cpp index c0d8679dae..030c1ebd45 100644 --- a/cocos/ui/UIScale9Sprite.cpp +++ b/cocos/ui/UIScale9Sprite.cpp @@ -20,7 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -****************************************************************************/ + ****************************************************************************/ #include "ui/UIScale9Sprite.h" #include "2d/CCSprite.h" @@ -36,1436 +36,491 @@ #include "2d/CCCamera.h" #include "renderer/CCRenderer.h" -NS_CC_BEGIN -namespace ui { +using namespace cocos2d; +using namespace cocos2d::ui; - Scale9Sprite::Scale9Sprite() - : _spriteFrameRotated(false) - , _scale9Image(nullptr) - , _scale9Enabled(true) - , _insetLeft(0) - , _insetTop(0) - , _insetRight(0) - , _insetBottom(0) - ,_flippedX(false) - ,_flippedY(false) - ,_isPatch9(false) - ,_brightState(State::NORMAL) - ,_nonSliceSpriteAnchor(Vec2::ANCHOR_MIDDLE) - ,_sliceVertices(nullptr) - ,_sliceIndices(nullptr) - ,_sliceSpriteDirty(false) - ,_renderingType(RenderingType::SLICE) - ,_insideBounds(true) +Scale9Sprite* Scale9Sprite::create() +{ + Scale9Sprite *ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->init()) { - this->setAnchorPoint(Vec2(0.5,0.5)); -#if CC_SPRITE_DEBUG_DRAW - _debugDrawNode = DrawNode::create(); - addChild(_debugDrawNode); -#endif //CC_SPRITE_DEBUG_DRAW - } - - Scale9Sprite::~Scale9Sprite() - { - this->cleanupSlicedSprites(); - CC_SAFE_RELEASE(_scale9Image); - } - - bool Scale9Sprite::initWithFile(const Rect& capInsets, const std::string& file) - { - bool pReturn = this->initWithFile(file, Rect::ZERO, capInsets); - return pReturn; - } - - bool Scale9Sprite::initWithFile(const std::string& file) - { - bool pReturn = this->initWithFile(file, Rect::ZERO); - return pReturn; - } - bool Scale9Sprite::initWithSpriteFrame(SpriteFrame* spriteFrame, - const Rect& capInsets) - { - bool ret = false; - do { - Texture2D* texture = spriteFrame->getTexture(); - CCASSERT(texture != nullptr, "Texture2D must be not null"); - if(texture == nullptr) break; - - Sprite *sprite = Sprite::createWithSpriteFrame(spriteFrame); - CCASSERT(sprite != nullptr, "Sprite must be not null"); - if(sprite == nullptr) break; - - ret = this->init(sprite, - spriteFrame->getRect(), - spriteFrame->isRotated(), - spriteFrame->getOffset(), - spriteFrame->getOriginalSize(), - capInsets); - } while (false); - + ret->autorelease(); return ret; } - bool Scale9Sprite::initWithSpriteFrame(SpriteFrame* spriteFrame) + CC_SAFE_DELETE(ret); + return nullptr; +} + +Scale9Sprite* Scale9Sprite::create(const std::string& filename, const Rect& rect, const Rect& capInsets) +{ + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->initWithFile(filename, rect, capInsets)) { - CCASSERT(spriteFrame != nullptr, "Invalid spriteFrame for sprite"); - bool pReturn = this->initWithSpriteFrame(spriteFrame, Rect::ZERO); - return pReturn; - } - bool Scale9Sprite::initWithSpriteFrameName(const std::string& spriteFrameName, - const Rect& capInsets) - { - bool ret = false; - do { - auto spriteFrameCache = SpriteFrameCache::getInstance(); - CCASSERT(spriteFrameCache != nullptr, - "SpriteFrameCache::getInstance() must be non-NULL"); - if(spriteFrameCache == nullptr) break; - - SpriteFrame *frame = spriteFrameCache->getSpriteFrameByName(spriteFrameName); - CCASSERT(frame != nullptr, StringUtils::format("CCSpriteFrame: %s must be non-NULL ", spriteFrameName.c_str()).c_str()); - if (frame == nullptr) break; - - ret = initWithSpriteFrame(frame, capInsets); - } while (false); - + ret->autorelease(); return ret; } - bool Scale9Sprite::initWithSpriteFrameName(const std::string& spriteFrameName) + CC_SAFE_DELETE(ret); + return nullptr; +} + +Scale9Sprite* Scale9Sprite::create(const std::string& filename, const Rect& rect) +{ + return create(filename, rect, Rect::ZERO); +} + +Scale9Sprite* Scale9Sprite::create(const Rect& capInsets, const std::string& file) +{ + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->initWithFile(capInsets, file)) { - bool pReturn = this->initWithSpriteFrameName(spriteFrameName, Rect::ZERO); - return pReturn; - } - - bool Scale9Sprite::init() - { - return this->init(nullptr, Rect::ZERO, Rect::ZERO); - } - - bool Scale9Sprite::init(Sprite* sprite, const Rect& rect, const Rect& capInsets) - { - return this->init(sprite, rect, false, capInsets); - } - - bool Scale9Sprite::init(Sprite* sprite, - const Rect& rect, - bool rotated, - const Rect& capInsets) - { - return init(sprite, rect, rotated, Vec2::ZERO, rect.size, capInsets); - } - - bool Scale9Sprite::init(Sprite* sprite, - const Rect& rect, - bool rotated, - const Vec2 &offset, - const Size &originalSize, - const Rect& capInsets) - { - bool ret = true; - if(sprite) - { - auto texture = sprite->getTexture(); - auto spriteFrame = sprite->getSpriteFrame(); - Rect actualCapInsets = capInsets; - - if (texture->isContain9PatchInfo()) - { - auto& parsedCapInset = texture->getSpriteFrameCapInset(spriteFrame); - if(!parsedCapInset.equals(Rect::ZERO)) - { - this->_isPatch9 = true; - if(capInsets.equals(Rect::ZERO)) - { - actualCapInsets = parsedCapInset; - } - - } - } - - ret = this->updateWithSprite(sprite, - rect, - rotated, - offset, - originalSize, - actualCapInsets); - } - + ret->autorelease(); return ret; } + CC_SAFE_DELETE(ret); + return nullptr; +} - bool Scale9Sprite::initWithBatchNode(cocos2d::SpriteBatchNode *batchnode, - const cocos2d::Rect &rect, - bool rotated, - const cocos2d::Rect &capInsets) - { - Sprite *sprite = Sprite::createWithTexture(batchnode->getTexture()); - return init(sprite, rect, rotated, capInsets); - } +Scale9Sprite* Scale9Sprite::create(const std::string& fileaname) +{ + return create(Rect::ZERO, fileaname); +} - bool Scale9Sprite::initWithBatchNode(cocos2d::SpriteBatchNode *batchnode, - const cocos2d::Rect &rect, - const cocos2d::Rect &capInsets) + +Scale9Sprite* Scale9Sprite::createWithSpriteFrame(SpriteFrame* spriteFrame, const Rect& capInsets) +{ + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->initWithSpriteFrame(spriteFrame, capInsets)) { - auto sprite = Sprite::createWithTexture(batchnode->getTexture()); - return init(sprite, rect, false, capInsets); + ret->autorelease(); + return ret; } - bool Scale9Sprite::initWithFile(const std::string& file, + CC_SAFE_DELETE(ret); + return nullptr; +} + +Scale9Sprite* Scale9Sprite::createWithSpriteFrame(SpriteFrame* spriteFrame) +{ + return createWithSpriteFrame(spriteFrame, Rect::ZERO); +} + +Scale9Sprite* Scale9Sprite::createWithSpriteFrameName(const std::string& spriteFrameName, const Rect& capInsets) +{ + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->initWithSpriteFrameName(spriteFrameName, capInsets)) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +Scale9Sprite* Scale9Sprite::createWithSpriteFrameName(const std::string& spriteFrameName) +{ + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->initWithSpriteFrameName(spriteFrameName, Rect::ZERO)) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + + log("Could not allocate Scale9Sprite()"); + return nullptr; +} + +Scale9Sprite::Scale9Sprite() +: _previousCenterRectNormalized(Rect(0,0,1,1)) +, _brightState(State::NORMAL) +, _renderingType(RenderingType::SLICE) +, _insetLeft(0) +, _insetTop(0) +, _insetRight(0) +, _insetBottom(0) +, _isPatch9(false) +{ +} + +Scale9Sprite::~Scale9Sprite() +{ +} + +bool Scale9Sprite::initWithFile(const Rect& capInsets, const std::string& file) +{ + // calls super + bool ret = Sprite::initWithFile(file); + setupSlice9(getTexture(), capInsets); + return ret; +} + +bool Scale9Sprite::initWithSpriteFrame(SpriteFrame* spriteFrame, const Rect& capInsets) +{ + // calls super + bool ret = Sprite::initWithSpriteFrame(spriteFrame); + setupSlice9(getTexture(), capInsets); + return ret; +} + +bool Scale9Sprite::initWithSpriteFrameName(const std::string& spriteFrameName, const Rect& capInsets) +{ + // calls super + bool ret = Sprite::initWithSpriteFrameName(spriteFrameName); + setupSlice9(getTexture(), capInsets); + return ret; +} + +bool Scale9Sprite::init() +{ + // calls super + bool ret = Sprite::init(); + setupSlice9(getTexture(), Rect::ZERO); + return ret; +} + +bool Scale9Sprite::init(Sprite* sprite, const Rect& rect, const Rect& capInsets) +{ + return init(sprite, rect, false, capInsets); +} + +bool Scale9Sprite::init(Sprite* sprite, const Rect& rect, bool rotated, const Rect& capInsets) +{ + return init(sprite, rect, rotated, Vec2::ZERO, rect.size, capInsets); +} + +bool Scale9Sprite::init(Sprite* sprite, const Rect& origRect, bool rotated, const Vec2 &offset, const Size &originalSize, const Rect& capInsets) +{ + bool ret = false; + + Rect actualCapInsets = capInsets; + Rect rect(origRect); + + if (sprite) { + auto texture = sprite->getTexture(); + + if (origRect.equals(Rect::ZERO)) + rect.size = texture->getContentSize(); + + auto spriteFrame = SpriteFrame::createWithTexture(texture, rect, rotated, offset, originalSize); + ret = initWithSpriteFrame(spriteFrame); + + if (!capInsets.equals(Rect::ZERO)) + setupSlice9(texture, capInsets); + else + setCapInsets(actualCapInsets); + } else { + ret = initWithTexture(nullptr, rect, rotated); + setupSlice9(nullptr, capInsets); + } + return ret; +} + +bool Scale9Sprite::initWithBatchNode(SpriteBatchNode *batchnode, const Rect &rect, bool rotated, const Rect &capInsets) +{ + auto sprite = Sprite::createWithTexture(batchnode->getTexture()); + return init(sprite, rect, rotated, capInsets); +} + +bool Scale9Sprite::initWithFile(const std::string& filename, const Rect& rect, const Rect& capInsets) +{ + // calls super + bool ret = Sprite::initWithFile(filename, rect); + setCapInsets(capInsets); + return ret; +} + +bool Scale9Sprite::initWithBatchNode(SpriteBatchNode *batchnode, const Rect &rect, const Rect &capInsets) +{ + auto sprite = Sprite::createWithTexture(batchnode->getTexture()); + return init(sprite, rect, false, capInsets); +} + +bool Scale9Sprite::updateWithBatchNode(SpriteBatchNode *batchnode, const Rect &originalRect, bool rotated, const Rect &capInsets) +{ + Sprite *sprite = Sprite::createWithTexture(batchnode->getTexture()); + return updateWithSprite(sprite, + originalRect, + rotated, + Vec2::ZERO, + originalRect.size, + capInsets); +} + +bool Scale9Sprite::updateWithSprite(Sprite* sprite, const Rect& rect, + bool rotated, const Rect& capInsets) +{ + return updateWithSprite(sprite, rect, rotated, Vec2::ZERO, rect.size, capInsets); +} + +bool Scale9Sprite::updateWithSprite(Sprite* sprite, + const Rect& textureRect, + bool rotated, + const Vec2 &offset, + const Size &originalSize, + const Rect& capInsets) +{ + SpriteFrame *spriteframe = SpriteFrame::createWithTexture(sprite->getTexture(), + CC_RECT_POINTS_TO_PIXELS(textureRect), + rotated, + CC_POINT_POINTS_TO_PIXELS(offset), + CC_SIZE_POINTS_TO_PIXELS(originalSize)); + setSpriteFrame(spriteframe); + setCapInsets(capInsets); + return true; +} + +Scale9Sprite* Scale9Sprite::resizableSpriteWithCapInsets(const Rect& capInsets) const +{ + // FIXME: there are no test cases for this method + Scale9Sprite* ret = new (std::nothrow) Scale9Sprite(); + if (ret && ret->init(const_cast(this), + _rect, + _rectRotated, + Vec2::ZERO, + _originalContentSize, + capInsets) ) { - CCASSERT(!file.empty(), "file must not be empty string!"); - if(file.empty()) - { - return false; - } - - auto sprite = Sprite::create(file); - return init(sprite, rect, capInsets); + ret->autorelease(); + return ret; } + CC_SAFE_DELETE(ret); + return nullptr; +} - bool Scale9Sprite::initWithFile(const std::string& file, const Rect& rect) - { - return initWithFile(file, rect, Rect::ZERO); - } +Scale9Sprite::State Scale9Sprite::getState() const +{ + return _brightState; +} - Scale9Sprite* Scale9Sprite::create() - { - Scale9Sprite *pReturn = new (std::nothrow) Scale9Sprite(); - if (pReturn && pReturn->init()) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } +void Scale9Sprite::setState(Scale9Sprite::State state) +{ + if (_brightState != state) { + _brightState = state; - Scale9Sprite* Scale9Sprite::create(const std::string& file, - const Rect& rect, - const Rect& capInsets) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithFile(file, rect, capInsets) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - - Scale9Sprite* Scale9Sprite::create(const std::string& file, const Rect& rect) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithFile(file, rect) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - - - Scale9Sprite* Scale9Sprite::create(const Rect& capInsets, - const std::string& file) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithFile(capInsets, file) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - - Scale9Sprite* Scale9Sprite::create(const std::string& file) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithFile(file) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - - Scale9Sprite* Scale9Sprite::createWithSpriteFrame(SpriteFrame* spriteFrame, - const Rect& capInsets) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithSpriteFrame(spriteFrame, capInsets) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - Scale9Sprite* Scale9Sprite::createWithSpriteFrame(SpriteFrame* spriteFrame) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithSpriteFrame(spriteFrame) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - - Scale9Sprite* Scale9Sprite::createWithSpriteFrameName(const std::string& spriteFrameName, - const Rect& capInsets) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithSpriteFrameName(spriteFrameName, capInsets) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - Scale9Sprite* Scale9Sprite::createWithSpriteFrameName(const std::string& spriteFrameName) - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->initWithSpriteFrameName(spriteFrameName) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - - log("Could not allocate Scale9Sprite()"); - return nullptr; - } - - void Scale9Sprite::cleanupSlicedSprites() - { - CC_SAFE_DELETE_ARRAY(_sliceIndices); - CC_SAFE_DELETE_ARRAY(_sliceVertices); - } - - - void Scale9Sprite::setBlendFunc(const BlendFunc &blendFunc) - { - _blendFunc = blendFunc; - applyBlendFunc(); - } - const BlendFunc &Scale9Sprite::getBlendFunc() const - { - return _blendFunc; - } - - void Scale9Sprite::updateBlendFunc(Texture2D *texture) - { - - // it is possible to have an untextured sprite - if (! texture || ! texture->hasPremultipliedAlpha()) - { - _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; - setOpacityModifyRGB(false); - } - else - { - _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; - setOpacityModifyRGB(true); - } - } - - void Scale9Sprite::applyBlendFunc() - { - if(_scale9Image) - _scale9Image->setBlendFunc(_blendFunc); - } - - bool Scale9Sprite::updateWithBatchNode(cocos2d::SpriteBatchNode *batchnode, - const cocos2d::Rect &originalRect, - bool rotated, - const cocos2d::Rect &capInsets) - { - Sprite *sprite = Sprite::createWithTexture(batchnode->getTexture()); - return this->updateWithSprite(sprite, - originalRect, - rotated, - Vec2::ZERO, - originalRect.size, - capInsets); - } - - bool Scale9Sprite::updateWithSprite(Sprite* sprite, - const Rect& rect, - bool rotated, - const Rect& capInsets) - { - return updateWithSprite(sprite, rect, rotated, Vec2::ZERO, rect.size, capInsets); - } - - bool Scale9Sprite::updateWithSprite(Sprite* sprite, - const Rect& textureRect, - bool rotated, - const Vec2 &offset, - const Size &originalSize, - const Rect& capInsets) - { - // Release old sprites - this->cleanupSlicedSprites(); - - updateBlendFunc(sprite?sprite->getTexture():nullptr); - - if(nullptr != sprite) - { - if (nullptr == sprite->getSpriteFrame()) - { - return false; - } - - if (nullptr == _scale9Image) - { - _scale9Image = sprite; - _scale9Image->retain(); - } - else - { - _scale9Image->setSpriteFrame(sprite->getSpriteFrame()); - } - } - else - { - CC_SAFE_RELEASE_NULL(_scale9Image); - } - - if (!_scale9Image) - { - return false; - } - - Rect rect(textureRect); - Size size(originalSize); - - // If there is no given rect - if ( rect.equals(Rect::ZERO) ) - { - // Get the texture size as original - Size textureSize = _scale9Image->getTexture()->getContentSize(); - - rect = Rect(0, 0, textureSize.width, textureSize.height); - } - - if( size.equals(Size::ZERO) ) - { - size = rect.size; - } - - // Set the given rect's size as original size - _spriteRect = rect; - _spriteFrameRotated = rotated; - _originalSize = size; - _preferredSize = size; - _offset = offset; - - _capInsetsInternal = capInsets; - - if (_scale9Enabled) - { - _scale9Image->setAnchorPoint(Vec2::ZERO); - _scale9Image->setPosition(Vec2::ZERO); - _sliceSpriteDirty = true; - } - - applyBlendFunc(); - - this->setState(_brightState); - - if(this->_isPatch9) - { - size.width = size.width - 2; - size.height = size.height - 2; - } - this->setContentSize(size); - - return true; - } - - void Scale9Sprite::configureSimpleModeRendering() - { - this->_insetLeft = 0; - this->_insetTop = 0; - this->_insetRight = 0; - this->_insetBottom = 0; - this->updateCapInset(); - } - - void Scale9Sprite::createSlicedSprites() - { - //todo create sliced sprite - if (_scale9Enabled) - { - Texture2D *tex = _scale9Image ? _scale9Image->getTexture() : nullptr; - - if (tex == nullptr) - { - return; - } - - if (_renderingType == RenderingType::SIMPLE) - { - this->configureSimpleModeRendering(); - } - - auto capInsets = CC_RECT_POINTS_TO_PIXELS(_capInsetsInternal); - auto textureRect = CC_RECT_POINTS_TO_PIXELS(_spriteRect); - auto spriteRectSize = _spriteRect.size; - auto originalSize = CC_SIZE_POINTS_TO_PIXELS(_originalSize); - auto offset = CC_POINT_POINTS_TO_PIXELS(_offset); - - Vec4 offsets; - offsets.x = offset.x + (originalSize.width - textureRect.size.width) / 2; - offsets.w = offset.y + (originalSize.height - textureRect.size.height) / 2; - offsets.z = originalSize.width - textureRect.size.width - offsets.x; - offsets.y = originalSize.height - textureRect.size.height - offsets.w; - - //handle .9.png - if (_isPatch9) - { - originalSize = Size(originalSize.width - 2, originalSize.height-2); - } - - - if(capInsets.equals(Rect::ZERO)) - { - capInsets = Rect(originalSize.width/3, originalSize.height/3, - originalSize.width/3, originalSize.height/3); - } - - auto uv = this->calculateUV(tex, capInsets, originalSize, offsets); - auto vertices = this->calculateVertices(capInsets, originalSize, offsets); - auto triangles = this->calculateTriangles(uv, vertices); - - auto polyInfo = _scale9Image->getPolygonInfo(); - polyInfo.setTriangles(triangles); - _scale9Image->setPolygonInfo(polyInfo); - } - } - - void Scale9Sprite::setContentSize(const Size &size) - { - if (_contentSize.equals(size)) - { - return; - } - Node::setContentSize(size); - _preferredSize = size; - _sliceSpriteDirty = true; - this->adjustNoneScale9ImagePosition(); - } - - Scale9Sprite* Scale9Sprite::resizableSpriteWithCapInsets(const Rect& capInsets) const - { - Scale9Sprite* pReturn = new (std::nothrow) Scale9Sprite(); - if ( pReturn && pReturn->init(_scale9Image, - _spriteRect, - _spriteFrameRotated, - Vec2::ZERO, - _originalSize, - capInsets) ) - { - pReturn->autorelease(); - return pReturn; - } - CC_SAFE_DELETE(pReturn); - return nullptr; - } - - Scale9Sprite::State Scale9Sprite::getState()const - { - return _brightState; - } - - void Scale9Sprite::setState(cocos2d::ui::Scale9Sprite::State state) - { - auto getScale9ImageTexture = [this] { - return _scale9Image != nullptr ? _scale9Image->getTexture() : nullptr; - }; GLProgramState *glState = nullptr; switch (state) { - case State::NORMAL: - { - glState = GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, getScale9ImageTexture()); + case State::NORMAL: + glState = GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, getTexture()); + break; + case State::GRAY: + glState = GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_GRAYSCALE, getTexture()); + default: + break; } - break; - case State::GRAY: - { - glState = GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_GRAYSCALE, getScale9ImageTexture()); - } - default: - break; - } - + setGLProgramState(glState); _brightState = state; } - -/** sets the opacity. - @warning If the texture has premultiplied alpha then, the R, G and B channels will be modified. - Values goes from 0 to 255, where 255 means fully opaque. -*/ - - - - void Scale9Sprite::updateCapInset() - { - Rect insets; - insets = Rect(_insetLeft, - _insetTop, - _originalSize.width-_insetLeft-_insetRight, - _originalSize.height-_insetTop-_insetBottom); - this->setCapInsets(insets); - } - - - void Scale9Sprite::setSpriteFrame(SpriteFrame * spriteFrame, const Rect& capInsets) - { - Sprite * sprite = Sprite::createWithTexture(spriteFrame->getTexture()); - this->updateWithSprite(sprite, - spriteFrame->getRect(), - spriteFrame->isRotated(), - spriteFrame->getOffset(), - spriteFrame->getOriginalSize(), - capInsets); - - // Reset insets - this->_insetLeft = capInsets.origin.x; - this->_insetTop = capInsets.origin.y; - this->_insetRight = _originalSize.width - _insetLeft - capInsets.size.width; - this->_insetBottom = _originalSize.height - _insetTop - capInsets.size.height; - } - - void Scale9Sprite::setPreferredSize(const Size& preferredSize) - { - this->setContentSize(preferredSize); - } - - - void Scale9Sprite::setCapInsets(const Rect& capInsets) - { - Size contentSize = this->_contentSize; - this->updateWithSprite(this->_scale9Image, - _spriteRect, - _spriteFrameRotated, - _offset, - _originalSize, - capInsets); - this->_insetLeft = capInsets.origin.x; - this->_insetTop = capInsets.origin.y; - this->_insetRight = _originalSize.width - _insetLeft - capInsets.size.width; - this->_insetBottom = _originalSize.height - _insetTop - capInsets.size.height; - this->setContentSize(contentSize); - } - - - void Scale9Sprite::setInsetLeft(float insetLeft) - { - this->_insetLeft = insetLeft; - this->updateCapInset(); - } - - void Scale9Sprite::setInsetTop(float insetTop) - { - this->_insetTop = insetTop; - this->updateCapInset(); - } - - void Scale9Sprite::setInsetRight(float insetRight) - { - this->_insetRight = insetRight; - this->updateCapInset(); - } - - void Scale9Sprite::setInsetBottom(float insetBottom) - { - this->_insetBottom = insetBottom; - this->updateCapInset(); - } - - void Scale9Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) - { - if (_scale9Image && _scale9Enabled) { -#if CC_USE_CULLING - // Don't do calculate the culling if the transform was not updated - auto visitingCamera = Camera::getVisitingCamera(); - auto defaultCamera = Camera::getDefaultCamera(); - if (visitingCamera == defaultCamera) { - _insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY)|| visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; - } - else - { - _insideBounds = renderer->checkVisibility(transform, _contentSize); - } - - if(_insideBounds) -#endif - { - auto texture = _scale9Image->getTexture(); - auto programState = _scale9Image->getGLProgramState(); - auto blendFunc = _scale9Image->getBlendFunc(); - auto& polyInfo = _scale9Image->getPolygonInfo(); - auto globalZOrder = _scale9Image->getGlobalZOrder(); - // ETC1 ALPHA support - _trianglesCommand.init(globalZOrder,texture, programState, blendFunc, polyInfo.triangles, transform, flags); - renderer->addCommand(&_trianglesCommand); - -#if CC_SPRITE_DEBUG_DRAW - _debugDrawNode->clear(); - auto count = polyInfo.triangles.indexCount/3; - auto indices = polyInfo.triangles.indices; - auto verts = polyInfo.triangles.verts; - for(ssize_t i = 0; i < count; i++) - { - //draw 3 lines - Vec3 from =verts[indices[i*3]].vertices; - Vec3 to = verts[indices[i*3+1]].vertices; - _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); - - from =verts[indices[i*3+1]].vertices; - to = verts[indices[i*3+2]].vertices; - _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); - - from =verts[indices[i*3+2]].vertices; - to = verts[indices[i*3]].vertices; - _debugDrawNode->drawLine(Vec2(from.x, from.y), Vec2(to.x,to.y), Color4F::WHITE); - } -#endif //CC_SPRITE_DEBUG_DRAW - } - } - } - - void Scale9Sprite::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) - { - // quick return if not visible. children won't be drawn. - if (!_visible) - { - return; - } - if (_scale9Enabled && _sliceSpriteDirty) { - this->createSlicedSprites(); - _sliceSpriteDirty = false; - } - - uint32_t flags = processParentFlags(parentTransform, parentFlags); - - // IMPORTANT: - // To ease the migration to v3.0, we still support the Mat4 stack, - // but it is deprecated and your code should not rely on it - Director* director = Director::getInstance(); - CCASSERT(nullptr != director, "Director is null when setting matrix stack"); - director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); - - int i = 0; // used by _children - - sortAllChildren(); - - // - // draw children and protectedChildren zOrder < 0 - // - for(auto size = _children.size(); i < size; i++) - { - auto node = _children.at(i); - - if ( node && node->getLocalZOrder() < 0 ) - node->visit(renderer, _modelViewTransform, flags); - else - break; - } - - if (!_scale9Enabled && _scale9Image && _scale9Image->getLocalZOrder() < 0 ) - { - _scale9Image->visit(renderer, _modelViewTransform, flags); - } - - // draw self - // - if (isVisitableByVisitingCamera()) - this->draw(renderer, _modelViewTransform, flags); - - if (!_scale9Enabled && _scale9Image && _scale9Image->getLocalZOrder() >= 0 ) - { - _scale9Image->visit(renderer, _modelViewTransform, flags); - } - - for(auto it=_children.cbegin()+i, itCend = _children.cend(); it != itCend; ++it) - (*it)->visit(renderer, _modelViewTransform, flags); - - // FIX ME: Why need to set _orderOfArrival to 0?? - // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 - // setOrderOfArrival(0); - - director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - - } - - Size Scale9Sprite::getOriginalSize()const - { - return _originalSize; - } - - - Size Scale9Sprite::getPreferredSize() const - { - return _preferredSize; - } - - Rect Scale9Sprite::getCapInsets()const - { - return _capInsetsInternal; - } - - - float Scale9Sprite::getInsetLeft()const - { - return this->_insetLeft; - } - - float Scale9Sprite::getInsetTop()const - { - return this->_insetTop; - } - - float Scale9Sprite::getInsetRight()const - { - return this->_insetRight; - } - - float Scale9Sprite::getInsetBottom()const - { - return this->_insetBottom; - } - - void Scale9Sprite::setScale9Enabled(bool enabled) - { - if (_scale9Enabled == enabled) - { - return; - } - _scale9Enabled = enabled; - - this->cleanupSlicedSprites(); - - //we must invalid the transform when toggling scale9enabled - _transformUpdated = _transformDirty = _inverseDirty = true; - - if (_scale9Enabled) - { - if (_scale9Image) - { - this->updateWithSprite(this->_scale9Image, - _spriteRect, - _spriteFrameRotated, - Vec2::ZERO, - _originalSize, - _capInsetsInternal); - } - } - else - { - if (_scale9Image) - { - auto quad = _scale9Image->getQuad(); - PolygonInfo polyInfo; - polyInfo.setQuad(&quad); - _scale9Image->setPolygonInfo(polyInfo); - } - - } - this->adjustNoneScale9ImagePosition(); - } - - bool Scale9Sprite::isScale9Enabled() const - { - return _scale9Enabled; - } - - void Scale9Sprite::setAnchorPoint(const cocos2d::Vec2 &position) - { - Node::setAnchorPoint(position); - if (!_scale9Enabled) - { - if (_scale9Image) - { - _nonSliceSpriteAnchor = position; - _scale9Image->setAnchorPoint(position); - this->adjustNoneScale9ImagePosition(); - } - } - } - - void Scale9Sprite::adjustNoneScale9ImagePosition() - { - if (_scale9Image) - { - if (!_scale9Enabled) { - _scale9Image->setAnchorPoint(_nonSliceSpriteAnchor); - _scale9Image->setPosition(_contentSize.width * _scale9Image->getAnchorPoint().x, - _contentSize.height * _scale9Image->getAnchorPoint().y); - - } - } - } - - void Scale9Sprite::updateDisplayedColor(const cocos2d::Color3B &parentColor) - { - _displayedColor.r = _realColor.r * parentColor.r/255.0; - _displayedColor.g = _realColor.g * parentColor.g/255.0; - _displayedColor.b = _realColor.b * parentColor.b/255.0; - updateColor(); - - if (_scale9Image) - { - _scale9Image->updateDisplayedColor(_displayedColor); - } - - if (_cascadeColorEnabled) - { - for(const auto &child : _children) - { - child->updateDisplayedColor(_displayedColor); - } - } - } - - void Scale9Sprite::updateDisplayedOpacity(GLubyte parentOpacity) - { - _displayedOpacity = _realOpacity * parentOpacity/255.0; - updateColor(); - - if (_scale9Image) - { - _scale9Image->updateDisplayedOpacity(_displayedOpacity); - } - - if (_cascadeOpacityEnabled) - { - for(auto child : _children) - { - child->updateDisplayedOpacity(_displayedOpacity); - } - } - } - - void Scale9Sprite::disableCascadeColor() - { - for(auto child : _children) - { - child->updateDisplayedColor(Color3B::WHITE); - } - - if (_scale9Image) - { - _scale9Image->updateDisplayedColor(Color3B::WHITE); - } - } - - void Scale9Sprite::disableCascadeOpacity() - { - _displayedOpacity = _realOpacity; - - for(auto child : _children){ - child->updateDisplayedOpacity(255); - } - } - - void Scale9Sprite::setGLProgram(GLProgram *glprogram) { - Node::setGLProgram(glprogram); - if (_scale9Image) { - _scale9Image->setGLProgram(glprogram); - } - } - - void Scale9Sprite::setGLProgramState(GLProgramState *glProgramState) { - Node::setGLProgramState(glProgramState); - if (_scale9Image) { - _scale9Image->setGLProgramState(glProgramState); - } - } - - Sprite* Scale9Sprite::getSprite()const - { - return _scale9Image; - } - - void Scale9Sprite::setFlippedX(bool flippedX) - { - - float realScale = this->getScaleX(); - _flippedX = flippedX; - this->setScaleX(realScale); - } - - void Scale9Sprite::setFlippedY(bool flippedY) - { - float realScale = this->getScaleY(); - _flippedY = flippedY; - this->setScaleY(realScale); - } - - bool Scale9Sprite::isFlippedX()const - { - return _flippedX; - } - - bool Scale9Sprite::isFlippedY()const - { - return _flippedY; - } - - void Scale9Sprite::setScaleX(float scaleX) - { - if (_flippedX) { - scaleX = scaleX * -1; - } - Node::setScaleX(scaleX); - } - - void Scale9Sprite::setScaleY(float scaleY) - { - if (_flippedY) { - scaleY = scaleY * -1; - } - Node::setScaleY(scaleY); - } - - void Scale9Sprite::setScale(float scale) - { - this->setScaleX(scale); - this->setScaleY(scale); - this->setScaleZ(scale); - } - - void Scale9Sprite::setScale(float scaleX, float scaleY) - { - this->setScaleX(scaleX); - this->setScaleY(scaleY); - } - - float Scale9Sprite::getScaleX()const - { - float originalScale = Node::getScaleX(); - if (_flippedX) - { - originalScale = originalScale * -1.0f; - } - return originalScale; - } - - float Scale9Sprite::getScaleY()const - { - float originalScale = Node::getScaleY(); - if (_flippedY) - { - originalScale = originalScale * -1.0f; - } - return originalScale; - } - - float Scale9Sprite::getScale()const - { - CCASSERT(this->getScaleX() == this->getScaleY(), - "Scale9Sprite#scale. ScaleX != ScaleY. Don't know which one to return"); - return this->getScaleX(); - } - - void Scale9Sprite::setCameraMask(unsigned short mask, bool applyChildren) - { - Node::setCameraMask(mask, applyChildren); - - if(_scale9Image) - _scale9Image->setCameraMask(mask,applyChildren); - } - - // (0,0) O = capInsets.origin - // v0---------------------- - // | | | | - // | | | | - // v1-------O------+------| - // | | | | - // | | | | - // v2-------+------+------| - // | | | | - // | | | | - // v3-------------------- (1,1) (texture coordinate is flipped) - // u0 u1 u2 u3 - std::vector Scale9Sprite::calculateUV(Texture2D *tex, - const Rect& capInsets, - const Size& originalSize, - const Vec4& offsets) - { - auto atlasWidth = tex->getPixelsWide(); - auto atlasHeight = tex->getPixelsHigh(); - - //calculate texture coordinate - float leftWidth = 0, centerWidth = 0, rightWidth = 0; - float topHeight = 0, centerHeight = 0, bottomHeight = 0; - - if (_spriteFrameRotated) - { - rightWidth = capInsets.origin.y - offsets.y; - centerWidth = capInsets.size.height; - leftWidth = originalSize.height - centerWidth - capInsets.origin.y - offsets.w; - - topHeight = capInsets.origin.x - offsets.x; - centerHeight = capInsets.size.width; - bottomHeight = originalSize.width - (capInsets.origin.x + centerHeight) - offsets.z; - } - else - { - leftWidth = capInsets.origin.x - offsets.x; - centerWidth = capInsets.size.width; - rightWidth = originalSize.width - (capInsets.origin.x + centerWidth) - offsets.z; - - topHeight = capInsets.origin.y - offsets.y; - centerHeight = capInsets.size.height; - bottomHeight = originalSize.height - (capInsets.origin.y + centerHeight) - offsets.w; - } - - - if(leftWidth<0) - { - centerWidth += leftWidth; - leftWidth = 0; - } - if(rightWidth<0) - { - centerWidth += rightWidth; - rightWidth = 0; - } - - if(topHeight<0) - { - centerHeight += topHeight; - topHeight = 0; - } - if(bottomHeight<0) - { - centerHeight += bottomHeight; - bottomHeight = 0; - } - - auto textureRect = CC_RECT_POINTS_TO_PIXELS(_spriteRect); - //handle .9.png - if (_isPatch9) - { - //This magic number is used to avoiding artifact with .9.png format. - float offset = 1.3f; - textureRect = Rect(textureRect.origin.x + offset, - textureRect.origin.y + offset, - textureRect.size.width - 2, - textureRect.size.height - 2); - } - - //uv computation should take spritesheet into account. - float u0, u1, u2, u3; - float v0, v1, v2, v3; - if (_spriteFrameRotated) - { - u0 = textureRect.origin.x / atlasWidth; - u1 = (leftWidth + textureRect.origin.x) / atlasWidth; - u2 = (leftWidth + centerWidth + textureRect.origin.x) / atlasWidth; - u3 = (textureRect.origin.x + textureRect.size.height) / atlasWidth; - - v3 = textureRect.origin.y / atlasHeight; - v2 = (topHeight + textureRect.origin.y) / atlasHeight; - v1 = (topHeight + centerHeight + textureRect.origin.y) / atlasHeight; - v0 = (textureRect.origin.y + textureRect.size.width) / atlasHeight; - } - else - { - u0 = textureRect.origin.x / atlasWidth; - u1 = (leftWidth + textureRect.origin.x) / atlasWidth; - u2 = (leftWidth + centerWidth + textureRect.origin.x) / atlasWidth; - u3 = (textureRect.origin.x + textureRect.size.width) / atlasWidth; - - v0 = textureRect.origin.y / atlasHeight; - v1 = (topHeight + textureRect.origin.y) / atlasHeight; - v2 = (topHeight + centerHeight + textureRect.origin.y) / atlasHeight; - v3 = (textureRect.origin.y + textureRect.size.height) / atlasHeight; - } - - - std::vector uvCoordinates; - if (_renderingType == RenderingType::SIMPLE) - { - uvCoordinates = {Vec2(u0,v3), Vec2(u3,v0)}; - } - else - { - uvCoordinates = {Vec2(u0,v3), Vec2(u1,v2), Vec2(u2,v1), Vec2(u3,v0)}; - } - - return uvCoordinates; - } - - // - // y3----------------------(preferedSize.width, preferedSize.height) - // | | | | - // | | | | - // y2-------O------+------| - // | | | | - // | | | | - // y1-------+------+------| - // | | | | - // | | | | - //x0,y0-------------------- - // x1 x2 x3 - std::vector Scale9Sprite::calculateVertices(const Rect& capInsets, - const Size& originalSize, - const Vec4& offsets) - { - - float offsetLeft = offsets.x / CC_CONTENT_SCALE_FACTOR(); - float offsetTop = offsets.y / CC_CONTENT_SCALE_FACTOR(); - float offsetRight = offsets.z / CC_CONTENT_SCALE_FACTOR(); - float offsetBottom = offsets.w / CC_CONTENT_SCALE_FACTOR(); - - std::vector vertices; - if (_renderingType == RenderingType::SIMPLE) - { - float hScale = _preferredSize.width / (originalSize.width / CC_CONTENT_SCALE_FACTOR()); - float vScale = _preferredSize.height / (originalSize.height / CC_CONTENT_SCALE_FACTOR()); - - vertices = {Vec2(offsetLeft * hScale, offsetBottom * vScale), - Vec2(_preferredSize.width - offsetRight * hScale, _preferredSize.height - offsetTop * vScale)}; - } - else - { - float leftWidth = 0, centerWidth = 0, rightWidth = 0; - float topHeight = 0, centerHeight = 0, bottomHeight = 0; - - leftWidth = capInsets.origin.x; - centerWidth = capInsets.size.width; - rightWidth = originalSize.width - (leftWidth + centerWidth); - - topHeight = capInsets.origin.y; - centerHeight = capInsets.size.height; - bottomHeight = originalSize.height - (topHeight + centerHeight); - - leftWidth = leftWidth / CC_CONTENT_SCALE_FACTOR(); - rightWidth = rightWidth / CC_CONTENT_SCALE_FACTOR(); - centerWidth = centerWidth / CC_CONTENT_SCALE_FACTOR(); - topHeight = topHeight / CC_CONTENT_SCALE_FACTOR(); - bottomHeight = bottomHeight / CC_CONTENT_SCALE_FACTOR(); - centerHeight = centerHeight / CC_CONTENT_SCALE_FACTOR(); - - float sizableWidth = _preferredSize.width - leftWidth - rightWidth; - float sizableHeight = _preferredSize.height - topHeight - bottomHeight; - - leftWidth -= offsetLeft; - rightWidth -= offsetRight; - topHeight -= offsetTop; - bottomHeight -= offsetBottom; - - float hScale = sizableWidth / centerWidth; - float vScale = sizableHeight / centerHeight; - - if(leftWidth<0) - { - offsetLeft -= leftWidth * (hScale - 1.0f); - sizableWidth += leftWidth * hScale; - leftWidth = 0; - } - if(rightWidth<0) - { - sizableWidth += rightWidth * hScale; - rightWidth = 0; - } - if(topHeight<0) - { - sizableHeight += topHeight * vScale; - topHeight = 0; - } - if(bottomHeight<0) - { - offsetBottom -= bottomHeight * (vScale - 1.0f); - sizableHeight += bottomHeight * vScale; - bottomHeight = 0; - } - - float x0,x1,x2,x3; - float y0,y1,y2,y3; - if(sizableWidth >= 0) - { - x0 = offsetLeft; - x1 = x0 + leftWidth; - x2 = x1 + sizableWidth; - x3 = x2 + rightWidth; - } - else - { - float xScale = _preferredSize.width / (leftWidth + rightWidth); - x0 = offsetLeft; - x1 = x2 = offsetLeft + leftWidth * xScale; - x3 = x2 + rightWidth * xScale; - } - - if(sizableHeight >= 0) - { - y0 = offsetBottom; - y1 = y0 + bottomHeight; - y2 = y1 + sizableHeight; - y3 = y2 + topHeight; - } - else - { - float yScale = _preferredSize.height / (topHeight + bottomHeight); - y0 = offsetBottom; - y1 = y2 = y0 + bottomHeight * yScale; - y3 = y2 + topHeight * yScale; - } - - vertices = {Vec2(x0,y0), Vec2(x1,y1), Vec2(x2,y2), Vec2(x3,y3)}; - } - return vertices; - } - - TrianglesCommand::Triangles Scale9Sprite::calculateTriangles(const std::vector& uv, - const std::vector& vertices) - { - const unsigned short slicedTotalVertexCount = powf(uv.size(),2); - const unsigned short slicedTotalIndices = 6 * powf(uv.size() -1, 2); - CC_SAFE_DELETE_ARRAY(_sliceVertices); - CC_SAFE_DELETE_ARRAY(_sliceIndices); - - _sliceVertices = new (std::nothrow) V3F_C4B_T2F[slicedTotalVertexCount]; - _sliceIndices = new (std::nothrow) unsigned short[slicedTotalIndices]; - - unsigned short indicesStart = 0; - const unsigned short indicesOffset = 6; - const unsigned short sliceQuadIndices[] = {4,0,5, 1,5,0}; - const unsigned short simpleQuadIndices[] = {0,1,2, 3,2,1}; - - auto displayedColor = _scale9Image->getDisplayedColor(); - auto displayedOpacity = _scale9Image->getDisplayedOpacity(); - Color4B color4( displayedColor.r, displayedColor.g, displayedColor.b, displayedOpacity ); - - // special opacity for premultiplied textures - if (_scale9Image->isOpacityModifyRGB()) - { - color4.r *= displayedOpacity/255.0f; - color4.g *= displayedOpacity/255.0f; - color4.b *= displayedOpacity/255.0f; - } - - int vertexCount = (int)(vertices.size() - 1); - - for (int j = 0; j <= vertexCount; ++j) - { - for (int i = 0; i <= vertexCount; ++i) - { - V3F_C4B_T2F vertextData; - vertextData.vertices.x = vertices[i].x; - vertextData.vertices.y = vertices[j].y; - - if (_spriteFrameRotated) - { - vertextData.texCoords.u = uv[j].x; - vertextData.texCoords.v = uv[i].y; - } - else - { - vertextData.texCoords.u = uv[i].x; - vertextData.texCoords.v = uv[j].y; - } - - vertextData.colors = color4; - - //if slice mode - if (_renderingType == RenderingType::SLICE) - { - memcpy(_sliceVertices + i + j * 4, &vertextData, sizeof(V3F_C4B_T2F)); - } - else - { - memcpy(_sliceVertices + i + j * 2, &vertextData, sizeof(V3F_C4B_T2F)); - } - } - } - - if (_renderingType == RenderingType::SLICE) - { - for (int j = 0; j <= vertexCount; ++j) - { - for (int i = 0; i <= vertexCount; ++i) - { - if (i < 3 && j < 3) - { - memcpy(_sliceIndices + indicesStart, sliceQuadIndices, indicesOffset * sizeof(unsigned short)); - - for (int k = 0; k < indicesOffset; ++k) - { - unsigned short actualIndex = (i + j * 3) * indicesOffset; - _sliceIndices[k + actualIndex] = _sliceIndices[k + actualIndex] + j * 4 + i; - } - indicesStart = indicesStart + indicesOffset; - } - - } - } - } - - if (_renderingType == RenderingType::SIMPLE) - { - memcpy(_sliceIndices, simpleQuadIndices, indicesOffset * sizeof(unsigned short)); - } - - TrianglesCommand::Triangles triangles; - triangles.vertCount = slicedTotalVertexCount; - triangles.indexCount = slicedTotalIndices; - triangles.verts = _sliceVertices; - triangles.indices = _sliceIndices; - - return triangles; - } - - void Scale9Sprite::setRenderingType(cocos2d::ui::Scale9Sprite::RenderingType type) - { - if (_renderingType == type) - { - return; - } +} + +void Scale9Sprite::setSpriteFrame(SpriteFrame * spriteFrame, const Rect& capInsets) +{ + setSpriteFrame(spriteFrame); + setCapInsets(capInsets); +} + +void Scale9Sprite::setPreferredSize(const Size& preferredSize) +{ + setContentSize(preferredSize); +} + +void Scale9Sprite::setInsetLeft(float insetLeft) +{ + _insetLeft = insetLeft; + updateCapInset(); +} + +void Scale9Sprite::setInsetTop(float insetTop) +{ + _insetTop = insetTop; + updateCapInset(); +} + +void Scale9Sprite::setInsetRight(float insetRight) +{ + _insetRight = insetRight; + updateCapInset(); +} + +void Scale9Sprite::setInsetBottom(float insetBottom) +{ + _insetBottom = insetBottom; + updateCapInset(); +} + +void Scale9Sprite::updateCapInset() +{ + Rect capInsets(_insetLeft, + _insetTop, + _originalContentSize.width - _insetRight - _insetLeft, + _originalContentSize.height - _insetBottom -_insetTop); + setCapInsets(capInsets); +} + +Size Scale9Sprite::getOriginalSize() const +{ + return _originalContentSize; +} + +Size Scale9Sprite::getPreferredSize() const +{ + return getContentSize(); +} + +float Scale9Sprite::getInsetLeft() const +{ + return _insetLeft; +} + +float Scale9Sprite::getInsetTop() const +{ + return _insetTop; +} + +float Scale9Sprite::getInsetRight() const +{ + return _insetRight; +} + +float Scale9Sprite::getInsetBottom() const +{ + return _insetBottom; +} + +void Scale9Sprite::setScale9Enabled(bool enabled) +{ + RenderingType type = enabled ? RenderingType::SLICE : RenderingType::SIMPLE; + setRenderingType(type); + + // only enable strech en scale9 is enabled + // for backward compatibiliy, since Sprite streches the texture no matter the rendering type + setStrechEnabled(enabled); +} + +bool Scale9Sprite::isScale9Enabled() const +{ + return (_renderingType == RenderingType::SLICE); +} + +Sprite* Scale9Sprite::getSprite() +{ + return this; +} + +// (0,0) O = capInsets.origin +// v0---------------------- +// | | | | +// | | | | +// v1-------O------+------| +// | | | | +// | | | | +// v2-------+------+------| +// | | | | +// | | | | +// v3-------------------- (1,1) (texture coordinate is flipped) +// u0 u1 u2 u3 + +// +// y3----------------------(preferedSize.width, preferedSize.height) +// | | | | +// | | | | +// y2-------O------+------| +// | | | | +// | | | | +// y1-------+------+------| +// | | | | +// | | | | +//x0,y0-------------------- +// x1 x2 x3 + +void Scale9Sprite::setRenderingType(Scale9Sprite::RenderingType type) +{ + if (_renderingType != type) { _renderingType = type; - _sliceSpriteDirty = true; - } - - Scale9Sprite::RenderingType Scale9Sprite::getRenderingType()const - { - return _renderingType; - } - - void Scale9Sprite::resetRender() - { - // Release old sprites - this->cleanupSlicedSprites(); - - CC_SAFE_RELEASE_NULL(this->_scale9Image); - } - - void Scale9Sprite::setGlobalZOrder(float globalZOrder) - { - Node::setGlobalZOrder(globalZOrder); - if (_scale9Image) - { - _scale9Image->setGlobalZOrder(globalZOrder); + if (_renderingType == RenderingType::SIMPLE) { + _previousCenterRectNormalized = getCenterRectNormalized(); + setCenterRectNormalized(Rect(0,0,1,1)); + } else { + setCenterRectNormalized(_previousCenterRectNormalized); } } +} -}} +Scale9Sprite::RenderingType Scale9Sprite::getRenderingType() const +{ + return _renderingType; +} + +void Scale9Sprite::resetRender() +{ + // nothing. keeping it to be backwards compatible +} + +void Scale9Sprite::setupSlice9(Texture2D* texture, const Rect& capInsets) +{ + setCapInsets(capInsets); + + if (texture && texture->isContain9PatchInfo()) { + auto& parsedCapInset = texture->getSpriteFrameCapInset(getSpriteFrame()); + + if(!parsedCapInset.equals(Rect::ZERO)) + { + // adjust texture rect. 1.3f seems to be the magic number + // to avoid artifacts + auto rect = getTextureRect(); + rect.origin.x += 1.3f; + rect.origin.y += 1.3f; + rect.size.width -= 2.0f; + rect.size.height -= 2.0f; + setTextureRect(rect); + + // and after adjusting the texture, set the new cap insets + _isPatch9 = true; + setCapInsets(parsedCapInset); + } + } +} + +void Scale9Sprite::setCapInsets(const cocos2d::Rect &insetsCopy) +{ + Rect insets = insetsCopy; + + // When Insets == Zero --> we should use a 1/3 of its untrimmed size + if (insets.equals(Rect::ZERO)) { + insets = Rect( _originalContentSize.width / 3.0f, + _originalContentSize.height / 3.0f, + _originalContentSize.width / 3.0f, + _originalContentSize.height / 3.0f); + } + + // we have to convert from untrimmed to trimmed + // Sprite::setCenterRect is using trimmed values (to be compatible with Cocos Creator) + // Scale9Sprite::setCapInsects uses untrimmed values (which makes more sense) + + // use _rect coordinates. recenter origin to calculate the + // intersecting rectangle + insets.origin.x -= _offsetPosition.x; + insets.origin.y -= _offsetPosition.y; + + // intersecting rectangle + const float x1 = std::max(insets.origin.x, 0.0f); + const float y1 = std::max(insets.origin.y, 0.0f); + const float x2 = std::min(insets.origin.x + insets.size.width, 0.0f + _rect.size.width); + const float y2 = std::min(insets.origin.y + insets.size.height, 0.0f + _rect.size.height); + + // centerRect uses the trimmed frame origin as 0,0. + // so, recenter inset rect + insets.setRect(x1, + y1, + x2 - x1, + y2 - y1); + + setCenterRect(insets); +} + +Rect Scale9Sprite::getCapInsets() const +{ + return getCenterRect(); +} diff --git a/cocos/ui/UIScale9Sprite.h b/cocos/ui/UIScale9Sprite.h index e09bfdd0ab..980b1c0ae3 100644 --- a/cocos/ui/UIScale9Sprite.h +++ b/cocos/ui/UIScale9Sprite.h @@ -1,18 +1,18 @@ /**************************************************************************** Copyright (c) 2013-2016 Chukong Technologies Inc. - + http://www.cocos2d-x.org - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,7 +25,7 @@ #ifndef __cocos2d_libs__UIScale9Sprite__ #define __cocos2d_libs__UIScale9Sprite__ -#include "2d/CCNode.h" +#include "2d/CCSprite.h" #include "2d/CCSpriteFrame.h" #include "2d/CCSpriteBatchNode.h" #include "platform/CCPlatformMacros.h" @@ -38,9 +38,10 @@ */ NS_CC_BEGIN class DrawNode; +class Texture2D; namespace ui { - + /** *@brief A 9-slice sprite for cocos2d-x. * @@ -53,7 +54,7 @@ namespace ui { * Then you could call any methods of Sprite class with the return pointers. * */ - class CC_GUI_DLL Scale9Sprite : public Node , public cocos2d::BlendProtocol + class CC_GUI_DLL Scale9Sprite : public Sprite { public: /** @@ -69,7 +70,7 @@ namespace ui { * @lua NA */ virtual ~Scale9Sprite(); - + /** * Builtin shader state. * Currently support Normal and Gray state. @@ -79,22 +80,22 @@ namespace ui { NORMAL, GRAY }; - + enum class RenderingType { SIMPLE, SLICE }; - + public: - + /** * @brief Create an empty Scale9Sprite. * * @return A Scale9Sprite instance. */ static Scale9Sprite* create(); - + /** * Creates a 9-slice sprite with a texture file, a delimitation zone and * with the specified cap insets. @@ -106,7 +107,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* create(const std::string& file, const Rect& rect, const Rect& capInsets); - + /** * Creates a 9-slice sprite with a texture file. The whole texture will be * broken down into a 3×3 grid of equal blocks. @@ -117,7 +118,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* create(const Rect& capInsets, const std::string& file); - + /** * Creates a 9-slice sprite with a texture file and a delimitation zone. The * texture will be broken down into a 3×3 grid of equal blocks. @@ -128,7 +129,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* create(const std::string& file, const Rect& rect); - + /** * Creates a 9-slice sprite with a texture file. The whole texture will be * broken down into a 3×3 grid of equal blocks. @@ -138,7 +139,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* create(const std::string& file); - + /** * Creates a 9-slice sprite with an sprite frame. * Once the sprite is created, you can then call its "setContentSize:" method @@ -150,7 +151,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* createWithSpriteFrame(SpriteFrame* spriteFrame); - + /** * Creates a 9-slice sprite with an sprite frame and the centre of its zone. * Once the sprite is created, you can then call its "setContentSize:" method @@ -163,7 +164,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* createWithSpriteFrame(SpriteFrame* spriteFrame, const Rect& capInsets); - + /** * Creates a 9-slice sprite with an sprite frame name. * Once the sprite is created, you can then call its "setContentSize:" method @@ -175,7 +176,7 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* createWithSpriteFrameName(const std::string& spriteFrameName); - + /** * Creates a 9-slice sprite with an sprite frame name and the centre of its zone. * Once the sprite is created, you can then call its "setContentSize:" method @@ -188,7 +189,13 @@ namespace ui { * @return A Scale9Sprite instance. */ static Scale9Sprite* createWithSpriteFrameName(const std::string& spriteFrameName, const Rect& capInsets); - + + // overriden methods that takes different parameters + using Sprite::initWithFile; + using Sprite::initWithSpriteFrame; + using Sprite::initWithSpriteFrameName; + using Sprite::setSpriteFrame; + /** * Initializes a 9-slice sprite with a texture file, a delimitation zone and * with the specified cap insets. @@ -204,22 +211,7 @@ namespace ui { * @return True if initialize success, false otherwise. */ virtual bool initWithFile(const std::string& file, const Rect& rect, const Rect& capInsets); - - /** - * Initializes a 9-slice sprite with a texture file and a delimitation zone. The - * texture will be broken down into a 3×3 grid of equal blocks. - * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. - * It respects the anchorPoint too. - * - * @param file The name of the texture file. - * @param rect The rectangle that describes the sub-part of the texture that - * is the whole image. If the shape is the whole texture, set this to the - * texture's full rect. - * @return True if initializes success, false otherwise. - */ - virtual bool initWithFile(const std::string& file, const Rect& rect); - + /** * Initializes a 9-slice sprite with a texture file and with the specified cap * insets. @@ -232,19 +224,7 @@ namespace ui { * @return True if initializes success, false otherwise. */ virtual bool initWithFile(const Rect& capInsets, const std::string& file); - - /** - * Initializes a 9-slice sprite with a texture file. The whole texture will be - * broken down into a 3×3 grid of equal blocks. - * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. - * It respects the anchorPoint too. - * - * @param file The name of the texture file. - * @return True if initializes success, false otherwise. - */ - virtual bool initWithFile(const std::string& file); - + /** * Initializes a 9-slice sprite with an sprite frame and with the specified * cap insets. @@ -257,18 +237,7 @@ namespace ui { * @return True if initializes success, false otherwise. */ virtual bool initWithSpriteFrame(SpriteFrame* spriteFrame, const Rect& capInsets); - - /** - * Initializes a 9-slice sprite with an sprite frame. - * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. - * It respects the anchorPoint too. - * - * @param spriteFrame The sprite frame object. - * @return True if initializes success, false otherwise. - */ - virtual bool initWithSpriteFrame(SpriteFrame* spriteFrame); - + /** * Initializes a 9-slice sprite with an sprite frame name and with the specified * cap insets. @@ -281,18 +250,7 @@ namespace ui { * @return True if initializes success, false otherwise. */ virtual bool initWithSpriteFrameName(const std::string& spriteFrameName, const Rect& capInsets); - - /** - * Initializes a 9-slice sprite with an sprite frame name. - * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. - * It respects the anchorPoint too. - * - * @param spriteFrameName The sprite frame name. - * @return True if initializes success, false otherwise. - */ - virtual bool initWithSpriteFrameName(const std::string& spriteFrameName); - + //override function virtual bool init() override; @@ -343,7 +301,7 @@ namespace ui { const Vec2 &offset, const Size &originalSize, const Rect& capInsets); - + /** * @brief Initializes a 9-slice sprite with a sprite batchnode. * Once the sprite is created, you can then call its "setContentSize:" method @@ -357,10 +315,10 @@ namespace ui { * @param capInsets The values to use for the cap insets. * @return True if initializes success, false otherwise. */ - CC_DEPRECATED(v3) virtual bool initWithBatchNode(SpriteBatchNode* batchnode, - const Rect& rect, - bool rotated, - const Rect& capInsets); + CC_DEPRECATED(v3) virtual bool initWithBatchNode(SpriteBatchNode* batchnode, + const Rect& rect, + bool rotated, + const Rect& capInsets); /** * @brief Initializes a 9-slice sprite with a sprite batch node. * Once the sprite is created, you can then call its "setContentSize:" method @@ -374,24 +332,6 @@ namespace ui { * @return True if initializes success, false otherwise. */ CC_DEPRECATED(v3) virtual bool initWithBatchNode(SpriteBatchNode* batchnode, const Rect& rect, const Rect& capInsets); - - /** - * Sets the source blending function. - * - * @param blendFunc A structure with source and destination factor to specify pixel arithmetic. e.g. {GL_ONE, GL_ONE}, {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}. - * @js NA - * @lua NA - */ - virtual void setBlendFunc(const BlendFunc &blendFunc) override; - - /** - * Returns the blending function that is currently being used. - * - * @return A BlendFunc structure with source and destination factor which specified pixel arithmetic. - * @js NA - * @lua NA - */ - virtual const BlendFunc &getBlendFunc() const override; /** * Creates and returns a new sprite object with the specified cap insets. @@ -403,8 +343,8 @@ namespace ui { * @return A Scale9Sprite instance. */ Scale9Sprite* resizableSpriteWithCapInsets(const Rect& capInsets) const; - - + + /** * @brief Update Scale9Sprite with a specified sprite. * @@ -454,18 +394,14 @@ namespace ui { bool rotated, const Rect& capInsets); - + /** * @brief Change inner sprite's sprite frame. * * @param spriteFrame A sprite frame pointer. * @param capInsets The values to use for the cap insets. */ - virtual void setSpriteFrame(SpriteFrame * spriteFrame, const Rect& capInsets = Rect::ZERO); - - // overrides - virtual void setContentSize(const Size & size) override; - virtual void setAnchorPoint(const Vec2& anchorPoint) override; + virtual void setSpriteFrame(SpriteFrame * spriteFrame, const Rect& capInsets); /** * Change the state of 9-slice sprite. @@ -474,106 +410,92 @@ namespace ui { * @since v3.4 */ void setState(State state); - + /** * Query the current bright state. * @return @see `State` * @since v3.7 */ - State getState()const; - + State getState() const; + /** * @brief Query the sprite's original size. * * @return Sprite size. */ Size getOriginalSize() const; - + /** * @brief Change the preferred size of Scale9Sprite. * * @param size A delimitation zone. */ void setPreferredSize(const Size& size); - + /** * @brief Query the Scale9Sprite's preferred size. * * @return Scale9Sprite's preferred size. */ Size getPreferredSize() const; - - /** - * @brief Change the cap inset size. - * - * @param rect A delimitation zone. - */ - void setCapInsets(const Rect& rect); - - /** - * @brief Query the Scale9Sprite's preferred size. - * - * @return Scale9Sprite's cap inset. - */ - Rect getCapInsets()const; - + /** * @brief Change the left sprite's cap inset. * * @param leftInset The values to use for the cap inset. */ void setInsetLeft(float leftInset); - + /** * @brief Query the left sprite's cap inset. * * @return The left sprite's cap inset. */ - float getInsetLeft()const; - + float getInsetLeft() const; + /** * @brief Change the top sprite's cap inset. * * @param topInset The values to use for the cap inset. */ void setInsetTop(float topInset); - + /** * @brief Query the top sprite's cap inset. * * @return The top sprite's cap inset. */ - float getInsetTop()const; - + float getInsetTop() const; + /** * @brief Change the right sprite's cap inset. * * @param rightInset The values to use for the cap inset. */ void setInsetRight(float rightInset); - + /** * @brief Query the right sprite's cap inset. * * @return The right sprite's cap inset. */ - float getInsetRight()const; - + float getInsetRight() const; + /** * @brief Change the bottom sprite's cap inset. * * @param bottomInset The values to use for the cap inset. - + */ void setInsetBottom(float bottomInset); - + /** * @brief Query the bottom sprite's cap inset. * * @return The bottom sprite's cap inset. */ - float getInsetBottom()const; - + float getInsetBottom() const; + /** * @brief Toggle 9-slice feature. * If Scale9Sprite is 9-slice disabled, the Scale9Sprite will rendered as a normal sprite. @@ -583,84 +505,24 @@ namespace ui { * @js NA */ void setScale9Enabled(bool enabled); - + /** * @brief Query whether the Scale9Sprite is enable 9-slice or not. * * @return True if 9-slice is enabled, false otherwise. * @js NA */ - bool isScale9Enabled()const; - + bool isScale9Enabled() const; + /// @} end of Children and Parent - - virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override; - virtual void visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) override; - - virtual void updateDisplayedOpacity(GLubyte parentOpacity) override; - virtual void updateDisplayedColor(const Color3B& parentColor) override; - virtual void disableCascadeColor() override; - virtual void disableCascadeOpacity() override; - virtual void setGLProgram(GLProgram *glprogram) override; - virtual void setGLProgramState(GLProgramState *glProgramState) override; - + /** * @brief Get the original no 9-sliced sprite * * @return A sprite instance. */ - Sprite* getSprite()const; - - /** - * Sets whether the widget should be flipped horizontally or not. - * - * @param flippedX true if the widget should be flipped horizontally, false otherwise. - */ - virtual void setFlippedX(bool flippedX); - - /** - * Returns the flag which indicates whether the widget is flipped horizontally or not. - * - * It only flips the texture of the widget, and not the texture of the widget's children. - * Also, flipping the texture doesn't alter the anchorPoint. - * If you want to flip the anchorPoint too, and/or to flip the children too use: - * widget->setScaleX(sprite->getScaleX() * -1); - * - * @return true if the widget is flipped horizontally, false otherwise. - */ - virtual bool isFlippedX()const; - - /** - * Sets whether the widget should be flipped vertically or not. - * - * @param flippedY true if the widget should be flipped vertically, false otherwise. - */ - virtual void setFlippedY(bool flippedY); + Sprite* getSprite(); - /** - * Return the flag which indicates whether the widget is flipped vertically or not. - * - * It only flips the texture of the widget, and not the texture of the widget's children. - * Also, flipping the texture doesn't alter the anchorPoint. - * If you want to flip the anchorPoint too, and/or to flip the children too use: - * widget->setScaleY(widget->getScaleY() * -1); - * - * @return true if the widget is flipped vertically, false otherwise. - */ - virtual bool isFlippedY()const; - - //override the setScale function of Node - virtual void setScaleX(float scaleX) override; - virtual void setScaleY(float scaleY) override; - virtual void setScale(float scale) override; - virtual void setScale(float scaleX, float scaleY) override; - using Node::setScaleZ; - virtual float getScaleX() const override; - virtual float getScaleY() const override; - virtual float getScale() const override; - using Node::getScaleZ; - virtual void setCameraMask(unsigned short mask, bool applyChildren = true) override; - virtual void setGlobalZOrder(float globalZOrder) override; /** * Set the slice sprite rendering type. @@ -669,70 +531,38 @@ namespace ui { * @see RenderingType */ void setRenderingType(RenderingType type); - + /** * Return the slice sprite rendering type. */ - RenderingType getRenderingType()const; + RenderingType getRenderingType() const; + + /** + * Set the Cap Insets in Points using the untrimmed size as reference + */ + void setCapInsets(const Rect& insets); + /** + * Returns the Cap Insets + */ + Rect getCapInsets() const; void resetRender(); protected: void updateCapInset(); - void createSlicedSprites(); - void cleanupSlicedSprites(); - void adjustNoneScale9ImagePosition(); - void configureSimpleModeRendering(); - void applyBlendFunc(); - void updateBlendFunc(Texture2D *texture); - std::vector calculateUV(Texture2D *tex, const Rect& capInsets, - const Size& originalSize, const Vec4& offsets); - std::vector calculateVertices(const Rect& capInsets, const Size& originalSize, const Vec4& offsets); - TrianglesCommand::Triangles calculateTriangles(const std::vector& uv, - const std::vector& vertices); - - Rect _spriteRect; - bool _spriteFrameRotated; - Rect _capInsetsInternal; - - Sprite* _scale9Image; //the original sprite - - bool _scale9Enabled; - BlendFunc _blendFunc; - - /** Original sprite's size. */ - Size _originalSize; - Vec2 _offset; - /** Preferred sprite's size. By default the preferred size is the original size. */ - - //if the preferredSize component is given as -1, it is ignored - Size _preferredSize; - - /** Sets the left side inset */ - float _insetLeft; - /** Sets the top side inset */ - float _insetTop; - /** Sets the right side inset */ - float _insetRight; - /** Sets the bottom side inset */ - float _insetBottom; - - bool _flippedX; - bool _flippedY; - bool _isPatch9; - State _brightState; - Vec2 _nonSliceSpriteAnchor; + void setupSlice9(Texture2D* texture, const Rect& capInsets); - V3F_C4B_T2F* _sliceVertices; - unsigned short* _sliceIndices; - bool _sliceSpriteDirty; - RenderingType _renderingType; - -#if CC_SPRITE_DEBUG_DRAW - DrawNode *_debugDrawNode; -#endif //CC_SPRITE_DEBUG_DRAW - bool _insideBounds; /// whether or not the sprite was inside bounds the previous frame - TrianglesCommand _trianglesCommand; /// + bool _isPatch9; + + Rect _previousCenterRectNormalized; + + float _insetLeft; + float _insetRight; + float _insetTop; + float _insetBottom; + + Scale9Sprite::State _brightState; + Scale9Sprite::RenderingType _renderingType; }; }} //end of namespace diff --git a/tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UIScale9SpriteTest.cpp b/tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UIScale9SpriteTest.cpp index 186148b422..e8be9c6ea2 100644 --- a/tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UIScale9SpriteTest.cpp +++ b/tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UIScale9SpriteTest.cpp @@ -110,7 +110,7 @@ bool UIScale9SpriteTest::init() sp1->setColor(Color3B::GREEN); this->addChild(sp1); sp1->runAction((FiniteTimeAction*)action2); - + cocos2d::ui::Scale9Sprite *sp2 = ui::Scale9Sprite::create("cocosui/animationbuttonnormal.png"); sp2->setPosition(350, 160); sp2->setPreferredSize(sp1->getContentSize() * 1.2f); @@ -120,7 +120,7 @@ bool UIScale9SpriteTest::init() this->addChild(sp2); auto action3 = action->clone(); sp2->runAction((FiniteTimeAction*)action3); - + return true; } return false; @@ -177,7 +177,7 @@ bool UIScale9SpriteHierarchialTest::init() sp2->setColor(Color3B::GREEN); sp2->setFlippedX(true); sp2->setContentSize(Size(100,100)); - + sp1->addChild(sp2); return true; @@ -661,15 +661,15 @@ bool UIS9FrameNameSpriteSheetRotatedSetCapInsetLater::init() auto winSize = Director::getInstance()->getWinSize(); float x = winSize.width / 2; float y = 0 + (winSize.height / 2); - + auto blocks_scaled_with_insets = ui::Scale9Sprite::createWithSpriteFrameName("blocks9r.png"); - + blocks_scaled_with_insets->setInsetLeft(32); blocks_scaled_with_insets->setInsetRight(32); - + blocks_scaled_with_insets->setPreferredSize(Size(32*5.5f, 32*4)); blocks_scaled_with_insets->setPosition(Vec2(x, y)); - + this->addChild(blocks_scaled_with_insets); return true; } @@ -944,14 +944,14 @@ bool UIS9NinePatchTest::init() playerSprite->setPosition(x, y); playerSprite->setContentSize(preferedSize); auto capInsets = playerSprite->getCapInsets(); - CCLOG("player sprite capInset = %f, %f %f, %f", capInsets.origin.x, + CCLOG("player sprite capInset = %g, %g %g, %g", capInsets.origin.x, capInsets.origin.y, capInsets.size.width, capInsets.size.height); this->addChild(playerSprite); auto animationBtnSprite = ui::Scale9Sprite::createWithSpriteFrameName("animationbuttonpressed.png"); animationBtnSprite->setPosition(x-100, y-100); capInsets = animationBtnSprite->getCapInsets(); - CCLOG("animationBtnSprite capInset = %f, %f %f, %f", capInsets.origin.x, + CCLOG("animationBtnSprite capInset = %g, %g %g, %g", capInsets.origin.x, capInsets.origin.y, capInsets.size.width, capInsets.size.height); this->addChild(animationBtnSprite); @@ -960,7 +960,7 @@ bool UIS9NinePatchTest::init() monsterSprite->setPosition(x+100, y-100); capInsets = monsterSprite->getCapInsets(); monsterSprite->setContentSize(preferedSize); - CCLOG("monsterSprite capInset = %f, %f %f, %f", capInsets.origin.x, + CCLOG("monsterSprite capInset = %g, %g %g, %g", capInsets.origin.x, capInsets.origin.y, capInsets.size.width, capInsets.size.height); this->addChild(monsterSprite); @@ -1189,4 +1189,4 @@ void UIS9GrayStateOpacityTest::sliderEvent(cocos2d::Ref *sender, cocos2d::ui::Sl auto scale9Sprite = (Scale9Sprite*)this->getChildByName("GrayScale9"); scale9Sprite->setOpacity(1.0 * percent / maxPercent * 255.0); } -} \ No newline at end of file +}