/* * Copyright (c) 2012 cocos2d-x.org * http://www.cocos2d-x.org * * Copyright 2012 Yannick Loriot. All rights reserved. * http://yannickloriot.com * * 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 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 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 "CCControlSwitch.h" #include "cocos2d.h" NS_CC_EXT_BEGIN // CCControlSwitchSprite class CCControlSwitchSprite : public CCSprite, public CCActionTweenDelegate { public: CCControlSwitchSprite(); virtual ~CCControlSwitchSprite(); bool initWithMaskSprite( CCSprite *maskSprite, CCSprite *onSprite, CCSprite *offSprite, CCSprite *thumbSprite, CCLabelTTF* onLabel, CCLabelTTF* offLabel); void draw(); void needsLayout(); void setSliderXPosition(float sliderXPosition); float getSliderXPosition() {return _sliderXPosition;} float onSideWidth(); float offSideWidth(); virtual void updateTweenAction(float value, const char* key); /** Contains the position (in x-axis) of the slider inside the receiver. */ float _sliderXPosition; CC_SYNTHESIZE(float, _onPosition, OnPosition) CC_SYNTHESIZE(float, _offPosition, OffPosition) CC_SYNTHESIZE_RETAIN(CCTexture2D*, _maskTexture, MaskTexture) CC_SYNTHESIZE(GLuint, _textureLocation, TextureLocation) CC_SYNTHESIZE(GLuint, _maskLocation, MaskLocation) CC_SYNTHESIZE_RETAIN(CCSprite*, _onSprite, OnSprite) CC_SYNTHESIZE_RETAIN(CCSprite*, _offSprite, OffSprite) CC_SYNTHESIZE_RETAIN(CCSprite*, _thumbSprite, ThumbSprite) CC_SYNTHESIZE_RETAIN(CCLabelTTF*, _onLabel, OnLabel) CC_SYNTHESIZE_RETAIN(CCLabelTTF*, _offLabel, OffLabel) }; CCControlSwitchSprite::CCControlSwitchSprite() : _sliderXPosition(0.0f) , _onPosition(0.0f) , _offPosition(0.0f) , _maskTexture(NULL) , _textureLocation(0) , _maskLocation(0) , _onSprite(NULL) , _offSprite(NULL) , _thumbSprite(NULL) , _onLabel(NULL) , _offLabel(NULL) { } CCControlSwitchSprite::~CCControlSwitchSprite() { CC_SAFE_RELEASE(_onSprite); CC_SAFE_RELEASE(_offSprite); CC_SAFE_RELEASE(_thumbSprite); CC_SAFE_RELEASE(_onLabel); CC_SAFE_RELEASE(_offLabel); CC_SAFE_RELEASE(_maskTexture); } bool CCControlSwitchSprite::initWithMaskSprite( CCSprite *maskSprite, CCSprite *onSprite, CCSprite *offSprite, CCSprite *thumbSprite, CCLabelTTF* onLabel, CCLabelTTF* offLabel) { if (CCSprite::initWithTexture(maskSprite->getTexture())) { // Sets the default values _onPosition = 0; _offPosition = -onSprite->getContentSize().width + thumbSprite->getContentSize().width / 2; _sliderXPosition = _onPosition; setOnSprite(onSprite); setOffSprite(offSprite); setThumbSprite(thumbSprite); setOnLabel(onLabel); setOffLabel(offLabel); addChild(_thumbSprite); // Set up the mask with the Mask shader setMaskTexture(maskSprite->getTexture()); CCGLProgram* pProgram = new CCGLProgram(); pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccExSwitchMask_frag); setShaderProgram(pProgram); pProgram->release(); CHECK_GL_ERROR_DEBUG(); getShaderProgram()->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position); getShaderProgram()->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color); getShaderProgram()->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords); CHECK_GL_ERROR_DEBUG(); getShaderProgram()->link(); CHECK_GL_ERROR_DEBUG(); getShaderProgram()->updateUniforms(); CHECK_GL_ERROR_DEBUG(); _textureLocation = glGetUniformLocation( getShaderProgram()->getProgram(), "u_texture"); _maskLocation = glGetUniformLocation( getShaderProgram()->getProgram(), "u_mask"); CHECK_GL_ERROR_DEBUG(); setContentSize(_maskTexture->getContentSize()); needsLayout(); return true; } return false; } void CCControlSwitchSprite::updateTweenAction(float value, const char* key) { CCLOG("key = %s, value = %f", key, value); setSliderXPosition(value); } void CCControlSwitchSprite::draw() { CC_NODE_DRAW_SETUP(); ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex); ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); getShaderProgram()->setUniformsForBuiltins(); glActiveTexture(GL_TEXTURE0); glBindTexture( GL_TEXTURE_2D, getTexture()->getName()); glUniform1i(_textureLocation, 0); glActiveTexture(GL_TEXTURE1); glBindTexture( GL_TEXTURE_2D, _maskTexture->getName() ); glUniform1i(_maskLocation, 1); #define kQuadSize sizeof(_quad.bl) #ifdef EMSCRIPTEN long offset = 0; setGLBufferData(&_quad, 4 * kQuadSize, 0); #else long offset = (long)&_quad; #endif // EMSCRIPTEN // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glActiveTexture(GL_TEXTURE0); } void CCControlSwitchSprite::needsLayout() { _onSprite->setPosition(ccp(_onSprite->getContentSize().width / 2 + _sliderXPosition, _onSprite->getContentSize().height / 2)); _offSprite->setPosition(ccp(_onSprite->getContentSize().width + _offSprite->getContentSize().width / 2 + _sliderXPosition, _offSprite->getContentSize().height / 2)); _thumbSprite->setPosition(ccp(_onSprite->getContentSize().width + _sliderXPosition, _maskTexture->getContentSize().height / 2)); if (_onLabel) { _onLabel->setPosition(ccp(_onSprite->getPosition().x - _thumbSprite->getContentSize().width / 6, _onSprite->getContentSize().height / 2)); } if (_offLabel) { _offLabel->setPosition(ccp(_offSprite->getPosition().x + _thumbSprite->getContentSize().width / 6, _offSprite->getContentSize().height / 2)); } CCRenderTexture *rt = CCRenderTexture::create((int)_maskTexture->getContentSize().width, (int)_maskTexture->getContentSize().height); rt->begin(); _onSprite->visit(); _offSprite->visit(); if (_onLabel) { _onLabel->visit(); } if (_offLabel) { _offLabel->visit(); } rt->end(); setTexture(rt->getSprite()->getTexture()); setFlipY(true); } void CCControlSwitchSprite::setSliderXPosition(float sliderXPosition) { if (sliderXPosition <= _offPosition) { // Off sliderXPosition = _offPosition; } else if (sliderXPosition >= _onPosition) { // On sliderXPosition = _onPosition; } _sliderXPosition = sliderXPosition; needsLayout(); } float CCControlSwitchSprite::onSideWidth() { return _onSprite->getContentSize().width; } float CCControlSwitchSprite::offSideWidth() { return _offSprite->getContentSize().height; } // CCControlSwitch CCControlSwitch::CCControlSwitch() : _switchSprite(NULL) , _initialTouchXPosition(0.0f) , _moved(false) , _on(false) { } CCControlSwitch::~CCControlSwitch() { CC_SAFE_RELEASE(_switchSprite); } bool CCControlSwitch::initWithMaskSprite(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite) { return initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, NULL, NULL); } CCControlSwitch* CCControlSwitch::create(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite) { CCControlSwitch* pRet = new CCControlSwitch(); if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, NULL, NULL)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet; } bool CCControlSwitch::initWithMaskSprite(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite, CCLabelTTF* onLabel, CCLabelTTF* offLabel) { if (CCControl::init()) { CCAssert(maskSprite, "Mask must not be nil."); CCAssert(onSprite, "onSprite must not be nil."); CCAssert(offSprite, "offSprite must not be nil."); CCAssert(thumbSprite, "thumbSprite must not be nil."); setTouchEnabled(true); _on = true; _switchSprite = new CCControlSwitchSprite(); _switchSprite->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel); _switchSprite->setPosition(ccp (_switchSprite->getContentSize().width / 2, _switchSprite->getContentSize().height / 2)); addChild(_switchSprite); ignoreAnchorPointForPosition(false); setAnchorPoint(ccp (0.5f, 0.5f)); setContentSize(_switchSprite->getContentSize()); return true; } return false; } CCControlSwitch* CCControlSwitch::create(CCSprite *maskSprite, CCSprite * onSprite, CCSprite * offSprite, CCSprite * thumbSprite, CCLabelTTF* onLabel, CCLabelTTF* offLabel) { CCControlSwitch* pRet = new CCControlSwitch(); if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel)) { pRet->autorelease(); } else { CC_SAFE_DELETE(pRet); } return pRet; } void CCControlSwitch::setOn(bool isOn) { setOn(isOn, false); } void CCControlSwitch::setOn(bool isOn, bool animated) { _on = isOn; if (animated) { _switchSprite->runAction ( CCActionTween::create ( 0.2f, "sliderXPosition", _switchSprite->getSliderXPosition(), (_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition() ) ); } else { _switchSprite->setSliderXPosition((_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition()); } sendActionsForControlEvents(CCControlEventValueChanged); } void CCControlSwitch::setEnabled(bool enabled) { _enabled = enabled; if (_switchSprite != NULL) { _switchSprite->setOpacity((enabled) ? 255 : 128); } } CCPoint CCControlSwitch::locationFromTouch(CCTouch* pTouch) { CCPoint touchLocation = pTouch->getLocation(); // Get the touch position touchLocation = this->convertToNodeSpace(touchLocation); // Convert to the node space of this class return touchLocation; } bool CCControlSwitch::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { if (!isTouchInside(pTouch) || !isEnabled() || !isVisible()) { return false; } _moved = false; CCPoint location = this->locationFromTouch(pTouch); _initialTouchXPosition = location.x - _switchSprite->getSliderXPosition(); _switchSprite->getThumbSprite()->setColor(ccGRAY); _switchSprite->needsLayout(); return true; } void CCControlSwitch::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { CCPoint location = this->locationFromTouch(pTouch); location = ccp (location.x - _initialTouchXPosition, 0); _moved = true; _switchSprite->setSliderXPosition(location.x); } void CCControlSwitch::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { CCPoint location = this->locationFromTouch(pTouch); _switchSprite->getThumbSprite()->setColor(ccWHITE); if (hasMoved()) { setOn(!(location.x < _switchSprite->getContentSize().width / 2), true); } else { setOn(!_on, true); } } void CCControlSwitch::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) { CCPoint location = this->locationFromTouch(pTouch); _switchSprite->getThumbSprite()->setColor(ccWHITE); if (hasMoved()) { setOn(!(location.x < _switchSprite->getContentSize().width / 2), true); } else { setOn(!_on, true); } } NS_CC_EXT_END