diff --git a/AUTHORS b/AUTHORS index e09e11d178..36fa8ce35e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -70,7 +70,8 @@ Developers: Refactoring network extension and fixing unlikely memory leaks. Adding PUT/DELETE methods for CCHttpRequest. Adding project part for QtCreator. - Implemented pitch, pan and gain + Implemented pitch, pan and gain. + Using SDL backend instead of glfw for Linux. savdalion Added example for russian language in TestCpp @@ -417,6 +418,8 @@ Developers: Creation of CCDeprecated-ext.h Use of a single emscripten HTML template file. Added some guards in fileutils. Fixed a bug in emscripten file utils. + Added emscripten keyboard support + Clang support for Linux elmiro Correction of passed buffer size to readlink and verification of result return by readlink. @@ -543,6 +546,9 @@ Developers: metalbass Fixing an issue that sigslot::_connection_base# (from 0 to 8) don't have virtual destructors. + + thp + Port Cocos2D-X to Qt 5 Retired Core Developers: WenSheng Yang @@ -564,6 +570,10 @@ Retired Core Developers: metadao make create_project.py more pythonic and fix some typoes + + timothyqiu + Project creator: use absolute path for json config files + Documentation fixes Cocos2d-x can not grow so fast without the active community. diff --git a/CHANGELOG b/CHANGELOG index 0db695f018..7139a01260 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,91 @@ -cocos2d-x-3.0alpha0-pre @Jul.24 2013 +cocos2d-x-3.0alpha0-pre @Jul.30 2013 [all platforms] - Feature #XXXX: Add support for std::function<> in CCMemuItem and CCCallFunc + [FIX] #2124: Image::initWithImageFileThreadSafe is not thread safe + [FIX] #2230: Node::onEnterTransitionDidFinish was called twice when a node is added in Node::onEnter + [FIX] #2237: calculation offset in font rendering + [FIX] #2303: missing precision when getting strokeColor and fontFillColor + [FIX] #2312: WebSocket can not parse url like "ws://domain.com/websocket" + [FIX] #2327: implement Node::isScheduled + [FIX] #2338: ccbRootPath is not passed to sub ccb nodes + [FIX] #2346: OpenGL error 0x0502 in TextureAtlas::drawNumberOfQuads + [FIX] #2359: Sprite will become white block when using ControlSwitch + [FIX] #2361: some bug fixed of the Set class + [FIX] #2366: text shadow + [FIX] #2367: ClippingNode works differently on different platforms + [FIX] #2370: Pivotjoint constructor and pointQueryFirst in Space class will return false instead of invalid shape object + [FIX] #2381: ControlSwitch wasn't displayed correctly when adding more than one switch + [FIX] #2384: The submenu of ExtensionTest in TestCpp can't scroll + [FIX] #2386: ClippingNode works wrongly when being set as a child + [FIX] #2396: Scale9Sprite::setInsetLeft/XXX can't work for rotated sprite frame + [FIX] #2401: LabelBMFont crashes in glDrawElements of CCTextureAtlas::drawNumberOfQuads randombly + [FIX] #2410: Black screen appears on android randomly + [FIX] #2411: Opacity option for shadow in CCLabelTTF is not working + [FIX] #2406: Color and Opacity of Scale9Sprite will not be changed when it's added to NodeRGBA and run with FadeIn/Out actions + [FIX] #2415: Warning of AL_INVALID_NAME and AL_INVALID_OPERATION in SimpleAudioEngineOpenAL.cpp + [FIX] #2418: Unused spriteframes also need to be removed when purgeCachedData + [FIX] #2431: Potential crash when loading js files + [FIX] #2229: Explicitly initialising CCAcceleration structure + [FIX] #2234: Add destructor to CCGLBufferedNode + [Feature] #2232: adding Norwegian language support + [Feature] #2235: Ability to save/retrieve CCData into/from CCUserDefault + [Feature] #2250: add support for std::function<> in CCMemuItem and CCCallFunc + [Feature] #2273: Hardware keyboard support + [Feature] #2278: Adds CALLBACK_0, CALLBACK_1 and CALLBACK_2 macros for MenuItems + [Feature] #2279: Updates chipmunk2d to v6.1.5 + [Feature] #2283: Adds Polish language support + [Feature] #2289: Uses clone() pattern for actions + [Feature] #2332: Adding project for QtCreator + [Feature] #2364: Adds DrawPrimitives::DrawSolidCircle + [Feature] #2365: Adds Rect::unionWithRect + [Feature] #2385: Implemented pitch, pan and gain for SimpleAudioEngine + [Feature] #2389: Adding cookie support for HttpClient + [Feature] #2392: Adds append() function for String class + [Feature] #2395: Adds Scale9SpriteTest for TestCpp + [Feature] #2399: Adds SocketIO support + [Feature] #2408: Adds String::componentsSeparatedByString function for splitting string + [Feature] #2414: Bindings-generator could bind std::function<> argument + [Refactor] #2129: Removes Hungarian notation from ivars. Removes CC and cc prefixes from name classes and free functions. + [Refactor] #2242: Enables c++11 + [Refactor] #2300: Using clone() pattern instead of 'copyWithZone' pattern + [Refactor] #2305: Use std::thread instead of pthread + [Refactor] #2328: ETC support for all platforms + [Refactor] #2373: Change some member functions to const + [Refactor] #2378: Remove the usage of CC_PROPERTY_XXX in engine code + [Refactor] #2388: Creating a default texture for CCSprite if setTexture(nullptr) is invoked + [Refactor] #2397: Singleton refactor, sharedXXX --> getInstance, purgeXXX --> destroyInstance + [Refactor] #2404: Move all deprecated global functions and variables into CCDeprecated.h + [Refactor] #2430: Uses strongly typed enums (enum class) instead of simple enums +[iOS] + [FIX] #2274: compile and run for iOS7 and Xcode5 + [Refactor] #2371: use one single Xcode project for iOS and Mac projects +[Android] + [FIX] #2306: CCLabelTTF::setString crash + [Refactor] #2329: use Android "asset manager" to improve file system read performance + [Refactor] #2400: use onWindowFocusChanged(bool) instead of onResume()/onPause() +[OS X] + [FIX] #2275: LabelTTF vertical alignment + [FIX] #2398: Add support for initializing Image with raw data +[windows] + [FIX] #2322: link error becasue of using multiply inheritance +[javascript binding] + [FIX] #2307: PhysicsSprite::getCPBody return wrong type + [FIX] #2313: bind cc.ClippingNode + [FIX] #2315: iterating through cc.Node children crash + [Feature] #2285: bind MontionStreak + [Feature] #2340: Updates SpiderMonekey to Firefox v22 (JS Bindings) + [Feature] #2427: bind FileUtils.getInstance().createDictionaryWithContentsOfFile +[lua binding] + [Feature] #2276: Add CCScrollView lua binding and corresponding test sample + [Feature] #2277: Add OpenGL lua binding and corresponding test sample + [Feature] #2324: Add OpenGL lua module + [Feature] #2343: Redesign the mechanism of invoking lua func from c++ + [Feature] #2344: make some execute functions into one function in ScriptEngineProtocol + [Feature] #2426: Add DrawPrimitives test sample + [Feature] #2429: LuaWebSocket supports sending binary string +[plugin-x] + [FIX] #2348: event will not be sent to server when paramMap argument of logEvent function is nil +[Emscript] + [Feature] #2289: Asynchronous Image loading 2.1rc0-x-2.1.4 @Jnue.12 2013 diff --git a/CocosDenshion/android/SimpleAudioEngine.cpp b/CocosDenshion/android/SimpleAudioEngine.cpp index 6425a71da0..824c5fe80a 100644 --- a/CocosDenshion/android/SimpleAudioEngine.cpp +++ b/CocosDenshion/android/SimpleAudioEngine.cpp @@ -74,7 +74,7 @@ SimpleAudioEngine::SimpleAudioEngine() const char* deviceModel = methodInfo.env->GetStringUTFChars(jstr, NULL); - LOGD(deviceModel); + LOGD("%s", deviceModel); if (strcmp(I9100_MODEL, deviceModel) == 0) { diff --git a/CocosDenshion/android/opensl/OpenSLEngine.cpp b/CocosDenshion/android/opensl/OpenSLEngine.cpp index 680200e314..e2c1943b7c 100644 --- a/CocosDenshion/android/opensl/OpenSLEngine.cpp +++ b/CocosDenshion/android/opensl/OpenSLEngine.cpp @@ -371,7 +371,7 @@ void OpenSLEngine::createEngine(void* pHandle) const char* errorInfo = dlerror(); if (errorInfo) { - LOGD(errorInfo); + LOGD("%s", errorInfo); return; } diff --git a/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp b/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp index f491f1bd3f..47a89f6abb 100644 --- a/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp +++ b/CocosDenshion/android/opensl/SimpleAudioEngineOpenSL.cpp @@ -38,7 +38,7 @@ bool SimpleAudioEngineOpenSL::initEngine() const char* errorInfo = dlerror(); if (errorInfo) { - LOGD(errorInfo); + LOGD("%s", errorInfo); bRet = false; break; } diff --git a/CocosDenshion/proj.qt5/cocosdenshion.pro b/CocosDenshion/proj.qt5/cocosdenshion.pro new file mode 100644 index 0000000000..0895763525 --- /dev/null +++ b/CocosDenshion/proj.qt5/cocosdenshion.pro @@ -0,0 +1,15 @@ + +include(../../cocos2dx/proj.qt5/common.pri) + +TEMPLATE = lib + +SOURCES += $$files(../qt5/*.cpp) + +INCLUDEPATH += .. +INCLUDEPATH += ../include + +TARGET = $${LIB_OUTPUT_DIR}/cocosdenshion + +INSTALLS += target +target.path = $${LIB_INSTALL_DIR} + diff --git a/CocosDenshion/qt5/SimpleAudioEngineQt5.cpp b/CocosDenshion/qt5/SimpleAudioEngineQt5.cpp new file mode 100644 index 0000000000..453fd0d9fd --- /dev/null +++ b/CocosDenshion/qt5/SimpleAudioEngineQt5.cpp @@ -0,0 +1,407 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "SimpleAudioEngine.h" + +#include "platform/CCCommon.h" +#include "platform/CCFileUtils.h" + +#include +#include + +USING_NS_CC; + +namespace CocosDenshion { + +static QString +fullPath(const char *filename) +{ + return QString::fromStdString(FileUtils::getInstance()->fullPathForFilename(filename)); +} + +class CocosQt5AudioBackend { + public: + static void cleanup(); + static void gcEffects(); + + static QMediaPlayer *player() { + if (background_music == NULL) { + background_music = new QMediaPlayer; + } + + return background_music; + } + + static void setEffectsVolume(float volume) + { + effects_volume = volume; + + foreach (QMediaPlayer *effect, effects.values()) { + effect->setVolume(volume * 100.0); + } + } + + static QMap effects; + static QMediaPlayer *background_music; + static int next_effect_id; + static float effects_volume; +}; + +QMap +CocosQt5AudioBackend::effects; + +QMediaPlayer * +CocosQt5AudioBackend::background_music = NULL; + +int +CocosQt5AudioBackend::next_effect_id = 0; + +float +CocosQt5AudioBackend::effects_volume = 1.0; + +void +CocosQt5AudioBackend::cleanup() +{ + foreach (QMediaPlayer *effect, effects.values()) { + delete effect; + } + + if (background_music != NULL) { + delete background_music; + background_music = NULL; + } +} + +void +CocosQt5AudioBackend::gcEffects() +{ + foreach (int id, effects.keys()) { + QMediaPlayer *effect = effects[id]; + if (effect->state() == QMediaPlayer::StoppedState) { + delete effect; + effects.remove(id); + } + } +} + + +/* Singleton object */ +static SimpleAudioEngine * +simple_audio_engine = NULL; + + +/** +@brief Get the shared Engine object,it will new one when first time be called +*/ +SimpleAudioEngine * +SimpleAudioEngine::getInstance() +{ + if (simple_audio_engine == NULL) { + simple_audio_engine = new SimpleAudioEngine; + } + + return simple_audio_engine; +} + +/** +@brief Release the shared Engine object +@warning It must be called before the application exit, or a memroy leak will be casued. +*/ +void +SimpleAudioEngine::end() +{ + if (simple_audio_engine != NULL) { + delete simple_audio_engine; + simple_audio_engine = NULL; + } +} + + +SimpleAudioEngine::SimpleAudioEngine() +{ +} + +SimpleAudioEngine::~SimpleAudioEngine() +{ + // Free sound effects and stop background music + CocosQt5AudioBackend::cleanup(); +} + +/** + @brief Preload background music + @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo + */ +void +SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) +{ + QString filename = fullPath(pszFilePath); +} + +/** +@brief Play background music +@param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo +@param bLoop Whether the background music loop or not +*/ +void +SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) +{ + QString filename = fullPath(pszFilePath); + + CocosQt5AudioBackend::player()->setMedia(QUrl::fromLocalFile(filename)); + if (bLoop) { + // TODO: Set QMediaPlayer to loop infinitely + } + CocosQt5AudioBackend::player()->play(); +} + +/** +@brief Stop playing background music +@param bReleaseData If release the background music data or not.As default value is false +*/ +void +SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) +{ + CocosQt5AudioBackend::player()->stop(); + + if (bReleaseData) { + CocosQt5AudioBackend::player()->setMedia(QMediaContent()); + } +} + +/** +@brief Pause playing background music +*/ +void +SimpleAudioEngine::pauseBackgroundMusic() +{ + CocosQt5AudioBackend::player()->pause(); +} + +/** +@brief Resume playing background music +*/ +void +SimpleAudioEngine::resumeBackgroundMusic() +{ + CocosQt5AudioBackend::player()->play(); +} + +/** +@brief Rewind playing background music +*/ +void +SimpleAudioEngine::rewindBackgroundMusic() +{ + CocosQt5AudioBackend::player()->stop(); + CocosQt5AudioBackend::player()->setPosition(0); + CocosQt5AudioBackend::player()->play(); +} + +bool +SimpleAudioEngine::willPlayBackgroundMusic() +{ + return true; +} + +/** +@brief Whether the background music is playing +@return If is playing return true,or return false +*/ +bool +SimpleAudioEngine::isBackgroundMusicPlaying() +{ + return (CocosQt5AudioBackend::player()->state() == QMediaPlayer::PlayingState); +} + +/** +@brief The volume of the background music max value is 1.0,the min value is 0.0 +*/ +float +SimpleAudioEngine::getBackgroundMusicVolume() +{ + return (float)(CocosQt5AudioBackend::player()->volume()) / 100.; +} + +/** +@brief set the volume of background music +@param volume must be in 0.0~1.0 +*/ +void +SimpleAudioEngine::setBackgroundMusicVolume(float volume) +{ + CocosQt5AudioBackend::player()->setVolume(100. * volume); +} + +/** +@brief The volume of the effects max value is 1.0,the min value is 0.0 +*/ +float +SimpleAudioEngine::getEffectsVolume() +{ + return CocosQt5AudioBackend::effects_volume; +} + +/** +@brief set the volume of sound effecs +@param volume must be in 0.0~1.0 +*/ +void +SimpleAudioEngine::setEffectsVolume(float volume) +{ + CocosQt5AudioBackend::setEffectsVolume(volume); +} + +// for sound effects +/** +@brief Play sound effect +@param pszFilePath The path of the effect file,or the FileName of T_SoundResInfo +@bLoop Whether to loop the effect playing, default value is false +*/ +unsigned int +SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, + float pitch, float pan, float gain) +{ + // TODO: Handle pitch, pan and gain + + CocosQt5AudioBackend::gcEffects(); + + QString filename = fullPath(pszFilePath); + int id = CocosQt5AudioBackend::next_effect_id++; + + QMediaPlayer *effect = new QMediaPlayer; + effect->setMedia(QUrl::fromLocalFile(filename)); + effect->setVolume(CocosQt5AudioBackend::effects_volume * 100.0); + if (bLoop) { + // TODO: Set QMediaPlayer to loop infinitely + } + effect->play(); + + CocosQt5AudioBackend::effects[id] = effect; + return id; +} + +/** +@brief Pause playing sound effect +@param nSoundId The return value of function playEffect +*/ +void +SimpleAudioEngine::pauseEffect(unsigned int nSoundId) +{ + if (CocosQt5AudioBackend::effects.contains(nSoundId)) { + QMediaPlayer *effect = CocosQt5AudioBackend::effects[nSoundId]; + effect->pause(); + } +} + +/** +@brief Pause all playing sound effect +@param nSoundId The return value of function playEffect +*/ +void +SimpleAudioEngine::pauseAllEffects() +{ + foreach (QMediaPlayer *effect, CocosQt5AudioBackend::effects.values()) { + effect->pause(); + } +} + +/** +@brief Resume playing sound effect +@param nSoundId The return value of function playEffect +*/ +void +SimpleAudioEngine::resumeEffect(unsigned int nSoundId) +{ + if (CocosQt5AudioBackend::effects.contains(nSoundId)) { + QMediaPlayer *effect = CocosQt5AudioBackend::effects[nSoundId]; + effect->play(); + } +} + +/** +@brief Resume all playing sound effect +@param nSoundId The return value of function playEffect +*/ +void +SimpleAudioEngine::resumeAllEffects() +{ + foreach (QMediaPlayer *effect, CocosQt5AudioBackend::effects.values()) { + if (effect->state() == QMediaPlayer::PausedState) { + effect->play(); + } + } +} + +/** +@brief Stop playing sound effect +@param nSoundId The return value of function playEffect +*/ +void +SimpleAudioEngine::stopEffect(unsigned int nSoundId) +{ + if (CocosQt5AudioBackend::effects.contains(nSoundId)) { + QMediaPlayer *effect = CocosQt5AudioBackend::effects[nSoundId]; + CocosQt5AudioBackend::effects.remove(nSoundId); + delete effect; + } +} + +/** +@brief Stop all playing sound effects +*/ +void +SimpleAudioEngine::stopAllEffects() +{ + foreach (QMediaPlayer *effect, CocosQt5AudioBackend::effects.values()) { + delete effect; + } + CocosQt5AudioBackend::effects.clear(); +} + +/** +@brief preload a compressed audio file +@details the compressed audio will be decode to wave, then write into an +internal buffer in SimpleAudioEngine +*/ +void +SimpleAudioEngine::preloadEffect(const char* pszFilePath) +{ + QString filename = fullPath(pszFilePath); +} + +/** +@brief unload the preloaded effect from internal buffer +@param[in] pszFilePath The path of the effect file,or the FileName of T_SoundResInfo +*/ +void +SimpleAudioEngine::unloadEffect(const char* pszFilePath) +{ + QString filename = fullPath(pszFilePath); +} + +} /* end namespace CocosDenshion */ diff --git a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index c92f5a3a00..024c567a4c 100644 --- a/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -cc411a26f60628d0276f802f1ba3b98137c2d3ba \ No newline at end of file +2be27e9efb6c86c102b456842fc79a7b397910e0 \ No newline at end of file diff --git a/cocos2dx-qt5.pro b/cocos2dx-qt5.pro new file mode 100644 index 0000000000..fa6af5270c --- /dev/null +++ b/cocos2dx-qt5.pro @@ -0,0 +1,19 @@ + +TEMPLATE = subdirs + +CONFIG += ordered + +# Cocos2D-X Core Library +SUBDIRS += external/chipmunk/proj.qt5/chipmunk.pro +SUBDIRS += external/Box2D/proj.qt5/box2d.pro +SUBDIRS += cocos2dx/proj.qt5/cocos2dx.pro + +# Cocos2D-X Additional Libraries +SUBDIRS += CocosDenshion/proj.qt5/cocosdenshion.pro +SUBDIRS += extensions/proj.qt5/extensions.pro + +# Examples +SUBDIRS += samples/Cpp/HelloCpp/proj.qt5/HelloCpp.pro +SUBDIRS += samples/Cpp/SimpleGame/proj.qt5/SimpleGame.pro +SUBDIRS += samples/Cpp/TestCpp/proj.qt5/TestCpp.pro + diff --git a/cocos2dx/Android.mk b/cocos2dx/Android.mk index d3b26b7a6d..3c40e54a31 100644 --- a/cocos2dx/Android.mk +++ b/cocos2dx/Android.mk @@ -79,7 +79,6 @@ particle_nodes/CCParticleExamples.cpp \ particle_nodes/CCParticleSystem.cpp \ particle_nodes/CCParticleBatchNode.cpp \ particle_nodes/CCParticleSystemQuad.cpp \ -platform/CCImageCommonWebp.cpp \ platform/CCSAXParser.cpp \ platform/CCThread.cpp \ platform/CCFileUtils.cpp \ @@ -131,9 +130,7 @@ text_input_node/CCTextFieldTTF.cpp \ textures/CCTexture2D.cpp \ textures/CCTextureAtlas.cpp \ textures/CCTextureCache.cpp \ -textures/CCTextureETC.cpp \ -textures/CCTexturePVR.cpp \ -textures/etc/etc1.cpp\ +platform/third_party/common/etc/etc1.cpp\ tilemap_parallax_nodes/CCParallaxNode.cpp \ tilemap_parallax_nodes/CCTMXLayer.cpp \ tilemap_parallax_nodes/CCTMXObjectGroup.cpp \ @@ -147,12 +144,15 @@ touch_dispatcher/CCTouch.cpp LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/kazmath/include \ - $(LOCAL_PATH)/platform/android + $(LOCAL_PATH)/platform/android \ + $(LOCAL_PATH)/platform/third_party/common/etc LOCAL_C_INCLUDES := $(LOCAL_PATH) \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/kazmath/include \ - $(LOCAL_PATH)/platform/android + $(LOCAL_PATH)/platform/android \ + $(LOCAL_PATH)/platform/third_party/common/etc + LOCAL_LDLIBS := -lGLESv2 \ -llog \ diff --git a/cocos2dx/CCDirector.cpp b/cocos2dx/CCDirector.cpp index 8b0573b8bc..75a46757fb 100644 --- a/cocos2dx/CCDirector.cpp +++ b/cocos2dx/CCDirector.cpp @@ -106,7 +106,7 @@ Director::Director(void) bool Director::init(void) { - setDefaultValues(); + setDefaultValues(); // scenes _runningScene = NULL; @@ -253,6 +253,11 @@ void Director::drawScene(void) // calculate "global" dt calculateDeltaTime(); + if (_openGLView) + { + _openGLView->pollInputEvents(); + } + //tick before glClear: issue #533 if (! _paused) { @@ -645,7 +650,7 @@ void Director::popToSceneStackLevel(int level) // pop stack until reaching desired level while (c > level) { - Scene *current = (Scene*)_scenesStack->lastObject(); + Scene *current = (Scene*)_scenesStack->lastObject(); if (current->isRunning()) { @@ -658,7 +663,7 @@ void Director::popToSceneStackLevel(int level) c--; } - _nextScene = (Scene*)_scenesStack->lastObject(); + _nextScene = (Scene*)_scenesStack->lastObject(); _sendCleanupToScene = false; } diff --git a/cocos2dx/actions/CCActionInterval.cpp b/cocos2dx/actions/CCActionInterval.cpp index aae2e323de..66ccbe88f8 100644 --- a/cocos2dx/actions/CCActionInterval.cpp +++ b/cocos2dx/actions/CCActionInterval.cpp @@ -1273,7 +1273,7 @@ void JumpTo::startWithTarget(Node *target) // Bezier cubic formula: // ((1 - t) + t)3 = 1 -// Expands toˇ­ +// Expands to ... // (1 - t)3 + 3t(1-t)2 + 3t2(1 - t) + t3 = 1 static inline float bezierat( float a, float b, float c, float d, float t ) { @@ -1987,11 +1987,11 @@ Animate* Animate::create(Animation *pAnimation) } Animate::Animate() -: _animation(NULL) -, _splitTimes(new std::vector) +: _splitTimes(new std::vector) , _nextFrame(0) , _origFrame(NULL) , _executedLoops(0) +, _animation(NULL) { } @@ -2155,8 +2155,8 @@ Animate* Animate::reverse() const // TargetedAction TargetedAction::TargetedAction() -: _forcedTarget(NULL) -, _action(NULL) +: _action(NULL) +, _forcedTarget(NULL) { } diff --git a/cocos2dx/base_nodes/CCNode.cpp b/cocos2dx/base_nodes/CCNode.cpp index 044d05436e..2c5657e677 100644 --- a/cocos2dx/base_nodes/CCNode.cpp +++ b/cocos2dx/base_nodes/CCNode.cpp @@ -64,6 +64,11 @@ Node::Node(void) , _anchorPoint(Point::ZERO) , _contentSize(Size::ZERO) , _additionalTransform(AffineTransformMakeIdentity()) +, _transform(AffineTransformMakeIdentity()) +, _inverse(AffineTransformMakeIdentity()) +, _additionalTransformDirty(false) +, _transformDirty(true) +, _inverseDirty(true) , _camera(NULL) // children (lazy allocs) // lazy alloc @@ -79,9 +84,6 @@ Node::Node(void) , _shaderProgram(NULL) , _orderOfArrival(0) , _running(false) -, _transformDirty(true) -, _inverseDirty(true) -, _additionalTransformDirty(false) , _visible(true) , _ignoreAnchorPointForPosition(false) , _reorderChildDirty(false) diff --git a/cocos2dx/base_nodes/CCNode.h b/cocos2dx/base_nodes/CCNode.h index 2a4e5fb3c3..50e07ffed4 100644 --- a/cocos2dx/base_nodes/CCNode.h +++ b/cocos2dx/base_nodes/CCNode.h @@ -224,9 +224,9 @@ public: * * The deafult value is 1.0 if you haven't changed it before * - * @param fScaleX The scale factor on X axis. + * @param scaleX The scale factor on X axis. */ - virtual void setScaleX(float fScaleX); + virtual void setScaleX(float scaleX); /** * Returns the scale factor on X axis of this node * @@ -242,9 +242,9 @@ public: * * The Default value is 1.0 if you haven't changed it before. * - * @param fScaleY The scale factor on Y axis. + * @param scaleY The scale factor on Y axis. */ - virtual void setScaleY(float fScaleY); + virtual void setScaleY(float scaleY); /** * Returns the scale factor on Y axis of this node * @@ -699,7 +699,7 @@ public: /** * Changes a grid object that is used when applying effects * - * @param A Grid object that is used when applying effects + * @param grid A Grid object that is used when applying effects */ virtual void setGrid(GridBase *grid); @@ -748,7 +748,7 @@ public: * * Please refer to getTag for the sample code. * - * @param A interger that indentifies the node. + * @param tag A interger that indentifies the node. */ virtual void setTag(int tag); @@ -769,7 +769,7 @@ public: * @warning Don't forget to release the memroy manually, * especially before you change this data pointer, and before this node is autoreleased. * - * @param A custom user data pointer + * @param userData A custom user data pointer */ virtual void setUserData(void *userData); @@ -791,7 +791,7 @@ public: * and the previous UserObject (if existed) will be relese. * The UserObject will be released in Node's destructure. * - * @param A user assigned Object + * @param userObject A user assigned Object */ virtual void setUserObject(Object *userObject); @@ -817,7 +817,7 @@ public: * node->setShaderProgram(ShaderCache::getInstance()->programForKey(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR)); * @endcode * - * @param The shader program which fetchs from ShaderCache. + * @param shaderProgram The shader program which fetchs from ShaderCache. */ virtual void setShaderProgram(GLProgram *shaderProgram); /// @} end of Shader Program @@ -961,14 +961,14 @@ public: /** * Stops and removes an action from the running action list. * - * @param An action object to be removed. + * @param action The action object to be removed. */ void stopAction(Action* action); /** * Removes an action from the running action list by its tag. * - * @param A tag that indicates the action to be removed. + * @param tag A tag that indicates the action to be removed. */ void stopActionByTag(int tag); diff --git a/cocos2dx/cocoa/CCDataVisitor.h b/cocos2dx/cocoa/CCDataVisitor.h index 0951d487e2..d2d112bc65 100644 --- a/cocos2dx/cocoa/CCDataVisitor.h +++ b/cocos2dx/cocoa/CCDataVisitor.h @@ -51,14 +51,14 @@ class Data; * * Use cases: * - data serialization, - * - pretty printing of \a Object * - * - safe value reading from \a Array, \a Dictionary, \a Set + * - pretty printing of Object * + * - safe value reading from Array, Dictionary, Set * * Usage: * 1. subclass DataVisitor * 2. overload visit() methods for object that you need to handle - * 3. handle other objects in \a visitObject() - * 4. pass your visitor to \a Object::acceptVisitor() + * 3. handle other objects in visitObject() + * 4. pass your visitor to Object::acceptVisitor() */ class CC_DLL DataVisitor { diff --git a/cocos2dx/cocoa/CCGeometry.h b/cocos2dx/cocoa/CCGeometry.h index d734f2a22c..ec9c285418 100644 --- a/cocos2dx/cocoa/CCGeometry.h +++ b/cocos2dx/cocoa/CCGeometry.h @@ -63,7 +63,7 @@ public: Point(); Point(float x, float y); Point(const Point& other); - Point(const Size& size); + explicit Point(const Size& size); Point& operator= (const Point& other); Point& operator= (const Size& size); Point operator+(const Point& right) const; @@ -295,7 +295,7 @@ public: Size(); Size(float width, float height); Size(const Size& other); - Size(const Point& point); + explicit Size(const Point& point); Size& operator= (const Size& other); Size& operator= (const Point& point); Size operator+(const Size& right) const; diff --git a/cocos2dx/effects/CCGrid.cpp b/cocos2dx/effects/CCGrid.cpp index 870548d283..98ec059928 100644 --- a/cocos2dx/effects/CCGrid.cpp +++ b/cocos2dx/effects/CCGrid.cpp @@ -119,7 +119,8 @@ bool GridBase::initWithSize(const Size& gridSize) // we only use rgba8888 Texture2D::PixelFormat format = Texture2D::PixelFormat::RGBA8888; - void *data = calloc((int)(POTWide * POTHigh * 4), 1); + int dataLen = (int)(POTWide * POTHigh * 4); + void *data = calloc(dataLen, 1); if (! data) { CCLOG("cocos2d: Grid: not enough memory."); @@ -128,7 +129,7 @@ bool GridBase::initWithSize(const Size& gridSize) } Texture2D *texture = new Texture2D(); - texture->initWithData(data, format, POTWide, POTHigh, s); + texture->initWithData(data, dataLen, format, POTWide, POTHigh, s); free(data); diff --git a/cocos2dx/include/CCDeprecated.h b/cocos2dx/include/CCDeprecated.h index 2a0eb23e18..0aec4a4e8a 100644 --- a/cocos2dx/include/CCDeprecated.h +++ b/cocos2dx/include/CCDeprecated.h @@ -882,8 +882,8 @@ CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_I8 CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_AI88 = Texture2D::PixelFormat::AI88; CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_RGBA4444 = Texture2D::PixelFormat::RGBA4444; CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_RGB5A1 = Texture2D::PixelFormat::RGB5A1; -CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_PVRTC4 = Texture2D::PixelFormat::PRVTC4; -CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_PVRTC2 = Texture2D::PixelFormat::PRVTC2; +CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_PVRTC4 = Texture2D::PixelFormat::PVRTC4; +CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_PVRTC2 = Texture2D::PixelFormat::PVRTC2; CC_DEPRECATED_ATTRIBUTE const Texture2D::PixelFormat kCCTexture2DPixelFormat_Default = Texture2D::PixelFormat::DEFAULT; CC_DEPRECATED_ATTRIBUTE typedef Texture2D::PixelFormat CCTexture2DPixelFormat; diff --git a/cocos2dx/include/CCProtocols.h b/cocos2dx/include/CCProtocols.h index 01f361f078..f3d6c46cc3 100644 --- a/cocos2dx/include/CCProtocols.h +++ b/cocos2dx/include/CCProtocols.h @@ -186,7 +186,7 @@ public: /** * Sets a new label using an string * - * @param A null terminated string + * @param label A null terminated string */ virtual void setString(const char *label) = 0; diff --git a/cocos2dx/include/ccTypes.h b/cocos2dx/include/ccTypes.h index 8a3e7a0c7e..2f7f7203e5 100644 --- a/cocos2dx/include/ccTypes.h +++ b/cocos2dx/include/ccTypes.h @@ -412,8 +412,8 @@ public: : _fontSize(0) , _alignment(TextHAlignment::CENTER) , _vertAlignment(TextVAlignment::TOP) + , _dimensions(Size::ZERO) , _fontFillColor(Color3B::WHITE) - , _dimensions(Size::ZERO) {} // font name diff --git a/cocos2dx/include/cocos2d.h b/cocos2dx/include/cocos2d.h index b885a5895f..8ab33a8931 100755 --- a/cocos2dx/include/cocos2d.h +++ b/cocos2dx/include/cocos2d.h @@ -217,6 +217,14 @@ THE SOFTWARE. #include "platform/tizen/CCStdC.h" #endif // CC_TARGET_PLATFORM == CC_PLATFORM_TIZEN +#if (CC_TARGET_PLATFORM == CC_PLATFORM_QT5) + #include "platform/qt5/CCAccelerometer.h" + #include "platform/qt5/CCApplication.h" + #include "platform/qt5/CCEGLView.h" + #include "platform/qt5/CCGL.h" + #include "platform/qt5/CCStdC.h" +#endif // CC_TARGET_PLATFORM == CC_PLATFORM_QT5 + // script_support #include "script_support/CCScriptSupport.h" @@ -251,7 +259,6 @@ THE SOFTWARE. #include "textures/CCTexture2D.h" #include "textures/CCTextureAtlas.h" #include "textures/CCTextureCache.h" -#include "textures/CCTexturePVR.h" // tilemap_parallax_nodes #include "tilemap_parallax_nodes/CCParallaxNode.h" diff --git a/cocos2dx/kazmath/include/kazmath/neon_matrix_impl.h b/cocos2dx/kazmath/include/kazmath/neon_matrix_impl.h index aa85e6d276..a34145d95b 100644 --- a/cocos2dx/kazmath/include/kazmath/neon_matrix_impl.h +++ b/cocos2dx/kazmath/include/kazmath/neon_matrix_impl.h @@ -25,7 +25,7 @@ #define __NEON_MATRIX_IMPL_H__ #ifdef __arm__ -#if defined(__QNX__) || defined(ANDROID) || defined(I3D_ARCH_ARM) || defined(__native_client__) || defined(TIZEN) // MARMALADE CHANGE: Added for Marmalade support +#if defined(__QNX__) || defined(CC_TARGET_QT5)|| defined(ANDROID) || defined(I3D_ARCH_ARM) || defined(__native_client__) || defined(TIZEN) // MARMALADE CHANGE: Added for Marmalade support // blackberry and android don't have arm/arch.h but it defines __arm__ #else #include "arm/arch.h" diff --git a/cocos2dx/menu_nodes/CCMenuItem.h b/cocos2dx/menu_nodes/CCMenuItem.h index 592d3f9ebb..b6136f14d5 100644 --- a/cocos2dx/menu_nodes/CCMenuItem.h +++ b/cocos2dx/menu_nodes/CCMenuItem.h @@ -128,8 +128,8 @@ public: static MenuItemLabel* create(Node *label); MenuItemLabel() - : _label(NULL) - , _originalScale(0.0) + : _originalScale(0.0) + , _label(NULL) {} virtual ~MenuItemLabel(); diff --git a/cocos2dx/misc_nodes/CCMotionStreak.cpp b/cocos2dx/misc_nodes/CCMotionStreak.cpp index 1e65cbd587..8e3d5dc081 100644 --- a/cocos2dx/misc_nodes/CCMotionStreak.cpp +++ b/cocos2dx/misc_nodes/CCMotionStreak.cpp @@ -37,6 +37,7 @@ MotionStreak::MotionStreak() : _fastMode(false) , _startingPositionInitialized(false) , _texture(NULL) +, _blendFunc(BlendFunc::ALPHA_NON_PREMULTIPLIED) , _positionR(Point::ZERO) , _stroke(0.0f) , _fadeDelta(0.0f) @@ -49,7 +50,6 @@ MotionStreak::MotionStreak() , _vertices(NULL) , _colorPointer(NULL) , _texCoords(NULL) -, _blendFunc(BlendFunc::ALPHA_NON_PREMULTIPLIED) { } diff --git a/cocos2dx/misc_nodes/CCProgressTimer.cpp b/cocos2dx/misc_nodes/CCProgressTimer.cpp index dbc09d05c4..3493ad9313 100644 --- a/cocos2dx/misc_nodes/CCProgressTimer.cpp +++ b/cocos2dx/misc_nodes/CCProgressTimer.cpp @@ -46,12 +46,12 @@ const char kProgressTextureCoords = 0x4b; ProgressTimer::ProgressTimer() :_type(Type::RADIAL) +,_midpoint(0,0) +,_barChangeRate(0,0) ,_percentage(0.0f) ,_sprite(NULL) ,_vertexDataCount(0) ,_vertexData(NULL) -,_midpoint(0,0) -,_barChangeRate(0,0) ,_reverseDirection(false) {} diff --git a/cocos2dx/misc_nodes/CCRenderTexture.cpp b/cocos2dx/misc_nodes/CCRenderTexture.cpp index 5f321b9c75..7501275312 100644 --- a/cocos2dx/misc_nodes/CCRenderTexture.cpp +++ b/cocos2dx/misc_nodes/CCRenderTexture.cpp @@ -44,8 +44,7 @@ NS_CC_BEGIN // implementation RenderTexture RenderTexture::RenderTexture() -: _sprite(NULL) -, _FBO(0) +: _FBO(0) , _depthRenderBufffer(0) , _oldFBO(0) , _texture(0) @@ -57,6 +56,7 @@ RenderTexture::RenderTexture() , _clearDepth(0.0f) , _clearStencil(0) , _autoDraw(false) +, _sprite(NULL) { #if CC_ENABLE_CACHE_TEXTURE_DATA // Listen this event to save render texture before come to background. @@ -102,11 +102,11 @@ void RenderTexture::listenToBackground(cocos2d::Object *obj) if (_UITextureImage) { const Size& s = _texture->getContentSizeInPixels(); - VolatileTexture::addDataTexture(_texture, _UITextureImage->getData(), Texture2D::PixelFormat::RGBA8888, s); + VolatileTexture::addDataTexture(_texture, _UITextureImage->getData(), s.width * s.height * 4, Texture2D::PixelFormat::RGBA8888, s); if ( _textureCopy ) { - VolatileTexture::addDataTexture(_textureCopy, _UITextureImage->getData(), Texture2D::PixelFormat::RGBA8888, s); + VolatileTexture::addDataTexture(_textureCopy, _UITextureImage->getData(), s.width * s.height * 4, Texture2D::PixelFormat::RGBA8888, s); } } else @@ -212,16 +212,17 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, Texture2D::PixelFormat powH = ccNextPOT(h); } - data = malloc((int)(powW * powH * 4)); + int dataLen = (int)(powW * powH * 4); + data = malloc(dataLen); CC_BREAK_IF(! data); - memset(data, 0, (int)(powW * powH * 4)); + memset(data, 0, dataLen); _pixelFormat = eFormat; _texture = new Texture2D(); if (_texture) { - _texture->initWithData(data, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); + _texture->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); } else { @@ -235,7 +236,7 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, Texture2D::PixelFormat _textureCopy = new Texture2D(); if (_textureCopy) { - _textureCopy->initWithData(data, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); + _textureCopy->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); } else { @@ -623,11 +624,11 @@ Image* RenderTexture::newImage(bool fliimage) nSavedBufferWidth * 4); } - image->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, Image::Format::RAW_DATA, nSavedBufferWidth, nSavedBufferHeight, 8); + image->initWithRawData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, nSavedBufferWidth, nSavedBufferHeight, 8); } else { - image->initWithImageData(pTempData, nSavedBufferWidth * nSavedBufferHeight * 4, Image::Format::RAW_DATA, nSavedBufferWidth, nSavedBufferHeight, 8); + image->initWithRawData(pTempData, nSavedBufferWidth * nSavedBufferHeight * 4, nSavedBufferWidth, nSavedBufferHeight, 8); } } while (0); diff --git a/cocos2dx/particle_nodes/CCParticleExamples.cpp b/cocos2dx/particle_nodes/CCParticleExamples.cpp index d117f7748d..0602a2a03e 100644 --- a/cocos2dx/particle_nodes/CCParticleExamples.cpp +++ b/cocos2dx/particle_nodes/CCParticleExamples.cpp @@ -47,7 +47,7 @@ static Texture2D* getDefaultTexture() pImage = new Image(); CC_BREAK_IF(NULL == pImage); - bRet = pImage->initWithImageData((void*)__firePngData, sizeof(__firePngData), Image::Format::PNG); + bRet = pImage->initWithImageData((void*)__firePngData, sizeof(__firePngData)); CC_BREAK_IF(!bRet); texture = TextureCache::getInstance()->addUIImage(pImage, key); diff --git a/cocos2dx/particle_nodes/CCParticleSystem.cpp b/cocos2dx/particle_nodes/CCParticleSystem.cpp index 90aa34e547..865d05ec86 100644 --- a/cocos2dx/particle_nodes/CCParticleSystem.cpp +++ b/cocos2dx/particle_nodes/CCParticleSystem.cpp @@ -81,7 +81,9 @@ NS_CC_BEGIN // ParticleSystem::ParticleSystem() -: _plistFile("") +: _isBlendAdditive(false) +, _isAutoRemoveOnFinish(false) +, _plistFile("") , _elapsed(0) , _particles(NULL) , _emitCounter(0) @@ -99,6 +101,7 @@ ParticleSystem::ParticleSystem() , _lifeVar(0) , _angle(0) , _angleVar(0) +, _emitterMode(Mode::GRAVITY) , _startSize(0) , _startSizeVar(0) , _endSize(0) @@ -110,12 +113,9 @@ ParticleSystem::ParticleSystem() , _emissionRate(0) , _totalParticles(0) , _texture(NULL) -, _opacityModifyRGB(false) -, _isBlendAdditive(false) -, _positionType(PositionType::FREE) -, _isAutoRemoveOnFinish(false) -, _emitterMode(Mode::GRAVITY) , _blendFunc(BlendFunc::ALPHA_PREMULTIPLIED) +, _opacityModifyRGB(false) +, _positionType(PositionType::FREE) { modeA.gravity = Point::ZERO; modeA.speed = 0; diff --git a/cocos2dx/platform/CCEGLViewProtocol.cpp b/cocos2dx/platform/CCEGLViewProtocol.cpp index 17448f9871..01ced6e3e0 100644 --- a/cocos2dx/platform/CCEGLViewProtocol.cpp +++ b/cocos2dx/platform/CCEGLViewProtocol.cpp @@ -55,6 +55,10 @@ EGLViewProtocol::~EGLViewProtocol() } +void EGLViewProtocol::pollInputEvents() +{ +} + void EGLViewProtocol::setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy) { CCASSERT(resolutionPolicy != ResolutionPolicy::UNKNOWN, "should set resolutionPolicy"); diff --git a/cocos2dx/platform/CCEGLViewProtocol.h b/cocos2dx/platform/CCEGLViewProtocol.h index 5cfb959032..27edb743c8 100644 --- a/cocos2dx/platform/CCEGLViewProtocol.h +++ b/cocos2dx/platform/CCEGLViewProtocol.h @@ -58,6 +58,12 @@ public: /** Open or close IME keyboard , subclass must implement this method. */ virtual void setIMEKeyboardState(bool bOpen) = 0; + /** + * Polls input events. Subclass must implement methods if platform + * does not provide event callbacks. + */ + virtual void pollInputEvents(); + /** * Get the frame size of EGL view. * In general, it returns the screen size since the EGL view is a fullscreen view. diff --git a/cocos2dx/platform/CCImage.h b/cocos2dx/platform/CCImage.h index 81eb450db1..7e55f8e64f 100644 --- a/cocos2dx/platform/CCImage.h +++ b/cocos2dx/platform/CCImage.h @@ -26,6 +26,7 @@ THE SOFTWARE. #define __CC_IMAGE_H__ #include "cocoa/CCObject.h" +#include "textures/CCTexture2D.h" // premultiply alpha, or the effect will wrong when want to use other pixel format in Texture2D, // such as RGB888, RGB5A1 @@ -41,6 +42,14 @@ NS_CC_BEGIN * @addtogroup platform * @{ */ + +/** + @brief Structure which can tell where mipmap begins and how long is it +*/ +typedef struct _MipmapInfo { + unsigned char* address; + int len; +}MipmapInfo; class CC_DLL Image : public Object { @@ -49,6 +58,14 @@ public: Image(); virtual ~Image(); + + /** + @brief Determine how many mipmaps can we have. + Its same as define but it respects namespaces + */ + enum { + CC_MIPMAP_MAX = 16, + }; /** Supported formats for Image */ enum class Format @@ -61,6 +78,10 @@ public: TIFF, //! WebP WEBP, + //! PVR + PVR, + //! ETC + ETC, //! Raw Data RAW_DATA, //! Unknown format @@ -86,26 +107,18 @@ public: @param imageType the type of image, currently only supporting two types. @return true if loaded correctly. */ - bool initWithImageFile(const char * strPath, Format imageType = Format::PNG); + bool initWithImageFile(const char * strPath); /** @brief Load image from stream buffer. - - @warning kFmtRawData only supports RGBA8888. - @param pBuffer stream buffer which holds the image data. - @param nLength data length expressed in (number of) bytes. - @param nWidth, nHeight, nBitsPerComponent are used for kFmtRawData. + @param data stream buffer which holds the image data. + @param dataLen data length expressed in (number of) bytes. @return true if loaded correctly. */ - bool initWithImageData(void * pData, - int nDataLen, - Format eFmt = Format::UNKOWN, - int nWidth = 0, - int nHeight = 0, - int nBitsPerComponent = 8); + bool initWithImageData(void * data, int dataLen); // @warning kFmtRawData only support RGBA8888 - bool initWithRawData(void *pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent, bool bPreMulti); + bool initWithRawData(void *data, int dataLen, int nWidth, int nHeight, int nBitsPerComponent = 8, bool bPreMulti = false); /** @brief Create image with specified string. @@ -130,7 +143,7 @@ public: const char * pText, int nWidth = 0, int nHeight = 0, - TextAlign eAlignMask = TextAlign::CENTER, + TextAlign eAlignMask = TextAlign::CENTER, const char * pFontName = 0, int nSize = 0, float textTintR = 1, @@ -151,6 +164,23 @@ public: #endif + + // Getters + inline unsigned char * getData() { return _data; } + inline int getDataLen() { return _dataLen; } + inline Format getFileType() {return _fileType; } + inline Texture2D::PixelFormat getRenderFormat() { return _renderFormat; } + inline int getWidth() { return _width; } + inline int getHeight() { return _height; } + inline bool isPremultipliedAlpha() { return _preMulti; } + inline int getNumberOfMipmaps() { return _numberOfMipmaps; } + inline MipmapInfo* getMipmaps() { return _mipmaps; } + inline bool hasPremultipliedAlpha() { return _hasPremultipliedAlpha; } + + int getBitPerPixel(); + bool hasAlpha(); + bool isCompressed(); + /** @brief Save Image data to the specified file, with specified format. @@ -158,35 +188,35 @@ public: @param bIsToRGB whether the image is saved as RGB format. */ bool saveToFile(const char *pszFilePath, bool bIsToRGB = true); - - // Getters - inline unsigned char * getData() { return _data; } - inline int getDataLen() { return _width * _height; } - inline bool hasAlpha() { return _hasAlpha; } - inline bool isPremultipliedAlpha() { return _preMulti; } - - inline unsigned short getWidth() { return _width; }; - inline unsigned short getHeight() { return _height; }; - inline int getBitsPerComponent() { return _bitsPerComponent; }; - // - protected: - bool initWithJpgData(void *pData, int nDatalen); - bool initWithPngData(void *pData, int nDatalen); - bool initWithTiffData(void *pData, int nDataLen); - bool initWithWebpData(void *pData, int nDataLen); + bool initWithJpgData(void *data, int dataLen); + bool initWithPngData(void *data, int dataLen); + bool initWithTiffData(void *data, int dataLen); + bool initWithWebpData(void *data, int dataLen); + bool initWithPVRData(void *data, int dataLen); + bool initWithPVRv2Data(void *data, int dataLen); + bool initWithPVRv3Data(void *data, int dataLen); + bool initWithETCData(void *data, int dataLen); bool saveImageToPNG(const char *pszFilePath, bool bIsToRGB = true); bool saveImageToJPG(const char *pszFilePath); - unsigned short _width; - unsigned short _height; - int _bitsPerComponent; - +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + bool iosSaveToFile(const char *pszFilePath, bool bIsToRGB = true); +#endif + unsigned char *_data; - bool _hasAlpha; + int _dataLen; + int _width; + int _height; + Format _fileType; + Texture2D::PixelFormat _renderFormat; bool _preMulti; + MipmapInfo _mipmaps[CC_MIPMAP_MAX]; // pointer to mipmap images + int _numberOfMipmaps; + // false if we cann't auto detect the image is premultiplied or not. + bool _hasPremultipliedAlpha; private: @@ -201,7 +231,17 @@ private: @param imageType the type of image, currently only supporting two types. @return true if loaded correctly. */ - bool initWithImageFileThreadSafe(const char *fullpath, Format imageType = Format::PNG); + bool initWithImageFileThreadSafe(const char *fullpath); + + Format detectFormat(void* data, int dataLen); + bool isPng(void *data, int dataLen); + bool isJpg(void *data, int dataLen); + bool isTiff(void *data, int dataLen); + bool isWebp(void *data, int dataLen); + bool isPvr(void *data, int dataLen); + bool isEtc(void *data, int dataLen); + + bool testFormatForPvrTCSupport(uint64_t format); }; // end of platform group diff --git a/cocos2dx/platform/CCImageCommonWebp.cpp b/cocos2dx/platform/CCImageCommonWebp.cpp deleted file mode 100644 index 45f181d194..0000000000 --- a/cocos2dx/platform/CCImageCommonWebp.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010 cocos2d-x.org - - 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 - 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 "platform/CCImage.h" -#include "textures/CCTexture2D.h" -#if defined(__native_client__) || defined(EMSCRIPTEN) -// TODO(sbc): I'm pretty sure all platforms should be including -// webph headers in this way. -#include "webp/decode.h" -#else -#include "decode.h" -#endif -#include "ccMacros.h" -#include -#include -#include - -NS_CC_BEGIN - -bool Image::initWithWebpData(void *pData, int nDataLen) -{ - bool bRet = false; - do - { - WebPDecoderConfig config; - if (WebPInitDecoderConfig(&config) == 0) break; - if (WebPGetFeatures((uint8_t*)pData, nDataLen, &config.input) != VP8_STATUS_OK) break; - if (config.input.width == 0 || config.input.height == 0) break; - - config.output.colorspace = MODE_RGBA; - _bitsPerComponent = 8; - _width = config.input.width; - _height = config.input.height; - _hasAlpha = true; - - int bufferSize = _width * _height * 4; - _data = new unsigned char[bufferSize]; - - config.output.u.RGBA.rgba = (uint8_t*)_data; - config.output.u.RGBA.stride = _width * 4; - config.output.u.RGBA.size = bufferSize; - config.output.is_external_memory = 1; - - if (WebPDecode((uint8_t*)pData, nDataLen, &config) != VP8_STATUS_OK) - { - delete []_data; - _data = NULL; - break; - } - - bRet = true; - } while (0); - return bRet; -} - -NS_CC_END diff --git a/cocos2dx/platform/CCImageCommon_cpp.h b/cocos2dx/platform/CCImageCommon_cpp.h index bdd3d40121..e882487952 100644 --- a/cocos2dx/platform/CCImageCommon_cpp.h +++ b/cocos2dx/platform/CCImageCommon_cpp.h @@ -22,20 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ -#ifndef __CC_PLATFORM_IMAGE_CPP__ -#error "CCFileUtilsCommon_cpp.h can only be included for FileUtils.cpp in platform/win32(android,...)" -#endif /* __CC_PLATFORM_IMAGE_CPP__ */ #include "CCImage.h" -#include "CCCommon.h" -#include "CCStdC.h" -#include "CCFileUtils.h" -#include "png.h" -#include "jpeglib.h" -#include "tiffio.h" -#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) -#include "platform/android/CCFileUtilsAndroid.h" -#endif #include #include @@ -45,9 +33,180 @@ THE SOFTWARE. #include #endif // EMSCRIPTEN +#include "png.h" +#include "jpeglib.h" +#include "tiffio.h" +#include "etc1.h" +#if defined(__native_client__) || defined(EMSCRIPTEN) +// TODO(sbc): I'm pretty sure all platforms should be including +// webph headers in this way. +#include "webp/decode.h" +#else +#include "decode.h" +#endif + +#include "ccMacros.h" +#include "CCCommon.h" +#include "CCStdC.h" +#include "CCFileUtils.h" +#include "CCConfiguration.h" +#include "support/ccUtils.h" +#include "support/zip_support/ZipUtils.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) +#include "platform/android/CCFileUtilsAndroid.h" +#endif + NS_CC_BEGIN -// on ios, we should use platform/ios/CCImage_ios.mm instead +////////////////////////////////////////////////////////////////////////// +//struct and data for pvr structure +#define PVR_TEXTURE_FLAG_TYPE_MASK 0xff + +// Values taken from PVRTexture.h from http://www.imgtec.com +enum { + kPVR2TextureFlagMipmap = (1<<8), // has mip map levels + kPVR2TextureFlagTwiddle = (1<<9), // is twiddled + kPVR2TextureFlagBumpmap = (1<<10), // has normals encoded for a bump map + kPVR2TextureFlagTiling = (1<<11), // is bordered for tiled pvr + kPVR2TextureFlagCubemap = (1<<12), // is a cubemap/skybox + kPVR2TextureFlagFalseMipCol = (1<<13), // are there false colored MIP levels + kPVR2TextureFlagVolume = (1<<14), // is this a volume texture + kPVR2TextureFlagAlpha = (1<<15), // v2.1 is there transparency info in the texture + kPVR2TextureFlagVerticalFlip = (1<<16), // v2.1 is the texture vertically flipped +}; + +enum { + kPVR3TextureFlagPremultipliedAlpha = (1<<1) // has premultiplied alpha +}; + +static char gPVRTexIdentifier[5] = "PVR!"; + +// v2 +typedef enum +{ + kPVR2TexturePixelFormat_RGBA_4444= 0x10, + kPVR2TexturePixelFormat_RGBA_5551, + kPVR2TexturePixelFormat_RGBA_8888, + kPVR2TexturePixelFormat_RGB_565, + kPVR2TexturePixelFormat_RGB_555, // unsupported + kPVR2TexturePixelFormat_RGB_888, + kPVR2TexturePixelFormat_I_8, + kPVR2TexturePixelFormat_AI_88, + kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA, + kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA, + kPVR2TexturePixelFormat_BGRA_8888, + kPVR2TexturePixelFormat_A_8, +} ccPVR2TexturePixelFormat; + +// v3 +/* supported predefined formats */ +#define kPVR3TexturePixelFormat_PVRTC_2BPP_RGB 0 +#define kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA 1 +#define kPVR3TexturePixelFormat_PVRTC_4BPP_RGB 2 +#define kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA 3 + +/* supported channel type formats */ +#define kPVR3TexturePixelFormat_BGRA_8888 0x0808080861726762ULL +#define kPVR3TexturePixelFormat_RGBA_8888 0x0808080861626772ULL +#define kPVR3TexturePixelFormat_RGBA_4444 0x0404040461626772ULL +#define kPVR3TexturePixelFormat_RGBA_5551 0x0105050561626772ULL +#define kPVR3TexturePixelFormat_RGB_565 0x0005060500626772ULL +#define kPVR3TexturePixelFormat_RGB_888 0x0008080800626772ULL +#define kPVR3TexturePixelFormat_A_8 0x0000000800000061ULL +#define kPVR3TexturePixelFormat_L_8 0x000000080000006cULL +#define kPVR3TexturePixelFormat_LA_88 0x000008080000616cULL + + +// v2 +typedef const std::map _pixel_formathash; + +static _pixel_formathash::value_type v2_pixel_formathash_value[] = +{ + _pixel_formathash::value_type(kPVR2TexturePixelFormat_BGRA_8888, Texture2D::PixelFormat::BGRA8888), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_RGBA_8888, Texture2D::PixelFormat::RGBA8888), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_RGBA_4444, Texture2D::PixelFormat::RGBA4444), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_RGBA_5551, Texture2D::PixelFormat::RGB5A1), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_RGB_565, Texture2D::PixelFormat::RGB565), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_RGB_888, Texture2D::PixelFormat::RGB888), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_A_8, Texture2D::PixelFormat::A8), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_I_8, Texture2D::PixelFormat::I8), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_AI_88, Texture2D::PixelFormat::AI88), + +#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + _pixel_formathash::value_type(kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA, Texture2D::PixelFormat::PVRTC2A), + _pixel_formathash::value_type(kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA, Texture2D::PixelFormat::PVRTC4A), +#endif +}; + +#define PVR2_MAX_TABLE_ELEMENTS (sizeof(v2_pixel_formathash_value) / sizeof(v2_pixel_formathash_value[0])) +static _pixel_formathash v2_pixel_formathash(v2_pixel_formathash_value, v2_pixel_formathash_value + PVR2_MAX_TABLE_ELEMENTS); + +// v3 +static _pixel_formathash::value_type v3_pixel_formathash_value[] = +{ + _pixel_formathash::value_type(kPVR3TexturePixelFormat_BGRA_8888, Texture2D::PixelFormat::BGRA8888), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_RGBA_8888, Texture2D::PixelFormat::RGBA8888), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_RGBA_4444, Texture2D::PixelFormat::RGBA4444), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_RGBA_5551, Texture2D::PixelFormat::RGB5A1), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_RGB_565, Texture2D::PixelFormat::RGB565), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_RGB_888, Texture2D::PixelFormat::RGB888), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_A_8, Texture2D::PixelFormat::A8), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_L_8, Texture2D::PixelFormat::I8), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_LA_88, Texture2D::PixelFormat::AI88), + +#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + _pixel_formathash::value_type(kPVR3TexturePixelFormat_PVRTC_2BPP_RGB, Texture2D::PixelFormat::PVRTC2), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA, Texture2D::PixelFormat::PVRTC2A), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_PVRTC_4BPP_RGB, Texture2D::PixelFormat::PVRTC4), + _pixel_formathash::value_type(kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA, Texture2D::PixelFormat::PVRTC4A), +#endif +}; + +#define PVR3_MAX_TABLE_ELEMENTS (sizeof(v3_pixel_formathash_value) / sizeof(v3_pixel_formathash_value[0])) +static _pixel_formathash v3_pixel_formathash(v3_pixel_formathash_value, v3_pixel_formathash_value + PVR3_MAX_TABLE_ELEMENTS); + +typedef struct _PVRTexHeader +{ + unsigned int headerLength; + unsigned int height; + unsigned int width; + unsigned int numMipmaps; + unsigned int flags; + unsigned int dataLength; + unsigned int bpp; + unsigned int bitmaskRed; + unsigned int bitmaskGreen; + unsigned int bitmaskBlue; + unsigned int bitmaskAlpha; + unsigned int pvrTag; + unsigned int numSurfs; +} ccPVRv2TexHeader; + +#ifdef _MSC_VER +#pragma pack(push,1) +#endif +typedef struct { + uint32_t version; + uint32_t flags; + uint64_t pixelFormat; + uint32_t colorSpace; + uint32_t channelType; + uint32_t height; + uint32_t width; + uint32_t depth; + uint32_t numberOfSurfaces; + uint32_t numberOfFaces; + uint32_t numberOfMipmaps; + uint32_t metadataLength; +#ifdef _MSC_VER +} ccPVRv3TexHeader; +#pragma pack(pop) +#else +} __attribute__((packed)) ccPVRv3TexHeader; +#endif +//pvr structure end +////////////////////////////////////////////////////////////////////////// + typedef struct { @@ -76,12 +235,15 @@ static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t leng ////////////////////////////////////////////////////////////////////////// Image::Image() -: _width(0) +: _data(0) +, _dataLen(0) +, _width(0) , _height(0) -, _bitsPerComponent(0) -, _data(0) -, _hasAlpha(false) +, _fileType(Format::UNKOWN) +, _renderFormat(Texture2D::PixelFormat::NONE) , _preMulti(false) +, _hasPremultipliedAlpha(true) +, _numberOfMipmaps(0) { } @@ -91,7 +253,7 @@ Image::~Image() CC_SAFE_DELETE_ARRAY(_data); } -bool Image::initWithImageFile(const char * strPath, Format eImgFmt/* = eFmtPng*/) +bool Image::initWithImageFile(const char * strPath) { bool bRet = false; std::string fullPath = FileUtils::getInstance()->fullPathForFilename(strPath); @@ -116,122 +278,196 @@ bool Image::initWithImageFile(const char * strPath, Format eImgFmt/* = eFmtPng*/ SDL_FreeSurface(iSurf); #else - unsigned long nSize = 0; - unsigned char* pBuffer = FileUtils::getInstance()->getFileData(fullPath.c_str(), "rb", &nSize); - if (pBuffer != NULL && nSize > 0) + unsigned long bufferLen = 0; + unsigned char* buffer = nullptr; + + //detecgt and unzip the compress file + if (ZipUtils::ccIsCCZFile(fullPath.c_str())) { - bRet = initWithImageData(pBuffer, nSize, eImgFmt); + bufferLen = ZipUtils::ccInflateCCZFile(fullPath.c_str(), &buffer); + }else if (ZipUtils::ccIsGZipFile(fullPath.c_str())) + { + bufferLen = ZipUtils::ccInflateGZipFile(fullPath.c_str(), &buffer); } - CC_SAFE_DELETE_ARRAY(pBuffer); + else + { + buffer = FileUtils::getInstance()->getFileData(fullPath.c_str(), "rb", &bufferLen); + } + + if (buffer != NULL && bufferLen > 0) + { + bRet = initWithImageData(buffer, bufferLen); + } + + CC_SAFE_DELETE_ARRAY(buffer); #endif // EMSCRIPTEN return bRet; } -bool Image::initWithImageFileThreadSafe(const char *fullpath, Format imageType) +bool Image::initWithImageFileThreadSafe(const char *fullpath) { bool bRet = false; - unsigned long nSize = 0; + unsigned long dataLen = 0; #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) FileUtilsAndroid *fileUitls = (FileUtilsAndroid*)FileUtils::getInstance(); - unsigned char *pBuffer = fileUitls->getFileDataForAsync(fullpath, "rb", &nSize); + unsigned char *pBuffer = fileUitls->getFileDataForAsync(fullpath, "rb", &dataLen); #else - unsigned char *pBuffer = FileUtils::getInstance()->getFileData(fullpath, "rb", &nSize); + unsigned char *pBuffer = FileUtils::getInstance()->getFileData(fullpath, "rb", &dataLen); #endif - if (pBuffer != NULL && nSize > 0) + if (pBuffer != NULL && dataLen > 0) { - bRet = initWithImageData(pBuffer, nSize, imageType); + bRet = initWithImageData(pBuffer, dataLen); } CC_SAFE_DELETE_ARRAY(pBuffer); return bRet; } -bool Image::initWithImageData(void * pData, - int nDataLen, - Format eFmt/* = eSrcFmtPng*/, - int nWidth/* = 0*/, - int nHeight/* = 0*/, - int nBitsPerComponent/* = 8*/) +bool Image::initWithImageData(void * data, int dataLen) { - bool bRet = false; do { - CC_BREAK_IF(! pData || nDataLen <= 0); + CC_BREAK_IF(! data || dataLen <= 0); - if (Format::PNG == eFmt) - { - bRet = initWithPngData(pData, nDataLen); - break; - } - else if (Format::JPG == eFmt) - { - bRet = initWithJpgData(pData, nDataLen); - break; - } - else if (Format::TIFF == eFmt) - { - bRet = initWithTiffData(pData, nDataLen); - break; - } - else if (Format::WEBP == eFmt) - { - bRet = initWithWebpData(pData, nDataLen); - break; - } - else if (Format::RAW_DATA == eFmt) - { - bRet = initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent, false); - break; - } - else - { - // if it is a png file buffer. - if (nDataLen > 8) - { - unsigned char* pHead = (unsigned char*)pData; - if ( pHead[0] == 0x89 - && pHead[1] == 0x50 - && pHead[2] == 0x4E - && pHead[3] == 0x47 - && pHead[4] == 0x0D - && pHead[5] == 0x0A - && pHead[6] == 0x1A - && pHead[7] == 0x0A) - { - bRet = initWithPngData(pData, nDataLen); - break; - } - } + _fileType = detectFormat(data, dataLen); - // if it is a tiff file buffer. - if (nDataLen > 2) - { - unsigned char* pHead = (unsigned char*)pData; - if ( (pHead[0] == 0x49 && pHead[1] == 0x49) - || (pHead[0] == 0x4d && pHead[1] == 0x4d) - ) - { - bRet = initWithTiffData(pData, nDataLen); - break; - } - } - - // if it is a jpeg file buffer. - if (nDataLen > 2) - { - unsigned char* pHead = (unsigned char*)pData; - if ( pHead[0] == 0xff - && pHead[1] == 0xd8) - { - bRet = initWithJpgData(pData, nDataLen); - break; - } - } + switch (_fileType) + { + case Format::PNG: + return initWithPngData(data, dataLen); + case Format::JPG: + return initWithJpgData(data, dataLen); + case Format::TIFF: + return initWithTiffData(data, dataLen); + case Format::WEBP: + return initWithWebpData(data, dataLen); + case Format::PVR: + return initWithPVRData(data, dataLen); + case Format::ETC: + return initWithETCData(data, dataLen); + default: + CCAssert(false, "unsupport image format!"); + return false; } } while (0); - return bRet; + + return false; } +bool Image::isPng(void *data, int dataLen) +{ + if (dataLen <= 8) + { + return false; + } + + static const unsigned char PNG_SIGNATURE[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}; + + return memcmp(PNG_SIGNATURE, data, sizeof(PNG_SIGNATURE)) == 0; +} + + +bool Image::isEtc(void *data, int dataLen) +{ + return (bool)etc1_pkm_is_valid((etc1_byte*)data); +} + +bool Image::isJpg(void *data, int dataLen) +{ + if (dataLen <= 4) + { + return false; + } + + static const unsigned char JPG_SOI[] = {0xFF, 0xD8}; + + return memcmp(data, JPG_SOI, 2) == 0; +} + +bool Image::isTiff(void *data, int dataLen) +{ + if (dataLen <= 4) + { + return false; + } + + static const char* TIFF_II = "II"; + static const char* TIFF_MM = "MM"; + + return (memcmp(data, TIFF_II, 2) == 0 && *((const char*)data + 2) == 42 && *((const char*)data + 3) == 0) + || (memcmp(data, TIFF_MM, 2) == 0 && *((const char*)data + 2) == 0 && *((const char*)data + 3) == 42); +} + +bool Image::isWebp(void *data, int dataLen) +{ + if (dataLen <= 12) + { + return false; + } + + static const char* WEBP_RIFF = "RIFF"; + static const char* WEBP_WEBP = "WEBP"; + + return memcmp(data, WEBP_RIFF, 4) == 0 + && memcmp((unsigned char*)data + 8, WEBP_WEBP, 4) == 0; +} + +bool Image::isPvr(void *data, int dataLen) +{ + if (dataLen < sizeof(ccPVRv2TexHeader) || dataLen < sizeof(ccPVRv3TexHeader)) + { + return false; + } + + ccPVRv2TexHeader* headerv2 = (ccPVRv2TexHeader*)data; + ccPVRv3TexHeader* headerv3 = (ccPVRv3TexHeader*)data; + + return memcmp(&headerv2->pvrTag, gPVRTexIdentifier, strlen(gPVRTexIdentifier)) == 0 || CC_SWAP_INT32_BIG_TO_HOST(headerv3->version) == 0x50565203; +} + + +Image::Format Image::detectFormat(void* data, int dataLen) +{ + if (isPng(data, dataLen)) + { + return Format::PNG; + }else if (isJpg(data, dataLen)) + { + return Format::JPG; + }else if (isTiff(data, dataLen)) + { + return Format::TIFF; + }else if (isWebp(data, dataLen)) + { + return Format::WEBP; + }else if (isPvr(data, dataLen)) + { + return Format::PVR; + }else if (isEtc(data, dataLen)) + { + return Format::ETC; + } + + else + { + return Format::UNKOWN; + } +} + +int Image::getBitPerPixel() +{ + return g_texturePixelFormatInfoTables.at(_renderFormat).bpp; +} + +bool Image::hasAlpha() +{ + return g_texturePixelFormatInfoTables.at(_renderFormat).alpha; +} + +bool Image::isCompressed() +{ + return g_texturePixelFormatInfoTables.at(_renderFormat).compressed; +} /* * ERROR HANDLING: * @@ -281,7 +517,7 @@ my_error_exit (j_common_ptr cinfo) longjmp(myerr->setjmp_buffer, 1); } -bool Image::initWithJpgData(void * data, int nSize) +bool Image::initWithJpgData(void * data, int dataLen) { /* these are standard libjpeg structures for reading(decompression) */ struct jpeg_decompress_struct cinfo; @@ -314,7 +550,9 @@ bool Image::initWithJpgData(void * data, int nSize) /* setup decompression process and source, then read JPEG header */ jpeg_create_decompress( &cinfo ); - jpeg_mem_src( &cinfo, (unsigned char *) data, nSize ); +#ifndef CC_TARGET_QT5 + jpeg_mem_src( &cinfo, (unsigned char *) data, dataLen ); +#endif /* CC_TARGET_QT5 */ /* reading the image header which contains image information */ #if (JPEG_LIB_VERSION >= 90) @@ -325,16 +563,13 @@ bool Image::initWithJpgData(void * data, int nSize) #endif // we only support RGB or grayscale - if (cinfo.jpeg_color_space != JCS_RGB) + if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { - if (cinfo.jpeg_color_space == JCS_GRAYSCALE || cinfo.jpeg_color_space == JCS_YCbCr) - { - cinfo.out_color_space = JCS_RGB; - } - } - else + _renderFormat = Texture2D::PixelFormat::I8; + }else { - break; + cinfo.out_color_space = JCS_RGB; + _renderFormat = Texture2D::PixelFormat::RGB888; } /* Start decompression jpeg here */ @@ -343,13 +578,12 @@ bool Image::initWithJpgData(void * data, int nSize) /* init image info */ _width = (short)(cinfo.output_width); _height = (short)(cinfo.output_height); - _hasAlpha = false; _preMulti = false; - _bitsPerComponent = 8; row_pointer[0] = new unsigned char[cinfo.output_width*cinfo.output_components]; CC_BREAK_IF(! row_pointer[0]); - _data = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components]; + _dataLen = cinfo.output_width*cinfo.output_height*cinfo.output_components; + _data = new unsigned char[_dataLen]; CC_BREAK_IF(! _data); /* now actually read the jpeg into the raw buffer */ @@ -378,9 +612,9 @@ bool Image::initWithJpgData(void * data, int nSize) return bRet; } -bool Image::initWithPngData(void * pData, int nDatalen) +bool Image::initWithPngData(void * data, int dataLen) { -// length of bytes to check if it is a valid png file + // length of bytes to check if it is a valid png file #define PNGSIGSIZE 8 bool bRet = false; png_byte header[PNGSIGSIZE] = {0}; @@ -390,10 +624,10 @@ bool Image::initWithPngData(void * pData, int nDatalen) do { // png header len is 8 bytes - CC_BREAK_IF(nDatalen < PNGSIGSIZE); + CC_BREAK_IF(dataLen < PNGSIGSIZE); // check the data is png or not - memcpy(header, pData, PNGSIGSIZE); + memcpy(header, data, PNGSIGSIZE); CC_BREAK_IF(png_sig_cmp(header, 0, PNGSIGSIZE)); // init png_struct @@ -410,23 +644,23 @@ bool Image::initWithPngData(void * pData, int nDatalen) // set the read call back function tImageSource imageSource; - imageSource.data = (unsigned char*)pData; - imageSource.size = nDatalen; + imageSource.data = (unsigned char*)data; + imageSource.size = dataLen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png header info - + // read png file info png_read_info(png_ptr, info_ptr); - + _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); - _bitsPerComponent = png_get_bit_depth(png_ptr, info_ptr); + png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); //CCLOG("color type %u", color_type); - + // force palette images to be expanded to 24-bit RGB // it may include alpha channel if (color_type == PNG_COLOR_TYPE_PALETTE) @@ -434,8 +668,9 @@ bool Image::initWithPngData(void * pData, int nDatalen) png_set_palette_to_rgb(png_ptr); } // low-bit-depth grayscale images are to be expanded to 8 bits - if (color_type == PNG_COLOR_TYPE_GRAY && _bitsPerComponent < 8) + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + bit_depth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } // expand any tRNS chunk data into a full alpha channel @@ -444,53 +679,57 @@ bool Image::initWithPngData(void * pData, int nDatalen) png_set_tRNS_to_alpha(png_ptr); } // reduce images with 16-bit samples to 8 bits - if (_bitsPerComponent == 16) + if (bit_depth == 16) { png_set_strip_16(png_ptr); } - // expand grayscale images to RGB - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + + // Expanded earlier for grayscale, now take care of palette and rgb + if (bit_depth < 8) { + png_set_packing(png_ptr); + } + // update info + png_read_update_info(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + color_type = png_get_color_type(png_ptr, info_ptr); + + switch (color_type) { - png_set_gray_to_rgb(png_ptr); + case PNG_COLOR_TYPE_GRAY: + _renderFormat = Texture2D::PixelFormat::I8; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + _renderFormat = Texture2D::PixelFormat::AI88; + break; + case PNG_COLOR_TYPE_RGB: + _renderFormat = Texture2D::PixelFormat::RGB888; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + _renderFormat = Texture2D::PixelFormat::RGBA8888; + break; + default: + break; } // read png data - // _bitsPerComponent will always be 8 - _bitsPerComponent = 8; png_uint_32 rowbytes; png_bytep* row_pointers = (png_bytep*)malloc( sizeof(png_bytep) * _height ); - - png_read_update_info(png_ptr, info_ptr); - + rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - _data = new unsigned char[rowbytes * _height]; + + _dataLen = rowbytes * _height; + _data = new unsigned char[_dataLen]; CC_BREAK_IF(!_data); - + for (unsigned short i = 0; i < _height; ++i) { row_pointers[i] = _data + i*rowbytes; } png_read_image(png_ptr, row_pointers); - + png_read_end(png_ptr, NULL); - - png_uint_32 channel = rowbytes/_width; - if (channel == 4) - { - _hasAlpha = true; - unsigned int *tmp = (unsigned int *)_data; - for(unsigned short i = 0; i < _height; i++) - { - for(unsigned int j = 0; j < rowbytes; j += 4) - { - *tmp++ = CC_RGB_PREMULTIPLY_ALPHA( row_pointers[i][j], row_pointers[i][j + 1], - row_pointers[i][j + 2], row_pointers[i][j + 3] ); - } - } - - _preMulti = true; - } + + _preMulti = false; CC_SAFE_FREE(row_pointers); @@ -611,15 +850,15 @@ static void _tiffUnmapProc(thandle_t fd, void* base, toff_t size) CC_UNUSED_PARAM(size); } -bool Image::initWithTiffData(void* pData, int nDataLen) +bool Image::initWithTiffData(void* data, int dataLen) { bool bRet = false; do { // set the read call back function tImageSource imageSource; - imageSource.data = (unsigned char*)pData; - imageSource.size = nDataLen; + imageSource.data = (unsigned char*)data; + imageSource.size = dataLen; imageSource.offset = 0; TIFF* tif = TIFFClientOpen("file.tif", "r", (thandle_t)&imageSource, @@ -642,12 +881,12 @@ bool Image::initWithTiffData(void* pData, int nDataLen) npixels = w * h; - _hasAlpha = true; + _renderFormat = Texture2D::PixelFormat::RGBA8888; _width = w; _height = h; - _bitsPerComponent = 8; - _data = new unsigned char[npixels * sizeof (uint32)]; + _dataLen = npixels * sizeof (uint32); + _data = new unsigned char[_dataLen]; uint32* raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); if (raster != NULL) @@ -655,16 +894,7 @@ bool Image::initWithTiffData(void* pData, int nDataLen) if (TIFFReadRGBAImageOriented(tif, w, h, raster, ORIENTATION_TOPLEFT, 0)) { /* the raster data is pre-multiplied by the alpha component - after invoking TIFFReadRGBAImageOriented - unsigned char* src = (unsigned char*)raster; - unsigned int* tmp = (unsigned int*)_data; - - for(int j = 0; j < _width * _height * 4; j += 4) - { - *tmp++ = CC_RGB_PREMULTIPLY_ALPHA( src[j], src[j + 1], - src[j + 2], src[j + 3] ); - } - */ + after invoking TIFFReadRGBAImageOriented*/ _preMulti = true; memcpy(_data, raster, npixels*sizeof (uint32)); @@ -681,25 +911,391 @@ bool Image::initWithTiffData(void* pData, int nDataLen) return bRet; } -bool Image::initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent, bool bPreMulti) +bool Image::testFormatForPvrTCSupport(uint64_t format) +{ +#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + if (!Configuration::getInstance()->supportsPVRTC()) + { + if (format == kPVR3TexturePixelFormat_PVRTC_2BPP_RGB || + format == kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA || + format == kPVR3TexturePixelFormat_PVRTC_4BPP_RGB || + format == kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA) + { + return false; + } + } + +#endif // GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + + return true; +} + +bool Image::initWithPVRv2Data(void *data, int dataLen) +{ + ccPVRv2TexHeader *header = NULL; + unsigned int flags, pvrTag; + int dataLength = 0, dataOffset = 0, dataSize = 0; + int blockSize = 0, widthBlocks = 0, heightBlocks = 0; + int width = 0, height = 0; + unsigned int formatFlags; + + //Cast first sizeof(PVRTexHeader) bytes of data stream as PVRTexHeader + header = (ccPVRv2TexHeader *)data; + + //Make sure that tag is in correct formatting + pvrTag = CC_SWAP_INT32_LITTLE_TO_HOST(header->pvrTag); + + if (gPVRTexIdentifier[0] != (char)(((pvrTag >> 0) & 0xff)) || + gPVRTexIdentifier[1] != (char)(((pvrTag >> 8) & 0xff)) || + gPVRTexIdentifier[2] != (char)(((pvrTag >> 16) & 0xff)) || + gPVRTexIdentifier[3] != (char)(((pvrTag >> 24) & 0xff))) + { + return false; + } + + Configuration *configuration = Configuration::getInstance(); + + _hasPremultipliedAlpha = false; + flags = CC_SWAP_INT32_LITTLE_TO_HOST(header->flags); + formatFlags = flags & PVR_TEXTURE_FLAG_TYPE_MASK; + bool flipped = (flags & kPVR2TextureFlagVerticalFlip) ? true : false; + if (flipped) + { + CCLOG("cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool"); + } + + if (! configuration->supportsNPOT() && + (header->width != ccNextPOT(header->width) || header->height != ccNextPOT(header->height))) + { + CCLOG("cocos2d: ERROR: Loading an NPOT texture (%dx%d) but is not supported on this device", header->width, header->height); + return false; + } + + if (!testFormatForPvrTCSupport(formatFlags)) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", formatFlags); + return false; + } + + if (v2_pixel_formathash.find(formatFlags) == v2_pixel_formathash.end()) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", formatFlags); + return false; + } + + const ConstTexturePixelFormatInfoMap::const_iterator it = g_texturePixelFormatInfoTables.find(v2_pixel_formathash.at(formatFlags)); + + if (it == g_texturePixelFormatInfoTables.end()) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%02X. Re-encode it with a OpenGL pixel format variant", formatFlags); + return false; + } + + _renderFormat = it->first; + + //Reset num of mipmaps + _numberOfMipmaps = 0; + + //Get size of mipmap + _width = width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width); + _height = height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height); + + //Get ptr to where data starts.. + dataLength = CC_SWAP_INT32_LITTLE_TO_HOST(header->dataLength); + + //Move by size of header + _dataLen = dataLen - sizeof(ccPVRv2TexHeader); + _data = new unsigned char[_dataLen]; + memcpy(_data, (unsigned char*)data + sizeof(ccPVRv2TexHeader), _dataLen); + + // Calculate the data size for each texture level and respect the minimum number of blocks + while (dataOffset < dataLength) + { + switch (formatFlags) { + case kPVR2TexturePixelFormat_PVRTC_2BPP_RGBA: + blockSize = 8 * 4; // Pixel by pixel block size for 2bpp + widthBlocks = width / 8; + heightBlocks = height / 4; + break; + case kPVR2TexturePixelFormat_PVRTC_4BPP_RGBA: + blockSize = 4 * 4; // Pixel by pixel block size for 4bpp + widthBlocks = width / 4; + heightBlocks = height / 4; + break; + case kPVR2TexturePixelFormat_BGRA_8888: + if (Configuration::getInstance()->supportsBGRA8888() == false) + { + CCLOG("cocos2d: Image. BGRA8888 not supported on this device"); + return false; + } + default: + blockSize = 1; + widthBlocks = width; + heightBlocks = height; + break; + } + + // Clamp to minimum number of blocks + if (widthBlocks < 2) + { + widthBlocks = 2; + } + if (heightBlocks < 2) + { + heightBlocks = 2; + } + + dataSize = widthBlocks * heightBlocks * ((blockSize * it->second.bpp) / 8); + int packetLength = (dataLength - dataOffset); + packetLength = packetLength > dataSize ? dataSize : packetLength; + + //Make record to the mipmaps array and increment counter + _mipmaps[_numberOfMipmaps].address = _data + dataOffset; + _mipmaps[_numberOfMipmaps].len = packetLength; + _numberOfMipmaps++; + + dataOffset += packetLength; + + //Update width and height to the next lower power of two + width = MAX(width >> 1, 1); + height = MAX(height >> 1, 1); + } + + return true; +} + +bool Image::initWithPVRv3Data(void *data, int dataLen) +{ + if (dataLen < sizeof(ccPVRv3TexHeader)) + { + return false; + } + + ccPVRv3TexHeader *header = (ccPVRv3TexHeader *)data; + + // validate version + if (CC_SWAP_INT32_BIG_TO_HOST(header->version) != 0x50565203) + { + CCLOG("cocos2d: WARNING: pvr file version mismatch"); + return false; + } + + // parse pixel format + uint64_t pixelFormat = header->pixelFormat; + + if (!testFormatForPvrTCSupport(pixelFormat)) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant", (unsigned long long)pixelFormat); + return false; + } + + + if (v3_pixel_formathash.find(pixelFormat) == v3_pixel_formathash.end()) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant", (unsigned long long)pixelFormat); + return false; + } + + const ConstTexturePixelFormatInfoMap::const_iterator it = g_texturePixelFormatInfoTables.find(v3_pixel_formathash.at(pixelFormat)); + + if (it == g_texturePixelFormatInfoTables.end()) + { + CCLOG("cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%016llX. Re-encode it with a OpenGL pixel format variant", (unsigned long long)pixelFormat); + return false; + } + + _renderFormat = it->first; + + // flags + int flags = CC_SWAP_INT32_LITTLE_TO_HOST(header->flags); + + // PVRv3 specifies premultiply alpha in a flag -- should always respect this in PVRv3 files + if (flags & kPVR3TextureFlagPremultipliedAlpha) + { + _preMulti = true; + } + + // sizing + int width = CC_SWAP_INT32_LITTLE_TO_HOST(header->width); + int height = CC_SWAP_INT32_LITTLE_TO_HOST(header->height); + _width = width; + _height = height; + int dataOffset = 0, dataSize = 0; + int blockSize = 0, widthBlocks = 0, heightBlocks = 0; + + _dataLen = dataLen - (sizeof(ccPVRv3TexHeader) + header->metadataLength); + _data = new unsigned char[_dataLen]; + memcpy(_data, (unsigned char*)data + sizeof(ccPVRv3TexHeader) + header->metadataLength, _dataLen); + + _numberOfMipmaps = header->numberOfMipmaps; + CCAssert(_numberOfMipmaps < CC_MIPMAP_MAX, "Image: Maximum number of mimpaps reached. Increate the CC_MIPMAP_MAX value"); + + for (int i = 0; i < _numberOfMipmaps; i++) + { + switch (pixelFormat) + { + case kPVR3TexturePixelFormat_PVRTC_2BPP_RGB : + case kPVR3TexturePixelFormat_PVRTC_2BPP_RGBA : + blockSize = 8 * 4; // Pixel by pixel block size for 2bpp + widthBlocks = width / 8; + heightBlocks = height / 4; + break; + case kPVR3TexturePixelFormat_PVRTC_4BPP_RGB : + case kPVR3TexturePixelFormat_PVRTC_4BPP_RGBA : + blockSize = 4 * 4; // Pixel by pixel block size for 4bpp + widthBlocks = width / 4; + heightBlocks = height / 4; + break; + case kPVR3TexturePixelFormat_BGRA_8888: + if( ! Configuration::getInstance()->supportsBGRA8888()) + { + CCLOG("cocos2d: Image. BGRA8888 not supported on this device"); + return false; + } + default: + blockSize = 1; + widthBlocks = width; + heightBlocks = height; + break; + } + + // Clamp to minimum number of blocks + if (widthBlocks < 2) + { + widthBlocks = 2; + } + if (heightBlocks < 2) + { + heightBlocks = 2; + } + + dataSize = widthBlocks * heightBlocks * ((blockSize * it->second.bpp) / 8); + int packetLength = _dataLen - dataOffset; + packetLength = packetLength > dataSize ? dataSize : packetLength; + + _mipmaps[i].address = _data + dataOffset; + _mipmaps[i].len = packetLength; + + dataOffset += packetLength; + CCAssert(dataOffset <= _dataLen, "CCTexurePVR: Invalid lenght"); + + + width = MAX(width >> 1, 1); + height = MAX(height >> 1, 1); + } + + return true; +} + +bool Image::initWithETCData(void *data, int dataLen) +{ + etc1_byte* header = (etc1_byte*)data; + + //check the data + if(!etc1_pkm_is_valid(header)) + { + return false; + } + + _width = etc1_pkm_get_width(header); + _height = etc1_pkm_get_height(header); + + if( 0 == _width || 0 == _height ) + { + return false; + } + + if(Configuration::getInstance()->supportsETC()) + { + //old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy. +#ifdef GL_ETC1_RGB8_OES + _renderFormat = Texture2D::PixelFormat::ETC; + _dataLen = dataLen - ETC_PKM_HEADER_SIZE; + _data = new unsigned char[_dataLen]; + memcpy(_data, (unsigned char*)data + ETC_PKM_HEADER_SIZE, _dataLen); + return true; +#endif + } + else + { + //if it is not gles or device do not support ETC, decode texture by software + int bytePerPixel = 3; + unsigned int stride = _width * bytePerPixel; + _renderFormat = Texture2D::PixelFormat::RGB888; + + _dataLen = _width * _height * bytePerPixel; + _data = new unsigned char[_dataLen]; + + if (etc1_decode_image((unsigned char*)data + ETC_PKM_HEADER_SIZE, (etc1_byte*)_data, _width, _height, bytePerPixel, stride) != 0) + { + _dataLen = 0; + CC_SAFE_DELETE_ARRAY(_data); + return false; + } + + return true; + } + return false; +} + +bool Image::initWithPVRData(void *data, int dataLen) +{ + return initWithPVRv2Data(data, dataLen) || initWithPVRv3Data(data, dataLen); +} + +bool Image::initWithWebpData(void *data, int dataLen) +{ + bool bRet = false; + do + { + WebPDecoderConfig config; + if (WebPInitDecoderConfig(&config) == 0) break; + if (WebPGetFeatures((uint8_t*)data, dataLen, &config.input) != VP8_STATUS_OK) break; + if (config.input.width == 0 || config.input.height == 0) break; + + config.output.colorspace = MODE_RGBA; + _renderFormat = Texture2D::PixelFormat::RGBA8888; + _width = config.input.width; + _height = config.input.height; + + int bufferSize = _width * _height * 4; + _data = new unsigned char[bufferSize]; + + config.output.u.RGBA.rgba = (uint8_t*)_data; + config.output.u.RGBA.stride = _width * 4; + config.output.u.RGBA.size = bufferSize; + config.output.is_external_memory = 1; + + if (WebPDecode((uint8_t*)data, dataLen, &config) != VP8_STATUS_OK) + { + delete []_data; + _data = NULL; + break; + } + + bRet = true; + } while (0); + return bRet; +} + +bool Image::initWithRawData(void * data, int dataLen, int nWidth, int nHeight, int nBitsPerComponent, bool bPreMulti) { bool bRet = false; do { CC_BREAK_IF(0 == nWidth || 0 == nHeight); - _bitsPerComponent = nBitsPerComponent; _height = (short)nHeight; _width = (short)nWidth; - _hasAlpha = true; _preMulti = bPreMulti; + _renderFormat = Texture2D::PixelFormat::RGBA8888; // only RGBA8888 supported int nBytesPerComponent = 4; - int nSize = nHeight * nWidth * nBytesPerComponent; - _data = new unsigned char[nSize]; + _dataLen = nHeight * nWidth * nBytesPerComponent; + _data = new unsigned char[_dataLen]; CC_BREAK_IF(! _data); - memcpy(_data, pData, nSize); + memcpy(_data, data, _dataLen); bRet = true; } while (0); @@ -709,6 +1305,19 @@ bool Image::initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) { + //only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data + if (isCompressed() || (_renderFormat != Texture2D::PixelFormat::RGB888 && _renderFormat != Texture2D::PixelFormat::RGBA8888)) + { + CCLOG("cocos2d: Image: saveToFile is only support for Texture2D::PixelFormat::RGB888 or Texture2D::PixelFormat::RGBA8888 uncompressed data for now"); + return false; + } + +#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) + assert(false); + return false; +#elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + return iosSaveToFile(pszFilePath, bIsToRGB); +#else bool bRet = false; do @@ -741,6 +1350,7 @@ bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) } while (0); return bRet; +#endif } bool Image::saveImageToPNG(const char * pszFilePath, bool bIsToRGB) @@ -784,7 +1394,7 @@ bool Image::saveImageToPNG(const char * pszFilePath, bool bIsToRGB) #endif png_init_io(png_ptr, fp); - if (!bIsToRGB && _hasAlpha) + if (!bIsToRGB && hasAlpha()) { png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); @@ -810,7 +1420,7 @@ bool Image::saveImageToPNG(const char * pszFilePath, bool bIsToRGB) break; } - if (!_hasAlpha) + if (hasAlpha()) { for (int i = 0; i < (int)_height; i++) { @@ -915,7 +1525,7 @@ bool Image::saveImageToJPG(const char * pszFilePath) row_stride = _width * 3; /* JSAMPLEs per row in image_buffer */ - if (_hasAlpha) + if (hasAlpha()) { unsigned char *pTempData = new unsigned char[_width * _height * 3]; if (NULL == pTempData) diff --git a/cocos2dx/platform/CCPlatformConfig.h b/cocos2dx/platform/CCPlatformConfig.h index 68d86a764e..5ba0757dac 100644 --- a/cocos2dx/platform/CCPlatformConfig.h +++ b/cocos2dx/platform/CCPlatformConfig.h @@ -46,6 +46,7 @@ Config of cocos2d-x project, per target platform. #define CC_PLATFORM_NACL 9 #define CC_PLATFORM_EMSCRIPTEN 10 #define CC_PLATFORM_TIZEN 11 +#define CC_PLATFORM_QT5 12 // Determine target platform by compile environment macro. #define CC_TARGET_PLATFORM CC_PLATFORM_UNKNOWN @@ -116,6 +117,12 @@ Config of cocos2d-x project, per target platform. #define CC_TARGET_PLATFORM CC_PLATFORM_TIZEN #endif +// qt5 +#if defined(CC_TARGET_QT5) + #undef CC_TARGET_PLATFORM + #define CC_TARGET_PLATFORM CC_PLATFORM_QT5 +#endif + ////////////////////////////////////////////////////////////////////////// // post configure ////////////////////////////////////////////////////////////////////////// diff --git a/cocos2dx/platform/CCPlatformMacros.h b/cocos2dx/platform/CCPlatformMacros.h index 814ba46940..c62816227e 100644 --- a/cocos2dx/platform/CCPlatformMacros.h +++ b/cocos2dx/platform/CCPlatformMacros.h @@ -33,7 +33,7 @@ /** * define a create function for a specific type, such as Layer - * @__TYPE__ class type to add create(), such as Layer + * @param \__TYPE__ class type to add create(), such as Layer */ #define CREATE_FUNC(__TYPE__) \ static __TYPE__* create() \ @@ -54,8 +54,8 @@ static __TYPE__* create() \ /** * define a node function for a specific type, such as Layer - * @__TYPE__ class type to add node(), such as Layer - * @deprecated: This interface will be deprecated sooner or later. + * @param \__TYPE__ class type to add node(), such as Layer + * @deprecated This interface will be deprecated sooner or later. */ #define NODE_FUNC(__TYPE__) \ CC_DEPRECATED_ATTRIBUTE static __TYPE__* node() \ @@ -111,12 +111,12 @@ It's new in cocos2d-x since v0.99.5 /** CC_PROPERTY_READONLY is used to declare a protected variable. We can use getter to read the variable. - @param varType : the type of variable. - @param varName : variable name. - @param funName : "get + funName" is the name of the getter. - @warning : The getter is a public virtual function, you should rewrite it first. - The variables and methods declared after CC_PROPERTY_READONLY are all public. - If you need protected or private, please declare. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + @warning The getter is a public virtual function, you should rewrite it first. + The variables and methods declared after CC_PROPERTY_READONLY are all public. + If you need protected or private, please declare. */ #define CC_PROPERTY_READONLY(varType, varName, funName)\ protected: varType varName;\ @@ -128,13 +128,13 @@ public: virtual const varType& get##funName(void) const; /** CC_PROPERTY is used to declare a protected variable. We can use getter to read the variable, and use the setter to change the variable. - @param varType : the type of variable. - @param varName : variable name. - @param funName : "get + funName" is the name of the getter. - "set + funName" is the name of the setter. - @warning : The getter and setter are public virtual functions, you should rewrite them first. - The variables and methods declared after CC_PROPERTY are all public. - If you need protected or private, please declare. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + "set + funName" will be the name of the setter. + @warning The getter and setter are public virtual functions, you should rewrite them first. + The variables and methods declared after CC_PROPERTY are all public. + If you need protected or private, please declare. */ #define CC_PROPERTY(varType, varName, funName)\ protected: varType varName;\ @@ -148,12 +148,12 @@ public: virtual void set##funName(const varType& var); /** CC_SYNTHESIZE_READONLY is used to declare a protected variable. We can use getter to read the variable. - @param varType : the type of variable. - @param varName : variable name. - @param funName : "get + funName" is the name of the getter. - @warning : The getter is a public inline function. - The variables and methods declared after CC_SYNTHESIZE_READONLY are all public. - If you need protected or private, please declare. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + @warning The getter is a public inline function. + The variables and methods declared after CC_SYNTHESIZE_READONLY are all public. + If you need protected or private, please declare. */ #define CC_SYNTHESIZE_READONLY(varType, varName, funName)\ protected: varType varName;\ @@ -165,13 +165,13 @@ public: virtual const varType& get##funName(void) const { return varName; } /** CC_SYNTHESIZE is used to declare a protected variable. We can use getter to read the variable, and use the setter to change the variable. - @param varType : the type of variable. - @param varName : variable name. - @param funName : "get + funName" is the name of the getter. - "set + funName" is the name of the setter. - @warning : The getter and setter are public inline functions. - The variables and methods declared after CC_SYNTHESIZE are all public. - If you need protected or private, please declare. + @param varType the type of variable. + @param varName variable name. + @param funName "get + funName" will be the name of the getter. + "set + funName" will be the name of the setter. + @warning The getter and setter are public inline functions. + The variables and methods declared after CC_SYNTHESIZE are all public. + If you need protected or private, please declare. */ #define CC_SYNTHESIZE(varType, varName, funName)\ protected: varType varName;\ diff --git a/cocos2dx/platform/android/CCCommon.cpp b/cocos2dx/platform/android/CCCommon.cpp index e00c05dbec..277db4b14d 100644 --- a/cocos2dx/platform/android/CCCommon.cpp +++ b/cocos2dx/platform/android/CCCommon.cpp @@ -35,14 +35,11 @@ NS_CC_BEGIN // XXX deprecated void CCLog(const char * pszFormat, ...) { - char buf[MAX_LEN]; - va_list args; va_start(args, pszFormat); - vsnprintf(buf, MAX_LEN, pszFormat, args); + __android_log_vprint(ANDROID_LOG_DEBUG, "cocos2d-x debug info", pszFormat, args); va_end(args); - __android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", buf); } void log(const char * pszFormat, ...) @@ -54,7 +51,7 @@ void log(const char * pszFormat, ...) vsnprintf(buf, MAX_LEN, pszFormat, args); va_end(args); - __android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", buf); + __android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", "%s", buf); } void MessageBox(const char * pszMsg, const char * pszTitle) @@ -64,7 +61,7 @@ void MessageBox(const char * pszMsg, const char * pszTitle) void LuaLog(const char * pszFormat) { - __android_log_print(ANDROID_LOG_DEBUG, "cocos2d-x debug info", pszFormat); + __android_log_write(ANDROID_LOG_DEBUG, "cocos2d-x debug info", pszFormat); } NS_CC_END diff --git a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp index 56cda63c06..ce9e279a9e 100644 --- a/cocos2dx/platform/android/CCFileUtilsAndroid.cpp +++ b/cocos2dx/platform/android/CCFileUtilsAndroid.cpp @@ -228,7 +228,7 @@ unsigned char* FileUtilsAndroid::doGetFileData(const char* filename, const char* { std::string msg = "Get data from file("; msg.append(filename).append(") failed!"); - CCLOG(msg.c_str()); + CCLOG("%s", msg.c_str()); } return pData; diff --git a/cocos2dx/platform/android/CCImage.cpp b/cocos2dx/platform/android/CCImage.cpp index d0668b24c6..cd6f1deaf7 100644 --- a/cocos2dx/platform/android/CCImage.cpp +++ b/cocos2dx/platform/android/CCImage.cpp @@ -168,9 +168,8 @@ bool Image::initWithString( _width = (short)dc._width; _height = (short)dc._height; - _hasAlpha = true; _preMulti = true; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; bRet = true; } while (0); @@ -220,9 +219,8 @@ bool Image::initWithStringShadowStroke( _width = (short)dc._width; _height = (short)dc._height; - _hasAlpha = true; _preMulti = true; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; // swap the alpha channel (ARGB to RGBA) swapAlphaChannel((unsigned int *)_data, (_width * _height) ); diff --git a/cocos2dx/platform/android/java/.classpath b/cocos2dx/platform/android/java/.classpath index f7b8a1f99e..5cc5eb909c 100644 --- a/cocos2dx/platform/android/java/.classpath +++ b/cocos2dx/platform/android/java/.classpath @@ -2,8 +2,8 @@ + - diff --git a/cocos2dx/platform/blackberry/CCImage.cpp b/cocos2dx/platform/blackberry/CCImage.cpp new file mode 100644 index 0000000000..3c08d2e438 --- /dev/null +++ b/cocos2dx/platform/blackberry/CCImage.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** + Copyright (c) 2010 cocos2d-x.org + + 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 + 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. + ****************************************************************************/ +#define __CC_PLATFORM_IMAGE_CPP__ +#include "platform/CCImageCommon_cpp.h" + +#include +#include +#include +#include +#include +#include "platform/CCImage.h" +#include "platform/CCFileUtils.h" +#include "platform/CCCommon.h" +#include "CCStdC.h" +#include "ft2build.h" +#include FT_FREETYPE_H + +#define szFont_kenning 2 + +#define SHIFT6(num) (num>>6) + +using namespace std; + +struct TextLine { + int iLineWidth; + wchar_t* text; +}; + +NS_CC_BEGIN + +class BitmapDC +{ +public: + BitmapDC() + { + libError = FT_Init_FreeType( &library ); + iInterval = szFont_kenning; + _data = NULL; + reset(); + } + + ~BitmapDC(void) + { + FT_Done_FreeType(library); + } + + void reset() { + iMaxLineWidth = 0; + iMaxLineHeight = 0; + size_t size = vLines.size(); + for (int i=0; iglyph->metrics.horiAdvance - face->glyph->metrics.horiBearingX - face->glyph->metrics.width))/*-iInterval*/;//TODO interval + iMaxLineWidth = MAX(iMaxLineWidth, oTempLine.iLineWidth); + + vLines.push_back(oTempLine); + } + + bool divideString(FT_Face face, const char* sText, int iMaxWidth, int iMaxHeight) { + int iError = 0; + int iCurXCursor, iCurYCursor; + const char* pText = sText; + + FT_UInt unicode = utf8((char**)&pText); + iError = FT_Load_Char(face, unicode, FT_LOAD_DEFAULT); + if (iError) { + return false; + } + iCurXCursor = -SHIFT6(face->glyph->metrics.horiBearingX); + + FT_UInt cLastCh = 0; + + pText = sText; + size_t text_len = 0; + wchar_t* text_buf = (wchar_t*) malloc(sizeof(wchar_t) * strlen(sText)); + while (unicode=utf8((char**)&pText)) { + if (unicode == '\n') { + buildLine(text_buf, text_len, face, iCurXCursor, cLastCh); + text_len = 0; + + iError = FT_Load_Char(face, unicode, FT_LOAD_DEFAULT); + if (iError) { + free(text_buf); + return false; + } + iCurXCursor = -SHIFT6(face->glyph->metrics.horiBearingX); + continue; + } + + iError = FT_Load_Char(face, unicode, FT_LOAD_DEFAULT); + + if (iError) { + free(text_buf); + return false; + } + + //check its width + //divide it when exceeding + if ((iMaxWidth > 0 + && iCurXCursor + SHIFT6(face->glyph->metrics.width) + > iMaxWidth)) { + buildLine(text_buf, text_len, face , iCurXCursor, cLastCh); + text_len = 0; + + iCurXCursor = -SHIFT6(face->glyph->metrics.horiBearingX); + } + + cLastCh = unicode; + text_buf[text_len] = unicode; + ++text_len; + iCurXCursor += SHIFT6(face->glyph->metrics.horiAdvance) + iInterval; + } + + if (iError) { + free(text_buf); + return false; + } + + buildLine(text_buf, text_len, face, iCurXCursor, cLastCh); + free(text_buf); + + return true; + } + + /** + * compute the start pos of every line + * + * return >0 represent the start x pos of the line + * while -1 means fail + * + */ + int computeLineStart(FT_Face face, Image::TextAlign eAlignMask, char cText, + int iLineIndex) { + int iRet; + int iError = FT_Load_Glyph(face, FT_Get_Char_Index(face, cText), + FT_LOAD_DEFAULT); + if (iError) { + return -1; + } + + if (eAlignMask == Image::kAlignCenter) { + iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth) / 2 + - SHIFT6(face->glyph->metrics.horiBearingX ); + + } else if (eAlignMask == Image::kAlignRight) { + iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth) + - SHIFT6(face->glyph->metrics.horiBearingX ); + } else { + // left or other situation + iRet = -SHIFT6(face->glyph->metrics.horiBearingX ); + } + return iRet; + } + + int computeLineStartY( FT_Face face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){ + int iRet; + if (eAlignMask == Image::kAlignCenter || eAlignMask == Image::kAlignLeft || + eAlignMask == Image::kAlignRight ) { + //vertical center + iRet = (borderHeight - txtHeight)/2 + SHIFT6(face->size->metrics.ascender); + + } else if (eAlignMask == Image::kAlignBottomRight || + eAlignMask == Image::kAlignBottom || + eAlignMask == Image::kAlignBottomLeft ) { + //vertical bottom + iRet = borderHeight - txtHeight + SHIFT6(face->size->metrics.ascender); + } else { + // left or other situation + iRet = SHIFT6(face->size->metrics.ascender); + } + return iRet; + } + + bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) { + FT_Face face; + FT_Error iError; + + const char* pText = text; + //data will be deleted by Image + // if (_data) { + // delete _data; + // } + + int iCurXCursor, iCurYCursor; + bool bRet = false; + if (libError) { + return false; + } + do { + //CCLog(" ---- FT_New_Face with pFontName = %s", pFontName); + iError = FT_New_Face( library, pFontName, 0, &face ); + + if (iError) { + //no valid font found use default + //CCLog(" ---- no valid font, use default %s", pFontName); + iError = FT_New_Face( library, "/usr/fonts/font_repository/monotype/arial.ttf", 0, &face ); + } + CC_BREAK_IF(iError); + + //select utf8 charmap + iError = FT_Select_Charmap(face,FT_ENCODING_UNICODE); + CC_BREAK_IF(iError); + + iError = FT_Set_Pixel_Sizes(face, fontSize,fontSize); + CC_BREAK_IF(iError); + + iError = divideString(face, text, nWidth, nHeight)?0:1; + + //compute the final line width + iMaxLineWidth = MAX(iMaxLineWidth, nWidth); + + iMaxLineHeight = (face->size->metrics.ascender >> 6) + - (face->size->metrics.descender >> 6); + iMaxLineHeight *= vLines.size(); + + int txtHeight = iMaxLineHeight; + + //compute the final line height + iMaxLineHeight = MAX(iMaxLineHeight, nHeight); + _data = new unsigned char[iMaxLineWidth * iMaxLineHeight*4]; +// iCurYCursor = SHIFT6(face->size->metrics.ascender); + iCurYCursor = computeLineStartY( face, eAlignMask, txtHeight, iMaxLineHeight ); + + memset(_data,0, iMaxLineWidth * iMaxLineHeight*4); + + size_t lines = vLines.size(); + for (size_t i = 0; i < lines; i++) { + const wchar_t* text_ptr = vLines[i].text; + + //initialize the origin cursor + iCurXCursor = computeLineStart(face, eAlignMask, text_ptr[0], i); + + size_t text_len = wcslen(text_ptr); + for (size_t i=0; iglyph->bitmap; + + int yoffset = iCurYCursor - (face->glyph->metrics.horiBearingY >> 6); + int xoffset = iCurXCursor + (face->glyph->metrics.horiBearingX >> 6); + for (int i = 0; i < bitmap.rows; ++i) { + for (int j = 0; j < bitmap.width; ++j) { + unsigned char cTemp = bitmap.buffer[i * bitmap.width + j]; + if (cTemp == 0) continue; + + // if it has gray>0 we set show it as 1, o otherwise + int iY = yoffset + i; + int iX = xoffset + j; + + if (iY>=iMaxLineHeight) { + //exceed the height truncate + continue; + } + +// _data[(iY * iMaxLineWidth + iX) * 4 + 3] = +// bitmap.buffer[i * bitmap.width + j] ? +// 0xff : 0;//alpha +// _data[(iY * iMaxLineWidth + iX) * 4 + 1] = +// bitmap.buffer[i * bitmap.width + j];//R +// _data[(iY * iMaxLineWidth + iX) * 4 + 2] = +// bitmap.buffer[i * bitmap.width + j];//G +// _data[(iY * iMaxLineWidth + iX) * 4 + 0] = +// bitmap.buffer[i * bitmap.width + j];//B + + int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp; + *(int*) &_data[(iY * iMaxLineWidth + iX) * 4 + 0] = iTemp; + } + } + //step to next glyph + iCurXCursor += (face->glyph->metrics.horiAdvance >> 6) + + iInterval; + + pText++; + } + iCurYCursor += (face->size->metrics.ascender >> 6) + - (face->size->metrics.descender >> 6); + } + //print all image bitmap + // for (int i = 0; i < iMaxLineHeight; i++) { + // for (int j = 0; j < iMaxLineWidth; j++) { + // printf("%d", + // _data[(i * iMaxLineWidth + j) * 4] ? 1 : 0); + // } + // printf("\n"); + // } + + // free face + FT_Done_Face(face); + face = NULL; + + //clear all lines + vLines.clear(); + + //success; + if (iError) { + bRet = false; + } else + bRet = true; + }while(0); + + return bRet; + } + +public: + FT_Library library; + unsigned char *_data; + int libError; + vector vLines; + int iInterval; + int iMaxLineWidth; + int iMaxLineHeight; +}; + +static BitmapDC& sharedBitmapDC() +{ + static BitmapDC s_BmpDC; + return s_BmpDC; +} + +bool Image::initWithString( + const char * pText, + int nWidth/* = 0*/, + int nHeight/* = 0*/, + TextAlign eAlignMask/* = kAlignCenter*/, + const char * pFontName/* = nil*/, + int nSize/* = 0*/) +{ + bool bRet = false; + do + { + CC_BREAK_IF(! pText); + BitmapDC &dc = sharedBitmapDC(); + + std::string fullFontName = pFontName; + std::string lowerCasePath = fullFontName; + std::transform(lowerCasePath.begin(), lowerCasePath.end(), lowerCasePath.begin(), ::tolower); + + if ( lowerCasePath.find(".ttf") != std::string::npos ) { + fullFontName = FileUtils::getInstance()->fullPathForFilename(pFontName); + } + //CCLog("-----pText=%s and Font File is %s nWidth= %d,nHeight=%d",pText,fullFontName.c_str(),nWidth,nHeight); + + CC_BREAK_IF(! dc.getBitmap(pText, nWidth, nHeight, eAlignMask, fullFontName.c_str(), nSize)); + //CCLog("---- dc.getBitmap is Succesfull..."); + + // assign the dc._data to _data in order to save time + _data = dc._data; + CC_BREAK_IF(! _data); + + _width = (short)dc.iMaxLineWidth; + _height = (short)dc.iMaxLineHeight; + _preMulti = true; + _renderFormat = Texture2D::PixelFormat::RGBA8888; + + bRet = true; + + dc.reset(); + + } while (0); + + return bRet; +} + +NS_CC_END + diff --git a/cocos2dx/platform/emscripten/CCImage.cpp b/cocos2dx/platform/emscripten/CCImage.cpp index 69935f0c5f..4b22c2813a 100644 --- a/cocos2dx/platform/emscripten/CCImage.cpp +++ b/cocos2dx/platform/emscripten/CCImage.cpp @@ -130,7 +130,7 @@ public: * while -1 means fail * */ - int computeLineStart(TTF_Font *face, Image::ETextAlign eAlignMask, char cText, + int computeLineStart(TTF_Font *face, Image::TextAlign eAlignMask, char cText, int iLineIndex) { return 0; /* @@ -156,7 +156,7 @@ public: */ } - int computeLineStartY( TTF_Font *face, Image::ETextAlign eAlignMask, int txtHeight, int borderHeight ){ + int computeLineStartY( TTF_Font *face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){ return 0; /* int iRet; @@ -178,7 +178,7 @@ public: */ } - bool getBitmap(const char *text, int nWidth, int nHeight, Image::ETextAlign eAlignMask, const char * pFontName, float fontSize) { + bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) { const char* pText = text; int pxSize = (int)fontSize; @@ -284,7 +284,7 @@ bool Image::initWithString( const char * pText, int nWidth/* = 0*/, int nHeight/* = 0*/, - ETextAlign eAlignMask/* = kAlignCenter*/, + TextAlign eAlignMask/* = kAlignCenter*/, const char * pFontName/* = nil*/, int nSize/* = 0*/) { @@ -306,9 +306,8 @@ bool Image::initWithString( _width = (short)dc.iMaxLineWidth; _height = (short)dc.iMaxLineHeight; - _hasAlpha = true; _preMulti = true; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; bRet = true; diff --git a/cocos2dx/platform/ios/CCImage.mm b/cocos2dx/platform/ios/CCImage.mm index 3704650f8b..46e5ac1738 100644 --- a/cocos2dx/platform/ios/CCImage.mm +++ b/cocos2dx/platform/ios/CCImage.mm @@ -21,6 +21,8 @@ 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 "CCImageCommon_cpp.h" + #import "CCImage.h" #import "CCFileUtils.h" #import "CCCommon.h" @@ -36,8 +38,6 @@ typedef struct { unsigned int height; unsigned int width; - int bitsPerComponent; - bool hasAlpha; bool isPremultipliedAlpha; bool hasShadow; CGSize shadowOffset; @@ -56,91 +56,6 @@ typedef struct } tImageInfo; -static bool _initWithImage(CGImageRef cgImage, tImageInfo *pImageinfo) -{ - if(cgImage == NULL) - { - return false; - } - - // get image info - - pImageinfo->width = CGImageGetWidth(cgImage); - pImageinfo->height = CGImageGetHeight(cgImage); - - CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage); - pImageinfo->hasAlpha = (info == kCGImageAlphaPremultipliedLast) - || (info == kCGImageAlphaPremultipliedFirst) - || (info == kCGImageAlphaLast) - || (info == kCGImageAlphaFirst); - - // If OS version < 5.x, add condition to support jpg - float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; - if(systemVersion < 5.0f) - { - pImageinfo->hasAlpha = (pImageinfo->hasAlpha || (info == kCGImageAlphaNoneSkipLast)); - } - - CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); - if (colorSpace) - { - if (pImageinfo->hasAlpha) - { - info = kCGImageAlphaPremultipliedLast; - pImageinfo->isPremultipliedAlpha = true; - } - else - { - info = kCGImageAlphaNoneSkipLast; - pImageinfo->isPremultipliedAlpha = false; - } - } - else - { - return false; - } - - // change to RGBA8888 - pImageinfo->hasAlpha = true; - pImageinfo->bitsPerComponent = 8; - pImageinfo->data = new unsigned char[pImageinfo->width * pImageinfo->height * 4]; - colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate(pImageinfo->data, - pImageinfo->width, - pImageinfo->height, - 8, - 4 * pImageinfo->width, - colorSpace, - info | kCGBitmapByteOrder32Big); - - CGContextClearRect(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height)); - //CGContextTranslateCTM(context, 0, 0); - CGContextDrawImage(context, CGRectMake(0, 0, pImageinfo->width, pImageinfo->height), cgImage); - - CGContextRelease(context); - CFRelease(colorSpace); - - return true; -} - -static bool _initWithData(void * pBuffer, int length, tImageInfo *pImageinfo) -{ - bool ret = false; - - if (pBuffer) - { - CGImageRef CGImage; - NSData *data; - - data = [NSData dataWithBytes:pBuffer length:length]; - CGImage = [[UIImage imageWithData:data] CGImage]; - - ret = _initWithImage(CGImage, pImageinfo); - } - - return ret; -} - static CGSize _calculateStringSize(NSString *str, id font, CGSize *constrainSize) { NSArray *listItems = [str componentsSeparatedByString: @"\n"]; @@ -386,9 +301,7 @@ static bool _initWithString(const char * pText, cocos2d::Image::TextAlign eAlign // output params pInfo->data = data; - pInfo->hasAlpha = true; pInfo->isPremultipliedAlpha = true; - pInfo->bitsPerComponent = 8; pInfo->width = dim.width; pInfo->height = dim.height; bRet = true; @@ -400,145 +313,6 @@ static bool _initWithString(const char * pText, cocos2d::Image::TextAlign eAlign NS_CC_BEGIN -Image::Image() -: _width(0) -, _height(0) -, _bitsPerComponent(0) -, _data(0) -, _hasAlpha(false) -, _preMulti(false) -{ - -} - -Image::~Image() -{ - CC_SAFE_DELETE_ARRAY(_data); -} - -bool Image::initWithImageFile(const char * strPath, Format eImgFmt/* = eFmtPng*/) -{ - bool bRet = false; - unsigned long nSize = 0; - unsigned char* pBuffer = FileUtils::getInstance()->getFileData( - FileUtils::getInstance()->fullPathForFilename(strPath).c_str(), - "rb", - &nSize); - - if (pBuffer != NULL && nSize > 0) - { - bRet = initWithImageData(pBuffer, nSize, eImgFmt); - } - CC_SAFE_DELETE_ARRAY(pBuffer); - return bRet; -} - -bool Image::initWithImageFileThreadSafe(const char *fullpath, Format imageType) -{ - /* - * FileUtils::fullPathFromRelativePath() is not thread-safe. - */ - bool bRet = false; - unsigned long nSize = 0; - unsigned char* pBuffer = FileUtils::getInstance()->getFileData(fullpath, "rb", &nSize); - if (pBuffer != NULL && nSize > 0) - { - bRet = initWithImageData(pBuffer, nSize, imageType); - } - CC_SAFE_DELETE_ARRAY(pBuffer); - return bRet; -} - -bool Image::initWithImageData(void * pData, - int nDataLen, - Format eFmt, - int nWidth, - int nHeight, - int nBitsPerComponent) -{ - bool bRet = false; - tImageInfo info = {0}; - - info.hasShadow = false; - info.hasStroke = false; - - do - { - CC_BREAK_IF(! pData || nDataLen <= 0); - if (eFmt == Format::RAW_DATA) - { - bRet = initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent, false); - } - else if (eFmt == Format::WEBP) - { - bRet = initWithWebpData(pData, nDataLen); - } - else // init with png or jpg file data - { - bRet = _initWithData(pData, nDataLen, &info); - if (bRet) - { - _height = (short)info.height; - _width = (short)info.width; - _bitsPerComponent = info.bitsPerComponent; - _hasAlpha = info.hasAlpha; - _preMulti = info.isPremultipliedAlpha; - _data = info.data; - } - } - } while (0); - - return bRet; -} - -bool Image::initWithRawData(void *pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent, bool bPreMulti) -{ - bool bRet = false; - do - { - CC_BREAK_IF(0 == nWidth || 0 == nHeight); - - _bitsPerComponent = nBitsPerComponent; - _height = (short)nHeight; - _width = (short)nWidth; - _hasAlpha = true; - - // only RGBA8888 supported - int nBytesPerComponent = 4; - int nSize = nHeight * nWidth * nBytesPerComponent; - _data = new unsigned char[nSize]; - CC_BREAK_IF(! _data); - memcpy(_data, pData, nSize); - - bRet = true; - } while (0); - return bRet; -} - -bool Image::initWithJpgData(void *pData, int nDatalen) -{ - assert(0); - return false; -} - -bool Image::initWithPngData(void *pData, int nDatalen) -{ - assert(0); - return false; -} - -bool Image::saveImageToPNG(const char *pszFilePath, bool bIsToRGB) -{ - assert(0); - return false; -} - -bool Image::saveImageToJPG(const char *pszFilePath) -{ - assert(0); - return false; -} - bool Image::initWithString( const char * pText, int nWidth /* = 0 */, @@ -572,7 +346,7 @@ bool Image::initWithStringShadowStroke( float strokeSize) { - + tImageInfo info = {0}; info.width = nWidth; @@ -598,16 +372,14 @@ bool Image::initWithStringShadowStroke( } _height = (short)info.height; _width = (short)info.width; - _bitsPerComponent = info.bitsPerComponent; - _hasAlpha = info.hasAlpha; + _renderFormat = Texture2D::PixelFormat::RGBA8888; _preMulti = info.isPremultipliedAlpha; _data = info.data; return true; } - -bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) +bool Image::iosSaveToFile(const char *pszFilePath, bool bIsToRGB) { bool saveToPNG = false; bool needToCopyPixels = false; @@ -618,7 +390,7 @@ bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) } int bitsPerComponent = 8; - int bitsPerPixel = _hasAlpha ? 32 : 24; + int bitsPerPixel = hasAlpha() ? 32 : 24; if ((! saveToPNG) || bIsToRGB) { bitsPerPixel = 24; @@ -631,7 +403,7 @@ bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) // The data has alpha channel, and want to save it with an RGB png file, // or want to save as jpg, remove the alpha channel. - if ((saveToPNG && _hasAlpha && bIsToRGB) + if ((saveToPNG && hasAlpha() && bIsToRGB) || (! saveToPNG)) { pixels = new unsigned char[myDataLength]; @@ -651,7 +423,7 @@ bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) // make data provider with data. CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; - if (saveToPNG && _hasAlpha && (! bIsToRGB)) + if (saveToPNG && hasAlpha() && (! bIsToRGB)) { bitmapInfo |= kCGImageAlphaPremultipliedLast; } diff --git a/cocos2dx/platform/linux/CCEGLView.cpp b/cocos2dx/platform/linux/CCEGLView.cpp index 247af6e62c..44234a8c1b 100644 --- a/cocos2dx/platform/linux/CCEGLView.cpp +++ b/cocos2dx/platform/linux/CCEGLView.cpp @@ -7,78 +7,26 @@ #include "CCEGLView.h" #include "CCGL.h" -#include "GL/glfw.h" #include "ccMacros.h" #include "CCDirector.h" #include "touch_dispatcher/CCTouch.h" #include "touch_dispatcher/CCTouchDispatcher.h" #include "text_input_node/CCIMEDispatcher.h" #include "keyboard_dispatcher/CCKeyboardDispatcher.h" +#include -PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; -PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; -PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; -PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; - -PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; -PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; -PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; -PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL; -PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; - -bool initExtensions() { -#define LOAD_EXTENSION_FUNCTION(TYPE, FN) FN = (TYPE)glfwGetProcAddress(#FN); - bool bRet = false; - do { - -// char* p = (char*) glGetString(GL_EXTENSIONS); -// printf(p); - - /* Supports frame buffer? */ - if (glfwExtensionSupported("GL_EXT_framebuffer_object") != GL_FALSE) - { - - /* Loads frame buffer extension functions */ - LOAD_EXTENSION_FUNCTION(PFNGLGENERATEMIPMAPEXTPROC, - glGenerateMipmapEXT); - LOAD_EXTENSION_FUNCTION(PFNGLGENFRAMEBUFFERSEXTPROC, - glGenFramebuffersEXT); - LOAD_EXTENSION_FUNCTION(PFNGLDELETEFRAMEBUFFERSEXTPROC, - glDeleteFramebuffersEXT); - LOAD_EXTENSION_FUNCTION(PFNGLBINDFRAMEBUFFEREXTPROC, - glBindFramebufferEXT); - LOAD_EXTENSION_FUNCTION(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, - glCheckFramebufferStatusEXT); - LOAD_EXTENSION_FUNCTION(PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, - glFramebufferTexture2DEXT); - - } else { - break; - } - - if (glfwExtensionSupported("GL_ARB_vertex_buffer_object") != GL_FALSE) { - LOAD_EXTENSION_FUNCTION(PFNGLGENBUFFERSARBPROC, glGenBuffersARB); - LOAD_EXTENSION_FUNCTION(PFNGLBINDBUFFERARBPROC, glBindBufferARB); - LOAD_EXTENSION_FUNCTION(PFNGLBUFFERDATAARBPROC, glBufferDataARB); - LOAD_EXTENSION_FUNCTION(PFNGLBUFFERSUBDATAARBPROC, - glBufferSubDataARB); - LOAD_EXTENSION_FUNCTION(PFNGLDELETEBUFFERSARBPROC, - glDeleteBuffersARB); - } else { - break; - } - bRet = true; - } while (0); - return bRet; +bool initExtensions() +{ + // Do nothing, on Linux we use GLEW. } NS_CC_BEGIN EGLView::EGLView() -: bIsInit(false) +: _wasInit(false) , _frameZoomFactor(1.0f) +,_window(nullptr) +,_context(nullptr) { } @@ -86,185 +34,83 @@ EGLView::~EGLView() { } -void keyEventHandle(int iKeyID,int iKeyState) { - if (iKeyState ==GLFW_RELEASE) { - return; - } - - if (iKeyID == GLFW_KEY_DEL) { - IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(); - } else if (iKeyID == GLFW_KEY_ENTER) { - IMEDispatcher::sharedDispatcher()->dispatchInsertText("\n", 1); - } else if (iKeyID == GLFW_KEY_TAB) { - - } -} - -void charEventHandle(int iCharID,int iCharState) { - if (iCharState ==GLFW_RELEASE) { - return; - } - - // ascii char - IMEDispatcher::sharedDispatcher()->dispatchInsertText((const char *)&iCharID, 1); -} - -void mouseButtonEventHandle(int iMouseID,int iMouseState) { - if (iMouseID == GLFW_MOUSE_BUTTON_LEFT) { - EGLView* pEGLView = EGLView::getInstance(); - //get current mouse pos - int x,y; - glfwGetMousePos(&x, &y); - Point oPoint((float)x,(float)y); - /* - if (!Rect::RectContainsPoint(s_pMainWindow->_rcViewPort,oPoint)) - { - CCLOG("not in the viewport"); - return; - } - */ - oPoint.x /= pEGLView->_frameZoomFactor; - oPoint.y /= pEGLView->_frameZoomFactor; - int id = 0; - if (iMouseState == GLFW_PRESS) { - pEGLView->handleTouchesBegin(1, &id, &oPoint.x, &oPoint.y); - - } else if (iMouseState == GLFW_RELEASE) { - pEGLView->handleTouchesEnd(1, &id, &oPoint.x, &oPoint.y); - } - } -} - -void mousePosEventHandle(int iPosX,int iPosY) { - int iButtonState = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT); - - //to test move - if (iButtonState == GLFW_PRESS) { - EGLView* pEGLView = EGLView::getInstance(); - int id = 0; - float x = (float)iPosX; - float y = (float)iPosY; - x /= pEGLView->_frameZoomFactor; - y /= pEGLView->_frameZoomFactor; - pEGLView->handleTouchesMove(1, &id, &x, &y); - } -} - -int closeEventHandle() { - Director::getInstance()->end(); - return GL_TRUE; -} - -void GLFWCALL keyboardEventHandle(int keyCode, int action) +static std::string getApplicationName() { - KeyboardDispatcher *kbDisp = Director::getInstance()->getKeyboardDispatcher(); + char fullpath[256] = {0}; + ssize_t length = readlink("/proc/self/exe", fullpath, sizeof(fullpath)-1); - switch (action) - { - case GLFW_PRESS: - kbDisp->dispatchKeyboardEvent(keyCode, true); - break; - case GLFW_RELEASE: - kbDisp->dispatchKeyboardEvent(keyCode, false); - break; - } + if (length <= 0) { + return "Cocos2dx-Linux"; + } + + fullpath[length] = '\0'; + const std::string appPath = fullpath; + return appPath.substr(appPath.find_last_of('/') + 1); +} + +void checkSDLError(int line) +{ +#if COCOS2D_DEBUG > 0 + const char *error = SDL_GetError(); + if (*error != '\0') + { + if (line != -1) + CCLOG("SDL Error: %s, line: %i", error, line); + else + CCLOG("SDL Error: %s", error); + SDL_ClearError(); + } +#endif } void EGLView::setFrameSize(float width, float height) { - bool eResult = false; - int u32GLFWFlags = GLFW_WINDOW; - //create the window by glfw. + bool eResult = false; + //create the window by SDL2. - //check - CCAssert(width!=0&&height!=0, "invalid window's size equal 0"); + //check + CCAssert(width!=0&&height!=0, "invalid window's size equal 0"); - //Inits GLFW - eResult = glfwInit() != GL_FALSE; + //Inits SDL2 + eResult = SDL_Init(SDL_INIT_VIDEO) == 0; + if (!eResult) { + CCAssert(0, "fail to init the SDL"); + } - if (!eResult) { - CCAssert(0, "fail to init the glfw"); - } + const std::string appName = getApplicationName(); + const int iDepth = 16; // set default value - /* Updates window hint */ - glfwOpenWindowHint(GLFW_WINDOW_NO_RESIZE, GL_TRUE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - int iDepth = 16; // set default value - /* Depending on video depth */ - switch(iDepth) - { - /* 16-bit */ - case 16: - { - /* Updates video mode */ - eResult = (glfwOpenWindow(width, height, 5, 6, 5, 0, 16, 8, (int)u32GLFWFlags) != false) ? true : false; + _window = SDL_CreateWindow(appName.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, iDepth); + checkSDLError(__LINE__); - break; - } + _context = SDL_GL_CreateContext(_window); - /* 24-bit */ - case 24: - { - /* Updates video mode */ - eResult = (glfwOpenWindow(width, height, 8, 8, 8, 0, 16, 8, (int)u32GLFWFlags) != false) ? true : false; + if (!_window || !_context) { + CCAssert(0, "Failed to initialize OpenGL context"); + } else { + SDL_GL_SetSwapInterval(1); + checkSDLError(__LINE__); + _wasInit = true; - break; - } - - /* 32-bit */ - default: - case 32: - { - /* Updates video mode */ - eResult = (glfwOpenWindow(width, height, 8, 8, 8, 8, 16, 8, (int)u32GLFWFlags) != GL_FALSE) ? true :false; - break; - } - } - - /* Success? */ - if(eResult) - { - - /* Updates actual size */ - // glfwGetWindowSize(&width, &height); - - EGLViewProtocol::setFrameSize(width, height); - - /* Updates its title */ - glfwSetWindowTitle("Cocos2dx-Linux"); - - //set the init flag - bIsInit = true; - - //register the glfw key event - glfwSetKeyCallback(keyEventHandle); - //register the glfw char event - glfwSetCharCallback(charEventHandle); - //register the glfw mouse event - glfwSetMouseButtonCallback(mouseButtonEventHandle); - //register the glfw mouse pos event - glfwSetMousePosCallback(mousePosEventHandle); -#ifdef CC_KEYBOARD_SUPPORT - //register the glfw keyboard event - glfwSetKeyCallback(keyboardEventHandle); -#endif - - glfwSetWindowCloseCallback(closeEventHandle); - - //Inits extensions - eResult = initExtensions(); - - if (!eResult) { - CCAssert(0, "fail to init the extensions of opengl"); - } - initGL(); - } + EGLViewProtocol::setFrameSize(width, height); + initGL(); + if (!GLEW_ARB_framebuffer_object) + CCAssert(0, "fail to init OpenGL extension ARB_framebuffer_object"); + if (!GLEW_ARB_vertex_buffer_object) + CCAssert(0, "fail to init OpenGL extension ARB_vertex_buffer_object"); + } } void EGLView::setFrameZoomFactor(float fZoomFactor) { _frameZoomFactor = fZoomFactor; - glfwSetWindowSize(_screenSize.width * fZoomFactor, _screenSize.height * fZoomFactor); + SDL_SetWindowSize(_window, _screenSize.width * fZoomFactor, _screenSize.height * fZoomFactor); Director::getInstance()->setProjection(Director::getInstance()->getProjection()); } @@ -292,26 +138,130 @@ void EGLView::setScissorInPoints(float x , float y , float w , float h) bool EGLView::isOpenGLReady() { - return bIsInit; + return _wasInit; } void EGLView::end() { - /* Exits from GLFW */ - glfwTerminate(); - delete this; - exit(0); + SDL_GL_DeleteContext(_context); + SDL_DestroyWindow(_window); + SDL_Quit(); + + delete this; + exit(0); } void EGLView::swapBuffers() { - if (bIsInit) { - /* Swap buffers */ - glfwSwapBuffers(); - } + if (_wasInit) { + /* Swap buffers */ + SDL_GL_SwapWindow(_window); + } } -void EGLView::setIMEKeyboardState(bool bOpen) { +// Polls events if SDL backend is on. +// Note that finger events allow multi-touch on Linux, but libsdl with X11 +// backend does not support multitouch. However multitouch should work +// out of the box on upcoming Weston and Mir display servers. +// Also supports mouse touches emulation, keyboard events, text events. +void EGLView::pollInputEvents() +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + Director::sharedDirector()->end(); + break; + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) { + int id = event.button.which; + _pressedMouseInstances.insert(id); + Point oPoint((float)event.button.x, (float)event.button.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesBegin(1, &id, &oPoint.x, &oPoint.y); + } + break; + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) { + int id = event.button.which; + _pressedMouseInstances.erase(id); + Point oPoint((float)event.button.x, (float)event.button.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesEnd(1, &id, &oPoint.x, &oPoint.y); + } + break; + case SDL_MOUSEMOTION: + if (_pressedMouseInstances.count(event.motion.which)) { + int id = event.motion.which; + Point oPoint((float)event.motion.x, (float)event.motion.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesMove(1, &id, &oPoint.x, &oPoint.y); + } + break; + case SDL_FINGERDOWN: { + int fingerId = event.tfinger.fingerId; + Point oPoint((float)event.tfinger.x, (float)event.tfinger.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesBegin(1, &fingerId, &oPoint.x, &oPoint.y); + } + break; + case SDL_FINGERUP: { + int fingerId = event.tfinger.fingerId; + Point oPoint((float)event.tfinger.x, (float)event.tfinger.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesEnd(1, &fingerId, &oPoint.x, &oPoint.y); + break; + } + case SDL_FINGERMOTION: { + int fingerId = event.tfinger.fingerId; + Point oPoint((float)event.tfinger.x, (float)event.tfinger.y); + oPoint.x /= _frameZoomFactor; + oPoint.y /= _frameZoomFactor; + handleTouchesMove(1, &fingerId, &oPoint.x, &oPoint.y); + } + break; + case SDL_TEXTINPUT: { + const std::string text = event.text.text; + IMEDispatcher::sharedDispatcher()->dispatchInsertText(text.c_str(), text.size()); + } + break; + case SDL_TEXTEDITING: + // TODO: not implemented. + // In SDL text editing is similar to patching. Each patch consists of + // selected text range and string that replaces selected text. + break; + case SDL_KEYDOWN: { + if (event.key.keysym.sym == SDLK_BACKSPACE) + IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward(); + Director::sharedDirector()->getKeyboardDispatcher()->dispatchKeyboardEvent(event.key.keysym.sym, true); + break; + case SDL_KEYUP: + Director::sharedDirector()->getKeyboardDispatcher()->dispatchKeyboardEvent(event.key.keysym.sym, false); + } + break; + } + } +} +void EGLView::setIMEKeyboardState(bool bOpen) +{ + _IMEKeyboardOpened = bOpen; + Rect zeroRect(0, 0, 0, 0); + IMEKeyboardNotificationInfo info; + info.begin = zeroRect; + info.end = zeroRect; + info.duration = 0; + if (bOpen) { + IMEDispatcher::sharedDispatcher()->dispatchKeyboardWillShow(info); + IMEDispatcher::sharedDispatcher()->dispatchKeyboardDidShow(info); + } else { + IMEDispatcher::sharedDispatcher()->dispatchKeyboardWillHide(info); + IMEDispatcher::sharedDispatcher()->dispatchKeyboardDidHide(info); + } } bool EGLView::initGL() @@ -349,14 +299,6 @@ bool EGLView::initGL() void EGLView::destroyGL() { - /* - if (_DC != NULL && _RC != NULL) - { - // deselect rendering context and delete it - wglMakeCurrent(_DC, NULL); - wglDeleteContext(_RC); - } - */ } EGLView* EGLView::getInstance() diff --git a/cocos2dx/platform/linux/CCEGLView.h b/cocos2dx/platform/linux/CCEGLView.h index 2cd4179ab7..b8b5f873cc 100644 --- a/cocos2dx/platform/linux/CCEGLView.h +++ b/cocos2dx/platform/linux/CCEGLView.h @@ -11,6 +11,8 @@ #include "platform/CCCommon.h" #include "cocoa/CCGeometry.h" #include "platform/CCEGLViewProtocol.h" +#include +#include bool initExtensions(); @@ -18,32 +20,33 @@ NS_CC_BEGIN class EGLView : public EGLViewProtocol{ public: - EGLView(); - virtual ~EGLView(); + EGLView(); + virtual ~EGLView(); - friend void keyEventHandle(int,int); - friend void mouseButtonEventHandle(int,int); - friend void mousePosEventHandle(int,int); - friend void charEventHandle(int,int); + friend void keyEventHandle(int,int); + friend void mouseButtonEventHandle(int,int); + friend void mousePosEventHandle(int,int); + friend void charEventHandle(int,int); - /** - * iPixelWidth, height: the window's size - * iWidth ,height: the point size, which may scale. - * iDepth is not the buffer depth of opengl, it indicate how may bits for a pixel - */ - virtual void setFrameSize(float width, float height); - virtual void setViewPortInPoints(float x , float y , float w , float h); - virtual void setScissorInPoints(float x , float y , float w , float h); + /** + * iPixelWidth, height: the window's size + * iWidth ,height: the point size, which may scale. + * iDepth is not the buffer depth of opengl, it indicate how may bits for a pixel + */ + virtual void setFrameSize(float width, float height); + virtual void setViewPortInPoints(float x , float y , float w , float h); + virtual void setScissorInPoints(float x , float y , float w , float h); - /* - * Set zoom factor for frame. This method is for debugging big resolution (e.g.new ipad) app on desktop. - */ - void setFrameZoomFactor(float fZoomFactor); - float getFrameZoomFactor(); - virtual bool isOpenGLReady(); - virtual void end(); - virtual void swapBuffers(); - virtual void setIMEKeyboardState(bool bOpen); + /* + * Set zoom factor for frame. This method is for debugging big resolution (e.g.new ipad) app on desktop. + */ + void setFrameZoomFactor(float fZoomFactor); + float getFrameZoomFactor(); + virtual bool isOpenGLReady(); + virtual void end(); + virtual void swapBuffers(); + virtual void pollInputEvents(); + virtual void setIMEKeyboardState(bool bOpen); /** @brief get the shared main open gl window @@ -54,13 +57,19 @@ public: CC_DEPRECATED_ATTRIBUTE static EGLView* sharedOpenGLView(); private: - bool initGL(); - void destroyGL(); -private: - //store current mouse point for moving, valid if and only if the mouse pressed - Point _mousePoint; - bool bIsInit; - float _frameZoomFactor; + bool initGL(); + void destroyGL(); + + //store current mouse point for moving, valid if and only if the mouse pressed + Point _mousePoint; + bool _wasInit; + float _frameZoomFactor; + + SDL_Window *_window; + SDL_GLContext _context; + // Several mouse instances are possible. + std::set _pressedMouseInstances; + bool _IMEKeyboardOpened; }; NS_CC_END diff --git a/cocos2dx/platform/linux/CCImage.cpp b/cocos2dx/platform/linux/CCImage.cpp index 916ad55163..38a01eff68 100644 --- a/cocos2dx/platform/linux/CCImage.cpp +++ b/cocos2dx/platform/linux/CCImage.cpp @@ -450,9 +450,8 @@ bool Image::initWithString( _width = (short)dc.iMaxLineWidth; _height = (short)dc.iMaxLineHeight; - _hasAlpha = true; + _renderFormat = Texture2D::PixelFormat::RGBA8888; _preMulti = true; - _bitsPerComponent = 8; bRet = true; diff --git a/cocos2dx/platform/mac/CCImage.mm b/cocos2dx/platform/mac/CCImage.mm index 80a1402727..c10f6981ad 100644 --- a/cocos2dx/platform/mac/CCImage.mm +++ b/cocos2dx/platform/mac/CCImage.mm @@ -21,6 +21,8 @@ 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 "CCImageCommon_cpp.h" #include #include #include "CCDirector.h" @@ -39,275 +41,11 @@ typedef struct { unsigned int height; unsigned int width; - int bitsPerComponent; bool hasAlpha; bool isPremultipliedAlpha; unsigned char* data; } tImageInfo; -static unsigned int nextPOT(unsigned int x) -{ - x = x - 1; - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >> 16); - return x + 1; -} - -static bool _initPremultipliedATextureWithImage(CGImageRef image, NSUInteger POTWide, NSUInteger POTHigh, tImageInfo *pImageInfo) -{ - NSUInteger i; - CGContextRef context = nil; - unsigned char* data = nil;; - CGColorSpaceRef colorSpace; - unsigned char* tempData; - unsigned int* inPixel32; - unsigned short* outPixel16; - bool hasAlpha; - CGImageAlphaInfo info; - CGSize imageSize; - Texture2D::PixelFormat pixelFormat; - - info = CGImageGetAlphaInfo(image); - hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO); - - size_t bpp = CGImageGetBitsPerComponent(image); - colorSpace = CGImageGetColorSpace(image); - - if(colorSpace) - { - if(hasAlpha || bpp >= 8) - { - pixelFormat = Texture2D::PixelFormat::DEFAULT; - } - else - { - pixelFormat = Texture2D::PixelFormat::RGB565; - } - } - else - { - // NOTE: No colorspace means a mask image - pixelFormat = Texture2D::PixelFormat::A8; - } - - imageSize.width = CGImageGetWidth(image); - imageSize.height = CGImageGetHeight(image); - - // Create the bitmap graphics context - - switch(pixelFormat) - { - case Texture2D::PixelFormat::RGBA8888: - case Texture2D::PixelFormat::RGBA4444: - case Texture2D::PixelFormat::RGB5A1: - colorSpace = CGColorSpaceCreateDeviceRGB(); - data = new unsigned char[POTHigh * POTWide * 4]; - info = hasAlpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); - CGColorSpaceRelease(colorSpace); - break; - - case Texture2D::PixelFormat::RGB565: - colorSpace = CGColorSpaceCreateDeviceRGB(); - data = new unsigned char[POTHigh * POTWide * 4]; - info = kCGImageAlphaNoneSkipLast; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrder32Big); - CGColorSpaceRelease(colorSpace); - break; - case Texture2D::PixelFormat::A8: - data = new unsigned char[POTHigh * POTWide]; - info = kCGImageAlphaOnly; - context = CGBitmapContextCreate(data, POTWide, POTHigh, 8, POTWide, NULL, info); - break; - default: - return false; - } - - CGRect rect; - rect.size.width = POTWide; - rect.size.height = POTHigh; - rect.origin.x = 0; - rect.origin.y = 0; - - CGContextClearRect(context, rect); - CGContextTranslateCTM(context, 0, 0); - CGContextDrawImage(context, rect, image); - - // Repack the pixel data into the right format - - if(pixelFormat == Texture2D::PixelFormat::RGB565) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); - } - - delete []data; - data = tempData; - - } - else if (pixelFormat == Texture2D::PixelFormat::RGBA4444) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A - } - - delete []data; - data = tempData; - - } - else if (pixelFormat == Texture2D::PixelFormat::RGB5A1) - { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - for(i = 0; i < POTWide * POTHigh; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A - } - - delete []data; - data = tempData; - } - - // should be after calling super init - pImageInfo->isPremultipliedAlpha = true; - pImageInfo->hasAlpha = true; - pImageInfo->bitsPerComponent = bpp; - pImageInfo->width = POTWide; - pImageInfo->height = POTHigh; - - if (pImageInfo->data) - { - delete [] pImageInfo->data; - } - pImageInfo->data = data; - - CGContextRelease(context); - return true; -} -// TODO: rename _initWithImage, it also makes a draw call. -static bool _initWithImage(CGImageRef CGImage, tImageInfo *pImageinfo, double scaleX, double scaleY) -{ - NSUInteger POTWide, POTHigh; - - if(CGImage == NULL) - { - return false; - } - - //if (cocos2d::Image::getIsScaleEnabled()) - if( cocos2d::Director::getInstance()->getContentScaleFactor() > 1.0f ) - { - POTWide = CGImageGetWidth(CGImage) * scaleX; - POTHigh = CGImageGetHeight(CGImage) * scaleY; - } - else - { - POTWide = CGImageGetWidth(CGImage); - POTHigh = CGImageGetHeight(CGImage); - } - - - // load and draw image - return _initPremultipliedATextureWithImage(CGImage, POTWide, POTHigh, pImageinfo); -} - -static bool _initWithFile(const char* path, tImageInfo *pImageinfo) -{ - CGImageRef CGImage; - NSImage *jpg; - //NSImage *png; - bool ret; - - // convert jpg to png before loading the texture - - NSString *fullPath = [NSString stringWithUTF8String:path]; - jpg = [[NSImage alloc] initWithContentsOfFile: fullPath]; - //png = [[NSImage alloc] initWithData:UIImagePNGRepresentation(jpg)]; - CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)[jpg TIFFRepresentation], NULL); - CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL); - - ret = _initWithImage(CGImage, pImageinfo, 1.0, 1.0); - - //[png release]; - [jpg release]; - if (CGImage) CFRelease(CGImage); - if (source) CFRelease(source); - - return ret; -} - -// TODO: rename _initWithData, it also makes a draw call. -static bool _initWithData(void * pBuffer, int length, tImageInfo *pImageinfo, double scaleX, double scaleY) -{ - bool ret = false; - - if (pBuffer) - { - CGImageRef CGImage; - NSData *data; - - data = [NSData dataWithBytes:pBuffer length:length]; - CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL); - CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL); - - ret = _initWithImage(CGImage, pImageinfo, scaleX, scaleY); - if (CGImage) CFRelease(CGImage); - if (source) CFRelease(source); - } - return ret; -} - -static bool _isValidFontName(const char *fontName) -{ - bool ret = false; -#if 0 - NSString *fontNameNS = [NSString stringWithUTF8String:fontName]; - - for (NSString *familiName in [NSFont familyNames]) - { - if ([familiName isEqualToString:fontNameNS]) - { - ret = true; - goto out; - } - - for(NSString *font in [NSFont fontNamesForFamilyName: familiName]) - { - if ([font isEqualToString: fontNameNS]) - { - ret = true; - goto out; - } - } - } -#endif - out: - return ret; -} - static bool _initWithString(const char * pText, cocos2d::Image::TextAlign eAlign, const char * pFontName, int nSize, tImageInfo* pInfo, cocos2d::Color3B* pStrokeColor) { bool bRet = false; @@ -452,7 +190,6 @@ static bool _initWithString(const char * pText, cocos2d::Image::TextAlign eAlign pInfo->data = dataNew; pInfo->hasAlpha = true; pInfo->isPremultipliedAlpha = true; - pInfo->bitsPerComponent = 8; bRet = true; } [bitmap release]; @@ -461,400 +198,6 @@ static bool _initWithString(const char * pText, cocos2d::Image::TextAlign eAlign return bRet; } - -static bool _enabledScale = true; - -bool isFileExists(const char* szFilePath); - -bool isFileExists(const char* szFilePath) -{ -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 - //TCHAR dirpath[MAX_PATH]; - //MultiByteToWideChar(936,0,szFilePath,-1,dirpath,sizeof(dirpath)); - DWORD dwFileAttr = GetFileAttributesA(szFilePath); - if (INVALID_FILE_ATTRIBUTES == dwFileAttr - || (dwFileAttr&FILE_ATTRIBUTE_DIRECTORY)) { - return false; - } -#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID - bool bFind = true; - do - { - struct stat buf; - int n = stat(szFilePath, &buf); - if ((0 != n) - || !(buf.st_mode&S_IFMT)) - { - bFind = false; - } - } while (0); - if (!bFind) - { - //std::string strFilenName = s_strRelativePath + szFilePath; - unsigned char * pBuffer = NULL; - unzFile pFile = NULL; - unsigned long pSize = 0; - - do - { - pFile = unzOpen(s_strAndroidPackagePath.c_str()); - if(!pFile)break; - - int nRet = unzLocateFile(pFile, szFilePath, 1); - if(UNZ_OK != nRet) - bFind = false; - else - bFind = true; - } while (0); - - if (pFile) - { - unzClose(pFile); - } - } - - return bFind; -#else - struct stat buf; - int n = stat(szFilePath, &buf); - if ((0 != n) - || !(buf.st_mode&S_IFMT)) { - return false; - } - -#endif - return true; -} - -Image::Image() -: _width(0) -, _height(0) -, _bitsPerComponent(0) -, _data(0) -, _hasAlpha(false) -, _preMulti(false) -{ - -} - -Image::~Image() -{ - CC_SAFE_DELETE_ARRAY(_data); -} - -bool Image::initWithImageFile(const char * strPath, Format eImgFmt/* = eFmtPng*/) -{ - std::string strTemp = FileUtils::getInstance()->fullPathForFilename(strPath); - if (_enabledScale) - { - if (!isFileExists(strTemp.c_str())) - { - if (strTemp.rfind("@2x") == std::string::npos) - { - int t = strTemp.rfind("."); - if (t != std::string::npos) - { - strTemp.insert(t, "@2x"); - } -/* Size size = Director::getInstance()->getWinSize(); - #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) - _scaleX = size.width/800.0f; - _scaleY = size.height/480.0f; - #else - _scaleX = size.width/960.0f; - _scaleY = size.height/640.0f; - - #endif -*/ - } - } - else - { -// _scaleX = 1.0; -// _scaleY = 1.0; - } - } - -// FileData tempData(strTemp.c_str(), "rb"); -// return initWithImageData(tempData.getBuffer(), tempData.getSize(), eImgFmt); - - unsigned long fileSize = 0; - unsigned char* pFileData = FileUtils::getInstance()->getFileData(strTemp.c_str(), "rb", &fileSize); - bool ret = initWithImageData(pFileData, fileSize, eImgFmt); - delete []pFileData; - return ret; -} - -bool Image::initWithImageFileThreadSafe(const char *fullpath, Format imageType) -{ - /* - * FileUtils::fullPathFromRelativePath() is not thread-safe, it use autorelease(). - */ - bool bRet = false; - unsigned long nSize = 0; - unsigned char* pBuffer = FileUtils::getInstance()->getFileData(fullpath, "rb", &nSize); - if (pBuffer != NULL && nSize > 0) - { - bRet = initWithImageData(pBuffer, nSize, imageType); - } - CC_SAFE_DELETE_ARRAY(pBuffer); - return bRet; -} - - - -/* -// please uncomment this and integrate it somehow if you know what your doing, thanks -bool Image::potImageData(unsigned int POTWide, unsigned int POTHigh) -{ - unsigned char* data = NULL; - unsigned char* tempData =NULL; - unsigned int* inPixel32 = NULL; - unsigned short* outPixel16 = NULL; - bool hasAlpha; - Texture2D::PixelFormat pixelFormat; - - hasAlpha = this->hasAlpha(); - - size_t bpp = this->getBitsPerComponent(); - - // compute pixel format - if(hasAlpha) - { - pixelFormat = Texture2D::defaultAlphaPixelFormat(); - } - else - { - if (bpp >= 8) - { - pixelFormat = Texture2D::PixelFormat::RGB888; - } - else - { - CCLOG("cocos2d: Texture2D: Using RGB565 texture since image has no alpha"); - pixelFormat = Texture2D::PixelFormat::RGB565; - } - } - - switch(pixelFormat) { - case Texture2D::PixelFormat::RGBA8888: - case Texture2D::PixelFormat::RGBA4444: - case Texture2D::PixelFormat::RGB5A1: - case Texture2D::PixelFormat::RGB565: - case Texture2D::PixelFormat::A8: - tempData = (unsigned char*)(this->getData()); - CCASSERT(tempData != NULL, "NULL image data."); - - if(this->getWidth() == (short)POTWide && this->getHeight() == (short)POTHigh) - { - data = new unsigned char[POTHigh * POTWide * 4]; - memcpy(data, tempData, POTHigh * POTWide * 4); - } - else - { - data = new unsigned char[POTHigh * POTWide * 4]; - memset(data, 0, POTHigh * POTWide * 4); - - unsigned char* pPixelData = (unsigned char*) tempData; - unsigned char* pTargetData = (unsigned char*) data; - - int imageHeight = this->getHeight(); - for(int y = 0; y < imageHeight; ++y) - { - memcpy(pTargetData+POTWide*4*y, pPixelData+(this->getWidth())*4*y, (this->getWidth())*4); - } - } - - break; - case Texture2D::PixelFormat::RGB888: - tempData = (unsigned char*)(this->getData()); - CCASSERT(tempData != NULL, "NULL image data."); - if(this->getWidth() == (short)POTWide && this->getHeight() == (short)POTHigh) - { - data = new unsigned char[POTHigh * POTWide * 3]; - memcpy(data, tempData, POTHigh * POTWide * 3); - } - else - { - data = new unsigned char[POTHigh * POTWide * 3]; - memset(data, 0, POTHigh * POTWide * 3); - - unsigned char* pPixelData = (unsigned char*) tempData; - unsigned char* pTargetData = (unsigned char*) data; - - int imageHeight = this->getHeight(); - for(int y = 0; y < imageHeight; ++y) - { - memcpy(pTargetData+POTWide*3*y, pPixelData+(this->getWidth())*3*y, (this->getWidth())*3); - } - } - break; - default: - CCASSERT(0, "Invalid pixel format"); - } - - // Repack the pixel data into the right format - - if(pixelFormat == Texture2D::PixelFormat::RGB565) { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - - unsigned int length = POTWide * POTHigh; - for(unsigned int i = 0; i < length; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B - } - - delete [] data; - data = tempData; - } - else if (pixelFormat == Texture2D::PixelFormat::RGBA4444) { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - - unsigned int length = POTWide * POTHigh; - for(unsigned int i = 0; i < length; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A - } - - delete [] data; - data = tempData; - } - else if (pixelFormat == Texture2D::PixelFormat::RGB5A1) { - //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" - tempData = new unsigned char[POTHigh * POTWide * 2]; - inPixel32 = (unsigned int*)data; - outPixel16 = (unsigned short*)tempData; - - unsigned int length = POTWide * POTHigh; - for(unsigned int i = 0; i < length; ++i, ++inPixel32) - { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A - } - - delete []data; - data = tempData; - } - else if (pixelFormat == Texture2D::PixelFormat::A8) - { - // fix me, how to convert to A8 - pixelFormat = Texture2D::PixelFormat::RGBA8888; - - // - //The code can not work, how to convert to A8? - // - //tempData = new unsigned char[POTHigh * POTWide]; - //inPixel32 = (unsigned int*)data; - //outPixel8 = tempData; - - //unsigned int length = POTWide * POTHigh; - //for(unsigned int i = 0; i < length; ++i, ++inPixel32) - //{ - // *outPixel8++ = (*inPixel32 >> 24) & 0xFF; - //} - - //delete []data; - //data = tempData; - - } - - if (data) - { - CC_SAFE_DELETE_ARRAY(_data); - _data = data; - } - return true; -} -*/ - -//bool Image::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/) -bool Image::initWithImageData(void * pData, - int nDataLen, - Format eFmt, - int nWidth, - int nHeight, - int nBitsPerComponent) -{ - bool bRet = false; - tImageInfo info = {0}; - do - { - CC_BREAK_IF(! pData || nDataLen <= 0); - - if (eFmt == Format::RAW_DATA) - { - bRet = initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent, false); - } - else if (eFmt == Image::Format::WEBP) - { - bRet = initWithWebpData(pData, nDataLen); - } - else - { - bRet = _initWithData(pData, nDataLen, &info, 1.0f, 1.0f);//_scaleX, _scaleY); - if (bRet) - { - _height = (short)info.height; - _width = (short)info.width; - _bitsPerComponent = info.bitsPerComponent; - if (eFmt == Format::JPG) - { - _hasAlpha = true; - _preMulti = false; - } - else - { - _hasAlpha = info.hasAlpha; - _preMulti = info.isPremultipliedAlpha; - } - _data = info.data; - } - } - } while (0); - - return bRet; -} - -bool Image::initWithRawData(void *pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent, bool bPreMulti) -{ - bool bRet = false; - do - { - CC_BREAK_IF(0 == nWidth || 0 == nHeight); - - _bitsPerComponent = nBitsPerComponent; - _height = (short)nHeight; - _width = (short)nWidth; - _hasAlpha = true; - - // only RGBA8888 supported - int nBytesPerComponent = 4; - int nSize = nHeight * nWidth * nBytesPerComponent; - _data = new unsigned char[nSize]; - CC_BREAK_IF(! _data); - memcpy(_data, pData, nSize); - - bRet = true; - } while (0); - return bRet; -} - bool Image::initWithString( const char * pText, int nWidth, @@ -873,8 +216,7 @@ bool Image::initWithString( } _height = (short)info.height; _width = (short)info.width; - _bitsPerComponent = info.bitsPerComponent; - _hasAlpha = info.hasAlpha; + _renderFormat = Texture2D::PixelFormat::RGBA8888; _preMulti = info.isPremultipliedAlpha; if (_data) { CC_SAFE_DELETE_ARRAY(_data); @@ -884,13 +226,6 @@ bool Image::initWithString( return true; } -bool Image::saveToFile(const char *pszFilePath, bool bIsToRGB) -{ - assert(false); - return false; -} - - NS_CC_END diff --git a/cocos2dx/platform/nacl/CCImage.cpp b/cocos2dx/platform/nacl/CCImage.cpp index c29109f8d4..f59e4ae027 100644 --- a/cocos2dx/platform/nacl/CCImage.cpp +++ b/cocos2dx/platform/nacl/CCImage.cpp @@ -462,9 +462,8 @@ bool Image::initWithString( _width = (short)dc.iMaxLineWidth; _height = (short)dc.iMaxLineHeight; - _hasAlpha = true; _preMulti = true; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; bRet = true; diff --git a/cocos2dx/platform/qt5/AccelerometerListener.cpp b/cocos2dx/platform/qt5/AccelerometerListener.cpp new file mode 100644 index 0000000000..6fdfb44fab --- /dev/null +++ b/cocos2dx/platform/qt5/AccelerometerListener.cpp @@ -0,0 +1,42 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "AccelerometerListener.h" + +#include + +AccelerometerListener::AccelerometerListener(Accelerometer *accelerometer) + : QObject() + , m_accelerometer(accelerometer) +{ +} + +void +AccelerometerListener::onReadingChanged() +{ + m_accelerometer->readingChanged(); +} diff --git a/cocos2dx/platform/qt5/AccelerometerListener.h b/cocos2dx/platform/qt5/AccelerometerListener.h new file mode 100644 index 0000000000..552be1c4c1 --- /dev/null +++ b/cocos2dx/platform/qt5/AccelerometerListener.h @@ -0,0 +1,50 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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. + * + **/ + +#ifndef COCOS2DX_ACCELEROMETER_LISTENER_QT5_H +#define COCOS2DX_ACCELEROMETER_LISTENER_QT5_H + +#include "CCAccelerometer.h" + +#include + +USING_NS_CC; + +class AccelerometerListener : public QObject { + Q_OBJECT + + public: + AccelerometerListener(Accelerometer *accelerometer); + + public slots: + void onReadingChanged(); + + private: + Accelerometer *m_accelerometer; +}; + +#endif /* COCOS2DX_ACCELEROMETER_LISTENER_QT5_H */ diff --git a/cocos2dx/platform/qt5/CCAccelerometer.cpp b/cocos2dx/platform/qt5/CCAccelerometer.cpp new file mode 100644 index 0000000000..7d31aa2f72 --- /dev/null +++ b/cocos2dx/platform/qt5/CCAccelerometer.cpp @@ -0,0 +1,100 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "CCAccelerometer.h" +#include "AccelerometerListener.h" + +#include +#include + +NS_CC_BEGIN + +static Accelerometer * +shared_accelerometer = NULL; + +Accelerometer::Accelerometer() + : m_accelerometer(new QAccelerometer) + , m_listener(new AccelerometerListener(this)) + , m_function(nullptr) +{ + QObject::connect(m_accelerometer, SIGNAL(readingChanged()), + m_listener, SLOT(onReadingChanged())); +} + +Accelerometer::~Accelerometer() +{ + delete m_listener; + delete m_accelerometer; +} + +Accelerometer * +Accelerometer::sharedAccelerometer() +{ + if (shared_accelerometer == NULL) { + shared_accelerometer = new Accelerometer; + } + + return shared_accelerometer; +} + + +void +Accelerometer::setDelegate(std::function function) +{ + m_function = function; +} + +void +Accelerometer::setAccelerometerInterval(float interval) +{ + if (interval == 0.0) { + m_accelerometer->setDataRate(0.0); + } else { + // Interval is specified in seconds + m_accelerometer->setDataRate(1.0 / interval); + } +} + +void +Accelerometer::readingChanged() +{ + if (m_function == NULL) { + return; + } + + QAccelerometerReading *reading = m_accelerometer->reading(); + + Acceleration accel; + accel.x = reading->x(); + accel.y = reading->y(); + accel.z = reading->z(); + accel.timestamp = reading->timestamp(); + + m_function(&accel); +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCAccelerometer.h b/cocos2dx/platform/qt5/CCAccelerometer.h new file mode 100644 index 0000000000..f8f12a1ffc --- /dev/null +++ b/cocos2dx/platform/qt5/CCAccelerometer.h @@ -0,0 +1,62 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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. + * + **/ + + +#ifndef CCACCELEROMETER_QT5_H +#define CCACCELEROMETER_QT5_H + +#include "platform/CCCommon.h" +#include "platform/CCAccelerometerDelegate.h" +#include + +class QAccelerometer; +class AccelerometerListener; + +NS_CC_BEGIN + +class Accelerometer { + public: + Accelerometer(); + ~Accelerometer(); + + static Accelerometer *sharedAccelerometer(); + + void setDelegate(std::function function); + void setAccelerometerInterval(float interval); + + /* Functions to be called from AccelerometerListener */ + void readingChanged(); + + private: + QAccelerometer *m_accelerometer; + AccelerometerListener *m_listener; + std::function m_function; +}; + +NS_CC_END + +#endif /* CCACCELEROMETER_QT5_H */ diff --git a/cocos2dx/platform/qt5/CCApplication.cpp b/cocos2dx/platform/qt5/CCApplication.cpp new file mode 100644 index 0000000000..e4748c0a33 --- /dev/null +++ b/cocos2dx/platform/qt5/CCApplication.cpp @@ -0,0 +1,204 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "CCApplication.h" +#include +#include +#include +#include "CCDirector.h" +#include "platform/CCFileUtils.h" + +#include +#include +#include +#include + +class Cocos2DQt5MainloopIntegration : public QObject { + public: + Cocos2DQt5MainloopIntegration() + : QObject() + , m_timer(0) + { + } + + void setInterval(int interval_ms) + { + if (m_timer != 0) { + killTimer(m_timer); + } + + m_timer = startTimer(interval_ms); + } + + protected: + virtual void timerEvent(QTimerEvent *event) + { + cocos2d::Director::getInstance()->mainLoop(); + } + + private: + int m_timer; +}; + + +NS_CC_BEGIN + +// Application singleton +static Application * +application = NULL; + +static int +global_fake_argc = 1; + +static char * +global_fake_argv[1]; + +// @deprecated Use getInstance() instead +Application * +Application::sharedApplication() +{ + return getInstance(); +} + +Application * +Application::getInstance() +{ + CC_ASSERT(application != NULL); + return application; +} + +Application::Application() + : m_application(NULL) + , m_animationInterval(1000 / 60) + , m_resourceRootPath("") + , m_mainloop(new Cocos2DQt5MainloopIntegration) +{ + // Inject argv[0] by resolving /proc/self/exe + QString filename = QDir("/proc/self/exe").canonicalPath(); + QByteArray utf8 = filename.toUtf8(); + global_fake_argv[0] = strdup(utf8.data()); + + m_application = new QGuiApplication(global_fake_argc, global_fake_argv); + + CC_ASSERT(application == NULL); + application = this; +} + +Application::~Application() +{ + delete m_mainloop; + delete m_application; + + CC_ASSERT(application == this); + application = NULL; +} + +int +Application::run() +{ + // Initialize instance and cocos2d. + if (!applicationDidFinishLaunching()) { + return 0; + } + + m_mainloop->setInterval(m_animationInterval); + + return m_application->exec(); +} + +void +Application::setAnimationInterval(double interval) +{ + // Interval is expressed in seconds + m_animationInterval = interval * 1000; + + m_mainloop->setInterval(m_animationInterval); +} + +void +Application::setResourceRootPath(const std::string &rootResDir) +{ + m_resourceRootPath = rootResDir; + if (m_resourceRootPath[m_resourceRootPath.length() - 1] != '/') { + m_resourceRootPath += '/'; + } + FileUtils* pFileUtils = FileUtils::getInstance(); + std::vector searchPaths = pFileUtils->getSearchPaths(); + searchPaths.insert(searchPaths.begin(), m_resourceRootPath); + pFileUtils->setSearchPaths(searchPaths); +} + +const std::string & +Application::getResourceRootPath() +{ + return m_resourceRootPath; +} + +TargetPlatform +Application::getTargetPlatform() +{ + return kTargetLinux; +} + +ccLanguageType +Application::getCurrentLanguage() +{ + QLocale locale; + + switch (locale.language()) { + case QLocale::English: + return kLanguageEnglish; + case QLocale::Chinese: + return kLanguageChinese; + case QLocale::French: + return kLanguageFrench; + case QLocale::Italian: + return kLanguageItalian; + case QLocale::German: + return kLanguageGerman; + case QLocale::Spanish: + return kLanguageSpanish; + case QLocale::Russian: + return kLanguageRussian; + case QLocale::Korean: + return kLanguageKorean; + case QLocale::Japanese: + return kLanguageJapanese; + case QLocale::Hungarian: + return kLanguageHungarian; + case QLocale::Portuguese: + return kLanguagePortuguese; + case QLocale::Arabic: + return kLanguageArabic; + default: + break; + } + + return kLanguageEnglish; +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCApplication.h b/cocos2dx/platform/qt5/CCApplication.h new file mode 100644 index 0000000000..85f3728603 --- /dev/null +++ b/cocos2dx/platform/qt5/CCApplication.h @@ -0,0 +1,95 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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. + * + **/ + + +#ifndef CCAPPLICATION_QT5_H +#define CCAPPLICATION_QT5_H + +#include "platform/CCCommon.h" +#include "platform/CCApplicationProtocol.h" +#include + +class QGuiApplication; +class Cocos2DQt5MainloopIntegration; + +NS_CC_BEGIN + +class Application : public ApplicationProtocol { + public: + Application(); + virtual ~Application(); + + /** + @brief Callback by Director for limit FPS. + @interval The time, which expressed in second in second, between current frame and next. + */ + void setAnimationInterval(double interval); + + /** + @brief Run the message loop. + */ + int run(); + + /** + @brief Get current application instance. + @return Current application instance pointer. + */ + static Application* getInstance(); + + /** @deprecated Use getInstance() instead */ + CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication(); + + /* override functions */ + virtual ccLanguageType getCurrentLanguage(); + + /** + * Sets the Resource root path. + * @deprecated Please use CCFileUtils::sharedFileUtils()->setSearchPaths() instead. + */ + CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string &rootResDir); + + /** + * Gets the Resource root path. + * @deprecated Please use CCFileUtils::sharedFileUtils()->getSearchPaths() instead. + */ + CC_DEPRECATED_ATTRIBUTE const std::string &getResourceRootPath(); + + /** + @brief Get target platform + */ + virtual TargetPlatform getTargetPlatform(); + + protected: + QGuiApplication *m_application; + long m_animationInterval; + std::string m_resourceRootPath; + Cocos2DQt5MainloopIntegration *m_mainloop; +}; + +NS_CC_END + +#endif /* CCAPPLICATION_QT5_H */ diff --git a/cocos2dx/platform/qt5/CCCommon.cpp b/cocos2dx/platform/qt5/CCCommon.cpp new file mode 100644 index 0000000000..5fd58ecb22 --- /dev/null +++ b/cocos2dx/platform/qt5/CCCommon.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Cocos2D-X Qt 5 Platform +Copyright (C) 2013 Jolla Ltd. +Contact: Thomas Perl + +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 "platform/CCCommon.h" +#include "CCStdC.h" + +NS_CC_BEGIN + +#define MAX_LEN (cocos2d::kMaxLogLen + 1) + +/* @deprecated, use cocos2d::log() instead (see below) */ +void CCLog(const char * pszFormat, ...) +{ + char szBuf[MAX_LEN]; + + va_list ap; + va_start(ap, pszFormat); + vsnprintf(szBuf, MAX_LEN, pszFormat, ap); + va_end(ap); + + // Strip any trailing newlines from log message. + size_t len = strlen(szBuf); + while (len && szBuf[len-1] == '\n') + { + szBuf[len-1] = '\0'; + len--; + } + + fprintf(stderr, "cocos2d-x debug info [%s]\n", szBuf); +} + +void log(const char * pszFormat, ...) +{ + char szBuf[MAX_LEN]; + + va_list ap; + va_start(ap, pszFormat); + vsnprintf(szBuf, MAX_LEN, pszFormat, ap); + va_end(ap); + + // Strip any trailing newlines from log message. + size_t len = strlen(szBuf); + while (len && szBuf[len-1] == '\n') + { + szBuf[len-1] = '\0'; + len--; + } + + fprintf(stderr, "cocos2d-x debug info [%s]\n", szBuf); +} + +void MessageBox(const char * pszMsg, const char * pszTitle) +{ + log("%s: %s", pszTitle, pszMsg); +} + +void LuaLog(const char * pszFormat) +{ + puts(pszFormat); +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCDevice.cpp b/cocos2dx/platform/qt5/CCDevice.cpp new file mode 100644 index 0000000000..ba3c0ba33e --- /dev/null +++ b/cocos2dx/platform/qt5/CCDevice.cpp @@ -0,0 +1,43 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "platform/CCDevice.h" + +#include +#include + +NS_CC_BEGIN + +int Device::getDPI() +{ + QGuiApplication *app = static_cast(QGuiApplication::instance()); + QScreen *screen = app->primaryScreen(); + return screen->physicalDotsPerInch(); +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCEGLView.cpp b/cocos2dx/platform/qt5/CCEGLView.cpp new file mode 100644 index 0000000000..aaeee74811 --- /dev/null +++ b/cocos2dx/platform/qt5/CCEGLView.cpp @@ -0,0 +1,200 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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 "CCEGLView.h" +#include "CCGL.h" + +#include "ccMacros.h" +#include "CCDirector.h" + +#include "touch_dispatcher/CCTouch.h" +#include "touch_dispatcher/CCTouchDispatcher.h" +#include "text_input_node/CCIMEDispatcher.h" + +#include +#include + +#include +#include +#include + +#include + +NS_CC_BEGIN + +class Cocos2DQt5OpenGLIntegration : public QWindow { + public: + Cocos2DQt5OpenGLIntegration(EGLView *view, int width, int height); + ~Cocos2DQt5OpenGLIntegration(); + + virtual void touchEvent(QTouchEvent *event); + virtual bool event(QEvent *event); + + void swapBuffers(); + + private: + EGLView *m_egl_view; + QOpenGLContext *m_context; +}; + +Cocos2DQt5OpenGLIntegration::Cocos2DQt5OpenGLIntegration(EGLView *view, int width, int height) + : m_egl_view(view) + , m_context(NULL) +{ + setSurfaceType(QSurface::OpenGLSurface); + resize(width, height); + showFullScreen(); + + m_context = new QOpenGLContext(this); + m_context->create(); + m_context->makeCurrent(this); +} + +Cocos2DQt5OpenGLIntegration::~Cocos2DQt5OpenGLIntegration() +{ + delete m_context; +} + +void +Cocos2DQt5OpenGLIntegration::touchEvent(QTouchEvent *event) +{ + foreach (QTouchEvent::TouchPoint point, event->touchPoints()) { + int id = point.id(); + QPointF pos = point.pos(); + float x = pos.x(); + float y = pos.y(); + Qt::TouchPointState state = point.state(); + + switch (state) { + case Qt::TouchPointPressed: + m_egl_view->handleTouchesBegin(1, &id, &x, &y); + break; + case Qt::TouchPointMoved: + m_egl_view->handleTouchesMove(1, &id, &x, &y); + break; + case Qt::TouchPointStationary: + // Do nothing + break; + case Qt::TouchPointReleased: + m_egl_view->handleTouchesEnd(1, &id, &x, &y); + break; + default: + // Do nothing + break; + } + } +} + +bool +Cocos2DQt5OpenGLIntegration::event(QEvent *event) +{ + if (event->type() == QEvent::Close) { + Director::getInstance()->end(); + } + + return QWindow::event(event); +} + +void +Cocos2DQt5OpenGLIntegration::swapBuffers() +{ + m_context->swapBuffers(this); + m_context->makeCurrent(this); +} + + +/* Global EGLView singleton for this module */ +static EGLView * +egl_view = NULL; + + +/** @deprecated Use getInstance() instead */ +EGLView * +EGLView::sharedOpenGLView() +{ + return getInstance(); +} + +EGLView * +EGLView::getInstance() +{ + if (egl_view == NULL) { + egl_view = new EGLView; + } + + return egl_view; +} + + +EGLView::EGLView() + : m_integration(NULL) +{ +} + +EGLView::~EGLView() +{ + if (m_integration) { + delete m_integration; + } +} + +void +EGLView::setFrameSize(float width, float height) +{ + if (m_integration == NULL) { + m_integration = new Cocos2DQt5OpenGLIntegration(this, + (int)width, (int)height); + } else { + m_integration->resize(width, height); + } + + EGLViewProtocol::setFrameSize(width, height); +} + +void +EGLView::swapBuffers() +{ + if (m_integration != NULL) { + m_integration->swapBuffers(); + } +} + +void +EGLView::setIMEKeyboardState(bool bOpen) +{ + QGuiApplication *app = static_cast(QGuiApplication::instance()); + app->inputMethod()->setVisible(bOpen); +} + +void +EGLView::end() +{ + QGuiApplication::exit(0); +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCEGLView.h b/cocos2dx/platform/qt5/CCEGLView.h new file mode 100644 index 0000000000..223e0f71e1 --- /dev/null +++ b/cocos2dx/platform/qt5/CCEGLView.h @@ -0,0 +1,63 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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. + * + **/ + + +#ifndef CCEGLVIEW_QT5_H +#define CCEGLVIEW_QT5_H + +#include "platform/CCCommon.h" +#include "cocoa/CCGeometry.h" +#include "platform/CCEGLViewProtocol.h" + +NS_CC_BEGIN + +class Cocos2DQt5OpenGLIntegration; + +class EGLView : public EGLViewProtocol { + public: + EGLView(); + virtual ~EGLView(); + + static EGLView *getInstance(); + + /** @deprecated Use getInstance() instead */ + CC_DEPRECATED_ATTRIBUTE static EGLView *sharedOpenGLView(); + + virtual bool isOpenGLReady() { return (m_integration != NULL); } + + virtual void setFrameSize(float width, float height); + virtual void swapBuffers(); + virtual void setIMEKeyboardState(bool bOpen); + virtual void end(); + + private: + Cocos2DQt5OpenGLIntegration *m_integration; +}; + +NS_CC_END + +#endif /* CCEGLVIEW_QT5_H */ diff --git a/cocos2dx/platform/qt5/CCFileUtilsQt5.cpp b/cocos2dx/platform/qt5/CCFileUtilsQt5.cpp new file mode 100644 index 0000000000..a0a6d3978f --- /dev/null +++ b/cocos2dx/platform/qt5/CCFileUtilsQt5.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** + Copyright (c) 2010 cocos2d-x.org + + http://www.cocos2d-x.org + + Cocos2D-X Qt 5 Platform + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + + 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 "platform/CCFileUtils.h" +#include "platform/CCPlatformMacros.h" +#include "platform/CCCommon.h" +#include "ccTypes.h" +#include "ccTypeInfo.h" +#include "ccMacros.h" + +#include +#include + +#include +#include +#include +#include + +NS_CC_BEGIN + +class CC_DLL FileUtilsQt5 : public FileUtils +{ + public: + FileUtilsQt5(); + + /* override funtions */ + virtual bool init(); + virtual std::string getWritablePath(); + virtual bool isFileExist(const std::string& strFilePath); +}; + +FileUtils * +FileUtils::getInstance() +{ + if (s_sharedFileUtils == NULL) + { + s_sharedFileUtils = new FileUtilsQt5(); + s_sharedFileUtils->init(); + } + return s_sharedFileUtils; +} + +FileUtilsQt5::FileUtilsQt5() +{ +} + +bool +FileUtilsQt5::init() +{ + // Determine directory of the application executable + QDir app_dir = QDir("/proc/self/exe").canonicalPath(); + app_dir.cdUp(); + + // Resources should be placed alongside the binary (same directory) + QString path = app_dir.path() + "/Resources/"; + _defaultResRootPath = path.toStdString(); + + return FileUtils::init(); +} + +std::string +FileUtilsQt5::getWritablePath() +{ + QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); + + // Create directory if it does not exist yet + if (!dir.exists()) { + dir.mkpath("."); + } + + return dir.path().toStdString(); +} + +bool FileUtilsQt5::isFileExist(const std::string& strFilePath) +{ + QString filePath = QString::fromStdString(strFilePath); + + // Try filename without any path first + if (QFile(filePath).exists()) { + return true; + } + + // If not found, look for file in _defaultResRootPath + QString defaultResRootPath = QString::fromStdString(_defaultResRootPath); + return QFile(QDir(defaultResRootPath).filePath(filePath)).exists(); +} + +NS_CC_END diff --git a/cocos2dx/platform/qt5/CCGL.h b/cocos2dx/platform/qt5/CCGL.h new file mode 100644 index 0000000000..6ebe1c3f3c --- /dev/null +++ b/cocos2dx/platform/qt5/CCGL.h @@ -0,0 +1,16 @@ +#ifndef __CCGL_H__ +#define __CCGL_H__ + +#include +#include + +#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES + +#define glClearDepth glClearDepthf + +// android defines GL_BGRA_EXT but not GL_BRGA +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif + +#endif // __CCGL_H__ diff --git a/cocos2dx/platform/qt5/CCPlatformDefine.h b/cocos2dx/platform/qt5/CCPlatformDefine.h new file mode 100644 index 0000000000..9bbd1df365 --- /dev/null +++ b/cocos2dx/platform/qt5/CCPlatformDefine.h @@ -0,0 +1,47 @@ +/** + * + * Cocos2D-X Qt 5 Platform + * + * Copyright (C) 2013 Jolla Ltd. + * Contact: Thomas Perl + * + * 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. + * + **/ + + +#ifndef __CCPLATFORMDEFINE_H__ +#define __CCPLATFORMDEFINE_H__ + +// Adapted from platform/linux/CCPlatformDefine.h + +#include +#include + +#if defined(_USRDLL) +# define CC_DLL __attribute__ ((visibility ("default"))) +#else +# define CC_DLL __attribute__ ((visibility ("default"))) +#endif + +#include +#define CC_ASSERT(cond) assert(cond) +#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam + +#endif /* __CCPLATFORMDEFINE_H__*/ diff --git a/cocos2dx/platform/qt5/CCStdC.h b/cocos2dx/platform/qt5/CCStdC.h new file mode 100644 index 0000000000..1813e0c4f4 --- /dev/null +++ b/cocos2dx/platform/qt5/CCStdC.h @@ -0,0 +1,58 @@ +/**************************************************************************** +Copyright (c) 2010 cocos2d-x.org + +http://www.cocos2d-x.org + +Cocos2D-X Qt 5 Platform +Copyright (C) 2013 Jolla Ltd. +Contact: Thomas Perl + +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. +****************************************************************************/ + +#ifndef __CC_STD_C_H__ +#define __CC_STD_C_H__ + +#include "platform/CCPlatformMacros.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MIN +#define MIN(x,y) (((x) > (y)) ? (y) : (x)) +#endif // MIN + +#ifndef MAX +#define MAX(x,y) (((x) < (y)) ? (y) : (x)) +#endif // MAX + +// some function linux do not have +#define tanf tan +#define sqrtf sqrt +#define cosf cos +#define sinf sin + +#endif // __CC_STD_C_H__ diff --git a/cocos2dx/textures/etc/etc1.cpp b/cocos2dx/platform/third_party/common/etc/etc1.cpp similarity index 100% rename from cocos2dx/textures/etc/etc1.cpp rename to cocos2dx/platform/third_party/common/etc/etc1.cpp diff --git a/cocos2dx/textures/etc/etc1.h b/cocos2dx/platform/third_party/common/etc/etc1.h similarity index 100% rename from cocos2dx/textures/etc/etc1.h rename to cocos2dx/platform/third_party/common/etc/etc1.h diff --git a/cocos2dx/platform/third_party/common/libjpeg/jconfig.h b/cocos2dx/platform/third_party/common/libjpeg/jconfig.h new file mode 100644 index 0000000000..c561e3ceb9 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libjpeg/jconfig.h @@ -0,0 +1,54 @@ +/* jconfig.h. Generated from jconfig.cfg by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.txt for explanations */ + +#define HAVE_PROTOTYPES 1 +#define HAVE_UNSIGNED_CHAR 1 +#define HAVE_UNSIGNED_SHORT 1 +/* #undef void */ +/* #undef const */ +/* #undef CHAR_IS_UNSIGNED */ +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_LOCALE_H 1 +/* #undef NEED_BSD_STRINGS */ +/* #undef NEED_SYS_TYPES_H */ +/* #undef NEED_FAR_POINTERS */ +/* #undef NEED_SHORT_EXTERNAL_NAMES */ +/* Define this if you get warnings about undefined structures. */ +/* #undef INCOMPLETE_TYPES_BROKEN */ + +/* Define "boolean" as unsigned char, not int, on Windows systems. */ +//#ifdef _WIN32 +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +//#endif + +#ifdef JPEG_INTERNALS + +/* #undef RIGHT_SHIFT_IS_UNSIGNED */ +#define INLINE __inline__ +/* These are for configuring the JPEG memory manager. */ +/* #undef DEFAULT_MAX_MEM */ +/* #undef NO_MKTEMP */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +/* #undef RLE_SUPPORTED */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* #undef TWO_FILE_COMMANDLINE */ +/* #undef NEED_SIGNAL_CATCHER */ +/* #undef DONT_USE_B_MODE */ + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +/* #undef PROGRESS_REPORT */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/cocos2dx/platform/third_party/common/libjpeg/jmorecfg.h b/cocos2dx/platform/third_party/common/libjpeg/jmorecfg.h new file mode 100644 index 0000000000..af266c422b --- /dev/null +++ b/cocos2dx/platform/third_party/common/libjpeg/jmorecfg.h @@ -0,0 +1,390 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2012 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +#ifndef _BASETSD_H /* MinGW is slightly different */ +#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +typedef long INT32; +#endif +#endif +#endif +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* The noreturn type identifier is used to declare functions + * which cannot return. + * Compilers can thus create more optimized code and perform + * better checks for warnings and errors. + * Static analyzer tools can make improved inferences about + * execution paths and are prevented from giving false alerts. + * + * Unfortunately, the proposed specifications of corresponding + * extensions in the Dec 2011 ISO C standard revision (C11), + * GCC, MSVC, etc. are not viable. + * Thus we introduce a user defined type to declare noreturn + * functions at least for clarity. A proper compiler would + * have a suitable noreturn type to match in place of void. + */ + +#ifndef HAVE_NORETURN_T +typedef void noreturn_t; +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ +#define HAVE_BOOLEAN +#ifdef HAVE_BOOLEAN +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#else +typedef enum { FALSE = 0, TRUE = 1 } boolean; +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/cocos2dx/platform/third_party/common/libjpeg/jpeglib.h b/cocos2dx/platform/third_party/common/libjpeg/jpeglib.h new file mode 100644 index 0000000000..0a6dac44c3 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libjpeg/jpeglib.h @@ -0,0 +1,1173 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * Modified 2002-2012 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +extern "C" { +#endif +#endif + +/* Version IDs for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90". + */ + +#define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ +#define JPEG_LIB_VERSION_MAJOR 9 +#define JPEG_LIB_VERSION_MINOR 0 + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples, + * reflecting any scaling we choose to apply during the DCT step. + * Values from 1 to 16 are supported. + * Note that different components may receive different DCT scalings. + */ + int DCT_h_scaled_size; + int DCT_v_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface); + * DCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE) + * and similarly for height. + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* Supported color transforms. */ + +typedef enum { + JCT_NONE = 0, + JCT_SUBTRACT_GREEN = 1 +} J_COLOR_TRANSFORM; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + JDIMENSION jpeg_width; /* scaled JPEG image width */ + JDIMENSION jpeg_height; /* scaled JPEG image height */ + /* Dimensions of actual JPEG image that will be written to file, + * derived from input dimensions by scaling factors above. + * These fields are computed by jpeg_start_compress(). + * You can also use jpeg_calc_jpeg_dimensions() to determine these values + * in advance of calling jpeg_start_compress(). + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + int q_scale_factor[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined, + * and corresponding scale factors (percentage, initialized 100). + */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier, writes LSE marker if nonzero */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + J_COLOR_TRANSFORM color_transform; + /* Color transform identifier derived from LSE marker, otherwise zero */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ + int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* These fields are derived from Se of first SOS marker. + */ + int block_size; /* the basic DCT block size: 1..16 */ + const int * natural_order; /* natural-order position array for entropy decode */ + int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_mem_dest jMemDest +#define jpeg_mem_src jMemSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_default_qtables jDefQTables +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_calc_jpeg_dimensions jCjpegDimensions +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_core_output_dimensions jCoreDimensions +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Data source and destination managers: memory buffers. */ +EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, + unsigned char ** outbuffer, + unsigned long * outsize)); +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + unsigned char * inbuffer, + unsigned long insize)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Precalculate JPEG dimensions for current compression parameters. */ +EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.txt concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +#ifndef DONT_USE_EXTERN_C +} +#endif +#endif + +#endif /* JPEGLIB_H */ diff --git a/cocos2dx/platform/third_party/common/libpng/png.h.REMOVED.git-id b/cocos2dx/platform/third_party/common/libpng/png.h.REMOVED.git-id new file mode 100644 index 0000000000..d467c8fd13 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libpng/png.h.REMOVED.git-id @@ -0,0 +1 @@ +0b5053fcffd754e25abc95e24905e5476ee5c451 \ No newline at end of file diff --git a/cocos2dx/platform/third_party/common/libpng/pngconf.h b/cocos2dx/platform/third_party/common/libpng/pngconf.h new file mode 100644 index 0000000000..31f996757b --- /dev/null +++ b/cocos2dx/platform/third_party/common/libpng/pngconf.h @@ -0,0 +1,616 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.6.2 - April 25, 2013 + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* To do: Do all of this in scripts/pnglibconf.dfa */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED +# ifdef PNG_USER_WIDTH_MAX +# undef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +# endif +# ifdef PNG_USER_HEIGHT_MAX +# undef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +# endif +# ifdef PNG_USER_CHUNK_MALLOC_MAX +# undef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 4000000L +# endif +# ifdef PNG_USER_CHUNK_CACHE_MAX +# undef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ + +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. + */ +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. + */ + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. + */ +#define PNG_CONST const /* backward compatibility only */ + +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" +# endif + +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ + +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ +#ifndef PNG_EXPORTA + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args)\ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__ == 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* _MSC_VER */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. + */ +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8 bit bytes" +#endif + +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error "libpng requires a signed 16 bit type" +#endif + +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; +#else +# error "libpng requires an unsigned 16 bit type" +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error "libpng requires a signed 32 bit (or more) type" +#endif + +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32 bit (or more) type" +#endif + +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T +# endif +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; +#endif + +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ + +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +#endif /* PNGCONF_H */ diff --git a/cocos2dx/platform/third_party/common/libpng/pnglibconf.h b/cocos2dx/platform/third_party/common/libpng/pnglibconf.h new file mode 100644 index 0000000000..16ad5c9f02 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libpng/pnglibconf.h @@ -0,0 +1,211 @@ +/* libpng 1.6.2 STANDARD API DEFINITION */ + +/* pnglibconf.h - library build configuration */ + +/* Libpng version 1.6.2 - April 25, 2013 */ + +/* Copyright (c) 1998-2013 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +/*#undef PNG_ARM_NEON_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +/*#undef PNG_SAFE_LIMITS_SUPPORTED*/ +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +/*#undef PNG_SET_OPTION_SUPPORTED*/ +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#define PNG_API_RULE 0 +#define PNG_CALLOC_SUPPORTED +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/cocos2dx/platform/third_party/common/libtiff/tiff.h b/cocos2dx/platform/third_party/common/libtiff/tiff.h new file mode 100644 index 0000000000..19b4e7976d --- /dev/null +++ b/cocos2dx/platform/third_party/common/libtiff/tiff.h @@ -0,0 +1,678 @@ +/* $Id: tiff.h,v 1.68 2012-08-19 16:56:35 bfriesen Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFF_ +#define _TIFF_ + +#include "tiffconf.h" + +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + * + * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) + * + * For BigTIFF design notes see the following links + * http://www.remotesensing.org/libtiff/bigtiffdesign.html + * http://www.awaresystems.be/imaging/tiff/bigtiff.html + */ + +#define TIFF_VERSION_CLASSIC 42 +#define TIFF_VERSION_BIG 43 + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define MDI_LITTLEENDIAN 0x5045 +#define MDI_BIGENDIAN 0x4550 + +/* + * Intrinsic data types required by the file format: + * + * 8-bit quantities int8/uint8 + * 16-bit quantities int16/uint16 + * 32-bit quantities int32/uint32 + * 64-bit quantities int64/uint64 + * strings unsigned char* + */ + +typedef TIFF_INT8_T int8; +typedef TIFF_UINT8_T uint8; + +typedef TIFF_INT16_T int16; +typedef TIFF_UINT16_T uint16; + +typedef TIFF_INT32_T int32; +typedef TIFF_UINT32_T uint32; + +typedef TIFF_INT64_T int64; +typedef TIFF_UINT64_T uint64; + +/* + * Some types as promoted in a variable argument list + * We use uint16_vap rather then directly using int, because this way + * we document the type we actually want to pass through, conceptually, + * rather then confusing the issue by merely stating the type it gets + * promoted to + */ + +typedef int uint16_vap; + +/* + * TIFF header. + */ +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ +} TIFFHeaderCommon; +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ + uint32 tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderClassic; +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ + uint16 tiff_offsetsize; /* size of offsets, should be 8 */ + uint16 tiff_unused; /* unused word, should be 0 */ + uint64 tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderBig; + + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + * - items marked with a & are introduced by Adobe DNG specification. + */ + +/* + * Tag data type information. + * + * Note: RATIONALs are the ratio of two 32-bit integer values. + */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ + TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */ + TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */ + TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */ + TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */ +} TIFFDataType; + +/* + * TIFF Tag Definitions. + */ +#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +#define FILETYPE_PAGE 0x2 /* one page of many */ +#define FILETYPE_MASK 0x4 /* transparency mask */ +#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +#define OFILETYPE_IMAGE 1 /* full resolution image data */ +#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +#define OFILETYPE_PAGE 3 /* one page of many */ +#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +#define TIFFTAG_COMPRESSION 259 /* data compression technique */ +#define COMPRESSION_NONE 1 /* dump mode */ +#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_T85 9 /* !TIFF/FX T.85 JBIG compression */ +#define COMPRESSION_T43 10 /* !TIFF/FX T.43 colour by layered JBIG compression */ +#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define COMPRESSION_LZMA 34925 /* LZMA2 */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define PREDICTOR_NONE 1 /* no prediction scheme used */ +#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */ +#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */ +#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_CLIPPATH 343 /* %ClipPath + [Adobe TIFF technote 2] */ +#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_INDEXED 346 /* %Indexed + [Adobe TIFF Technote 3] */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* Tags 400-435 are from the TIFF/FX spec */ +#define TIFFTAG_GLOBALPARAMETERSIFD 400 /* ! */ +#define TIFFTAG_PROFILETYPE 401 /* ! */ +#define PROFILETYPE_UNSPECIFIED 0 /* ! */ +#define PROFILETYPE_G3_FAX 1 /* ! */ +#define TIFFTAG_FAXPROFILE 402 /* ! */ +#define FAXPROFILE_S 1 /* !TIFF/FX FAX profile S */ +#define FAXPROFILE_F 2 /* !TIFF/FX FAX profile F */ +#define FAXPROFILE_J 3 /* !TIFF/FX FAX profile J */ +#define FAXPROFILE_C 4 /* !TIFF/FX FAX profile C */ +#define FAXPROFILE_L 5 /* !TIFF/FX FAX profile L */ +#define FAXPROFILE_M 6 /* !TIFF/FX FAX profile LM */ +#define TIFFTAG_CODINGMETHODS 403 /* !TIFF/FX coding methods */ +#define CODINGMETHODS_T4_1D (1 << 1) /* !T.4 1D */ +#define CODINGMETHODS_T4_2D (1 << 2) /* !T.4 2D */ +#define CODINGMETHODS_T6 (1 << 3) /* !T.6 */ +#define CODINGMETHODS_T85 (1 << 4) /* !T.85 JBIG */ +#define CODINGMETHODS_T42 (1 << 5) /* !T.42 JPEG */ +#define CODINGMETHODS_T43 (1 << 6) /* !T.43 colour by layered JBIG */ +#define TIFFTAG_VERSIONYEAR 404 /* !TIFF/FX version year */ +#define TIFFTAG_MODENUMBER 405 /* !TIFF/FX mode number */ +#define TIFFTAG_DECODE 433 /* !TIFF/FX decode */ +#define TIFFTAG_IMAGEBASECOLOR 434 /* !TIFF/FX image base colour */ +#define TIFFTAG_T82OPTIONS 435 /* !TIFF/FX T.82 options */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 which specifies a + * revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_STRIPROWCOUNTS 559 /* !TIFF/FX strip row counts */ +#define TIFFTAG_XMLPACKET 700 /* %XML packet + [Adobe XMP Specification, + January 2004 */ +#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID + [Adobe TIFF technote] */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +/* Adobe Digital Negative (DNG) format tags */ +#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model + name */ +#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space + mapping */ +#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for + the BlackLevel tag */ +#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level + differences (columns) */ +#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level + differences (rows) */ +#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding + level */ +#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image + area */ +#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image + area */ +#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space + transformation matrix 1 */ +#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space + transformation matrix 2 */ +#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction + matrix 1 */ +#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction + matrix 2 */ +#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw + values*/ +#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in + linear reference space */ +#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in + x-y chromaticity + coordinates */ +#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero + point */ +#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of + sharpening */ +#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of + the green pixels in the + blue/green rows track the + values of the green pixels + in the red/green rows */ +#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +#define TIFFTAG_LENSINFO 50736 /* info about the lens */ +#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the + camera's anti-alias filter */ +#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote + tag is safe to preserve + along with the rest of the + EXIF data */ +#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for + the raw image data */ +#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original + raw file */ +#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original + raw file */ +#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels + of the sensor */ +#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates + of fully masked pixels */ +#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space + into ICC profile space */ +#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be used to control + * codec-specific functionality. These tags are not written to file. + * Note that these values start at 0xffff+1 so that they'll never + * collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' (i.e. added to + * this file), please post a bug report via the tracking system at + * http://www.remotesensing.org/libtiff/bugs.html with the appropriate + * C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ +#define TIFFTAG_LZMAPRESET 65562 /* LZMA2 preset (compression level) */ +#define TIFFTAG_PERSAMPLE 65563 /* interface for per sample tags */ +#define PERSAMPLE_MERGED 0 /* present as a single value */ +#define PERSAMPLE_MULTI 1 /* present as multiple values */ + +/* + * EXIF tags + */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define EXIFTAG_OECF 34856 /* Optoelectric conversion + factor */ +#define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original + data generation */ +#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital + data generation */ +#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +#define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +#define EXIFTAG_FLASH 37385 /* Flash */ +#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define EXIFTAG_USERCOMMENT 37510 /* User comments */ +#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +#define EXIFTAG_COLORSPACE 40961 /* Color space information */ +#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +#define EXIFTAG_FILESOURCE 41728 /* File source */ +#define EXIFTAG_SCENETYPE 41729 /* Scene type */ +#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +#define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_CONTRAST 41992 /* Contrast */ +#define EXIFTAG_SATURATION 41993 /* Saturation */ +#define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + +#endif /* _TIFF_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/cocos2dx/platform/third_party/common/libtiff/tiffconf.h b/cocos2dx/platform/third_party/common/libtiff/tiffconf.h new file mode 100644 index 0000000000..4c48378446 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libtiff/tiffconf.h @@ -0,0 +1,128 @@ +/* libtiff/tiffconf.h. Generated from tiffconf.h.in by configure. */ +/* + Configuration defines for installed libtiff. + This file maintained for backward compatibility. Do not use definitions + from this file in your programs. +*/ + +#ifndef _TIFFCONF_ +#define _TIFFCONF_ + +/* Signed 16-bit type */ +#define TIFF_INT16_T signed short + +/* Signed 32-bit type */ +#define TIFF_INT32_T signed int + +/* Signed 64-bit type */ +#define TIFF_INT64_T signed long long + +/* Signed 8-bit type */ +#define TIFF_INT8_T signed char + +/* Unsigned 16-bit type */ +#define TIFF_UINT16_T unsigned short + +/* Unsigned 32-bit type */ +#define TIFF_UINT32_T unsigned int + +/* Unsigned 64-bit type */ +#define TIFF_UINT64_T unsigned long long + +/* Unsigned 8-bit type */ +#define TIFF_UINT8_T unsigned char + +/* Signed size type */ +#define TIFF_SSIZE_T signed long + +/* Pointer difference type */ +#define TIFF_PTRDIFF_T ptrdiff_t + +/* Define to 1 if the system has the type `int16'. */ +/* #undef HAVE_INT16 */ + +/* Define to 1 if the system has the type `int32'. */ +/* #undef HAVE_INT32 */ + +/* Define to 1 if the system has the type `int8'. */ +/* #undef HAVE_INT8 */ + +/* Compatibility stuff. */ + +/* Define as 0 or 1 according to the floating point format suported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ +#define HOST_BIGENDIAN 0 + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Support JPEG compression (requires IJG JPEG library) */ +/* #undef JPEG_SUPPORT */ + +/* Support JBIG compression (requires JBIG-KIT library) */ +/* #undef JBIG_SUPPORT */ + +/* Support LogLuv high dynamic range encoding */ +#define LOGLUV_SUPPORT 1 + +/* Support LZW algorithm */ +#define LZW_SUPPORT 1 + +/* Support NeXT 2-bit RLE algorithm */ +#define NEXT_SUPPORT 1 + +/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation + fails with unpatched IJG JPEG library) */ +/* #undef OJPEG_SUPPORT */ + +/* Support Macintosh PackBits algorithm */ +#define PACKBITS_SUPPORT 1 + +/* Support Pixar log-format algorithm (requires Zlib) */ +#define PIXARLOG_SUPPORT 1 + +/* Support ThunderScan 4-bit RLE algorithm */ +#define THUNDER_SUPPORT 1 + +/* Support Deflate compression */ +#define ZIP_SUPPORT 1 + +/* Support strip chopping (whether or not to convert single-strip uncompressed + images to mutiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */ +#define SUBIFD_SUPPORT 1 + +/* Treat extra sample as alpha (default enabled). The RGBA interface will + treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many + packages produce RGBA files but don't mark the alpha properly. */ +#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* Support MS MDI magic number files as TIFF */ +#define MDI_SUPPORT 1 + +/* + * Feature support definitions. + * XXX: These macros are obsoleted. Don't use them in your apps! + * Macros stays here for backward compatibility and should be always defined. + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT + +#endif /* _TIFFCONF_ */ diff --git a/cocos2dx/platform/third_party/common/libtiff/tiffio.h b/cocos2dx/platform/third_party/common/libtiff/tiffio.h new file mode 100644 index 0000000000..038b67013f --- /dev/null +++ b/cocos2dx/platform/third_party/common/libtiff/tiffio.h @@ -0,0 +1,557 @@ +/* $Id: tiffio.h,v 1.91 2012-07-29 15:45:29 tgl Exp $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets, and BigTIFF maxes out at 64-bit + * offsets being the most important, and to ensure use of + * a consistently unsigned type across architectures. + * Prior to libtiff 4.0, this was an unsigned 32 bit type. + */ +/* + * this is the machine addressing size type, only it's signed, so make it + * int32 on 32bit machines, int64 on 64bit machines + */ +typedef TIFF_SSIZE_T tmsize_t; +typedef uint64 toff_t; /* file offset */ +/* the following are deprecated and should be replaced by their defining + counterparts */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrile_t; /* strip or tile number */ +typedef tstrile_t tstrip_t; /* strip number */ +typedef tstrile_t ttile_t; /* tile number */ +typedef tmsize_t tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_unix.c is assumed. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define AVOID_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32 d_Vrwr; /* Pixel values for ref. white */ + uint32 d_Vrwg; + uint32 d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + int32* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 req_orientation; /* requested orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + /* put decoded strip/tile */ + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + uint8* UaToAa; /* Unassociated alpha to associated alpha convertion LUT */ + uint8* Bitdepth16To8; /* LUT for conversion from 16bit to 8bit values */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if !defined(__GNUC__) && !defined(__attribute__) +# define __attribute__(x) /*nothing*/ +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size); +typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern void* _TIFFmalloc(tmsize_t s); +extern void* _TIFFrealloc(void* p, tmsize_t s); +extern void _TIFFmemset(void* p, int v, tmsize_t c); +extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c); +extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c); +extern void _TIFFfree(void* p); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern uint32 TIFFGetTagListEntry( TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct _TIFFField TIFFField; +typedef struct _TIFFFieldArray TIFFFieldArray; + +extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType); +extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32); +extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); + +extern uint32 TIFFFieldTag(const TIFFField*); +extern const char* TIFFFieldName(const TIFFField*); +extern TIFFDataType TIFFFieldDataType(const TIFFField*); +extern int TIFFFieldPassCount(const TIFFField*); +extern int TIFFFieldReadCount(const TIFFField*); +extern int TIFFFieldWriteCount(const TIFFField*); + +typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, uint32, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods(TIFF *); +extern void *TIFFGetClientInfo(TIFF *, const char *); +extern void TIFFSetClientInfo(TIFF *, void *, const char *); + +extern void TIFFCleanup(TIFF* tif); +extern void TIFFClose(TIFF* tif); +extern int TIFFFlush(TIFF* tif); +extern int TIFFFlushData(TIFF* tif); +extern int TIFFGetField(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...); +extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 tag, va_list ap); +extern int TIFFReadDirectory(TIFF* tif); +extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray); +extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff); +extern uint64 TIFFScanlineSize64(TIFF* tif); +extern tmsize_t TIFFScanlineSize(TIFF* tif); +extern uint64 TIFFRasterScanlineSize64(TIFF* tif); +extern tmsize_t TIFFRasterScanlineSize(TIFF* tif); +extern uint64 TIFFStripSize64(TIFF* tif); +extern tmsize_t TIFFStripSize(TIFF* tif); +extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip); +extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip); +extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows); +extern uint64 TIFFTileRowSize64(TIFF* tif); +extern tmsize_t TIFFTileRowSize(TIFF* tif); +extern uint64 TIFFTileSize64(TIFF* tif); +extern tmsize_t TIFFTileSize(TIFF* tif); +extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows); +extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows); +extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern uint16 TIFFCurrentDirectory(TIFF*); +extern uint16 TIFFNumberOfDirectories(TIFF*); +extern uint64 TIFFCurrentDirOffset(TIFF*); +extern uint32 TIFFCurrentStrip(TIFF*); +extern uint32 TIFFCurrentTile(TIFF* tif); +extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFCreateCustomDirectory(TIFF*,const TIFFFieldArray*); +extern int TIFFCreateEXIFDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, uint16); +extern int TIFFSetSubDirectory(TIFF*, uint64); +extern int TIFFUnlinkDirectory(TIFF*, uint16); +extern int TIFFSetField(TIFF*, uint32, ...); +extern int TIFFVSetField(TIFF*, uint32, va_list); +extern int TIFFUnsetField(TIFF*, uint32); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFWriteCustomDirectory(TIFF *, uint64 *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, uint32, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void TIFFError(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3))); +extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4))); +extern void TIFFWarning(const char*, const char*, ...) __attribute__((__format__ (__printf__,2,3))); +extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((__format__ (__printf__,3,4))); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFNumberOfTiles(TIFF*); +extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s); +extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16); +extern uint32 TIFFNumberOfStrips(TIFF*); +extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size); +extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF* tif, toff_t off); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabLong8(uint64*); +extern void TIFFSwabFloat(float*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n); +extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n); +extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n); +extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n); +extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n); +extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); +extern void TIFFReverseBits(uint8* cp, tmsize_t n); +extern const unsigned char* TIFFGetBitRevTable(int); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32, float*); +extern void LogLuv32toXYZ(uint32, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32 LogLuv24fromXYZ(float*, int); +extern uint32 LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32 *, uint32 *, uint32 *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, + uint32 *, uint32 *, uint32 *); + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/cocos2dx/platform/third_party/common/libtiff/tiffvers.h b/cocos2dx/platform/third_party/common/libtiff/tiffvers.h new file mode 100644 index 0000000000..40edc813d5 --- /dev/null +++ b/cocos2dx/platform/third_party/common/libtiff/tiffvers.h @@ -0,0 +1,9 @@ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.3\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 20120922 diff --git a/cocos2dx/platform/third_party/ios/libraries/libjpeg.a.REMOVED.git-id b/cocos2dx/platform/third_party/ios/libraries/libjpeg.a.REMOVED.git-id new file mode 100644 index 0000000000..dcdc5912f8 --- /dev/null +++ b/cocos2dx/platform/third_party/ios/libraries/libjpeg.a.REMOVED.git-id @@ -0,0 +1 @@ +9e3629f0bc6e96d4af5aea9a20446e4f9b5ca6d0 \ No newline at end of file diff --git a/cocos2dx/platform/third_party/ios/libraries/libpng.a.REMOVED.git-id b/cocos2dx/platform/third_party/ios/libraries/libpng.a.REMOVED.git-id new file mode 100644 index 0000000000..adbc13a75d --- /dev/null +++ b/cocos2dx/platform/third_party/ios/libraries/libpng.a.REMOVED.git-id @@ -0,0 +1 @@ +2a8128e7d552dc8b2d79c1cbd8c84c21ad578672 \ No newline at end of file diff --git a/cocos2dx/platform/third_party/ios/libraries/libtiff.a.REMOVED.git-id b/cocos2dx/platform/third_party/ios/libraries/libtiff.a.REMOVED.git-id new file mode 100644 index 0000000000..1305bb3f84 --- /dev/null +++ b/cocos2dx/platform/third_party/ios/libraries/libtiff.a.REMOVED.git-id @@ -0,0 +1 @@ +60433133a48054eb884d9e6a0cee95fe4ba22b1c \ No newline at end of file diff --git a/cocos2dx/platform/third_party/mac/libraries/libjpeg.a.REMOVED.git-id b/cocos2dx/platform/third_party/mac/libraries/libjpeg.a.REMOVED.git-id new file mode 100644 index 0000000000..6f2cccd4ea --- /dev/null +++ b/cocos2dx/platform/third_party/mac/libraries/libjpeg.a.REMOVED.git-id @@ -0,0 +1 @@ +31b08ad941b4c313ae9996e4ba8bee4837f8bccb \ No newline at end of file diff --git a/cocos2dx/platform/third_party/mac/libraries/libpng.a.REMOVED.git-id b/cocos2dx/platform/third_party/mac/libraries/libpng.a.REMOVED.git-id new file mode 100644 index 0000000000..9d858ddb88 --- /dev/null +++ b/cocos2dx/platform/third_party/mac/libraries/libpng.a.REMOVED.git-id @@ -0,0 +1 @@ +fb78024e2f81c33d196af83e7740de7c7f4ea021 \ No newline at end of file diff --git a/cocos2dx/platform/third_party/mac/libraries/libtiff.a.REMOVED.git-id b/cocos2dx/platform/third_party/mac/libraries/libtiff.a.REMOVED.git-id new file mode 100644 index 0000000000..4cc30a45bb --- /dev/null +++ b/cocos2dx/platform/third_party/mac/libraries/libtiff.a.REMOVED.git-id @@ -0,0 +1 @@ +5fe8aca7e0bfa91c79b4b6b0a562f88a6653c452 \ No newline at end of file diff --git a/cocos2dx/platform/third_party/mac/libraries/libwebp.a.REMOVED.git-id b/cocos2dx/platform/third_party/mac/libraries/libwebp.a.REMOVED.git-id index 57cce30b7a..7a441fa135 100644 --- a/cocos2dx/platform/third_party/mac/libraries/libwebp.a.REMOVED.git-id +++ b/cocos2dx/platform/third_party/mac/libraries/libwebp.a.REMOVED.git-id @@ -1 +1 @@ -98a9f91fff796092bb7afab1f50fb11c3fe696d9 \ No newline at end of file +4c5c7d34a90f5fcac954f6d44803173224d8ead2 \ No newline at end of file diff --git a/cocos2dx/platform/tizen/CCImage.cpp b/cocos2dx/platform/tizen/CCImage.cpp index fc9af7ad3a..a080e2bef0 100644 --- a/cocos2dx/platform/tizen/CCImage.cpp +++ b/cocos2dx/platform/tizen/CCImage.cpp @@ -244,7 +244,7 @@ public: int lineWidth = textLines.at(line).lineWidth; if (eAlignMask == Image::TextAlign::CENTER || eAlignMask == Image::TextAlign::TOP || eAlignMask == Image::TextAlign::BOTTOM) { return (iMaxLineWidth - lineWidth) / 2; - } else if (eAlignMask == Image::TextAlign::RIGHT || eAlignMask == Image::TextAlign::TO_RIGHT || eAlignMask == Image::TextAlign::BOTTOM_RIGHT) { + } else if (eAlignMask == Image::TextAlign::RIGHT || eAlignMask == Image::TextAlign::TOP_RIGHT || eAlignMask == Image::TextAlign::BOTTOM_RIGHT) { return (iMaxLineWidth - lineWidth); } @@ -428,7 +428,7 @@ bool Image::initWithString( const char * pText, int nWidth/* = 0*/, int nHeight/* = 0*/, - ETextAlign eAlignMask/* = kAlignCenter*/, + TextAlign eAlignMask/* = kAlignCenter*/, const char * pFontName/* = nil*/, int nSize/* = 0*/) { @@ -449,9 +449,8 @@ bool Image::initWithString( _width = (short)dc.iMaxLineWidth; _height = (short)dc.iMaxLineHeight; - _hasAlpha = true; _preMulti = true; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; bRet = true; diff --git a/cocos2dx/platform/win32/CCFileUtilsWin32.cpp b/cocos2dx/platform/win32/CCFileUtilsWin32.cpp index 460e2400df..627747ecad 100644 --- a/cocos2dx/platform/win32/CCFileUtilsWin32.cpp +++ b/cocos2dx/platform/win32/CCFileUtilsWin32.cpp @@ -43,6 +43,36 @@ static void _checkPath() } } +// D:/aaa/bbb/ccc/ddd/abc.txt --> D:\aaa\bbb\ccc\ddd\abc.txt +static inline std::string convertPathFormatToWindowStyle(const std::string& path) +{ + std::string ret = path; + int len = ret.length(); + for (int i = 0; i < len; ++i) + { + if (ret[i] == '/') + { + ret[i] = '\\'; + } + } + return ret; +} + +// D:\aaa\bbb\ccc\ddd\abc.txt --> D:/aaa/bbb/ccc/ddd/abc.txt +static inline std::string convertPathFormatToUnixStyle(const std::string& path) +{ + std::string ret = path; + int len = ret.length(); + for (int i = 0; i < len; ++i) + { + if (ret[i] == '\\') + { + ret[i] = '/'; + } + } + return ret; +} + FileUtils* FileUtils::getInstance() { if (s_sharedFileUtils == NULL) @@ -81,7 +111,12 @@ bool FileUtilsWin32::isFileExist(const std::string& strFilePath) { // Not absolute path, add the default root path at the beginning. strPath.insert(0, _defaultResRootPath); } - return GetFileAttributesA(strPath.c_str()) != -1 ? true : false; + + convertPathFormatToWindowStyle(strPath); + WCHAR wszBuf[MAX_PATH] = {0}; + MultiByteToWideChar(CP_UTF8, 0, strPath.c_str(), -1, wszBuf, sizeof(wszBuf)); + + return GetFileAttributesW(wszBuf) != -1 ? true : false; } bool FileUtilsWin32::isAbsolutePath(const std::string& strPath) @@ -95,6 +130,68 @@ bool FileUtilsWin32::isAbsolutePath(const std::string& strPath) return false; } +unsigned char* FileUtilsWin32::getFileData(const char* filename, const char* mode, unsigned long* size) +{ + unsigned char * pBuffer = NULL; + CCASSERT(filename != NULL && size != NULL && mode != NULL, "Invalid parameters."); + *size = 0; + do + { + // read the file from hardware + std::string fullPath = fullPathForFilename(filename); + + WCHAR wszBuf[MAX_PATH] = {0}; + MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, wszBuf, sizeof(wszBuf)); + + + HANDLE fileHandle = ::CreateFileW(wszBuf, GENERIC_READ, 0, NULL, OPEN_EXISTING, NULL, NULL); + CC_BREAK_IF(fileHandle == INVALID_HANDLE_VALUE); + + *size = ::GetFileSize(fileHandle, NULL); + + pBuffer = new unsigned char[*size]; + DWORD sizeRead = 0; + BOOL successed = FALSE; + successed = ::ReadFile(fileHandle, pBuffer, *size, &sizeRead, NULL); + ::CloseHandle(fileHandle); + + if (!successed) + { + CC_SAFE_DELETE_ARRAY(pBuffer); + } + } while (0); + + if (! pBuffer) + { + std::string msg = "Get data from file("; + // Gets error code. + DWORD errorCode = ::GetLastError(); + char errorCodeBuffer[20] = {0}; + snprintf(errorCodeBuffer, sizeof(errorCodeBuffer), "%d", errorCode); + + msg = msg + filename + ") failed, error code is " + errorCodeBuffer; + CCLOG("%s", msg.c_str()); + } + return pBuffer; +} + +std::string FileUtilsWin32::getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath) +{ + std::string unixFileName = convertPathFormatToUnixStyle(filename); + std::string unixResolutionDirector = convertPathFormatToUnixStyle(resolutionDirectory); + std::string unixSearchPath = convertPathFormatToUnixStyle(searchPath); + + return FileUtils::getPathForFilename(unixFileName, unixResolutionDirector, unixSearchPath); +} + +std::string FileUtilsWin32::getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) +{ + std::string dosDirectory = convertPathFormatToWindowStyle(strDirectory); + std::string dosFilename = convertPathFormatToWindowStyle(strFilename); + + return FileUtils::getFullPathForDirectoryAndFilename(dosDirectory, dosFilename); +} + string FileUtilsWin32::getWritablePath() { // Get full path of executable, e.g. c:\Program Files (x86)\My Game Folder\MyGame.exe diff --git a/cocos2dx/platform/win32/CCFileUtilsWin32.h b/cocos2dx/platform/win32/CCFileUtilsWin32.h index 3dc975a559..38656cf7f2 100644 --- a/cocos2dx/platform/win32/CCFileUtilsWin32.h +++ b/cocos2dx/platform/win32/CCFileUtilsWin32.h @@ -49,6 +49,39 @@ public: virtual std::string getWritablePath(); virtual bool isFileExist(const std::string& strFilePath); virtual bool isAbsolutePath(const std::string& strPath); +protected: + /** + * Gets resource file data + * + * @param[in] filename The resource file name which contains the path. + * @param[in] pszMode The read mode of the file. + * @param[out] pSize If the file read operation succeeds, it will be the data size, otherwise 0. + * @return Upon success, a pointer to the data is returned, otherwise NULL. + * @warning Recall: you are responsible for calling delete[] on any Non-NULL pointer returned. + */ + virtual unsigned char* getFileData(const char* filename, const char* mode, unsigned long * size) override; + + /** + * Gets full path for filename, resolution directory and search path. + * + * @param filename The file name. + * @param resolutionDirectory The resolution directory. + * @param searchPath The search path. + * @return The full path of the file. It will return an empty string if the full path of the file doesn't exist. + */ + virtual std::string getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath) override; + + /** + * Gets full path for the directory and the filename. + * + * @note Only iOS and Mac need to override this method since they are using + * `[[NSBundle mainBundle] pathForResource: ofType: inDirectory:]` to make a full path. + * Other platforms will use the default implementation of this method. + * @param strDirectory The directory contains the file we are looking for. + * @param strFilename The name of the file. + * @return The full path of the file, if the file can't be found, it will return an empty string. + */ + virtual std::string getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename) override; }; // end of platform group diff --git a/cocos2dx/platform/win32/CCImage.cpp b/cocos2dx/platform/win32/CCImage.cpp index 15d3e2aae5..a5d4d68a21 100644 --- a/cocos2dx/platform/win32/CCImage.cpp +++ b/cocos2dx/platform/win32/CCImage.cpp @@ -390,7 +390,8 @@ bool Image::initWithString( SIZE size = {nWidth, nHeight}; CC_BREAK_IF(! dc.drawText(pText, size, eAlignMask)); - _data = new unsigned char[size.cx * size.cy * 4]; + _dataLen = size.cx * size.cy * 4; + _data = new unsigned char[_dataLen]; CC_BREAK_IF(! _data); struct @@ -404,9 +405,8 @@ bool Image::initWithString( _width = (short)size.cx; _height = (short)size.cy; - _hasAlpha = true; _preMulti = false; - _bitsPerComponent = 8; + _renderFormat = Texture2D::PixelFormat::RGBA8888; // copy pixed data bi.bmiHeader.biHeight = (bi.bmiHeader.biHeight > 0) ? - bi.bmiHeader.biHeight : bi.bmiHeader.biHeight; diff --git a/cocos2dx/platform/win32/CCStdC.h b/cocos2dx/platform/win32/CCStdC.h index 6a5ea87393..a361e5b056 100644 --- a/cocos2dx/platform/win32/CCStdC.h +++ b/cocos2dx/platform/win32/CCStdC.h @@ -109,6 +109,11 @@ NS_CC_END #undef RELATIVE #endif +// Conflicted with CCBReader::SizeType::RELATIVE and CCBReader::ScaleType::RELATIVE, so we need to undef it. +#ifdef ABSOLUTE +#undef ABSOLUTE +#endif + // Conflicted with HttpRequest::Type::DELETE, so we need to undef it. #ifdef DELETE #undef DELETE diff --git a/cocos2dx/proj.emscripten/Makefile b/cocos2dx/proj.emscripten/Makefile index 50987c8847..b82b0be2ad 100644 --- a/cocos2dx/proj.emscripten/Makefile +++ b/cocos2dx/proj.emscripten/Makefile @@ -46,6 +46,7 @@ SOURCES = ../actions/CCAction.cpp \ ../effects/CCGrid.cpp \ ../keypad_dispatcher/CCKeypadDelegate.cpp \ ../keypad_dispatcher/CCKeypadDispatcher.cpp \ +../keyboard_dispatcher/CCKeyboardDispatcher.cpp \ ../label_nodes/CCLabelAtlas.cpp \ ../label_nodes/CCLabelBMFont.cpp \ ../label_nodes/CCLabelTTF.cpp \ @@ -66,7 +67,6 @@ SOURCES = ../actions/CCAction.cpp \ ../particle_nodes/CCParticleBatchNode.cpp \ ../platform/CCSAXParser.cpp \ ../platform/CCThread.cpp \ -../platform/platform.cpp \ ../platform/CCImageCommonWebp.cpp \ ../platform/CCEGLViewProtocol.cpp \ ../platform/CCFileUtils.cpp \ diff --git a/cocos2dx/proj.emscripten/cocos2dx.mk b/cocos2dx/proj.emscripten/cocos2dx.mk index b6893beeea..397dd1aaeb 100644 --- a/cocos2dx/proj.emscripten/cocos2dx.mk +++ b/cocos2dx/proj.emscripten/cocos2dx.mk @@ -1,6 +1,6 @@ all: -DEFINES += -DEMSCRIPTEN +DEFINES += -DEMSCRIPTEN -DCC_KEYBOARD_SUPPORT THIS_MAKEFILE := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) ifndef COCOS_ROOT @@ -52,8 +52,8 @@ LBITS := $(shell getconf LONG_BIT) INCLUDES += -I$(COCOS_SRC)/platform/third_party/linux ifeq ($(DEBUG), 1) -CCFLAGS += -O0 -s ASSERTIONS=1 -s SAFE_HEAP=1 --jcache -s GL_UNSAFE_OPTS=0 -CXXFLAGS += -O0 -s ASSERTIONS=1 -s SAFE_HEAP=1 --jcache -s GL_UNSAFE_OPTS=0 +CCFLAGS += -O0 -s ASSERTIONS=1 -s SAFE_HEAP=1 --jcache -s GL_UNSAFE_OPTS=0 -g +CXXFLAGS += -O0 -s ASSERTIONS=1 -s SAFE_HEAP=1 --jcache -s GL_UNSAFE_OPTS=0 -g DEFINES += -D_DEBUG -DCOCOS2D_DEBUG=1 -DCP_USE_DOUBLES=0 OBJ_DIR := $(OBJ_DIR)/debug LIB_DIR := $(LIB_DIR)/debug diff --git a/cocos2dx/proj.linux/Makefile b/cocos2dx/proj.linux/Makefile index d1d6b249a3..7c13f789cd 100644 --- a/cocos2dx/proj.linux/Makefile +++ b/cocos2dx/proj.linux/Makefile @@ -2,6 +2,7 @@ TARGET = libcocos2d.so INCLUDES += \ -I../platform/third_party/linux/libfreetype2 \ + -I../platform/third_party/common/etc \ -I../../extensions \ -I../../extensions/CCBReader \ -I../../extensions/GUI/CCControlExtension \ @@ -63,7 +64,6 @@ SOURCES = ../actions/CCAction.cpp \ ../particle_nodes/CCParticleBatchNode.cpp \ ../platform/CCSAXParser.cpp \ ../platform/CCThread.cpp \ -../platform/CCImageCommonWebp.cpp \ ../platform/CCEGLViewProtocol.cpp \ ../platform/CCFileUtils.cpp \ ../platform/linux/CCStdC.cpp \ @@ -73,6 +73,7 @@ SOURCES = ../actions/CCAction.cpp \ ../platform/linux/CCEGLView.cpp \ ../platform/linux/CCImage.cpp \ ../platform/linux/CCDevice.cpp \ +../platform/third_party/common/etc/etc1.cpp \ ../script_support/CCScriptSupport.cpp \ ../sprite_nodes/CCAnimation.cpp \ ../sprite_nodes/CCAnimationCache.cpp \ @@ -101,9 +102,6 @@ SOURCES = ../actions/CCAction.cpp \ ../textures/CCTexture2D.cpp \ ../textures/CCTextureAtlas.cpp \ ../textures/CCTextureCache.cpp \ -../textures/CCTextureETC.cpp \ -../textures/CCTexturePVR.cpp \ -../textures/etc/etc1.cpp\ ../tilemap_parallax_nodes/CCParallaxNode.cpp \ ../tilemap_parallax_nodes/CCTMXLayer.cpp \ ../tilemap_parallax_nodes/CCTMXObjectGroup.cpp \ diff --git a/cocos2dx/proj.linux/cocos2dx.mk b/cocos2dx/proj.linux/cocos2dx.mk index bb1b98d495..af47b4767c 100644 --- a/cocos2dx/proj.linux/cocos2dx.mk +++ b/cocos2dx/proj.linux/cocos2dx.mk @@ -1,14 +1,36 @@ +################################################################################ +# +# LINUX MAKEFILE +# +# Available options are: +# - CLANG=1 : Compiles with clang instead of gcc. Clang must be in your PATH. +# - V=1 : Enables the verbose mode. +# - DEBUG=1 : Enables the debug mode, disable compiler optimizations. +# - OPENAL=1 : Uses OpenAL instead of FMOD as sound engine. +# +################################################################################ + all: -CC = gcc -CXX = g++ # Remove -Wall, because it enables -Wunused-function, and this warning exists in webp.h # when enable c++11. I don't know why. # GCC 4.6 is primary platform for cocos2d v.3, because it's default compiler for Android, # Blackberry, some Linux distributions.It supports all important features of c++11, but have # no flag "-std=c++11" (which was turned on in version 4.7). -CCFLAGS += -MMD -Werror -Wno-deprecated-declarations -fPIC -CXXFLAGS += -MMD -Werror -Wno-deprecated-declarations -fPIC -std=gnu++0x +CCFLAGS += -MMD -Wno-deprecated-declarations -fPIC +CXXFLAGS += -MMD -Wno-deprecated-declarations -fPIC -std=gnu++0x + +ifeq ($(CLANG), 1) +CC := clang +CXX := clang++ +DEFINES += -D__STRICT_ANSI__ # Allows clang 3.3 to use __float128 +else +CC = gcc +CXX = g++ +CCFLAGS += -Werror +CXXFLAGS += -Werror +endif + ARFLAGS = cr DEFINES += -DLINUX -DCC_KEYBOARD_SUPPORT @@ -100,7 +122,7 @@ SHAREDLIBS += -lfmodex endif endif -SHAREDLIBS += -lglfw -lGLEW -lfontconfig -lpthread -lGL +SHAREDLIBS += -lSDL2 -lGLEW -lfontconfig -lpthread -lGL SHAREDLIBS += -L$(FMOD_LIBDIR) -Wl,-rpath,$(abspath $(FMOD_LIBDIR)) SHAREDLIBS += -L$(LIB_DIR) -Wl,-rpath,$(abspath $(LIB_DIR)) diff --git a/cocos2dx/proj.qt5/cocos2dx.pro b/cocos2dx/proj.qt5/cocos2dx.pro new file mode 100644 index 0000000000..1cfe811dfb --- /dev/null +++ b/cocos2dx/proj.qt5/cocos2dx.pro @@ -0,0 +1,166 @@ + +include(common.pri) + +TEMPLATE = lib + +# Uncomment the following line to build Cocos2D-X as static library +#CONFIG += static + +LIBS += $${COCOS2DX_SYSTEM_LIBS} + +#SOURCES += $$files(../Collision/*.cpp) + +SOURCES += ../actions/CCAction.cpp \ +../actions/CCActionCamera.cpp \ +../actions/CCActionEase.cpp \ +../actions/CCActionGrid.cpp \ +../actions/CCActionGrid3D.cpp \ +../actions/CCActionInstant.cpp \ +../actions/CCActionInterval.cpp \ +../actions/CCActionManager.cpp \ +../actions/CCActionPageTurn3D.cpp \ +../actions/CCActionProgressTimer.cpp \ +../actions/CCActionTiledGrid.cpp \ +../actions/CCActionCatmullRom.cpp \ +../actions/CCActionTween.cpp \ +../base_nodes/CCAtlasNode.cpp \ +../base_nodes/CCNode.cpp \ +../cocoa/CCAffineTransform.cpp \ +../cocoa/CCAutoreleasePool.cpp \ +../cocoa/CCGeometry.cpp \ +../cocoa/CCNS.cpp \ +../cocoa/CCObject.cpp \ +../cocoa/CCSet.cpp \ +../cocoa/CCArray.cpp \ +../cocoa/CCDictionary.cpp \ +../cocoa/CCString.cpp \ +../cocoa/CCDataVisitor.cpp \ +../cocoa/CCData.cpp \ +../draw_nodes/CCDrawingPrimitives.cpp \ +../draw_nodes/CCDrawNode.cpp \ +../effects/CCGrabber.cpp \ +../effects/CCGrid.cpp \ +../keypad_dispatcher/CCKeypadDelegate.cpp \ +../keypad_dispatcher/CCKeypadDispatcher.cpp \ +../keyboard_dispatcher/CCKeyboardDispatcher.cpp \ +../label_nodes/CCLabelAtlas.cpp \ +../label_nodes/CCLabelBMFont.cpp \ +../label_nodes/CCLabelTTF.cpp \ +../layers_scenes_transitions_nodes/CCLayer.cpp \ +../layers_scenes_transitions_nodes/CCScene.cpp \ +../layers_scenes_transitions_nodes/CCTransition.cpp \ +../layers_scenes_transitions_nodes/CCTransitionPageTurn.cpp \ +../layers_scenes_transitions_nodes/CCTransitionProgress.cpp \ +../menu_nodes/CCMenu.cpp \ +../menu_nodes/CCMenuItem.cpp \ +../misc_nodes/CCMotionStreak.cpp \ +../misc_nodes/CCProgressTimer.cpp \ +../misc_nodes/CCClippingNode.cpp \ +../misc_nodes/CCRenderTexture.cpp \ +../particle_nodes/CCParticleExamples.cpp \ +../particle_nodes/CCParticleSystem.cpp \ +../particle_nodes/CCParticleSystemQuad.cpp \ +../particle_nodes/CCParticleBatchNode.cpp \ +../platform/CCSAXParser.cpp \ +../platform/CCThread.cpp \ +../platform/CCImageCommonWebp.cpp \ +../platform/CCEGLViewProtocol.cpp \ +../platform/CCFileUtils.cpp \ +../platform/qt5/CCCommon.cpp \ +../platform/qt5/CCFileUtilsQt5.cpp \ +../platform/qt5/CCEGLView.cpp \ +../platform/qt5/CCDevice.cpp \ +../platform/qt5/CCApplication.cpp \ +../platform/qt5/CCAccelerometer.cpp \ +../platform/qt5/AccelerometerListener.cpp \ +../platform/linux/CCImage.cpp \ +../script_support/CCScriptSupport.cpp \ +../sprite_nodes/CCAnimation.cpp \ +../sprite_nodes/CCAnimationCache.cpp \ +../sprite_nodes/CCSprite.cpp \ +../sprite_nodes/CCSpriteBatchNode.cpp \ +../sprite_nodes/CCSpriteFrame.cpp \ +../sprite_nodes/CCSpriteFrameCache.cpp \ +../support/ccUTF8.cpp \ +../support/CCProfiling.cpp \ +../support/user_default/CCUserDefault.cpp \ +../support/TransformUtils.cpp \ +../support/base64.cpp \ +../support/ccUtils.cpp \ +../support/CCVertex.cpp \ +../support/CCNotificationCenter.cpp \ +../support/image_support/TGAlib.cpp \ +../support/tinyxml2/tinyxml2.cpp \ +../support/zip_support/ZipUtils.cpp \ +../support/zip_support/ioapi.cpp \ +../support/zip_support/unzip.cpp \ +../support/data_support/ccCArray.cpp \ +../support/component/CCComponent.cpp \ +../support/component/CCComponentContainer.cpp \ +../text_input_node/CCIMEDispatcher.cpp \ +../text_input_node/CCTextFieldTTF.cpp \ +../textures/CCTexture2D.cpp \ +../textures/CCTextureAtlas.cpp \ +../textures/CCTextureCache.cpp \ +../textures/CCTextureETC.cpp \ +../textures/CCTexturePVR.cpp \ +../textures/etc/etc1.cpp \ +../tilemap_parallax_nodes/CCParallaxNode.cpp \ +../tilemap_parallax_nodes/CCTMXLayer.cpp \ +../tilemap_parallax_nodes/CCTMXObjectGroup.cpp \ +../tilemap_parallax_nodes/CCTMXTiledMap.cpp \ +../tilemap_parallax_nodes/CCTMXXMLParser.cpp \ +../tilemap_parallax_nodes/CCTileMapAtlas.cpp \ +../touch_dispatcher/CCTouchDispatcher.cpp \ +../touch_dispatcher/CCTouchHandler.cpp \ +../touch_dispatcher/CCTouch.cpp \ +../shaders/CCGLProgram.cpp \ +../shaders/ccGLStateCache.cpp \ +../shaders/CCShaderCache.cpp \ +../shaders/ccShaders.cpp \ +../kazmath/src/aabb.c \ +../kazmath/src/plane.c \ +../kazmath/src/vec2.c \ +../kazmath/src/mat3.c \ +../kazmath/src/quaternion.c \ +../kazmath/src/vec3.c \ +../kazmath/src/mat4.c \ +../kazmath/src/ray2.c \ +../kazmath/src/vec4.c \ +../kazmath/src/neon_matrix_impl.c \ +../kazmath/src/utility.c \ +../kazmath/src/GL/mat4stack.c \ +../kazmath/src/GL/matrix.c \ +../CCCamera.cpp \ +../CCConfiguration.cpp \ +../CCDirector.cpp \ +../CCScheduler.cpp \ +../ccFPSImages.c \ +../ccTypes.cpp \ +../cocos2d.cpp + +# Headers with QObject subclasses (will be processed by moc) +HEADERS += ../platform/qt5/AccelerometerListener.h + +# WebP +INCLUDEPATH += ../../external/libwebp/webp +SOURCES += $$files(../../external/libwebp/dec/*.c) +SOURCES += $$files(../../external/libwebp/dsp/*.c) +SOURCES += $$files(../../external/libwebp/utils/*.c) + +# FreeType (FIXME: use pkg-config) +INCLUDEPATH += /usr/include/freetype2 + +INCLUDEPATH += ../../extensions +INCLUDEPATH += ../../extensions/CCBReader +INCLUDEPATH += ../../extensions/GUI/CCControlExtension +INCLUDEPATH += ../../extensions/GUI/CCControlExtension +INCLUDEPATH += ../../external/chipmunk/include/chipmunk +INCLUDEPATH += ../../extensions/network +INCLUDEPATH += ../../extensions/Components + +TARGET = $${LIB_OUTPUT_DIR}/cocos2d + +INSTALLS += target +target.path = $${LIB_INSTALL_DIR} + diff --git a/cocos2dx/proj.qt5/common.pri b/cocos2dx/proj.qt5/common.pri new file mode 100644 index 0000000000..353e86b448 --- /dev/null +++ b/cocos2dx/proj.qt5/common.pri @@ -0,0 +1,60 @@ + +DEFINES += CC_TARGET_QT5 + +CONFIG += silent + +# Disable some warnings to make compiler output easier to read during development +DISABLED_WARNINGS = -Wno-ignored-qualifiers -Wno-unused-parameter -Wno-psabi +QMAKE_CXXFLAGS += $${DISABLED_WARNINGS} -Wno-reorder +QMAKE_CFLAGS += $${DISABLED_WARNINGS} + +# C++11 support (GCC 4.6; for newer versions, change to -std=c++11) +QMAKE_CXXFLAGS += -Doverride= -std=c++0x + +OS_TYPE = linux + +CONFIG(debug, debug|release) { + BUILD_TYPE = debug +} else { + BUILD_TYPE = release +} + +OBJECTS_DIR = obj/$${BUILD_TYPE} +MOC_DIR = obj/$${BUILD_TYPE} +LIB_OUTPUT_DIR = $${PWD}/../../lib/$${OS_TYPE}/$${BUILD_TYPE} + +# Installation location of binaries +LIB_INSTALL_DIR = /usr/lib +BIN_INSTALL_DIR = /usr/bin +DESKTOP_INSTALL_DIR = /usr/share/applications + +INCLUDEPATH += $${PWD}/.. +INCLUDEPATH += $${PWD}/../include +INCLUDEPATH += $${PWD}/../platform +INCLUDEPATH += $${PWD}/../platform/qt5 +INCLUDEPATH += $${PWD}/../kazmath/include + +COCOS2DX_SYSTEM_LIBS += -lz +COCOS2DX_SYSTEM_LIBS += -ljpeg -ltiff -lpng +COCOS2DX_SYSTEM_LIBS += -lfontconfig -lfreetype + +# Sensors module needed for CCAccelerometer +QT += sensors + +LINK_AGAINST_COCOS2DX = -L$${LIB_OUTPUT_DIR} -lcocos2d $${COCOS2DX_SYSTEM_LIBS} + +# CocosDenshion (audio library) +QT += multimedia +INCLUDEPATH += $${PWD}/../../CocosDenshion/include +LINK_AGAINST_COCOSDENSHION = -lcocosdenshion + +# Extensions library +INCLUDEPATH += $${PWD}/../../extensions +LINK_AGAINST_COCOSEXTENSION = -lextension -lbox2d -lchipmunk -lcurl + +# Physics engines (pick one) +DEFINES += CC_ENABLE_CHIPMUNK_INTEGRATION +#DEFINES += CC_ENABLE_BOX2D_INTEGRATION +INCLUDEPATH += $${PWD}/../../external/chipmunk/include/chipmunk +INCLUDEPATH += $${PWD}/../../external + diff --git a/cocos2dx/proj.tizen/.project b/cocos2dx/proj.tizen/.project index f2080913f9..17c0930d3d 100644 --- a/cocos2dx/proj.tizen/.project +++ b/cocos2dx/proj.tizen/.project @@ -7,8 +7,11 @@ org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, + + ?children? + ?name?=outputEntries\|?children?=?name?=entry\\\\\\\|\\\|?name?=entry\\\\\\\|\\\|?name?=entry\\\\\\\|\\\|\|| + ?name? @@ -31,7 +34,7 @@ org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/cocos2dx/Debug-Tizen-Device} + ${workspace_loc:/cocos2dx/Debug-Tizen-Emulator} org.eclipse.cdt.make.core.cleanBuildTarget @@ -43,7 +46,7 @@ org.eclipse.cdt.make.core.enableAutoBuild - false + true org.eclipse.cdt.make.core.enableCleanBuild @@ -107,6 +110,11 @@ 1 PARENT-1-PROJECT_LOC/CCConfiguration.h + + src/CCDeprecated.cpp + 1 + PARENT-1-PROJECT_LOC/CCDeprecated.cpp + src/CCDirector.cpp 1 @@ -347,16 +355,6 @@ 1 PARENT-1-PROJECT_LOC/platform/CCThread.h - - src/platform/platform.cpp - 1 - PARENT-1-PROJECT_LOC/platform/platform.cpp - - - src/platform/platform.h - 1 - PARENT-1-PROJECT_LOC/platform/platform.h - src/platform/tizen 2 diff --git a/cocos2dx/proj.win32/cocos2d.vcxproj b/cocos2dx/proj.win32/cocos2d.vcxproj index 5f45a4e614..119794fdfe 100644 --- a/cocos2dx/proj.win32/cocos2d.vcxproj +++ b/cocos2dx/proj.win32/cocos2d.vcxproj @@ -69,7 +69,7 @@ Disabled - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..;$(ProjectDir)..\platform\win32;$(ProjectDir)..\platform\third_party\win32\iconv;$(ProjectDir)..\platform\third_party\win32\zlib;$(ProjectDir)..\platform\third_party\win32\libpng;$(ProjectDir)..\platform\third_party\win32\libjpeg;$(ProjectDir)..\platform\third_party\win32\libtiff;$(ProjectDir)..\platform\third_party\win32\libwebp;$(ProjectDir)..\platform\third_party\win32\pthread;$(ProjectDir)..\platform\third_party\win32\OGLES;..\include;$(ProjectDir)..\kazmath\include;%(AdditionalIncludeDirectories) + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..;$(ProjectDir)..\platform\win32;$(ProjectDir)..\platform\third_party\win32\iconv;$(ProjectDir)..\platform\third_party\win32\zlib;$(ProjectDir)..\platform\third_party\win32\libpng;$(ProjectDir)..\platform\third_party\win32\libjpeg;$(ProjectDir)..\platform\third_party\win32\libtiff;$(ProjectDir)..\platform\third_party\win32\libwebp;$(ProjectDir)..\platform\third_party\win32\pthread;$(ProjectDir)..\platform\third_party\win32\OGLES;..\include;$(ProjectDir)..\kazmath\include;$(ProjectDir)..\platform\third_party\common\etc;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -82,8 +82,8 @@ true - if not exist "$(OutDir)" mkdir "$(OutDir)" -xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir)" + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir)" @@ -118,8 +118,8 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir true - if not exist "$(OutDir)" mkdir "$(OutDir)" -xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir)" + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir)" @@ -194,9 +194,9 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir - + @@ -234,9 +234,6 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir - - - @@ -343,6 +340,8 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir + + @@ -397,9 +396,6 @@ xcopy /Y /Q "$(ProjectDir)..\platform\third_party\win32\libraries\*.*" "$(OutDir - - - diff --git a/cocos2dx/proj.win32/cocos2d.vcxproj.filters b/cocos2dx/proj.win32/cocos2d.vcxproj.filters index 4564d7b152..c2a235e145 100644 --- a/cocos2dx/proj.win32/cocos2d.vcxproj.filters +++ b/cocos2dx/proj.win32/cocos2d.vcxproj.filters @@ -103,12 +103,12 @@ {caa78ce0-9b58-4314-b117-1acae278691e} - - {5e6e45aa-50ef-451b-9bb1-f98b9b78259b} - {e7134ba0-4220-4dd1-b120-3533883394ac} + + {47fda93e-6eb4-4abc-b5bc-725bf667a395} + @@ -330,9 +330,6 @@ textures - - textures - tilemap_parallax_nodes @@ -446,9 +443,6 @@ platform - - platform - platform\win32 @@ -465,22 +459,19 @@ cocoa - - textures - support\component support\component - - textures\etc - keyboard_dispatcher + + platform\etc + @@ -754,9 +745,6 @@ textures - - textures - tilemap_parallax_nodes @@ -944,9 +932,6 @@ cocoa - - textures - support\component @@ -954,14 +939,15 @@ support\component - - textures\etc - keyboard_dispatcher include + + platform\etc + + \ No newline at end of file diff --git a/cocos2dx/sprite_nodes/CCSprite.cpp b/cocos2dx/sprite_nodes/CCSprite.cpp index 7ba285e3d0..c1ae8842a1 100644 --- a/cocos2dx/sprite_nodes/CCSprite.cpp +++ b/cocos2dx/sprite_nodes/CCSprite.cpp @@ -808,15 +808,15 @@ void Sprite::setSkewY(float sy) SET_DIRTY_RECURSIVELY(); } -void Sprite::setScaleX(float fScaleX) +void Sprite::setScaleX(float scaleX) { - Node::setScaleX(fScaleX); + Node::setScaleX(scaleX); SET_DIRTY_RECURSIVELY(); } -void Sprite::setScaleY(float fScaleY) +void Sprite::setScaleY(float scaleY) { - Node::setScaleY(fScaleY); + Node::setScaleY(scaleY); SET_DIRTY_RECURSIVELY(); } @@ -1099,8 +1099,8 @@ void Sprite::setTexture(Texture2D *texture) if (NULL == texture) { Image* image = new Image(); - bool isOK = image->initWithImageData(cc_2x2_white_image, sizeof(cc_2x2_white_image), Image::Format::RAW_DATA, 2, 2, 8); - CCASSERT(isOK, "The 2x2 empty texture was created unsuccessfully."); + bool isOK = image->initWithRawData(cc_2x2_white_image, sizeof(cc_2x2_white_image), 2, 2, 8); + CCAssert(isOK, "The 2x2 empty texture was created unsuccessfully."); texture = TextureCache::getInstance()->addUIImage(image, CC_2x2_WHITE_IMAGE_KEY); CC_SAFE_RELEASE(image); diff --git a/cocos2dx/sprite_nodes/CCSprite.h b/cocos2dx/sprite_nodes/CCSprite.h index bcead0dc23..3a8f72700e 100644 --- a/cocos2dx/sprite_nodes/CCSprite.h +++ b/cocos2dx/sprite_nodes/CCSprite.h @@ -456,8 +456,8 @@ public: /// @{ /// @name Functions inherited from Node - virtual void setScaleX(float fScaleX) override; - virtual void setScaleY(float fScaleY) override; + virtual void setScaleX(float scaleX) override; + virtual void setScaleY(float scaleY) override; virtual void setPosition(const Point& pos) override; virtual void setRotation(float fRotation) override; virtual void setRotationX(float fRotationX) override; diff --git a/cocos2dx/support/zip_support/ZipUtils.cpp b/cocos2dx/support/zip_support/ZipUtils.cpp index 3302d28095..74b8def85e 100644 --- a/cocos2dx/support/zip_support/ZipUtils.cpp +++ b/cocos2dx/support/zip_support/ZipUtils.cpp @@ -300,10 +300,157 @@ int ZipUtils::ccInflateGZipFile(const char *path, unsigned char **out) return offset; } +bool ZipUtils::ccIsCCZFile(const char *path) +{ + // load file into memory + unsigned char* compressed = NULL; + + unsigned long fileLen = 0; + compressed = FileUtils::getInstance()->getFileData(path, "rb", &fileLen); + + if(NULL == compressed || 0 == fileLen) + { + CCLOG("cocos2d: ZipUtils: loading file failed"); + return false; + } + + return ccIsCCZBuffer(compressed, fileLen); +} + +bool ZipUtils::ccIsCCZBuffer(const unsigned char *buffer, int len) +{ + if (len < sizeof(struct CCZHeader)) + { + return false; + } + + struct CCZHeader *header = (struct CCZHeader*) buffer; + return header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && (header->sig[3] == '!' || header->sig[3] == 'p'); +} + + +bool ZipUtils::ccIsGZipFile(const char *path) +{ + // load file into memory + unsigned char* compressed = NULL; + + unsigned long fileLen = 0; + compressed = FileUtils::getInstance()->getFileData(path, "rb", &fileLen); + + if(NULL == compressed || 0 == fileLen) + { + CCLOG("cocos2d: ZipUtils: loading file failed"); + return false; + } + + return ccIsGZipBuffer(compressed, fileLen); +} + +bool ZipUtils::ccIsGZipBuffer(const unsigned char *buffer, int len) +{ + if (len < 2) + { + return false; + } + + return buffer[0] == 0x1F && buffer[1] == 0x8B; +} + + +int ZipUtils::ccInflateCCZBuffer(const unsigned char *buffer, int bufferLen, unsigned char **out) +{ + struct CCZHeader *header = (struct CCZHeader*) buffer; + + // verify header + if( header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == '!' ) + { + // verify header version + unsigned int version = CC_SWAP_INT16_BIG_TO_HOST( header->version ); + if( version > 2 ) + { + CCLOG("cocos2d: Unsupported CCZ header format"); + return -1; + } + + // verify compression format + if( CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB ) + { + CCLOG("cocos2d: CCZ Unsupported compression method"); + return -1; + } + } + else if( header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == 'p' ) + { + // encrypted ccz file + header = (struct CCZHeader*) buffer; + + // verify header version + unsigned int version = CC_SWAP_INT16_BIG_TO_HOST( header->version ); + if( version > 0 ) + { + CCLOG("cocos2d: Unsupported CCZ header format"); + return -1; + } + + // verify compression format + if( CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB ) + { + CCLOG("cocos2d: CCZ Unsupported compression method"); + return -1; + } + + // decrypt + unsigned int* ints = (unsigned int*)(buffer+12); + int enclen = (bufferLen-12)/4; + + ccDecodeEncodedPvr(ints, enclen); + +#if COCOS2D_DEBUG > 0 + // verify checksum in debug mode + unsigned int calculated = ccChecksumPvr(ints, enclen); + unsigned int required = CC_SWAP_INT32_BIG_TO_HOST( header->reserved ); + + if(calculated != required) + { + CCLOG("cocos2d: Can't decrypt image file. Is the decryption key valid?"); + return -1; + } +#endif + } + else + { + CCLOG("cocos2d: Invalid CCZ file"); + return -1; + } + + unsigned int len = CC_SWAP_INT32_BIG_TO_HOST( header->len ); + + *out = (unsigned char*)malloc( len ); + if(! *out ) + { + CCLOG("cocos2d: CCZ: Failed to allocate memory for texture"); + return -1; + } + + unsigned long destlen = len; + unsigned long source = (unsigned long) buffer + sizeof(*header); + int ret = uncompress(*out, &destlen, (Bytef*)source, bufferLen - sizeof(*header) ); + + if( ret != Z_OK ) + { + CCLOG("cocos2d: CCZ: Failed to uncompress data"); + free( *out ); + *out = NULL; + return -1; + } + + return len; +} + int ZipUtils::ccInflateCCZFile(const char *path, unsigned char **out) { - CCASSERT(out, ""); - CCASSERT(&*out, ""); + CCAssert(out, ""); + CCAssert(&*out, ""); // load file into memory unsigned char* compressed = NULL; @@ -317,101 +464,7 @@ int ZipUtils::ccInflateCCZFile(const char *path, unsigned char **out) return -1; } - struct CCZHeader *header = (struct CCZHeader*) compressed; - - // verify header - if( header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == '!' ) - { - // verify header version - unsigned int version = CC_SWAP_INT16_BIG_TO_HOST( header->version ); - if( version > 2 ) - { - CCLOG("cocos2d: Unsupported CCZ header format"); - delete [] compressed; - return -1; - } - - // verify compression format - if( CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB ) - { - CCLOG("cocos2d: CCZ Unsupported compression method"); - delete [] compressed; - return -1; - } - } - else if( header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == 'p' ) - { - // encrypted ccz file - header = (struct CCZHeader*) compressed; - - // verify header version - unsigned int version = CC_SWAP_INT16_BIG_TO_HOST( header->version ); - if( version > 0 ) - { - CCLOG("cocos2d: Unsupported CCZ header format"); - delete [] compressed; - return -1; - } - - // verify compression format - if( CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB ) - { - CCLOG("cocos2d: CCZ Unsupported compression method"); - delete [] compressed; - return -1; - } - - // decrypt - unsigned int* ints = (unsigned int*)(compressed+12); - int enclen = (fileLen-12)/4; - - ccDecodeEncodedPvr(ints, enclen); - -#if COCOS2D_DEBUG > 0 - // verify checksum in debug mode - unsigned int calculated = ccChecksumPvr(ints, enclen); - unsigned int required = CC_SWAP_INT32_BIG_TO_HOST( header->reserved ); - - if(calculated != required) - { - CCLOG("cocos2d: Can't decrypt image file. Is the decryption key valid?"); - delete [] compressed; - return -1; - } -#endif - } - else - { - CCLOG("cocos2d: Invalid CCZ file"); - delete [] compressed; - return -1; - } - - unsigned int len = CC_SWAP_INT32_BIG_TO_HOST( header->len ); - - *out = (unsigned char*)malloc( len ); - if(! *out ) - { - CCLOG("cocos2d: CCZ: Failed to allocate memory for texture"); - delete [] compressed; - return -1; - } - - unsigned long destlen = len; - unsigned long source = (unsigned long) compressed + sizeof(*header); - int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) ); - - delete [] compressed; - - if( ret != Z_OK ) - { - CCLOG("cocos2d: CCZ: Failed to uncompress data"); - free( *out ); - *out = NULL; - return -1; - } - - return len; + return ccInflateCCZBuffer(compressed, fileLen, out); } void ZipUtils::ccSetPvrEncryptionKeyPart(int index, unsigned int value) diff --git a/cocos2dx/support/zip_support/ZipUtils.h b/cocos2dx/support/zip_support/ZipUtils.h index d245760271..d7202a091d 100644 --- a/cocos2dx/support/zip_support/ZipUtils.h +++ b/cocos2dx/support/zip_support/ZipUtils.h @@ -85,6 +85,22 @@ namespace cocos2d * @since v0.99.5 */ static int ccInflateGZipFile(const char *filename, unsigned char **out); + + /** test a file is a GZip format file or not + * + * @returns true is a GZip format file. false is not + * + * @since v3.0 + */ + static bool ccIsGZipFile(const char *filename); + + /** test the buffer is GZip format or not + * + * @returns true is GZip format. false is not + * + * @since v3.0 + */ + static bool ccIsGZipBuffer(const unsigned char *buffer, int len); /** inflates a CCZ file into memory * @@ -94,6 +110,30 @@ namespace cocos2d */ static int ccInflateCCZFile(const char *filename, unsigned char **out); + /** inflates a buffer with CCZ format into memory + * + * @returns the length of the deflated buffer + * + * @since v3.0 + */ + static int ccInflateCCZBuffer(const unsigned char *buffer, int len, unsigned char **out); + + /** test a file is a CCZ format file or not + * + * @returns true is a CCZ format file. false is not + * + * @since v3.0 + */ + static bool ccIsCCZFile(const char *filename); + + /** test the buffer is CCZ format or not + * + * @returns true is CCZ format. false is not + * + * @since v3.0 + */ + static bool ccIsCCZBuffer(const unsigned char *buffer, int len); + /** Sets the pvr.ccz encryption key parts separately for added * security. * diff --git a/cocos2dx/textures/CCTexture2D.cpp b/cocos2dx/textures/CCTexture2D.cpp index a8766d82f5..f06307fb13 100644 --- a/cocos2dx/textures/CCTexture2D.cpp +++ b/cocos2dx/textures/CCTexture2D.cpp @@ -38,8 +38,6 @@ THE SOFTWARE. #include "CCGL.h" #include "support/ccUtils.h" #include "platform/CCPlatformMacros.h" -#include "textures/CCTexturePVR.h" -#include "textures/CCTextureETC.h" #include "CCDirector.h" #include "shaders/CCGLProgram.h" #include "shaders/ccGLStateCache.h" @@ -57,14 +55,302 @@ NS_CC_BEGIN // Default is: RGBA8888 (32-bit textures) static Texture2D::PixelFormat g_defaultAlphaPixelFormat = Texture2D::PixelFormat::DEFAULT; -// By default PVR images are treated as if they don't have the alpha channel premultiplied -static bool PVRHaveAlphaPremultiplied_ = false; +static bool _PVRHaveAlphaPremultiplied = false; + +////////////////////////////////////////////////////////////////////////// +//conventer function + +// IIIIIIII -> RRRRRRRRGGGGGGGGGBBBBBBBB +void Texture2D::convertI8ToRGB888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i=0; i < len; ++i) + { + *out++ = in[i];//R + *out++ = in[i];//G + *out++ = in[i];//B + } +} + +// IIIIIIIIAAAAAAAA -> RRRRRRRRGGGGGGGGBBBBBBBB +void Texture2D::convertAI88ToRGB888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out++ = in[i];//R + *out++ = in[i];//G + *out++ = in[i];//B + } +} + +// IIIIIIII -> RRRRRRRRGGGGGGGGGBBBBBBBBAAAAAAAA +void Texture2D::convertI8ToRGBA8888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0; i < len; ++i) + { + *out++ = in[i];//R + *out++ = in[i];//G + *out++ = in[i];//B + *out++ = 0xFF;//A + } +} + +// IIIIIIIIAAAAAAAA -> RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA +void Texture2D::convertAI88ToRGBA8888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out++ = in[i];//R + *out++ = in[i];//G + *out++ = in[i];//B + *out++ = in[i + 1];//A + } +} + +// IIIIIIII -> RRRRRGGGGGGBBBBB +void Texture2D::convertI8ToRGB565(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0; i < len; ++i) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i] & 0x00FC) << 3 //G + | (in[i] & 0x00F8) >> 3; //B + } +} + +// IIIIIIIIAAAAAAAA -> RRRRRGGGGGGBBBBB +void Texture2D::convertAI88ToRGB565(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i] & 0x00FC) << 3 //G + | (in[i] & 0x00F8) >> 3; //B + } +} + +// IIIIIIII -> RRRRGGGGBBBBAAAA +void Texture2D::convertI8ToRGBA4444(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0; i < len; ++i) + { + *out16++ = (in[i] & 0x00F0) << 8 | (in[i] & 0x00F0) << 4 | (in[i] & 0x00F0) | 0x000F; //RGBA + } +} + +// IIIIIIIIAAAAAAAA -> RRRRGGGGBBBBAAAA +void Texture2D::convertAI88ToRGBA4444(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out16++ = (in[i] & 0x00F0) << 8 | (in[i] & 0x00F0) << 4 | (in[i] & 0x00F0) | (in[i+1] & 0x00F0) >> 4; //RGBA + } +} + +// IIIIIIII -> RRRRRGGGGGBBBBBA +void Texture2D::convertI8ToRGB5A1(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0; i < len; ++i) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i] & 0x00F8) << 3 //G + | (in[i] & 0x00F8) >> 2 //B + | 0x0001; //A + } +} + +// IIIIIIIIAAAAAAAA -> RRRRRGGGGGBBBBBA +void Texture2D::convertAI88ToRGB5A1(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i] & 0x00F8) << 3 //G + | (in[i] & 0x00F8) >> 2 //B + | (in[i + 1] & 0x0080) >> 7; //A + } +} + +// IIIIIIII -> IIIIIIIIAAAAAAAA +void Texture2D::convertI8ToAI88(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0; i < len; ++i) + { + *out16++ = 0xFF00 | in[i]; //AI + } +} + +// IIIIIIIIAAAAAAAA -> AAAAAAAA +void Texture2D::convertAI88ToA8(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 1; i < len; i += 2) + { + *out++ = in[i]; //A + } +} + +// IIIIIIIIAAAAAAAA -> IIIIIIII +void Texture2D::convertAI88ToI8(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 1; i < l; i += 2) + { + *out++ = in[i]; //R + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA +void Texture2D::convertRGB888ToRGBA8888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out++ = in[i]; + *out++ = in[i + 1]; + *out++ = in[i + 2]; + *out++ = 0xFF; + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> RRRRRRRRGGGGGGGGBBBBBBBB +void Texture2D::convertRGBA8888ToRGB888(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 3; i < l; i += 4) + { + *out++ = in[i]; + *out++ = in[i + 1]; + *out++ = in[i + 2]; + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> RRRRRGGGGGGBBBBB +void Texture2D::convertRGB888ToRGB565(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i + 1] & 0x00FC) << 3 //G + | (in[i + 2] & 0x00F8) >> 3; //B + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> RRRRRGGGGGGBBBBB +void Texture2D::convertRGBA8888ToRGB565(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 3; i < l; i += 4) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i + 1] & 0x00FC) << 3 //G + | (in[i + 2] & 0x00F8) >> 3; //B + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> IIIIIIII +void Texture2D::convertRGB888ToI8(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out++ = (in[i] * 299 + in[i + 1] * 587 + in[i + 2] * 114 + 500) / 1000; //I = (R*299 + G*587 + B*114 + 500) / 1000 + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> IIIIIIII +void Texture2D::convertRGBA8888ToI8(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 3; i < l; i += 4) + { + *out++ = (in[i] * 299 + in[i + 1] * 587 + in[i + 2] * 114 + 500) / 1000; //I = (R*299 + G*587 + B*114 + 500) / 1000 + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> AAAAAAAA +void Texture2D::convertRGBA8888ToA8(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len -3; i < l; i += 4) + { + *out++ = in[i + 3]; + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> IIIIIIIIAAAAAAAA +void Texture2D::convertRGB888ToAI88(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out++ = (in[i] * 299 + in[i + 1] * 587 + in[i + 2] * 114 + 500) / 1000; //I = (R*299 + G*587 + B*114 + 500) / 1000 + *out++ = 0xFF; + } +} + + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> IIIIIIIIAAAAAAAA +void Texture2D::convertRGBA8888ToAI88(const unsigned char* in, int len, unsigned char* out) +{ + for (int i = 0, l = len - 3; i < l; i += 4) + { + *out++ = (in[i] * 299 + in[i + 1] * 587 + in[i + 2] * 114 + 500) / 1000; //I = (R*299 + G*587 + B*114 + 500) / 1000 + *out++ = in[i + 3]; + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> RRRRGGGGBBBBAAAA +void Texture2D::convertRGB888ToRGBA4444(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out16++ = ((in[i] & 0x00F0) << 8 | (in[i + 1] & 0x00F0) << 4 | (in[i + 2] & 0xF0) | 0x0F); //RGBA + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA -> RRRRGGGGBBBBAAAA +void Texture2D::convertRGBA8888ToRGBA4444(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 3; i < l; i += 4) + { + *out16++ = (in[i] & 0x00F0) << 8 | (in[i + 1] & 0x00F0) << 4 | (in[i + 2] & 0xF0) | (in[i + 3] & 0xF0) >> 4; //RGBA + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> RRRRRGGGGGBBBBBA +void Texture2D::convertRGB888ToRGB5A1(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 2; i < l; i += 3) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i + 1] & 0x00F8) << 3 //G + | (in[i + 2] & 0x00F8) >> 2 //B + | 0x01; //A + } +} + +// RRRRRRRRGGGGGGGGBBBBBBBB -> RRRRRGGGGGBBBBBA +void Texture2D::convertRGBA8888ToRGB5A1(const unsigned char* in, int len, unsigned char* out) +{ + unsigned short* out16 = (unsigned short*)out; + for (int i = 0, l = len - 2; i < l; i += 4) + { + *out16++ = (in[i] & 0x00F8) << 8 //R + | (in[i + 1] & 0x00F8) << 3 //G + | (in[i + 2] & 0x00F8) >> 2 //B + | (in[i + 3] & 0x0080) >> 7; //A + } +} +// conventer function end +////////////////////////////////////////////////////////////////////////// Texture2D::Texture2D() -: _PVRHaveAlphaPremultiplied(true) +: _pixelFormat(Texture2D::PixelFormat::DEFAULT) , _pixelsWide(0) , _pixelsHigh(0) -, _pixelFormat(Texture2D::PixelFormat::DEFAULT) , _name(0) , _maxS(0.0) , _maxT(0.0) @@ -172,89 +458,135 @@ bool Texture2D::hasPremultipliedAlpha() const return _hasPremultipliedAlpha; } -bool Texture2D::initWithData(const void *data, Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const Size& contentSize) +bool Texture2D::initWithData(const void *data, int dataLen, Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const Size& contentSize) { - unsigned int bitsPerPixel; - //Hack: bitsPerPixelForFormat returns wrong number for RGB_888 textures. See function. - if(pixelFormat == Texture2D::PixelFormat::RGB888) + //if data has no mipmaps, we will consider it has only one mipmap + MipmapInfo mipmap; + mipmap.address = (unsigned char*)data; + mipmap.len = dataLen; + return initWithMipmaps(&mipmap, 1, pixelFormat, pixelsWide, pixelsHigh); + + //update information + _contentSize = contentSize; + _maxS = contentSize.width / (float)(pixelsWide); + _maxT = contentSize.height / (float)(pixelsHigh); + +} + +bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh) +{ + //the pixelFormat must be a certain value + CCAssert(pixelFormat != PixelFormat::NONE && pixelFormat != PixelFormat::AUTO, "the \"pixelFormat\" param must be a certain value!"); + + if (mipmapsNum <= 0) { - bitsPerPixel = 24; + CCLOG("cocos2d: WARNING: mipmap number is less than 1"); + return false; } - else + + + if(g_texturePixelFormatInfoTables.find(pixelFormat) == g_texturePixelFormatInfoTables.end()) { - bitsPerPixel = getBitsPerPixelForFormat(pixelFormat); + CCLOG("cocos2d: WARNING: unsupported pixelformat: %lx", (unsigned long)pixelFormat ); + return false; } - unsigned int bytesPerRow = pixelsWide * bitsPerPixel / 8; + const TexturePixelFormatInfo& info = g_texturePixelFormatInfoTables.at(pixelFormat); - if(bytesPerRow % 8 == 0) + if (info.compressed && !Configuration::getInstance()->supportsPVRTC() && !Configuration::getInstance()->supportsETC()) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 8); + CCLOG("cocos2d: WARNING: PVRTC/ETC images are not supported"); + return false; } - else if(bytesPerRow % 4 == 0) + + //Set the row align only when mipmapsNum == 1 and the data is uncompressed + if (mipmapsNum == 1 && !info.compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - else if(bytesPerRow % 2 == 0) - { - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - } - else + unsigned int bytesPerRow = pixelsWide * info.bpp / 8; + + if(bytesPerRow % 8 == 0) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 8); + } + else if(bytesPerRow % 4 == 0) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + } + else if(bytesPerRow % 2 == 0) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + } + else + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + }else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } + glGenTextures(1, &_name); GL::bindTexture2D(_name); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + if (mipmapsNum == 1) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + }else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR_DEBUG(); // clean possible GL error + // Specify OpenGL texture image - - switch(pixelFormat) + int width = pixelsWide; + int height = pixelsHigh; + for (int i = 0; i < mipmapsNum; ++i) { - case Texture2D::PixelFormat::RGBA8888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - break; - case Texture2D::PixelFormat::RGB888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data); - break; - case Texture2D::PixelFormat::RGBA4444: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - break; - case Texture2D::PixelFormat::RGB5A1: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); - break; - case Texture2D::PixelFormat::RGB565: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - break; - case Texture2D::PixelFormat::AI88: - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data); - break; - case Texture2D::PixelFormat::A8: - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); - break; - case Texture2D::PixelFormat::I8: - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); - break; - default: - CCASSERT(0, "NSInternalInconsistencyException"); + unsigned char *data = mipmaps[i].address; + GLsizei datalen = mipmaps[i].len; + if (info.compressed) + { + glCompressedTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, datalen, data); + } + else + { + glTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, info.format, info.type, data); + } + + if (i > 0 && (width != height || ccNextPOT(width) != width )) + { + CCLOG("cocos2d: Texture2D. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%u != height=%u", i, width, height); + } + + GLenum err = glGetError(); + if (err != GL_NO_ERROR) + { + CCLOG("cocos2d: Texture2D: Error uploading compressed texture level: %u . glError: 0x%04X", i, err); + return false; + } + + width = MAX(width >> 1, 1); + height = MAX(height >> 1, 1); + } - _contentSize = contentSize; + _contentSize = Size((float)pixelsWide, (float)pixelsHigh); _pixelsWide = pixelsWide; _pixelsHigh = pixelsHigh; _pixelFormat = pixelFormat; - _maxS = contentSize.width / (float)(pixelsWide); - _maxT = contentSize.height / (float)(pixelsHigh); + _maxS = 1; + _maxT = 1; _hasPremultipliedAlpha = false; - _hasMipmaps = false; + _hasMipmaps = mipmapsNum > 1; setShaderProgram(ShaderCache::getInstance()->programForKey(GLProgram::SHADER_NAME_POSITION_TEXTURE)); @@ -268,168 +600,344 @@ const char* Texture2D::description(void) const } // implementation Texture2D (Image) - -bool Texture2D::initWithImage(Image *uiImage) +bool Texture2D::initWithImage(Image *image) { - if (uiImage == NULL) + return initWithImage(image, PixelFormat::NONE); +} + +bool Texture2D::initWithImage(Image *image, PixelFormat format) +{ + if (image == NULL) { CCLOG("cocos2d: Texture2D. Can't create Texture. UIImage is nil"); return false; } - - unsigned int imageWidth = uiImage->getWidth(); - unsigned int imageHeight = uiImage->getHeight(); - + + int imageWidth = image->getWidth(); + int imageHeight = image->getHeight(); + Configuration *conf = Configuration::getInstance(); - - unsigned maxTextureSize = conf->getMaxTextureSize(); + + int maxTextureSize = conf->getMaxTextureSize(); if (imageWidth > maxTextureSize || imageHeight > maxTextureSize) { CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize); return false; } - - // always load premultiplied images - return initPremultipliedATextureWithImage(uiImage, imageWidth, imageHeight); -} -bool Texture2D::initPremultipliedATextureWithImage(Image *image, unsigned int width, unsigned int height) -{ - unsigned char* tempData = image->getData(); - unsigned int* inPixel32 = NULL; - unsigned char* inPixel8 = NULL; - unsigned short* outPixel16 = NULL; - bool hasAlpha = image->hasAlpha(); - Size imageSize = Size((float)(image->getWidth()), (float)(image->getHeight())); - Texture2D::PixelFormat pixelFormat; - size_t bpp = image->getBitsPerComponent(); + unsigned char* tempData = image->getData(); + Size imageSize = Size((float)imageWidth, (float)imageHeight); + PixelFormat pixelFormat = PixelFormat::NONE; + PixelFormat renderFormat = image->getRenderFormat(); + size_t tempDataLen = image->getDataLen(); - // compute pixel format - if (hasAlpha) + + if (image->getNumberOfMipmaps() > 1) { - pixelFormat = g_defaultAlphaPixelFormat; + if (format != PixelFormat::NONE) + { + CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format"); + } + + initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getRenderFormat(), imageWidth, imageHeight); + return true; + } + else if (image->isCompressed()) + { + if (format != PixelFormat::NONE) + { + CCLOG("cocos2d: WARNING: This image is compressed and we cann't convert it for now"); + } + + initWithData(tempData, tempDataLen, image->getRenderFormat(), imageWidth, imageHeight, imageSize); + return true; } else { - if (bpp >= 8) + // compute pixel format + if (format != PixelFormat::NONE) { - pixelFormat = Texture2D::PixelFormat::RGB888; - } - else + pixelFormat = format; + }else { - pixelFormat = Texture2D::PixelFormat::RGB565; + pixelFormat = g_defaultAlphaPixelFormat; } - - } - - // Repack the pixel data into the right format - unsigned int length = width * height; - if (pixelFormat == Texture2D::PixelFormat::RGB565) - { - if (hasAlpha) + unsigned char* outTempData = NULL; + int outTempDataLen = 0; + + pixelFormat = convertDataToFormat(tempData, tempDataLen, renderFormat, pixelFormat, &outTempData, &outTempDataLen); + + initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize); + + + if (outTempData != NULL && outTempData != tempData) { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" - - tempData = new unsigned char[width * height * 2]; - outPixel16 = (unsigned short*)tempData; - inPixel32 = (unsigned int*)image->getData(); - - for(unsigned int i = 0; i < length; ++i, ++inPixel32) + + delete [] outTempData; + } + + // set the premultiplied tag + if (!image->hasPremultipliedAlpha()) + { + if (image->getFileType() == Image::Format::PVR) { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B - } - } - else - { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB" - - tempData = new unsigned char[width * height * 2]; - outPixel16 = (unsigned short*)tempData; - inPixel8 = (unsigned char*)image->getData(); - - for(unsigned int i = 0; i < length; ++i) + _hasPremultipliedAlpha = _PVRHaveAlphaPremultiplied; + }else { - *outPixel16++ = - (((*inPixel8++ & 0xFF) >> 3) << 11) | // R - (((*inPixel8++ & 0xFF) >> 2) << 5) | // G - (((*inPixel8++ & 0xFF) >> 3) << 0); // B + CCLOG("wanning: We cann't find the data is premultiplied or not, we will assume it's false."); + _hasPremultipliedAlpha = false; } - } - } - else if (pixelFormat == Texture2D::PixelFormat::RGBA4444) - { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" - - inPixel32 = (unsigned int*)image->getData(); - tempData = new unsigned char[width * height * 2]; - outPixel16 = (unsigned short*)tempData; - - for(unsigned int i = 0; i < length; ++i, ++inPixel32) + }else { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A + _hasPremultipliedAlpha = image->isPremultipliedAlpha(); } + return true; } - else if (pixelFormat == Texture2D::PixelFormat::RGB5A1) +} + +Texture2D::PixelFormat Texture2D::convertI8ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen) +{ + switch (format) { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" - inPixel32 = (unsigned int*)image->getData(); - tempData = new unsigned char[width * height * 2]; - outPixel16 = (unsigned short*)tempData; - - for(unsigned int i = 0; i < length; ++i, ++inPixel32) + case PixelFormat::RGBA8888: + *outDataLen = dataLen*4; + *outData = new unsigned char[*outDataLen]; + convertI8ToRGBA8888(data, dataLen, *outData); + break; + case PixelFormat::RGB888: + *outDataLen = dataLen*3; + *outData = new unsigned char[*outDataLen]; + convertI8ToRGB888(data, dataLen, *outData); + break; + case PixelFormat::RGB565: + *outDataLen = dataLen*2; + *outData = new unsigned char[*outDataLen]; + convertI8ToRGB565(data, dataLen, *outData); + break; + case PixelFormat::AI88: + *outDataLen = dataLen*2; + *outData = new unsigned char[*outDataLen]; + convertI8ToAI88(data, dataLen, *outData); + break; + case PixelFormat::RGBA4444: + *outDataLen = dataLen*2; + *outData = new unsigned char[*outDataLen]; + convertI8ToRGBA4444(data, dataLen, *outData); + break; + case PixelFormat::RGB5A1: + *outDataLen = dataLen*2; + *outData = new unsigned char[*outDataLen]; + convertI8ToRGB5A1(data, dataLen, *outData); + break; + default: + // unsupport convertion or don't need to convert + if (format != PixelFormat::AUTO && format != PixelFormat::I8) { - *outPixel16++ = - ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R - ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G - ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B - ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A + CCLOG("Can not convert image format PixelFormat::I8 to format ID:%d, we will use it's origin format PixelFormat::I8", format); } - } - else if (pixelFormat == Texture2D::PixelFormat::A8) - { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "AAAAAAAA" - inPixel32 = (unsigned int*)image->getData(); - tempData = new unsigned char[width * height]; - unsigned char *outPixel8 = tempData; - - for(unsigned int i = 0; i < length; ++i, ++inPixel32) - { - *outPixel8++ = (*inPixel32 >> 24) & 0xFF; // A - } - } - - if (hasAlpha && pixelFormat == Texture2D::PixelFormat::RGB888) - { - // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB" - inPixel32 = (unsigned int*)image->getData(); - tempData = new unsigned char[width * height * 3]; - unsigned char *outPixel8 = tempData; - - for(unsigned int i = 0; i < length; ++i, ++inPixel32) - { - *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R - *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G - *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B - } - } - - initWithData(tempData, pixelFormat, width, height, imageSize); - - if (tempData != image->getData()) - { - delete [] tempData; + + *outData = (unsigned char*)data; + *outDataLen = dataLen; + return PixelFormat::I8; } - _hasPremultipliedAlpha = image->isPremultipliedAlpha(); - return true; + return format; +} + +Texture2D::PixelFormat Texture2D::convertAI88ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen) +{ + switch (format) + { + case PixelFormat::RGBA8888: + *outDataLen = dataLen*2; + *outData = new unsigned char[*outDataLen]; + convertAI88ToRGBA8888(data, dataLen, *outData); + break; + case PixelFormat::RGB888: + *outDataLen = dataLen/2*3; + *outData = new unsigned char[*outDataLen]; + convertAI88ToRGB888(data, dataLen, *outData); + break; + case PixelFormat::RGB565: + *outDataLen = dataLen; + *outData = new unsigned char[*outDataLen]; + convertAI88ToRGB565(data, dataLen, *outData); + break; + case PixelFormat::A8: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertAI88ToA8(data, dataLen, *outData); + break; + case PixelFormat::I8: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertAI88ToI8(data, dataLen, *outData); + break; + case PixelFormat::RGBA4444: + *outDataLen = dataLen; + *outData = new unsigned char[*outDataLen]; + convertAI88ToRGBA4444(data, dataLen, *outData); + break; + case PixelFormat::RGB5A1: + *outDataLen = dataLen; + *outData = new unsigned char[*outDataLen]; + convertAI88ToRGB5A1(data, dataLen, *outData); + break; + default: + // unsupport convertion or don't need to convert + if (format != PixelFormat::AUTO && format != PixelFormat::AI88) + { + CCLOG("Can not convert image format PixelFormat::AI88 to format ID:%d, we will use it's origin format PixelFormat::AI88", format); + } + + *outData = (unsigned char*)data; + *outDataLen = dataLen; + return PixelFormat::AI88; + break; + } + + return format; +} + +Texture2D::PixelFormat Texture2D::convertRGB888ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen) +{ + switch (format) + { + case PixelFormat::RGBA8888: + *outDataLen = dataLen/3*4; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToRGBA8888(data, dataLen, *outData); + break; + case PixelFormat::RGB565: + *outDataLen = dataLen/3*2; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToRGB565(data, dataLen, *outData); + break; + case PixelFormat::I8: + *outDataLen = dataLen/3; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToI8(data, dataLen, *outData); + break; + case PixelFormat::AI88: + *outDataLen = dataLen/3*2; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToAI88(data, dataLen, *outData); + break; + case PixelFormat::RGBA4444: + *outDataLen = dataLen/3*2; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToRGBA4444(data, dataLen, *outData); + break; + case PixelFormat::RGB5A1: + *outDataLen = dataLen; + *outData = new unsigned char[*outDataLen]; + convertRGB888ToRGB5A1(data, dataLen, *outData); + break; + default: + // unsupport convertion or don't need to convert + if (format != PixelFormat::AUTO && format != PixelFormat::RGB888) + { + CCLOG("Can not convert image format PixelFormat::RGB888 to format ID:%d, we will use it's origin format PixelFormat::RGB888", format); + } + + *outData = (unsigned char*)data; + *outDataLen = dataLen; + return PixelFormat::RGB888; + } + return format; +} + +Texture2D::PixelFormat Texture2D::convertRGBA8888ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen) +{ + + switch (format) + { + case PixelFormat::RGB888: + *outDataLen = dataLen/4*3; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToRGB888(data, dataLen, *outData); + break; + case PixelFormat::RGB565: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToRGB565(data, dataLen, *outData); + break; + case PixelFormat::A8: + *outDataLen = dataLen/4; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToA8(data, dataLen, *outData); + break; + case PixelFormat::I8: + *outDataLen = dataLen/4; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToI8(data, dataLen, *outData); + break; + case PixelFormat::AI88: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToAI88(data, dataLen, *outData); + break; + case PixelFormat::RGBA4444: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToRGBA4444(data, dataLen, *outData); + break; + case PixelFormat::RGB5A1: + *outDataLen = dataLen/2; + *outData = new unsigned char[*outDataLen]; + convertRGBA8888ToRGB5A1(data, dataLen, *outData); + break; + default: + // unsupport convertion or don't need to convert + if (format != PixelFormat::AUTO && format != PixelFormat::RGBA8888) + { + CCLOG("Can not convert image format PixelFormat::RGBA8888 to format ID:%d, we will use it's origin format PixelFormat::RGBA8888", format); + } + + *outData = (unsigned char*)data; + *outDataLen = dataLen; + return PixelFormat::RGBA8888; + } + + return format; +} + +/* +convert map: +1.PixelFormat::RGBA8888 +2.PixelFormat::RGB888 +3.PixelFormat::RGB565 +4.PixelFormat::A8 +5.PixelFormat::I8 +6.PixelFormat::AI88 +7.PixelFormat::RGBA4444 +8.PixelFormat::RGB5A1 + +gray(5) -> 1235678 +gray alpha(6) -> 12345678 +rgb(2) -> 1235678 +rgba(1) -> 12345678 + +*/ +Texture2D::PixelFormat Texture2D::convertDataToFormat(const unsigned char* data, int dataLen, PixelFormat originFormat, PixelFormat format, unsigned char** outData, int* outDataLen) +{ + switch (originFormat) + { + case PixelFormat::I8: + return convertI8ToFormat(data, dataLen, format, outData, outDataLen); + case PixelFormat::AI88: + return convertAI88ToFormat(data, dataLen, format, outData, outDataLen); + case PixelFormat::RGB888: + return convertRGB888ToFormat(data, dataLen, format, outData, outDataLen); + case PixelFormat::RGBA8888: + return convertRGBA8888ToFormat(data, dataLen, format, outData, outDataLen); + default: + CCLOG("unsupport convert for format %d to format %d", originFormat, format); + *outData = (unsigned char*)data; + *outDataLen = dataLen; + return originFormat; + } } // implementation Texture2D (Text) @@ -644,69 +1152,9 @@ void Texture2D::drawInRect(const Rect& rect) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } -bool Texture2D::initWithPVRFile(const char* file) -{ - bool bRet = false; - // nothing to do with Object::init - - TexturePVR *pvr = new TexturePVR; - bRet = pvr->initWithContentsOfFile(file); - - if (bRet) - { - pvr->setRetainName(true); // don't dealloc texture on release - - _name = pvr->getName(); - _maxS = 1.0f; - _maxT = 1.0f; - _pixelsWide = pvr->getWidth(); - _pixelsHigh = pvr->getHeight(); - _contentSize = Size((float)_pixelsWide, (float)_pixelsHigh); - _hasPremultipliedAlpha = (pvr->isForcePremultipliedAlpha()) ? pvr->hasPremultipliedAlpha() : _PVRHaveAlphaPremultiplied; - _pixelFormat = pvr->getFormat(); - _hasMipmaps = pvr->getNumberOfMipmaps() > 1; - - pvr->release(); - } - else - { - CCLOG("cocos2d: Couldn't load PVR image %s", file); - } - - return bRet; -} - -bool Texture2D::initWithETCFile(const char* file) -{ - bool bRet = false; - // nothing to do with Object::init - - TextureETC *etc = new TextureETC; - bRet = etc->initWithFile(file); - - if (bRet) - { - _name = etc->getName(); - _maxS = 1.0f; - _maxT = 1.0f; - _pixelsWide = etc->getWidth(); - _pixelsHigh = etc->getHeight(); - _contentSize = Size((float)_pixelsWide, (float)_pixelsHigh); - _hasPremultipliedAlpha = true; - - etc->release(); - } - else - { - CCLOG("cocos2d: Couldn't load ETC image %s", file); - } - - return bRet; -} - void Texture2D::PVRImagesHavePremultipliedAlpha(bool haveAlphaPremultiplied) { - PVRHaveAlphaPremultiplied_ = haveAlphaPremultiplied; + _PVRHaveAlphaPremultiplied = haveAlphaPremultiplied; } @@ -813,10 +1261,10 @@ const char* Texture2D::getStringForFormat() const case Texture2D::PixelFormat::I8: return "I8"; - case Texture2D::PixelFormat::PRVTC4: + case Texture2D::PixelFormat::PVRTC4: return "PVRTC4"; - case Texture2D::PixelFormat::PRVTC2: + case Texture2D::PixelFormat::PVRTC2: return "PVRTC2"; default: @@ -845,47 +1293,12 @@ Texture2D::PixelFormat Texture2D::getDefaultAlphaPixelFormat() unsigned int Texture2D::getBitsPerPixelForFormat(Texture2D::PixelFormat format) const { - unsigned int ret=0; - - switch (format) { - case Texture2D::PixelFormat::RGBA8888: - ret = 32; - break; - case Texture2D::PixelFormat::RGB888: - // It is 32 and not 24, since its internal representation uses 32 bits. - ret = 32; - break; - case Texture2D::PixelFormat::RGB565: - ret = 16; - break; - case Texture2D::PixelFormat::RGBA4444: - ret = 16; - break; - case Texture2D::PixelFormat::RGB5A1: - ret = 16; - break; - case Texture2D::PixelFormat::AI88: - ret = 16; - break; - case Texture2D::PixelFormat::A8: - ret = 8; - break; - case Texture2D::PixelFormat::I8: - ret = 8; - break; - case Texture2D::PixelFormat::PRVTC4: - ret = 4; - break; - case Texture2D::PixelFormat::PRVTC2: - ret = 2; - break; - default: - ret = -1; - CCASSERT(false , "unrecognized pixel format"); - CCLOG("bitsPerPixelForFormat: %ld, cannot give useful result", (long)format); - break; - } - return ret; + if (format == PixelFormat::NONE) + { + return 0; + } + + return g_texturePixelFormatInfoTables.at(format).bpp; } unsigned int Texture2D::getBitsPerPixelForFormat() const diff --git a/cocos2dx/textures/CCTexture2D.h b/cocos2dx/textures/CCTexture2D.h index 926e16464b..5782a774d3 100644 --- a/cocos2dx/textures/CCTexture2D.h +++ b/cocos2dx/textures/CCTexture2D.h @@ -27,6 +27,8 @@ THE SOFTWARE. #define __CCTEXTURE2D_H__ #include +#include + #include "cocoa/CCObject.h" #include "cocoa/CCGeometry.h" #include "ccTypes.h" @@ -37,6 +39,7 @@ THE SOFTWARE. NS_CC_BEGIN class Image; +typedef struct _MipmapInfo MipmapInfo; /** * @addtogroup textures @@ -76,7 +79,10 @@ public: */ enum class PixelFormat { - + //! auto detect the type + AUTO, + //! 32-bit texture: BGRA8888 + BGRA8888, //! 32-bit texture: RGBA8888 RGBA8888, //! 24-bit texture: RGBA888 @@ -94,12 +100,20 @@ public: //! 16-bit textures: RGB5A1 RGB5A1, //! 4-bit PVRTC-compressed texture: PVRTC4 - PRVTC4, + PVRTC4, + //! 4-bit PVRTC-compressed texture: PVRTC4 (has alpha channel) + PVRTC4A, //! 2-bit PVRTC-compressed texture: PVRTC2 - PRVTC2, + PVRTC2, + //! 2-bit PVRTC-compressed texture: PVRTC2 (has alpha channel) + PVRTC2A, + //! ETC-compressed texture: ETC + ETC, - //! Default texture format: RGBA8888 - DEFAULT = RGBA8888 + //! Default texture format: AUTO + DEFAULT = AUTO, + + NONE = -1 }; /** sets the default pixel format for UIImagescontains alpha channel. @@ -148,7 +162,10 @@ public: void* keepData(void *data, unsigned int length); /** Initializes with a texture2d with data */ - bool initWithData(const void* data, Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const Size& contentSize); + bool initWithData(const void *data, int dataLen, Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const Size& contentSize); + + /** Initializes with mipmaps */ + bool initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh); /** Drawing extensions to make it easy to draw basic quads using a Texture2D object. @@ -161,22 +178,25 @@ public: /** Extensions to make it easy to create a Texture2D object from an image file. - Note that RGBA type textures will have their alpha premultiplied - use the blending mode (GL_ONE, GL_ONE_MINUS_SRC_ALPHA). */ - /** Initializes a texture from a UIImage object */ - + /** + Initializes a texture from a UIImage object. + We will use the format you specified with setDefaultAlphaPixelFormat to convert the image for texture. + NOTE: It will not convert the pvr image file. + */ bool initWithImage(Image * uiImage); + + /** + Initializes a texture from a UIImage object. + we will use the format you passed to the function to convert the image format to the texture format. + If you pass PixelFormat::Automatic, we will auto detect the image render type and use that type for texture to render. + **/ + bool initWithImage(Image * uiImage, PixelFormat format); /** Initializes a texture from a string with dimensions, alignment, font name and font size */ bool initWithString(const char *text, const char *fontName, float fontSize, const Size& dimensions = Size(0, 0), TextHAlignment hAlignment = TextHAlignment::CENTER, TextVAlignment vAlignment = TextVAlignment::TOP); /** Initializes a texture from a string using a text definition*/ bool initWithString(const char *text, const FontDefinition& textDefinition); - - /** Initializes a texture from a PVR file */ - bool initWithPVRFile(const char* file); - - /** Initializes a texture from a ETC file */ - bool initWithETCFile(const char* file); /** sets the min filter, mag filter, wrap s and wrap t texture parameters. If the texture size is NPOT (non power of 2), then in can only use GL_CLAMP_TO_EDGE in GL_TEXTURE_WRAP_{S,T}. @@ -267,10 +287,53 @@ public: GLProgram* getShaderProgram() const; private: - bool initPremultipliedATextureWithImage(Image * image, unsigned int pixelsWide, unsigned int pixelsHigh); - - // By default PVR images are treated as if they don't have the alpha channel premultiplied - bool _PVRHaveAlphaPremultiplied; + + /**convert functions*/ + + /** + Convert the format to the format param you specified, if the format is PixelFormat::Automatic, it will detect it automatically and convert to the closest format for you. + It will return the converted format to you. if the outData != data, you must delete it manually. + */ + static PixelFormat convertDataToFormat(const unsigned char* data, int dataLen, PixelFormat originFormat, PixelFormat format, unsigned char** outData, int* outDataLen); + + static PixelFormat convertI8ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen); + static PixelFormat convertAI88ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen); + static PixelFormat convertRGB888ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen); + static PixelFormat convertRGBA8888ToFormat(const unsigned char* data, int dataLen, PixelFormat format, unsigned char** outData, int* outDataLen); + + //I8 to XXX + static void convertI8ToRGB888(const unsigned char* in, int len, unsigned char* out); + static void convertI8ToRGBA8888(const unsigned char* in, int len, unsigned char* out); + static void convertI8ToRGB565(const unsigned char* in, int len, unsigned char* out); + static void convertI8ToRGBA4444(const unsigned char* in, int len, unsigned char* out); + static void convertI8ToRGB5A1(const unsigned char* in, int len, unsigned char* out); + static void convertI8ToAI88(const unsigned char* in, int len, unsigned char* out); + + //AI88 to XXX + static void convertAI88ToRGB888(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToRGBA8888(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToRGB565(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToRGBA4444(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToRGB5A1(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToA8(const unsigned char* in, int len, unsigned char* out); + static void convertAI88ToI8(const unsigned char* in, int len, unsigned char* out); + + //RGB888 to XXX + static void convertRGB888ToRGBA8888(const unsigned char* in, int len, unsigned char* out); + static void convertRGB888ToRGB565(const unsigned char* in, int len, unsigned char* out); + static void convertRGB888ToI8(const unsigned char* in, int len, unsigned char* out); + static void convertRGB888ToAI88(const unsigned char* in, int len, unsigned char* out); + static void convertRGB888ToRGBA4444(const unsigned char* in, int len, unsigned char* out); + static void convertRGB888ToRGB5A1(const unsigned char* in, int len, unsigned char* out); + + //RGBA8888 to XXX + static void convertRGBA8888ToRGB888(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToRGB565(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToI8(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToA8(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToAI88(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToRGBA4444(const unsigned char* in, int len, unsigned char* out); + static void convertRGBA8888ToRGB5A1(const unsigned char* in, int len, unsigned char* out); protected: /** pixel format of the texture */ @@ -303,6 +366,49 @@ protected: GLProgram* _shaderProgram; }; +class TexturePixelFormatInfo { +public: + GLenum internalFormat; + GLenum format; + GLenum type; + int bpp; + bool compressed; + bool alpha; + + TexturePixelFormatInfo(GLenum internalFormat, GLenum format, GLenum type, int bpp, bool compressed, bool alpha) + :internalFormat(internalFormat), format(format), type(type), bpp(bpp), compressed(compressed), alpha(alpha){} +}; + +typedef const std::map ConstTexturePixelFormatInfoMap; +typedef const ConstTexturePixelFormatInfoMap::value_type ConstTexturePixelFormatInfoMapValue; + +static ConstTexturePixelFormatInfoMapValue TexturePixelFormatInfoTablesValue[] = +{ + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::BGRA8888, TexturePixelFormatInfo(GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32, false, true)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::RGBA8888, TexturePixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, false, true)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::RGBA4444, TexturePixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, false, true)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::RGB5A1, TexturePixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, false, true)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::RGB565, TexturePixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, false, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::RGB888, TexturePixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 24, false, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::A8, TexturePixelFormatInfo(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, false, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::I8, TexturePixelFormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, false, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::AI88, TexturePixelFormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, false, true)), + +#ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC2, TexturePixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC2A, TexturePixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, true)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC4, TexturePixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)), + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC4A, TexturePixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, true)), +#endif + +#ifdef GL_ETC1_RGB8_OES + ConstTexturePixelFormatInfoMapValue(Texture2D::PixelFormat::ETC, TexturePixelFormatInfo(GL_ETC1_RGB8_OES, 0xFFFFFFFF, 0xFFFFFFFF, 24, true, false)), +#endif +}; + +static ConstTexturePixelFormatInfoMap g_texturePixelFormatInfoTables(TexturePixelFormatInfoTablesValue, + TexturePixelFormatInfoTablesValue + sizeof(TexturePixelFormatInfoTablesValue) / sizeof(TexturePixelFormatInfoTablesValue[0])); + // end of textures group /// @} diff --git a/cocos2dx/textures/CCTextureCache.cpp b/cocos2dx/textures/CCTextureCache.cpp index be124de3dc..ed906a68f8 100644 --- a/cocos2dx/textures/CCTextureCache.cpp +++ b/cocos2dx/textures/CCTextureCache.cpp @@ -205,20 +205,10 @@ void TextureCache::loadImage() } const char *filename = pAsyncStruct->filename.c_str(); - - // compute image type - Image::Format imageType = computeImageFormatType(pAsyncStruct->filename); - if (imageType == Image::Format::UNKOWN) - { - CCLOG("unsupported format %s",filename); - delete pAsyncStruct; - - continue; - } // generate image Image *pImage = new Image(); - if (pImage && !pImage->initWithImageFileThreadSafe(filename, imageType)) + if (pImage && !pImage->initWithImageFileThreadSafe(filename)) { CC_SAFE_RELEASE(pImage); CCLOG("can not load %s", filename); @@ -229,7 +219,6 @@ void TextureCache::loadImage() ImageInfo *pImageInfo = new ImageInfo(); pImageInfo->asyncStruct = pAsyncStruct; pImageInfo->image = pImage; - pImageInfo->imageType = imageType; // put the image info into the queue _imageInfoMutex.lock(); @@ -246,30 +235,6 @@ void TextureCache::loadImage() } } -Image::Format TextureCache::computeImageFormatType(string& filename) -{ - Image::Format ret = Image::Format::UNKOWN; - - if ((std::string::npos != filename.find(".jpg")) || (std::string::npos != filename.find(".jpeg"))) - { - ret = Image::Format::JPG; - } - else if ((std::string::npos != filename.find(".png")) || (std::string::npos != filename.find(".PNG"))) - { - ret = Image::Format::PNG; - } - else if ((std::string::npos != filename.find(".tiff")) || (std::string::npos != filename.find(".TIFF"))) - { - ret = Image::Format::TIFF; - } - else if ((std::string::npos != filename.find(".webp")) || (std::string::npos != filename.find(".WEBP"))) - { - ret = Image::Format::WEBP; - } - - return ret; -} - void TextureCache::addImageAsyncCallBack(float dt) { // the image is generated in loading thread @@ -300,7 +265,7 @@ void TextureCache::addImageAsyncCallBack(float dt) #if CC_ENABLE_CACHE_TEXTURE_DATA // cache the texture file name - VolatileTexture::addImageTexture(texture, filename, pImageInfo->imageType); + VolatileTexture::addImageTexture(texture, filename); #endif // cache the texture _textures->setObject(texture, filename); @@ -354,57 +319,27 @@ Texture2D * TextureCache::addImage(const char * path) // all images are handled by UIImage except PVR extension that is handled by our own handler do { - if (std::string::npos != lowerCase.find(".pvr")) + pImage = new Image(); + CC_BREAK_IF(NULL == pImage); + + bool bRet = pImage->initWithImageFile(fullpath.c_str()); + CC_BREAK_IF(!bRet); + + texture = new Texture2D(); + + if( texture && + texture->initWithImage(pImage) ) { - texture = this->addPVRImage(fullpath.c_str()); - } - else if (std::string::npos != lowerCase.find(".pkm")) - { - // ETC1 file format, only supportted on Android - texture = this->addETCImage(fullpath.c_str()); +#if CC_ENABLE_CACHE_TEXTURE_DATA + // cache the texture file name + VolatileTexture::addImageTexture(texture, fullpath.c_str()); +#endif + _textures->setObject(texture, pathKey.c_str()); + texture->release(); } else { - Image::Format eImageFormat = Image::Format::UNKOWN; - if (std::string::npos != lowerCase.find(".png")) - { - eImageFormat = Image::Format::PNG; - } - else if (std::string::npos != lowerCase.find(".jpg") || std::string::npos != lowerCase.find(".jpeg")) - { - eImageFormat = Image::Format::JPG; - } - else if (std::string::npos != lowerCase.find(".tif") || std::string::npos != lowerCase.find(".tiff")) - { - eImageFormat = Image::Format::TIFF; - } - else if (std::string::npos != lowerCase.find(".webp")) - { - eImageFormat = Image::Format::WEBP; - } - - pImage = new Image(); - CC_BREAK_IF(NULL == pImage); - - bool bRet = pImage->initWithImageFile(fullpath.c_str(), eImageFormat); - CC_BREAK_IF(!bRet); - - texture = new Texture2D(); - - if( texture && - texture->initWithImage(pImage) ) - { -#if CC_ENABLE_CACHE_TEXTURE_DATA - // cache the texture file name - VolatileTexture::addImageTexture(texture, fullpath.c_str(), eImageFormat); -#endif - _textures->setObject(texture, pathKey.c_str()); - texture->release(); - } - else - { - CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path); - } + CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path); } } while (0); } @@ -414,68 +349,6 @@ Texture2D * TextureCache::addImage(const char * path) return texture; } -Texture2D * TextureCache::addPVRImage(const char* path) -{ - CCASSERT(path != NULL, "TextureCache: fileimage MUST not be nil"); - - Texture2D* texture = NULL; - std::string key(path); - - if( (texture = (Texture2D*)_textures->objectForKey(key.c_str())) ) - { - return texture; - } - - // Split up directory and filename - std::string fullpath = FileUtils::getInstance()->fullPathForFilename(key.c_str()); - texture = new Texture2D(); - if(texture != NULL && texture->initWithPVRFile(fullpath.c_str()) ) - { -#if CC_ENABLE_CACHE_TEXTURE_DATA - // cache the texture file name - VolatileTexture::addImageTexture(texture, fullpath.c_str(), Image::Format::RAW_DATA); -#endif - _textures->setObject(texture, key.c_str()); - texture->autorelease(); - } - else - { - CCLOG("cocos2d: Couldn't add PVRImage:%s in TextureCache",key.c_str()); - CC_SAFE_DELETE(texture); - } - - return texture; -} - -Texture2D* TextureCache::addETCImage(const char* path) -{ - CCASSERT(path != NULL, "TextureCache: fileimage MUST not be nil"); - - Texture2D* texture = NULL; - std::string key(path); - - if( (texture = (Texture2D*)_textures->objectForKey(key.c_str())) ) - { - return texture; - } - - // Split up directory and filename - std::string fullpath = FileUtils::getInstance()->fullPathForFilename(key.c_str()); - texture = new Texture2D(); - if(texture != NULL && texture->initWithETCFile(fullpath.c_str())) - { - _textures->setObject(texture, key.c_str()); - texture->autorelease(); - } - else - { - CCLOG("cocos2d: Couldn't add ETCImage:%s in TextureCache",key.c_str()); - CC_SAFE_DELETE(texture); - } - - return texture; -} - Texture2D* TextureCache::addUIImage(Image *image, const char *key) { CCASSERT(image != NULL, "TextureCache: image MUST not be nil"); @@ -643,7 +516,6 @@ VolatileTexture::VolatileTexture(Texture2D *t) , _textureData(NULL) , _pixelFormat(Texture2D::PixelFormat::RGBA8888) , _fileName("") -, _fmtImage(Image::Format::PNG) , _text("") , _uiImage(NULL) { @@ -660,7 +532,7 @@ VolatileTexture::~VolatileTexture() CC_SAFE_RELEASE(_uiImage); } -void VolatileTexture::addImageTexture(Texture2D *tt, const char* imageFileName, Image::Format format) +void VolatileTexture::addImageTexture(Texture2D *tt, const char* imageFileName) { if (_isReloading) { @@ -671,7 +543,6 @@ void VolatileTexture::addImageTexture(Texture2D *tt, const char* imageFileName, vt->_cashedImageType = kImageFile; vt->_fileName = imageFileName; - vt->_fmtImage = format; vt->_pixelFormat = tt->getPixelFormat(); } @@ -705,7 +576,7 @@ VolatileTexture* VolatileTexture::findVolotileTexture(Texture2D *tt) return vt; } -void VolatileTexture::addDataTexture(Texture2D *tt, void* data, Texture2D::PixelFormat pixelFormat, const Size& contentSize) +void VolatileTexture::addDataTexture(Texture2D *tt, void* data, int dataLen, Texture2D::PixelFormat pixelFormat, const Size& contentSize) { if (_isReloading) { @@ -716,6 +587,7 @@ void VolatileTexture::addDataTexture(Texture2D *tt, void* data, Texture2D::Pixel vt->_cashedImageType = kImageData; vt->_textureData = data; + vt->_dataLen = dataLen; vt->_pixelFormat = pixelFormat; vt->_textureSize = contentSize; } @@ -777,42 +649,26 @@ void VolatileTexture::reloadAllTextures() { case kImageFile: { - std::string lowerCase(vt->_fileName.c_str()); - for (unsigned int i = 0; i < lowerCase.length(); ++i) - { - lowerCase[i] = tolower(lowerCase[i]); - } - - if (std::string::npos != lowerCase.find(".pvr")) + Image* pImage = new Image(); + unsigned long nSize = 0; + unsigned char* pBuffer = FileUtils::getInstance()->getFileData(vt->_fileName.c_str(), "rb", &nSize); + + if (pImage && pImage->initWithImageData((void*)pBuffer, nSize)) { Texture2D::PixelFormat oldPixelFormat = Texture2D::getDefaultAlphaPixelFormat(); Texture2D::setDefaultAlphaPixelFormat(vt->_pixelFormat); - - vt->_texture->initWithPVRFile(vt->_fileName.c_str()); + vt->_texture->initWithImage(pImage); Texture2D::setDefaultAlphaPixelFormat(oldPixelFormat); - } - else - { - Image* pImage = new Image(); - unsigned long nSize = 0; - unsigned char* pBuffer = FileUtils::getInstance()->getFileData(vt->_fileName.c_str(), "rb", &nSize); - - if (pImage && pImage->initWithImageData((void*)pBuffer, nSize, vt->_fmtImage)) - { - Texture2D::PixelFormat oldPixelFormat = Texture2D::getDefaultAlphaPixelFormat(); - Texture2D::setDefaultAlphaPixelFormat(vt->_pixelFormat); - vt->_texture->initWithImage(pImage); - Texture2D::setDefaultAlphaPixelFormat(oldPixelFormat); - } - - CC_SAFE_DELETE_ARRAY(pBuffer); - CC_SAFE_RELEASE(pImage); } + + CC_SAFE_DELETE_ARRAY(pBuffer); + CC_SAFE_RELEASE(pImage); } break; case kImageData: { - vt->_texture->initWithData(vt->_textureData, + vt->_texture->initWithData(vt->_textureData, + vt->_dataLen, vt->_pixelFormat, vt->_textureSize.width, vt->_textureSize.height, diff --git a/cocos2dx/textures/CCTextureCache.h b/cocos2dx/textures/CCTextureCache.h index 82d199609f..b443c80b4d 100644 --- a/cocos2dx/textures/CCTextureCache.h +++ b/cocos2dx/textures/CCTextureCache.h @@ -145,23 +145,10 @@ public: * @since v1.0 */ void dumpCachedTextureInfo(); - - /** Returns a Texture2D object given an PVR filename - * If the file image was not previously loaded, it will create a new Texture2D - * object and it will return it. Otherwise it will return a reference of a previously loaded image - */ - Texture2D* addPVRImage(const char* filename); - - /** Returns a Texture2D object given an ETC filename - * If the file image was not previously loaded, it will create a new Texture2D - * object and it will return it. Otherwise it will return a reference of a previously loaded image - */ - Texture2D* addETCImage(const char* filename); private: void addImageAsyncCallBack(float dt); void loadImage(); - Image::Format computeImageFormatType(std::string& filename); public: struct AsyncStruct @@ -179,7 +166,6 @@ protected: { AsyncStruct *asyncStruct; Image *image; - Image::Format imageType; } ImageInfo; std::thread* _loadingThread; @@ -218,9 +204,9 @@ public: VolatileTexture(Texture2D *t); ~VolatileTexture(); - static void addImageTexture(Texture2D *tt, const char* imageFileName, Image::Format format); + static void addImageTexture(Texture2D *tt, const char* imageFileName); static void addStringTexture(Texture2D *tt, const char* text, const FontDefinition& fontDefinition); - static void addDataTexture(Texture2D *tt, void* data, Texture2D::PixelFormat pixelFormat, const Size& contentSize); + static void addDataTexture(Texture2D *tt, void* data, int dataLen, Texture2D::PixelFormat pixelFormat, const Size& contentSize); static void addImage(Texture2D *tt, Image *image); static void setTexParameters(Texture2D *t, const ccTexParams &texParams); @@ -244,11 +230,11 @@ protected: ccCachedImageType _cashedImageType; void *_textureData; + int _dataLen; Size _textureSize; Texture2D::PixelFormat _pixelFormat; std::string _fileName; - Image::Format _fmtImage; ccTexParams _texParams; std::string _text; diff --git a/cocos2dx/textures/CCTextureETC.cpp b/cocos2dx/textures/CCTextureETC.cpp deleted file mode 100644 index 0f19b13b19..0000000000 --- a/cocos2dx/textures/CCTextureETC.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 cocos2d-x.org - - 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 - 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 "CCTextureETC.h" -#include "platform/CCPlatformConfig.h" -#include "platform/CCFileUtils.h" -#include "CCConfiguration.h" -#include "etc/etc1.h" - -#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) -#include "platform/android/jni/JniHelper.h" -#endif - -NS_CC_BEGIN - -TextureETC::TextureETC() -: _name(0) -, _width(0) -, _height(0) -{} - -TextureETC::~TextureETC() -{ -} - -bool TextureETC::initWithFile(const char *file) -{ - return loadTexture(FileUtils::getInstance()->fullPathForFilename(file).c_str()); -} - -unsigned int TextureETC::getName() const -{ - return _name; -} - -unsigned int TextureETC::getWidth() const -{ - return _width; -} - -unsigned int TextureETC::getHeight() const -{ - return _height; -} - -// Call back function for java -#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) -#define LOG_TAG "CCTextureETC.cpp" -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) - -static unsigned int sWidth = 0; -static unsigned int sHeight = 0; -static unsigned char *sData = NULL; -static unsigned int sLength = 0; - -extern "C" -{ - JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxETCLoader_nativeSetTextureInfo(JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray data, jint dataLength) - { - sWidth = (unsigned int)width; - sHeight = (unsigned int)height; - sLength = dataLength; - sData = new unsigned char[sLength]; - env->GetByteArrayRegion(data, 0, sLength, (jbyte*)sData); - } -} -#endif - -bool TextureETC::loadTexture(const char* file) -{ - unsigned long etcFileSize = 0; - etc1_byte* etcFileData = NULL; - etcFileData = FileUtils::getInstance()->getFileData(file, "rb", &etcFileSize); - - if(0 == etcFileSize) - { - return false; - } - - if(!etc1_pkm_is_valid(etcFileData)) - { - delete[] etcFileData; - etcFileData = NULL; - return false; - } - - _width = etc1_pkm_get_width(etcFileData); - _height = etc1_pkm_get_height(etcFileData); - - if( 0 == _width || 0 == _height ) - { - delete[] etcFileData; - etcFileData = NULL; - return false; - } - - if(Configuration::getInstance()->supportsETC()) - { - //old opengl version has no define for GL_ETC1_RGB8_OES, add macro to make compiler happy. -#ifdef GL_ETC1_RGB8_OES - glGenTextures(1, &_name); - glBindTexture(GL_TEXTURE_2D, _name); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES, _width, _height, 0, etcFileSize - ETC_PKM_HEADER_SIZE, - etcFileData + ETC_PKM_HEADER_SIZE); - - glBindTexture(GL_TEXTURE_2D, 0); - - delete[] etcFileData; - etcFileData = NULL; - return true; -#endif - } - else - { - //if it is not gles or device do not support ETC, decode texture by software - int bytePerPixel = 3; - GLenum fallBackType = GL_UNSIGNED_BYTE; - - /*bool fallBackUseShort = false; - if(fallBackUseShort) - { - bytePerPixel = 2; - fallBackType = GL_UNSIGNED_SHORT_5_6_5; - } - */ - unsigned int stride = _width * bytePerPixel; - - std::vector decodeImageData(stride * _height); - - etc1_decode_image(etcFileData + ETC_PKM_HEADER_SIZE, &decodeImageData[0], _width, _height, bytePerPixel, stride); - - //set decoded data to gl - glGenTextures(1, &_name); - glBindTexture(GL_TEXTURE_2D, _name); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, fallBackType, &decodeImageData[0]); - glBindTexture(GL_TEXTURE_2D, 0); - delete[] etcFileData; - etcFileData = NULL; - return true; - } - return false; -} - -NS_CC_END diff --git a/cocos2dx/tilemap_parallax_nodes/CCTMXLayer.cpp b/cocos2dx/tilemap_parallax_nodes/CCTMXLayer.cpp index 4929e12d70..61bd2a07b4 100644 --- a/cocos2dx/tilemap_parallax_nodes/CCTMXLayer.cpp +++ b/cocos2dx/tilemap_parallax_nodes/CCTMXLayer.cpp @@ -98,14 +98,21 @@ bool TMXLayer::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *la } TMXLayer::TMXLayer() -:_layerSize(Size::ZERO) +:_layerName("") +,_opacity(0) +,_minGID(0) +,_maxGID(0) +,_vertexZvalue(0) +,_useAutomaticVertexZ(false) +,_reusedTile(NULL) +,_atlasIndexArray(NULL) +,_contentScaleFactor(1.0f) +,_layerSize(Size::ZERO) ,_mapTileSize(Size::ZERO) ,_tiles(NULL) ,_tileSet(NULL) +,_layerOrientation(TMXOrientationOrtho) ,_properties(NULL) -,_layerName("") -,_reusedTile(NULL) -,_atlasIndexArray(NULL) {} TMXLayer::~TMXLayer() diff --git a/cocos2dx/tilemap_parallax_nodes/CCTMXObjectGroup.cpp b/cocos2dx/tilemap_parallax_nodes/CCTMXObjectGroup.cpp index 12fce07617..b4652873a4 100644 --- a/cocos2dx/tilemap_parallax_nodes/CCTMXObjectGroup.cpp +++ b/cocos2dx/tilemap_parallax_nodes/CCTMXObjectGroup.cpp @@ -32,8 +32,8 @@ NS_CC_BEGIN //implementation TMXObjectGroup TMXObjectGroup::TMXObjectGroup() - :_positionOffset(Point::ZERO) - ,_groupName("") + : _groupName("") + , _positionOffset(Point::ZERO) { _objects = Array::create(); _objects->retain(); diff --git a/cocos2dx/tilemap_parallax_nodes/CCTileMapAtlas.cpp b/cocos2dx/tilemap_parallax_nodes/CCTileMapAtlas.cpp index 483e607f85..8adfec66de 100644 --- a/cocos2dx/tilemap_parallax_nodes/CCTileMapAtlas.cpp +++ b/cocos2dx/tilemap_parallax_nodes/CCTileMapAtlas.cpp @@ -65,9 +65,9 @@ bool TileMapAtlas::initWithTileFile(const char *tile, const char *mapFile, int t } TileMapAtlas::TileMapAtlas() - :_TGAInfo(NULL) - ,_posToAtlasIndex(NULL) - ,_itemsToRender(0) + : _posToAtlasIndex(NULL) + , _itemsToRender(0) + , _TGAInfo(NULL) { } diff --git a/extensions/AssetsManager/AssetsManager.cpp b/extensions/AssetsManager/AssetsManager.cpp index e1e5a06ec5..ac0ca37dac 100644 --- a/extensions/AssetsManager/AssetsManager.cpp +++ b/extensions/AssetsManager/AssetsManager.cpp @@ -205,7 +205,11 @@ void AssetsManager::update() } // Check if there is a new version. - if (! checkUpdate()) return; + if (! checkUpdate()) + { + _isDownloading = false; + return; + } // Is package already downloaded? _downloadedVersion = UserDefault::getInstance()->getStringForKey(KEY_OF_DOWNLOADED_VERSION); diff --git a/extensions/AssetsManager/AssetsManager.h b/extensions/AssetsManager/AssetsManager.h index afe6efc62f..b150e073e0 100644 --- a/extensions/AssetsManager/AssetsManager.h +++ b/extensions/AssetsManager/AssetsManager.h @@ -139,12 +139,6 @@ public: */ friend int assetsManagerProgressFunc(void *, double, double, double, double); - // Backward compatibility - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kCCCreateFile = ErrorCode::CREATE_FILE; - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kCCNetwork = ErrorCode::NETWORK; - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kCCNoNewVersion = ErrorCode::NO_NEW_VERSION; - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kCCUncompress = ErrorCode::UNCOMPRESS; - protected: bool downLoad(); void checkStoragePath(); diff --git a/extensions/CCArmature/external_tool/CCTexture2DMutable.cpp b/extensions/CCArmature/external_tool/CCTexture2DMutable.cpp index 63c607be18..53a7efd747 100644 --- a/extensions/CCArmature/external_tool/CCTexture2DMutable.cpp +++ b/extensions/CCArmature/external_tool/CCTexture2DMutable.cpp @@ -46,7 +46,7 @@ bool Texture2DMutable::initWithImageFile(const char *imageFile, cocos2d::Texture image_->initWithImageFile(imageFile); - return initWithData(image_->getData(), pixelFormat, pixelsWide, pixelsHigh, contentSize); + return initWithData(image_->getData(), image_->getDataLen(), pixelFormat, pixelsWide, pixelsHigh, contentSize); } bool Texture2DMutable::initWithImageFile(const char *imageFile) @@ -56,7 +56,7 @@ bool Texture2DMutable::initWithImageFile(const char *imageFile) bool hasAlpha = image_->hasAlpha(); Size imageSize = Size((float)(image_->getWidth()), (float)(image_->getHeight())); - size_t bpp = image_->getBitsPerComponent(); + size_t bpp = image_->getBitPerPixel(); cocos2d::Texture2D::PixelFormat pixelFormat; // compute pixel format @@ -77,12 +77,12 @@ bool Texture2DMutable::initWithImageFile(const char *imageFile) } - return initWithData(image_->getData(), pixelFormat, imageSize.width, imageSize.height, imageSize); + return initWithData(image_->getData(), image_->getDataLen(), pixelFormat, imageSize.width, imageSize.height, imageSize); } -bool Texture2DMutable::initWithData(const void* data, Texture2D::PixelFormat pixelFormat, unsigned int width, unsigned int height, const Size& size) +bool Texture2DMutable::initWithData(const void* data, int dataLen, Texture2D::PixelFormat pixelFormat, unsigned int width, unsigned int height, const Size& size) { - if(!Texture2D::initWithData(data, pixelFormat, width, height, size)) { + if(!Texture2D::initWithData(data, dataLen, pixelFormat, width, height, size)) { return false; } @@ -215,14 +215,14 @@ Texture2D* Texture2DMutable::copyMutable(bool isMutable ) void *newData = malloc(mem); memcpy(newData, data_, mem); co = new Texture2DMutable(); - if (!co->initWithData(newData, _pixelFormat, _pixelsWide, _pixelsHigh, _contentSize)) { + if (!co->initWithData(newData, mem, _pixelFormat, _pixelsWide, _pixelsHigh, _contentSize)) { delete co; co = NULL; } }else { co = new Texture2D(); - if (!co->initWithData(data_, _pixelFormat, _pixelsWide, _pixelsHigh, _contentSize)) { + if (!co->initWithData(data_, _pixelsWide*_pixelsHigh*bytesPerPixel_, _pixelFormat, _pixelsWide, _pixelsHigh, _contentSize)) { delete co; co = NULL; } diff --git a/extensions/CCArmature/external_tool/CCTexture2DMutable.h b/extensions/CCArmature/external_tool/CCTexture2DMutable.h index dfcbd6cd6d..27d8c24560 100644 --- a/extensions/CCArmature/external_tool/CCTexture2DMutable.h +++ b/extensions/CCArmature/external_tool/CCTexture2DMutable.h @@ -45,7 +45,7 @@ public: bool initWithImageFile(const char *imageFilex); /** Intializes with a texture2d with data */ - bool initWithData(const void* data, cocos2d::Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const cocos2d::Size& contentSize); + bool initWithData(const void* data, int dataLen, cocos2d::Texture2D::PixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const cocos2d::Size& contentSize); cocos2d::Color4B pixelAt(const cocos2d::Point& pt); diff --git a/extensions/CCArmature/physics/CCPhysicsWorld.cpp b/extensions/CCArmature/physics/CCPhysicsWorld.cpp index 644c604ca3..0ccf8eb617 100644 --- a/extensions/CCArmature/physics/CCPhysicsWorld.cpp +++ b/extensions/CCArmature/physics/CCPhysicsWorld.cpp @@ -41,7 +41,7 @@ public: class ContactListener : public b2ContactListener { //! Callbacks for derived classes. - virtual void BeginContact(b2Contact *contact) + virtual void BeginContact(b2Contact *contact) override { if (contact) { @@ -53,17 +53,17 @@ class ContactListener : public b2ContactListener } B2_NOT_USED(contact); } - virtual void EndContact(b2Contact *contact) + virtual void EndContact(b2Contact *contact) override { contact_list.clear(); B2_NOT_USED(contact); } - virtual void PreSolve(b2Contact *contact, const b2Manifold *oldManifold) + virtual void PreSolve(b2Contact *contact, const b2Manifold *oldManifold) override { B2_NOT_USED(contact); B2_NOT_USED(oldManifold); } - virtual void PostSolve(const b2Contact *contact, const b2ContactImpulse *impulse) + virtual void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) override { B2_NOT_USED(contact); B2_NOT_USED(impulse); diff --git a/extensions/CCBReader/CCBAnimationManager.cpp b/extensions/CCBReader/CCBAnimationManager.cpp index 24476de243..bd30b0a168 100644 --- a/extensions/CCBReader/CCBAnimationManager.cpp +++ b/extensions/CCBReader/CCBAnimationManager.cpp @@ -17,35 +17,36 @@ NS_CC_EXT_BEGIN // Implementation of CCBAinmationManager CCBAnimationManager::CCBAnimationManager() -: mSequences(NULL) -, mNodeSequences(NULL) -, mBaseValues(NULL) -, mAutoPlaySequenceId(0) -, mRootNode(NULL) -, mRootContainerSize(Size::ZERO) -, mDelegate(NULL) -, mRunningSequence(NULL) -, jsControlled(false) -, mOwner(NULL) +: _jsControlled(false) +, _owner(NULL) +, _sequences(NULL) +, _nodeSequences(NULL) +, _baseValues(NULL) +, _autoPlaySequenceId(0) +, _rootNode(NULL) +, _rootContainerSize(Size::ZERO) +, _delegate(NULL) +, _runningSequence(NULL) + { init(); } bool CCBAnimationManager::init() { - mSequences = new Array(); - mNodeSequences = new Dictionary(); - mBaseValues = new Dictionary(); + _sequences = new Array(); + _nodeSequences = new Dictionary(); + _baseValues = new Dictionary(); - mDocumentOutletNames = new Array(); - mDocumentOutletNodes = new Array(); - mDocumentCallbackNames = new Array(); - mDocumentCallbackNodes = new Array(); - mKeyframeCallbacks = new Array(); - mKeyframeCallFuncs = new Dictionary(); + _documentOutletNames = new Array(); + _documentOutletNodes = new Array(); + _documentCallbackNames = new Array(); + _documentCallbackNodes = new Array(); + _keyframeCallbacks = new Array(); + _keyframeCallFuncs = new Dictionary(); - mTarget = NULL; - mAnimationCompleteCallbackFunc = NULL; + _target = NULL; + _animationCompleteCallbackFunc = NULL; return true; } @@ -53,141 +54,141 @@ bool CCBAnimationManager::init() CCBAnimationManager::~CCBAnimationManager() { // DictElement *pElement = NULL; -// CCDICT_FOREACH(mNodeSequences, pElement) +// CCDICT_FOREACH(_nodeSequences, pElement) // { // Node *node = (Node*)pElement->getIntKey(); // node->release(); // } // -// CCDICT_FOREACH(mBaseValues, pElement) +// CCDICT_FOREACH(_baseValues, pElement) // { // Node *node = (Node*)pElement->getIntKey(); // node->release(); // } - mNodeSequences->release(); - mBaseValues->release(); - mSequences->release(); + _nodeSequences->release(); + _baseValues->release(); + _sequences->release(); setRootNode(NULL); setDelegate(NULL); - CC_SAFE_RELEASE(mDocumentOutletNames); - CC_SAFE_RELEASE(mDocumentOutletNodes); - CC_SAFE_RELEASE(mDocumentCallbackNames); - CC_SAFE_RELEASE(mDocumentCallbackNodes); + CC_SAFE_RELEASE(_documentOutletNames); + CC_SAFE_RELEASE(_documentOutletNodes); + CC_SAFE_RELEASE(_documentCallbackNames); + CC_SAFE_RELEASE(_documentCallbackNodes); - CC_SAFE_RELEASE(mKeyframeCallFuncs); - CC_SAFE_RELEASE(mKeyframeCallbacks); - CC_SAFE_RELEASE(mTarget); + CC_SAFE_RELEASE(_keyframeCallFuncs); + CC_SAFE_RELEASE(_keyframeCallbacks); + CC_SAFE_RELEASE(_target); } Array* CCBAnimationManager::getSequences() { - return mSequences; + return _sequences; } void CCBAnimationManager::setSequences(Array* seq) { - mSequences = seq; + _sequences = seq; } int CCBAnimationManager::getAutoPlaySequenceId() { - return mAutoPlaySequenceId; + return _autoPlaySequenceId; } void CCBAnimationManager::setAutoPlaySequenceId(int autoPlaySequenceId) { - mAutoPlaySequenceId = autoPlaySequenceId; + _autoPlaySequenceId = autoPlaySequenceId; } Node* CCBAnimationManager::getRootNode() { - return mRootNode; + return _rootNode; } void CCBAnimationManager::setRootNode(Node *pRootNode) { - mRootNode = pRootNode; + _rootNode = pRootNode; } void CCBAnimationManager::setDocumentControllerName(const std::string &name) { - mDocumentControllerName = name; + _documentControllerName = name; } std::string CCBAnimationManager::getDocumentControllerName() { - return mDocumentControllerName; + return _documentControllerName; } void CCBAnimationManager::addDocumentCallbackNode(Node *node) { - mDocumentCallbackNodes->addObject(node); + _documentCallbackNodes->addObject(node); } void CCBAnimationManager::addDocumentCallbackName(std::string name) { String *tmpName = String::create(name); - mDocumentCallbackNames->addObject(tmpName); + _documentCallbackNames->addObject(tmpName); } Array* CCBAnimationManager::getDocumentCallbackNames() { - return mDocumentCallbackNames; + return _documentCallbackNames; } Array* CCBAnimationManager::getDocumentCallbackNodes() { - return mDocumentCallbackNodes; + return _documentCallbackNodes; } void CCBAnimationManager::addDocumentOutletNode(Node *node) { - mDocumentOutletNodes->addObject(node); + _documentOutletNodes->addObject(node); } void CCBAnimationManager::addDocumentOutletName(std::string name) { - mDocumentOutletNames->addObject(String::create(name)); + _documentOutletNames->addObject(String::create(name)); } Array* CCBAnimationManager::getDocumentOutletNames() { - return mDocumentOutletNames; + return _documentOutletNames; } Array* CCBAnimationManager::getDocumentOutletNodes() { - return mDocumentOutletNodes; + return _documentOutletNodes; } std::string CCBAnimationManager::getLastCompletedSequenceName() { - return lastCompletedSequenceName; + return _lastCompletedSequenceName; } Array* CCBAnimationManager::getKeyframeCallbacks() { - return mKeyframeCallbacks; + return _keyframeCallbacks; } const Size& CCBAnimationManager::getRootContainerSize() { - return mRootContainerSize; + return _rootContainerSize; } void CCBAnimationManager::setRootContainerSize(const Size &rootContainerSize) { - mRootContainerSize.setSize(rootContainerSize.width, rootContainerSize.height); + _rootContainerSize.setSize(rootContainerSize.width, rootContainerSize.height); } CCBAnimationManagerDelegate* CCBAnimationManager::getDelegate() { - return mDelegate; + return _delegate; } void CCBAnimationManager::setDelegate(CCBAnimationManagerDelegate *pDelegate) { - CC_SAFE_RELEASE(dynamic_cast(mDelegate)); - mDelegate = pDelegate; - CC_SAFE_RETAIN(dynamic_cast(mDelegate)); + CC_SAFE_RELEASE(dynamic_cast(_delegate)); + _delegate = pDelegate; + CC_SAFE_RETAIN(dynamic_cast(_delegate)); } const char* CCBAnimationManager::getRunningSequenceName() { - if (mRunningSequence) + if (_runningSequence) { - return mRunningSequence->getName(); + return _runningSequence->getName(); } return NULL; } @@ -200,7 +201,7 @@ const Size& CCBAnimationManager::getContainerSize(Node *pNode) } else { - return mRootContainerSize; + return _rootContainerSize; } } @@ -209,34 +210,34 @@ void CCBAnimationManager::addNode(Node *pNode, Dictionary *pSeq) { // pNode->retain(); - mNodeSequences->setObject(pSeq, (intptr_t)pNode); + _nodeSequences->setObject(pSeq, (intptr_t)pNode); } -void CCBAnimationManager::setBaseValue(Object *pValue, Node *pNode, const char *pPropName) +void CCBAnimationManager::setBaseValue(Object *pValue, Node *pNode, const char *propName) { - Dictionary *props = (Dictionary*)mBaseValues->objectForKey((intptr_t)pNode); + Dictionary *props = (Dictionary*)_baseValues->objectForKey((intptr_t)pNode); if (! props) { props = Dictionary::create(); - mBaseValues->setObject(props, (intptr_t)pNode); + _baseValues->setObject(props, (intptr_t)pNode); // pNode->retain(); } - props->setObject(pValue, pPropName); + props->setObject(pValue, propName); } -Object* CCBAnimationManager::getBaseValue(Node *pNode, const char* pPropName) +Object* CCBAnimationManager::getBaseValue(Node *pNode, const char* propName) { - Dictionary *props = (Dictionary*)mBaseValues->objectForKey((intptr_t)pNode); + Dictionary *props = (Dictionary*)_baseValues->objectForKey((intptr_t)pNode); - return props->objectForKey(pPropName); + return props->objectForKey(propName); } int CCBAnimationManager::getSequenceId(const char* pSequenceName) { Object *pElement = NULL; string seqName(pSequenceName); - CCARRAY_FOREACH(mSequences, pElement) + CCARRAY_FOREACH(_sequences, pElement) { CCBSequence *seq = static_cast(pElement); if (seqName.compare(seq->getName()) == 0) @@ -250,7 +251,7 @@ int CCBAnimationManager::getSequenceId(const char* pSequenceName) CCBSequence* CCBAnimationManager::getSequence(int nSequenceId) { Object *pElement = NULL; - CCARRAY_FOREACH(mSequences, pElement) + CCARRAY_FOREACH(_sequences, pElement) { CCBSequence *seq = static_cast(pElement); if (seq->getSequenceId() == nSequenceId) @@ -265,20 +266,20 @@ CCBSequence* CCBAnimationManager::getSequence(int nSequenceId) void CCBAnimationManager::moveAnimationsFromNode(Node* fromNode, Node* toNode) { // Move base values - Object* baseValue = mBaseValues->objectForKey((intptr_t)fromNode); + Object* baseValue = _baseValues->objectForKey((intptr_t)fromNode); if(baseValue) { - mBaseValues->setObject(baseValue, (intptr_t)toNode); - mBaseValues->removeObjectForKey((intptr_t)fromNode); + _baseValues->setObject(baseValue, (intptr_t)toNode); + _baseValues->removeObjectForKey((intptr_t)fromNode); // fromNode->release(); // toNode->retain(); } // Move seqs - Object *seqs = mNodeSequences->objectForKey((intptr_t)fromNode); + Object *seqs = _nodeSequences->objectForKey((intptr_t)fromNode); if(seqs) { - mNodeSequences->setObject(seqs, (intptr_t)toNode); - mNodeSequences->removeObjectForKey((intptr_t)fromNode); + _nodeSequences->setObject(seqs, (intptr_t)toNode); + _nodeSequences->removeObjectForKey((intptr_t)fromNode); // fromNode->release(); // toNode->retain(); @@ -286,38 +287,38 @@ void CCBAnimationManager::moveAnimationsFromNode(Node* fromNode, Node* toNode) { } // Refer to CCBReader::readKeyframe() for the real type of value -ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyframe *pKeyframe1, const char *pPropName, Node *pNode) +ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyframe *pKeyframe1, const char *propName, Node *pNode) { float duration = pKeyframe1->getTime() - (pKeyframe0 ? pKeyframe0->getTime() : 0); - if (strcmp(pPropName, "rotationX") == 0) + if (strcmp(propName, "rotationX") == 0) { CCBValue *value = (CCBValue*)pKeyframe1->getValue(); return CCBRotateXTo::create(duration, value->getFloatValue()); } - else if(strcmp(pPropName, "rotationY") == 0) + else if(strcmp(propName, "rotationY") == 0) { CCBValue *value = (CCBValue*)pKeyframe1->getValue(); return CCBRotateYTo::create(duration, value->getFloatValue()); } - else if (strcmp(pPropName, "rotation") == 0) + else if (strcmp(propName, "rotation") == 0) { CCBValue *value = (CCBValue*)pKeyframe1->getValue(); return CCBRotateTo::create(duration, value->getFloatValue()); } - else if (strcmp(pPropName, "opacity") == 0) + else if (strcmp(propName, "opacity") == 0) { CCBValue *value = (CCBValue*)pKeyframe1->getValue(); return FadeTo::create(duration, value->getByteValue()); } - else if (strcmp(pPropName, "color") == 0) + else if (strcmp(propName, "color") == 0) { Color3BWapper* color = (Color3BWapper*)pKeyframe1->getValue(); Color3B c = color->getColor(); return TintTo::create(duration, c.r, c.g, c.b); } - else if (strcmp(pPropName, "visible") == 0) + else if (strcmp(propName, "visible") == 0) { CCBValue *value = (CCBValue*)pKeyframe1->getValue(); if (value->getBoolValue()) @@ -329,40 +330,40 @@ ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyfr return Sequence::createWithTwoActions(DelayTime::create(duration), Hide::create()); } } - else if (strcmp(pPropName, "displayFrame") == 0) + else if (strcmp(propName, "displayFrame") == 0) { return Sequence::createWithTwoActions(DelayTime::create(duration), CCBSetSpriteFrame::create((SpriteFrame *)pKeyframe1->getValue())); } - else if (strcmp(pPropName, "position") == 0) + else if (strcmp(propName, "position") == 0) { // Get position type - Array *array = (Array*)getBaseValue(pNode, pPropName); - int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue(); + Array *array = static_cast(getBaseValue(pNode, propName)); + CCBReader::PositionType type = (CCBReader::PositionType)((CCBValue*)array->objectAtIndex(2))->getIntValue(); // Get relative position - Array *value = (Array*)pKeyframe1->getValue(); + Array *value = static_cast(pKeyframe1->getValue()); float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue(); float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue(); Size containerSize = getContainerSize(pNode->getParent()); - Point absPos = getAbsolutePosition(Point(x,y), type, containerSize, pPropName); + Point absPos = getAbsolutePosition(Point(x,y), type, containerSize, propName); return MoveTo::create(duration, absPos); } - else if (strcmp(pPropName, "scale") == 0) + else if (strcmp(propName, "scale") == 0) { // Get position type - Array *array = (Array*)getBaseValue(pNode, pPropName); - int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue(); + Array *array = (Array*)getBaseValue(pNode, propName); + CCBReader::ScaleType type = (CCBReader::ScaleType)((CCBValue*)array->objectAtIndex(2))->getIntValue(); // Get relative scale Array *value = (Array*)pKeyframe1->getValue(); float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue(); float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue(); - if (type == kCCBScaleTypeMultiplyResolution) + if (type == CCBReader::ScaleType::MULTIPLY_RESOLUTION) { float resolutionScale = CCBReader::getResolutionScale(); x *= resolutionScale; @@ -371,7 +372,7 @@ ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyfr return ScaleTo::create(duration, x, y); } - else if(strcmp(pPropName, "skew") == 0) + else if(strcmp(propName, "skew") == 0) { // Get relative skew Array *value = (Array*)pKeyframe1->getValue(); @@ -382,13 +383,13 @@ ActionInterval* CCBAnimationManager::getAction(CCBKeyframe *pKeyframe0, CCBKeyfr } else { - log("CCBReader: Failed to create animation for property: %s", pPropName); + log("CCBReader: Failed to create animation for property: %s", propName); } return NULL; } -void CCBAnimationManager::setAnimatedProperty(const char *pPropName, Node *pNode, Object *pValue, float fTweenDuration) +void CCBAnimationManager::setAnimatedProperty(const char *propName, Node *pNode, Object *pValue, float fTweenDuration) { if (fTweenDuration > 0) { @@ -397,43 +398,43 @@ void CCBAnimationManager::setAnimatedProperty(const char *pPropName, Node *pNode kf1->autorelease(); kf1->setValue(pValue); kf1->setTime(fTweenDuration); - kf1->setEasingType(kCCBKeyframeEasingLinear); + kf1->setEasingType(CCBKeyframe::EasingType::LINEAR); // Animate - ActionInterval *tweenAction = getAction(NULL, kf1, pPropName, pNode); + ActionInterval *tweenAction = getAction(NULL, kf1, propName, pNode); pNode->runAction(tweenAction); } else { // Just set the value - if (strcmp(pPropName, "position") == 0) + if (strcmp(propName, "position") == 0) { // Get position type - Array *array = (Array*)getBaseValue(pNode, pPropName); - int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue(); + Array *array = (Array*)getBaseValue(pNode, propName); + CCBReader::PositionType type = (CCBReader::PositionType)((CCBValue*)array->objectAtIndex(2))->getIntValue(); // Get relative position Array *value = (Array*)pValue; float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue(); float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue(); - pNode->setPosition(getAbsolutePosition(Point(x,y), type, getContainerSize(pNode->getParent()), pPropName)); + pNode->setPosition(getAbsolutePosition(Point(x,y), type, getContainerSize(pNode->getParent()), propName)); } - else if (strcmp(pPropName, "scale") == 0) + else if (strcmp(propName, "scale") == 0) { // Get scale type - Array *array = (Array*)getBaseValue(pNode, pPropName); - int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue(); + Array *array = (Array*)getBaseValue(pNode, propName); + CCBReader::ScaleType type = (CCBReader::ScaleType)((CCBValue*)array->objectAtIndex(2))->getIntValue(); // Get relative scale Array *value = (Array*)pValue; float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue(); float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue(); - setRelativeScale(pNode, x, y, type, pPropName); + setRelativeScale(pNode, x, y, type, propName); } - else if(strcmp(pPropName, "skew") == 0) + else if(strcmp(propName, "skew") == 0) { // Get relative scale Array *value = (Array*)pValue; @@ -448,41 +449,41 @@ void CCBAnimationManager::setAnimatedProperty(const char *pPropName, Node *pNode // [node setValue:value forKey:name]; // TODO only handle rotation, opacity, displayFrame, color - if (strcmp(pPropName, "rotation") == 0) + if (strcmp(propName, "rotation") == 0) { float rotate = ((CCBValue*)pValue)->getFloatValue(); pNode->setRotation(rotate); - } else if(strcmp(pPropName, "rotationX") == 0) + } else if(strcmp(propName, "rotationX") == 0) { float rotate = ((CCBValue*)pValue)->getFloatValue(); pNode->setRotationX(rotate); - }else if(strcmp(pPropName, "rotationY") == 0) + }else if(strcmp(propName, "rotationY") == 0) { float rotate = ((CCBValue*)pValue)->getFloatValue(); pNode->setRotationY(rotate); } - else if (strcmp(pPropName, "opacity") == 0) + else if (strcmp(propName, "opacity") == 0) { int opacity = ((CCBValue*)pValue)->getByteValue(); (dynamic_cast(pNode))->setOpacity(opacity); } - else if (strcmp(pPropName, "displayFrame") == 0) + else if (strcmp(propName, "displayFrame") == 0) { ((Sprite*)pNode)->setDisplayFrame((SpriteFrame*)pValue); } - else if (strcmp(pPropName, "color") == 0) + else if (strcmp(propName, "color") == 0) { Color3BWapper *color = (Color3BWapper*)pValue; (dynamic_cast(pNode))->setColor(color->getColor()); } - else if (strcmp(pPropName, "visible") == 0) + else if (strcmp(propName, "visible") == 0) { bool visible = ((CCBValue*)pValue)->getBoolValue(); pNode->setVisible(visible); } else { - log("unsupported property name is %s", pPropName); + log("unsupported property name is %s", propName); CCASSERT(false, "unsupported property now"); } } @@ -508,72 +509,72 @@ void CCBAnimationManager::setFirstFrame(Node *pNode, CCBSequenceProperty *pSeqPr } } -ActionInterval* CCBAnimationManager::getEaseAction(ActionInterval *pAction, int nEasingType, float fEasingOpt) +ActionInterval* CCBAnimationManager::getEaseAction(ActionInterval *pAction, CCBKeyframe::EasingType easingType, float fEasingOpt) { if (dynamic_cast(pAction)) { return pAction; } - if (nEasingType == kCCBKeyframeEasingLinear) + if (easingType == CCBKeyframe::EasingType::LINEAR) { return pAction; } - else if (nEasingType == kCCBKeyframeEasingInstant) + else if (easingType == CCBKeyframe::EasingType::INSTANT) { return CCBEaseInstant::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingCubicIn) + else if (easingType == CCBKeyframe::EasingType::CUBIC_IN) { return EaseIn::create(pAction, fEasingOpt); } - else if (nEasingType == kCCBKeyframeEasingCubicOut) + else if (easingType == CCBKeyframe::EasingType::CUBIC_OUT) { return EaseOut::create(pAction, fEasingOpt); } - else if (nEasingType == kCCBKeyframeEasingCubicInOut) + else if (easingType == CCBKeyframe::EasingType::CUBIC_INOUT) { return EaseInOut::create(pAction, fEasingOpt); } - else if (nEasingType == kCCBKeyframeEasingBackIn) + else if (easingType == CCBKeyframe::EasingType::BACK_IN) { return EaseBackIn::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingBackOut) + else if (easingType == CCBKeyframe::EasingType::BACK_OUT) { return EaseBackOut::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingBackInOut) + else if (easingType == CCBKeyframe::EasingType::BACK_INOUT) { return EaseBackInOut::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingBounceIn) + else if (easingType == CCBKeyframe::EasingType::BOUNCE_IN) { return EaseBounceIn::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingBounceOut) + else if (easingType == CCBKeyframe::EasingType::BOUNCE_OUT) { return EaseBounceOut::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingBounceInOut) + else if (easingType == CCBKeyframe::EasingType::BOUNCE_INOUT) { return EaseBounceInOut::create(pAction); } - else if (nEasingType == kCCBKeyframeEasingElasticIn) + else if (easingType == CCBKeyframe::EasingType::ELASTIC_IN) { return EaseElasticIn::create(pAction, fEasingOpt); } - else if (nEasingType == kCCBKeyframeEasingElasticOut) + else if (easingType == CCBKeyframe::EasingType::ELASTIC_OUT) { return EaseElasticOut::create(pAction, fEasingOpt); } - else if (nEasingType == kCCBKeyframeEasingElasticInOut) + else if (easingType == CCBKeyframe::EasingType::ELASTIC_INOUT) { return EaseElasticInOut::create(pAction, fEasingOpt); } else { - log("CCBReader: Unkown easing type %d", nEasingType); + log("CCBReader: Unkown easing type %d", easingType); return pAction; } } @@ -586,7 +587,8 @@ Object* CCBAnimationManager::actionForCallbackChannel(CCBSequenceProperty* chann Array *keyframes = channel->getKeyframes(); int numKeyframes = keyframes->count(); - for (int i = 0; i < numKeyframes; ++i) { + for (int i = 0; i < numKeyframes; ++i) + { CCBKeyframe *keyframe = (CCBKeyframe*)keyframes->objectAtIndex(i); float timeSinceLastKeyframe = keyframe->getTime() - lastKeyframeTime; @@ -595,37 +597,52 @@ Object* CCBAnimationManager::actionForCallbackChannel(CCBSequenceProperty* chann actions->addObject(DelayTime::create(timeSinceLastKeyframe)); } - Array* keyVal = (Array *)keyframe->getValue(); - std::string selectorName = ((String *)keyVal->objectAtIndex(0))->getCString(); - int selectorTarget = atoi(((String *)keyVal->objectAtIndex(1))->getCString()); + Array* keyVal = static_cast(keyframe->getValue()); + std::string selectorName = static_cast(keyVal->objectAtIndex(0))->getCString(); + CCBReader::TargetType selectorTarget = (CCBReader::TargetType)atoi(static_cast(keyVal->objectAtIndex(1))->getCString()); - if(jsControlled) { + if(_jsControlled) { String* callbackName = String::createWithFormat("%d:%s", selectorTarget, selectorName.c_str()); - CallFunc *callback = ((CallFunc*)(mKeyframeCallFuncs->objectForKey(callbackName->getCString())))->clone(); + CallFunc *callback = ((CallFunc*)(_keyframeCallFuncs->objectForKey(callbackName->getCString())))->clone(); if(callback != NULL) { actions->addObject(callback); } - } else { + } + else + { Object* target = NULL; - if(selectorTarget == kCCBTargetTypeDocumentRoot) target = mRootNode; - else if (selectorTarget == kCCBTargetTypeOwner) target = mOwner; - if(target != NULL) { - if(selectorName.length() > 0) { + + if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) + target = _rootNode; + else if (selectorTarget == CCBReader::TargetType::OWNER) + target = _owner; + + if(target != NULL) + { + if(selectorName.length() > 0) + { SEL_CallFuncN selCallFunc = 0; CCBSelectorResolver* targetAsCCBSelectorResolver = dynamic_cast(target); - if(targetAsCCBSelectorResolver != NULL) { + if(targetAsCCBSelectorResolver != NULL) + { selCallFunc = targetAsCCBSelectorResolver->onResolveCCBCCCallFuncSelector(target, selectorName.c_str ()); } - if(selCallFunc == 0) { + + if(selCallFunc == 0) + { CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str()); - } else { + } + else + { CallFuncN *callback = CallFuncN::create(target, selCallFunc); actions->addObject(callback); } - } else { + } + else + { CCLOG("Unexpected empty selector."); } } @@ -737,10 +754,10 @@ void CCBAnimationManager::runAnimationsForSequenceIdTweenDuration(int nSeqId, fl { CCASSERT(nSeqId != -1, "Sequence id couldn't be found"); - mRootNode->stopAllActions(); + _rootNode->stopAllActions(); DictElement* pElement = NULL; - CCDICT_FOREACH(mNodeSequences, pElement) + CCDICT_FOREACH(_nodeSequences, pElement) { Node *node = reinterpret_cast(pElement->getIntKey()); node->stopAllActions(); @@ -767,7 +784,7 @@ void CCBAnimationManager::runAnimationsForSequenceIdTweenDuration(int nSeqId, fl } // Reset the nodes that may have been changed by other timelines - Dictionary *nodeBaseValues = (Dictionary*)mBaseValues->objectForKey(pElement->getIntKey()); + Dictionary *nodeBaseValues = (Dictionary*)_baseValues->objectForKey(pElement->getIntKey()); if (nodeBaseValues) { DictElement* pElement2 = NULL; @@ -790,25 +807,25 @@ void CCBAnimationManager::runAnimationsForSequenceIdTweenDuration(int nSeqId, fl CCBSequence *seq = getSequence(nSeqId); Action *completeAction = Sequence::createWithTwoActions(DelayTime::create(seq->getDuration() + fTweenDuration), CallFunc::create( CC_CALLBACK_0(CCBAnimationManager::sequenceCompleted,this))); - mRootNode->runAction(completeAction); + _rootNode->runAction(completeAction); // Set the running scene if(seq->getCallbackChannel() != NULL) { Action* action = (Action *)actionForCallbackChannel(seq->getCallbackChannel()); if(action != NULL) { - mRootNode->runAction(action); + _rootNode->runAction(action); } } if(seq->getSoundChannel() != NULL) { Action* action = (Action *)actionForSoundChannel(seq->getSoundChannel()); if(action != NULL) { - mRootNode->runAction(action); + _rootNode->runAction(action); } } - mRunningSequence = getSequence(nSeqId); + _runningSequence = getSequence(nSeqId); } void CCBAnimationManager::runAnimationsForSequenceNamedTweenDuration(const char *pName, float fTweenDuration) @@ -833,38 +850,38 @@ void CCBAnimationManager::setAnimationCompletedCallback(Object *target, SEL_Call target->retain(); } - if (mTarget) + if (_target) { - mTarget->release(); + _target->release(); } - mTarget = target; - mAnimationCompleteCallbackFunc = callbackFunc; + _target = target; + _animationCompleteCallbackFunc = callbackFunc; } void CCBAnimationManager::setCallFunc(CallFunc* callFunc, const std::string &callbackNamed) { - mKeyframeCallFuncs->setObject((Object*)callFunc, callbackNamed); + _keyframeCallFuncs->setObject((Object*)callFunc, callbackNamed); } void CCBAnimationManager::sequenceCompleted() { - const char *runningSequenceName = mRunningSequence->getName(); - int nextSeqId = mRunningSequence->getChainedSequenceId(); - mRunningSequence = NULL; + const char *runningSequenceName = _runningSequence->getName(); + int nextSeqId = _runningSequence->getChainedSequenceId(); + _runningSequence = NULL; - if(lastCompletedSequenceName != runningSequenceName) { - lastCompletedSequenceName = runningSequenceName; + if(_lastCompletedSequenceName != runningSequenceName) { + _lastCompletedSequenceName = runningSequenceName; } - if (mDelegate) + if (_delegate) { // There may be another runAnimation() call in this delegate method - // which will assign mRunningSequence - mDelegate->completedAnimationSequenceNamed(runningSequenceName); + // which will assign _runningSequence + _delegate->completedAnimationSequenceNamed(runningSequenceName); } - if (mTarget && mAnimationCompleteCallbackFunc) { - (mTarget->*mAnimationCompleteCallbackFunc)(); + if (_target && _animationCompleteCallbackFunc) { + (_target->*_animationCompleteCallbackFunc)(); } if (nextSeqId != -1) @@ -899,22 +916,22 @@ CCBSetSpriteFrame* CCBSetSpriteFrame::create(SpriteFrame *pSpriteFrame) bool CCBSetSpriteFrame::initWithSpriteFrame(SpriteFrame *pSpriteFrame) { - mSpriteFrame = pSpriteFrame; - CC_SAFE_RETAIN(mSpriteFrame); + _spriteFrame = pSpriteFrame; + CC_SAFE_RETAIN(_spriteFrame); return true; } CCBSetSpriteFrame::~CCBSetSpriteFrame() { - CC_SAFE_RELEASE_NULL(mSpriteFrame); + CC_SAFE_RELEASE_NULL(_spriteFrame); } CCBSetSpriteFrame* CCBSetSpriteFrame::clone() const { // no copy constructor auto a = new CCBSetSpriteFrame(); - a->initWithSpriteFrame(mSpriteFrame); + a->initWithSpriteFrame(_spriteFrame); a->autorelease(); return a; } @@ -927,7 +944,7 @@ CCBSetSpriteFrame* CCBSetSpriteFrame::reverse() const void CCBSetSpriteFrame::update(float time) { - ((Sprite*)_target)->setDisplayFrame(mSpriteFrame); + ((Sprite*)_target)->setDisplayFrame(_spriteFrame); } @@ -954,10 +971,10 @@ CCBSoundEffect::~CCBSoundEffect() } bool CCBSoundEffect::initWithSoundFile(const std::string &filename, float pitch, float pan, float gain) { - mSoundFile = filename; - mPitch = pitch; - mPan = pan; - mGain = gain; + _soundFile = filename; + _pitch = pitch; + _pan = pan; + _gain = gain; return true; } @@ -965,7 +982,7 @@ CCBSoundEffect* CCBSoundEffect::clone() const { // no copy constructor auto a = new CCBSoundEffect(); - a->initWithSoundFile(mSoundFile, mPitch, mPan, mGain); + a->initWithSoundFile(_soundFile, _pitch, _pan, _gain); a->autorelease(); return a; } @@ -978,7 +995,7 @@ CCBSoundEffect* CCBSoundEffect::reverse() const void CCBSoundEffect::update(float time) { - CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(mSoundFile.c_str()); + CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(_soundFile.c_str()); } @@ -1008,7 +1025,7 @@ bool CCBRotateTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { - mDstAngle = fAngle; + _dstAngle = fAngle; return true; } @@ -1022,7 +1039,7 @@ CCBRotateTo* CCBRotateTo::clone() const { // no copy constructor auto a = new CCBRotateTo(); - a->initWithDuration(_duration, mDstAngle); + a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } @@ -1036,13 +1053,13 @@ CCBRotateTo* CCBRotateTo::reverse() const void CCBRotateTo::startWithTarget(Node *pNode) { ActionInterval::startWithTarget(pNode); - mStartAngle = _target->getRotation(); - mDiffAngle = mDstAngle - mStartAngle; + _startAngle = _target->getRotation(); + _diffAngle = _dstAngle - _startAngle; } void CCBRotateTo::update(float time) { - _target->setRotation(mStartAngle + (mDiffAngle * time)) + _target->setRotation(_startAngle + (_diffAngle * time)) ; } @@ -1076,7 +1093,7 @@ bool CCBRotateXTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { - mDstAngle = fAngle; + _dstAngle = fAngle; return true; } @@ -1094,15 +1111,15 @@ void CCBRotateXTo::startWithTarget(Node *pNode) _target = pNode; _elapsed = 0.0f; _firstTick = true; - mStartAngle = _target->getRotationX(); - mDiffAngle = mDstAngle - mStartAngle; + _startAngle = _target->getRotationX(); + _diffAngle = _dstAngle - _startAngle; } CCBRotateXTo* CCBRotateXTo::clone() const { // no copy constructor auto a = new CCBRotateXTo(); - a->initWithDuration(_duration, mDstAngle); + a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } @@ -1115,7 +1132,7 @@ CCBRotateXTo* CCBRotateXTo::reverse() const void CCBRotateXTo::update(float time) { - _target->setRotationX(mStartAngle + (mDiffAngle * time)) + _target->setRotationX(_startAngle + (_diffAngle * time)) ; } @@ -1149,7 +1166,7 @@ bool CCBRotateYTo::initWithDuration(float fDuration, float fAngle) { if (ActionInterval::initWithDuration(fDuration)) { - mDstAngle = fAngle; + _dstAngle = fAngle; return true; } @@ -1163,7 +1180,7 @@ CCBRotateYTo* CCBRotateYTo::clone() const { // no copy constructor auto a = new CCBRotateYTo(); - a->initWithDuration(_duration, mDstAngle); + a->initWithDuration(_duration, _dstAngle); a->autorelease(); return a; } @@ -1182,13 +1199,13 @@ void CCBRotateYTo::startWithTarget(Node *pNode) _target = pNode; _elapsed = 0.0f; _firstTick = true; - mStartAngle = _target->getRotationY(); - mDiffAngle = mDstAngle - mStartAngle; + _startAngle = _target->getRotationY(); + _diffAngle = _dstAngle - _startAngle; } void CCBRotateYTo::update(float time) { - _target->setRotationY(mStartAngle + (mDiffAngle * time)) + _target->setRotationY(_startAngle + (_diffAngle * time)) ; } diff --git a/extensions/CCBReader/CCBAnimationManager.h b/extensions/CCBReader/CCBAnimationManager.h index 08382b9bcd..d630ae545d 100644 --- a/extensions/CCBReader/CCBAnimationManager.h +++ b/extensions/CCBReader/CCBAnimationManager.h @@ -17,40 +17,13 @@ public: class CCBAnimationManager : public Object { -private: - Array *mSequences; - Dictionary *mNodeSequences; - Dictionary *mBaseValues; - int mAutoPlaySequenceId; - - Node *mRootNode; - - Size mRootContainerSize; - - CCBAnimationManagerDelegate *mDelegate; - CCBSequence *mRunningSequence; - - Array *mDocumentOutletNames; - Array *mDocumentOutletNodes; - Array *mDocumentCallbackNames; - Array *mDocumentCallbackNodes; - Array *mKeyframeCallbacks; - Dictionary *mKeyframeCallFuncs; - - std::string mDocumentControllerName; - std::string lastCompletedSequenceName; - - SEL_CallFunc mAnimationCompleteCallbackFunc; - Object *mTarget; - - public: - bool jsControlled; + bool _jsControlled; CCBAnimationManager(); ~CCBAnimationManager(); - Object *mOwner; + Object *_owner; virtual bool init(); @@ -92,7 +65,7 @@ public: const Size& getContainerSize(Node* pNode); void addNode(Node *pNode, Dictionary *pSeq); - void setBaseValue(Object *pValue, Node *pNode, const char *pPropName); + void setBaseValue(Object *pValue, Node *pNode, const char *propName); void moveAnimationsFromNode(Node* fromNode, Node* toNode); /** @deprecated This interface will be deprecated sooner or later.*/ @@ -116,15 +89,41 @@ public: Object* actionForSoundChannel(CCBSequenceProperty* channel); private: - Object* getBaseValue(Node *pNode, const char* pPropName); + Object* getBaseValue(Node *pNode, const char* propName); int getSequenceId(const char* pSequenceName); CCBSequence* getSequence(int nSequenceId); - ActionInterval* getAction(CCBKeyframe *pKeyframe0, CCBKeyframe *pKeyframe1, const char *pPropName, Node *pNode); - void setAnimatedProperty(const char *pPropName, Node *pNode, Object *pValue, float fTweenDuraion); + ActionInterval* getAction(CCBKeyframe *pKeyframe0, CCBKeyframe *pKeyframe1, const char *propName, Node *pNode); + void setAnimatedProperty(const char *propName, Node *pNode, Object *pValue, float fTweenDuraion); void setFirstFrame(Node *pNode, CCBSequenceProperty *pSeqProp, float fTweenDuration); - ActionInterval* getEaseAction(ActionInterval *pAction, int nEasingType, float fEasingOpt); + ActionInterval* getEaseAction(ActionInterval *pAction, CCBKeyframe::EasingType easingType, float fEasingOpt); void runAction(Node *pNode, CCBSequenceProperty *pSeqProp, float fTweenDuration); void sequenceCompleted(); + +private: + Array *_sequences; + Dictionary *_nodeSequences; + Dictionary *_baseValues; + int _autoPlaySequenceId; + + Node *_rootNode; + + Size _rootContainerSize; + + CCBAnimationManagerDelegate *_delegate; + CCBSequence *_runningSequence; + + Array *_documentOutletNames; + Array *_documentOutletNodes; + Array *_documentCallbackNames; + Array *_documentCallbackNodes; + Array *_keyframeCallbacks; + Dictionary *_keyframeCallFuncs; + + std::string _documentControllerName; + std::string _lastCompletedSequenceName; + + SEL_CallFunc _animationCompleteCallbackFunc; + Object *_target; }; class CCBSetSpriteFrame : public ActionInstant @@ -143,7 +142,7 @@ public: virtual CCBSetSpriteFrame* reverse() const override; private: - SpriteFrame *mSpriteFrame; + SpriteFrame *_spriteFrame; }; @@ -160,8 +159,8 @@ public: virtual CCBSoundEffect* reverse() const override; private: - std::string mSoundFile; - float mPitch, mPan, mGain; + std::string _soundFile; + float _pitch, _pan, _gain; }; @@ -178,9 +177,9 @@ public: virtual void startWithTarget(Node *pNode) override; private: - float mStartAngle; - float mDstAngle; - float mDiffAngle; + float _startAngle; + float _dstAngle; + float _diffAngle; }; @@ -197,9 +196,9 @@ public: virtual void update(float time) override; private: - float mStartAngle; - float mDstAngle; - float mDiffAngle; + float _startAngle; + float _dstAngle; + float _diffAngle; }; @@ -216,9 +215,9 @@ public: virtual void update(float time) override; private: - float mStartAngle; - float mDstAngle; - float mDiffAngle; + float _startAngle; + float _dstAngle; + float _diffAngle; }; diff --git a/extensions/CCBReader/CCBFileLoader.cpp b/extensions/CCBReader/CCBFileLoader.cpp index 2e85c2de2d..12af936847 100644 --- a/extensions/CCBReader/CCBFileLoader.cpp +++ b/extensions/CCBReader/CCBFileLoader.cpp @@ -6,11 +6,11 @@ NS_CC_EXT_BEGIN #define PROPERTY_CCBFILE "ccbFile" -void CCBFileLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader) { +void CCBFileLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CCBFILE) == 0) { ((CCBFile*)pNode)->setCCBFileNode(pCCBFileNode); } else { - NodeLoader::onHandlePropTypeCCBFile(pNode, pParent, pPropertyName, pCCBFileNode, pCCBReader); + NodeLoader::onHandlePropTypeCCBFile(pNode, pParent, pPropertyName, pCCBFileNode, ccbReader); } } diff --git a/extensions/CCBReader/CCBFileLoader.h b/extensions/CCBReader/CCBFileLoader.h index 36fa6216c5..7264a01909 100644 --- a/extensions/CCBReader/CCBFileLoader.h +++ b/extensions/CCBReader/CCBFileLoader.h @@ -17,7 +17,7 @@ class CCBFileLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(CCBFile); - virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader); + virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBKeyframe.cpp b/extensions/CCBReader/CCBKeyframe.cpp index e69cecb876..d2f3c5dc87 100644 --- a/extensions/CCBReader/CCBKeyframe.cpp +++ b/extensions/CCBReader/CCBKeyframe.cpp @@ -5,57 +5,57 @@ using namespace cocos2d; NS_CC_EXT_BEGIN CCBKeyframe::CCBKeyframe() -: mValue(NULL) -, mTime(0.0f) -, mEasingType(0) -, mEasingOpt(0.0f) +: _value(NULL) +, _time(0.0f) +, _easingType(EasingType::INSTANT) +, _easingOpt(0.0f) {} CCBKeyframe::~CCBKeyframe() { - CC_SAFE_RELEASE_NULL(mValue); + CC_SAFE_RELEASE_NULL(_value); } Object* CCBKeyframe::getValue() { - return mValue; + return _value; } void CCBKeyframe::setValue(Object *pValue) { - CC_SAFE_RELEASE(mValue); - mValue = pValue; - CC_SAFE_RETAIN(mValue); + CC_SAFE_RELEASE(_value); + _value = pValue; + CC_SAFE_RETAIN(_value); } float CCBKeyframe::getTime() { - return mTime; + return _time; } void CCBKeyframe::setTime(float fTime) { - mTime = fTime; + _time = fTime; } -int CCBKeyframe::getEasingType() +CCBKeyframe::EasingType CCBKeyframe::getEasingType() { - return mEasingType; + return _easingType; } -void CCBKeyframe::setEasingType(int nEasingType) +void CCBKeyframe::setEasingType(CCBKeyframe::EasingType easingType) { - mEasingType = nEasingType; + _easingType = easingType; } float CCBKeyframe::getEasingOpt() { - return mEasingOpt; + return _easingOpt; } void CCBKeyframe::setEasingOpt(float fEasingOpt) { - mEasingOpt = fEasingOpt; + _easingOpt = fEasingOpt; } NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBKeyframe.h b/extensions/CCBReader/CCBKeyframe.h index b634c7851c..2365b03733 100644 --- a/extensions/CCBReader/CCBKeyframe.h +++ b/extensions/CCBReader/CCBKeyframe.h @@ -8,13 +8,30 @@ NS_CC_EXT_BEGIN class CCBKeyframe : public Object { -private: - Object *mValue; - float mTime; - int mEasingType; - float mEasingOpt; - public: + enum class EasingType + { + INSTANT, + + LINEAR, + + CUBIC_IN, + CUBIC_OUT, + CUBIC_INOUT, + + ELASTIC_IN, + ELASTIC_OUT, + ELASTIC_INOUT, + + BOUNCE_IN, + BOUNCE_OUT, + BOUNCE_INOUT, + + BACK_IN, + BACK_OUT, + BACK_INOUT, + }; + CCBKeyframe(); ~CCBKeyframe(); @@ -24,11 +41,17 @@ public: float getTime(); void setTime(float fTime); - int getEasingType(); - void setEasingType(int nEasingType); + EasingType getEasingType(); + void setEasingType(EasingType easingType); float getEasingOpt(); void setEasingOpt(float fEasingOpt); + +private: + Object *_value; + float _time; + EasingType _easingType; + float _easingOpt; }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBReader.cpp b/extensions/CCBReader/CCBReader.cpp index 17e6111b5c..9d6df2baba 100644 --- a/extensions/CCBReader/CCBReader.cpp +++ b/extensions/CCBReader/CCBReader.cpp @@ -14,10 +14,6 @@ #include -#ifdef __CC_PLATFORM_IOS -#include -#endif - using namespace std; NS_CC_EXT_BEGIN; @@ -26,7 +22,7 @@ NS_CC_EXT_BEGIN; Implementation of CCBFile *************************************************************************/ -CCBFile::CCBFile():mCCBFileNode(NULL) {} +CCBFile::CCBFile():_CCBFileNode(NULL) {} CCBFile* CCBFile::create() { @@ -42,14 +38,14 @@ CCBFile* CCBFile::create() Node* CCBFile::getCCBFileNode() { - return mCCBFileNode; + return _CCBFileNode; } void CCBFile::setCCBFileNode(Node *pNode) { - CC_SAFE_RELEASE(mCCBFileNode); - mCCBFileNode = pNode; - CC_SAFE_RETAIN(mCCBFileNode); + CC_SAFE_RELEASE(_CCBFileNode); + _CCBFileNode = pNode; + CC_SAFE_RETAIN(_CCBFileNode); } /************************************************************************* @@ -57,111 +53,111 @@ void CCBFile::setCCBFileNode(Node *pNode) *************************************************************************/ CCBReader::CCBReader(NodeLoaderLibrary * pNodeLoaderLibrary, CCBMemberVariableAssigner * pCCBMemberVariableAssigner, CCBSelectorResolver * pCCBSelectorResolver, NodeLoaderListener * pNodeLoaderListener) -: mData(NULL) -, mBytes(NULL) -, mCurrentByte(-1) -, mCurrentBit(-1) -, mOwner(NULL) -, mActionManager(NULL) -, mActionManagers(NULL) -, mAnimatedProps(NULL) -, mOwnerOutletNodes(NULL) -, mNodesWithAnimationManagers(NULL) -, mAnimationManagersForNodes(NULL) -, mOwnerCallbackNodes(NULL) -, hasScriptingOwner(false) +: _data(NULL) +, _bytes(NULL) +, _currentByte(-1) +, _currentBit(-1) +, _owner(NULL) +, _actionManager(NULL) +, _actionManagers(NULL) +, _animatedProps(NULL) +, _ownerOutletNodes(NULL) +, _nodesWithAnimationManagers(NULL) +, _animationManagersForNodes(NULL) +, _ownerCallbackNodes(NULL) +, _hasScriptingOwner(false) { - this->mNodeLoaderLibrary = pNodeLoaderLibrary; - this->mNodeLoaderLibrary->retain(); - this->mCCBMemberVariableAssigner = pCCBMemberVariableAssigner; - this->mCCBSelectorResolver = pCCBSelectorResolver; - this->mNodeLoaderListener = pNodeLoaderListener; + this->_nodeLoaderLibrary = pNodeLoaderLibrary; + this->_nodeLoaderLibrary->retain(); + this->_CCBMemberVariableAssigner = pCCBMemberVariableAssigner; + this->_CCBSelectorResolver = pCCBSelectorResolver; + this->_nodeLoaderListener = pNodeLoaderListener; init(); } -CCBReader::CCBReader(CCBReader * pCCBReader) -: mData(NULL) -, mBytes(NULL) -, mCurrentByte(-1) -, mCurrentBit(-1) -, mOwner(NULL) -, mActionManager(NULL) -, mActionManagers(NULL) -, mAnimatedProps(NULL) -, mOwnerOutletNodes(NULL) -, mNodesWithAnimationManagers(NULL) -, mAnimationManagersForNodes(NULL) -, mOwnerCallbackNodes(NULL) -, hasScriptingOwner(false) +CCBReader::CCBReader(CCBReader * ccbReader) +: _data(NULL) +, _bytes(NULL) +, _currentByte(-1) +, _currentBit(-1) +, _owner(NULL) +, _actionManager(NULL) +, _actionManagers(NULL) +, _animatedProps(NULL) +, _ownerOutletNodes(NULL) +, _nodesWithAnimationManagers(NULL) +, _animationManagersForNodes(NULL) +, _ownerCallbackNodes(NULL) +, _hasScriptingOwner(false) { - this->mLoadedSpriteSheets = pCCBReader->mLoadedSpriteSheets; - this->mNodeLoaderLibrary = pCCBReader->mNodeLoaderLibrary; - this->mNodeLoaderLibrary->retain(); + this->_loadedSpriteSheets = ccbReader->_loadedSpriteSheets; + this->_nodeLoaderLibrary = ccbReader->_nodeLoaderLibrary; + this->_nodeLoaderLibrary->retain(); - this->mCCBMemberVariableAssigner = pCCBReader->mCCBMemberVariableAssigner; - this->mCCBSelectorResolver = pCCBReader->mCCBSelectorResolver; - this->mNodeLoaderListener = pCCBReader->mNodeLoaderListener; + this->_CCBMemberVariableAssigner = ccbReader->_CCBMemberVariableAssigner; + this->_CCBSelectorResolver = ccbReader->_CCBSelectorResolver; + this->_nodeLoaderListener = ccbReader->_nodeLoaderListener; - this->mOwnerCallbackNames = pCCBReader->mOwnerCallbackNames; - this->mOwnerCallbackNodes = pCCBReader->mOwnerCallbackNodes; - this->mOwnerCallbackNodes->retain(); - this->mOwnerOutletNames = pCCBReader->mOwnerOutletNames; - this->mOwnerOutletNodes = pCCBReader->mOwnerOutletNodes; - this->mOwnerOutletNodes->retain(); + this->_ownerCallbackNames = ccbReader->_ownerCallbackNames; + this->_ownerCallbackNodes = ccbReader->_ownerCallbackNodes; + this->_ownerCallbackNodes->retain(); + this->_ownerOutletNames = ccbReader->_ownerOutletNames; + this->_ownerOutletNodes = ccbReader->_ownerOutletNodes; + this->_ownerOutletNodes->retain(); - this->mCCBRootPath = pCCBReader->getCCBRootPath(); + this->_CCBRootPath = ccbReader->getCCBRootPath(); init(); } CCBReader::CCBReader() -: mData(NULL) -, mBytes(NULL) -, mCurrentByte(-1) -, mCurrentBit(-1) -, mOwner(NULL) -, mActionManager(NULL) -, mActionManagers(NULL) -, mNodeLoaderLibrary(NULL) -, mNodeLoaderListener(NULL) -, mCCBMemberVariableAssigner(NULL) -, mCCBSelectorResolver(NULL) -, mNodesWithAnimationManagers(NULL) -, mAnimationManagersForNodes(NULL) -, hasScriptingOwner(false) +: _data(NULL) +, _bytes(NULL) +, _currentByte(-1) +, _currentBit(-1) +, _owner(NULL) +, _actionManager(NULL) +, _actionManagers(NULL) +, _nodeLoaderLibrary(NULL) +, _nodeLoaderListener(NULL) +, _CCBMemberVariableAssigner(NULL) +, _CCBSelectorResolver(NULL) +, _nodesWithAnimationManagers(NULL) +, _animationManagersForNodes(NULL) +, _hasScriptingOwner(false) { init(); } CCBReader::~CCBReader() { - CC_SAFE_RELEASE_NULL(mOwner); - CC_SAFE_RELEASE_NULL(mData); + CC_SAFE_RELEASE_NULL(_owner); + CC_SAFE_RELEASE_NULL(_data); - this->mNodeLoaderLibrary->release(); + this->_nodeLoaderLibrary->release(); - CC_SAFE_RELEASE(mOwnerOutletNodes); - mOwnerOutletNames.clear(); - CC_SAFE_RELEASE(mOwnerCallbackNodes); - mOwnerCallbackNames.clear(); + CC_SAFE_RELEASE(_ownerOutletNodes); + _ownerOutletNames.clear(); + CC_SAFE_RELEASE(_ownerCallbackNodes); + _ownerCallbackNames.clear(); // Clear string cache. - this->mStringCache.clear(); - CC_SAFE_RELEASE(mNodesWithAnimationManagers); - CC_SAFE_RELEASE(mAnimationManagersForNodes); + this->_stringCache.clear(); + CC_SAFE_RELEASE(_nodesWithAnimationManagers); + CC_SAFE_RELEASE(_animationManagersForNodes); setAnimationManager(NULL); } -void CCBReader::setCCBRootPath(const char* pCCBRootPath) +void CCBReader::setCCBRootPath(const char* ccbRootPath) { - CCASSERT(pCCBRootPath != NULL, ""); - mCCBRootPath = pCCBRootPath; + CCASSERT(ccbRootPath != NULL, ""); + _CCBRootPath = ccbRootPath; } const std::string& CCBReader::getCCBRootPath() const { - return mCCBRootPath; + return _CCBRootPath; } bool CCBReader::init() @@ -172,54 +168,54 @@ bool CCBReader::init() pActionManager->release(); // Setup resolution scale and container size - mActionManager->setRootContainerSize(Director::getInstance()->getWinSize()); + _actionManager->setRootContainerSize(Director::getInstance()->getWinSize()); return true; } CCBAnimationManager* CCBReader::getAnimationManager() { - return mActionManager; + return _actionManager; } void CCBReader::setAnimationManager(CCBAnimationManager *pAnimationManager) { - CC_SAFE_RELEASE(mActionManager); - mActionManager = pAnimationManager; - CC_SAFE_RETAIN(mActionManager); + CC_SAFE_RELEASE(_actionManager); + _actionManager = pAnimationManager; + CC_SAFE_RETAIN(_actionManager); } Dictionary* CCBReader::getAnimationManagers() { - return mActionManagers; + return _actionManagers; } void CCBReader::setAnimationManagers(Dictionary* x) { - mActionManagers = x; + _actionManagers = x; } CCBMemberVariableAssigner * CCBReader::getCCBMemberVariableAssigner() { - return this->mCCBMemberVariableAssigner; + return this->_CCBMemberVariableAssigner; } CCBSelectorResolver * CCBReader::getCCBSelectorResolver() { - return this->mCCBSelectorResolver; + return this->_CCBSelectorResolver; } set* CCBReader::getAnimatedProperties() { - return mAnimatedProps; + return _animatedProps; } set& CCBReader::getLoadedSpriteSheet() { - return mLoadedSpriteSheets; + return _loadedSpriteSheets; } Object* CCBReader::getOwner() { - return mOwner; + return _owner; } Node* CCBReader::readNodeGraphFromFile(const char *pCCBFileName) @@ -263,31 +259,31 @@ Node* CCBReader::readNodeGraphFromFile(const char *pCCBFileName, Object *pOwner, Node* CCBReader::readNodeGraphFromData(Data *pData, Object *pOwner, const Size &parentSize) { - mData = pData; - CC_SAFE_RETAIN(mData); - mBytes = mData->getBytes(); - mCurrentByte = 0; - mCurrentBit = 0; - mOwner = pOwner; - CC_SAFE_RETAIN(mOwner); + _data = pData; + CC_SAFE_RETAIN(_data); + _bytes =_data->getBytes(); + _currentByte = 0; + _currentBit = 0; + _owner = pOwner; + CC_SAFE_RETAIN(_owner); - mActionManager->setRootContainerSize(parentSize); - mActionManager->mOwner = mOwner; - mOwnerOutletNodes = new Array(); - mOwnerCallbackNodes = new Array(); + _actionManager->setRootContainerSize(parentSize); + _actionManager->_owner = _owner; + _ownerOutletNodes = new Array(); + _ownerCallbackNodes = new Array(); Dictionary* animationManagers = Dictionary::create(); Node *pNodeGraph = readFileWithCleanUp(true, animationManagers); - if (pNodeGraph && mActionManager->getAutoPlaySequenceId() != -1 && !jsControlled) + if (pNodeGraph && _actionManager->getAutoPlaySequenceId() != -1 && !_jsControlled) { // Auto play animations - mActionManager->runAnimationsForSequenceIdTweenDuration(mActionManager->getAutoPlaySequenceId(), 0); + _actionManager->runAnimationsForSequenceIdTweenDuration(_actionManager->getAutoPlaySequenceId(), 0); } // Assign actionManagers to userObject - if(jsControlled) { - mNodesWithAnimationManagers = new Array(); - mAnimationManagersForNodes = new Array(); + if(_jsControlled) { + _nodesWithAnimationManagers = new Array(); + _animationManagersForNodes = new Array(); } DictElement* pElement = NULL; @@ -297,10 +293,10 @@ Node* CCBReader::readNodeGraphFromData(Data *pData, Object *pOwner, const Size & CCBAnimationManager* manager = static_cast(animationManagers->objectForKey((intptr_t)pNode)); pNode->setUserObject(manager); - if (jsControlled) + if (_jsControlled) { - mNodesWithAnimationManagers->addObject(pNode); - mAnimationManagersForNodes->addObject(manager); + _nodesWithAnimationManagers->addObject(pNode); + _animationManagersForNodes->addObject(manager); } } @@ -358,7 +354,7 @@ Node* CCBReader::readFileWithCleanUp(bool bCleanUp, Dictionary* am) Node *pNode = readNodeGraph(NULL); - mActionManagers->setObject(mActionManager, intptr_t(pNode)); + _actionManagers->setObject(_actionManager, intptr_t(pNode)); if (bCleanUp) { @@ -372,7 +368,7 @@ bool CCBReader::readStringCache() { int numStrings = this->readInt(false); for(int i = 0; i < numStrings; i++) { - this->mStringCache.push_back(this->readUTF8()); + this->_stringCache.push_back(this->readUTF8()); } return true; @@ -381,13 +377,13 @@ bool CCBReader::readStringCache() { bool CCBReader::readHeader() { /* If no bytes loaded, don't crash about it. */ - if(this->mBytes == NULL) { + if(this->_bytes == NULL) { return false; } /* Read magic bytes */ - int magicBytes = *((int*)(this->mBytes + this->mCurrentByte)); - this->mCurrentByte += 4; + int magicBytes = *((int*)(this->_bytes + this->_currentByte)); + this->_currentByte += 4; if(CC_SWAP_INT32_LITTLE_TO_HOST(magicBytes) != 'ccbi') { return false; @@ -395,25 +391,27 @@ bool CCBReader::readHeader() /* Read version. */ int version = this->readInt(false); - if(version != kCCBVersion) { - log("WARNING! Incompatible ccbi file version (file: %d reader: %d)", version, kCCBVersion); + if(version != CCB_VERSION) { + log("WARNING! Incompatible ccbi file version (file: %d reader: %d)", version, CCB_VERSION); return false; } // Read JS check - jsControlled = this->readBool(); - mActionManager->jsControlled = jsControlled; + _jsControlled = this->readBool(); + _actionManager->_jsControlled = _jsControlled; return true; } -unsigned char CCBReader::readByte() { - unsigned char byte = this->mBytes[this->mCurrentByte]; - this->mCurrentByte++; +unsigned char CCBReader::readByte() +{ + unsigned char byte = this->_bytes[this->_currentByte]; + this->_currentByte++; return byte; } -bool CCBReader::readBool() { +bool CCBReader::readBool() +{ return 0 == this->readByte() ? false : true; } @@ -427,39 +425,39 @@ std::string CCBReader::readUTF8() int numBytes = b0 << 8 | b1; char* pStr = (char*)malloc(numBytes+1); - memcpy(pStr, mBytes+mCurrentByte, numBytes); + memcpy(pStr, _bytes+_currentByte, numBytes); pStr[numBytes] = '\0'; ret = pStr; free(pStr); - mCurrentByte += numBytes; + _currentByte += numBytes; return ret; } bool CCBReader::getBit() { bool bit; - unsigned char byte = *(this->mBytes + this->mCurrentByte); - if(byte & (1 << this->mCurrentBit)) { + unsigned char byte = *(this->_bytes + this->_currentByte); + if(byte & (1 << this->_currentBit)) { bit = true; } else { bit = false; } - this->mCurrentBit++; + this->_currentBit++; - if(this->mCurrentBit >= 8) { - this->mCurrentBit = 0; - this->mCurrentByte++; + if(this->_currentBit >= 8) { + this->_currentBit = 0; + this->_currentByte++; } return bit; } void CCBReader::alignBits() { - if(this->mCurrentBit) { - this->mCurrentBit = 0; - this->mCurrentByte++; + if(this->_currentBit) { + this->_currentBit = 0; + this->_currentByte++; } } @@ -496,26 +494,28 @@ int CCBReader::readInt(bool pSigned) { } -float CCBReader::readFloat() { - unsigned char type = this->readByte(); +float CCBReader::readFloat() +{ + FloatType type = static_cast(this->readByte()); - switch (type) { - case kCCBFloat0: + switch (type) + { + case FloatType::_0: return 0; - case kCCBFloat1: + case FloatType::_1: return 1; - case kCCBFloatMinus1: + case FloatType::MINUS1: return -1; - case kCCBFloat05: + case FloatType::_05: return 0.5f; - case kCCBFloatInteger: + case FloatType::INTEGER: return (float)this->readInt(true); default: { /* using a memcpy since the compiler isn't * doing the float ptr math correctly on device. * TODO still applies in C++ ? */ - unsigned char* pF = (this->mBytes + this->mCurrentByte); + unsigned char* pF = (this->_bytes + this->_currentByte); float f = 0; // N.B - in order to avoid an unaligned memory access crash on 'memcpy()' the the (void*) casts of the source and @@ -531,35 +531,38 @@ float CCBReader::readFloat() { // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html memcpy((void*) &f, (const void*) pF, sizeof(float)); - this->mCurrentByte += sizeof(float); + this->_currentByte += sizeof(float); return f; } } } -std::string CCBReader::readCachedString() { +std::string CCBReader::readCachedString() +{ int n = this->readInt(false); - return this->mStringCache[n]; + return this->_stringCache[n]; } -Node * CCBReader::readNodeGraph(Node * pParent) { +Node * CCBReader::readNodeGraph(Node * pParent) +{ /* Read class name. */ std::string className = this->readCachedString(); - std::string jsControlledName; + std::string _jsControlledName; - if(jsControlled) { - jsControlledName = this->readCachedString(); + if(_jsControlled) { + _jsControlledName = this->readCachedString(); } // Read assignment type and name - int memberVarAssignmentType = this->readInt(false); + TargetType memberVarAssignmentType = static_cast(this->readInt(false)); std::string memberVarAssignmentName; - if(memberVarAssignmentType != kCCBTargetTypeNone) { + if(memberVarAssignmentType != TargetType::NONE) + { memberVarAssignmentName = this->readCachedString(); } - NodeLoader *ccNodeLoader = this->mNodeLoaderLibrary->getNodeLoader(className.c_str()); + NodeLoader *ccNodeLoader = this->_nodeLoaderLibrary->getNodeLoader(className.c_str()); if (! ccNodeLoader) { @@ -570,20 +573,20 @@ Node * CCBReader::readNodeGraph(Node * pParent) { Node *node = ccNodeLoader->loadNode(pParent, this); // Set root node - if (! mActionManager->getRootNode()) + if (! _actionManager->getRootNode()) { - mActionManager->setRootNode(node); + _actionManager->setRootNode(node); } // Assign controller - if(jsControlled && node == mActionManager->getRootNode()) + if(_jsControlled && node == _actionManager->getRootNode()) { - mActionManager->setDocumentControllerName(jsControlledName); + _actionManager->setDocumentControllerName(_jsControlledName); } // Read animated properties Dictionary *seqs = Dictionary::create(); - mAnimatedProps = new set(); + _animatedProps = new set(); int numSequence = readInt(false); for (int i = 0; i < numSequence; ++i) @@ -600,13 +603,13 @@ Node * CCBReader::readNodeGraph(Node * pParent) { seqProp->setName(readCachedString().c_str()); seqProp->setType(readInt(false)); - mAnimatedProps->insert(seqProp->getName()); + _animatedProps->insert(seqProp->getName()); int numKeyframes = readInt(false); for (int k = 0; k < numKeyframes; ++k) { - CCBKeyframe *keyframe = readKeyframe(seqProp->getType()); + CCBKeyframe *keyframe = readKeyframe(static_cast(seqProp->getType())); seqProp->getKeyframes()->addObject(keyframe); } @@ -619,7 +622,7 @@ Node * CCBReader::readNodeGraph(Node * pParent) { if (seqs->count() > 0) { - mActionManager->addNode(node, seqs); + _actionManager->addNode(node, seqs); } // Read properties @@ -640,7 +643,7 @@ Node * CCBReader::readNodeGraph(Node * pParent) { embeddedNode->setVisible(true); //embeddedNode->ignoreAnchorPointForPosition(ccbFileNode->isIgnoreAnchorPointForPosition()); - mActionManager->moveAnimationsFromNode(ccbFileNode, embeddedNode); + _actionManager->moveAnimationsFromNode(ccbFileNode, embeddedNode); ccbFileNode->setCCBFileNode(NULL); @@ -654,18 +657,18 @@ Node * CCBReader::readNodeGraph(Node * pParent) { [[JSCocoa sharedController] setObject:node withName:memberVarAssignmentName]; }*/ #else - if (memberVarAssignmentType != kCCBTargetTypeNone) + if (memberVarAssignmentType != TargetType::NONE) { - if(!jsControlled) + if(!_jsControlled) { Object * target = NULL; - if(memberVarAssignmentType == kCCBTargetTypeDocumentRoot) + if(memberVarAssignmentType == TargetType::DOCUMENT_ROOT) { - target = mActionManager->getRootNode(); + target = _actionManager->getRootNode(); } - else if(memberVarAssignmentType == kCCBTargetTypeOwner) + else if(memberVarAssignmentType == TargetType::OWNER) { - target = this->mOwner; + target = this->_owner; } if(target != NULL) @@ -673,36 +676,41 @@ Node * CCBReader::readNodeGraph(Node * pParent) { CCBMemberVariableAssigner * targetAsCCBMemberVariableAssigner = dynamic_cast(target); bool assigned = false; - if (memberVarAssignmentType != kCCBTargetTypeNone) + if (memberVarAssignmentType != TargetType::NONE) { - if(targetAsCCBMemberVariableAssigner != NULL) { + if(targetAsCCBMemberVariableAssigner != NULL) + { assigned = targetAsCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName.c_str(), node); } - if(!assigned && this->mCCBMemberVariableAssigner != NULL) { - assigned = this->mCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName.c_str(), node); + if(!assigned && this->_CCBMemberVariableAssigner != NULL) + { + assigned = this->_CCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName.c_str(), node); } } } } else { - if(memberVarAssignmentType == kCCBTargetTypeDocumentRoot) { - mActionManager->addDocumentOutletName(memberVarAssignmentName); - mActionManager->addDocumentOutletNode(node); - } else { - mOwnerOutletNames.push_back(memberVarAssignmentName); - mOwnerOutletNodes->addObject(node); + if(memberVarAssignmentType == TargetType::DOCUMENT_ROOT) + { + _actionManager->addDocumentOutletName(memberVarAssignmentName); + _actionManager->addDocumentOutletNode(node); + } + else + { + _ownerOutletNames.push_back(memberVarAssignmentName); + _ownerOutletNodes->addObject(node); } } } // Assign custom properties. - if (ccNodeLoader->getCustomProperties()->count() > 0) { - + if (ccNodeLoader->getCustomProperties()->count() > 0) + { bool customAssigned = false; - if(!jsControlled) + if(!_jsControlled) { Object * target = node; if(target != NULL) @@ -716,9 +724,9 @@ Node * CCBReader::readNodeGraph(Node * pParent) { { customAssigned = targetAsCCBMemberVariableAssigner->onAssignCCBCustomProperty(target, pElement->getStrKey(), static_cast(pElement->getObject())); - if(!customAssigned && this->mCCBMemberVariableAssigner != NULL) + if(!customAssigned && this->_CCBMemberVariableAssigner != NULL) { - customAssigned = this->mCCBMemberVariableAssigner->onAssignCCBCustomProperty(target, pElement->getStrKey(), static_cast(pElement->getObject())); + customAssigned = this->_CCBMemberVariableAssigner->onAssignCCBCustomProperty(target, pElement->getStrKey(), static_cast(pElement->getObject())); } } } @@ -728,8 +736,8 @@ Node * CCBReader::readNodeGraph(Node * pParent) { #endif // CCB_ENABLE_JAVASCRIPT - delete mAnimatedProps; - mAnimatedProps = NULL; + delete _animatedProps; + _animatedProps = NULL; /* Read and add children. */ int numChildren = this->readInt(false); @@ -746,45 +754,45 @@ Node * CCBReader::readNodeGraph(Node * pParent) { NodeLoaderListener * nodeAsNodeLoaderListener = dynamic_cast(node); if(nodeAsNodeLoaderListener != NULL) { nodeAsNodeLoaderListener->onNodeLoaded(node, ccNodeLoader); - } else if(this->mNodeLoaderListener != NULL) { - this->mNodeLoaderListener->onNodeLoaded(node, ccNodeLoader); + } else if(this->_nodeLoaderListener != NULL) { + this->_nodeLoaderListener->onNodeLoaded(node, ccNodeLoader); } } return node; } -CCBKeyframe* CCBReader::readKeyframe(int type) +CCBKeyframe* CCBReader::readKeyframe(PropertyType type) { CCBKeyframe *keyframe = new CCBKeyframe(); keyframe->autorelease(); keyframe->setTime(readFloat()); - int easingType = readInt(false); + CCBKeyframe::EasingType easingType = static_cast(readInt(false)); float easingOpt = 0; Object *value = NULL; - if (easingType == kCCBKeyframeEasingCubicIn - || easingType == kCCBKeyframeEasingCubicOut - || easingType == kCCBKeyframeEasingCubicInOut - || easingType == kCCBKeyframeEasingElasticIn - || easingType == kCCBKeyframeEasingElasticOut - || easingType == kCCBKeyframeEasingElasticInOut) + if (easingType == CCBKeyframe::EasingType::CUBIC_IN + || easingType == CCBKeyframe::EasingType::CUBIC_OUT + || easingType == CCBKeyframe::EasingType::CUBIC_INOUT + || easingType == CCBKeyframe::EasingType::ELASTIC_IN + || easingType == CCBKeyframe::EasingType::ELASTIC_OUT + || easingType == CCBKeyframe::EasingType::ELASTIC_INOUT) { easingOpt = readFloat(); } keyframe->setEasingType(easingType); keyframe->setEasingOpt(easingOpt); - if (type == kCCBPropTypeCheck) + if (type == PropertyType::CHECK) { value = CCBValue::create(readBool()); } - else if (type == kCCBPropTypeByte) + else if (type == PropertyType::BYTE) { value = CCBValue::create(readByte()); } - else if (type == kCCBPropTypeColor3) + else if (type == PropertyType::COLOR3) { int r = readByte(); int g = readByte(); @@ -793,12 +801,12 @@ CCBKeyframe* CCBReader::readKeyframe(int type) Color3B c = Color3B(r,g,b); value = Color3BWapper::create(c); } - else if (type == kCCBPropTypeDegrees) + else if (type == PropertyType::DEGREES) { value = CCBValue::create(readFloat()); } - else if (type == kCCBPropTypeScaleLock || type == kCCBPropTypePosition - || type == kCCBPropTypeFloatXY) + else if (type == PropertyType::SCALE_LOCK || type == PropertyType::POSITION + || type == PropertyType::FLOAT_XY) { float a = readFloat(); float b = readFloat(); @@ -807,7 +815,7 @@ CCBKeyframe* CCBReader::readKeyframe(int type) CCBValue::create(b), NULL); } - else if (type == kCCBPropTypeSpriteFrame) + else if (type == PropertyType::SPRITEFRAME) { std::string spriteSheet = readCachedString(); std::string spriteFile = readCachedString(); @@ -816,7 +824,7 @@ CCBKeyframe* CCBReader::readKeyframe(int type) if (spriteSheet.length() == 0) { - spriteFile = mCCBRootPath + spriteFile; + spriteFile = _CCBRootPath + spriteFile; Texture2D *texture = TextureCache::getInstance()->addImage(spriteFile.c_str()); Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height); @@ -825,14 +833,14 @@ CCBKeyframe* CCBReader::readKeyframe(int type) } else { - spriteSheet = mCCBRootPath + spriteSheet; + spriteSheet = _CCBRootPath + spriteSheet; SpriteFrameCache* frameCache = SpriteFrameCache::getInstance(); // Load the sprite sheet only if it is not loaded - if (mLoadedSpriteSheets.find(spriteSheet) == mLoadedSpriteSheets.end()) + if (_loadedSpriteSheets.find(spriteSheet) == _loadedSpriteSheets.end()) { frameCache->addSpriteFramesWithFile(spriteSheet.c_str()); - mLoadedSpriteSheets.insert(spriteSheet); + _loadedSpriteSheets.insert(spriteSheet); } spriteFrame = frameCache->getSpriteFrameByName(spriteFile.c_str()); @@ -846,7 +854,8 @@ CCBKeyframe* CCBReader::readKeyframe(int type) } -bool CCBReader::readCallbackKeyframesForSeq(CCBSequence* seq) { +bool CCBReader::readCallbackKeyframesForSeq(CCBSequence* seq) +{ int numKeyframes = readInt(false); if(!numKeyframes) return true; @@ -870,9 +879,9 @@ bool CCBReader::readCallbackKeyframesForSeq(CCBSequence* seq) { keyframe->setTime(time); keyframe->setValue(value); - if(jsControlled) { + if(_jsControlled) { string callbackIdentifier; - mActionManager->getKeyframeCallbacks()->addObject(String::createWithFormat("%d:%s",callbackType, callbackName.c_str())); + _actionManager->getKeyframeCallbacks()->addObject(String::createWithFormat("%d:%s",callbackType, callbackName.c_str())); } channel->getKeyframes()->addObject(keyframe); @@ -924,7 +933,7 @@ Node * CCBReader::readNodeGraph() { bool CCBReader::readSequences() { - Array *sequences = mActionManager->getSequences(); + Array *sequences = _actionManager->getSequences(); int numSeqs = readInt(false); @@ -944,7 +953,7 @@ bool CCBReader::readSequences() sequences->addObject(seq); } - mActionManager->setAutoPlaySequenceId(readInt(true)); + _actionManager->setAutoPlaySequenceId(readInt(true)); return true; } @@ -983,31 +992,31 @@ bool CCBReader::endsWith(const char* pString, const char* pEnding) { } bool CCBReader::isJSControlled() { - return jsControlled; + return _jsControlled; } void CCBReader::addOwnerCallbackName(std::string name) { - mOwnerCallbackNames.push_back(name); + _ownerCallbackNames.push_back(name); } void CCBReader::addOwnerCallbackNode(Node *node) { - mOwnerCallbackNodes->addObject(node); + _ownerCallbackNodes->addObject(node); } void CCBReader::addDocumentCallbackName(std::string name) { - mActionManager->addDocumentCallbackName(name); + _actionManager->addDocumentCallbackName(name); } void CCBReader::addDocumentCallbackNode(Node *node) { - mActionManager->addDocumentCallbackNode(node); + _actionManager->addDocumentCallbackNode(node); } Array* CCBReader::getOwnerCallbackNames() { - Array* pRet = Array::createWithCapacity(mOwnerCallbackNames.size()); - std::vector::iterator it = mOwnerCallbackNames.begin(); - for (; it != mOwnerCallbackNames.end(); ++it) + Array* pRet = Array::createWithCapacity(_ownerCallbackNames.size()); + std::vector::iterator it = _ownerCallbackNames.begin(); + for (; it != _ownerCallbackNames.end(); ++it) { pRet->addObject(String::create(*it)); } @@ -1016,13 +1025,13 @@ Array* CCBReader::getOwnerCallbackNames() { } Array* CCBReader::getOwnerCallbackNodes() { - return mOwnerCallbackNodes; + return _ownerCallbackNodes; } Array* CCBReader::getOwnerOutletNames() { - Array* pRet = Array::createWithCapacity(mOwnerOutletNames.size()); - std::vector::iterator it = mOwnerOutletNames.begin(); - for (; it != mOwnerOutletNames.end(); ++it) + Array* pRet = Array::createWithCapacity(_ownerOutletNames.size()); + std::vector::iterator it = _ownerOutletNames.begin(); + for (; it != _ownerOutletNames.end(); ++it) { pRet->addObject(String::create(*it)); } @@ -1030,20 +1039,20 @@ Array* CCBReader::getOwnerOutletNames() { } Array* CCBReader::getOwnerOutletNodes() { - return mOwnerOutletNodes; + return _ownerOutletNodes; } Array* CCBReader::getNodesWithAnimationManagers() { - return mNodesWithAnimationManagers; + return _nodesWithAnimationManagers; } Array* CCBReader::getAnimationManagersForNodes() { - return mAnimationManagersForNodes; + return _animationManagersForNodes; } void CCBReader::addOwnerOutletName(std::string name) { - mOwnerOutletNames.push_back(name); + _ownerOutletNames.push_back(name); } void CCBReader::addOwnerOutletNode(Node *node) @@ -1051,7 +1060,7 @@ void CCBReader::addOwnerOutletNode(Node *node) if (NULL != node) return; - mOwnerOutletNodes->addObject(node); + _ownerOutletNodes->addObject(node); } /************************************************************************ diff --git a/extensions/CCBReader/CCBReader.h b/extensions/CCBReader/CCBReader.h index cf0ed19423..d30c7ecbea 100644 --- a/extensions/CCBReader/CCBReader.h +++ b/extensions/CCBReader/CCBReader.h @@ -28,109 +28,7 @@ return NULL; \ } -#define kCCBVersion 5 - -enum { - kCCBPropTypePosition = 0, - kCCBPropTypeSize, - kCCBPropTypePoint, - kCCBPropTypePointLock, - kCCBPropTypeScaleLock, - kCCBPropTypeDegrees, - kCCBPropTypeInteger, - kCCBPropTypeFloat, - kCCBPropTypeFloatVar, - kCCBPropTypeCheck, - kCCBPropTypeSpriteFrame, - kCCBPropTypeTexture, - kCCBPropTypeByte, - kCCBPropTypeColor3, - kCCBPropTypeColor4FVar, - kCCBPropTypeFlip, - kCCBPropTypeBlendmode, - kCCBPropTypeFntFile, - kCCBPropTypeText, - kCCBPropTypeFontTTF, - kCCBPropTypeIntegerLabeled, - kCCBPropTypeBlock, - kCCBPropTypeAnimation, - kCCBPropTypeCCBFile, - kCCBPropTypeString, - kCCBPropTypeBlockControl, - kCCBPropTypeFloatScale, - kCCBPropTypeFloatXY -}; - -enum { - kCCBFloat0 = 0, - kCCBFloat1, - kCCBFloatMinus1, - kCCBFloat05, - kCCBFloatInteger, - kCCBFloatFull -}; - -enum { - kCCBPlatformAll = 0, - kCCBPlatformIOS, - kCCBPlatformMac -}; - -enum { - kCCBTargetTypeNone = 0, - kCCBTargetTypeDocumentRoot = 1, - kCCBTargetTypeOwner = 2, -}; - -enum -{ - kCCBKeyframeEasingInstant, - - kCCBKeyframeEasingLinear, - - kCCBKeyframeEasingCubicIn, - kCCBKeyframeEasingCubicOut, - kCCBKeyframeEasingCubicInOut, - - kCCBKeyframeEasingElasticIn, - kCCBKeyframeEasingElasticOut, - kCCBKeyframeEasingElasticInOut, - - kCCBKeyframeEasingBounceIn, - kCCBKeyframeEasingBounceOut, - kCCBKeyframeEasingBounceInOut, - - kCCBKeyframeEasingBackIn, - kCCBKeyframeEasingBackOut, - kCCBKeyframeEasingBackInOut, -}; - -enum -{ - kCCBPositionTypeRelativeBottomLeft, - kCCBPositionTypeRelativeTopLeft, - kCCBPositionTypeRelativeTopRight, - kCCBPositionTypeRelativeBottomRight, - kCCBPositionTypePercent, - kCCBPositionTypeMultiplyResolution, -}; - -enum -{ - kCCBSizeTypeAbsolute, - kCCBSizeTypePercent, - kCCBSizeTypeRelativeContainer, - kCCBSizeTypeHorizontalPercent, - kCCBSizeTypeVerticalPercent, - kCCBSizeTypeMultiplyResolution, -}; - -enum -{ - kCCBScaleTypeAbsolute, - kCCBScaleTypeMultiplyResolution -}; - +#define CCB_VERSION 5 NS_CC_EXT_BEGIN @@ -142,7 +40,7 @@ NS_CC_EXT_BEGIN class CCBFile : public Node { private: - Node *mCCBFileNode; + Node *_CCBFileNode; public: CCBFile(); @@ -167,47 +65,91 @@ class CCBKeyframe; */ class CCBReader : public Object { -private: - - Data *mData; - unsigned char *mBytes; - int mCurrentByte; - int mCurrentBit; - - std::vector mStringCache; - std::set mLoadedSpriteSheets; - - Object *mOwner; - - CCBAnimationManager *mActionManager; //retain - Dictionary* mActionManagers; - - std::set *mAnimatedProps; - - NodeLoaderLibrary *mNodeLoaderLibrary; - NodeLoaderListener *mNodeLoaderListener; - CCBMemberVariableAssigner *mCCBMemberVariableAssigner; - CCBSelectorResolver *mCCBSelectorResolver; - - std::vector mOwnerOutletNames; - Array* mOwnerOutletNodes; - Array* mNodesWithAnimationManagers; - Array* mAnimationManagersForNodes; - - std::vector mOwnerCallbackNames; - Array* mOwnerCallbackNodes; - std::string mCCBRootPath; - bool hasScriptingOwner; - bool init(); public: + enum class PropertyType { + POSITION = 0, + SIZE, + POINT, + POINT_LOCK, + SCALE_LOCK, + DEGREES, + INTEGER, + FLOAT, + FLOAT_VAR, + CHECK, + SPRITEFRAME, + TEXTURE, + BYTE, + COLOR3, + COLOR4F_VAR, + FLIP, + BLEND_MODE, + FNT_FILE, + TEXT, + FONT_TTF, + INTEGER_LABELED, + BLOCK, + ANIMATION, + CCB_FILE, + STRING, + BLOCK_CONTROL, + FLOAT_SCALE, + FLOAT_XY + }; + + enum class FloatType { + _0 = 0, + _1, + MINUS1, + _05, + INTEGER, + FULL + }; + + enum class PlatformType { + ALL = 0, + IOS, + MAC + }; + + enum class TargetType { + NONE = 0, + DOCUMENT_ROOT = 1, + OWNER = 2, + }; + + enum class PositionType + { + RELATIVE_BOTTOM_LEFT, + RELATIVE_TOP_LEFT, + RELATIVE_TOP_RIGHT, + RELATIVE_BOTTOM_RIGHT, + PERCENT, + MULTIPLY_RESOLUTION, + }; + + enum class SizeType + { + ABSOLUTE, + PERCENT, + RELATIVE_CONTAINER, + HORIZONTAL_PERCENT, + VERTICAL_PERCENT, + MULTIPLY_RESOLUTION, + }; + + enum class ScaleType + { + ABSOLUTE, + MULTIPLY_RESOLUTION + }; - bool jsControlled; CCBReader(NodeLoaderLibrary *pNodeLoaderLibrary, CCBMemberVariableAssigner *pCCBMemberVariableAssigner = NULL, CCBSelectorResolver *pCCBSelectorResolver = NULL, NodeLoaderListener *pNodeLoaderListener = NULL); - CCBReader(CCBReader *pCCBReader); + CCBReader(CCBReader *ccbReader); virtual ~CCBReader(); CCBReader(); - void setCCBRootPath(const char* pCCBRootPath); + void setCCBRootPath(const char* ccbRootPath); const std::string& getCCBRootPath() const; Node* readNodeGraphFromFile(const char *pCCBFileName); @@ -279,7 +221,7 @@ public: private: void cleanUpNodeGraph(Node *pNode); bool readSequences(); - CCBKeyframe* readKeyframe(int type); + CCBKeyframe* readKeyframe(PropertyType type); bool readHeader(); bool readStringCache(); @@ -291,6 +233,41 @@ private: void alignBits(); friend class NodeLoader; + +private: + Data *_data; + unsigned char *_bytes; + int _currentByte; + int _currentBit; + + std::vector _stringCache; + std::set _loadedSpriteSheets; + + Object *_owner; + + CCBAnimationManager *_actionManager; //retain + Dictionary* _actionManagers; + + std::set *_animatedProps; + + NodeLoaderLibrary *_nodeLoaderLibrary; + NodeLoaderListener *_nodeLoaderListener; + CCBMemberVariableAssigner *_CCBMemberVariableAssigner; + CCBSelectorResolver *_CCBSelectorResolver; + + std::vector _ownerOutletNames; + Array* _ownerOutletNodes; + Array* _nodesWithAnimationManagers; + Array* _animationManagersForNodes; + + std::vector _ownerCallbackNames; + Array* _ownerCallbackNodes; + std::string _CCBRootPath; + + bool _jsControlled; + + bool _hasScriptingOwner; + bool init(); }; // end of effects group diff --git a/extensions/CCBReader/CCBSequence.cpp b/extensions/CCBReader/CCBSequence.cpp index 33bab2faae..07e8d96189 100644 --- a/extensions/CCBReader/CCBSequence.cpp +++ b/extensions/CCBReader/CCBSequence.cpp @@ -7,8 +7,8 @@ using namespace std; NS_CC_EXT_BEGIN CCBSequence::CCBSequence() -: mDuration(0.0f) -, mName("") +: _duration(0.0f) +, _name("") , mSequenceId(0) , mChainedSequenceId(0) , mCallbackChannel(NULL) @@ -22,22 +22,22 @@ CCBSequence::~CCBSequence() { float CCBSequence::getDuration() { - return mDuration; + return _duration; } void CCBSequence::setDuration(float fDuration) { - mDuration = fDuration; + _duration = fDuration; } const char* CCBSequence::getName() { - return mName.c_str(); + return _name.c_str(); } void CCBSequence::setName(const char *pName) { - mName = pName; + _name = pName; } int CCBSequence::getSequenceId() diff --git a/extensions/CCBReader/CCBSequence.h b/extensions/CCBReader/CCBSequence.h index 7cd6c70156..e309c3f436 100644 --- a/extensions/CCBReader/CCBSequence.h +++ b/extensions/CCBReader/CCBSequence.h @@ -10,14 +10,6 @@ NS_CC_EXT_BEGIN class CCBSequence : public Object { -private: - float mDuration; - std::string mName; - int mSequenceId; - int mChainedSequenceId; - CCBSequenceProperty* mCallbackChannel; - CCBSequenceProperty* mSoundChannel; - public: CCBSequence(); ~CCBSequence(); @@ -38,6 +30,14 @@ public: int getChainedSequenceId(); void setChainedSequenceId(int nChainedSequenceId); + +private: + float _duration; + std::string _name; + int mSequenceId; + int mChainedSequenceId; + CCBSequenceProperty* mCallbackChannel; + CCBSequenceProperty* mSoundChannel; }; diff --git a/extensions/CCBReader/CCBSequenceProperty.cpp b/extensions/CCBReader/CCBSequenceProperty.cpp index d3914239ca..ca39935e57 100644 --- a/extensions/CCBReader/CCBSequenceProperty.cpp +++ b/extensions/CCBReader/CCBSequenceProperty.cpp @@ -6,47 +6,47 @@ using namespace std; NS_CC_EXT_BEGIN CCBSequenceProperty::CCBSequenceProperty() -: mName("") -, mType(0) +: _name("") +, _type(0) { init(); } bool CCBSequenceProperty::init() { - mKeyframes = new Array(); + _keyframes = new Array(); return true; } CCBSequenceProperty::~CCBSequenceProperty() { - CC_SAFE_RELEASE_NULL(mKeyframes); + CC_SAFE_RELEASE_NULL(_keyframes); } const char* CCBSequenceProperty::getName() { - return mName.c_str(); + return _name.c_str(); } void CCBSequenceProperty::setName(const char *pName) { - mName = pName; + _name = pName; } int CCBSequenceProperty::getType() { - return mType; + return _type; } -void CCBSequenceProperty::setType(int nType) +void CCBSequenceProperty::setType(int type) { - mType = nType; + _type = type; } Array* CCBSequenceProperty::getKeyframes() { - return mKeyframes; + return _keyframes; } NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBSequenceProperty.h b/extensions/CCBReader/CCBSequenceProperty.h index bb7d73c27d..4ab096f7b7 100644 --- a/extensions/CCBReader/CCBSequenceProperty.h +++ b/extensions/CCBReader/CCBSequenceProperty.h @@ -9,11 +9,6 @@ NS_CC_EXT_BEGIN class CCBSequenceProperty : public Object { -private: - std::string mName; - int mType; - Array *mKeyframes; - public: CCBSequenceProperty(); ~CCBSequenceProperty(); @@ -24,9 +19,14 @@ public: void setName(const char* pName); int getType(); - void setType(int nType); + void setType(int type); Array* getKeyframes(); + +private: + std::string _name; + int _type; + Array *_keyframes; }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBValue.cpp b/extensions/CCBReader/CCBValue.cpp index 4a17926416..051100383d 100644 --- a/extensions/CCBReader/CCBValue.cpp +++ b/extensions/CCBReader/CCBValue.cpp @@ -1,7 +1,5 @@ #include "CCBValue.h" -using namespace cocos2d; - NS_CC_EXT_BEGIN // Implementation of Color3BWapper @@ -14,10 +12,10 @@ Color3BWapper* Color3BWapper::create(const Color3B& color) ret->color.r = color.r; ret->color.g = color.g; ret->color.b = color.b; - + ret->autorelease(); } - + return ret; } @@ -33,11 +31,11 @@ CCBValue* CCBValue::create(int nValue) CCBValue *ret = new CCBValue(); if (ret) { - ret->mValue.nValue = nValue; - ret->mType = kIntValue; + ret->_value.intValue = nValue; + ret->_type = Type::INT; ret->autorelease(); } - + return ret; } @@ -46,11 +44,11 @@ CCBValue* CCBValue::create(float fValue) CCBValue *ret = new CCBValue(); if (ret) { - ret->mValue.fValue = fValue; - ret->mType = kFloatValue; + ret->_value.floatValue = fValue; + ret->_type = Type::FLOAT; ret->autorelease(); } - + return ret; } @@ -59,11 +57,11 @@ CCBValue* CCBValue::create(bool vValue) CCBValue *ret = new CCBValue(); if (ret) { - ret->mValue.nValue = vValue ? 1 : 0; - ret->mType = kBoolValue; + ret->_value.intValue = vValue ? 1 : 0; + ret->_type = Type::BOOL; ret->autorelease(); } - + return ret; } @@ -72,11 +70,11 @@ CCBValue* CCBValue::create(unsigned char byte) CCBValue *ret = new CCBValue(); if (ret) { - ret->mValue.nValue = byte; - ret->mType = kUnsignedCharValue; + ret->_value.intValue = byte; + ret->_type = Type::UNSIGNED_CHAR; ret->autorelease(); } - + return ret; } @@ -85,11 +83,11 @@ CCBValue* CCBValue::create(const char *pStringValue) CCBValue *ret = new CCBValue(); if (ret) { - ret->_value = pStringValue; - ret->mType = kStringValue; + ret->_strValue = pStringValue; + ret->_type = Type::STRING; ret->autorelease(); } - + return ret; } @@ -100,59 +98,60 @@ CCBValue* CCBValue::create(Array *pArrValue) if (ret) { ret->_arrValue = pArrValue; - ret->mType = kArrayValue; + ret->_type = Type::ARRAY; ret->autorelease(); } - + return ret; } int CCBValue::getIntValue() { - assert(mType == kIntValue); - - return mValue.nValue; + CCASSERT(_type == Type::INT, "The type of CCBValue isn't integer."); + + return _value.intValue; } float CCBValue::getFloatValue() { - assert(mType == kFloatValue); - - return mValue.fValue; + CCASSERT(_type == Type::FLOAT, "The type of CCBValue isn't float."); + + return _value.floatValue; } bool CCBValue::getBoolValue() { - assert(mType == kBoolValue); - - return mValue.nValue == 1 ? true : false; + CCASSERT(_type == Type::BOOL, "The type of CCBValue isn't boolean."); + + return _value.intValue == 1 ? true : false; } unsigned char CCBValue::getByteValue() { - assert(mType == kUnsignedCharValue); - - return (unsigned char)(mValue.nValue); + CCASSERT(_type == Type::UNSIGNED_CHAR, "The type of CCBValue isn't unsigned char."); + + return (unsigned char)(_value.intValue); } -Array* CCBValue::getArrayValue() { - assert(mType == kArrayValue); - +Array* CCBValue::getArrayValue() +{ + CCASSERT(_type == Type::ARRAY, "The type of CCBValue isn't array."); + return _arrValue; } const char* CCBValue::getStringValue() { - assert(mType == kStringValue); - - return _value.c_str(); + CCASSERT(_type == Type::STRING, "The type of CCBValue isn't string."); + + return _strValue.c_str(); } -int CCBValue::getType() +CCBValue::Type CCBValue::getType() { - return mType; + return _type; } NS_CC_EXT_END diff --git a/extensions/CCBReader/CCBValue.h b/extensions/CCBReader/CCBValue.h index d0359bf201..267ed5809a 100644 --- a/extensions/CCBReader/CCBValue.h +++ b/extensions/CCBReader/CCBValue.h @@ -12,39 +12,31 @@ NS_CC_EXT_BEGIN class Color3BWapper : public Object { -private: - Color3B color; - public: static Color3BWapper* create(const Color3B& color); const Color3B& getColor() const; + +private: + Color3B color; }; -enum -{ - kIntValue, - kFloatValue, - kBoolValue, - kUnsignedCharValue, - kStringValue, - kArrayValue -}; + class CCBValue : public Object { -private: - union - { - int nValue; - float fValue; - } mValue; - - std::string _value; - Array* _arrValue; - int mType; - public: + + enum class Type + { + INT, + FLOAT, + BOOL, + UNSIGNED_CHAR, + STRING, + ARRAY + }; + static CCBValue* create(int nValue); static CCBValue* create(bool bValue); static CCBValue* create(float fValue); @@ -60,7 +52,18 @@ public: const char* getStringValue(); Array *getArrayValue(); - int getType(); + Type getType(); + +private: + union + { + int intValue; + float floatValue; + } _value; + + std::string _strValue; + Array* _arrValue; + Type _type; }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCControlButtonLoader.cpp b/extensions/CCBReader/CCControlButtonLoader.cpp index 3b71ee5d78..6b76adf3ec 100644 --- a/extensions/CCBReader/CCControlButtonLoader.cpp +++ b/extensions/CCBReader/CCControlButtonLoader.cpp @@ -22,15 +22,15 @@ NS_CC_EXT_BEGIN; #define PROPERTY_BACKGROUNDSPRITEFRAME_HIGHLIGHTED "backgroundSpriteFrame|2" #define PROPERTY_BACKGROUNDSPRITEFRAME_DISABLED "backgroundSpriteFrame|3" -void ControlButtonLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_ZOOMONTOUCHDOWN) == 0) { ((ControlButton *)pNode)->setZoomOnTouchDown(pCheck); } else { - ControlLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, pCCBReader); + ControlLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeString(Node * pNode, Node * pParent, const char * pPropertyName, const char * pString, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeString(Node * pNode, Node * pParent, const char * pPropertyName, const char * pString, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TITLE_NORMAL) == 0) { ((ControlButton *)pNode)->setTitleForState(String::create(pString), Control::State::NORMAL); } else if(strcmp(pPropertyName, PROPERTY_TITLE_HIGHLIGHTED) == 0) { @@ -38,11 +38,11 @@ void ControlButtonLoader::onHandlePropTypeString(Node * pNode, Node * pParent, c } else if(strcmp(pPropertyName, PROPERTY_TITLE_DISABLED) == 0) { ((ControlButton *)pNode)->setTitleForState(String::create(pString), Control::State::DISABLED); } else { - ControlLoader::onHandlePropTypeString(pNode, pParent, pPropertyName, pString, pCCBReader); + ControlLoader::onHandlePropTypeString(pNode, pParent, pPropertyName, pString, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TITLETTF_NORMAL) == 0) { ((ControlButton *)pNode)->setTitleTTFForState(pFontTTF, Control::State::NORMAL); } else if(strcmp(pPropertyName, PROPERTY_TITLETTF_HIGHLIGHTED) == 0) { @@ -50,11 +50,11 @@ void ControlButtonLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, } else if(strcmp(pPropertyName, PROPERTY_TITLETTF_DISABLED) == 0) { ((ControlButton *)pNode)->setTitleTTFForState(pFontTTF, Control::State::DISABLED); } else { - ControlLoader::onHandlePropTypeFontTTF(pNode, pParent, pPropertyName, pFontTTF, pCCBReader); + ControlLoader::onHandlePropTypeFontTTF(pNode, pParent, pPropertyName, pFontTTF, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TITLETTFSIZE_NORMAL) == 0) { ((ControlButton *)pNode)->setTitleTTFSizeForState(pFloatScale, Control::State::NORMAL); } else if(strcmp(pPropertyName, PROPERTY_TITLETTFSIZE_HIGHLIGHTED) == 0) { @@ -62,27 +62,27 @@ void ControlButtonLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParen } else if(strcmp(pPropertyName, PROPERTY_TITLETTFSIZE_DISABLED) == 0) { ((ControlButton *)pNode)->setTitleTTFSizeForState(pFloatScale, Control::State::DISABLED); } else { - ControlLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pFloatScale, pCCBReader); + ControlLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pFloatScale, ccbReader); } } -void ControlButtonLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_LABELANCHORPOINT) == 0) { ((ControlButton *)pNode)->setLabelAnchorPoint(pPoint); } else { - ControlLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, pCCBReader); + ControlLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_PREFEREDSIZE) == 0) { ((ControlButton *)pNode)->setPreferredSize(pSize); } else { - ControlLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, pCCBReader); + ControlLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BACKGROUNDSPRITEFRAME_NORMAL) == 0) { if(pSpriteFrame != NULL) { ((ControlButton *)pNode)->setBackgroundSpriteFrameForState(pSpriteFrame, Control::State::NORMAL); @@ -96,11 +96,11 @@ void ControlButtonLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pPare ((ControlButton *)pNode)->setBackgroundSpriteFrameForState(pSpriteFrame, Control::State::DISABLED); } } else { - ControlLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, pCCBReader); + ControlLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, ccbReader); } } -void ControlButtonLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void ControlButtonLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TITLECOLOR_NORMAL) == 0) { ((ControlButton *)pNode)->setTitleColorForState(pColor3B, Control::State::NORMAL); } else if(strcmp(pPropertyName, PROPERTY_TITLECOLOR_HIGHLIGHTED) == 0) { @@ -108,7 +108,7 @@ void ControlButtonLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, c } else if(strcmp(pPropertyName, PROPERTY_TITLECOLOR_DISABLED) == 0) { ((ControlButton *)pNode)->setTitleColorForState(pColor3B, Control::State::DISABLED); } else { - ControlLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + ControlLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } diff --git a/extensions/CCBReader/CCControlButtonLoader.h b/extensions/CCBReader/CCControlButtonLoader.h index 59e041d881..f5f66b8046 100644 --- a/extensions/CCBReader/CCControlButtonLoader.h +++ b/extensions/CCBReader/CCControlButtonLoader.h @@ -17,14 +17,14 @@ class ControlButtonLoader : public ControlLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(ControlButton); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader); - virtual void onHandlePropTypeString(Node * pNode, Node * pParent, const char * pPropertyName, const char * pString, CCBReader * pCCBReader); - virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * pCCBReader); - virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader); - virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader); - virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader); + virtual void onHandlePropTypeString(Node * pNode, Node * pParent, const char * pPropertyName, const char * pString, CCBReader * ccbReader); + virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * ccbReader); + virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader); + virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader); + virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCControlLoader.cpp b/extensions/CCBReader/CCControlLoader.cpp index 95ee26ec6a..aff1fd2f11 100644 --- a/extensions/CCBReader/CCControlLoader.cpp +++ b/extensions/CCBReader/CCControlLoader.cpp @@ -7,21 +7,21 @@ NS_CC_EXT_BEGIN #define PROPERTY_SELECTED "selected" #define PROPERTY_CCCONTROL "ccControl" -void ControlLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void ControlLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_ENABLED) == 0) { ((Control *)pNode)->setEnabled(pCheck); } else if(strcmp(pPropertyName, PROPERTY_SELECTED) == 0) { ((Control *)pNode)->setSelected(pCheck); } else { - NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, pCCBReader); + NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, ccbReader); } } -void ControlLoader::onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char * pPropertyName, BlockControlData * pBlockControlData, CCBReader * pCCBReader) { +void ControlLoader::onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char * pPropertyName, BlockControlData * pBlockControlData, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CCCONTROL) == 0) { - ((Control *)pNode)->addTargetWithActionForControlEvents(pBlockControlData->mTarget, pBlockControlData->mSELControlHandler, pBlockControlData->mControlEvents); + ((Control *)pNode)->addTargetWithActionForControlEvents(pBlockControlData->_target, pBlockControlData->mSELControlHandler, pBlockControlData->mControlEvents); } else { - NodeLoader::onHandlePropTypeBlockControl(pNode, pParent, pPropertyName, pBlockControlData, pCCBReader); + NodeLoader::onHandlePropTypeBlockControl(pNode, pParent, pPropertyName, pBlockControlData, ccbReader); } } diff --git a/extensions/CCBReader/CCControlLoader.h b/extensions/CCBReader/CCControlLoader.h index d40aa23bcc..728193834e 100644 --- a/extensions/CCBReader/CCControlLoader.h +++ b/extensions/CCBReader/CCControlLoader.h @@ -16,8 +16,8 @@ class ControlLoader : public NodeLoader { protected: CCB_PURE_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(Control); - virtual void onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char * pPropertyName, BlockControlData * pBlockControlData, CCBReader * pCCBReader); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader); + virtual void onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char * pPropertyName, BlockControlData * pBlockControlData, CCBReader * ccbReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCLabelBMFontLoader.cpp b/extensions/CCBReader/CCLabelBMFontLoader.cpp index 9bc808e1a7..52230fb282 100644 --- a/extensions/CCBReader/CCLabelBMFontLoader.cpp +++ b/extensions/CCBReader/CCLabelBMFontLoader.cpp @@ -10,43 +10,43 @@ NS_CC_EXT_BEGIN #define PROPERTY_FNTFILE "fntFile" #define PROPERTY_STRING "string" -void LabelBMFontLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void LabelBMFontLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_COLOR) == 0) { ((LabelBMFont *)pNode)->setColor(pColor3B); } else { - NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void LabelBMFontLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void LabelBMFontLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_OPACITY) == 0) { ((LabelBMFont *)pNode)->setOpacity(pByte); } else { - NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void LabelBMFontLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void LabelBMFontLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((LabelBMFont *)pNode)->setBlendFunc(pBlendFunc); } else { - NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } -void LabelBMFontLoader::onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char * pPropertyName, const char* pFntFile, CCBReader * pCCBReader) { +void LabelBMFontLoader::onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char * pPropertyName, const char* pFntFile, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_FNTFILE) == 0) { ((LabelBMFont *)pNode)->setFntFile(pFntFile); } else { - NodeLoader::onHandlePropTypeFntFile(pNode, pParent, pPropertyName, pFntFile, pCCBReader); + NodeLoader::onHandlePropTypeFntFile(pNode, pParent, pPropertyName, pFntFile, ccbReader); } } -void LabelBMFontLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char* pText, CCBReader * pCCBReader) { +void LabelBMFontLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char* pText, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_STRING) == 0) { ((LabelBMFont *)pNode)->setString(pText); } else { - NodeLoader::onHandlePropTypeText(pNode, pParent, pPropertyName, pText, pCCBReader); + NodeLoader::onHandlePropTypeText(pNode, pParent, pPropertyName, pText, ccbReader); } } diff --git a/extensions/CCBReader/CCLabelBMFontLoader.h b/extensions/CCBReader/CCLabelBMFontLoader.h index b2d4615d01..d786a6db06 100644 --- a/extensions/CCBReader/CCLabelBMFontLoader.h +++ b/extensions/CCBReader/CCLabelBMFontLoader.h @@ -16,11 +16,11 @@ class LabelBMFontLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(LabelBMFont); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char * pPropertyName, const char* pFntFile, CCBReader * pCCBReader); - virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char* pText, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char * pPropertyName, const char* pFntFile, CCBReader * ccbReader); + virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char* pText, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCLabelTTFLoader.cpp b/extensions/CCBReader/CCLabelTTFLoader.cpp index 7efa495f2e..470698fd8a 100644 --- a/extensions/CCBReader/CCLabelTTFLoader.cpp +++ b/extensions/CCBReader/CCLabelTTFLoader.cpp @@ -14,69 +14,69 @@ NS_CC_EXT_BEGIN -void LabelTTFLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_COLOR) == 0) { ((LabelTTF *)pNode)->setColor(pColor3B); } else { - NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_OPACITY) == 0) { ((LabelTTF *)pNode)->setOpacity(pByte); } else { - NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((LabelTTF *)pNode)->setBlendFunc(pBlendFunc); } else { - NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_FONTNAME) == 0) { ((LabelTTF *)pNode)->setFontName(pFontTTF); } else { - NodeLoader::onHandlePropTypeFontTTF(pNode, pParent, pPropertyName, pFontTTF, pCCBReader); + NodeLoader::onHandlePropTypeFontTTF(pNode, pParent, pPropertyName, pFontTTF, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char * pText, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char * pText, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_STRING) == 0) { ((LabelTTF *)pNode)->setString(pText); } else { - NodeLoader::onHandlePropTypeText(pNode, pParent, pPropertyName, pText, pCCBReader); + NodeLoader::onHandlePropTypeText(pNode, pParent, pPropertyName, pText, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_FONTSIZE) == 0) { ((LabelTTF *)pNode)->setFontSize(pFloatScale); } else { - NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pFloatScale, pCCBReader); + NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pFloatScale, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_HORIZONTALALIGNMENT) == 0) { ((LabelTTF *)pNode)->setHorizontalAlignment(TextHAlignment(pIntegerLabeled)); } else if(strcmp(pPropertyName, PROPERTY_VERTICALALIGNMENT) == 0) { ((LabelTTF *)pNode)->setVerticalAlignment(TextVAlignment(pIntegerLabeled)); } else { - NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pIntegerLabeled, pCCBReader); + NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pIntegerLabeled, ccbReader); } } -void LabelTTFLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader) { +void LabelTTFLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_DIMENSIONS) == 0) { ((LabelTTF *)pNode)->setDimensions(pSize); } else { - NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, pCCBReader); + NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, ccbReader); } } diff --git a/extensions/CCBReader/CCLabelTTFLoader.h b/extensions/CCBReader/CCLabelTTFLoader.h index 86d854016f..ff4d491ac9 100644 --- a/extensions/CCBReader/CCLabelTTFLoader.h +++ b/extensions/CCBReader/CCLabelTTFLoader.h @@ -16,14 +16,14 @@ class LabelTTFLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(LabelTTF); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * pCCBReader); - virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char * pText, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * pCCBReader); - virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader); - virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char * pPropertyName, const char * pFontTTF, CCBReader * ccbReader); + virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char * pPropertyName, const char * pText, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char * pPropertyName, float pFloatScale, CCBReader * ccbReader); + virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader); + virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCLayerColorLoader.cpp b/extensions/CCBReader/CCLayerColorLoader.cpp index cff9162f30..abac77efdf 100644 --- a/extensions/CCBReader/CCLayerColorLoader.cpp +++ b/extensions/CCBReader/CCLayerColorLoader.cpp @@ -8,27 +8,27 @@ NS_CC_EXT_BEGIN #define PROPERTY_OPACITY "opacity" #define PROPERTY_BLENDFUNC "blendFunc" -void LayerColorLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void LayerColorLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_COLOR) == 0) { ((LayerColor *)pNode)->setColor(pColor3B); } else { - LayerLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + LayerLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void LayerColorLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void LayerColorLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_OPACITY) == 0) { ((LayerColor *)pNode)->setOpacity(pByte); } else { - LayerLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + LayerLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void LayerColorLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void LayerColorLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((LayerColor *)pNode)->setBlendFunc(pBlendFunc); } else { - LayerLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + LayerLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } diff --git a/extensions/CCBReader/CCLayerColorLoader.h b/extensions/CCBReader/CCLayerColorLoader.h index f925eef772..5c6bae09b5 100644 --- a/extensions/CCBReader/CCLayerColorLoader.h +++ b/extensions/CCBReader/CCLayerColorLoader.h @@ -16,9 +16,9 @@ class LayerColorLoader : public LayerLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(LayerColor); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCLayerGradientLoader.cpp b/extensions/CCBReader/CCLayerGradientLoader.cpp index 356ba2244f..a14bfac0f7 100644 --- a/extensions/CCBReader/CCLayerGradientLoader.cpp +++ b/extensions/CCBReader/CCLayerGradientLoader.cpp @@ -11,43 +11,43 @@ NS_CC_EXT_BEGIN -void LayerGradientLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void LayerGradientLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_STARTCOLOR) == 0) { ((LayerGradient *)pNode)->setStartColor(pColor3B); } else if(strcmp(pPropertyName, PROPERTY_ENDCOLOR) == 0) { ((LayerGradient *)pNode)->setEndColor(pColor3B); } else { - LayerLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + LayerLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void LayerGradientLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void LayerGradientLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_STARTOPACITY) == 0) { ((LayerGradient *)pNode)->setStartOpacity(pByte); } else if(strcmp(pPropertyName, PROPERTY_ENDOPACITY) == 0) { ((LayerGradient *)pNode)->setEndOpacity(pByte); } else { - LayerLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + LayerLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void LayerGradientLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void LayerGradientLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((LayerGradient *)pNode)->setBlendFunc(pBlendFunc); } else { - LayerLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + LayerLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } -void LayerGradientLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader) { +void LayerGradientLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_VECTOR) == 0) { ((LayerGradient *)pNode)->setVector(pPoint); // TODO Not passed along the ccbi file. // ((LayerGradient *)pNode)->setCompressedInterpolation(true); } else { - LayerLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, pCCBReader); + LayerLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, ccbReader); } } diff --git a/extensions/CCBReader/CCLayerGradientLoader.h b/extensions/CCBReader/CCLayerGradientLoader.h index cbe2d7d8c8..4a69440013 100644 --- a/extensions/CCBReader/CCLayerGradientLoader.h +++ b/extensions/CCBReader/CCLayerGradientLoader.h @@ -16,10 +16,10 @@ class LayerGradientLoader : public LayerLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(LayerGradient); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCLayerLoader.cpp b/extensions/CCBReader/CCLayerLoader.cpp index 16c276ab02..d5f353d0f5 100644 --- a/extensions/CCBReader/CCLayerLoader.cpp +++ b/extensions/CCBReader/CCLayerLoader.cpp @@ -10,7 +10,7 @@ NS_CC_EXT_BEGIN -void LayerLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void LayerLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TOUCH_ENABLED) == 0) { ((Layer *)pNode)->setTouchEnabled(pCheck); } else if(strcmp(pPropertyName, PROPERTY_ACCELEROMETER_ENABLED) == 0) { @@ -23,7 +23,7 @@ void LayerLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char CCLOG("The property '%s' is not supported!", PROPERTY_KEYBOARD_ENABLED); // This comes closest: ((Layer *)pNode)->setKeypadEnabled(pCheck); } else { - NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, pCCBReader); + NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, ccbReader); } } diff --git a/extensions/CCBReader/CCLayerLoader.h b/extensions/CCBReader/CCLayerLoader.h index 98ac65d7c0..5475c611a7 100644 --- a/extensions/CCBReader/CCLayerLoader.h +++ b/extensions/CCBReader/CCLayerLoader.h @@ -16,7 +16,7 @@ class LayerLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(Layer); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCMenuItemImageLoader.cpp b/extensions/CCBReader/CCMenuItemImageLoader.cpp index 1d658e6796..169d2a469a 100644 --- a/extensions/CCBReader/CCMenuItemImageLoader.cpp +++ b/extensions/CCBReader/CCMenuItemImageLoader.cpp @@ -8,7 +8,7 @@ NS_CC_EXT_BEGIN -void MenuItemImageLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader) { +void MenuItemImageLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_NORMALDISPLAYFRAME) == 0) { if(pSpriteFrame != NULL) { ((MenuItemImage *)pNode)->setNormalSpriteFrame(pSpriteFrame); @@ -22,7 +22,7 @@ void MenuItemImageLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pPare ((MenuItemImage *)pNode)->setDisabledSpriteFrame(pSpriteFrame); } } else { - MenuItemLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, pCCBReader); + MenuItemLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, ccbReader); } } diff --git a/extensions/CCBReader/CCMenuItemImageLoader.h b/extensions/CCBReader/CCMenuItemImageLoader.h index 79be96ca28..c7d37bd004 100644 --- a/extensions/CCBReader/CCMenuItemImageLoader.h +++ b/extensions/CCBReader/CCMenuItemImageLoader.h @@ -16,7 +16,7 @@ class MenuItemImageLoader : public MenuItemLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(MenuItemImage); - virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader); + virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCMenuItemLoader.cpp b/extensions/CCBReader/CCMenuItemLoader.cpp index c3013315d9..d6dd6f2ecd 100644 --- a/extensions/CCBReader/CCMenuItemLoader.cpp +++ b/extensions/CCBReader/CCMenuItemLoader.cpp @@ -7,23 +7,23 @@ NS_CC_EXT_BEGIN -void MenuItemLoader::onHandlePropTypeBlock(Node * pNode, Node * pParent, const char * pPropertyName, BlockData * pBlockData, CCBReader * pCCBReader) { +void MenuItemLoader::onHandlePropTypeBlock(Node * pNode, Node * pParent, const char * pPropertyName, BlockData * pBlockData, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLOCK) == 0) { if (NULL != pBlockData) // Add this condition to allow MenuItemImage without target/selector predefined { - ((MenuItem *)pNode)->setCallback( std::bind( pBlockData->mSELMenuHandler, pBlockData->mTarget, std::placeholders::_1) ); -// ((MenuItem *)pNode)->setTarget(pBlockData->mTarget, pBlockData->mSELMenuHandler); + ((MenuItem *)pNode)->setCallback( std::bind( pBlockData->mSELMenuHandler, pBlockData->_target, std::placeholders::_1) ); +// ((MenuItem *)pNode)->setTarget(pBlockData->_target, pBlockData->mSELMenuHandler); } } else { - NodeLoader::onHandlePropTypeBlock(pNode, pParent, pPropertyName, pBlockData, pCCBReader); + NodeLoader::onHandlePropTypeBlock(pNode, pParent, pPropertyName, pBlockData, ccbReader); } } -void MenuItemLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void MenuItemLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_ISENABLED) == 0) { ((MenuItem *)pNode)->setEnabled(pCheck); } else { - NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, pCCBReader); + NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, ccbReader); } } diff --git a/extensions/CCBReader/CCMenuItemLoader.h b/extensions/CCBReader/CCMenuItemLoader.h index 3ff8de3078..6c691d5629 100644 --- a/extensions/CCBReader/CCMenuItemLoader.h +++ b/extensions/CCBReader/CCMenuItemLoader.h @@ -15,8 +15,8 @@ class MenuItemLoader : public NodeLoader { protected: CCB_PURE_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(MenuItem); - virtual void onHandlePropTypeBlock(Node * pNode, Node * pParent, const char * pPropertyName, BlockData * pBlockData, CCBReader * pCCBReader); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader); + virtual void onHandlePropTypeBlock(Node * pNode, Node * pParent, const char * pPropertyName, BlockData * pBlockData, CCBReader * ccbReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCNode+CCBRelativePositioning.cpp b/extensions/CCBReader/CCNode+CCBRelativePositioning.cpp index 51a3075cbc..4797b8ad2d 100644 --- a/extensions/CCBReader/CCNode+CCBRelativePositioning.cpp +++ b/extensions/CCBReader/CCNode+CCBRelativePositioning.cpp @@ -1,38 +1,36 @@ #include "CCNode+CCBRelativePositioning.h" #include "CCBReader.h" -using namespace cocos2d; - NS_CC_EXT_BEGIN -Point getAbsolutePosition(const Point &pt, int nType, const Size &containerSize, const char *pPropName) +Point getAbsolutePosition(const Point &pt, CCBReader::PositionType type, const Size &containerSize, const char *propName) { Point absPt = Point(0,0); - if (nType == kCCBPositionTypeRelativeBottomLeft) + if (type == CCBReader::PositionType::RELATIVE_BOTTOM_LEFT) { absPt = pt; } - else if (nType == kCCBPositionTypeRelativeTopLeft) + else if (type == CCBReader::PositionType::RELATIVE_TOP_LEFT) { absPt.x = pt.x; absPt.y = containerSize.height - pt.y; } - else if (nType == kCCBPositionTypeRelativeTopRight) + else if (type == CCBReader::PositionType::RELATIVE_TOP_RIGHT) { absPt.x = containerSize.width - pt.x; absPt.y = containerSize.height - pt.y; } - else if (nType == kCCBPositionTypeRelativeBottomRight) + else if (type == CCBReader::PositionType::RELATIVE_BOTTOM_RIGHT) { absPt.x = containerSize.width - pt.x; absPt.y = pt.y; } - else if (nType == kCCBPositionTypePercent) + else if (type == CCBReader::PositionType::PERCENT) { absPt.x = (int)(containerSize.width * pt.x / 100.0f); absPt.y = (int)(containerSize.height * pt.y / 100.0f); } - else if (nType == kCCBPositionTypeMultiplyResolution) + else if (type == CCBReader::PositionType::MULTIPLY_RESOLUTION) { float resolutionScale = CCBReader::getResolutionScale(); @@ -43,20 +41,20 @@ Point getAbsolutePosition(const Point &pt, int nType, const Size &containerSize, return absPt; } -void setRelativeScale(Node *pNode, float fScaleX, float fScaleY, int nType, const char* pPropName) +void setRelativeScale(Node *pNode, float scaleX, float scaleY, CCBReader::ScaleType type, const char* propName) { CCASSERT(pNode, "pNode should not be null"); - if (nType == kCCBScaleTypeMultiplyResolution) + if (type == CCBReader::ScaleType::MULTIPLY_RESOLUTION) { float resolutionScale = CCBReader::getResolutionScale(); - fScaleX *= resolutionScale; - fScaleY *= resolutionScale; + scaleX *= resolutionScale; + scaleY *= resolutionScale; } - pNode->setScaleX(fScaleX); - pNode->setScaleY(fScaleY); + pNode->setScaleX(scaleX); + pNode->setScaleY(scaleY); } NS_CC_EXT_END diff --git a/extensions/CCBReader/CCNode+CCBRelativePositioning.h b/extensions/CCBReader/CCNode+CCBRelativePositioning.h index 7e3acb957d..7e8a8e7baa 100644 --- a/extensions/CCBReader/CCNode+CCBRelativePositioning.h +++ b/extensions/CCBReader/CCNode+CCBRelativePositioning.h @@ -3,12 +3,13 @@ #include "cocos2d.h" #include "ExtensionMacros.h" +#include "CCBReader.h" NS_CC_EXT_BEGIN -extern Point getAbsolutePosition(const Point &pt, int nType, const Size &containerSize, const char *pPropName); +extern Point getAbsolutePosition(const Point &pt, CCBReader::PositionType type, const Size &containerSize, const char *propName); -extern void setRelativeScale(Node *pNode, float fScaleX, float fScaleY, int nType, const char* pPropName); +extern void setRelativeScale(Node *node, float scaleX, float scaleY, CCBReader::ScaleType type, const char* propName); NS_CC_EXT_END diff --git a/extensions/CCBReader/CCNodeLoader.cpp b/extensions/CCBReader/CCNodeLoader.cpp index 22ccb69fb3..6b5e7534e4 100644 --- a/extensions/CCBReader/CCNodeLoader.cpp +++ b/extensions/CCBReader/CCNodeLoader.cpp @@ -23,42 +23,42 @@ Dictionary* NodeLoader::getCustomProperties() return _customProperties; } -Node * NodeLoader::loadNode(Node * pParent, CCBReader * pCCBReader) { - Node * ccNode = this->createNode(pParent, pCCBReader); +Node * NodeLoader::loadNode(Node * pParent, CCBReader * ccbReader) { + Node * ccNode = this->createNode(pParent, ccbReader); - //this->parseProperties(ccNode, pParent, pCCBReader); + //this->parseProperties(ccNode, pParent, ccbReader); return ccNode; } -void NodeLoader::parseProperties(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - int numRegularProps = pCCBReader->readInt(false); - int numExturaProps = pCCBReader->readInt(false); +void NodeLoader::parseProperties(Node * pNode, Node * pParent, CCBReader * ccbReader) { + int numRegularProps = ccbReader->readInt(false); + int numExturaProps = ccbReader->readInt(false); int propertyCount = numRegularProps + numExturaProps; for(int i = 0; i < propertyCount; i++) { bool isExtraProp = (i >= numRegularProps); - int type = pCCBReader->readInt(false); - std::string propertyName = pCCBReader->readCachedString(); + CCBReader::PropertyType type = (CCBReader::PropertyType)ccbReader->readInt(false); + std::string propertyName = ccbReader->readCachedString(); // Check if the property can be set for this platform bool setProp = false; - int platform = pCCBReader->readByte(); - if(platform == kCCBPlatformAll) + CCBReader::PlatformType platform = (CCBReader::PlatformType)ccbReader->readByte(); + if(platform == CCBReader::PlatformType::ALL) { setProp = true; } // Cocos2d-x is using touch event callback for all platforms, // it's different from cocos2d-iphone which uses mouse event for Mac port. - // So we just need to touch event by using kCCBPlatformIOS. + // So we just need to touch event by using CCBReader::PlatformType::IOS. //#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) - if(platform == kCCBPlatformIOS) + if(platform == CCBReader::PlatformType::IOS) { setProp = true; } // #elif (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) -// if(platform == kCCBPlatformMac) +// if(platform == CCBReader::PlatformType::MAC) // { // setProp = true; // } @@ -88,7 +88,7 @@ void NodeLoader::parseProperties(Node * pNode, Node * pParent, CCBReader * pCCBR setProp &= bFound; } } - else if (isExtraProp && pNode == pCCBReader->getAnimationManager()->getRootNode()) + else if (isExtraProp && pNode == ccbReader->getAnimationManager()->getRootNode()) { Array *extraPropsNames = static_cast(pNode->getUserObject()); if (! extraPropsNames) @@ -102,246 +102,255 @@ void NodeLoader::parseProperties(Node * pNode, Node * pParent, CCBReader * pCCBR switch(type) { - case kCCBPropTypePosition: + case CCBReader::PropertyType::POSITION: { - Point position = this->parsePropTypePosition(pNode, pParent, pCCBReader, propertyName.c_str()); + Point position = this->parsePropTypePosition(pNode, pParent, ccbReader, propertyName.c_str()); if (setProp) { - this->onHandlePropTypePosition(pNode, pParent, propertyName.c_str(), position, pCCBReader); + this->onHandlePropTypePosition(pNode, pParent, propertyName.c_str(), position, ccbReader); } break; } - case kCCBPropTypePoint: + case CCBReader::PropertyType::POINT: { - Point point = this->parsePropTypePoint(pNode, pParent, pCCBReader); + Point point = this->parsePropTypePoint(pNode, pParent, ccbReader); if (setProp) { - this->onHandlePropTypePoint(pNode, pParent, propertyName.c_str(), point, pCCBReader); + this->onHandlePropTypePoint(pNode, pParent, propertyName.c_str(), point, ccbReader); } break; } - case kCCBPropTypePointLock: + case CCBReader::PropertyType::POINT_LOCK: { - Point pointLock = this->parsePropTypePointLock(pNode, pParent, pCCBReader); + Point pointLock = this->parsePropTypePointLock(pNode, pParent, ccbReader); if (setProp) { - this->onHandlePropTypePointLock(pNode, pParent, propertyName.c_str(), pointLock, pCCBReader); + this->onHandlePropTypePointLock(pNode, pParent, propertyName.c_str(), pointLock, ccbReader); } break; } - case kCCBPropTypeSize: { - Size size = this->parsePropTypeSize(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::SIZE: + { + Size size = this->parsePropTypeSize(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeSize(pNode, pParent, propertyName.c_str(), size, pCCBReader); + this->onHandlePropTypeSize(pNode, pParent, propertyName.c_str(), size, ccbReader); } break; } - case kCCBPropTypeScaleLock: + case CCBReader::PropertyType::SCALE_LOCK: { - float * scaleLock = this->parsePropTypeScaleLock(pNode, pParent, pCCBReader, propertyName.c_str()); + float * scaleLock = this->parsePropTypeScaleLock(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeScaleLock(pNode, pParent, propertyName.c_str(), scaleLock, pCCBReader); + this->onHandlePropTypeScaleLock(pNode, pParent, propertyName.c_str(), scaleLock, ccbReader); } CC_SAFE_DELETE_ARRAY(scaleLock); break; } - case kCCBPropTypeFloat: + case CCBReader::PropertyType::FLOAT: { - float f = this->parsePropTypeFloat(pNode, pParent, pCCBReader); + float f = this->parsePropTypeFloat(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFloat(pNode, pParent, propertyName.c_str(), f, pCCBReader); + this->onHandlePropTypeFloat(pNode, pParent, propertyName.c_str(), f, ccbReader); } break; } - case kCCBPropTypeFloatXY: - { - float * xy = this->parsePropTypeFloatXY(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::FLOAT_XY: + { + float * xy = this->parsePropTypeFloatXY(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFloatXY(pNode, pParent, propertyName.c_str(), xy, pCCBReader); + this->onHandlePropTypeFloatXY(pNode, pParent, propertyName.c_str(), xy, ccbReader); } CC_SAFE_DELETE_ARRAY(xy); break; - } + } - case kCCBPropTypeDegrees: + case CCBReader::PropertyType::DEGREES: { - float degrees = this->parsePropTypeDegrees(pNode, pParent, pCCBReader, propertyName.c_str()); + float degrees = this->parsePropTypeDegrees(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeDegrees(pNode, pParent, propertyName.c_str(), degrees, pCCBReader); + this->onHandlePropTypeDegrees(pNode, pParent, propertyName.c_str(), degrees, ccbReader); } break; } - case kCCBPropTypeFloatScale: + case CCBReader::PropertyType::FLOAT_SCALE: { - float floatScale = this->parsePropTypeFloatScale(pNode, pParent, pCCBReader); + float floatScale = this->parsePropTypeFloatScale(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFloatScale(pNode, pParent, propertyName.c_str(), floatScale, pCCBReader); + this->onHandlePropTypeFloatScale(pNode, pParent, propertyName.c_str(), floatScale, ccbReader); } break; } - case kCCBPropTypeInteger: + case CCBReader::PropertyType::INTEGER: { - int integer = this->parsePropTypeInteger(pNode, pParent, pCCBReader); + int integer = this->parsePropTypeInteger(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeInteger(pNode, pParent, propertyName.c_str(), integer, pCCBReader); + this->onHandlePropTypeInteger(pNode, pParent, propertyName.c_str(), integer, ccbReader); } break; } - case kCCBPropTypeIntegerLabeled: + case CCBReader::PropertyType::INTEGER_LABELED: { - int integerLabeled = this->parsePropTypeIntegerLabeled(pNode, pParent, pCCBReader); + int integerLabeled = this->parsePropTypeIntegerLabeled(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeIntegerLabeled(pNode, pParent, propertyName.c_str(), integerLabeled, pCCBReader); + this->onHandlePropTypeIntegerLabeled(pNode, pParent, propertyName.c_str(), integerLabeled, ccbReader); } break; } - case kCCBPropTypeFloatVar: + case CCBReader::PropertyType::FLOAT_VAR: { - float * floatVar = this->parsePropTypeFloatVar(pNode, pParent, pCCBReader); + float * floatVar = this->parsePropTypeFloatVar(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFloatVar(pNode, pParent, propertyName.c_str(), floatVar, pCCBReader); + this->onHandlePropTypeFloatVar(pNode, pParent, propertyName.c_str(), floatVar, ccbReader); } CC_SAFE_DELETE_ARRAY(floatVar); break; } - case kCCBPropTypeCheck: + case CCBReader::PropertyType::CHECK: { - bool check = this->parsePropTypeCheck(pNode, pParent, pCCBReader, propertyName.c_str()); + bool check = this->parsePropTypeCheck(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeCheck(pNode, pParent, propertyName.c_str(), check, pCCBReader); + this->onHandlePropTypeCheck(pNode, pParent, propertyName.c_str(), check, ccbReader); } break; } - case kCCBPropTypeSpriteFrame: { - SpriteFrame * ccSpriteFrame = this->parsePropTypeSpriteFrame(pNode, pParent, pCCBReader, propertyName.c_str()); + case CCBReader::PropertyType::SPRITEFRAME: + { + SpriteFrame * ccSpriteFrame = this->parsePropTypeSpriteFrame(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeSpriteFrame(pNode, pParent, propertyName.c_str(), ccSpriteFrame, pCCBReader); + this->onHandlePropTypeSpriteFrame(pNode, pParent, propertyName.c_str(), ccSpriteFrame, ccbReader); } break; } - case kCCBPropTypeAnimation: + case CCBReader::PropertyType::ANIMATION: { - Animation * ccAnimation = this->parsePropTypeAnimation(pNode, pParent, pCCBReader); + Animation * ccAnimation = this->parsePropTypeAnimation(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeAnimation(pNode, pParent, propertyName.c_str(), ccAnimation, pCCBReader); + this->onHandlePropTypeAnimation(pNode, pParent, propertyName.c_str(), ccAnimation, ccbReader); } break; } - case kCCBPropTypeTexture: + case CCBReader::PropertyType::TEXTURE: { - Texture2D * ccTexture2D = this->parsePropTypeTexture(pNode, pParent, pCCBReader); + Texture2D * ccTexture2D = this->parsePropTypeTexture(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeTexture(pNode, pParent, propertyName.c_str(), ccTexture2D, pCCBReader); + this->onHandlePropTypeTexture(pNode, pParent, propertyName.c_str(), ccTexture2D, ccbReader); } break; } - case kCCBPropTypeByte: + case CCBReader::PropertyType::BYTE: { - unsigned char byte = this->parsePropTypeByte(pNode, pParent, pCCBReader, propertyName.c_str()); + unsigned char byte = this->parsePropTypeByte(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeByte(pNode, pParent, propertyName.c_str(), byte, pCCBReader); + this->onHandlePropTypeByte(pNode, pParent, propertyName.c_str(), byte, ccbReader); } break; } - case kCCBPropTypeColor3: + case CCBReader::PropertyType::COLOR3: { - Color3B color3B = this->parsePropTypeColor3(pNode, pParent, pCCBReader, propertyName.c_str()); + Color3B color3B = this->parsePropTypeColor3(pNode, pParent, ccbReader, propertyName.c_str()); if(setProp) { - this->onHandlePropTypeColor3(pNode, pParent, propertyName.c_str(), color3B, pCCBReader); + this->onHandlePropTypeColor3(pNode, pParent, propertyName.c_str(), color3B, ccbReader); } break; } - case kCCBPropTypeColor4FVar: + case CCBReader::PropertyType::COLOR4F_VAR: { - Color4F * color4FVar = this->parsePropTypeColor4FVar(pNode, pParent, pCCBReader); + Color4F * color4FVar = this->parsePropTypeColor4FVar(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeColor4FVar(pNode, pParent, propertyName.c_str(), color4FVar, pCCBReader); + this->onHandlePropTypeColor4FVar(pNode, pParent, propertyName.c_str(), color4FVar, ccbReader); } CC_SAFE_DELETE_ARRAY(color4FVar); break; } - case kCCBPropTypeFlip: { - bool * flip = this->parsePropTypeFlip(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::FLIP: + { + bool * flip = this->parsePropTypeFlip(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFlip(pNode, pParent, propertyName.c_str(), flip, pCCBReader); + this->onHandlePropTypeFlip(pNode, pParent, propertyName.c_str(), flip, ccbReader); } CC_SAFE_DELETE_ARRAY(flip); break; } - case kCCBPropTypeBlendmode: + case CCBReader::PropertyType::BLEND_MODE: { - BlendFunc blendFunc = this->parsePropTypeBlendFunc(pNode, pParent, pCCBReader); + BlendFunc blendFunc = this->parsePropTypeBlendFunc(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeBlendFunc(pNode, pParent, propertyName.c_str(), blendFunc, pCCBReader); + this->onHandlePropTypeBlendFunc(pNode, pParent, propertyName.c_str(), blendFunc, ccbReader); } break; } - case kCCBPropTypeFntFile: + case CCBReader::PropertyType::FNT_FILE: { - std::string fntFile = pCCBReader->getCCBRootPath() + this->parsePropTypeFntFile(pNode, pParent, pCCBReader); + std::string fntFile = ccbReader->getCCBRootPath() + this->parsePropTypeFntFile(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFntFile(pNode, pParent, propertyName.c_str(), fntFile.c_str(), pCCBReader); + this->onHandlePropTypeFntFile(pNode, pParent, propertyName.c_str(), fntFile.c_str(), ccbReader); } break; } - case kCCBPropTypeFontTTF: { - std::string fontTTF = this->parsePropTypeFontTTF(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::FONT_TTF: + { + std::string fontTTF = this->parsePropTypeFontTTF(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeFontTTF(pNode, pParent, propertyName.c_str(), fontTTF.c_str(), pCCBReader); + this->onHandlePropTypeFontTTF(pNode, pParent, propertyName.c_str(), fontTTF.c_str(), ccbReader); } break; } - case kCCBPropTypeString: { - std::string string = this->parsePropTypeString(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::STRING: + { + std::string string = this->parsePropTypeString(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeString(pNode, pParent, propertyName.c_str(), string.c_str(), pCCBReader); + this->onHandlePropTypeString(pNode, pParent, propertyName.c_str(), string.c_str(), ccbReader); } break; } - case kCCBPropTypeText: { - std::string text = this->parsePropTypeText(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::TEXT: + { + std::string text = this->parsePropTypeText(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeText(pNode, pParent, propertyName.c_str(), text.c_str(), pCCBReader); + this->onHandlePropTypeText(pNode, pParent, propertyName.c_str(), text.c_str(), ccbReader); } break; } - case kCCBPropTypeBlock: { - BlockData * blockData = this->parsePropTypeBlock(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::BLOCK: + { + BlockData * blockData = this->parsePropTypeBlock(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeBlock(pNode, pParent, propertyName.c_str(), blockData, pCCBReader); + this->onHandlePropTypeBlock(pNode, pParent, propertyName.c_str(), blockData, ccbReader); } CC_SAFE_DELETE(blockData); break; } - case kCCBPropTypeBlockControl: { - BlockControlData * blockControlData = this->parsePropTypeBlockControl(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::BLOCK_CONTROL: + { + BlockControlData * blockControlData = this->parsePropTypeBlockControl(pNode, pParent, ccbReader); if(setProp && blockControlData != NULL) { - this->onHandlePropTypeBlockControl(pNode, pParent, propertyName.c_str(), blockControlData, pCCBReader); + this->onHandlePropTypeBlockControl(pNode, pParent, propertyName.c_str(), blockControlData, ccbReader); } CC_SAFE_DELETE(blockControlData); break; } - case kCCBPropTypeCCBFile: { - Node * ccbFileNode = this->parsePropTypeCCBFile(pNode, pParent, pCCBReader); + case CCBReader::PropertyType::CCB_FILE: + { + Node * ccbFileNode = this->parsePropTypeCCBFile(pNode, pParent, ccbReader); if(setProp) { - this->onHandlePropTypeCCBFile(pNode, pParent, propertyName.c_str(), ccbFileNode, pCCBReader); + this->onHandlePropTypeCCBFile(pNode, pParent, propertyName.c_str(), ccbFileNode, ccbReader); } break; } @@ -352,82 +361,83 @@ void NodeLoader::parseProperties(Node * pNode, Node * pParent, CCBReader * pCCBR } } -Point NodeLoader::parsePropTypePosition(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) { - float x = pCCBReader->readFloat(); - float y = pCCBReader->readFloat(); +Point NodeLoader::parsePropTypePosition(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) +{ + float x = ccbReader->readFloat(); + float y = ccbReader->readFloat(); - int type = pCCBReader->readInt(false); + CCBReader::PositionType type = static_cast(ccbReader->readInt(false)); - Size containerSize = pCCBReader->getAnimationManager()->getContainerSize(pParent); + Size containerSize = ccbReader->getAnimationManager()->getContainerSize(pParent); Point pt = getAbsolutePosition(Point(x,y), type, containerSize, pPropertyName); pNode->setPosition(pt); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { Array *baseValue = Array::create(CCBValue::create(x), CCBValue::create(y), - CCBValue::create(type), + CCBValue::create((int)type), NULL); - pCCBReader->getAnimationManager()->setBaseValue(baseValue, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(baseValue, pNode, pPropertyName); } return pt; } -Point NodeLoader::parsePropTypePoint(Node * pNode, Node * pParent, CCBReader * pCCBReader) +Point NodeLoader::parsePropTypePoint(Node * pNode, Node * pParent, CCBReader * ccbReader) { - float x = pCCBReader->readFloat(); - float y = pCCBReader->readFloat(); + float x = ccbReader->readFloat(); + float y = ccbReader->readFloat(); return Point(x, y); } -Point NodeLoader::parsePropTypePointLock(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - float x = pCCBReader->readFloat(); - float y = pCCBReader->readFloat(); +Point NodeLoader::parsePropTypePointLock(Node * pNode, Node * pParent, CCBReader * ccbReader) { + float x = ccbReader->readFloat(); + float y = ccbReader->readFloat(); return Point(x, y); } -Size NodeLoader::parsePropTypeSize(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - float width = pCCBReader->readFloat(); - float height = pCCBReader->readFloat(); +Size NodeLoader::parsePropTypeSize(Node * pNode, Node * pParent, CCBReader * ccbReader) { + float width = ccbReader->readFloat(); + float height = ccbReader->readFloat(); - int type = pCCBReader->readInt(false); + CCBReader::SizeType type = static_cast(ccbReader->readInt(false)); - Size containerSize = pCCBReader->getAnimationManager()->getContainerSize(pParent); + Size containerSize = ccbReader->getAnimationManager()->getContainerSize(pParent); switch (type) { - case kCCBSizeTypeAbsolute: + case CCBReader::SizeType::ABSOLUTE: { /* Nothing. */ break; } - case kCCBSizeTypeRelativeContainer: + case CCBReader::SizeType::RELATIVE_CONTAINER: { width = containerSize.width - width; height = containerSize.height - height; break; } - case kCCBSizeTypePercent: + case CCBReader::SizeType::PERCENT: { width = (int)(containerSize.width * width / 100.0f); height = (int)(containerSize.height * height / 100.0f); break; } - case kCCBSizeTypeHorizontalPercent: + case CCBReader::SizeType::HORIZONTAL_PERCENT: { width = (int)(containerSize.width * width / 100.0f); break; } - case kCCBSizeTypeVerticalPercent: + case CCBReader::SizeType::VERTICAL_PERCENT: { height = (int)(containerSize.height * height / 100.0f); break; } - case kCCBSizeTypeMultiplyResolution: + case CCBReader::SizeType::MULTIPLY_RESOLUTION: { float resolutionScale = CCBReader::getResolutionScale(); @@ -447,9 +457,9 @@ Size NodeLoader::parsePropTypeSize(Node * pNode, Node * pParent, CCBReader * pCC -float * NodeLoader::parsePropTypeFloatXY(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - float x = pCCBReader->readFloat(); - float y = pCCBReader->readFloat(); +float * NodeLoader::parsePropTypeFloatXY(Node * pNode, Node * pParent, CCBReader * ccbReader) { + float x = ccbReader->readFloat(); + float y = ccbReader->readFloat(); float * floatXY = new float[2]; floatXY[0] = x; @@ -458,27 +468,27 @@ float * NodeLoader::parsePropTypeFloatXY(Node * pNode, Node * pParent, CCBReader return floatXY; } -float * NodeLoader::parsePropTypeScaleLock(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) { - float x = pCCBReader->readFloat(); - float y = pCCBReader->readFloat(); +float * NodeLoader::parsePropTypeScaleLock(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { + float x = ccbReader->readFloat(); + float y = ccbReader->readFloat(); - int type = pCCBReader->readInt(false); + CCBReader::ScaleType type = static_cast(ccbReader->readInt(false)); setRelativeScale(pNode, x, y, type, pPropertyName); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { Array *baseValue = Array::create(CCBValue::create(x), CCBValue::create(y), - CCBValue::create(type), + CCBValue::create((int)type), NULL); - pCCBReader->getAnimationManager()->setBaseValue(baseValue, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(baseValue, pNode, pPropertyName); } - if (type == kCCBScaleTypeMultiplyResolution) + if (type == CCBReader::ScaleType::MULTIPLY_RESOLUTION) { - x *= pCCBReader->getResolutionScale(); - y *= pCCBReader->getResolutionScale(); + x *= ccbReader->getResolutionScale(); + y *= ccbReader->getResolutionScale(); } float * scaleLock = new float[2]; @@ -488,49 +498,49 @@ float * NodeLoader::parsePropTypeScaleLock(Node * pNode, Node * pParent, CCBRead return scaleLock; } -float NodeLoader::parsePropTypeFloat(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - return pCCBReader->readFloat(); +float NodeLoader::parsePropTypeFloat(Node * pNode, Node * pParent, CCBReader * ccbReader) { + return ccbReader->readFloat(); } -float NodeLoader::parsePropTypeDegrees(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) { - float ret = pCCBReader->readFloat(); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) +float NodeLoader::parsePropTypeDegrees(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { + float ret = ccbReader->readFloat(); + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { CCBValue *value = CCBValue::create(ret); - pCCBReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); } return ret; } -float NodeLoader::parsePropTypeFloatScale(Node * pNode, Node * pParent, CCBReader * pCCBReader) +float NodeLoader::parsePropTypeFloatScale(Node * pNode, Node * pParent, CCBReader * ccbReader) { - float f = pCCBReader->readFloat(); + float f = ccbReader->readFloat(); - int type = pCCBReader->readInt(false); + CCBReader::ScaleType type = static_cast(ccbReader->readInt(false)); - if(type == kCCBScaleTypeMultiplyResolution) + if(type == CCBReader::ScaleType::MULTIPLY_RESOLUTION) { - f *= pCCBReader->getResolutionScale(); + f *= ccbReader->getResolutionScale(); } return f; } -int NodeLoader::parsePropTypeInteger(Node * pNode, Node * pParent, CCBReader * pCCBReader) +int NodeLoader::parsePropTypeInteger(Node * pNode, Node * pParent, CCBReader * ccbReader) { - return pCCBReader->readInt(true); + return ccbReader->readInt(true); } -int NodeLoader::parsePropTypeIntegerLabeled(Node * pNode, Node * pParent, CCBReader * pCCBReader) +int NodeLoader::parsePropTypeIntegerLabeled(Node * pNode, Node * pParent, CCBReader * ccbReader) { - return pCCBReader->readInt(true); + return ccbReader->readInt(true); } -float * NodeLoader::parsePropTypeFloatVar(Node * pNode, Node * pParent, CCBReader * pCCBReader) +float * NodeLoader::parsePropTypeFloatVar(Node * pNode, Node * pParent, CCBReader * ccbReader) { - float f = pCCBReader->readFloat(); - float fVar = pCCBReader->readFloat(); + float f = ccbReader->readFloat(); + float fVar = ccbReader->readFloat(); float * arr = new float[2]; arr[0] = f; @@ -539,31 +549,31 @@ float * NodeLoader::parsePropTypeFloatVar(Node * pNode, Node * pParent, CCBReade return arr; } -bool NodeLoader::parsePropTypeCheck(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) +bool NodeLoader::parsePropTypeCheck(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { - bool ret = pCCBReader->readBool(); + bool ret = ccbReader->readBool(); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { CCBValue *value = CCBValue::create(ret); - pCCBReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); } return ret; } -SpriteFrame * NodeLoader::parsePropTypeSpriteFrame(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) +SpriteFrame * NodeLoader::parsePropTypeSpriteFrame(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { - std::string spriteSheet = pCCBReader->readCachedString(); - std::string spriteFile = pCCBReader->readCachedString(); + std::string spriteSheet = ccbReader->readCachedString(); + std::string spriteFile = ccbReader->readCachedString(); SpriteFrame *spriteFrame = NULL; if (spriteFile.length() != 0) { if (spriteSheet.length() == 0) { - spriteFile = pCCBReader->getCCBRootPath() + spriteFile; + spriteFile = ccbReader->getCCBRootPath() + spriteFile; Texture2D * texture = TextureCache::getInstance()->addImage(spriteFile.c_str()); if(texture != NULL) { Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height); @@ -573,29 +583,29 @@ SpriteFrame * NodeLoader::parsePropTypeSpriteFrame(Node * pNode, Node * pParent, else { SpriteFrameCache * frameCache = SpriteFrameCache::getInstance(); - spriteSheet = pCCBReader->getCCBRootPath() + spriteSheet; + spriteSheet = ccbReader->getCCBRootPath() + spriteSheet; // Load the sprite sheet only if it is not loaded - if (pCCBReader->getLoadedSpriteSheet().find(spriteSheet) == pCCBReader->getLoadedSpriteSheet().end()) + if (ccbReader->getLoadedSpriteSheet().find(spriteSheet) == ccbReader->getLoadedSpriteSheet().end()) { frameCache->addSpriteFramesWithFile(spriteSheet.c_str()); - pCCBReader->getLoadedSpriteSheet().insert(spriteSheet); + ccbReader->getLoadedSpriteSheet().insert(spriteSheet); } spriteFrame = frameCache->getSpriteFrameByName(spriteFile.c_str()); } - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { - pCCBReader->getAnimationManager()->setBaseValue(spriteFrame, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(spriteFrame, pNode, pPropertyName); } } return spriteFrame; } -Animation * NodeLoader::parsePropTypeAnimation(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - std::string animationFile = pCCBReader->getCCBRootPath() + pCCBReader->readCachedString(); - std::string animation = pCCBReader->readCachedString(); +Animation * NodeLoader::parsePropTypeAnimation(Node * pNode, Node * pParent, CCBReader * ccbReader) { + std::string animationFile = ccbReader->getCCBRootPath() + ccbReader->readCachedString(); + std::string animation = ccbReader->readCachedString(); Animation * ccAnimation = NULL; @@ -617,8 +627,8 @@ Animation * NodeLoader::parsePropTypeAnimation(Node * pNode, Node * pParent, CCB return ccAnimation; } -Texture2D * NodeLoader::parsePropTypeTexture(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - std::string spriteFile = pCCBReader->getCCBRootPath() + pCCBReader->readCachedString(); +Texture2D * NodeLoader::parsePropTypeTexture(Node * pNode, Node * pParent, CCBReader * ccbReader) { + std::string spriteFile = ccbReader->getCCBRootPath() + ccbReader->readCachedString(); if (spriteFile.length() > 0) { @@ -630,41 +640,41 @@ Texture2D * NodeLoader::parsePropTypeTexture(Node * pNode, Node * pParent, CCBRe } } -unsigned char NodeLoader::parsePropTypeByte(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) +unsigned char NodeLoader::parsePropTypeByte(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { - unsigned char ret = pCCBReader->readByte(); + unsigned char ret = ccbReader->readByte(); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { - pCCBReader->getAnimationManager()->setBaseValue(CCBValue::create(ret), pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(CCBValue::create(ret), pNode, pPropertyName); } return ret; } -Color3B NodeLoader::parsePropTypeColor3(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName) { - unsigned char red = pCCBReader->readByte(); - unsigned char green = pCCBReader->readByte(); - unsigned char blue = pCCBReader->readByte(); +Color3B NodeLoader::parsePropTypeColor3(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName) { + unsigned char red = ccbReader->readByte(); + unsigned char green = ccbReader->readByte(); + unsigned char blue = ccbReader->readByte(); Color3B color(red, green, blue); - if (pCCBReader->getAnimatedProperties()->find(pPropertyName) != pCCBReader->getAnimatedProperties()->end()) + if (ccbReader->getAnimatedProperties()->find(pPropertyName) != ccbReader->getAnimatedProperties()->end()) { Color3BWapper *value = Color3BWapper::create(color); - pCCBReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); + ccbReader->getAnimationManager()->setBaseValue(value, pNode, pPropertyName); } return color; } -Color4F * NodeLoader::parsePropTypeColor4FVar(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - float red = pCCBReader->readFloat(); - float green = pCCBReader->readFloat(); - float blue = pCCBReader->readFloat(); - float alpha = pCCBReader->readFloat(); - float redVar = pCCBReader->readFloat(); - float greenVar = pCCBReader->readFloat(); - float blueVar = pCCBReader->readFloat(); - float alphaVar = pCCBReader->readFloat(); +Color4F * NodeLoader::parsePropTypeColor4FVar(Node * pNode, Node * pParent, CCBReader * ccbReader) { + float red = ccbReader->readFloat(); + float green = ccbReader->readFloat(); + float blue = ccbReader->readFloat(); + float alpha = ccbReader->readFloat(); + float redVar = ccbReader->readFloat(); + float greenVar = ccbReader->readFloat(); + float blueVar = ccbReader->readFloat(); + float alphaVar = ccbReader->readFloat(); Color4F * colors = new Color4F[2]; colors[0].r = red; @@ -680,9 +690,9 @@ Color4F * NodeLoader::parsePropTypeColor4FVar(Node * pNode, Node * pParent, CCBR return colors; } -bool * NodeLoader::parsePropTypeFlip(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - bool flipX = pCCBReader->readBool(); - bool flipY = pCCBReader->readBool(); +bool * NodeLoader::parsePropTypeFlip(Node * pNode, Node * pParent, CCBReader * ccbReader) { + bool flipX = ccbReader->readBool(); + bool flipY = ccbReader->readBool(); bool * arr = new bool[2]; arr[0] = flipX; @@ -691,10 +701,10 @@ bool * NodeLoader::parsePropTypeFlip(Node * pNode, Node * pParent, CCBReader * p return arr; } -BlendFunc NodeLoader::parsePropTypeBlendFunc(Node * pNode, Node * pParent, CCBReader * pCCBReader) +BlendFunc NodeLoader::parsePropTypeBlendFunc(Node * pNode, Node * pParent, CCBReader * ccbReader) { - int source = pCCBReader->readInt(false); - int destination = pCCBReader->readInt(false); + int source = ccbReader->readInt(false); + int destination = ccbReader->readInt(false); BlendFunc blendFunc; blendFunc.src = source; @@ -703,21 +713,21 @@ BlendFunc NodeLoader::parsePropTypeBlendFunc(Node * pNode, Node * pParent, CCBRe return blendFunc; } -std::string NodeLoader::parsePropTypeFntFile(Node * pNode, Node * pParent, CCBReader * pCCBReader) +std::string NodeLoader::parsePropTypeFntFile(Node * pNode, Node * pParent, CCBReader * ccbReader) { - return pCCBReader->readCachedString(); + return ccbReader->readCachedString(); } -std::string NodeLoader::parsePropTypeString(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - return pCCBReader->readCachedString(); +std::string NodeLoader::parsePropTypeString(Node * pNode, Node * pParent, CCBReader * ccbReader) { + return ccbReader->readCachedString(); } -std::string NodeLoader::parsePropTypeText(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - return pCCBReader->readCachedString(); +std::string NodeLoader::parsePropTypeText(Node * pNode, Node * pParent, CCBReader * ccbReader) { + return ccbReader->readCachedString(); } -std::string NodeLoader::parsePropTypeFontTTF(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - std::string fontTTF = pCCBReader->readCachedString(); +std::string NodeLoader::parsePropTypeFontTTF(Node * pNode, Node * pParent, CCBReader * ccbReader) { + std::string fontTTF = ccbReader->readCachedString(); // String * ttfEnding = String::create(".ttf"); @@ -726,39 +736,50 @@ std::string NodeLoader::parsePropTypeFontTTF(Node * pNode, Node * pParent, CCBRe * System fonts come without the ".ttf" extension and do not need the path prepended. */ /* if(CCBReader::endsWith(CCBReader::toLowerCase(fontTTF), ttfEnding)){ - fontTTF = CCBReader::concat(pCCBReader->getCCBRootPath(), fontTTF); + fontTTF = CCBReader::concat(ccbReader->getCCBRootPath(), fontTTF); } */ return fontTTF; } -BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - std::string selectorName = pCCBReader->readCachedString(); - int selectorTarget = pCCBReader->readInt(false); +BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBReader * ccbReader) +{ + std::string selectorName = ccbReader->readCachedString(); + CCBReader::TargetType selectorTarget = static_cast(ccbReader->readInt(false)); - if(selectorTarget != kCCBTargetTypeNone) { + if(selectorTarget != CCBReader::TargetType::NONE) + { Object * target = NULL; - if(!pCCBReader->isJSControlled()) { - - if(selectorTarget == kCCBTargetTypeDocumentRoot) { - target = pCCBReader->getAnimationManager()->getRootNode(); - } else if(selectorTarget == kCCBTargetTypeOwner) { - target = pCCBReader->getOwner(); + if(!ccbReader->isJSControlled()) + { + if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) + { + target = ccbReader->getAnimationManager()->getRootNode(); + } + else if(selectorTarget == CCBReader::TargetType::OWNER) + { + target = ccbReader->getOwner(); } - if(target != NULL) { - if(selectorName.length() > 0) { + if(target != NULL) + { + if(selectorName.length() > 0) + { SEL_MenuHandler selMenuHandler = 0; CCBSelectorResolver * targetAsCCBSelectorResolver = dynamic_cast(target); - if(targetAsCCBSelectorResolver != NULL) { + if(targetAsCCBSelectorResolver != NULL) + { selMenuHandler = targetAsCCBSelectorResolver->onResolveCCBCCMenuItemSelector(target, selectorName.c_str()); } - if(selMenuHandler == 0) { - CCBSelectorResolver * ccbSelectorResolver = pCCBReader->getCCBSelectorResolver(); - if(ccbSelectorResolver != NULL) { + + if(selMenuHandler == 0) + { + CCBSelectorResolver * ccbSelectorResolver = ccbReader->getCCBSelectorResolver(); + if(ccbSelectorResolver != NULL) + { selMenuHandler = ccbSelectorResolver->onResolveCCBCCMenuItemSelector(target, selectorName.c_str()); } } @@ -769,7 +790,7 @@ BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBRead BlockData * blockData = new BlockData(); blockData->mSELMenuHandler = selMenuHandler; - blockData->mTarget = target; + blockData->_target = target; return blockData; } @@ -780,13 +801,13 @@ BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBRead CCLOG("Unexpected NULL target for selector."); } } else { - if(selectorTarget == kCCBTargetTypeDocumentRoot) { - pCCBReader->addDocumentCallbackNode(pNode); - pCCBReader->addDocumentCallbackName(selectorName); + if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) { + ccbReader->addDocumentCallbackNode(pNode); + ccbReader->addDocumentCallbackName(selectorName); } else { - pCCBReader->addOwnerCallbackNode(pNode); - pCCBReader->addOwnerCallbackName(selectorName); + ccbReader->addOwnerCallbackNode(pNode); + ccbReader->addOwnerCallbackName(selectorName); } } } @@ -794,44 +815,58 @@ BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBRead return NULL; } -BlockControlData * NodeLoader::parsePropTypeBlockControl(Node * pNode, Node * pParent, CCBReader * pCCBReader) { - std::string selectorName = pCCBReader->readCachedString(); - int selectorTarget = pCCBReader->readInt(false); - int controlEvents = pCCBReader->readInt(false); +BlockControlData * NodeLoader::parsePropTypeBlockControl(Node * pNode, Node * pParent, CCBReader * ccbReader) +{ + std::string selectorName = ccbReader->readCachedString(); + CCBReader::TargetType selectorTarget = static_cast(ccbReader->readInt(false)); + int controlEvents = ccbReader->readInt(false); - if(selectorTarget != kCCBTargetTypeNone) { - - if(!pCCBReader->isJSControlled()) { + if(selectorTarget != CCBReader::TargetType::NONE) + { + if(!ccbReader->isJSControlled()) + { Object * target = NULL; - if(selectorTarget == kCCBTargetTypeDocumentRoot) { - target = pCCBReader->getAnimationManager()->getRootNode(); - } else if(selectorTarget == kCCBTargetTypeOwner) { - target = pCCBReader->getOwner(); + if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) + { + target = ccbReader->getAnimationManager()->getRootNode(); + } + else if(selectorTarget == CCBReader::TargetType::OWNER) + { + target = ccbReader->getOwner(); } - if(target != NULL) { - if(selectorName.length() > 0) { + if(target != NULL) + { + if(selectorName.length() > 0) + { Control::Handler selControlHandler = 0; CCBSelectorResolver * targetAsCCBSelectorResolver = dynamic_cast(target); - if(targetAsCCBSelectorResolver != NULL) { + if(targetAsCCBSelectorResolver != NULL) + { selControlHandler = targetAsCCBSelectorResolver->onResolveCCBCCControlSelector(target, selectorName.c_str()); } - if(selControlHandler == 0) { - CCBSelectorResolver * ccbSelectorResolver = pCCBReader->getCCBSelectorResolver(); - if(ccbSelectorResolver != NULL) { + + if(selControlHandler == 0) + { + CCBSelectorResolver * ccbSelectorResolver = ccbReader->getCCBSelectorResolver(); + if(ccbSelectorResolver != NULL) + { selControlHandler = ccbSelectorResolver->onResolveCCBCCControlSelector(target, selectorName.c_str()); } } - if(selControlHandler == 0) { + if(selControlHandler == 0) + { CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str()); - } else { + } + else + { BlockControlData * blockControlData = new BlockControlData(); blockControlData->mSELControlHandler = selControlHandler; - blockControlData->mTarget = target; + blockControlData->_target = target; blockControlData->mControlEvents = (Control::EventType)controlEvents; return blockControlData; @@ -842,14 +877,19 @@ BlockControlData * NodeLoader::parsePropTypeBlockControl(Node * pNode, Node * pP } else { CCLOG("Unexpected NULL target for selector."); } - } else { - if(selectorTarget == kCCBTargetTypeDocumentRoot) { - pCCBReader->addDocumentCallbackNode(pNode); - pCCBReader->addDocumentCallbackName(selectorName); + } + else + { + if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT) + { + ccbReader->addDocumentCallbackNode(pNode); + ccbReader->addDocumentCallbackName(selectorName); - } else { - pCCBReader->addOwnerCallbackNode(pNode); - pCCBReader->addOwnerCallbackName(selectorName); + } + else + { + ccbReader->addOwnerCallbackNode(pNode); + ccbReader->addOwnerCallbackName(selectorName); } } } @@ -869,47 +909,47 @@ Node * NodeLoader::parsePropTypeCCBFile(Node * pNode, Node * pParent, CCBReader unsigned long size = 0; unsigned char * pBytes = FileUtils::getInstance()->getFileData(path.c_str(), "rb", &size); - CCBReader * ccbReader = new CCBReader(pCCBReader); - ccbReader->autorelease(); - ccbReader->getAnimationManager()->setRootContainerSize(pParent->getContentSize()); + CCBReader * reader = new CCBReader(pCCBReader); + reader->autorelease(); + reader->getAnimationManager()->setRootContainerSize(pParent->getContentSize()); Data *data = new Data(pBytes, size); CC_SAFE_DELETE_ARRAY(pBytes); data->retain(); - ccbReader->mData = data; - ccbReader->mBytes = data->getBytes(); - ccbReader->mCurrentByte = 0; - ccbReader->mCurrentBit = 0; - CC_SAFE_RETAIN(pCCBReader->mOwner); - ccbReader->mOwner = pCCBReader->mOwner; + reader->_data = data; + reader->_bytes = data->getBytes(); + reader->_currentByte = 0; + reader->_currentBit = 0; + CC_SAFE_RETAIN(pCCBReader->_owner); + reader->_owner = pCCBReader->_owner; - ccbReader->getAnimationManager()->mOwner = ccbReader->mOwner; + reader->getAnimationManager()->_owner = reader->_owner; // The assignments below are done in the CCBReader constructor. -// ccbReader->mOwnerOutletNames = pCCBReader->mOwnerOutletNames; -// ccbReader->mOwnerOutletNodes = pCCBReader->mOwnerOutletNodes; -// ccbReader->mOwnerOutletNodes->retain(); -// ccbReader->mOwnerCallbackNames = pCCBReader->mOwnerCallbackNames; -// ccbReader->mOwnerCallbackNodes = pCCBReader->mOwnerCallbackNodes; -// ccbReader->mOwnerCallbackNodes->retain(); +// reader->_ownerOutletNames = pCCBReader->_ownerOutletNames; +// reader->_ownerOutletNodes = pCCBReader->_ownerOutletNodes; +// reader->_ownerOutletNodes->retain(); +// reader->_ownerCallbackNames = pCCBReader->_ownerCallbackNames; +// reader->_ownerCallbackNodes = pCCBReader->_ownerCallbackNodes; +// reader->_ownerCallbackNodes->retain(); data->release(); - Node * ccbFileNode = ccbReader->readFileWithCleanUp(false, pCCBReader->getAnimationManagers()); + Node * ccbFileNode = reader->readFileWithCleanUp(false, pCCBReader->getAnimationManagers()); - if (ccbFileNode && ccbReader->getAnimationManager()->getAutoPlaySequenceId() != -1) + if (ccbFileNode && reader->getAnimationManager()->getAutoPlaySequenceId() != -1) { // Auto play animations - ccbReader->getAnimationManager()->runAnimationsForSequenceIdTweenDuration(ccbReader->getAnimationManager()->getAutoPlaySequenceId(), 0); + reader->getAnimationManager()->runAnimationsForSequenceIdTweenDuration(reader->getAnimationManager()->getAutoPlaySequenceId(), 0); } - if (ccbReader->isJSControlled() && pCCBReader->isJSControlled() && NULL != ccbReader->mOwner) + if (reader->isJSControlled() && pCCBReader->isJSControlled() && NULL != reader->_owner) { //set variables and callback to owner //set callback - Array *ownerCallbackNames = ccbReader->getOwnerCallbackNames(); - Array *ownerCallbackNodes = ccbReader->getOwnerCallbackNodes(); + Array *ownerCallbackNames = reader->getOwnerCallbackNames(); + Array *ownerCallbackNodes = reader->getOwnerCallbackNodes(); if (NULL != ownerCallbackNames && ownerCallbackNames->count() > 0 && NULL != ownerCallbackNodes && ownerCallbackNodes->count() > 0) { @@ -921,8 +961,8 @@ Node * NodeLoader::parsePropTypeCCBFile(Node * pNode, Node * pParent, CCBReader } } //set variables - Array *ownerOutletNames = ccbReader->getOwnerOutletNames(); - Array *ownerOutletNodes = ccbReader->getOwnerOutletNodes(); + Array *ownerOutletNames = reader->getOwnerOutletNames(); + Array *ownerOutletNodes = reader->getOwnerOutletNodes(); if (NULL != ownerOutletNames && ownerOutletNames->count() > 0 && NULL != ownerOutletNodes && ownerOutletNodes->count() > 0) { @@ -939,7 +979,7 @@ Node * NodeLoader::parsePropTypeCCBFile(Node * pNode, Node * pParent, CCBReader -void NodeLoader::onHandlePropTypePosition(Node * pNode, Node * pParent, const char* pPropertyName, Point pPosition, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypePosition(Node * pNode, Node * pParent, const char* pPropertyName, Point pPosition, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_POSITION) == 0) { pNode->setPosition(pPosition); } else { @@ -947,7 +987,7 @@ void NodeLoader::onHandlePropTypePosition(Node * pNode, Node * pParent, const ch } } -void NodeLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char* pPropertyName, Point pPoint, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char* pPropertyName, Point pPoint, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_ANCHORPOINT) == 0) { pNode->setAnchorPoint(pPoint); } else { @@ -955,11 +995,11 @@ void NodeLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char* } } -void NodeLoader::onHandlePropTypePointLock(Node * pNode, Node * pParent, const char* pPropertyName, Point pPointLock, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypePointLock(Node * pNode, Node * pParent, const char* pPropertyName, Point pPointLock, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char* pPropertyName, Size pSize, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char* pPropertyName, Size pSize, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CONTENTSIZE) == 0) { pNode->setContentSize(pSize); } else { @@ -967,7 +1007,7 @@ void NodeLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char* } } -void NodeLoader::onHandlePropTypeFloatXY(Node * pNode, Node * pParent, const char* pPropertyName, float * pFloat, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFloatXY(Node * pNode, Node * pParent, const char* pPropertyName, float * pFloat, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_SKEW) == 0) { pNode->setSkewX(pFloat[0]); pNode->setSkewY(pFloat[1]); @@ -977,7 +1017,7 @@ void NodeLoader::onHandlePropTypeFloatXY(Node * pNode, Node * pParent, const cha } -void NodeLoader::onHandlePropTypeScaleLock(Node * pNode, Node * pParent, const char* pPropertyName, float * pScaleLock, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeScaleLock(Node * pNode, Node * pParent, const char* pPropertyName, float * pScaleLock, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_SCALE) == 0) { pNode->setScaleX(pScaleLock[0]); pNode->setScaleY(pScaleLock[1]); @@ -986,14 +1026,14 @@ void NodeLoader::onHandlePropTypeScaleLock(Node * pNode, Node * pParent, const c } } -void NodeLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char* pPropertyName, float pFloat, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char* pPropertyName, float pFloat, CCBReader * ccbReader) { // ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); // It may be a custom property, add it to custom property dictionary. _customProperties->setObject(CCBValue::create(pFloat), pPropertyName); } -void NodeLoader::onHandlePropTypeDegrees(Node * pNode, Node * pParent, const char* pPropertyName, float pDegrees, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeDegrees(Node * pNode, Node * pParent, const char* pPropertyName, float pDegrees, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_ROTATION) == 0) { pNode->setRotation(pDegrees); } else if(strcmp(pPropertyName, PROPERTY_ROTATIONX) == 0) { @@ -1006,11 +1046,11 @@ void NodeLoader::onHandlePropTypeDegrees(Node * pNode, Node * pParent, const cha } } -void NodeLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char* pPropertyName, float pFloatScale, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char* pPropertyName, float pFloatScale, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeInteger(Node * pNode, Node * pParent, const char* pPropertyName, int pInteger, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeInteger(Node * pNode, Node * pParent, const char* pPropertyName, int pInteger, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TAG) == 0) { pNode->setTag(pInteger); } else { @@ -1020,15 +1060,15 @@ void NodeLoader::onHandlePropTypeInteger(Node * pNode, Node * pParent, const cha } } -void NodeLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char* pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char* pPropertyName, int pIntegerLabeled, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char* pPropertyName, float * pFloatVar, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char* pPropertyName, float * pFloatVar, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char* pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char* pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_VISIBLE) == 0) { pNode->setVisible(pCheck); } else if(strcmp(pPropertyName, PROPERTY_IGNOREANCHORPOINTFORPOSITION) == 0) { @@ -1040,65 +1080,65 @@ void NodeLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char* } } -void NodeLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char* pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char* pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeAnimation(Node * pNode, Node * pParent, const char* pPropertyName, Animation * pAnimation, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeAnimation(Node * pNode, Node * pParent, const char* pPropertyName, Animation * pAnimation, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeTexture(Node * pNode, Node * pParent, const char* pPropertyName, Texture2D * pTexture2D, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeTexture(Node * pNode, Node * pParent, const char* pPropertyName, Texture2D * pTexture2D, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char* pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char* pPropertyName, unsigned char pByte, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char* pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char* pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char* pPropertyName, Color4F * pColor4FVar, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char* pPropertyName, Color4F * pColor4FVar, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeFlip(Node * pNode, Node * pParent, const char* pPropertyName, bool * pFlip, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFlip(Node * pNode, Node * pParent, const char* pPropertyName, bool * pFlip, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char* pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char* pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char* pPropertyName, const char* pFntFile, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char* pPropertyName, const char* pFntFile, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeString(Node * pNode, Node * pParent, const char* pPropertyName, const char * pString, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeString(Node * pNode, Node * pParent, const char* pPropertyName, const char * pString, CCBReader * ccbReader) { // ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); // It may be a custom property, add it to custom property dictionary. _customProperties->setObject(CCBValue::create(pString), pPropertyName); } -void NodeLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char* pPropertyName, const char * pText, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeText(Node * pNode, Node * pParent, const char* pPropertyName, const char * pText, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFontTTF, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFontTTF, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeBlock(Node * pNode, Node * pParent, const char* pPropertyName, BlockData * pBlockData, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeBlock(Node * pNode, Node * pParent, const char* pPropertyName, BlockData * pBlockData, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char* pPropertyName, BlockControlData * pBlockControlData, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char* pPropertyName, BlockControlData * pBlockControlData, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } -void NodeLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char* pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader) { +void NodeLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char* pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader) { ASSERT_FAIL_UNEXPECTED_PROPERTY(pPropertyName); } diff --git a/extensions/CCBReader/CCNodeLoader.h b/extensions/CCBReader/CCNodeLoader.h index 2d468f189a..80a0722130 100644 --- a/extensions/CCBReader/CCNodeLoader.h +++ b/extensions/CCBReader/CCNodeLoader.h @@ -24,20 +24,20 @@ NS_CC_EXT_BEGIN #define ASSERT_FAIL_UNEXPECTED_PROPERTY(PROPERTY) cocos2d::log("Unexpected property: '%s'!\n", PROPERTY); assert(false) #define ASSERT_FAIL_UNEXPECTED_PROPERTYTYPE(PROPERTYTYPE) cocos2d::log("Unexpected property type: '%d'!\n", PROPERTYTYPE); assert(false) -#define CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(T) virtual T * createNode(cocos2d::Node * pParent, cocos2d::extension::CCBReader * pCCBReader) { \ +#define CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(T) virtual T * createNode(cocos2d::Node * pParent, cocos2d::extension::CCBReader * ccbReader) { \ return T::create(); \ } -#define CCB_PURE_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(T) virtual T * createNode(cocos2d::Node * pParent, cocos2d::extension::CCBReader * pCCBReader) = 0 +#define CCB_PURE_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(T) virtual T * createNode(cocos2d::Node * pParent, cocos2d::extension::CCBReader * ccbReader) = 0 struct BlockData { SEL_MenuHandler mSELMenuHandler; - Object * mTarget; + Object * _target; }; struct BlockControlData { Control::Handler mSELControlHandler; - Object * mTarget; + Object * _target; Control::EventType mControlEvents; }; @@ -50,72 +50,72 @@ class NodeLoader : public Object { virtual ~NodeLoader(); CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(NodeLoader, loader); - virtual Node * loadNode(Node *, CCBReader * pCCBReader); - virtual void parseProperties(Node * pNode, Node * pParent, CCBReader * pCCBReader); + virtual Node * loadNode(Node *, CCBReader * ccbReader); + virtual void parseProperties(Node * pNode, Node * pParent, CCBReader * ccbReader); virtual Dictionary* getCustomProperties(); protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(Node); - virtual Point parsePropTypePosition(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual Point parsePropTypePoint(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual Point parsePropTypePointLock(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual Size parsePropTypeSize(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual float * parsePropTypeScaleLock(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual float parsePropTypeFloat(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual float parsePropTypeDegrees(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual float parsePropTypeFloatScale(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual int parsePropTypeInteger(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual int parsePropTypeIntegerLabeled(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual float * parsePropTypeFloatVar(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual bool parsePropTypeCheck(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual SpriteFrame * parsePropTypeSpriteFrame(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual Animation * parsePropTypeAnimation(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual Texture2D * parsePropTypeTexture(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual unsigned char parsePropTypeByte(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual Color3B parsePropTypeColor3(Node * pNode, Node * pParent, CCBReader * pCCBReader, const char *pPropertyName); - virtual Color4F * parsePropTypeColor4FVar(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual bool * parsePropTypeFlip(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual BlendFunc parsePropTypeBlendFunc(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual std::string parsePropTypeFntFile(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual std::string parsePropTypeString(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual std::string parsePropTypeText(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual std::string parsePropTypeFontTTF(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual BlockData * parsePropTypeBlock(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual BlockControlData * parsePropTypeBlockControl(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual Node * parsePropTypeCCBFile(Node * pNode, Node * pParent, CCBReader * pCCBReader); - virtual float * parsePropTypeFloatXY(Node * pNode, Node * pParent, CCBReader * pCCBReader); + virtual Point parsePropTypePosition(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual Point parsePropTypePoint(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual Point parsePropTypePointLock(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual Size parsePropTypeSize(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual float * parsePropTypeScaleLock(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual float parsePropTypeFloat(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual float parsePropTypeDegrees(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual float parsePropTypeFloatScale(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual int parsePropTypeInteger(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual int parsePropTypeIntegerLabeled(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual float * parsePropTypeFloatVar(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual bool parsePropTypeCheck(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual SpriteFrame * parsePropTypeSpriteFrame(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual Animation * parsePropTypeAnimation(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual Texture2D * parsePropTypeTexture(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual unsigned char parsePropTypeByte(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual Color3B parsePropTypeColor3(Node * pNode, Node * pParent, CCBReader * ccbReader, const char *pPropertyName); + virtual Color4F * parsePropTypeColor4FVar(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual bool * parsePropTypeFlip(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual BlendFunc parsePropTypeBlendFunc(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual std::string parsePropTypeFntFile(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual std::string parsePropTypeString(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual std::string parsePropTypeText(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual std::string parsePropTypeFontTTF(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual BlockData * parsePropTypeBlock(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual BlockControlData * parsePropTypeBlockControl(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual Node * parsePropTypeCCBFile(Node * pNode, Node * pParent, CCBReader * ccbReader); + virtual float * parsePropTypeFloatXY(Node * pNode, Node * pParent, CCBReader * ccbReader); - virtual void onHandlePropTypePosition(Node * pNode, Node * pParent, const char* pPropertyName, Point pPosition, CCBReader * pCCBReader); - virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char* pPropertyName, Point pPoint, CCBReader * pCCBReader); - virtual void onHandlePropTypePointLock(Node * pNode, Node * pParent, const char* pPropertyName, Point pPointLock, CCBReader * pCCBReader); - virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char* pPropertyName, Size pSize, CCBReader * pCCBReader); - virtual void onHandlePropTypeScaleLock(Node * pNode, Node * pParent, const char* pPropertyName, float * pScaleLock, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char* pPropertyName, float pFloat, CCBReader * pCCBReader); - virtual void onHandlePropTypeDegrees(Node * pNode, Node * pParent, const char* pPropertyName, float pDegrees, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char* pPropertyName, float pFloatScale, CCBReader * pCCBReader); - virtual void onHandlePropTypeInteger(Node * pNode, Node * pParent, const char* pPropertyName, int pInteger, CCBReader * pCCBReader); - virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char* pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char* pPropertyName, float * pFoatVar, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatXY(Node * pNode, Node * pParent, const char* pPropertyName, float * pFoatVar, CCBReader * pCCBReader); + virtual void onHandlePropTypePosition(Node * pNode, Node * pParent, const char* pPropertyName, Point pPosition, CCBReader * ccbReader); + virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char* pPropertyName, Point pPoint, CCBReader * ccbReader); + virtual void onHandlePropTypePointLock(Node * pNode, Node * pParent, const char* pPropertyName, Point pPointLock, CCBReader * ccbReader); + virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char* pPropertyName, Size pSize, CCBReader * ccbReader); + virtual void onHandlePropTypeScaleLock(Node * pNode, Node * pParent, const char* pPropertyName, float * pScaleLock, CCBReader * ccbReader); + virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char* pPropertyName, float pFloat, CCBReader * ccbReader); + virtual void onHandlePropTypeDegrees(Node * pNode, Node * pParent, const char* pPropertyName, float pDegrees, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatScale(Node * pNode, Node * pParent, const char* pPropertyName, float pFloatScale, CCBReader * ccbReader); + virtual void onHandlePropTypeInteger(Node * pNode, Node * pParent, const char* pPropertyName, int pInteger, CCBReader * ccbReader); + virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char* pPropertyName, int pIntegerLabeled, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char* pPropertyName, float * pFoatVar, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatXY(Node * pNode, Node * pParent, const char* pPropertyName, float * pFoatVar, CCBReader * ccbReader); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char* pPropertyName, bool pCheck, CCBReader * pCCBReader); - virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char* pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader); - virtual void onHandlePropTypeAnimation(Node * pNode, Node * pParent, const char* pPropertyName, Animation * pAnimation, CCBReader * pCCBReader); - virtual void onHandlePropTypeTexture(Node * pNode, Node * pParent, const char* pPropertyName, Texture2D * pTexture2D, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char* pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char* pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char* pPropertyName, Color4F * pColor4FVar, CCBReader * pCCBReader); - virtual void onHandlePropTypeFlip(Node * pNode, Node * pParent, const char* pPropertyName, bool * pFlip, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char* pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFntFile, CCBReader * pCCBReader); - virtual void onHandlePropTypeString(Node * pNode, Node * pParent, const char* pPropertyName, const char * pString, CCBReader * pCCBReader); - virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char* pPropertyName, const char * pText, CCBReader * pCCBReader); - virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFontTTF, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlock(Node * pNode, Node * pParent, const char* pPropertyName, BlockData * pBlockData, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char* pPropertyName, BlockControlData * pBlockControlData, CCBReader * pCCBReader); - virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char* pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char* pPropertyName, bool pCheck, CCBReader * ccbReader); + virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char* pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader); + virtual void onHandlePropTypeAnimation(Node * pNode, Node * pParent, const char* pPropertyName, Animation * pAnimation, CCBReader * ccbReader); + virtual void onHandlePropTypeTexture(Node * pNode, Node * pParent, const char* pPropertyName, Texture2D * pTexture2D, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char* pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char* pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char* pPropertyName, Color4F * pColor4FVar, CCBReader * ccbReader); + virtual void onHandlePropTypeFlip(Node * pNode, Node * pParent, const char* pPropertyName, bool * pFlip, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char* pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeFntFile(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFntFile, CCBReader * ccbReader); + virtual void onHandlePropTypeString(Node * pNode, Node * pParent, const char* pPropertyName, const char * pString, CCBReader * ccbReader); + virtual void onHandlePropTypeText(Node * pNode, Node * pParent, const char* pPropertyName, const char * pText, CCBReader * ccbReader); + virtual void onHandlePropTypeFontTTF(Node * pNode, Node * pParent, const char* pPropertyName, const char * pFontTTF, CCBReader * ccbReader); + virtual void onHandlePropTypeBlock(Node * pNode, Node * pParent, const char* pPropertyName, BlockData * pBlockData, CCBReader * ccbReader); + virtual void onHandlePropTypeBlockControl(Node * pNode, Node * pParent, const char* pPropertyName, BlockControlData * pBlockControlData, CCBReader * ccbReader); + virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char* pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader); protected: Dictionary* _customProperties; diff --git a/extensions/CCBReader/CCNodeLoaderLibrary.cpp b/extensions/CCBReader/CCNodeLoaderLibrary.cpp index 515df267ff..c7d61b24ec 100644 --- a/extensions/CCBReader/CCNodeLoaderLibrary.cpp +++ b/extensions/CCBReader/CCNodeLoaderLibrary.cpp @@ -46,15 +46,15 @@ void NodeLoaderLibrary::registerDefaultNodeLoaders() { void NodeLoaderLibrary::registerNodeLoader(const char * pClassName, NodeLoader * pNodeLoader) { pNodeLoader->retain(); - this->mNodeLoaders.insert(NodeLoaderMapEntry(pClassName, pNodeLoader)); + this->_nodeLoaders.insert(NodeLoaderMapEntry(pClassName, pNodeLoader)); } void NodeLoaderLibrary::unregisterNodeLoader(const char * pClassName) { - NodeLoaderMap::iterator ccNodeLoadersIterator = this->mNodeLoaders.find(pClassName); - if (ccNodeLoadersIterator != this->mNodeLoaders.end()) + NodeLoaderMap::iterator ccNodeLoadersIterator = this->_nodeLoaders.find(pClassName); + if (ccNodeLoadersIterator != this->_nodeLoaders.end()) { ccNodeLoadersIterator->second->release(); - mNodeLoaders.erase(ccNodeLoadersIterator); + _nodeLoaders.erase(ccNodeLoadersIterator); } else { @@ -63,18 +63,18 @@ void NodeLoaderLibrary::unregisterNodeLoader(const char * pClassName) { } NodeLoader * NodeLoaderLibrary::getNodeLoader(const char* pClassName) { - NodeLoaderMap::iterator ccNodeLoadersIterator = this->mNodeLoaders.find(pClassName); - assert(ccNodeLoadersIterator != this->mNodeLoaders.end()); + NodeLoaderMap::iterator ccNodeLoadersIterator = this->_nodeLoaders.find(pClassName); + assert(ccNodeLoadersIterator != this->_nodeLoaders.end()); return ccNodeLoadersIterator->second; } void NodeLoaderLibrary::purge(bool pReleaseNodeLoaders) { if(pReleaseNodeLoaders) { - for(NodeLoaderMap::iterator it = this->mNodeLoaders.begin(); it != this->mNodeLoaders.end(); it++) { + for(NodeLoaderMap::iterator it = this->_nodeLoaders.begin(); it != this->_nodeLoaders.end(); it++) { it->second->release(); } } - this->mNodeLoaders.clear(); + this->_nodeLoaders.clear(); } diff --git a/extensions/CCBReader/CCNodeLoaderLibrary.h b/extensions/CCBReader/CCNodeLoaderLibrary.h index 9abd64b660..9f462dd7ff 100644 --- a/extensions/CCBReader/CCNodeLoaderLibrary.h +++ b/extensions/CCBReader/CCNodeLoaderLibrary.h @@ -11,10 +11,8 @@ class NodeLoader; typedef std::map NodeLoaderMap; typedef std::pair NodeLoaderMapEntry; -class NodeLoaderLibrary : public Object { -private: - NodeLoaderMap mNodeLoaders; - +class NodeLoaderLibrary : public Object +{ public: CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(NodeLoaderLibrary, library); @@ -45,6 +43,9 @@ public: CC_DEPRECATED_ATTRIBUTE static void purgeSharedNodeLoaderLibrary() { NodeLoaderLibrary::destroyInstance(); }; CC_DEPRECATED_ATTRIBUTE static NodeLoaderLibrary * newDefaultCCNodeLoaderLibrary() { return NodeLoaderLibrary::newDefaultNodeLoaderLibrary(); }; + +private: + NodeLoaderMap _nodeLoaders; }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCParticleSystemQuadLoader.cpp b/extensions/CCBReader/CCParticleSystemQuadLoader.cpp index e0b17e3232..8f94db33ad 100644 --- a/extensions/CCBReader/CCParticleSystemQuadLoader.cpp +++ b/extensions/CCBReader/CCParticleSystemQuadLoader.cpp @@ -27,43 +27,43 @@ NS_CC_EXT_BEGIN -void ParticleSystemQuadLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_EMITERMODE) == 0) { ((ParticleSystemQuad *)pNode)->setEmitterMode((ParticleSystem::Mode)pIntegerLabeled); } else { - NodeLoader::onHandlePropTypeIntegerLabeled(pNode, pParent, pPropertyName, pIntegerLabeled, pCCBReader); + NodeLoader::onHandlePropTypeIntegerLabeled(pNode, pParent, pPropertyName, pIntegerLabeled, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_POSVAR) == 0) { ((ParticleSystemQuad *)pNode)->setPosVar(pPoint); } else if(strcmp(pPropertyName, PROPERTY_GRAVITY) == 0) { ((ParticleSystemQuad *)pNode)->setGravity(pPoint); } else { - NodeLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, pCCBReader); + NodeLoader::onHandlePropTypePoint(pNode, pParent, pPropertyName, pPoint, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_EMISSIONRATE) == 0) { ((ParticleSystemQuad *)pNode)->setEmissionRate(pFloat); } else if(strcmp(pPropertyName, PROPERTY_DURATION) == 0) { ((ParticleSystemQuad *)pNode)->setDuration(pFloat); } else { - NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, pCCBReader); + NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeInteger(Node * pNode, Node * pParent, const char * pPropertyName, int pInteger, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeInteger(Node * pNode, Node * pParent, const char * pPropertyName, int pInteger, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TOTALPARTICLES) == 0) { ((ParticleSystemQuad *)pNode)->setTotalParticles(pInteger); } else { - NodeLoader::onHandlePropTypeInteger(pNode, pParent, pPropertyName, pInteger, pCCBReader); + NodeLoader::onHandlePropTypeInteger(pNode, pParent, pPropertyName, pInteger, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char * pPropertyName, float * pFloatVar, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char * pPropertyName, float * pFloatVar, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_LIFE) == 0) { ((ParticleSystemQuad *)pNode)->setLife(pFloatVar[0]); ((ParticleSystemQuad *)pNode)->setLifeVar(pFloatVar[1]); @@ -101,11 +101,11 @@ void ParticleSystemQuadLoader::onHandlePropTypeFloatVar(Node * pNode, Node * pPa ((ParticleSystemQuad *)pNode)->setRotatePerSecond(pFloatVar[0]); ((ParticleSystemQuad *)pNode)->setRotatePerSecondVar(pFloatVar[1]); } else { - NodeLoader::onHandlePropTypeFloatVar(pNode, pParent, pPropertyName, pFloatVar, pCCBReader); + NodeLoader::onHandlePropTypeFloatVar(pNode, pParent, pPropertyName, pFloatVar, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char * pPropertyName, Color4F * pColor4FVar, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char * pPropertyName, Color4F * pColor4FVar, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_STARTCOLOR) == 0) { ((ParticleSystemQuad *)pNode)->setStartColor(pColor4FVar[0]); ((ParticleSystemQuad *)pNode)->setStartColorVar(pColor4FVar[1]); @@ -113,23 +113,23 @@ void ParticleSystemQuadLoader::onHandlePropTypeColor4FVar(Node * pNode, Node * p ((ParticleSystemQuad *)pNode)->setEndColor(pColor4FVar[0]); ((ParticleSystemQuad *)pNode)->setEndColorVar(pColor4FVar[1]); } else { - NodeLoader::onHandlePropTypeColor4FVar(pNode, pParent, pPropertyName, pColor4FVar, pCCBReader); + NodeLoader::onHandlePropTypeColor4FVar(pNode, pParent, pPropertyName, pColor4FVar, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((ParticleSystemQuad *)pNode)->setBlendFunc(pBlendFunc); } else { - NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } -void ParticleSystemQuadLoader::onHandlePropTypeTexture(Node * pNode, Node * pParent, const char * pPropertyName, Texture2D * pTexture2D, CCBReader * pCCBReader) { +void ParticleSystemQuadLoader::onHandlePropTypeTexture(Node * pNode, Node * pParent, const char * pPropertyName, Texture2D * pTexture2D, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_TEXTURE) == 0) { ((ParticleSystemQuad *)pNode)->setTexture(pTexture2D); } else { - NodeLoader::onHandlePropTypeTexture(pNode, pParent, pPropertyName, pTexture2D, pCCBReader); + NodeLoader::onHandlePropTypeTexture(pNode, pParent, pPropertyName, pTexture2D, ccbReader); } } diff --git a/extensions/CCBReader/CCParticleSystemQuadLoader.h b/extensions/CCBReader/CCParticleSystemQuadLoader.h index 43003c2c0f..5aa1bc0ae2 100644 --- a/extensions/CCBReader/CCParticleSystemQuadLoader.h +++ b/extensions/CCBReader/CCParticleSystemQuadLoader.h @@ -16,14 +16,14 @@ class ParticleSystemQuadLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(ParticleSystemQuad); - virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader); - virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader); - virtual void onHandlePropTypeInteger(Node * pNode, Node * pParent, const char * pPropertyName, int pInteger, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char * pPropertyName, float * pFloatVar, CCBReader * pCCBReader); - virtual void onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char * pPropertyName, Color4F * pColor4FVar, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeTexture(Node * pNode, Node * pParent, const char * pPropertyName, Texture2D * pTexture2D, CCBReader * pCCBReader); + virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader); + virtual void onHandlePropTypePoint(Node * pNode, Node * pParent, const char * pPropertyName, Point pPoint, CCBReader * ccbReader); + virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader); + virtual void onHandlePropTypeInteger(Node * pNode, Node * pParent, const char * pPropertyName, int pInteger, CCBReader * ccbReader); + virtual void onHandlePropTypeFloatVar(Node * pNode, Node * pParent, const char * pPropertyName, float * pFloatVar, CCBReader * ccbReader); + virtual void onHandlePropTypeColor4FVar(Node * pNode, Node * pParent, const char * pPropertyName, Color4F * pColor4FVar, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeTexture(Node * pNode, Node * pParent, const char * pPropertyName, Texture2D * pTexture2D, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCScale9SpriteLoader.cpp b/extensions/CCBReader/CCScale9SpriteLoader.cpp index f7024b0042..b2172bf855 100644 --- a/extensions/CCBReader/CCScale9SpriteLoader.cpp +++ b/extensions/CCBReader/CCScale9SpriteLoader.cpp @@ -15,50 +15,50 @@ NS_CC_EXT_BEGIN -void Scale9SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_SPRITEFRAME) == 0) { ((Scale9Sprite *)pNode)->setSpriteFrame(pSpriteFrame); } else { - NodeLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, pCCBReader); + NodeLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, ccbReader); } } -void Scale9SpriteLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_COLOR) == 0) { ((Scale9Sprite *)pNode)->setColor(pColor3B); } else { - NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void Scale9SpriteLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_OPACITY) == 0) { ((Scale9Sprite *)pNode)->setOpacity(pByte); } else { - NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void Scale9SpriteLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { // TODO Not exported by CocosBuilder yet! // ((Scale9Sprite *)pNode)->setBlendFunc(pBlendFunc); } else { - NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } -void Scale9SpriteLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CONTENTSIZE) == 0) { //((Scale9Sprite *)pNode)->setContentSize(pSize); } else if(strcmp(pPropertyName, PROPERTY_PREFEREDSIZE) == 0) { ((Scale9Sprite *)pNode)->setPreferredSize(pSize); } else { - NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, pCCBReader); + NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, ccbReader); } } -void Scale9SpriteLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader) { +void Scale9SpriteLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_INSETLEFT) == 0) { ((Scale9Sprite *)pNode)->setInsetLeft(pFloat); } else if(strcmp(pPropertyName, PROPERTY_INSETTOP) == 0) { @@ -68,7 +68,7 @@ void Scale9SpriteLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, con } else if(strcmp(pPropertyName, PROPERTY_INSETBOTTOM) == 0) { ((Scale9Sprite *)pNode)->setInsetBottom(pFloat); } else { - NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, pCCBReader); + NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, ccbReader); } } diff --git a/extensions/CCBReader/CCScale9SpriteLoader.h b/extensions/CCBReader/CCScale9SpriteLoader.h index 8cf0dd07bd..3e0630c793 100644 --- a/extensions/CCBReader/CCScale9SpriteLoader.h +++ b/extensions/CCBReader/CCScale9SpriteLoader.h @@ -18,12 +18,12 @@ class Scale9SpriteLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(Scale9Sprite); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader); - virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader); + virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader); + virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCScrollViewLoader.cpp b/extensions/CCBReader/CCScrollViewLoader.cpp index 4380dcba10..5006a5fd89 100644 --- a/extensions/CCBReader/CCScrollViewLoader.cpp +++ b/extensions/CCBReader/CCScrollViewLoader.cpp @@ -10,46 +10,46 @@ NS_CC_EXT_BEGIN -void ScrollViewLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader) { +void ScrollViewLoader::onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CONTENTSIZE) == 0) { ((ScrollView *)pNode)->setViewSize(pSize); } else { - NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, pCCBReader); + NodeLoader::onHandlePropTypeSize(pNode, pParent, pPropertyName, pSize, ccbReader); } } -void ScrollViewLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader) { +void ScrollViewLoader::onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CLIPSTOBOUNDS) == 0) { ((ScrollView *)pNode)->setClippingToBounds(pCheck); } else if(strcmp(pPropertyName, PROPERTY_BOUNCES) == 0) { ((ScrollView *)pNode)->setBounceable(pCheck); } else { - NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, pCCBReader); + NodeLoader::onHandlePropTypeCheck(pNode, pParent, pPropertyName, pCheck, ccbReader); } } -void ScrollViewLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader) { +void ScrollViewLoader::onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_CONTAINER) == 0) { ((ScrollView *)pNode)->setContainer(pCCBFileNode); ((ScrollView *)pNode)->updateInset(); } else { - NodeLoader::onHandlePropTypeCCBFile(pNode, pParent, pPropertyName, pCCBFileNode, pCCBReader); + NodeLoader::onHandlePropTypeCCBFile(pNode, pParent, pPropertyName, pCCBFileNode, ccbReader); } } -void ScrollViewLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader) { +void ScrollViewLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_SCALE) == 0) { ((ScrollView *)pNode)->setScale(pFloat); } else { - NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, pCCBReader); + NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, ccbReader); } } -void ScrollViewLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader) { +void ScrollViewLoader::onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_DIRECTION) == 0) { ((ScrollView *)pNode)->setDirection(ScrollView::Direction(pIntegerLabeled)); } else { - NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pIntegerLabeled, pCCBReader); + NodeLoader::onHandlePropTypeFloatScale(pNode, pParent, pPropertyName, pIntegerLabeled, ccbReader); } } diff --git a/extensions/CCBReader/CCScrollViewLoader.h b/extensions/CCBReader/CCScrollViewLoader.h index d3c0ea81e9..9ca0a47585 100644 --- a/extensions/CCBReader/CCScrollViewLoader.h +++ b/extensions/CCBReader/CCScrollViewLoader.h @@ -16,11 +16,11 @@ class ScrollViewLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(ScrollView); - virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * pCCBReader); - virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * pCCBReader); - virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * pCCBReader); - virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * pCCBReader); - virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * pCCBReader); + virtual void onHandlePropTypeSize(Node * pNode, Node * pParent, const char * pPropertyName, Size pSize, CCBReader * ccbReader); + virtual void onHandlePropTypeCCBFile(Node * pNode, Node * pParent, const char * pPropertyName, Node * pCCBFileNode, CCBReader * ccbReader); + virtual void onHandlePropTypeCheck(Node * pNode, Node * pParent, const char * pPropertyName, bool pCheck, CCBReader * ccbReader); + virtual void onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader); + virtual void onHandlePropTypeIntegerLabeled(Node * pNode, Node * pParent, const char * pPropertyName, int pIntegerLabeled, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCBReader/CCSpriteLoader.cpp b/extensions/CCBReader/CCSpriteLoader.cpp index e6b447942e..cb3dbe2967 100644 --- a/extensions/CCBReader/CCSpriteLoader.cpp +++ b/extensions/CCBReader/CCSpriteLoader.cpp @@ -8,7 +8,7 @@ NS_CC_EXT_BEGIN -void SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader) { +void SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_DISPLAYFRAME) == 0) { if(pSpriteFrame != NULL) { ((Sprite *)pNode)->setDisplayFrame(pSpriteFrame); @@ -16,40 +16,40 @@ void SpriteLoader::onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, con CCLOG("ERROR: SpriteFrame NULL"); } } else { - NodeLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, pCCBReader); + NodeLoader::onHandlePropTypeSpriteFrame(pNode, pParent, pPropertyName, pSpriteFrame, ccbReader); } } -void SpriteLoader::onHandlePropTypeFlip(Node * pNode, Node * pParent, const char * pPropertyName, bool * pFlip, CCBReader * pCCBReader) { +void SpriteLoader::onHandlePropTypeFlip(Node * pNode, Node * pParent, const char * pPropertyName, bool * pFlip, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_FLIP) == 0) { ((Sprite *)pNode)->setFlipX(pFlip[0]); ((Sprite *)pNode)->setFlipY(pFlip[1]); } else { - NodeLoader::onHandlePropTypeFlip(pNode, pParent, pPropertyName, pFlip, pCCBReader); + NodeLoader::onHandlePropTypeFlip(pNode, pParent, pPropertyName, pFlip, ccbReader); } } -void SpriteLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader) { +void SpriteLoader::onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_COLOR) == 0) { ((Sprite *)pNode)->setColor(pColor3B); } else { - NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, pCCBReader); + NodeLoader::onHandlePropTypeColor3(pNode, pParent, pPropertyName, pColor3B, ccbReader); } } -void SpriteLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader) { +void SpriteLoader::onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_OPACITY) == 0) { ((Sprite *)pNode)->setOpacity(pByte); } else { - NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, pCCBReader); + NodeLoader::onHandlePropTypeByte(pNode, pParent, pPropertyName, pByte, ccbReader); } } -void SpriteLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * pCCBReader) { +void SpriteLoader::onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pBlendFunc, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_BLENDFUNC) == 0) { ((Sprite *)pNode)->setBlendFunc(pBlendFunc); } else { - NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, pCCBReader); + NodeLoader::onHandlePropTypeBlendFunc(pNode, pParent, pPropertyName, pBlendFunc, ccbReader); } } diff --git a/extensions/CCBReader/CCSpriteLoader.h b/extensions/CCBReader/CCSpriteLoader.h index 844ccda303..1c2738118e 100644 --- a/extensions/CCBReader/CCSpriteLoader.h +++ b/extensions/CCBReader/CCSpriteLoader.h @@ -16,11 +16,11 @@ class SpriteLoader : public NodeLoader { protected: CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(Sprite); - virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * pCCBReader); - virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * pCCBReader); - virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pCCBBlendFunc, CCBReader * pCCBReader); - virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * pCCBReader); - virtual void onHandlePropTypeFlip(Node * pNode, Node * pParent, const char * pPropertyName, bool * pFlip, CCBReader * pCCBReader); + virtual void onHandlePropTypeColor3(Node * pNode, Node * pParent, const char * pPropertyName, Color3B pColor3B, CCBReader * ccbReader); + virtual void onHandlePropTypeByte(Node * pNode, Node * pParent, const char * pPropertyName, unsigned char pByte, CCBReader * ccbReader); + virtual void onHandlePropTypeBlendFunc(Node * pNode, Node * pParent, const char * pPropertyName, BlendFunc pCCBBlendFunc, CCBReader * ccbReader); + virtual void onHandlePropTypeSpriteFrame(Node * pNode, Node * pParent, const char * pPropertyName, SpriteFrame * pSpriteFrame, CCBReader * ccbReader); + virtual void onHandlePropTypeFlip(Node * pNode, Node * pParent, const char * pPropertyName, bool * pFlip, CCBReader * ccbReader); }; NS_CC_EXT_END diff --git a/extensions/CCDeprecated-ext.h b/extensions/CCDeprecated-ext.h index 091318da92..5aded2b4f4 100644 --- a/extensions/CCDeprecated-ext.h +++ b/extensions/CCDeprecated-ext.h @@ -83,6 +83,9 @@ CC_DEPRECATED_ATTRIBUTE typedef LabelTTFLoader CCLabelTTFLoader; #if CC_ENABLE_BOX2D_INTEGRATION || CC_ENABLE_CHIPMUNK_INTEGRATION CC_DEPRECATED_ATTRIBUTE typedef PhysicsSprite CCPhysicsSprite; +#endif + +#if CC_ENABLE_CHIPMUNK_INTEGRATION CC_DEPRECATED_ATTRIBUTE typedef PhysicsDebugNode CCPhysicsDebugNode; #endif @@ -183,6 +186,92 @@ CC_DEPRECATED_ATTRIBUTE typedef Control::State CCControlState; CC_DEPRECATED_ATTRIBUTE typedef Control::Handler SEL_CCControlHandler; +// For CCBReader + +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kIntValue = CCBValue::Type::INT; +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kFloatValue = CCBValue::Type::FLOAT; +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kBoolValue = CCBValue::Type::BOOL; +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kUnsignedCharValue = CCBValue::Type::UNSIGNED_CHAR; +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kStringValue = CCBValue::Type::STRING; +CC_DEPRECATED_ATTRIBUTE const CCBValue::Type kArrayValue = CCBValue::Type::ARRAY; + + +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypePosition = CCBReader::PropertyType::POSITION; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeSize = CCBReader::PropertyType::SIZE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypePoint = CCBReader::PropertyType::POINT; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypePointLock = CCBReader::PropertyType::POINT_LOCK; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeScaleLock = CCBReader::PropertyType::SCALE_LOCK; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeDegrees = CCBReader::PropertyType::DEGREES; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeInteger = CCBReader::PropertyType::INTEGER; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFloat = CCBReader::PropertyType::FLOAT; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFloatVar = CCBReader::PropertyType::FLOAT_VAR; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeCheck = CCBReader::PropertyType::CHECK; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeSpriteFrame = CCBReader::PropertyType::SPRITEFRAME; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeTexture = CCBReader::PropertyType::TEXTURE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeByte = CCBReader::PropertyType::BYTE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeColor3 = CCBReader::PropertyType::COLOR3; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeColor4FVar = CCBReader::PropertyType::COLOR4F_VAR; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFlip = CCBReader::PropertyType::FLIP; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeBlendmode = CCBReader::PropertyType::BLEND_MODE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFntFile = CCBReader::PropertyType::FNT_FILE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeText = CCBReader::PropertyType::TEXT; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFontTTF = CCBReader::PropertyType::FONT_TTF; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeIntegerLabeled = CCBReader::PropertyType::INTEGER_LABELED; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeBlock = CCBReader::PropertyType::BLOCK; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeAnimation = CCBReader::PropertyType::ANIMATION; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeCCBFile = CCBReader::PropertyType::CCB_FILE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeString = CCBReader::PropertyType::STRING; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeBlockCCControl = CCBReader::PropertyType::BLOCK_CONTROL; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFloatScale = CCBReader::PropertyType::FLOAT_SCALE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PropertyType kCCBPropTypeFloatXY = CCBReader::PropertyType::FLOAT_XY; + +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloat0 = CCBReader::FloatType::_0; +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloat1 = CCBReader::FloatType::_1; +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloatMinus1 = CCBReader::FloatType::MINUS1; +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloat05 = CCBReader::FloatType::_05; +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloatInteger = CCBReader::FloatType::INTEGER; +CC_DEPRECATED_ATTRIBUTE const CCBReader::FloatType kCCBFloatFull = CCBReader::FloatType::FULL; + +CC_DEPRECATED_ATTRIBUTE const CCBReader::PlatformType kCCBPlatformAll = CCBReader::PlatformType::ALL; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PlatformType kCCBPlatformIOS = CCBReader::PlatformType::IOS; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PlatformType kCCBPlatformMac = CCBReader::PlatformType::MAC; + +CC_DEPRECATED_ATTRIBUTE const CCBReader::TargetType kCCBTargetTypeNone = CCBReader::TargetType::NONE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::TargetType kCCBTargetTypeDocumentRoot = CCBReader::TargetType::DOCUMENT_ROOT; +CC_DEPRECATED_ATTRIBUTE const CCBReader::TargetType kCCBTargetTypeOwner = CCBReader::TargetType::OWNER; + +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingInstant = CCBKeyframe::EasingType::INSTANT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingLinear = CCBKeyframe::EasingType::LINEAR ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingCubicIn = CCBKeyframe::EasingType::CUBIC_IN ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingCubicOut = CCBKeyframe::EasingType::CUBIC_OUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingCubicInOut = CCBKeyframe::EasingType::CUBIC_INOUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingElasticIn = CCBKeyframe::EasingType::ELASTIC_IN ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingElasticOut = CCBKeyframe::EasingType::ELASTIC_OUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingElasticInOut = CCBKeyframe::EasingType::ELASTIC_INOUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBounceIn = CCBKeyframe::EasingType::BOUNCE_IN ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBounceOut = CCBKeyframe::EasingType::BOUNCE_OUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBounceInOut = CCBKeyframe::EasingType::BOUNCE_INOUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBackIn = CCBKeyframe::EasingType::BACK_IN ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBackOut = CCBKeyframe::EasingType::BACK_OUT ; +CC_DEPRECATED_ATTRIBUTE const CCBKeyframe::EasingType kCCBKeyframeEasingBackInOut = CCBKeyframe::EasingType::BACK_INOUT ; + +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypeRelativeBottomLeft = CCBReader::PositionType::RELATIVE_BOTTOM_LEFT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypeRelativeTopLeft = CCBReader::PositionType::RELATIVE_TOP_LEFT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypeRelativeTopRight = CCBReader::PositionType::RELATIVE_TOP_RIGHT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypeRelativeBottomRight = CCBReader::PositionType::RELATIVE_BOTTOM_RIGHT; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypePercent = CCBReader::PositionType::PERCENT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::PositionType kCCBPositionTypeMultiplyResolution = CCBReader::PositionType::MULTIPLY_RESOLUTION ; +; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypeAbsolute = CCBReader::SizeType::ABSOLUTE ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypePercent = CCBReader::SizeType::PERCENT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypeRelativeContainer = CCBReader::SizeType::RELATIVE_CONTAINER ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypeHorizontalPercent = CCBReader::SizeType::HORIZONTAL_PERCENT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypeVerticalPercent = CCBReader::SizeType::VERTICAL_PERCENT ; +CC_DEPRECATED_ATTRIBUTE const CCBReader::SizeType kCCBSizeTypeMultiplyResolution = CCBReader::SizeType::MULTIPLY_RESOLUTION; + + +CC_DEPRECATED_ATTRIBUTE const CCBReader::ScaleType kCCBScaleTypeAbsolute = CCBReader::ScaleType::ABSOLUTE; +CC_DEPRECATED_ATTRIBUTE const CCBReader::ScaleType kCCBScaleTypeMultiplyResolution = CCBReader::ScaleType::MULTIPLY_RESOLUTION; NS_CC_EXT_END diff --git a/extensions/GUI/CCControlExtension/CCControl.cpp b/extensions/GUI/CCControlExtension/CCControl.cpp index b32ee30225..03aeab0594 100644 --- a/extensions/GUI/CCControlExtension/CCControl.cpp +++ b/extensions/GUI/CCControlExtension/CCControl.cpp @@ -37,13 +37,13 @@ NS_CC_EXT_BEGIN Control::Control() -: _isOpacityModifyRGB(false) -, _state(State::NORMAL) -, _hasVisibleParents(false) -, _enabled(false) +: _enabled(false) , _selected(false) , _highlighted(false) +, _hasVisibleParents(false) , _dispatchTable(NULL) +, _isOpacityModifyRGB(false) +, _state(State::NORMAL) { } diff --git a/extensions/GUI/CCControlExtension/CCControlButton.cpp b/extensions/GUI/CCControlExtension/CCControlButton.cpp index 7f3a521612..ddbee20262 100644 --- a/extensions/GUI/CCControlExtension/CCControlButton.cpp +++ b/extensions/GUI/CCControlExtension/CCControlButton.cpp @@ -42,14 +42,14 @@ enum }; ControlButton::ControlButton() -: _currentTitle(NULL) -, _currentTitleColor(Color3B::WHITE) +: _isPushed(false) +, _parentInited(false) , _doesAdjustBackgroundImage(false) +, _currentTitle(NULL) +, _currentTitleColor(Color3B::WHITE) , _titleLabel(NULL) , _backgroundSprite(NULL) , _zoomOnTouchDown(false) -, _isPushed(false) -, _parentInited(false) , _titleDispatchTable(NULL) , _titleColorDispatchTable(NULL) , _titleLabelDispatchTable(NULL) diff --git a/extensions/GUI/CCControlExtension/CCControlPotentiometer.cpp b/extensions/GUI/CCControlExtension/CCControlPotentiometer.cpp index fdc957e608..40907afca8 100644 --- a/extensions/GUI/CCControlExtension/CCControlPotentiometer.cpp +++ b/extensions/GUI/CCControlExtension/CCControlPotentiometer.cpp @@ -31,11 +31,11 @@ NS_CC_EXT_BEGIN ControlPotentiometer::ControlPotentiometer() -: _thumbSprite(NULL) -, _progressTimer(NULL) -, _value(0.0f) +: _value(0.0f) , _minimumValue(0.0f) , _maximumValue(0.0f) +, _thumbSprite(NULL) +, _progressTimer(NULL) { } diff --git a/extensions/GUI/CCControlExtension/CCControlStepper.cpp b/extensions/GUI/CCControlExtension/CCControlStepper.cpp index f1c504d528..a14343b5ad 100644 --- a/extensions/GUI/CCControlExtension/CCControlStepper.cpp +++ b/extensions/GUI/CCControlExtension/CCControlStepper.cpp @@ -39,11 +39,7 @@ NS_CC_EXT_BEGIN #define kAutorepeatIncreaseTimeIncrement 12 ControlStepper::ControlStepper() -: _minusSprite(NULL) -, _plusSprite(NULL) -, _minusLabel(NULL) -, _plusLabel(NULL) -, _value(0.0) +: _value(0.0) , _continuous(false) , _autorepeat(false) , _wraps(false) @@ -53,6 +49,10 @@ ControlStepper::ControlStepper() , _touchInsideFlag(false) , _touchedPart(Part::NONE) , _autorepeatCount(0) +, _minusSprite(NULL) +, _plusSprite(NULL) +, _minusLabel(NULL) +, _plusLabel(NULL) { } diff --git a/extensions/GUI/CCControlExtension/CCInvocation.h b/extensions/GUI/CCControlExtension/CCInvocation.h index f066d645a5..9c4b145d91 100644 --- a/extensions/GUI/CCControlExtension/CCInvocation.h +++ b/extensions/GUI/CCControlExtension/CCInvocation.h @@ -43,7 +43,7 @@ NS_CC_EXT_BEGIN * @{ */ -#define cccontrol_selector(_SELECTOR) (Control::Handler)(&_SELECTOR) +#define cccontrol_selector(_SELECTOR) static_cast(&_SELECTOR) class Invocation : public Object { diff --git a/extensions/GUI/CCControlExtension/CCScale9Sprite.cpp b/extensions/GUI/CCControlExtension/CCScale9Sprite.cpp index 8e588b5706..a086e475b5 100644 --- a/extensions/GUI/CCControlExtension/CCScale9Sprite.cpp +++ b/extensions/GUI/CCControlExtension/CCScale9Sprite.cpp @@ -43,11 +43,7 @@ enum positions }; Scale9Sprite::Scale9Sprite() -: _insetLeft(0) -, _insetTop(0) -, _insetRight(0) -, _insetBottom(0) -, _spritesGenerated(false) +: _spritesGenerated(false) , _spriteFrameRotated(false) , _positionsAreDirty(false) , _scale9Image(NULL) @@ -61,6 +57,10 @@ Scale9Sprite::Scale9Sprite() , _bottom(NULL) , _bottomRight(NULL) , _opacityModifyRGB(false) +, _insetLeft(0) +, _insetTop(0) +, _insetRight(0) +, _insetBottom(0) { } diff --git a/extensions/GUI/CCEditBox/CCEditBoxImplIOS.mm b/extensions/GUI/CCEditBox/CCEditBoxImplIOS.mm index 0848178220..a4cbae50ba 100644 --- a/extensions/GUI/CCEditBox/CCEditBoxImplIOS.mm +++ b/extensions/GUI/CCEditBox/CCEditBoxImplIOS.mm @@ -257,8 +257,8 @@ EditBoxImplIOS::EditBoxImplIOS(EditBox* pEditText) : EditBoxImpl(pEditText) , _label(NULL) , _labelPlaceHolder(NULL) -, _systemControl(NULL) , _anchorPoint(Point(0.5f, 0.5f)) +, _systemControl(NULL) , _maxTextLength(-1) { _inRetinaMode = [[CCEAGLView sharedEGLView] contentScaleFactor] == 2.0f ? true : false; diff --git a/extensions/GUI/CCEditBox/CCEditBoxImplMac.mm b/extensions/GUI/CCEditBox/CCEditBoxImplMac.mm index 0dfac0adc0..941687acec 100644 --- a/extensions/GUI/CCEditBox/CCEditBoxImplMac.mm +++ b/extensions/GUI/CCEditBox/CCEditBoxImplMac.mm @@ -234,8 +234,10 @@ EditBoxImpl* __createSystemEditBox(EditBox* pEditBox) } EditBoxImplMac::EditBoxImplMac(EditBox* pEditText) -: EditBoxImpl(pEditText), _sysEdit(NULL), _maxTextLength(-1) +: EditBoxImpl(pEditText) , _anchorPoint(Point(0.5f, 0.5f)) +, _maxTextLength(-1) +, _sysEdit(NULL) { //! TODO: Retina on Mac //! _inRetinaMode = [[CCEAGLView sharedEGLView] contentScaleFactor] == 2.0f ? true : false; diff --git a/extensions/GUI/CCEditBox/CCEditBoxImplTizen.cpp b/extensions/GUI/CCEditBox/CCEditBoxImplTizen.cpp index c5d6fda658..705034c0af 100644 --- a/extensions/GUI/CCEditBox/CCEditBoxImplTizen.cpp +++ b/extensions/GUI/CCEditBox/CCEditBoxImplTizen.cpp @@ -46,7 +46,7 @@ EditBoxImplTizen::EditBoxImplTizen(EditBox* pEditText) , _labelPlaceHolder(NULL) , _editBoxInputMode(EditBox::InputMode::SINGLE_LINE) , _editBoxInputFlag(EditBox::InputFlag::INTIAL_CAPS_ALL_CHARACTERS) -, _keyboardReturnType(kKeyboardReturnTypeDefault) +, _keyboardReturnType(EditBox::KeyboardReturnType::DEFAULT) , _colText(Color3B::WHITE) , _colPlaceHolder(Color3B::GRAY) , _maxLength(-1) @@ -65,7 +65,7 @@ static const int CC_EDIT_BOX_PADDING = 5; bool EditBoxImplTizen::initWithSize(const Size& size) { - int fontSize = (int)size.height-12; +// int fontSize = (int)size.height-12; _label = LabelTTF::create("", "", size.height-12); // align the text vertically center _label->setAnchorPoint(Point(0, 0.5f)); @@ -160,7 +160,7 @@ void EditBoxImplTizen::setText(const char* pText) std::string strToShow; - if (kEditBoxInputFlagPassword == _editBoxInputFlag) + if (EditBox::InputFlag::PASSWORD == _editBoxInputFlag) { long length = cc_utf8_strlen(_text.c_str(), -1); for (long i = 0; i < length; i++) @@ -284,21 +284,21 @@ void EditBoxImplTizen::openKeyboard() bool bSingleLineEnabled = false; switch (_editBoxInputMode) { - case kEditBoxInputModeAny: + case EditBox::InputMode::ANY: keypadStyle = KEYPAD_STYLE_NORMAL; break; - case kEditBoxInputModeEmailAddr: + case EditBox::InputMode::EMAIL_ADDRESS: keypadStyle = KEYPAD_STYLE_EMAIL; break; - case kEditBoxInputModeNumeric: - case kEditBoxInputModeDecimal: + case EditBox::InputMode::NUMERIC: + case EditBox::InputMode::DECIMAL: keypadStyle = KEYPAD_STYLE_NUMBER; keypadCategory = KEYPAD_MODE_NUMERIC; break; - case kEditBoxInputModePhoneNumber: + case EditBox::InputMode::PHONE_NUMBER: keypadStyle = KEYPAD_STYLE_PHONE_NUMBER; break; - case kEditBoxInputModeUrl: + case EditBox::InputMode::URL: keypadStyle = KEYPAD_STYLE_URL; break; case EditBox::InputMode::SINGLE_LINE: @@ -312,10 +312,10 @@ void EditBoxImplTizen::openKeyboard() bool bTextPrediction = true; switch (_editBoxInputFlag) { - case kEditBoxInputFlagPassword: + case EditBox::InputFlag::PASSWORD: keypadStyle = KEYPAD_STYLE_PASSWORD; break; - case kEditBoxInputFlagSensitive: + case EditBox::InputFlag::SENSITIVE: bTextPrediction = false; break; default: diff --git a/extensions/network/HttpRequest.h b/extensions/network/HttpRequest.h index 4dc495b528..0bf8d82eb5 100644 --- a/extensions/network/HttpRequest.h +++ b/extensions/network/HttpRequest.h @@ -214,13 +214,6 @@ public: { return _headers; } - - // Backward compatibility - CC_DEPRECATED_ATTRIBUTE static const Type kHttpGet = Type::GET; - CC_DEPRECATED_ATTRIBUTE static const Type kHttpPut = Type::PUT; - CC_DEPRECATED_ATTRIBUTE static const Type kHttpPost = Type::POST; - CC_DEPRECATED_ATTRIBUTE static const Type kHttpDelete = Type::DELETE; - CC_DEPRECATED_ATTRIBUTE static const Type kHttpUnkown = Type::UNKNOWN; protected: // properties diff --git a/extensions/network/SocketIO.cpp b/extensions/network/SocketIO.cpp index b1f4131602..3921e3cdcd 100644 --- a/extensions/network/SocketIO.cpp +++ b/extensions/network/SocketIO.cpp @@ -490,11 +490,11 @@ void SIOClientImpl::onError(cocos2d::extension::WebSocket* ws, const cocos2d::ex //begin SIOClient methods SIOClient::SIOClient(const std::string& host, int port, const std::string& path, SIOClientImpl* impl, SocketIO::SIODelegate& delegate) - : _host(host) - , _port(port) + : _port(port) + , _host(host) , _path(path) + , _connected(false) , _socket(impl) - , _connected(false) , _delegate(&delegate) { diff --git a/extensions/network/WebSocket.h b/extensions/network/WebSocket.h index bb1e55af19..0b28a6629a 100644 --- a/extensions/network/WebSocket.h +++ b/extensions/network/WebSocket.h @@ -126,16 +126,6 @@ public: */ State getReadyState(); - // Backward compatibility - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kErrorTimeout = ErrorCode::TIME_OUT; - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kErrorConnectionFailure = ErrorCode::CONNECTION_FAILURE; - CC_DEPRECATED_ATTRIBUTE static const ErrorCode kErrorUnknown = ErrorCode::UNKNOWN; - - CC_DEPRECATED_ATTRIBUTE static const State kStateConnecting = State::CONNECTING; - CC_DEPRECATED_ATTRIBUTE static const State kStateOpen = State::OPEN; - CC_DEPRECATED_ATTRIBUTE static const State kStateClosing = State::CLOSING; - CC_DEPRECATED_ATTRIBUTE static const State kStateClosed = State::CLOSED; - private: virtual void onSubThreadStarted(); virtual int onSubThreadLoop(); diff --git a/extensions/proj.emscripten/Makefile b/extensions/proj.emscripten/Makefile index 1d6c663a08..840e7564a5 100644 --- a/extensions/proj.emscripten/Makefile +++ b/extensions/proj.emscripten/Makefile @@ -88,7 +88,7 @@ SOURCES = ../CCBReader/CCBFileLoader.cpp \ ../CCArmature/utils/CCTransformHelp.cpp \ ../CCArmature/utils/CCTweenFunction.cpp \ ../CCArmature/utils/CCUtilMath.cpp \ -../CCDprecated-ext.cpp +../CCDeprecated-ext.cpp include $(COCOS_ROOT)/cocos2dx/proj.emscripten/cocos2dx.mk diff --git a/extensions/proj.qt5/extensions.pro b/extensions/proj.qt5/extensions.pro new file mode 100644 index 0000000000..48ace018e9 --- /dev/null +++ b/extensions/proj.qt5/extensions.pro @@ -0,0 +1,116 @@ + +include(../../cocos2dx/proj.qt5/common.pri) + +TEMPLATE = lib +CONFIG += static + +#SOURCES += $$files(../qt5/*.cpp) + +SOURCES += ../CCBReader/CCBFileLoader.cpp \ +../CCBReader/CCMenuItemImageLoader.cpp \ +../CCBReader/CCBReader.cpp \ +../CCBReader/CCMenuItemLoader.cpp \ +../CCBReader/CCControlButtonLoader.cpp \ +../CCBReader/CCNodeLoader.cpp \ +../CCBReader/CCControlLoader.cpp \ +../CCBReader/CCNodeLoaderLibrary.cpp \ +../CCBReader/CCLabelBMFontLoader.cpp \ +../CCBReader/CCParticleSystemQuadLoader.cpp \ +../CCBReader/CCLabelTTFLoader.cpp \ +../CCBReader/CCScale9SpriteLoader.cpp \ +../CCBReader/CCLayerColorLoader.cpp \ +../CCBReader/CCScrollViewLoader.cpp \ +../CCBReader/CCLayerGradientLoader.cpp \ +../CCBReader/CCSpriteLoader.cpp \ +../CCBReader/CCLayerLoader.cpp \ +../CCBReader/CCBAnimationManager.cpp \ +../CCBReader/CCBKeyframe.cpp \ +../CCBReader/CCBSequence.cpp \ +../CCBReader/CCBSequenceProperty.cpp \ +../CCBReader/CCBValue.cpp \ +../CCBReader/CCNode+CCBRelativePositioning.cpp \ +../GUI/CCScrollView/CCScrollView.cpp \ +../GUI/CCScrollView/CCSorting.cpp \ +../GUI/CCScrollView/CCTableView.cpp \ +../GUI/CCScrollView/CCTableViewCell.cpp \ +../GUI/CCControlExtension/CCControlButton.cpp \ +../GUI/CCControlExtension/CCControlColourPicker.cpp \ +../GUI/CCControlExtension/CCControl.cpp \ +../GUI/CCControlExtension/CCControlHuePicker.cpp \ +../GUI/CCControlExtension/CCControlSaturationBrightnessPicker.cpp \ +../GUI/CCControlExtension/CCControlSlider.cpp \ +../GUI/CCControlExtension/CCControlSwitch.cpp \ +../GUI/CCControlExtension/CCControlUtils.cpp \ +../GUI/CCControlExtension/CCInvocation.cpp \ +../GUI/CCControlExtension/CCScale9Sprite.cpp \ +../GUI/CCControlExtension/CCControlPotentiometer.cpp \ +../GUI/CCControlExtension/CCControlStepper.cpp \ +../GUI/CCEditBox/CCEditBox.cpp \ +../GUI/CCEditBox/CCEditBoxImplNone.cpp \ +../network/HttpClient.cpp \ +../physics_nodes/CCPhysicsDebugNode.cpp \ +../physics_nodes/CCPhysicsSprite.cpp \ +../spine/Animation.cpp \ +../spine/AnimationState.cpp \ +../spine/AnimationStateData.cpp \ +../spine/Atlas.cpp \ +../spine/AtlasAttachmentLoader.cpp \ +../spine/Attachment.cpp \ +../spine/AttachmentLoader.cpp \ +../spine/Bone.cpp \ +../spine/BoneData.cpp \ +../spine/Json.cpp \ +../spine/RegionAttachment.cpp \ +../spine/Skeleton.cpp \ +../spine/SkeletonData.cpp \ +../spine/SkeletonJson.cpp \ +../spine/Skin.cpp \ +../spine/Slot.cpp \ +../spine/SlotData.cpp \ +../spine/extension.cpp \ +../spine/spine-cocos2dx.cpp \ +../spine/CCSkeleton.cpp \ +../spine/CCSkeletonAnimation.cpp \ +../Components/CCComAttribute.cpp \ +../Components/CCComAudio.cpp \ +../Components/CCComController.cpp \ +../Components/CCInputDelegate.cpp \ +../CCArmature/CCArmature.cpp \ +../CCArmature/CCBone.cpp \ +../CCArmature/animation/CCArmatureAnimation.cpp \ +../CCArmature/animation/CCProcessBase.cpp \ +../CCArmature/animation/CCTween.cpp \ +../CCArmature/datas/CCDatas.cpp \ +../CCArmature/display/CCBatchNode.cpp \ +../CCArmature/display/CCDecorativeDisplay.cpp \ +../CCArmature/display/CCDisplayFactory.cpp \ +../CCArmature/display/CCDisplayManager.cpp \ +../CCArmature/display/CCShaderNode.cpp \ +../CCArmature/display/CCSkin.cpp \ +../CCArmature/external_tool/GLES-Render.cpp \ +../CCArmature/external_tool/Json/CSContentJsonDictionary.cpp \ +../CCArmature/external_tool/Json/lib_json/json_value.cpp \ +../CCArmature/external_tool/Json/lib_json/json_reader.cpp \ +../CCArmature/external_tool/Json/lib_json/json_writer.cpp \ +../CCArmature/physics/CCColliderDetector.cpp \ +../CCArmature/physics/CCPhysicsWorld.cpp \ +../CCArmature/utils/CCArmatureDataManager.cpp \ +../CCArmature/utils/CCDataReaderHelper.cpp \ +../CCArmature/utils/CCSpriteFrameCacheHelper.cpp \ +../CCArmature/utils/CCTransformHelp.cpp \ +../CCArmature/utils/CCTweenFunction.cpp \ +../CCArmature/utils/CCUtilMath.cpp + +INCLUDEPATH += .. +INCLUDEPATH += ../include +INCLUDEPATH += ../CCBReader +INCLUDEPATH += ../GUI/CCControlExtension +INCLUDEPATH += ../GUI/CCEditBox +INCLUDEPATH += ../network +INCLUDEPATH += ../Components +INCLUDEPATH += ../CCArmature + +#INCLUDES = -I$(COCOS_ROOT)/external \ + +TARGET = $${LIB_OUTPUT_DIR}/extension + diff --git a/extensions/proj.tizen/.cproject b/extensions/proj.tizen/.cproject index 80985f441a..db9765a9fe 100644 --- a/extensions/proj.tizen/.cproject +++ b/extensions/proj.tizen/.cproject @@ -67,9 +67,8 @@ - - @@ -114,7 +112,6 @@ @@ -209,7 +206,7 @@ - @@ -250,7 +247,6 @@ diff --git a/extensions/proj.tizen/.project b/extensions/proj.tizen/.project index 0f6f69efa2..0ef194d93a 100644 --- a/extensions/proj.tizen/.project +++ b/extensions/proj.tizen/.project @@ -105,6 +105,16 @@ 2 PARENT-1-PROJECT_LOC/CCBReader + + src/CCDeprecated-ext.cpp + 1 + PARENT-1-PROJECT_LOC/CCDeprecated-ext.cpp + + + src/CCDeprecated-ext.h + 1 + PARENT-1-PROJECT_LOC/CCDeprecated-ext.h + src/Components 2 @@ -135,6 +145,11 @@ 2 PARENT-1-PROJECT_LOC/network + + src/physics_nodes + 2 + PARENT-1-PROJECT_LOC/physics_nodes + src/spine 2 diff --git a/external/Box2D/proj.emscripten/Makefile b/external/Box2D/proj.emscripten/Makefile index ddfba9aa99..b0cc6a5e93 100644 --- a/external/Box2D/proj.emscripten/Makefile +++ b/external/Box2D/proj.emscripten/Makefile @@ -50,14 +50,13 @@ include ../../../cocos2dx/proj.emscripten/cocos2dx.mk INCLUDES = -I../.. -# Unfortunetly Box2D doesn't compiler cleanly without these -CXXFLAGS += -Qunused-variable -CXXFLAGS += -Wno-uninitialized +# Cocos2d is not responsible for warnings in external projects +CXXFLAGS += -w ifeq ($(DEBUG), 1) -DEFINES = -D_DEBUG +DEFINES += -D_DEBUG else -DEFINES = +DEFINES += endif TARGET := $(LIB_DIR)/$(TARGET) diff --git a/external/Box2D/proj.linux/Makefile b/external/Box2D/proj.linux/Makefile index 38abcbc489..e430bc9883 100644 --- a/external/Box2D/proj.linux/Makefile +++ b/external/Box2D/proj.linux/Makefile @@ -50,9 +50,8 @@ include ../../../cocos2dx/proj.linux/cocos2dx.mk INCLUDES = -I../.. -# Unfortunetly Box2D doesn't compiler cleanly without these -CXXFLAGS += -Wno-unused-but-set-variable -CXXFLAGS += -Wno-uninitialized +# Cocos2d is not responsible for warnings in external projects +CXXFLAGS += -w ifeq ($(DEBUG), 1) DEFINES = -D_DEBUG diff --git a/external/Box2D/proj.qt5/box2d.pro b/external/Box2D/proj.qt5/box2d.pro new file mode 100644 index 0000000000..88d1654ae6 --- /dev/null +++ b/external/Box2D/proj.qt5/box2d.pro @@ -0,0 +1,18 @@ + +include(../../../cocos2dx/proj.qt5/common.pri) + +TEMPLATE = lib +CONFIG += static + +SOURCES += $$files(../Collision/Shapes/*.cpp) +SOURCES += $$files(../Collision/*.cpp) +SOURCES += $$files(../Common/*.cpp) +SOURCES += $$files(../Dynamics/Contacts/*.cpp) +SOURCES += $$files(../Dynamics/Joints/*.cpp) +SOURCES += $$files(../Dynamics/*.cpp) +SOURCES += $$files(../Rope/*.cpp) + +INCLUDEPATH += ../.. + +TARGET = $${LIB_OUTPUT_DIR}/box2d + diff --git a/external/chipmunk/proj.qt5/chipmunk.pro b/external/chipmunk/proj.qt5/chipmunk.pro new file mode 100644 index 0000000000..2e1f180363 --- /dev/null +++ b/external/chipmunk/proj.qt5/chipmunk.pro @@ -0,0 +1,15 @@ + +include(../../../cocos2dx/proj.qt5/common.pri) + +TEMPLATE = lib +CONFIG += static + +SOURCES += $$files(../src/*.c) +SOURCES += $$files(../src/constraints/*.c) + +QMAKE_CFLAGS += -std=gnu99 + +INCLUDEPATH += ../include/chipmunk + +TARGET = $${LIB_OUTPUT_DIR}/chipmunk + diff --git a/external/chipmunk/proj.tizen/.project b/external/chipmunk/proj.tizen/.project index 1f7cbcd8ee..0542d33de2 100644 --- a/external/chipmunk/proj.tizen/.project +++ b/external/chipmunk/proj.tizen/.project @@ -7,7 +7,6 @@ org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, ?name? @@ -31,7 +30,7 @@ org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/chipmunk/Debug-Tizen-Device} + ${workspace_loc:/chipmunk/Debug-Tizen-Emulator} org.eclipse.cdt.make.core.cleanBuildTarget @@ -43,7 +42,7 @@ org.eclipse.cdt.make.core.enableAutoBuild - false + true org.eclipse.cdt.make.core.enableCleanBuild diff --git a/external/libwebp/dec/Makefile.am b/external/libwebp/dec/Makefile.am new file mode 100644 index 0000000000..06142063f5 --- /dev/null +++ b/external/libwebp/dec/Makefile.am @@ -0,0 +1,28 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src +noinst_LTLIBRARIES = libwebpdecode.la + +libwebpdecode_la_SOURCES = +libwebpdecode_la_SOURCES += alpha.c +libwebpdecode_la_SOURCES += buffer.c +libwebpdecode_la_SOURCES += decode_vp8.h +libwebpdecode_la_SOURCES += frame.c +libwebpdecode_la_SOURCES += idec.c +libwebpdecode_la_SOURCES += io.c +libwebpdecode_la_SOURCES += layer.c +libwebpdecode_la_SOURCES += quant.c +libwebpdecode_la_SOURCES += tree.c +libwebpdecode_la_SOURCES += vp8.c +libwebpdecode_la_SOURCES += vp8i.h +libwebpdecode_la_SOURCES += vp8l.c +libwebpdecode_la_SOURCES += vp8li.h +libwebpdecode_la_SOURCES += webp.c +libwebpdecode_la_SOURCES += webpi.h + +libwebpdecodeinclude_HEADERS = +libwebpdecodeinclude_HEADERS += ../webp/decode.h +libwebpdecodeinclude_HEADERS += ../webp/types.h +noinst_HEADERS = +noinst_HEADERS += ../webp/format_constants.h + +libwebpdecode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) +libwebpdecodeincludedir = $(includedir)/webp diff --git a/external/libwebp/dec/alpha.c b/external/libwebp/dec/alpha.c new file mode 100644 index 0000000000..6e65de9030 --- /dev/null +++ b/external/libwebp/dec/alpha.c @@ -0,0 +1,140 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Alpha-plane decompression. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "./vp8i.h" +#include "./vp8li.h" +#include "../utils/filters.h" +#include "../utils/quant_levels.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// TODO(skal): move to dsp/ ? +static void CopyPlane(const uint8_t* src, int src_stride, + uint8_t* dst, int dst_stride, int width, int height) { + while (height-- > 0) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } +} + +//------------------------------------------------------------------------------ +// Decodes the compressed data 'data' of size 'data_size' into the 'output'. +// The 'output' buffer should be pre-allocated and must be of the same +// dimension 'height'x'stride', as that of the image. +// +// Returns 1 on successfully decoding the compressed alpha and +// 0 if either: +// error in bit-stream header (invalid compression mode or filter), or +// error returned by appropriate compression method. + +static int DecodeAlpha(const uint8_t* data, size_t data_size, + int width, int height, int stride, uint8_t* output) { + uint8_t* decoded_data = NULL; + const size_t decoded_size = height * width; + uint8_t* unfiltered_data = NULL; + WEBP_FILTER_TYPE filter; + int pre_processing; + int rsrv; + int ok = 0; + int method; + + assert(width > 0 && height > 0 && stride >= width); + assert(data != NULL && output != NULL); + + if (data_size <= ALPHA_HEADER_LEN) { + return 0; + } + + method = (data[0] >> 0) & 0x03; + filter = (data[0] >> 2) & 0x03; + pre_processing = (data[0] >> 4) & 0x03; + rsrv = (data[0] >> 6) & 0x03; + if (method < ALPHA_NO_COMPRESSION || + method > ALPHA_LOSSLESS_COMPRESSION || + filter >= WEBP_FILTER_LAST || + pre_processing > ALPHA_PREPROCESSED_LEVELS || + rsrv != 0) { + return 0; + } + + if (method == ALPHA_NO_COMPRESSION) { + ok = (data_size >= decoded_size); + decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN; + } else { + decoded_data = (uint8_t*)malloc(decoded_size); + if (decoded_data == NULL) return 0; + ok = VP8LDecodeAlphaImageStream(width, height, + data + ALPHA_HEADER_LEN, + data_size - ALPHA_HEADER_LEN, + decoded_data); + } + + if (ok) { + WebPFilterFunc unfilter_func = WebPUnfilters[filter]; + if (unfilter_func != NULL) { + unfiltered_data = (uint8_t*)malloc(decoded_size); + if (unfiltered_data == NULL) { + ok = 0; + goto Error; + } + // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode + // and apply filter per image-row. + unfilter_func(decoded_data, width, height, 1, width, unfiltered_data); + // Construct raw_data (height x stride) from alpha data (height x width). + CopyPlane(unfiltered_data, width, output, stride, width, height); + free(unfiltered_data); + } else { + // Construct raw_data (height x stride) from alpha data (height x width). + CopyPlane(decoded_data, width, output, stride, width, height); + } + if (pre_processing == ALPHA_PREPROCESSED_LEVELS) { + ok = DequantizeLevels(decoded_data, width, height); + } + } + + Error: + if (method != ALPHA_NO_COMPRESSION) { + free(decoded_data); + } + return ok; +} + +//------------------------------------------------------------------------------ + +const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, + int row, int num_rows) { + const int stride = dec->pic_hdr_.width_; + + if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) { + return NULL; // sanity check. + } + + if (row == 0) { + // Decode everything during the first call. + if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_, + dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride, + dec->alpha_plane_)) { + return NULL; // Error. + } + } + + // Return a pointer to the current decoded row. + return dec->alpha_plane_ + row * stride; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/buffer.c b/external/libwebp/dec/buffer.c new file mode 100644 index 0000000000..c159f6f248 --- /dev/null +++ b/external/libwebp/dec/buffer.c @@ -0,0 +1,215 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Everything about WebPDecBuffer +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./vp8i.h" +#include "./webpi.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// WebPDecBuffer + +// Number of bytes per pixel for the different color-spaces. +static const int kModeBpp[MODE_LAST] = { + 3, 4, 3, 4, 4, 2, 2, + 4, 4, 4, 2, // pre-multiplied modes + 1, 1 }; + +// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. +// Convert to an integer to handle both the unsigned/signed enum cases +// without the need for casting to remove type limit warnings. +static int IsValidColorspace(int webp_csp_mode) { + return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); +} + +static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) { + int ok = 1; + const WEBP_CSP_MODE mode = buffer->colorspace; + const int width = buffer->width; + const int height = buffer->height; + if (!IsValidColorspace(mode)) { + ok = 0; + } else if (!WebPIsRGBMode(mode)) { // YUV checks + const WebPYUVABuffer* const buf = &buffer->u.YUVA; + const uint64_t y_size = (uint64_t)buf->y_stride * height; + const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2); + const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2); + const uint64_t a_size = (uint64_t)buf->a_stride * height; + ok &= (y_size <= buf->y_size); + ok &= (u_size <= buf->u_size); + ok &= (v_size <= buf->v_size); + ok &= (buf->y_stride >= width); + ok &= (buf->u_stride >= (width + 1) / 2); + ok &= (buf->v_stride >= (width + 1) / 2); + ok &= (buf->y != NULL); + ok &= (buf->u != NULL); + ok &= (buf->v != NULL); + if (mode == MODE_YUVA) { + ok &= (buf->a_stride >= width); + ok &= (a_size <= buf->a_size); + ok &= (buf->a != NULL); + } + } else { // RGB checks + const WebPRGBABuffer* const buf = &buffer->u.RGBA; + const uint64_t size = (uint64_t)buf->stride * height; + ok &= (size <= buf->size); + ok &= (buf->stride >= width * kModeBpp[mode]); + ok &= (buf->rgba != NULL); + } + return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM; +} + +static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) { + const int w = buffer->width; + const int h = buffer->height; + const WEBP_CSP_MODE mode = buffer->colorspace; + + if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) { + return VP8_STATUS_INVALID_PARAM; + } + + if (!buffer->is_external_memory && buffer->private_memory == NULL) { + uint8_t* output; + int uv_stride = 0, a_stride = 0; + uint64_t uv_size = 0, a_size = 0, total_size; + // We need memory and it hasn't been allocated yet. + // => initialize output buffer, now that dimensions are known. + const int stride = w * kModeBpp[mode]; + const uint64_t size = (uint64_t)stride * h; + + if (!WebPIsRGBMode(mode)) { + uv_stride = (w + 1) / 2; + uv_size = (uint64_t)uv_stride * ((h + 1) / 2); + if (mode == MODE_YUVA) { + a_stride = w; + a_size = (uint64_t)a_stride * h; + } + } + total_size = size + 2 * uv_size + a_size; + + // Security/sanity checks + output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output)); + if (output == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + buffer->private_memory = output; + + if (!WebPIsRGBMode(mode)) { // YUVA initialization + WebPYUVABuffer* const buf = &buffer->u.YUVA; + buf->y = output; + buf->y_stride = stride; + buf->y_size = (size_t)size; + buf->u = output + size; + buf->u_stride = uv_stride; + buf->u_size = (size_t)uv_size; + buf->v = output + size + uv_size; + buf->v_stride = uv_stride; + buf->v_size = (size_t)uv_size; + if (mode == MODE_YUVA) { + buf->a = output + size + 2 * uv_size; + } + buf->a_size = (size_t)a_size; + buf->a_stride = a_stride; + } else { // RGBA initialization + WebPRGBABuffer* const buf = &buffer->u.RGBA; + buf->rgba = output; + buf->stride = stride; + buf->size = (size_t)size; + } + } + return CheckDecBuffer(buffer); +} + +VP8StatusCode WebPAllocateDecBuffer(int w, int h, + const WebPDecoderOptions* const options, + WebPDecBuffer* const out) { + if (out == NULL || w <= 0 || h <= 0) { + return VP8_STATUS_INVALID_PARAM; + } + if (options != NULL) { // First, apply options if there is any. + if (options->use_cropping) { + const int cw = options->crop_width; + const int ch = options->crop_height; + const int x = options->crop_left & ~1; + const int y = options->crop_top & ~1; + if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) { + return VP8_STATUS_INVALID_PARAM; // out of frame boundary. + } + w = cw; + h = ch; + } + if (options->use_scaling) { + if (options->scaled_width <= 0 || options->scaled_height <= 0) { + return VP8_STATUS_INVALID_PARAM; + } + w = options->scaled_width; + h = options->scaled_height; + } + } + out->width = w; + out->height = h; + + // Then, allocate buffer for real + return AllocateBuffer(out); +} + +//------------------------------------------------------------------------------ +// constructors / destructors + +int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // version mismatch + } + if (buffer == NULL) return 0; + memset(buffer, 0, sizeof(*buffer)); + return 1; +} + +void WebPFreeDecBuffer(WebPDecBuffer* buffer) { + if (buffer != NULL) { + if (!buffer->is_external_memory) + free(buffer->private_memory); + buffer->private_memory = NULL; + } +} + +void WebPCopyDecBuffer(const WebPDecBuffer* const src, + WebPDecBuffer* const dst) { + if (src != NULL && dst != NULL) { + *dst = *src; + if (src->private_memory != NULL) { + dst->is_external_memory = 1; // dst buffer doesn't own the memory. + dst->private_memory = NULL; + } + } +} + +// Copy and transfer ownership from src to dst (beware of parameter order!) +void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) { + if (src != NULL && dst != NULL) { + *dst = *src; + if (src->private_memory != NULL) { + src->is_external_memory = 1; // src relinquishes ownership + src->private_memory = NULL; + } + } +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/decode_vp8.h b/external/libwebp/dec/decode_vp8.h new file mode 100644 index 0000000000..12c77bcbf6 --- /dev/null +++ b/external/libwebp/dec/decode_vp8.h @@ -0,0 +1,182 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Low-level API for VP8 decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_DECODE_VP8_H_ +#define WEBP_WEBP_DECODE_VP8_H_ + +#include "../webp/decode.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Lower-level API +// +// These functions provide fine-grained control of the decoding process. +// The call flow should resemble: +// +// VP8Io io; +// VP8InitIo(&io); +// io.data = data; +// io.data_size = size; +// /* customize io's functions (setup()/put()/teardown()) if needed. */ +// +// VP8Decoder* dec = VP8New(); +// bool ok = VP8Decode(dec); +// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec)); +// VP8Delete(dec); +// return ok; + +// Input / Output +typedef struct VP8Io VP8Io; +typedef int (*VP8IoPutHook)(const VP8Io* io); +typedef int (*VP8IoSetupHook)(VP8Io* io); +typedef void (*VP8IoTeardownHook)(const VP8Io* io); + +struct VP8Io { + // set by VP8GetHeaders() + int width, height; // picture dimensions, in pixels (invariable). + // These are the original, uncropped dimensions. + // The actual area passed to put() is stored + // in mb_w / mb_h fields. + + // set before calling put() + int mb_y; // position of the current rows (in pixels) + int mb_w; // number of columns in the sample + int mb_h; // number of rows in the sample + const uint8_t* y, *u, *v; // rows to copy (in yuv420 format) + int y_stride; // row stride for luma + int uv_stride; // row stride for chroma + + void* opaque; // user data + + // called when fresh samples are available. Currently, samples are in + // YUV420 format, and can be up to width x 24 in size (depending on the + // in-loop filtering level, e.g.). Should return false in case of error + // or abort request. The actual size of the area to update is mb_w x mb_h + // in size, taking cropping into account. + VP8IoPutHook put; + + // called just before starting to decode the blocks. + // Must return false in case of setup error, true otherwise. If false is + // returned, teardown() will NOT be called. But if the setup succeeded + // and true is returned, then teardown() will always be called afterward. + VP8IoSetupHook setup; + + // Called just after block decoding is finished (or when an error occurred + // during put()). Is NOT called if setup() failed. + VP8IoTeardownHook teardown; + + // this is a recommendation for the user-side yuv->rgb converter. This flag + // is set when calling setup() hook and can be overwritten by it. It then + // can be taken into consideration during the put() method. + int fancy_upsampling; + + // Input buffer. + size_t data_size; + const uint8_t* data; + + // If true, in-loop filtering will not be performed even if present in the + // bitstream. Switching off filtering may speed up decoding at the expense + // of more visible blocking. Note that output will also be non-compliant + // with the VP8 specifications. + int bypass_filtering; + + // Cropping parameters. + int use_cropping; + int crop_left, crop_right, crop_top, crop_bottom; + + // Scaling parameters. + int use_scaling; + int scaled_width, scaled_height; + + // If non NULL, pointer to the alpha data (if present) corresponding to the + // start of the current row (That is: it is pre-offset by mb_y and takes + // cropping into account). + const uint8_t* a; +}; + +// Internal, version-checked, entry point +int VP8InitIoInternal(VP8Io* const, int); + +// Set the custom IO function pointers and user-data. The setter for IO hooks +// should be called before initiating incremental decoding. Returns true if +// WebPIDecoder object is successfully modified, false otherwise. +int WebPISetIOHooks(WebPIDecoder* const idec, + VP8IoPutHook put, + VP8IoSetupHook setup, + VP8IoTeardownHook teardown, + void* user_data); + +// Main decoding object. This is an opaque structure. +typedef struct VP8Decoder VP8Decoder; + +// Create a new decoder object. +VP8Decoder* VP8New(void); + +// Must be called to make sure 'io' is initialized properly. +// Returns false in case of version mismatch. Upon such failure, no other +// decoding function should be called (VP8Decode, VP8GetHeaders, ...) +static WEBP_INLINE int VP8InitIo(VP8Io* const io) { + return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION); +} + +// Start decoding a new picture. Returns true if ok. +int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); + +// Decode a picture. Will call VP8GetHeaders() if it wasn't done already. +// Returns false in case of error. +int VP8Decode(VP8Decoder* const dec, VP8Io* const io); + +// Return current status of the decoder: +VP8StatusCode VP8Status(VP8Decoder* const dec); + +// return readable string corresponding to the last status. +const char* VP8StatusMessage(VP8Decoder* const dec); + +// Resets the decoder in its initial state, reclaiming memory. +// Not a mandatory call between calls to VP8Decode(). +void VP8Clear(VP8Decoder* const dec); + +// Destroy the decoder object. +void VP8Delete(VP8Decoder* const dec); + +//------------------------------------------------------------------------------ +// Miscellaneous VP8/VP8L bitstream probing functions. + +// Returns true if the next 3 bytes in data contain the VP8 signature. +WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size); + +// Validates the VP8 data-header and retrieves basic header information viz +// width and height. Returns 0 in case of formatting error. *width/*height +// can be passed NULL. +WEBP_EXTERN(int) VP8GetInfo( + const uint8_t* data, + size_t data_size, // data available so far + size_t chunk_size, // total data size expected in the chunk + int* const width, int* const height); + +// Returns true if the next byte(s) in data is a VP8L signature. +WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size); + +// Validates the VP8L data-header and retrieves basic header information viz +// width, height and alpha. Returns 0 in case of formatting error. +// width/height/has_alpha can be passed NULL. +WEBP_EXTERN(int) VP8LGetInfo( + const uint8_t* data, size_t data_size, // data available so far + int* const width, int* const height, int* const has_alpha); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_WEBP_DECODE_VP8_H_ */ diff --git a/external/libwebp/dec/frame.c b/external/libwebp/dec/frame.c new file mode 100644 index 0000000000..9c91a48e17 --- /dev/null +++ b/external/libwebp/dec/frame.c @@ -0,0 +1,679 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Frame-reconstruction function. Memory allocation. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "./vp8i.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define ALIGN_MASK (32 - 1) + +//------------------------------------------------------------------------------ +// Filtering + +// kFilterExtraRows[] = How many extra lines are needed on the MB boundary +// for caching, given a filtering level. +// Simple filter: up to 2 luma samples are read and 1 is written. +// Complex filter: up to 4 luma samples are read and 3 are written. Same for +// U/V, so it's 8 samples total (because of the 2x upsampling). +static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 }; + +static WEBP_INLINE int hev_thresh_from_level(int level, int keyframe) { + if (keyframe) { + return (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + } else { + return (level >= 40) ? 3 : (level >= 20) ? 2 : (level >= 15) ? 1 : 0; + } +} + +static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { + const VP8ThreadContext* const ctx = &dec->thread_ctx_; + const int y_bps = dec->cache_y_stride_; + VP8FInfo* const f_info = ctx->f_info_ + mb_x; + uint8_t* const y_dst = dec->cache_y_ + ctx->id_ * 16 * y_bps + mb_x * 16; + const int level = f_info->f_level_; + const int ilevel = f_info->f_ilevel_; + const int limit = 2 * level + ilevel; + if (level == 0) { + return; + } + if (dec->filter_type_ == 1) { // simple + if (mb_x > 0) { + VP8SimpleHFilter16(y_dst, y_bps, limit + 4); + } + if (f_info->f_inner_) { + VP8SimpleHFilter16i(y_dst, y_bps, limit); + } + if (mb_y > 0) { + VP8SimpleVFilter16(y_dst, y_bps, limit + 4); + } + if (f_info->f_inner_) { + VP8SimpleVFilter16i(y_dst, y_bps, limit); + } + } else { // complex + const int uv_bps = dec->cache_uv_stride_; + uint8_t* const u_dst = dec->cache_u_ + ctx->id_ * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v_ + ctx->id_ * 8 * uv_bps + mb_x * 8; + const int hev_thresh = + hev_thresh_from_level(level, dec->frm_hdr_.key_frame_); + if (mb_x > 0) { + VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); + VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); + } + if (f_info->f_inner_) { + VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); + VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); + } + if (mb_y > 0) { + VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); + VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); + } + if (f_info->f_inner_) { + VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); + VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); + } + } +} + +// Filter the decoded macroblock row (if needed) +static void FilterRow(const VP8Decoder* const dec) { + int mb_x; + const int mb_y = dec->thread_ctx_.mb_y_; + assert(dec->thread_ctx_.filter_row_); + for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { + DoFilter(dec, mb_x, mb_y); + } +} + +//------------------------------------------------------------------------------ + +void VP8StoreBlock(VP8Decoder* const dec) { + if (dec->filter_type_ > 0) { + VP8FInfo* const info = dec->f_info_ + dec->mb_x_; + const int skip = dec->mb_info_[dec->mb_x_].skip_; + int level = dec->filter_levels_[dec->segment_]; + if (dec->filter_hdr_.use_lf_delta_) { + // TODO(skal): only CURRENT is handled for now. + level += dec->filter_hdr_.ref_lf_delta_[0]; + if (dec->is_i4x4_) { + level += dec->filter_hdr_.mode_lf_delta_[0]; + } + } + level = (level < 0) ? 0 : (level > 63) ? 63 : level; + info->f_level_ = level; + + if (dec->filter_hdr_.sharpness_ > 0) { + if (dec->filter_hdr_.sharpness_ > 4) { + level >>= 2; + } else { + level >>= 1; + } + if (level > 9 - dec->filter_hdr_.sharpness_) { + level = 9 - dec->filter_hdr_.sharpness_; + } + } + + info->f_ilevel_ = (level < 1) ? 1 : level; + info->f_inner_ = (!skip || dec->is_i4x4_); + } + { + // Transfer samples to row cache + int y; + const int y_offset = dec->cache_id_ * 16 * dec->cache_y_stride_; + const int uv_offset = dec->cache_id_ * 8 * dec->cache_uv_stride_; + uint8_t* const ydst = dec->cache_y_ + dec->mb_x_ * 16 + y_offset; + uint8_t* const udst = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset; + uint8_t* const vdst = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset; + for (y = 0; y < 16; ++y) { + memcpy(ydst + y * dec->cache_y_stride_, + dec->yuv_b_ + Y_OFF + y * BPS, 16); + } + for (y = 0; y < 8; ++y) { + memcpy(udst + y * dec->cache_uv_stride_, + dec->yuv_b_ + U_OFF + y * BPS, 8); + memcpy(vdst + y * dec->cache_uv_stride_, + dec->yuv_b_ + V_OFF + y * BPS, 8); + } + } +} + +//------------------------------------------------------------------------------ +// This function is called after a row of macroblocks is finished decoding. +// It also takes into account the following restrictions: +// * In case of in-loop filtering, we must hold off sending some of the bottom +// pixels as they are yet unfiltered. They will be when the next macroblock +// row is decoded. Meanwhile, we must preserve them by rotating them in the +// cache area. This doesn't hold for the very bottom row of the uncropped +// picture of course. +// * we must clip the remaining pixels against the cropping area. The VP8Io +// struct must have the following fields set correctly before calling put(): + +#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB + +// Finalize and transmit a complete row. Return false in case of user-abort. +static int FinishRow(VP8Decoder* const dec, VP8Io* const io) { + int ok = 1; + const VP8ThreadContext* const ctx = &dec->thread_ctx_; + const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; + const int ysize = extra_y_rows * dec->cache_y_stride_; + const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_; + const int y_offset = ctx->id_ * 16 * dec->cache_y_stride_; + const int uv_offset = ctx->id_ * 8 * dec->cache_uv_stride_; + uint8_t* const ydst = dec->cache_y_ - ysize + y_offset; + uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset; + uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset; + const int first_row = (ctx->mb_y_ == 0); + const int last_row = (ctx->mb_y_ >= dec->br_mb_y_ - 1); + int y_start = MACROBLOCK_VPOS(ctx->mb_y_); + int y_end = MACROBLOCK_VPOS(ctx->mb_y_ + 1); + + if (ctx->filter_row_) { + FilterRow(dec); + } + + if (io->put) { + if (!first_row) { + y_start -= extra_y_rows; + io->y = ydst; + io->u = udst; + io->v = vdst; + } else { + io->y = dec->cache_y_ + y_offset; + io->u = dec->cache_u_ + uv_offset; + io->v = dec->cache_v_ + uv_offset; + } + + if (!last_row) { + y_end -= extra_y_rows; + } + if (y_end > io->crop_bottom) { + y_end = io->crop_bottom; // make sure we don't overflow on last row. + } + io->a = NULL; + if (dec->alpha_data_ != NULL && y_start < y_end) { + // TODO(skal): several things to correct here: + // * testing presence of alpha with dec->alpha_data_ is not a good idea + // * we're actually decompressing the full plane only once. It should be + // more obvious from signature. + // * we could free alpha_data_ right after this call, but we don't own. + io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start); + if (io->a == NULL) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Could not decode alpha data."); + } + } + if (y_start < io->crop_top) { + const int delta_y = io->crop_top - y_start; + y_start = io->crop_top; + assert(!(delta_y & 1)); + io->y += dec->cache_y_stride_ * delta_y; + io->u += dec->cache_uv_stride_ * (delta_y >> 1); + io->v += dec->cache_uv_stride_ * (delta_y >> 1); + if (io->a != NULL) { + io->a += io->width * delta_y; + } + } + if (y_start < y_end) { + io->y += io->crop_left; + io->u += io->crop_left >> 1; + io->v += io->crop_left >> 1; + if (io->a != NULL) { + io->a += io->crop_left; + } + io->mb_y = y_start - io->crop_top; + io->mb_w = io->crop_right - io->crop_left; + io->mb_h = y_end - y_start; + ok = io->put(io); + } + } + // rotate top samples if needed + if (ctx->id_ + 1 == dec->num_caches_) { + if (!last_row) { + memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize); + memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize); + memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize); + } + } + + return ok; +} + +#undef MACROBLOCK_VPOS + +//------------------------------------------------------------------------------ + +int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) { + int ok = 1; + VP8ThreadContext* const ctx = &dec->thread_ctx_; + if (!dec->use_threads_) { + // ctx->id_ and ctx->f_info_ are already set + ctx->mb_y_ = dec->mb_y_; + ctx->filter_row_ = dec->filter_row_; + ok = FinishRow(dec, io); + } else { + WebPWorker* const worker = &dec->worker_; + // Finish previous job *before* updating context + ok &= WebPWorkerSync(worker); + assert(worker->status_ == OK); + if (ok) { // spawn a new deblocking/output job + ctx->io_ = *io; + ctx->id_ = dec->cache_id_; + ctx->mb_y_ = dec->mb_y_; + ctx->filter_row_ = dec->filter_row_; + if (ctx->filter_row_) { // just swap filter info + VP8FInfo* const tmp = ctx->f_info_; + ctx->f_info_ = dec->f_info_; + dec->f_info_ = tmp; + } + WebPWorkerLaunch(worker); + if (++dec->cache_id_ == dec->num_caches_) { + dec->cache_id_ = 0; + } + } + } + return ok; +} + +//------------------------------------------------------------------------------ +// Finish setting up the decoding parameter once user's setup() is called. + +VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { + // Call setup() first. This may trigger additional decoding features on 'io'. + // Note: Afterward, we must call teardown() not matter what. + if (io->setup && !io->setup(io)) { + VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed"); + return dec->status_; + } + + // Disable filtering per user request + if (io->bypass_filtering) { + dec->filter_type_ = 0; + } + // TODO(skal): filter type / strength / sharpness forcing + + // Define the area where we can skip in-loop filtering, in case of cropping. + // + // 'Simple' filter reads two luma samples outside of the macroblock and + // and filters one. It doesn't filter the chroma samples. Hence, we can + // avoid doing the in-loop filtering before crop_top/crop_left position. + // For the 'Complex' filter, 3 samples are read and up to 3 are filtered. + // Means: there's a dependency chain that goes all the way up to the + // top-left corner of the picture (MB #0). We must filter all the previous + // macroblocks. + // TODO(skal): add an 'approximate_decoding' option, that won't produce + // a 1:1 bit-exactness for complex filtering? + { + const int extra_pixels = kFilterExtraRows[dec->filter_type_]; + if (dec->filter_type_ == 2) { + // For complex filter, we need to preserve the dependency chain. + dec->tl_mb_x_ = 0; + dec->tl_mb_y_ = 0; + } else { + // For simple filter, we can filter only the cropped region. + // We include 'extra_pixels' on the other side of the boundary, since + // vertical or horizontal filtering of the previous macroblock can + // modify some abutting pixels. + dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4; + dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4; + if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0; + if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0; + } + // We need some 'extra' pixels on the right/bottom. + dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; + dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; + if (dec->br_mb_x_ > dec->mb_w_) { + dec->br_mb_x_ = dec->mb_w_; + } + if (dec->br_mb_y_ > dec->mb_h_) { + dec->br_mb_y_ = dec->mb_h_; + } + } + return VP8_STATUS_OK; +} + +int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { + int ok = 1; + if (dec->use_threads_) { + ok = WebPWorkerSync(&dec->worker_); + } + + if (io->teardown) { + io->teardown(io); + } + return ok; +} + +//------------------------------------------------------------------------------ +// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line. +// +// Reason is: the deblocking filter cannot deblock the bottom horizontal edges +// immediately, and needs to wait for first few rows of the next macroblock to +// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending +// on strength). +// With two threads, the vertical positions of the rows being decoded are: +// Decode: [ 0..15][16..31][32..47][48..63][64..79][... +// Deblock: [ 0..11][12..27][28..43][44..59][... +// If we use two threads and two caches of 16 pixels, the sequence would be: +// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][... +// Deblock: [ 0..11][12..27!!][-4..11][12..27][... +// The problem occurs during row [12..15!!] that both the decoding and +// deblocking threads are writing simultaneously. +// With 3 cache lines, one get a safe write pattern: +// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0.. +// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28... +// Note that multi-threaded output _without_ deblocking can make use of two +// cache lines of 16 pixels only, since there's no lagging behind. The decoding +// and output process have non-concurrent writing: +// Decode: [ 0..15][16..31][ 0..15][16..31][... +// io->put: [ 0..15][16..31][ 0..15][... + +#define MT_CACHE_LINES 3 +#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case + +// Initialize multi/single-thread worker +static int InitThreadContext(VP8Decoder* const dec) { + dec->cache_id_ = 0; + if (dec->use_threads_) { + WebPWorker* const worker = &dec->worker_; + if (!WebPWorkerReset(worker)) { + return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "thread initialization failed."); + } + worker->data1 = dec; + worker->data2 = (void*)&dec->thread_ctx_.io_; + worker->hook = (WebPWorkerHook)FinishRow; + dec->num_caches_ = + (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; + } else { + dec->num_caches_ = ST_CACHE_LINES; + } + return 1; +} + +#undef MT_CACHE_LINES +#undef ST_CACHE_LINES + +//------------------------------------------------------------------------------ +// Memory setup + +static int AllocateMemory(VP8Decoder* const dec) { + const int num_caches = dec->num_caches_; + const int mb_w = dec->mb_w_; + // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise. + const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t); + const size_t top_size = (16 + 8 + 8) * mb_w; + const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB); + const size_t f_info_size = + (dec->filter_type_ > 0) ? + mb_w * (dec->use_threads_ ? 2 : 1) * sizeof(VP8FInfo) + : 0; + const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_); + const size_t coeffs_size = 384 * sizeof(*dec->coeffs_); + const size_t cache_height = (16 * num_caches + + kFilterExtraRows[dec->filter_type_]) * 3 / 2; + const size_t cache_size = top_size * cache_height; + // alpha_size is the only one that scales as width x height. + const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? + (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; + const uint64_t needed = (uint64_t)intra_pred_mode_size + + top_size + mb_info_size + f_info_size + + yuv_size + coeffs_size + + cache_size + alpha_size + ALIGN_MASK; + uint8_t* mem; + + if (needed != (size_t)needed) return 0; // check for overflow + if (needed > dec->mem_size_) { + free(dec->mem_); + dec->mem_size_ = 0; + dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); + if (dec->mem_ == NULL) { + return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, + "no memory during frame initialization."); + } + // down-cast is ok, thanks to WebPSafeAlloc() above. + dec->mem_size_ = (size_t)needed; + } + + mem = (uint8_t*)dec->mem_; + dec->intra_t_ = (uint8_t*)mem; + mem += intra_pred_mode_size; + + dec->y_t_ = (uint8_t*)mem; + mem += 16 * mb_w; + dec->u_t_ = (uint8_t*)mem; + mem += 8 * mb_w; + dec->v_t_ = (uint8_t*)mem; + mem += 8 * mb_w; + + dec->mb_info_ = ((VP8MB*)mem) + 1; + mem += mb_info_size; + + dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL; + mem += f_info_size; + dec->thread_ctx_.id_ = 0; + dec->thread_ctx_.f_info_ = dec->f_info_; + if (dec->use_threads_) { + // secondary cache line. The deblocking process need to make use of the + // filtering strength from previous macroblock row, while the new ones + // are being decoded in parallel. We'll just swap the pointers. + dec->thread_ctx_.f_info_ += mb_w; + } + + mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK); + assert((yuv_size & ALIGN_MASK) == 0); + dec->yuv_b_ = (uint8_t*)mem; + mem += yuv_size; + + dec->coeffs_ = (int16_t*)mem; + mem += coeffs_size; + + dec->cache_y_stride_ = 16 * mb_w; + dec->cache_uv_stride_ = 8 * mb_w; + { + const int extra_rows = kFilterExtraRows[dec->filter_type_]; + const int extra_y = extra_rows * dec->cache_y_stride_; + const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_; + dec->cache_y_ = ((uint8_t*)mem) + extra_y; + dec->cache_u_ = dec->cache_y_ + + 16 * num_caches * dec->cache_y_stride_ + extra_uv; + dec->cache_v_ = dec->cache_u_ + + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; + dec->cache_id_ = 0; + } + mem += cache_size; + + // alpha plane + dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL; + mem += alpha_size; + + // note: left-info is initialized once for all. + memset(dec->mb_info_ - 1, 0, mb_info_size); + + // initialize top + memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); + + return 1; +} + +static void InitIo(VP8Decoder* const dec, VP8Io* io) { + // prepare 'io' + io->mb_y = 0; + io->y = dec->cache_y_; + io->u = dec->cache_u_; + io->v = dec->cache_v_; + io->y_stride = dec->cache_y_stride_; + io->uv_stride = dec->cache_uv_stride_; + io->a = NULL; +} + +int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) { + if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_. + if (!AllocateMemory(dec)) return 0; + InitIo(dec, io); + VP8DspInit(); // Init critical function pointers and look-up tables. + return 1; +} + +//------------------------------------------------------------------------------ +// Main reconstruction function. + +static const int kScan[16] = { + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS +}; + +static WEBP_INLINE int CheckMode(VP8Decoder* const dec, int mode) { + if (mode == B_DC_PRED) { + if (dec->mb_x_ == 0) { + return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT; + } else { + return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOP : B_DC_PRED; + } + } + return mode; +} + +static WEBP_INLINE void Copy32b(uint8_t* dst, uint8_t* src) { + *(uint32_t*)dst = *(uint32_t*)src; +} + +void VP8ReconstructBlock(VP8Decoder* const dec) { + uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; + uint8_t* const u_dst = dec->yuv_b_ + U_OFF; + uint8_t* const v_dst = dec->yuv_b_ + V_OFF; + + // Rotate in the left samples from previously decoded block. We move four + // pixels at a time for alignment reason, and because of in-loop filter. + if (dec->mb_x_ > 0) { + int j; + for (j = -1; j < 16; ++j) { + Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]); + } + for (j = -1; j < 8; ++j) { + Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]); + Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]); + } + } else { + int j; + for (j = 0; j < 16; ++j) { + y_dst[j * BPS - 1] = 129; + } + for (j = 0; j < 8; ++j) { + u_dst[j * BPS - 1] = 129; + v_dst[j * BPS - 1] = 129; + } + // Init top-left sample on left column too + if (dec->mb_y_ > 0) { + y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129; + } + } + { + // bring top samples into the cache + uint8_t* const top_y = dec->y_t_ + dec->mb_x_ * 16; + uint8_t* const top_u = dec->u_t_ + dec->mb_x_ * 8; + uint8_t* const top_v = dec->v_t_ + dec->mb_x_ * 8; + const int16_t* coeffs = dec->coeffs_; + int n; + + if (dec->mb_y_ > 0) { + memcpy(y_dst - BPS, top_y, 16); + memcpy(u_dst - BPS, top_u, 8); + memcpy(v_dst - BPS, top_v, 8); + } else if (dec->mb_x_ == 0) { + // we only need to do this init once at block (0,0). + // Afterward, it remains valid for the whole topmost row. + memset(y_dst - BPS - 1, 127, 16 + 4 + 1); + memset(u_dst - BPS - 1, 127, 8 + 1); + memset(v_dst - BPS - 1, 127, 8 + 1); + } + + // predict and add residuals + + if (dec->is_i4x4_) { // 4x4 + uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16); + + if (dec->mb_y_ > 0) { + if (dec->mb_x_ >= dec->mb_w_ - 1) { // on rightmost border + top_right[0] = top_y[15] * 0x01010101u; + } else { + memcpy(top_right, top_y + 16, sizeof(*top_right)); + } + } + // replicate the top-right pixels below + top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0]; + + // predict and add residues for all 4x4 blocks in turn. + for (n = 0; n < 16; n++) { + uint8_t* const dst = y_dst + kScan[n]; + VP8PredLuma4[dec->imodes_[n]](dst); + if (dec->non_zero_ac_ & (1 << n)) { + VP8Transform(coeffs + n * 16, dst, 0); + } else if (dec->non_zero_ & (1 << n)) { // only DC is present + VP8TransformDC(coeffs + n * 16, dst); + } + } + } else { // 16x16 + const int pred_func = CheckMode(dec, dec->imodes_[0]); + VP8PredLuma16[pred_func](y_dst); + if (dec->non_zero_) { + for (n = 0; n < 16; n++) { + uint8_t* const dst = y_dst + kScan[n]; + if (dec->non_zero_ac_ & (1 << n)) { + VP8Transform(coeffs + n * 16, dst, 0); + } else if (dec->non_zero_ & (1 << n)) { // only DC is present + VP8TransformDC(coeffs + n * 16, dst); + } + } + } + } + { + // Chroma + const int pred_func = CheckMode(dec, dec->uvmode_); + VP8PredChroma8[pred_func](u_dst); + VP8PredChroma8[pred_func](v_dst); + + if (dec->non_zero_ & 0x0f0000) { // chroma-U + const int16_t* const u_coeffs = dec->coeffs_ + 16 * 16; + if (dec->non_zero_ac_ & 0x0f0000) { + VP8TransformUV(u_coeffs, u_dst); + } else { + VP8TransformDCUV(u_coeffs, u_dst); + } + } + if (dec->non_zero_ & 0xf00000) { // chroma-V + const int16_t* const v_coeffs = dec->coeffs_ + 20 * 16; + if (dec->non_zero_ac_ & 0xf00000) { + VP8TransformUV(v_coeffs, v_dst); + } else { + VP8TransformDCUV(v_coeffs, v_dst); + } + } + + // stash away top samples for next block + if (dec->mb_y_ < dec->mb_h_ - 1) { + memcpy(top_y, y_dst + 15 * BPS, 16); + memcpy(top_u, u_dst + 7 * BPS, 8); + memcpy(top_v, v_dst + 7 * BPS, 8); + } + } + } +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/idec.c b/external/libwebp/dec/idec.c new file mode 100644 index 0000000000..7df790ced8 --- /dev/null +++ b/external/libwebp/dec/idec.c @@ -0,0 +1,785 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Incremental decoding +// +// Author: somnath@google.com (Somnath Banerjee) + +#include +#include +#include + +#include "./webpi.h" +#include "./vp8i.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// In append mode, buffer allocations increase as multiples of this value. +// Needs to be a power of 2. +#define CHUNK_SIZE 4096 +#define MAX_MB_SIZE 4096 + +//------------------------------------------------------------------------------ +// Data structures for memory and states + +// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE. +// If there is any error the decoder goes into state ERROR. +typedef enum { + STATE_PRE_VP8, // All data before that of the first VP8 chunk. + STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk). + STATE_VP8_PARTS0, + STATE_VP8_DATA, + STATE_VP8L_HEADER, + STATE_VP8L_DATA, + STATE_DONE, + STATE_ERROR +} DecState; + +// Operating state for the MemBuffer +typedef enum { + MEM_MODE_NONE = 0, + MEM_MODE_APPEND, + MEM_MODE_MAP +} MemBufferMode; + +// storage for partition #0 and partial data (in a rolling fashion) +typedef struct { + MemBufferMode mode_; // Operation mode + size_t start_; // start location of the data to be decoded + size_t end_; // end location + size_t buf_size_; // size of the allocated buffer + uint8_t* buf_; // We don't own this buffer in case WebPIUpdate() + + size_t part0_size_; // size of partition #0 + const uint8_t* part0_buf_; // buffer to store partition #0 +} MemBuffer; + +struct WebPIDecoder { + DecState state_; // current decoding state + WebPDecParams params_; // Params to store output info + int is_lossless_; // for down-casting 'dec_'. + void* dec_; // either a VP8Decoder or a VP8LDecoder instance + VP8Io io_; + + MemBuffer mem_; // input memory buffer. + WebPDecBuffer output_; // output buffer (when no external one is supplied) + size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. +}; + +// MB context to restore in case VP8DecodeMB() fails +typedef struct { + VP8MB left_; + VP8MB info_; + uint8_t intra_t_[4]; + uint8_t intra_l_[4]; + VP8BitReader br_; + VP8BitReader token_br_; +} MBContext; + +//------------------------------------------------------------------------------ +// MemBuffer: incoming data handling + +static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) { + if (br->buf_ != NULL) { + br->buf_ += offset; + br->buf_end_ += offset; + } +} + +static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { + return (mem->end_ - mem->start_); +} + +static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* const new_base = mem->buf_ + mem->start_; + // note: for VP8, setting up idec->io_ is only really needed at the beginning + // of the decoding, till partition #0 is complete. + idec->io_.data = new_base; + idec->io_.data_size = MemDataSize(mem); + + if (idec->dec_ != NULL) { + if (!idec->is_lossless_) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + const int last_part = dec->num_parts_ - 1; + if (offset != 0) { + int p; + for (p = 0; p <= last_part; ++p) { + RemapBitReader(dec->parts_ + p, offset); + } + // Remap partition #0 data pointer to new offset, but only in MAP + // mode (in APPEND mode, partition #0 is copied into a fixed memory). + if (mem->mode_ == MEM_MODE_MAP) { + RemapBitReader(&dec->br_, offset); + } + } + assert(last_part >= 0); + dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; + } else { // Resize lossless bitreader + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); + } + } +} + +// Appends data to the end of MemBuffer->buf_. It expands the allocated memory +// size if required and also updates VP8BitReader's if new memory is allocated. +static int AppendToMemBuffer(WebPIDecoder* const idec, + const uint8_t* const data, size_t data_size) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* const old_base = mem->buf_ + mem->start_; + assert(mem->mode_ == MEM_MODE_APPEND); + if (data_size > MAX_CHUNK_PAYLOAD) { + // security safeguard: trying to allocate more than what the format + // allows for a chunk should be considered a smoke smell. + return 0; + } + + if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory + const size_t current_size = MemDataSize(mem); + const uint64_t new_size = (uint64_t)current_size + data_size; + const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1); + uint8_t* const new_buf = + (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); + if (new_buf == NULL) return 0; + memcpy(new_buf, old_base, current_size); + free(mem->buf_); + mem->buf_ = new_buf; + mem->buf_size_ = (size_t)extra_size; + mem->start_ = 0; + mem->end_ = current_size; + } + + memcpy(mem->buf_ + mem->end_, data, data_size); + mem->end_ += data_size; + assert(mem->end_ <= mem->buf_size_); + + DoRemap(idec, mem->buf_ + mem->start_ - old_base); + return 1; +} + +static int RemapMemBuffer(WebPIDecoder* const idec, + const uint8_t* const data, size_t data_size) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* const old_base = mem->buf_ + mem->start_; + assert(mem->mode_ == MEM_MODE_MAP); + + if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + + mem->buf_ = (uint8_t*)data; + mem->end_ = mem->buf_size_ = data_size; + + DoRemap(idec, mem->buf_ + mem->start_ - old_base); + return 1; +} + +static void InitMemBuffer(MemBuffer* const mem) { + mem->mode_ = MEM_MODE_NONE; + mem->buf_ = NULL; + mem->buf_size_ = 0; + mem->part0_buf_ = NULL; + mem->part0_size_ = 0; +} + +static void ClearMemBuffer(MemBuffer* const mem) { + assert(mem); + if (mem->mode_ == MEM_MODE_APPEND) { + free(mem->buf_); + free((void*)mem->part0_buf_); + } +} + +static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { + if (mem->mode_ == MEM_MODE_NONE) { + mem->mode_ = expected; // switch to the expected mode + } else if (mem->mode_ != expected) { + return 0; // we mixed the modes => error + } + assert(mem->mode_ == expected); // mode is ok + return 1; +} + +//------------------------------------------------------------------------------ +// Macroblock-decoding contexts + +static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, + MBContext* const context) { + const VP8BitReader* const br = &dec->br_; + const VP8MB* const left = dec->mb_info_ - 1; + const VP8MB* const info = dec->mb_info_ + dec->mb_x_; + + context->left_ = *left; + context->info_ = *info; + context->br_ = *br; + context->token_br_ = *token_br; + memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4); + memcpy(context->intra_l_, dec->intra_l_, 4); +} + +static void RestoreContext(const MBContext* context, VP8Decoder* const dec, + VP8BitReader* const token_br) { + VP8BitReader* const br = &dec->br_; + VP8MB* const left = dec->mb_info_ - 1; + VP8MB* const info = dec->mb_info_ + dec->mb_x_; + + *left = context->left_; + *info = context->info_; + *br = context->br_; + *token_br = context->token_br_; + memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4); + memcpy(dec->intra_l_, context->intra_l_, 4); +} + +//------------------------------------------------------------------------------ + +static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { + if (idec->state_ == STATE_VP8_DATA) { + VP8Io* const io = &idec->io_; + if (io->teardown) { + io->teardown(io); + } + } + idec->state_ = STATE_ERROR; + return error; +} + +static void ChangeState(WebPIDecoder* const idec, DecState new_state, + size_t consumed_bytes) { + MemBuffer* const mem = &idec->mem_; + idec->state_ = new_state; + mem->start_ += consumed_bytes; + assert(mem->start_ <= mem->end_); + idec->io_.data = mem->buf_ + mem->start_; + idec->io_.data_size = MemDataSize(mem); +} + +// Headers +static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { + MemBuffer* const mem = &idec->mem_; + const uint8_t* data = mem->buf_ + mem->start_; + size_t curr_size = MemDataSize(mem); + VP8StatusCode status; + WebPHeaderStructure headers; + + headers.data = data; + headers.data_size = curr_size; + status = WebPParseHeaders(&headers); + if (status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet. + } else if (status != VP8_STATUS_OK) { + return IDecError(idec, status); + } + + idec->chunk_size_ = headers.compressed_size; + idec->is_lossless_ = headers.is_lossless; + if (!idec->is_lossless_) { + VP8Decoder* const dec = VP8New(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + idec->dec_ = dec; +#ifdef WEBP_USE_THREAD + dec->use_threads_ = (idec->params_.options != NULL) && + (idec->params_.options->use_threads > 0); +#else + dec->use_threads_ = 0; +#endif + dec->alpha_data_ = headers.alpha_data; + dec->alpha_data_size_ = headers.alpha_data_size; + ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset); + } else { + VP8LDecoder* const dec = VP8LNew(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + idec->dec_ = dec; + ChangeState(idec, STATE_VP8L_HEADER, headers.offset); + } + return VP8_STATUS_OK; +} + +static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { + const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; + const size_t curr_size = MemDataSize(&idec->mem_); + uint32_t bits; + + if (curr_size < VP8_FRAME_HEADER_SIZE) { + // Not enough data bytes to extract VP8 Frame Header. + return VP8_STATUS_SUSPENDED; + } + if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + + bits = data[0] | (data[1] << 8) | (data[2] << 16); + idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; + + idec->io_.data = data; + idec->io_.data_size = curr_size; + idec->state_ = STATE_VP8_PARTS0; + return VP8_STATUS_OK; +} + +// Partition #0 +static int CopyParts0Data(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8BitReader* const br = &dec->br_; + const size_t psize = br->buf_end_ - br->buf_; + MemBuffer* const mem = &idec->mem_; + assert(!idec->is_lossless_); + assert(mem->part0_buf_ == NULL); + assert(psize > 0); + assert(psize <= mem->part0_size_); // Format limit: no need for runtime check + if (mem->mode_ == MEM_MODE_APPEND) { + // We copy and grab ownership of the partition #0 data. + uint8_t* const part0_buf = (uint8_t*)malloc(psize); + if (part0_buf == NULL) { + return 0; + } + memcpy(part0_buf, br->buf_, psize); + mem->part0_buf_ = part0_buf; + br->buf_ = part0_buf; + br->buf_end_ = part0_buf + psize; + } else { + // Else: just keep pointers to the partition #0's data in dec_->br_. + } + mem->start_ += psize; + return 1; +} + +static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8Io* const io = &idec->io_; + const WebPDecParams* const params = &idec->params_; + WebPDecBuffer* const output = params->output; + + // Wait till we have enough data for the whole partition #0 + if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) { + return VP8_STATUS_SUSPENDED; + } + + if (!VP8GetHeaders(dec, io)) { + const VP8StatusCode status = dec->status_; + if (status == VP8_STATUS_SUSPENDED || + status == VP8_STATUS_NOT_ENOUGH_DATA) { + // treating NOT_ENOUGH_DATA as SUSPENDED state + return VP8_STATUS_SUSPENDED; + } + return IDecError(idec, status); + } + + // Allocate/Verify output buffer now + dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + if (!CopyParts0Data(idec)) { + return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY); + } + + // Finish setting up the decoding parameters. Will call io->setup(). + if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + // Note: past this point, teardown() must always be called + // in case of error. + idec->state_ = STATE_VP8_DATA; + // Allocate memory and prepare everything. + if (!VP8InitFrame(dec, io)) { + return IDecError(idec, dec->status_); + } + return VP8_STATUS_OK; +} + +// Remaining partitions +static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + VP8Io* const io = &idec->io_; + + assert(dec->ready_); + + for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { + VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; + if (dec->mb_x_ == 0) { + VP8InitScanline(dec); + } + for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) { + MBContext context; + SaveContext(dec, token_br, &context); + + if (!VP8DecodeMB(dec, token_br)) { + RestoreContext(&context, dec, token_br); + // We shouldn't fail when MAX_MB data was available + if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + return VP8_STATUS_SUSPENDED; + } + VP8ReconstructBlock(dec); + // Store data and save block's filtering params + VP8StoreBlock(dec); + + // Release buffer only if there is only one partition + if (dec->num_parts_ == 1) { + idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; + assert(idec->mem_.start_ <= idec->mem_.end_); + } + } + if (!VP8ProcessRow(dec, io)) { + return IDecError(idec, VP8_STATUS_USER_ABORT); + } + dec->mb_x_ = 0; + } + // Synchronize the thread and check for errors. + if (!VP8ExitCritical(dec, io)) { + return IDecError(idec, VP8_STATUS_USER_ABORT); + } + dec->ready_ = 0; + idec->state_ = STATE_DONE; + + return VP8_STATUS_OK; +} + +static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) { + if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_SUSPENDED; + } + return IDecError(idec, status); +} + +static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { + VP8Io* const io = &idec->io_; + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + const WebPDecParams* const params = &idec->params_; + WebPDecBuffer* const output = params->output; + size_t curr_size = MemDataSize(&idec->mem_); + assert(idec->is_lossless_); + + // Wait until there's enough data for decoding header. + if (curr_size < (idec->chunk_size_ >> 3)) { + return VP8_STATUS_SUSPENDED; + } + if (!VP8LDecodeHeader(dec, io)) { + return ErrorStatusLossless(idec, dec->status_); + } + // Allocate/verify output buffer now. + dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status_ != VP8_STATUS_OK) { + return IDecError(idec, dec->status_); + } + + idec->state_ = STATE_VP8L_DATA; + return VP8_STATUS_OK; +} + +static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; + const size_t curr_size = MemDataSize(&idec->mem_); + assert(idec->is_lossless_); + + // At present Lossless decoder can't decode image incrementally. So wait till + // all the image data is aggregated before image can be decoded. + if (curr_size < idec->chunk_size_) { + return VP8_STATUS_SUSPENDED; + } + + if (!VP8LDecodeImage(dec)) { + return ErrorStatusLossless(idec, dec->status_); + } + + idec->state_ = STATE_DONE; + + return VP8_STATUS_OK; +} + + // Main decoding loop +static VP8StatusCode IDecode(WebPIDecoder* idec) { + VP8StatusCode status = VP8_STATUS_SUSPENDED; + + if (idec->state_ == STATE_PRE_VP8) { + status = DecodeWebPHeaders(idec); + } else { + if (idec->dec_ == NULL) { + return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. + } + } + if (idec->state_ == STATE_VP8_FRAME_HEADER) { + status = DecodeVP8FrameHeader(idec); + } + if (idec->state_ == STATE_VP8_PARTS0) { + status = DecodePartition0(idec); + } + if (idec->state_ == STATE_VP8_DATA) { + status = DecodeRemaining(idec); + } + if (idec->state_ == STATE_VP8L_HEADER) { + status = DecodeVP8LHeader(idec); + } + if (idec->state_ == STATE_VP8L_DATA) { + status = DecodeVP8LData(idec); + } + return status; +} + +//------------------------------------------------------------------------------ +// Public functions + +WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { + WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec)); + if (idec == NULL) { + return NULL; + } + + idec->state_ = STATE_PRE_VP8; + idec->chunk_size_ = 0; + + InitMemBuffer(&idec->mem_); + WebPInitDecBuffer(&idec->output_); + VP8InitIo(&idec->io_); + + WebPResetDecParams(&idec->params_); + idec->params_.output = output_buffer ? output_buffer : &idec->output_; + WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. + + return idec; +} + +WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config) { + WebPIDecoder* idec; + + // Parse the bitstream's features, if requested: + if (data != NULL && data_size > 0 && config != NULL) { + if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) { + return NULL; + } + } + // Create an instance of the incremental decoder + idec = WebPINewDecoder(config ? &config->output : NULL); + if (idec == NULL) { + return NULL; + } + // Finish initialization + if (config != NULL) { + idec->params_.options = &config->options; + } + return idec; +} + +void WebPIDelete(WebPIDecoder* idec) { + if (idec == NULL) return; + if (idec->dec_ != NULL) { + if (!idec->is_lossless_) { + VP8Delete(idec->dec_); + } else { + VP8LDelete(idec->dec_); + } + } + ClearMemBuffer(&idec->mem_); + WebPFreeDecBuffer(&idec->output_); + free(idec); +} + +//------------------------------------------------------------------------------ +// Wrapper toward WebPINewDecoder + +WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer, + size_t output_buffer_size, int output_stride) { + WebPIDecoder* idec; + if (mode >= MODE_YUV) return NULL; + idec = WebPINewDecoder(NULL); + if (idec == NULL) return NULL; + idec->output_.colorspace = mode; + idec->output_.is_external_memory = 1; + idec->output_.u.RGBA.rgba = output_buffer; + idec->output_.u.RGBA.stride = output_stride; + idec->output_.u.RGBA.size = output_buffer_size; + return idec; +} + +WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride, + uint8_t* a, size_t a_size, int a_stride) { + WebPIDecoder* const idec = WebPINewDecoder(NULL); + if (idec == NULL) return NULL; + idec->output_.colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA; + idec->output_.is_external_memory = 1; + idec->output_.u.YUVA.y = luma; + idec->output_.u.YUVA.y_stride = luma_stride; + idec->output_.u.YUVA.y_size = luma_size; + idec->output_.u.YUVA.u = u; + idec->output_.u.YUVA.u_stride = u_stride; + idec->output_.u.YUVA.u_size = u_size; + idec->output_.u.YUVA.v = v; + idec->output_.u.YUVA.v_stride = v_stride; + idec->output_.u.YUVA.v_size = v_size; + idec->output_.u.YUVA.a = a; + idec->output_.u.YUVA.a_stride = a_stride; + idec->output_.u.YUVA.a_size = a_size; + return idec; +} + +WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride) { + return WebPINewYUVA(luma, luma_size, luma_stride, + u, u_size, u_stride, + v, v_size, v_stride, + NULL, 0, 0); +} + +//------------------------------------------------------------------------------ + +static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) { + assert(idec); + if (idec->state_ == STATE_ERROR) { + return VP8_STATUS_BITSTREAM_ERROR; + } + if (idec->state_ == STATE_DONE) { + return VP8_STATUS_OK; + } + return VP8_STATUS_SUSPENDED; +} + +VP8StatusCode WebPIAppend(WebPIDecoder* idec, + const uint8_t* data, size_t data_size) { + VP8StatusCode status; + if (idec == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + status = IDecCheckStatus(idec); + if (status != VP8_STATUS_SUSPENDED) { + return status; + } + // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. + if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) { + return VP8_STATUS_INVALID_PARAM; + } + // Append data to memory buffer + if (!AppendToMemBuffer(idec, data, data_size)) { + return VP8_STATUS_OUT_OF_MEMORY; + } + return IDecode(idec); +} + +VP8StatusCode WebPIUpdate(WebPIDecoder* idec, + const uint8_t* data, size_t data_size) { + VP8StatusCode status; + if (idec == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + status = IDecCheckStatus(idec); + if (status != VP8_STATUS_SUSPENDED) { + return status; + } + // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. + if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) { + return VP8_STATUS_INVALID_PARAM; + } + // Make the memory buffer point to the new buffer + if (!RemapMemBuffer(idec, data, data_size)) { + return VP8_STATUS_INVALID_PARAM; + } + return IDecode(idec); +} + +//------------------------------------------------------------------------------ + +static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { + if (idec == NULL || idec->dec_ == NULL) { + return NULL; + } + if (idec->state_ <= STATE_VP8_PARTS0) { + return NULL; + } + return idec->params_.output; +} + +const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, + int* left, int* top, + int* width, int* height) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (left != NULL) *left = 0; + if (top != NULL) *top = 0; + // TODO(skal): later include handling of rotations. + if (src) { + if (width != NULL) *width = src->width; + if (height != NULL) *height = idec->params_.last_y; + } else { + if (width != NULL) *width = 0; + if (height != NULL) *height = 0; + } + return src; +} + +uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, + int* width, int* height, int* stride) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (src == NULL) return NULL; + if (src->colorspace >= MODE_YUV) { + return NULL; + } + + if (last_y != NULL) *last_y = idec->params_.last_y; + if (width != NULL) *width = src->width; + if (height != NULL) *height = src->height; + if (stride != NULL) *stride = src->u.RGBA.stride; + + return src->u.RGBA.rgba; +} + +uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y, + uint8_t** u, uint8_t** v, uint8_t** a, + int* width, int* height, + int* stride, int* uv_stride, int* a_stride) { + const WebPDecBuffer* const src = GetOutputBuffer(idec); + if (src == NULL) return NULL; + if (src->colorspace < MODE_YUV) { + return NULL; + } + + if (last_y != NULL) *last_y = idec->params_.last_y; + if (u != NULL) *u = src->u.YUVA.u; + if (v != NULL) *v = src->u.YUVA.v; + if (a != NULL) *a = src->u.YUVA.a; + if (width != NULL) *width = src->width; + if (height != NULL) *height = src->height; + if (stride != NULL) *stride = src->u.YUVA.y_stride; + if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride; + if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride; + + return src->u.YUVA.y; +} + +int WebPISetIOHooks(WebPIDecoder* const idec, + VP8IoPutHook put, + VP8IoSetupHook setup, + VP8IoTeardownHook teardown, + void* user_data) { + if (idec == NULL || idec->state_ > STATE_PRE_VP8) { + return 0; + } + + idec->io_.put = put; + idec->io_.setup = setup; + idec->io_.teardown = teardown; + idec->io_.opaque = user_data; + + return 1; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/io.c b/external/libwebp/dec/io.c new file mode 100644 index 0000000000..594804c2e6 --- /dev/null +++ b/external/libwebp/dec/io.c @@ -0,0 +1,633 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// functions for sample output. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include "../dec/vp8i.h" +#include "./webpi.h" +#include "../dsp/dsp.h" +#include "../dsp/yuv.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Main YUV<->RGB conversion functions + +static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { + WebPDecBuffer* output = p->output; + const WebPYUVABuffer* const buf = &output->u.YUVA; + uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride; + uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride; + uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + const int uv_w = (mb_w + 1) / 2; + const int uv_h = (mb_h + 1) / 2; + int j; + for (j = 0; j < mb_h; ++j) { + memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w); + } + for (j = 0; j < uv_h; ++j) { + memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w); + memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w); + } + return io->mb_h; +} + +// Point-sampling U/V sampler. +static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { + WebPDecBuffer* output = p->output; + const WebPRGBABuffer* const buf = &output->u.RGBA; + uint8_t* dst = buf->rgba + io->mb_y * buf->stride; + const uint8_t* y_src = io->y; + const uint8_t* u_src = io->u; + const uint8_t* v_src = io->v; + const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace]; + const int mb_w = io->mb_w; + const int last = io->mb_h - 1; + int j; + for (j = 0; j < last; j += 2) { + sample(y_src, y_src + io->y_stride, u_src, v_src, + dst, dst + buf->stride, mb_w); + y_src += 2 * io->y_stride; + u_src += io->uv_stride; + v_src += io->uv_stride; + dst += 2 * buf->stride; + } + if (j == last) { // Just do the last line twice + sample(y_src, y_src, u_src, v_src, dst, dst, mb_w); + } + return io->mb_h; +} + +//------------------------------------------------------------------------------ +// YUV444 -> RGB conversion + +#if 0 // TODO(skal): this is for future rescaling. +static int EmitRGB(const VP8Io* const io, WebPDecParams* const p) { + WebPDecBuffer* output = p->output; + const WebPRGBABuffer* const buf = &output->u.RGBA; + uint8_t* dst = buf->rgba + io->mb_y * buf->stride; + const uint8_t* y_src = io->y; + const uint8_t* u_src = io->u; + const uint8_t* v_src = io->v; + const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace]; + const int mb_w = io->mb_w; + const int last = io->mb_h; + int j; + for (j = 0; j < last; ++j) { + convert(y_src, u_src, v_src, dst, mb_w); + y_src += io->y_stride; + u_src += io->uv_stride; + v_src += io->uv_stride; + dst += buf->stride; + } + return io->mb_h; +} +#endif + +//------------------------------------------------------------------------------ +// Fancy upsampling + +#ifdef FANCY_UPSAMPLING +static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { + int num_lines_out = io->mb_h; // a priori guess + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* dst = buf->rgba + io->mb_y * buf->stride; + WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; + const uint8_t* cur_y = io->y; + const uint8_t* cur_u = io->u; + const uint8_t* cur_v = io->v; + const uint8_t* top_u = p->tmp_u; + const uint8_t* top_v = p->tmp_v; + int y = io->mb_y; + const int y_end = io->mb_y + io->mb_h; + const int mb_w = io->mb_w; + const int uv_w = (mb_w + 1) / 2; + + if (y == 0) { + // First line is special cased. We mirror the u/v samples at boundary. + upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w); + } else { + // We can finish the left-over line from previous call. + upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v, + dst - buf->stride, dst, mb_w); + ++num_lines_out; + } + // Loop over each output pairs of row. + for (; y + 2 < y_end; y += 2) { + top_u = cur_u; + top_v = cur_v; + cur_u += io->uv_stride; + cur_v += io->uv_stride; + dst += 2 * buf->stride; + cur_y += 2 * io->y_stride; + upsample(cur_y - io->y_stride, cur_y, + top_u, top_v, cur_u, cur_v, + dst - buf->stride, dst, mb_w); + } + // move to last row + cur_y += io->y_stride; + if (io->crop_top + y_end < io->crop_bottom) { + // Save the unfinished samples for next call (as we're not done yet). + memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y)); + memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u)); + memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v)); + // The fancy upsampler leaves a row unfinished behind + // (except for the very last row) + num_lines_out--; + } else { + // Process the very last row of even-sized picture + if (!(y_end & 1)) { + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, + dst + buf->stride, NULL, mb_w); + } + } + return num_lines_out; +} + +#endif /* FANCY_UPSAMPLING */ + +//------------------------------------------------------------------------------ + +static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { + const uint8_t* alpha = io->a; + const WebPYUVABuffer* const buf = &p->output->u.YUVA; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + uint8_t* dst = buf->a + io->mb_y * buf->a_stride; + int j; + + if (alpha != NULL) { + for (j = 0; j < mb_h; ++j) { + memcpy(dst, alpha, mb_w * sizeof(*dst)); + alpha += io->width; + dst += buf->a_stride; + } + } else if (buf->a != NULL) { + // the user requested alpha, but there is none, set it to opaque. + for (j = 0; j < mb_h; ++j) { + memset(dst, 0xff, mb_w * sizeof(*dst)); + dst += buf->a_stride; + } + } + return 0; +} + +static int GetAlphaSourceRow(const VP8Io* const io, + const uint8_t** alpha, int* const num_rows) { + int start_y = io->mb_y; + *num_rows = io->mb_h; + + // Compensate for the 1-line delay of the fancy upscaler. + // This is similar to EmitFancyRGB(). + if (io->fancy_upsampling) { + if (start_y == 0) { + // We don't process the last row yet. It'll be done during the next call. + --*num_rows; + } else { + --start_y; + // Fortunately, *alpha data is persistent, so we can go back + // one row and finish alpha blending, now that the fancy upscaler + // completed the YUV->RGB interpolation. + *alpha -= io->width; + } + if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) { + // If it's the very last call, we process all the remaining rows! + *num_rows = io->crop_bottom - io->crop_top - start_y; + } + } + return start_y; +} + +static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { + const uint8_t* alpha = io->a; + if (alpha != NULL) { + const int mb_w = io->mb_w; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int alpha_first = + (colorspace == MODE_ARGB || colorspace == MODE_Argb); + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + int num_rows; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); + uint32_t alpha_mask = 0xff; + int i, j; + + for (j = 0; j < num_rows; ++j) { + for (i = 0; i < mb_w; ++i) { + const uint32_t alpha_value = alpha[i]; + dst[4 * i] = alpha_value; + alpha_mask &= alpha_value; + } + alpha += io->width; + dst += buf->stride; + } + // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with. + if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) { + WebPApplyAlphaMultiply(base_rgba, alpha_first, + mb_w, num_rows, buf->stride); + } + } + return 0; +} + +static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) { + const uint8_t* alpha = io->a; + if (alpha != NULL) { + const int mb_w = io->mb_w; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + int num_rows; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + uint8_t* alpha_dst = base_rgba + 1; + uint32_t alpha_mask = 0x0f; + int i, j; + + for (j = 0; j < num_rows; ++j) { + for (i = 0; i < mb_w; ++i) { + // Fill in the alpha value (converted to 4 bits). + const uint32_t alpha_value = alpha[i] >> 4; + alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; + alpha_mask &= alpha_value; + } + alpha += io->width; + alpha_dst += buf->stride; + } + if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) { + WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride); + } + } + return 0; +} + +//------------------------------------------------------------------------------ +// YUV rescaling (no final RGB conversion needed) + +static int Rescale(const uint8_t* src, int src_stride, + int new_lines, WebPRescaler* const wrk) { + int num_lines_out = 0; + while (new_lines > 0) { // import new contributions of source rows. + const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride); + src += lines_in * src_stride; + new_lines -= lines_in; + num_lines_out += WebPRescalerExport(wrk); // emit output row(s) + } + return num_lines_out; +} + +static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { + const int mb_h = io->mb_h; + const int uv_mb_h = (mb_h + 1) >> 1; + const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y); + Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u); + Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v); + return num_lines_out; +} + +static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) { + if (io->a != NULL) { + Rescale(io->a, io->width, io->mb_h, &p->scaler_a); + } + return 0; +} + +static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) { + const int has_alpha = WebPIsAlphaMode(p->output->colorspace); + const WebPYUVABuffer* const buf = &p->output->u.YUVA; + const int out_width = io->scaled_width; + const int out_height = io->scaled_height; + const int uv_out_width = (out_width + 1) >> 1; + const int uv_out_height = (out_height + 1) >> 1; + const int uv_in_width = (io->mb_w + 1) >> 1; + const int uv_in_height = (io->mb_h + 1) >> 1; + const size_t work_size = 2 * out_width; // scratch memory for luma rescaler + const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones + size_t tmp_size; + int32_t* work; + + tmp_size = work_size + 2 * uv_work_size; + if (has_alpha) { + tmp_size += work_size; + } + p->memory = calloc(1, tmp_size * sizeof(*work)); + if (p->memory == NULL) { + return 0; // memory error + } + work = (int32_t*)p->memory; + WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, + buf->y, out_width, out_height, buf->y_stride, 1, + io->mb_w, out_width, io->mb_h, out_height, + work); + WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, + buf->u, uv_out_width, uv_out_height, buf->u_stride, 1, + uv_in_width, uv_out_width, + uv_in_height, uv_out_height, + work + work_size); + WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, + buf->v, uv_out_width, uv_out_height, buf->v_stride, 1, + uv_in_width, uv_out_width, + uv_in_height, uv_out_height, + work + work_size + uv_work_size); + p->emit = EmitRescaledYUV; + + if (has_alpha) { + WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, + buf->a, out_width, out_height, buf->a_stride, 1, + io->mb_w, out_width, io->mb_h, out_height, + work + work_size + 2 * uv_work_size); + p->emit_alpha = EmitRescaledAlphaYUV; + } + return 1; +} + +//------------------------------------------------------------------------------ +// RGBA rescaling + +static int ExportRGB(WebPDecParams* const p, int y_pos) { + const WebPYUV444Converter convert = + WebPYUV444Converters[p->output->colorspace]; + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride; + int num_lines_out = 0; + // For RGB rescaling, because of the YUV420, current scan position + // U/V can be +1/-1 line from the Y one. Hence the double test. + while (WebPRescalerHasPendingOutput(&p->scaler_y) && + WebPRescalerHasPendingOutput(&p->scaler_u)) { + assert(p->last_y + y_pos + num_lines_out < p->output->height); + assert(p->scaler_u.y_accum == p->scaler_v.y_accum); + WebPRescalerExportRow(&p->scaler_y); + WebPRescalerExportRow(&p->scaler_u); + WebPRescalerExportRow(&p->scaler_v); + convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst, + dst, p->scaler_y.dst_width); + dst += buf->stride; + ++num_lines_out; + } + return num_lines_out; +} + +static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { + const int mb_h = io->mb_h; + const int uv_mb_h = (mb_h + 1) >> 1; + int j = 0, uv_j = 0; + int num_lines_out = 0; + while (j < mb_h) { + const int y_lines_in = + WebPRescalerImport(&p->scaler_y, mb_h - j, + io->y + j * io->y_stride, io->y_stride); + const int u_lines_in = + WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j, + io->u + uv_j * io->uv_stride, io->uv_stride); + const int v_lines_in = + WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j, + io->v + uv_j * io->uv_stride, io->uv_stride); + (void)v_lines_in; // remove a gcc warning + assert(u_lines_in == v_lines_in); + j += y_lines_in; + uv_j += u_lines_in; + num_lines_out += ExportRGB(p, num_lines_out); + } + return num_lines_out; +} + +static int ExportAlpha(WebPDecParams* const p, int y_pos) { + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int alpha_first = + (colorspace == MODE_ARGB || colorspace == MODE_Argb); + uint8_t* dst = base_rgba + (alpha_first ? 0 : 3); + int num_lines_out = 0; + const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); + uint32_t alpha_mask = 0xff; + const int width = p->scaler_a.dst_width; + + while (WebPRescalerHasPendingOutput(&p->scaler_a)) { + int i; + assert(p->last_y + y_pos + num_lines_out < p->output->height); + WebPRescalerExportRow(&p->scaler_a); + for (i = 0; i < width; ++i) { + const uint32_t alpha_value = p->scaler_a.dst[i]; + dst[4 * i] = alpha_value; + alpha_mask &= alpha_value; + } + dst += buf->stride; + ++num_lines_out; + } + if (is_premult_alpha && alpha_mask != 0xff) { + WebPApplyAlphaMultiply(base_rgba, alpha_first, + width, num_lines_out, buf->stride); + } + return num_lines_out; +} + +static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) { + const WebPRGBABuffer* const buf = &p->output->u.RGBA; + uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride; + uint8_t* alpha_dst = base_rgba + 1; + int num_lines_out = 0; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int width = p->scaler_a.dst_width; + const int is_premult_alpha = WebPIsPremultipliedMode(colorspace); + uint32_t alpha_mask = 0x0f; + + while (WebPRescalerHasPendingOutput(&p->scaler_a)) { + int i; + assert(p->last_y + y_pos + num_lines_out < p->output->height); + WebPRescalerExportRow(&p->scaler_a); + for (i = 0; i < width; ++i) { + // Fill in the alpha value (converted to 4 bits). + const uint32_t alpha_value = p->scaler_a.dst[i] >> 4; + alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value; + alpha_mask &= alpha_value; + } + alpha_dst += buf->stride; + ++num_lines_out; + } + if (is_premult_alpha && alpha_mask != 0x0f) { + WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride); + } + return num_lines_out; +} + +static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) { + if (io->a != NULL) { + WebPRescaler* const scaler = &p->scaler_a; + int j = 0; + int pos = 0; + while (j < io->mb_h) { + j += WebPRescalerImport(scaler, io->mb_h - j, + io->a + j * io->width, io->width); + pos += p->emit_alpha_row(p, pos); + } + } + return 0; +} + +static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) { + const int has_alpha = WebPIsAlphaMode(p->output->colorspace); + const int out_width = io->scaled_width; + const int out_height = io->scaled_height; + const int uv_in_width = (io->mb_w + 1) >> 1; + const int uv_in_height = (io->mb_h + 1) >> 1; + const size_t work_size = 2 * out_width; // scratch memory for one rescaler + int32_t* work; // rescalers work area + uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion + size_t tmp_size1, tmp_size2; + + tmp_size1 = 3 * work_size; + tmp_size2 = 3 * out_width; + if (has_alpha) { + tmp_size1 += work_size; + tmp_size2 += out_width; + } + p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp)); + if (p->memory == NULL) { + return 0; // memory error + } + work = (int32_t*)p->memory; + tmp = (uint8_t*)(work + tmp_size1); + WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h, + tmp + 0 * out_width, out_width, out_height, 0, 1, + io->mb_w, out_width, io->mb_h, out_height, + work + 0 * work_size); + WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height, + tmp + 1 * out_width, out_width, out_height, 0, 1, + io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, + work + 1 * work_size); + WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height, + tmp + 2 * out_width, out_width, out_height, 0, 1, + io->mb_w, 2 * out_width, io->mb_h, 2 * out_height, + work + 2 * work_size); + p->emit = EmitRescaledRGB; + + if (has_alpha) { + WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h, + tmp + 3 * out_width, out_width, out_height, 0, 1, + io->mb_w, out_width, io->mb_h, out_height, + work + 3 * work_size); + p->emit_alpha = EmitRescaledAlphaRGB; + if (p->output->colorspace == MODE_RGBA_4444 || + p->output->colorspace == MODE_rgbA_4444) { + p->emit_alpha_row = ExportAlphaRGBA4444; + } else { + p->emit_alpha_row = ExportAlpha; + } + } + return 1; +} + +//------------------------------------------------------------------------------ +// Default custom functions + +static int CustomSetup(VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + const WEBP_CSP_MODE colorspace = p->output->colorspace; + const int is_rgb = WebPIsRGBMode(colorspace); + const int is_alpha = WebPIsAlphaMode(colorspace); + + p->memory = NULL; + p->emit = NULL; + p->emit_alpha = NULL; + p->emit_alpha_row = NULL; + if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) { + return 0; + } + + if (io->use_scaling) { + const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p); + if (!ok) { + return 0; // memory error + } + } else { + if (is_rgb) { + p->emit = EmitSampledRGB; // default +#ifdef FANCY_UPSAMPLING + if (io->fancy_upsampling) { + const int uv_width = (io->mb_w + 1) >> 1; + p->memory = malloc(io->mb_w + 2 * uv_width); + if (p->memory == NULL) { + return 0; // memory error. + } + p->tmp_y = (uint8_t*)p->memory; + p->tmp_u = p->tmp_y + io->mb_w; + p->tmp_v = p->tmp_u + uv_width; + p->emit = EmitFancyRGB; + WebPInitUpsamplers(); + } +#endif + } else { + p->emit = EmitYUV; + } + if (is_alpha) { // need transparency output + if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply(); + p->emit_alpha = + (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ? + EmitAlphaRGBA4444 + : is_rgb ? EmitAlphaRGB + : EmitAlphaYUV; + } + } + + if (is_rgb) { + VP8YUVInit(); + } + return 1; +} + +//------------------------------------------------------------------------------ + +static int CustomPut(const VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + const int mb_w = io->mb_w; + const int mb_h = io->mb_h; + int num_lines_out; + assert(!(io->mb_y & 1)); + + if (mb_w <= 0 || mb_h <= 0) { + return 0; + } + num_lines_out = p->emit(io, p); + if (p->emit_alpha) { + p->emit_alpha(io, p); + } + p->last_y += num_lines_out; + return 1; +} + +//------------------------------------------------------------------------------ + +static void CustomTeardown(const VP8Io* io) { + WebPDecParams* const p = (WebPDecParams*)io->opaque; + free(p->memory); + p->memory = NULL; +} + +//------------------------------------------------------------------------------ +// Main entry point + +void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) { + io->put = CustomPut; + io->setup = CustomSetup; + io->teardown = CustomTeardown; + io->opaque = params; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/layer.c b/external/libwebp/dec/layer.c new file mode 100644 index 0000000000..a3a5bdcfe8 --- /dev/null +++ b/external/libwebp/dec/layer.c @@ -0,0 +1,35 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Enhancement layer (for YUV444/422) +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include + +#include "./vp8i.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ + +int VP8DecodeLayer(VP8Decoder* const dec) { + assert(dec); + assert(dec->layer_data_size_ > 0); + (void)dec; + + // TODO: handle enhancement layer here. + + return 1; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/quant.c b/external/libwebp/dec/quant.c new file mode 100644 index 0000000000..d54097af0d --- /dev/null +++ b/external/libwebp/dec/quant.c @@ -0,0 +1,113 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Quantizer initialization +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./vp8i.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static WEBP_INLINE int clip(int v, int M) { + return v < 0 ? 0 : v > M ? M : v; +} + +// Paragraph 14.1 +static const uint8_t kDcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, + 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, + 138, 140, 143, 145, 148, 151, 154, 157 +}; + +static const uint16_t kAcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, + 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, + 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, + 249, 254, 259, 264, 269, 274, 279, 284 +}; + +//------------------------------------------------------------------------------ +// Paragraph 9.6 + +void VP8ParseQuant(VP8Decoder* const dec) { + VP8BitReader* const br = &dec->br_; + const int base_q0 = VP8GetValue(br, 7); + const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; + const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; + const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; + const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; + const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0; + + const VP8SegmentHeader* const hdr = &dec->segment_hdr_; + int i; + + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + int q; + if (hdr->use_segment_) { + q = hdr->quantizer_[i]; + if (!hdr->absolute_delta_) { + q += base_q0; + } + } else { + if (i > 0) { + dec->dqm_[i] = dec->dqm_[0]; + continue; + } else { + q = base_q0; + } + } + { + VP8QuantMatrix* const m = &dec->dqm_[i]; + m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)]; + m->y1_mat_[1] = kAcTable[clip(q + 0, 127)]; + + m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; + // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16. + // The smallest precision for that is '(x*6349) >> 12' but 16 is a good + // word size. + m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; + if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8; + + m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)]; + m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)]; + } + } +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/tree.c b/external/libwebp/dec/tree.c new file mode 100644 index 0000000000..82484e4c55 --- /dev/null +++ b/external/libwebp/dec/tree.c @@ -0,0 +1,589 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Coding trees and probas +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "vp8i.h" + +#define USE_GENERIC_TREE + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#ifdef USE_GENERIC_TREE +static const int8_t kYModesIntra4[18] = { + -B_DC_PRED, 1, + -B_TM_PRED, 2, + -B_VE_PRED, 3, + 4, 6, + -B_HE_PRED, 5, + -B_RD_PRED, -B_VR_PRED, + -B_LD_PRED, 7, + -B_VL_PRED, 8, + -B_HD_PRED, -B_HU_PRED +}; +#endif + +#ifndef ONLY_KEYFRAME_CODE + +// inter prediction modes +enum { + LEFT4 = 0, ABOVE4 = 1, ZERO4 = 2, NEW4 = 3, + NEARESTMV, NEARMV, ZEROMV, NEWMV, SPLITMV }; + +static const int8_t kYModesInter[8] = { + -DC_PRED, 1, + 2, 3, + -V_PRED, -H_PRED, + -TM_PRED, -B_PRED +}; + +static const int8_t kMBSplit[6] = { + -3, 1, + -2, 2, + -0, -1 +}; + +static const int8_t kMVRef[8] = { + -ZEROMV, 1, + -NEARESTMV, 2, + -NEARMV, 3, + -NEWMV, -SPLITMV +}; + +static const int8_t kMVRef4[6] = { + -LEFT4, 1, + -ABOVE4, 2, + -ZERO4, -NEW4 +}; +#endif + +//------------------------------------------------------------------------------ +// Default probabilities + +// Inter +#ifndef ONLY_KEYFRAME_CODE +static const uint8_t kYModeProbaInter0[4] = { 112, 86, 140, 37 }; +static const uint8_t kUVModeProbaInter0[3] = { 162, 101, 204 }; +static const uint8_t kMVProba0[2][NUM_MV_PROBAS] = { + { 162, 128, 225, 146, 172, 147, 214, 39, + 156, 128, 129, 132, 75, 145, 178, 206, + 239, 254, 254 }, + { 164, 128, 204, 170, 119, 235, 140, 230, + 228, 128, 130, 130, 74, 148, 180, 203, + 236, 254, 254 } +}; +#endif + +// Paragraph 13.5 +static const uint8_t + CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + // genereated using vp8_default_coef_probs() in entropy.c:129 + { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, + { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, + { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } + }, + { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, + { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, + { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 }, + }, + { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, + { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, + { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 }, + }, + { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, + { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, + { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } + }, + { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, + { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, + { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } + }, + { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, + { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, + { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, + { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, + { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } + }, + { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, + { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, + { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } + }, + { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, + { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, + { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } + }, + { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, + { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, + { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } + }, + { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, + { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, + { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } + }, + { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, + { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, + { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } + }, + { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, + { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, + { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } + }, + { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } + } + }, + { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, + { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, + { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } + }, + { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, + { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, + { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } + }, + { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, + { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, + { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } + }, + { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, + { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, + { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, + { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } + }, + { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, + { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, + { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } + }, + { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, + { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, + { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } + }, + { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, + { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, + { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } + }, + { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, + { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, + { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } + }, + { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, + { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, + { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } + }, + { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, + { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, + { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + } + } +}; + +// Paragraph 11.5 +static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { + { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, + { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, + { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, + { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, + { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, + { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, + { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, + { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, + { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, + { 81, 40, 11, 96, 182, 84, 29, 16, 36 } }, + { { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, + { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, + { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, + { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, + { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, + { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, + { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, + { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, + { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, + { 66, 45, 25, 102, 197, 189, 23, 18, 22 } }, + { { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, + { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, + { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, + { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, + { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, + { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, + { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, + { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, + { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, + { 62, 18, 78, 95, 85, 57, 50, 48, 51 } }, + { { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, + { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, + { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, + { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, + { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, + { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, + { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, + { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, + { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, + { 51, 50, 17, 168, 209, 192, 23, 25, 82 } }, + { { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, + { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, + { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, + { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, + { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, + { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, + { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, + { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, + { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, + { 87, 37, 9, 115, 59, 77, 64, 21, 47 } }, + { { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, + { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, + { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, + { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, + { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, + { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, + { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, + { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, + { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, + { 55, 38, 70, 124, 73, 102, 1, 34, 98 } }, + { { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, + { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, + { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, + { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, + { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, + { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, + { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, + { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, + { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, + { 117, 20, 15, 36, 163, 128, 68, 1, 26 } }, + { { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, + { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, + { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, + { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, + { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, + { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, + { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, + { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, + { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, + { 58, 15, 20, 82, 135, 57, 26, 121, 40 } }, + { { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, + { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, + { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, + { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, + { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, + { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, + { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, + { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, + { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, + { 35, 27, 10, 146, 174, 171, 12, 26, 128 } }, + { { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, + { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, + { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, + { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, + { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, + { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, + { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, + { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, + { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, + { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } +}; + +void VP8ResetProba(VP8Proba* const proba) { + memset(proba->segments_, 255u, sizeof(proba->segments_)); + memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0)); +#ifndef ONLY_KEYFRAME_CODE + memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0)); + memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0)); + memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0)); +#endif +} + +void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) { + uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_; + uint8_t* const left = dec->intra_l_; + // Hardcoded 16x16 intra-mode decision tree. + dec->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first + if (!dec->is_i4x4_) { + const int ymode = + VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED) + : (VP8GetBit(br, 163) ? V_PRED : DC_PRED); + dec->imodes_[0] = ymode; + memset(top, ymode, 4 * sizeof(top[0])); + memset(left, ymode, 4 * sizeof(left[0])); + } else { + uint8_t* modes = dec->imodes_; + int y; + for (y = 0; y < 4; ++y) { + int ymode = left[y]; + int x; + for (x = 0; x < 4; ++x) { + const uint8_t* const prob = kBModesProba[top[x]][ymode]; +#ifdef USE_GENERIC_TREE + // Generic tree-parsing + int i = 0; + do { + i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])]; + } while (i > 0); + ymode = -i; +#else + // Hardcoded tree parsing + ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED : + !VP8GetBit(br, prob[1]) ? B_TM_PRED : + !VP8GetBit(br, prob[2]) ? B_VE_PRED : + !VP8GetBit(br, prob[3]) ? + (!VP8GetBit(br, prob[4]) ? B_HE_PRED : + (!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) : + (!VP8GetBit(br, prob[6]) ? B_LD_PRED : + (!VP8GetBit(br, prob[7]) ? B_VL_PRED : + (!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED))); +#endif // USE_GENERIC_TREE + top[x] = ymode; + *modes++ = ymode; + } + left[y] = ymode; + } + } + // Hardcoded UVMode decision tree + dec->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED + : !VP8GetBit(br, 114) ? V_PRED + : VP8GetBit(br, 183) ? TM_PRED : H_PRED; +} + +//------------------------------------------------------------------------------ +// Paragraph 13 + +static const uint8_t + CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 }, + { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + } +}; + +#ifndef ONLY_KEYFRAME_CODE +static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = { + { 237, 246, 253, 253, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 250, 250, + 252, 254, 254 }, + { 231, 243, 245, 253, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 251, 251, + 254, 254, 254 } +}; +#endif + +// Paragraph 9.9 +void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) { + VP8Proba* const proba = &dec->proba_; + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) { + proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8); + } + } + } + } + } + dec->use_skip_proba_ = VP8Get(br); + if (dec->use_skip_proba_) { + dec->skip_p_ = VP8GetValue(br, 8); + } +#ifndef ONLY_KEYFRAME_CODE + if (!dec->frm_hdr_.key_frame_) { + int i; + dec->intra_p_ = VP8GetValue(br, 8); + dec->last_p_ = VP8GetValue(br, 8); + dec->golden_p_ = VP8GetValue(br, 8); + if (VP8Get(br)) { // update y-mode + for (i = 0; i < 4; ++i) { + proba->ymode_[i] = VP8GetValue(br, 8); + } + } + if (VP8Get(br)) { // update uv-mode + for (i = 0; i < 3; ++i) { + proba->uvmode_[i] = VP8GetValue(br, 8); + } + } + // update MV + for (i = 0; i < 2; ++i) { + int k; + for (k = 0; k < NUM_MV_PROBAS; ++k) { + if (VP8GetBit(br, MVUpdateProba[i][k])) { + const int v = VP8GetValue(br, 7); + proba->mv_[i][k] = v ? v << 1 : 1; + } + } + } + } +#endif +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/vp8.c b/external/libwebp/dec/vp8.c new file mode 100644 index 0000000000..b0ccfa2a06 --- /dev/null +++ b/external/libwebp/dec/vp8.c @@ -0,0 +1,787 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// main entry for the decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./vp8i.h" +#include "./vp8li.h" +#include "./webpi.h" +#include "../utils/bit_reader.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ + +int WebPGetDecoderVersion(void) { + return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION; +} + +//------------------------------------------------------------------------------ +// VP8Decoder + +static void SetOk(VP8Decoder* const dec) { + dec->status_ = VP8_STATUS_OK; + dec->error_msg_ = "OK"; +} + +int VP8InitIoInternal(VP8Io* const io, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // mismatch error + } + if (io != NULL) { + memset(io, 0, sizeof(*io)); + } + return 1; +} + +VP8Decoder* VP8New(void) { + VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec)); + if (dec != NULL) { + SetOk(dec); + WebPWorkerInit(&dec->worker_); + dec->ready_ = 0; + dec->num_parts_ = 1; + } + return dec; +} + +VP8StatusCode VP8Status(VP8Decoder* const dec) { + if (!dec) return VP8_STATUS_INVALID_PARAM; + return dec->status_; +} + +const char* VP8StatusMessage(VP8Decoder* const dec) { + if (dec == NULL) return "no object"; + if (!dec->error_msg_) return "OK"; + return dec->error_msg_; +} + +void VP8Delete(VP8Decoder* const dec) { + if (dec != NULL) { + VP8Clear(dec); + free(dec); + } +} + +int VP8SetError(VP8Decoder* const dec, + VP8StatusCode error, const char* const msg) { + // TODO This check would be unnecessary if alpha decompression was separated + // from VP8ProcessRow/FinishRow. This avoids setting 'dec->status_' to + // something other than VP8_STATUS_BITSTREAM_ERROR on alpha decompression + // failure. + if (dec->status_ == VP8_STATUS_OK) { + dec->status_ = error; + dec->error_msg_ = msg; + dec->ready_ = 0; + } + return 0; +} + +//------------------------------------------------------------------------------ + +int VP8CheckSignature(const uint8_t* const data, size_t data_size) { + return (data_size >= 3 && + data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a); +} + +int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, + int* const width, int* const height) { + if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) { + return 0; // not enough data + } + // check signature + if (!VP8CheckSignature(data + 3, data_size - 3)) { + return 0; // Wrong signature. + } else { + const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16); + const int key_frame = !(bits & 1); + const int w = ((data[7] << 8) | data[6]) & 0x3fff; + const int h = ((data[9] << 8) | data[8]) & 0x3fff; + + if (!key_frame) { // Not a keyframe. + return 0; + } + + if (((bits >> 1) & 7) > 3) { + return 0; // unknown profile + } + if (!((bits >> 4) & 1)) { + return 0; // first frame is invisible! + } + if (((bits >> 5)) >= chunk_size) { // partition_length + return 0; // inconsistent size information. + } + + if (width) { + *width = w; + } + if (height) { + *height = h; + } + + return 1; + } +} + +//------------------------------------------------------------------------------ +// Header parsing + +static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { + assert(hdr != NULL); + hdr->use_segment_ = 0; + hdr->update_map_ = 0; + hdr->absolute_delta_ = 1; + memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_)); + memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_)); +} + +// Paragraph 9.3 +static int ParseSegmentHeader(VP8BitReader* br, + VP8SegmentHeader* hdr, VP8Proba* proba) { + assert(br != NULL); + assert(hdr != NULL); + hdr->use_segment_ = VP8Get(br); + if (hdr->use_segment_) { + hdr->update_map_ = VP8Get(br); + if (VP8Get(br)) { // update data + int s; + hdr->absolute_delta_ = VP8Get(br); + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0; + } + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0; + } + } + if (hdr->update_map_) { + int s; + for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) { + proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u; + } + } + } else { + hdr->update_map_ = 0; + } + return !br->eof_; +} + +// Paragraph 9.5 +// This function returns VP8_STATUS_SUSPENDED if we don't have all the +// necessary data in 'buf'. +// This case is not necessarily an error (for incremental decoding). +// Still, no bitreader is ever initialized to make it possible to read +// unavailable memory. +// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA +// is returned, and this is an unrecoverable error. +// If the partitions were positioned ok, VP8_STATUS_OK is returned. +static VP8StatusCode ParsePartitions(VP8Decoder* const dec, + const uint8_t* buf, size_t size) { + VP8BitReader* const br = &dec->br_; + const uint8_t* sz = buf; + const uint8_t* buf_end = buf + size; + const uint8_t* part_start; + int last_part; + int p; + + dec->num_parts_ = 1 << VP8GetValue(br, 2); + last_part = dec->num_parts_ - 1; + part_start = buf + last_part * 3; + if (buf_end < part_start) { + // we can't even read the sizes with sz[]! That's a failure. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + for (p = 0; p < last_part; ++p) { + const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16); + const uint8_t* part_end = part_start + psize; + if (part_end > buf_end) part_end = buf_end; + VP8InitBitReader(dec->parts_ + p, part_start, part_end); + part_start = part_end; + sz += 3; + } + VP8InitBitReader(dec->parts_ + last_part, part_start, buf_end); + return (part_start < buf_end) ? VP8_STATUS_OK : + VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data +} + +// Paragraph 9.4 +static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { + VP8FilterHeader* const hdr = &dec->filter_hdr_; + hdr->simple_ = VP8Get(br); + hdr->level_ = VP8GetValue(br, 6); + hdr->sharpness_ = VP8GetValue(br, 3); + hdr->use_lf_delta_ = VP8Get(br); + if (hdr->use_lf_delta_) { + if (VP8Get(br)) { // update lf-delta? + int i; + for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { + if (VP8Get(br)) { + hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6); + } + } + for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { + if (VP8Get(br)) { + hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6); + } + } + } + } + dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2; + if (dec->filter_type_ > 0) { // precompute filter levels per segment + if (dec->segment_hdr_.use_segment_) { + int s; + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + int strength = dec->segment_hdr_.filter_strength_[s]; + if (!dec->segment_hdr_.absolute_delta_) { + strength += hdr->level_; + } + dec->filter_levels_[s] = strength; + } + } else { + dec->filter_levels_[0] = hdr->level_; + } + } + return !br->eof_; +} + +// Topmost call +int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { + const uint8_t* buf; + size_t buf_size; + VP8FrameHeader* frm_hdr; + VP8PictureHeader* pic_hdr; + VP8BitReader* br; + VP8StatusCode status; + WebPHeaderStructure headers; + + if (dec == NULL) { + return 0; + } + SetOk(dec); + if (io == NULL) { + return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, + "null VP8Io passed to VP8GetHeaders()"); + } + + // Process Pre-VP8 chunks. + headers.data = io->data; + headers.data_size = io->data_size; + status = WebPParseHeaders(&headers); + if (status != VP8_STATUS_OK) { + return VP8SetError(dec, status, "Incorrect/incomplete header."); + } + if (headers.is_lossless) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Unexpected lossless format encountered."); + } + + if (dec->alpha_data_ == NULL) { + assert(dec->alpha_data_size_ == 0); + // We have NOT set alpha data yet. Set it now. + // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if + // WebPParseHeaders() is called more than once, as in incremental decoding + // case.) + dec->alpha_data_ = headers.alpha_data; + dec->alpha_data_size_ = headers.alpha_data_size; + } + + // Process the VP8 frame header. + buf = headers.data + headers.offset; + buf_size = headers.data_size - headers.offset; + assert(headers.data_size >= headers.offset); // WebPParseHeaders' guarantee + if (buf_size < 4) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "Truncated header."); + } + + // Paragraph 9.1 + { + const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16); + frm_hdr = &dec->frm_hdr_; + frm_hdr->key_frame_ = !(bits & 1); + frm_hdr->profile_ = (bits >> 1) & 7; + frm_hdr->show_ = (bits >> 4) & 1; + frm_hdr->partition_length_ = (bits >> 5); + if (frm_hdr->profile_ > 3) + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Incorrect keyframe parameters."); + if (!frm_hdr->show_) + return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, + "Frame not displayable."); + buf += 3; + buf_size -= 3; + } + + pic_hdr = &dec->pic_hdr_; + if (frm_hdr->key_frame_) { + // Paragraph 9.2 + if (buf_size < 7) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "cannot parse picture header"); + } + if (!VP8CheckSignature(buf, buf_size)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "Bad code word"); + } + pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; + pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 + pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff; + pic_hdr->yscale_ = buf[6] >> 6; + buf += 7; + buf_size -= 7; + + dec->mb_w_ = (pic_hdr->width_ + 15) >> 4; + dec->mb_h_ = (pic_hdr->height_ + 15) >> 4; + // Setup default output area (can be later modified during io->setup()) + io->width = pic_hdr->width_; + io->height = pic_hdr->height_; + io->use_scaling = 0; + io->use_cropping = 0; + io->crop_top = 0; + io->crop_left = 0; + io->crop_right = io->width; + io->crop_bottom = io->height; + io->mb_w = io->width; // sanity check + io->mb_h = io->height; // ditto + + VP8ResetProba(&dec->proba_); + ResetSegmentHeader(&dec->segment_hdr_); + dec->segment_ = 0; // default for intra + } + + // Check if we have all the partition #0 available, and initialize dec->br_ + // to read this partition (and this partition only). + if (frm_hdr->partition_length_ > buf_size) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "bad partition length"); + } + + br = &dec->br_; + VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_); + buf += frm_hdr->partition_length_; + buf_size -= frm_hdr->partition_length_; + + if (frm_hdr->key_frame_) { + pic_hdr->colorspace_ = VP8Get(br); + pic_hdr->clamp_type_ = VP8Get(br); + } + if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "cannot parse segment header"); + } + // Filter specs + if (!ParseFilterHeader(br, dec)) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "cannot parse filter header"); + } + status = ParsePartitions(dec, buf, buf_size); + if (status != VP8_STATUS_OK) { + return VP8SetError(dec, status, "cannot parse partitions"); + } + + // quantizer change + VP8ParseQuant(dec); + + // Frame buffer marking + if (!frm_hdr->key_frame_) { + // Paragraph 9.7 +#ifndef ONLY_KEYFRAME_CODE + dec->buffer_flags_ = VP8Get(br) << 0; // update golden + dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref + if (!(dec->buffer_flags_ & 1)) { + dec->buffer_flags_ |= VP8GetValue(br, 2) << 2; + } + if (!(dec->buffer_flags_ & 2)) { + dec->buffer_flags_ |= VP8GetValue(br, 2) << 4; + } + dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden + dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref +#else + return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, + "Not a key frame."); +#endif + } else { + dec->buffer_flags_ = 0x003 | 0x100; + } + + // Paragraph 9.8 +#ifndef ONLY_KEYFRAME_CODE + dec->update_proba_ = VP8Get(br); + if (!dec->update_proba_) { // save for later restore + dec->proba_saved_ = dec->proba_; + } + dec->buffer_flags_ &= 1 << 8; + dec->buffer_flags_ |= + (frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame +#else + VP8Get(br); // just ignore the value of update_proba_ +#endif + + VP8ParseProba(br, dec); + +#ifdef WEBP_EXPERIMENTAL_FEATURES + // Extensions + if (dec->pic_hdr_.colorspace_) { + const size_t kTrailerSize = 8; + const uint8_t kTrailerMarker = 0x01; + const uint8_t* ext_buf = buf - kTrailerSize; + size_t size; + + if (frm_hdr->partition_length_ < kTrailerSize || + ext_buf[kTrailerSize - 1] != kTrailerMarker) { + return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, + "RIFF: Inconsistent extra information."); + } + + // Layer + size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16); + dec->layer_data_size_ = size; + dec->layer_data_ = NULL; // will be set later + dec->layer_colorspace_ = ext_buf[3]; + } +#endif + + // sanitized state + dec->ready_ = 1; + return 1; +} + +//------------------------------------------------------------------------------ +// Residual decoding (Paragraph 13.2 / 13.3) + +static const uint8_t kBands[16 + 1] = { + 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 0 // extra entry as sentinel +}; + +static const uint8_t kCat3[] = { 173, 148, 140, 0 }; +static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 }; +static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 }; +static const uint8_t kCat6[] = + { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 }; +static const uint8_t* const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 }; +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting + +// Returns the position of the last non-zero coeff plus one +// (and 0 if there's no coeff at all) +static int GetCoeffs(VP8BitReader* const br, ProbaArray prob, + int ctx, const quant_t dq, int n, int16_t* out) { + // n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'. + const uint8_t* p = prob[n][ctx]; + if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit. + return 0; + } + while (1) { + ++n; + if (!VP8GetBit(br, p[1])) { + p = prob[kBands[n]][0]; + } else { // non zero coeff + int v, j; + if (!VP8GetBit(br, p[2])) { + p = prob[kBands[n]][1]; + v = 1; + } else { + if (!VP8GetBit(br, p[3])) { + if (!VP8GetBit(br, p[4])) { + v = 2; + } else { + v = 3 + VP8GetBit(br, p[5]); + } + } else { + if (!VP8GetBit(br, p[6])) { + if (!VP8GetBit(br, p[7])) { + v = 5 + VP8GetBit(br, 159); + } else { + v = 7 + 2 * VP8GetBit(br, 165); + v += VP8GetBit(br, 145); + } + } else { + const uint8_t* tab; + const int bit1 = VP8GetBit(br, p[8]); + const int bit0 = VP8GetBit(br, p[9 + bit1]); + const int cat = 2 * bit1 + bit0; + v = 0; + for (tab = kCat3456[cat]; *tab; ++tab) { + v += v + VP8GetBit(br, *tab); + } + v += 3 + (8 << cat); + } + } + p = prob[kBands[n]][2]; + } + j = kZigzag[n - 1]; + out[j] = VP8GetSigned(br, v) * dq[j > 0]; + if (n == 16 || !VP8GetBit(br, p[0])) { // EOB + return n; + } + } + if (n == 16) { + return 16; + } + } +} + +// Alias-safe way of converting 4bytes to 32bits. +typedef union { + uint8_t i8[4]; + uint32_t i32; +} PackedNz; + +// Table to unpack four bits into four bytes +static const PackedNz kUnpackTab[16] = { + {{0, 0, 0, 0}}, {{1, 0, 0, 0}}, {{0, 1, 0, 0}}, {{1, 1, 0, 0}}, + {{0, 0, 1, 0}}, {{1, 0, 1, 0}}, {{0, 1, 1, 0}}, {{1, 1, 1, 0}}, + {{0, 0, 0, 1}}, {{1, 0, 0, 1}}, {{0, 1, 0, 1}}, {{1, 1, 0, 1}}, + {{0, 0, 1, 1}}, {{1, 0, 1, 1}}, {{0, 1, 1, 1}}, {{1, 1, 1, 1}} }; + +// Macro to pack four LSB of four bytes into four bits. +#if defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || \ + defined(__BIG_ENDIAN__) +#define PACK_CST 0x08040201U +#else +#define PACK_CST 0x01020408U +#endif +#define PACK(X, S) ((((X).i32 * PACK_CST) & 0xff000000) >> (S)) + +static void ParseResiduals(VP8Decoder* const dec, + VP8MB* const mb, VP8BitReader* const token_br) { + int out_t_nz, out_l_nz, first; + ProbaArray ac_prob; + const VP8QuantMatrix* q = &dec->dqm_[dec->segment_]; + int16_t* dst = dec->coeffs_; + VP8MB* const left_mb = dec->mb_info_ - 1; + PackedNz nz_ac, nz_dc; + PackedNz tnz, lnz; + uint32_t non_zero_ac = 0; + uint32_t non_zero_dc = 0; + int x, y, ch; + + nz_dc.i32 = nz_ac.i32 = 0; + memset(dst, 0, 384 * sizeof(*dst)); + if (!dec->is_i4x4_) { // parse DC + int16_t dc[16] = { 0 }; + const int ctx = mb->dc_nz_ + left_mb->dc_nz_; + mb->dc_nz_ = left_mb->dc_nz_ = + (GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1], + ctx, q->y2_mat_, 0, dc) > 0); + first = 1; + ac_prob = (ProbaArray)dec->proba_.coeffs_[0]; + VP8TransformWHT(dc, dst); + } else { + first = 0; + ac_prob = (ProbaArray)dec->proba_.coeffs_[3]; + } + + tnz = kUnpackTab[mb->nz_ & 0xf]; + lnz = kUnpackTab[left_mb->nz_ & 0xf]; + for (y = 0; y < 4; ++y) { + int l = lnz.i8[y]; + for (x = 0; x < 4; ++x) { + const int ctx = l + tnz.i8[x]; + const int nz = GetCoeffs(token_br, ac_prob, ctx, + q->y1_mat_, first, dst); + tnz.i8[x] = l = (nz > 0); + nz_dc.i8[x] = (dst[0] != 0); + nz_ac.i8[x] = (nz > 1); + dst += 16; + } + lnz.i8[y] = l; + non_zero_dc |= PACK(nz_dc, 24 - y * 4); + non_zero_ac |= PACK(nz_ac, 24 - y * 4); + } + out_t_nz = PACK(tnz, 24); + out_l_nz = PACK(lnz, 24); + + tnz = kUnpackTab[mb->nz_ >> 4]; + lnz = kUnpackTab[left_mb->nz_ >> 4]; + for (ch = 0; ch < 4; ch += 2) { + for (y = 0; y < 2; ++y) { + int l = lnz.i8[ch + y]; + for (x = 0; x < 2; ++x) { + const int ctx = l + tnz.i8[ch + x]; + const int nz = + GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2], + ctx, q->uv_mat_, 0, dst); + tnz.i8[ch + x] = l = (nz > 0); + nz_dc.i8[y * 2 + x] = (dst[0] != 0); + nz_ac.i8[y * 2 + x] = (nz > 1); + dst += 16; + } + lnz.i8[ch + y] = l; + } + non_zero_dc |= PACK(nz_dc, 8 - ch * 2); + non_zero_ac |= PACK(nz_ac, 8 - ch * 2); + } + out_t_nz |= PACK(tnz, 20); + out_l_nz |= PACK(lnz, 20); + mb->nz_ = out_t_nz; + left_mb->nz_ = out_l_nz; + + dec->non_zero_ac_ = non_zero_ac; + dec->non_zero_ = non_zero_ac | non_zero_dc; + mb->skip_ = !dec->non_zero_; +} +#undef PACK + +//------------------------------------------------------------------------------ +// Main loop + +int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) { + VP8BitReader* const br = &dec->br_; + VP8MB* const left = dec->mb_info_ - 1; + VP8MB* const info = dec->mb_info_ + dec->mb_x_; + + // Note: we don't save segment map (yet), as we don't expect + // to decode more than 1 keyframe. + if (dec->segment_hdr_.update_map_) { + // Hardcoded tree parsing + dec->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) ? + VP8GetBit(br, dec->proba_.segments_[1]) : + 2 + VP8GetBit(br, dec->proba_.segments_[2]); + } + info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0; + + VP8ParseIntraMode(br, dec); + if (br->eof_) { + return 0; + } + + if (!info->skip_) { + ParseResiduals(dec, info, token_br); + } else { + left->nz_ = info->nz_ = 0; + if (!dec->is_i4x4_) { + left->dc_nz_ = info->dc_nz_ = 0; + } + dec->non_zero_ = 0; + dec->non_zero_ac_ = 0; + } + + return (!token_br->eof_); +} + +void VP8InitScanline(VP8Decoder* const dec) { + VP8MB* const left = dec->mb_info_ - 1; + left->nz_ = 0; + left->dc_nz_ = 0; + memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_)); + dec->filter_row_ = + (dec->filter_type_ > 0) && + (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); +} + +static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { + for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) { + VP8BitReader* const token_br = + &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; + VP8InitScanline(dec); + for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) { + if (!VP8DecodeMB(dec, token_br)) { + return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, + "Premature end-of-file encountered."); + } + VP8ReconstructBlock(dec); + + // Store data and save block's filtering params + VP8StoreBlock(dec); + } + if (!VP8ProcessRow(dec, io)) { + return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted."); + } + } + if (dec->use_threads_ && !WebPWorkerSync(&dec->worker_)) { + return 0; + } + + // Finish +#ifndef ONLY_KEYFRAME_CODE + if (!dec->update_proba_) { + dec->proba_ = dec->proba_saved_; + } +#endif + +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (dec->layer_data_size_ > 0) { + if (!VP8DecodeLayer(dec)) { + return 0; + } + } +#endif + + return 1; +} + +// Main entry point +int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { + int ok = 0; + if (dec == NULL) { + return 0; + } + if (io == NULL) { + return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, + "NULL VP8Io parameter in VP8Decode()."); + } + + if (!dec->ready_) { + if (!VP8GetHeaders(dec, io)) { + return 0; + } + } + assert(dec->ready_); + + // Finish setting up the decoding parameter. Will call io->setup(). + ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK); + if (ok) { // good to go. + // Will allocate memory and prepare everything. + if (ok) ok = VP8InitFrame(dec, io); + + // Main decoding loop + if (ok) ok = ParseFrame(dec, io); + + // Exit. + ok &= VP8ExitCritical(dec, io); + } + + if (!ok) { + VP8Clear(dec); + return 0; + } + + dec->ready_ = 0; + return ok; +} + +void VP8Clear(VP8Decoder* const dec) { + if (dec == NULL) { + return; + } + if (dec->use_threads_) { + WebPWorkerEnd(&dec->worker_); + } + if (dec->mem_) { + free(dec->mem_); + } + dec->mem_ = NULL; + dec->mem_size_ = 0; + memset(&dec->br_, 0, sizeof(dec->br_)); + dec->ready_ = 0; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/vp8i.h b/external/libwebp/dec/vp8i.h new file mode 100644 index 0000000000..6e27456fe1 --- /dev/null +++ b/external/libwebp/dec/vp8i.h @@ -0,0 +1,335 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// VP8 decoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DEC_VP8I_H_ +#define WEBP_DEC_VP8I_H_ + +#include // for memcpy() +#include "./vp8li.h" +#include "../utils/bit_reader.h" +#include "../utils/thread.h" +#include "../dsp/dsp.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Various defines and enums + +// version numbers +#define DEC_MAJ_VERSION 0 +#define DEC_MIN_VERSION 2 +#define DEC_REV_VERSION 1 + +#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames + +// intra prediction modes +enum { B_DC_PRED = 0, // 4x4 modes + B_TM_PRED, + B_VE_PRED, + B_HE_PRED, + B_RD_PRED, + B_VR_PRED, + B_LD_PRED, + B_VL_PRED, + B_HD_PRED, + B_HU_PRED, + NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10 + + // Luma16 or UV modes + DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED, + H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED, + B_PRED = NUM_BMODES, // refined I4x4 mode + + // special modes + B_DC_PRED_NOTOP = 4, + B_DC_PRED_NOLEFT = 5, + B_DC_PRED_NOTOPLEFT = 6, + NUM_B_DC_MODES = 7 }; + +enum { MB_FEATURE_TREE_PROBS = 3, + NUM_MB_SEGMENTS = 4, + NUM_REF_LF_DELTAS = 4, + NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT + MAX_NUM_PARTITIONS = 8, + // Probabilities + NUM_TYPES = 4, + NUM_BANDS = 8, + NUM_CTX = 3, + NUM_PROBAS = 11, + NUM_MV_PROBAS = 19 }; + +// YUV-cache parameters. +// Constraints are: We need to store one 16x16 block of luma samples (y), +// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned, +// in order to be SIMD-friendly. We also need to store the top, left and +// top-left samples (from previously decoded blocks), along with four +// extra top-right samples for luma (intra4x4 prediction only). +// One possible layout is, using 32 * (17 + 9) bytes: +// +// .+------ <- only 1 pixel high +// .|yyyyt. +// .|yyyyt. +// .|yyyyt. +// .|yyyy.. +// .+--.+-- <- only 1 pixel high +// .|uu.|vv +// .|uu.|vv +// +// Every character is a 4x4 block, with legend: +// '.' = unused +// 'y' = y-samples 'u' = u-samples 'v' = u-samples +// '|' = left sample, '-' = top sample, '+' = top-left sample +// 't' = extra top-right sample for 4x4 modes +// With this layout, BPS (=Bytes Per Scan-line) is one cacheline size. +#define BPS 32 // this is the common stride used by yuv[] +#define YUV_SIZE (BPS * 17 + BPS * 9) +#define Y_SIZE (BPS * 17) +#define Y_OFF (BPS * 1 + 8) +#define U_OFF (Y_OFF + BPS * 16 + BPS) +#define V_OFF (U_OFF + 16) + +//------------------------------------------------------------------------------ +// Headers + +typedef struct { + uint8_t key_frame_; + uint8_t profile_; + uint8_t show_; + uint32_t partition_length_; +} VP8FrameHeader; + +typedef struct { + uint16_t width_; + uint16_t height_; + uint8_t xscale_; + uint8_t yscale_; + uint8_t colorspace_; // 0 = YCbCr + uint8_t clamp_type_; +} VP8PictureHeader; + +// segment features +typedef struct { + int use_segment_; + int update_map_; // whether to update the segment map or not + int absolute_delta_; // absolute or delta values for quantizer and filter + int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes + int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments +} VP8SegmentHeader; + +// Struct collecting all frame-persistent probabilities. +typedef struct { + uint8_t segments_[MB_FEATURE_TREE_PROBS]; + // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4 + uint8_t coeffs_[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; +#ifndef ONLY_KEYFRAME_CODE + uint8_t ymode_[4], uvmode_[3]; + uint8_t mv_[2][NUM_MV_PROBAS]; +#endif +} VP8Proba; + +// Filter parameters +typedef struct { + int simple_; // 0=complex, 1=simple + int level_; // [0..63] + int sharpness_; // [0..7] + int use_lf_delta_; + int ref_lf_delta_[NUM_REF_LF_DELTAS]; + int mode_lf_delta_[NUM_MODE_LF_DELTAS]; +} VP8FilterHeader; + +//------------------------------------------------------------------------------ +// Informations about the macroblocks. + +typedef struct { // filter specs + unsigned int f_level_:6; // filter strength: 0..63 + unsigned int f_ilevel_:6; // inner limit: 1..63 + unsigned int f_inner_:1; // do inner filtering? +} VP8FInfo; + +typedef struct { // used for syntax-parsing + unsigned int nz_; // non-zero AC/DC coeffs + unsigned int dc_nz_:1; // non-zero DC coeffs + unsigned int skip_:1; // block type +} VP8MB; + +// Dequantization matrices +typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower). +typedef struct { + quant_t y1_mat_, y2_mat_, uv_mat_; +} VP8QuantMatrix; + +// Persistent information needed by the parallel processing +typedef struct { + int id_; // cache row to process (in [0..2]) + int mb_y_; // macroblock position of the row + int filter_row_; // true if row-filtering is needed + VP8FInfo* f_info_; // filter strengths + VP8Io io_; // copy of the VP8Io to pass to put() +} VP8ThreadContext; + +//------------------------------------------------------------------------------ +// VP8Decoder: the main opaque structure handed over to user + +struct VP8Decoder { + VP8StatusCode status_; + int ready_; // true if ready to decode a picture with VP8Decode() + const char* error_msg_; // set when status_ is not OK. + + // Main data source + VP8BitReader br_; + + // headers + VP8FrameHeader frm_hdr_; + VP8PictureHeader pic_hdr_; + VP8FilterHeader filter_hdr_; + VP8SegmentHeader segment_hdr_; + + // Worker + WebPWorker worker_; + int use_threads_; // use multi-thread + int cache_id_; // current cache row + int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3) + VP8ThreadContext thread_ctx_; // Thread context + + // dimension, in macroblock units. + int mb_w_, mb_h_; + + // Macroblock to process/filter, depending on cropping and filter_type. + int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered + int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded + + // number of partitions. + int num_parts_; + // per-partition boolean decoders. + VP8BitReader parts_[MAX_NUM_PARTITIONS]; + + // buffer refresh flags + // bit 0: refresh Gold, bit 1: refresh Alt + // bit 2-3: copy to Gold, bit 4-5: copy to Alt + // bit 6: Gold sign bias, bit 7: Alt sign bias + // bit 8: refresh last frame + uint32_t buffer_flags_; + + // dequantization (one set of DC/AC dequant factor per segment) + VP8QuantMatrix dqm_[NUM_MB_SEGMENTS]; + + // probabilities + VP8Proba proba_; + int use_skip_proba_; + uint8_t skip_p_; +#ifndef ONLY_KEYFRAME_CODE + uint8_t intra_p_, last_p_, golden_p_; + VP8Proba proba_saved_; + int update_proba_; +#endif + + // Boundary data cache and persistent buffers. + uint8_t* intra_t_; // top intra modes values: 4 * mb_w_ + uint8_t intra_l_[4]; // left intra modes values + uint8_t* y_t_; // top luma samples: 16 * mb_w_ + uint8_t* u_t_, *v_t_; // top u/v samples: 8 * mb_w_ each + + VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1) + VP8FInfo* f_info_; // filter strength info + uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE) + int16_t* coeffs_; // 384 coeffs = (16+8+8) * 4*4 + + uint8_t* cache_y_; // macroblock row for storing unfiltered samples + uint8_t* cache_u_; + uint8_t* cache_v_; + int cache_y_stride_; + int cache_uv_stride_; + + // main memory chunk for the above data. Persistent. + void* mem_; + size_t mem_size_; + + // Per macroblock non-persistent infos. + int mb_x_, mb_y_; // current position, in macroblock units + uint8_t is_i4x4_; // true if intra4x4 + uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes + uint8_t uvmode_; // chroma prediction mode + uint8_t segment_; // block's segment + + // bit-wise info about the content of each sub-4x4 blocks: there are 16 bits + // for luma (bits #0->#15), then 4 bits for chroma-u (#16->#19) and 4 bits for + // chroma-v (#20->#23), each corresponding to one 4x4 block in decoding order. + // If the bit is set, the 4x4 block contains some non-zero coefficients. + uint32_t non_zero_; + uint32_t non_zero_ac_; + + // Filtering side-info + int filter_type_; // 0=off, 1=simple, 2=complex + int filter_row_; // per-row flag + uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment + + // extensions + const uint8_t* alpha_data_; // compressed alpha data (if present) + size_t alpha_data_size_; + uint8_t* alpha_plane_; // output. Persistent, contains the whole data. + + int layer_colorspace_; + const uint8_t* layer_data_; // compressed layer data (if present) + size_t layer_data_size_; +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// in vp8.c +int VP8SetError(VP8Decoder* const dec, + VP8StatusCode error, const char* const msg); + +// in tree.c +void VP8ResetProba(VP8Proba* const proba); +void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec); +void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec); + +// in quant.c +void VP8ParseQuant(VP8Decoder* const dec); + +// in frame.c +int VP8InitFrame(VP8Decoder* const dec, VP8Io* io); +// Predict a block and add residual +void VP8ReconstructBlock(VP8Decoder* const dec); +// Call io->setup() and finish setting up scan parameters. +// After this call returns, one must always call VP8ExitCritical() with the +// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK +// if ok, otherwise sets and returns the error status on *dec. +VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io); +// Must always be called in pair with VP8EnterCritical(). +// Returns false in case of error. +int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io); +// Process the last decoded row (filtering + output) +int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io); +// Store a block, along with filtering params +void VP8StoreBlock(VP8Decoder* const dec); +// To be called at the start of a new scanline, to initialize predictors. +void VP8InitScanline(VP8Decoder* const dec); +// Decode one macroblock. Returns false if there is not enough data. +int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br); + +// in alpha.c +const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, + int row, int num_rows); + +// in layer.c +int VP8DecodeLayer(VP8Decoder* const dec); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_DEC_VP8I_H_ */ diff --git a/external/libwebp/dec/vp8l.c b/external/libwebp/dec/vp8l.c new file mode 100644 index 0000000000..897e4395c7 --- /dev/null +++ b/external/libwebp/dec/vp8l.c @@ -0,0 +1,1200 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// main entry for the decoder +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) + +#include +#include +#include "./vp8li.h" +#include "../dsp/lossless.h" +#include "../dsp/yuv.h" +#include "../utils/huffman.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define NUM_ARGB_CACHE_ROWS 16 + +static const int kCodeLengthLiterals = 16; +static const int kCodeLengthRepeatCode = 16; +static const int kCodeLengthExtraBits[3] = { 2, 3, 7 }; +static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 }; + +// ----------------------------------------------------------------------------- +// Five Huffman codes are used at each meta code: +// 1. green + length prefix codes + color cache codes, +// 2. alpha, +// 3. red, +// 4. blue, and, +// 5. distance prefix codes. +typedef enum { + GREEN = 0, + RED = 1, + BLUE = 2, + ALPHA = 3, + DIST = 4 +} HuffIndex; + +static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = { + NUM_LITERAL_CODES + NUM_LENGTH_CODES, + NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES, + NUM_DISTANCE_CODES +}; + + +#define NUM_CODE_LENGTH_CODES 19 +static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = { + 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +#define CODE_TO_PLANE_CODES 120 +static const uint8_t code_to_plane_lut[CODE_TO_PLANE_CODES] = { + 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a, + 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a, + 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b, + 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03, + 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c, + 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e, + 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b, + 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f, + 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b, + 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41, + 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f, + 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70 +}; + +static int DecodeImageStream(int xsize, int ysize, + int is_level0, + VP8LDecoder* const dec, + uint32_t** const decoded_data); + +//------------------------------------------------------------------------------ + +int VP8LCheckSignature(const uint8_t* const data, size_t size) { + return (size >= 1) && (data[0] == VP8L_MAGIC_BYTE); +} + +static int ReadImageInfo(VP8LBitReader* const br, + int* const width, int* const height, + int* const has_alpha) { + const uint8_t signature = VP8LReadBits(br, 8); + if (!VP8LCheckSignature(&signature, 1)) { + return 0; + } + *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; + *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; + *has_alpha = VP8LReadBits(br, 1); + VP8LReadBits(br, VP8L_VERSION_BITS); // Read/ignore the version number. + return 1; +} + +int VP8LGetInfo(const uint8_t* data, size_t data_size, + int* const width, int* const height, int* const has_alpha) { + if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) { + return 0; // not enough data + } else { + int w, h, a; + VP8LBitReader br; + VP8LInitBitReader(&br, data, data_size); + if (!ReadImageInfo(&br, &w, &h, &a)) { + return 0; + } + if (width != NULL) *width = w; + if (height != NULL) *height = h; + if (has_alpha != NULL) *has_alpha = a; + return 1; + } +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int GetCopyDistance(int distance_symbol, + VP8LBitReader* const br) { + int extra_bits, offset; + if (distance_symbol < 4) { + return distance_symbol + 1; + } + extra_bits = (distance_symbol - 2) >> 1; + offset = (2 + (distance_symbol & 1)) << extra_bits; + return offset + VP8LReadBits(br, extra_bits) + 1; +} + +static WEBP_INLINE int GetCopyLength(int length_symbol, + VP8LBitReader* const br) { + // Length and distance prefixes are encoded the same way. + return GetCopyDistance(length_symbol, br); +} + +static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) { + if (plane_code > CODE_TO_PLANE_CODES) { + return plane_code - CODE_TO_PLANE_CODES; + } else { + const int dist_code = code_to_plane_lut[plane_code - 1]; + const int yoffset = dist_code >> 4; + const int xoffset = 8 - (dist_code & 0xf); + const int dist = yoffset * xsize + xoffset; + return (dist >= 1) ? dist : 1; + } +} + +//------------------------------------------------------------------------------ +// Decodes the next Huffman code from bit-stream. +// FillBitWindow(br) needs to be called at minimum every second call +// to ReadSymbolUnsafe. +static int ReadSymbolUnsafe(const HuffmanTree* tree, VP8LBitReader* const br) { + const HuffmanTreeNode* node = tree->root_; + assert(node != NULL); + while (!HuffmanTreeNodeIsLeaf(node)) { + node = HuffmanTreeNextNode(node, VP8LReadOneBitUnsafe(br)); + } + return node->symbol_; +} + +static WEBP_INLINE int ReadSymbol(const HuffmanTree* tree, + VP8LBitReader* const br) { + const int read_safe = (br->pos_ + 8 > br->len_); + if (!read_safe) { + return ReadSymbolUnsafe(tree, br); + } else { + const HuffmanTreeNode* node = tree->root_; + assert(node != NULL); + while (!HuffmanTreeNodeIsLeaf(node)) { + node = HuffmanTreeNextNode(node, VP8LReadOneBit(br)); + } + return node->symbol_; + } +} + +static int ReadHuffmanCodeLengths( + VP8LDecoder* const dec, const int* const code_length_code_lengths, + int num_symbols, int* const code_lengths) { + int ok = 0; + VP8LBitReader* const br = &dec->br_; + int symbol; + int max_symbol; + int prev_code_len = DEFAULT_CODE_LENGTH; + HuffmanTree tree; + + if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths, + NUM_CODE_LENGTH_CODES)) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + return 0; + } + + if (VP8LReadBits(br, 1)) { // use length + const int length_nbits = 2 + 2 * VP8LReadBits(br, 3); + max_symbol = 2 + VP8LReadBits(br, length_nbits); + if (max_symbol > num_symbols) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto End; + } + } else { + max_symbol = num_symbols; + } + + symbol = 0; + while (symbol < num_symbols) { + int code_len; + if (max_symbol-- == 0) break; + VP8LFillBitWindow(br); + code_len = ReadSymbol(&tree, br); + if (code_len < kCodeLengthLiterals) { + code_lengths[symbol++] = code_len; + if (code_len != 0) prev_code_len = code_len; + } else { + const int use_prev = (code_len == kCodeLengthRepeatCode); + const int slot = code_len - kCodeLengthLiterals; + const int extra_bits = kCodeLengthExtraBits[slot]; + const int repeat_offset = kCodeLengthRepeatOffsets[slot]; + int repeat = VP8LReadBits(br, extra_bits) + repeat_offset; + if (symbol + repeat > num_symbols) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto End; + } else { + const int length = use_prev ? prev_code_len : 0; + while (repeat-- > 0) code_lengths[symbol++] = length; + } + } + } + ok = 1; + + End: + HuffmanTreeRelease(&tree); + return ok; +} + +static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, + HuffmanTree* const tree) { + int ok = 0; + VP8LBitReader* const br = &dec->br_; + const int simple_code = VP8LReadBits(br, 1); + + if (simple_code) { // Read symbols, codes & code lengths directly. + int symbols[2]; + int codes[2]; + int code_lengths[2]; + const int num_symbols = VP8LReadBits(br, 1) + 1; + const int first_symbol_len_code = VP8LReadBits(br, 1); + // The first code is either 1 bit or 8 bit code. + symbols[0] = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8); + codes[0] = 0; + code_lengths[0] = num_symbols - 1; + // The second code (if present), is always 8 bit long. + if (num_symbols == 2) { + symbols[1] = VP8LReadBits(br, 8); + codes[1] = 1; + code_lengths[1] = num_symbols - 1; + } + ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols, + alphabet_size, num_symbols); + } else { // Decode Huffman-coded code lengths. + int* code_lengths = NULL; + int i; + int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 }; + const int num_codes = VP8LReadBits(br, 4) + 4; + if (num_codes > NUM_CODE_LENGTH_CODES) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + return 0; + } + + code_lengths = + (int*)WebPSafeCalloc((uint64_t)alphabet_size, sizeof(*code_lengths)); + if (code_lengths == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + return 0; + } + + for (i = 0; i < num_codes; ++i) { + code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3); + } + ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size, + code_lengths); + if (ok) { + ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size); + } + free(code_lengths); + } + ok = ok && !br->error_; + if (!ok) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + return 0; + } + return 1; +} + +static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) { + if (htree_groups != NULL) { + int i, j; + for (i = 0; i < num_htree_groups; ++i) { + HuffmanTree* const htrees = htree_groups[i].htrees_; + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + HuffmanTreeRelease(&htrees[j]); + } + } + free(htree_groups); + } +} + +static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, + int color_cache_bits, int allow_recursion) { + int i, j; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* huffman_image = NULL; + HTreeGroup* htree_groups = NULL; + int num_htree_groups = 1; + + if (allow_recursion && VP8LReadBits(br, 1)) { + // use meta Huffman codes. + const int huffman_precision = VP8LReadBits(br, 3) + 2; + const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision); + const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); + const int huffman_pixs = huffman_xsize * huffman_ysize; + if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec, + &huffman_image)) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto Error; + } + hdr->huffman_subsample_bits_ = huffman_precision; + for (i = 0; i < huffman_pixs; ++i) { + // The huffman data is stored in red and green bytes. + const int index = (huffman_image[i] >> 8) & 0xffff; + huffman_image[i] = index; + if (index >= num_htree_groups) { + num_htree_groups = index + 1; + } + } + } + + if (br->error_) goto Error; + + assert(num_htree_groups <= 0x10000); + htree_groups = + (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups, + sizeof(*htree_groups)); + if (htree_groups == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + goto Error; + } + + for (i = 0; i < num_htree_groups; ++i) { + HuffmanTree* const htrees = htree_groups[i].htrees_; + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + int alphabet_size = kAlphabetSize[j]; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += 1 << color_cache_bits; + } + if (!ReadHuffmanCode(alphabet_size, dec, htrees + j)) goto Error; + } + } + + // All OK. Finalize pointers and return. + hdr->huffman_image_ = huffman_image; + hdr->num_htree_groups_ = num_htree_groups; + hdr->htree_groups_ = htree_groups; + return 1; + + Error: + free(huffman_image); + DeleteHtreeGroups(htree_groups, num_htree_groups); + return 0; +} + +//------------------------------------------------------------------------------ +// Scaling. + +static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) { + const int num_channels = 4; + const int in_width = io->mb_w; + const int out_width = io->scaled_width; + const int in_height = io->mb_h; + const int out_height = io->scaled_height; + const uint64_t work_size = 2 * num_channels * (uint64_t)out_width; + int32_t* work; // Rescaler work area. + const uint64_t scaled_data_size = num_channels * (uint64_t)out_width; + uint32_t* scaled_data; // Temporary storage for scaled BGRA data. + const uint64_t memory_size = sizeof(*dec->rescaler) + + work_size * sizeof(*work) + + scaled_data_size * sizeof(*scaled_data); + uint8_t* memory = (uint8_t*)WebPSafeCalloc(memory_size, sizeof(*memory)); + if (memory == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + return 0; + } + assert(dec->rescaler_memory == NULL); + dec->rescaler_memory = memory; + + dec->rescaler = (WebPRescaler*)memory; + memory += sizeof(*dec->rescaler); + work = (int32_t*)memory; + memory += work_size * sizeof(*work); + scaled_data = (uint32_t*)memory; + + WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data, + out_width, out_height, 0, num_channels, + in_width, out_width, in_height, out_height, work); + return 1; +} + +//------------------------------------------------------------------------------ +// Export to ARGB + +// We have special "export" function since we need to convert from BGRA +static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace, + int rgba_stride, uint8_t* const rgba) { + const uint32_t* const src = (const uint32_t*)rescaler->dst; + const int dst_width = rescaler->dst_width; + int num_lines_out = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + uint8_t* const dst = rgba + num_lines_out * rgba_stride; + WebPRescalerExportRow(rescaler); + VP8LConvertFromBGRA(src, dst_width, colorspace, dst); + ++num_lines_out; + } + return num_lines_out; +} + +// Emit scaled rows. +static int EmitRescaledRows(const VP8LDecoder* const dec, + const uint32_t* const data, int in_stride, int mb_h, + uint8_t* const out, int out_stride) { + const WEBP_CSP_MODE colorspace = dec->output_->colorspace; + const uint8_t* const in = (const uint8_t*)data; + int num_lines_in = 0; + int num_lines_out = 0; + while (num_lines_in < mb_h) { + const uint8_t* const row_in = in + num_lines_in * in_stride; + uint8_t* const row_out = out + num_lines_out * out_stride; + num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in, + row_in, in_stride); + num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out); + } + return num_lines_out; +} + +// Emit rows without any scaling. +static int EmitRows(WEBP_CSP_MODE colorspace, + const uint32_t* const data, int in_stride, + int mb_w, int mb_h, + uint8_t* const out, int out_stride) { + int lines = mb_h; + const uint8_t* row_in = (const uint8_t*)data; + uint8_t* row_out = out; + while (lines-- > 0) { + VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out); + row_in += in_stride; + row_out += out_stride; + } + return mb_h; // Num rows out == num rows in. +} + +//------------------------------------------------------------------------------ +// Export to YUVA + +static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos, + const WebPDecBuffer* const output) { + const WebPYUVABuffer* const buf = &output->u.YUVA; + // first, the luma plane + { + int i; + uint8_t* const y = buf->y + y_pos * buf->y_stride; + for (i = 0; i < width; ++i) { + const uint32_t p = src[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff); + } + } + + // then U/V planes + { + uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride; + uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride; + const int uv_width = width >> 1; + int i; + for (i = 0; i < uv_width; ++i) { + const uint32_t v0 = src[2 * i + 0]; + const uint32_t v1 = src[2 * i + 1]; + // VP8RGBToU/V expects four accumulated pixels. Hence we need to + // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less. + const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe); + const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe); + const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe); + if (!(y_pos & 1)) { // even lines: store values + u[i] = VP8RGBToU(r, g, b); + v[i] = VP8RGBToV(r, g, b); + } else { // odd lines: average with previous values + const int tmp_u = VP8RGBToU(r, g, b); + const int tmp_v = VP8RGBToV(r, g, b); + // Approximated average-of-four. But it's an acceptable diff. + u[i] = (u[i] + tmp_u + 1) >> 1; + v[i] = (v[i] + tmp_v + 1) >> 1; + } + } + if (width & 1) { // last pixel + const uint32_t v0 = src[2 * i + 0]; + const int r = (v0 >> 14) & 0x3fc; + const int g = (v0 >> 6) & 0x3fc; + const int b = (v0 << 2) & 0x3fc; + if (!(y_pos & 1)) { // even lines + u[i] = VP8RGBToU(r, g, b); + v[i] = VP8RGBToV(r, g, b); + } else { // odd lines (note: we could just skip this) + const int tmp_u = VP8RGBToU(r, g, b); + const int tmp_v = VP8RGBToV(r, g, b); + u[i] = (u[i] + tmp_u + 1) >> 1; + v[i] = (v[i] + tmp_v + 1) >> 1; + } + } + } + // Lastly, store alpha if needed. + if (buf->a != NULL) { + int i; + uint8_t* const a = buf->a + y_pos * buf->a_stride; + for (i = 0; i < width; ++i) a[i] = (src[i] >> 24); + } +} + +static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) { + WebPRescaler* const rescaler = dec->rescaler; + const uint32_t* const src = (const uint32_t*)rescaler->dst; + const int dst_width = rescaler->dst_width; + int num_lines_out = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + ConvertToYUVA(src, dst_width, y_pos, dec->output_); + ++y_pos; + ++num_lines_out; + } + return num_lines_out; +} + +static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, + const uint32_t* const data, + int in_stride, int mb_h) { + const uint8_t* const in = (const uint8_t*)data; + int num_lines_in = 0; + int y_pos = dec->last_out_row_; + while (num_lines_in < mb_h) { + const uint8_t* const row_in = in + num_lines_in * in_stride; + num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in, + row_in, in_stride); + y_pos += ExportYUVA(dec, y_pos); + } + return y_pos; +} + +static int EmitRowsYUVA(const VP8LDecoder* const dec, + const uint32_t* const data, int in_stride, + int mb_w, int num_rows) { + int y_pos = dec->last_out_row_; + const uint8_t* row_in = (const uint8_t*)data; + while (num_rows-- > 0) { + ConvertToYUVA((const uint32_t*)row_in, mb_w, y_pos, dec->output_); + row_in += in_stride; + ++y_pos; + } + return y_pos; +} + +//------------------------------------------------------------------------------ +// Cropping. + +// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and +// crop options. Also updates the input data pointer, so that it points to the +// start of the cropped window. +// Note that 'pixel_stride' is in units of 'uint32_t' (and not 'bytes). +// Returns true if the crop window is not empty. +static int SetCropWindow(VP8Io* const io, int y_start, int y_end, + const uint32_t** const in_data, int pixel_stride) { + assert(y_start < y_end); + assert(io->crop_left < io->crop_right); + if (y_end > io->crop_bottom) { + y_end = io->crop_bottom; // make sure we don't overflow on last row. + } + if (y_start < io->crop_top) { + const int delta = io->crop_top - y_start; + y_start = io->crop_top; + *in_data += pixel_stride * delta; + } + if (y_start >= y_end) return 0; // Crop window is empty. + + *in_data += io->crop_left; + + io->mb_y = y_start - io->crop_top; + io->mb_w = io->crop_right - io->crop_left; + io->mb_h = y_end - y_start; + return 1; // Non-empty crop window. +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int GetMetaIndex( + const uint32_t* const image, int xsize, int bits, int x, int y) { + if (bits == 0) return 0; + return image[xsize * (y >> bits) + (x >> bits)]; +} + +static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr, + int x, int y) { + const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_, + hdr->huffman_subsample_bits_, x, y); + assert(meta_index < hdr->num_htree_groups_); + return hdr->htree_groups_ + meta_index; +} + +//------------------------------------------------------------------------------ +// Main loop, with custom row-processing function + +typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); + +static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows, + const uint32_t* const rows) { + int n = dec->next_transform_; + const int cache_pixs = dec->width_ * num_rows; + const int start_row = dec->last_row_; + const int end_row = start_row + num_rows; + const uint32_t* rows_in = rows; + uint32_t* const rows_out = dec->argb_cache_; + + // Inverse transforms. + // TODO: most transforms only need to operate on the cropped region only. + memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out)); + while (n-- > 0) { + VP8LTransform* const transform = &dec->transforms_[n]; + VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); + rows_in = rows_out; + } +} + +// Processes (transforms, scales & color-converts) the rows decoded after the +// last call. +static void ProcessRows(VP8LDecoder* const dec, int row) { + const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_; + const int num_rows = row - dec->last_row_; + + if (num_rows <= 0) return; // Nothing to be done. + ApplyInverseTransforms(dec, num_rows, rows); + + // Emit output. + { + VP8Io* const io = dec->io_; + const uint32_t* rows_data = dec->argb_cache_; + if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) { + // Nothing to output (this time). + } else { + const WebPDecBuffer* const output = dec->output_; + const int in_stride = io->width * sizeof(*rows_data); + if (output->colorspace < MODE_YUV) { // convert to RGBA + const WebPRGBABuffer* const buf = &output->u.RGBA; + uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride; + const int num_rows_out = io->use_scaling ? + EmitRescaledRows(dec, rows_data, in_stride, io->mb_h, + rgba, buf->stride) : + EmitRows(output->colorspace, rows_data, in_stride, + io->mb_w, io->mb_h, rgba, buf->stride); + // Update 'last_out_row_'. + dec->last_out_row_ += num_rows_out; + } else { // convert to YUVA + dec->last_out_row_ = io->use_scaling ? + EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) : + EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h); + } + assert(dec->last_out_row_ <= output->height); + } + } + + // Update 'last_row_'. + dec->last_row_ = row; + assert(dec->last_row_ <= dec->height_); +} + +static int DecodeImageData(VP8LDecoder* const dec, + uint32_t* const data, int width, int height, + ProcessRowsFunc process_func) { + int ok = 1; + int col = 0, row = 0; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + HTreeGroup* htree_group = hdr->htree_groups_; + uint32_t* src = data; + uint32_t* last_cached = data; + uint32_t* const src_end = data + width * height; + const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; + const int color_cache_limit = len_code_limit + hdr->color_cache_size_; + VP8LColorCache* const color_cache = + (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; + const int mask = hdr->huffman_mask_; + + assert(htree_group != NULL); + + while (!br->eos_ && src < src_end) { + int code; + // Only update when changing tile. Note we could use the following test: + // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed + // but that's actually slower and requires storing the previous col/row + if ((col & mask) == 0) { + htree_group = GetHtreeGroupForPos(hdr, col, row); + } + VP8LFillBitWindow(br); + code = ReadSymbol(&htree_group->htrees_[GREEN], br); + if (code < NUM_LITERAL_CODES) { // Literal. + int red, green, blue, alpha; + red = ReadSymbol(&htree_group->htrees_[RED], br); + green = code; + VP8LFillBitWindow(br); + blue = ReadSymbol(&htree_group->htrees_[BLUE], br); + alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br); + *src = (alpha << 24) + (red << 16) + (green << 8) + blue; + AdvanceByOne: + ++src; + ++col; + if (col >= width) { + col = 0; + ++row; + if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { + process_func(dec, row); + } + if (color_cache != NULL) { + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + } + } + } else if (code < len_code_limit) { // Backward reference + int dist_code, dist; + const int length_sym = code - NUM_LITERAL_CODES; + const int length = GetCopyLength(length_sym, br); + const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br); + VP8LFillBitWindow(br); + dist_code = GetCopyDistance(dist_symbol, br); + dist = PlaneCodeToDistance(width, dist_code); + if (src - data < dist || src_end - src < length) { + ok = 0; + goto End; + } + { + int i; + for (i = 0; i < length; ++i) src[i] = src[i - dist]; + src += length; + } + col += length; + while (col >= width) { + col -= width; + ++row; + if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) { + process_func(dec, row); + } + } + if (src < src_end) { + htree_group = GetHtreeGroupForPos(hdr, col, row); + if (color_cache != NULL) { + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + } + } + } else if (code < color_cache_limit) { // Color cache. + const int key = code - len_code_limit; + assert(color_cache != NULL); + while (last_cached < src) { + VP8LColorCacheInsert(color_cache, *last_cached++); + } + *src = VP8LColorCacheLookup(color_cache, key); + goto AdvanceByOne; + } else { // Not reached. + ok = 0; + goto End; + } + ok = !br->error_; + if (!ok) goto End; + } + // Process the remaining rows corresponding to last row-block. + if (process_func != NULL) process_func(dec, row); + + End: + if (br->error_ || !ok || (br->eos_ && src < src_end)) { + ok = 0; + dec->status_ = (!br->eos_) ? + VP8_STATUS_BITSTREAM_ERROR : VP8_STATUS_SUSPENDED; + } else if (src == src_end) { + dec->state_ = READ_DATA; + } + + return ok; +} + +// ----------------------------------------------------------------------------- +// VP8LTransform + +static void ClearTransform(VP8LTransform* const transform) { + free(transform->data_); + transform->data_ = NULL; +} + +// For security reason, we need to remap the color map to span +// the total possible bundled values, and not just the num_colors. +static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { + int i; + const int final_num_colors = 1 << (8 >> transform->bits_); + uint32_t* const new_color_map = + (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, + sizeof(*new_color_map)); + if (new_color_map == NULL) { + return 0; + } else { + uint8_t* const data = (uint8_t*)transform->data_; + uint8_t* const new_data = (uint8_t*)new_color_map; + new_color_map[0] = transform->data_[0]; + for (i = 4; i < 4 * num_colors; ++i) { + // Equivalent to AddPixelEq(), on a byte-basis. + new_data[i] = (data[i] + new_data[i - 4]) & 0xff; + } + for (; i < 4 * final_num_colors; ++i) + new_data[i] = 0; // black tail. + free(transform->data_); + transform->data_ = new_color_map; + } + return 1; +} + +static int ReadTransform(int* const xsize, int const* ysize, + VP8LDecoder* const dec) { + int ok = 1; + VP8LBitReader* const br = &dec->br_; + VP8LTransform* transform = &dec->transforms_[dec->next_transform_]; + const VP8LImageTransformType type = + (VP8LImageTransformType)VP8LReadBits(br, 2); + + // Each transform type can only be present once in the stream. + if (dec->transforms_seen_ & (1U << type)) { + return 0; // Already there, let's not accept the second same transform. + } + dec->transforms_seen_ |= (1U << type); + + transform->type_ = type; + transform->xsize_ = *xsize; + transform->ysize_ = *ysize; + transform->data_ = NULL; + ++dec->next_transform_; + assert(dec->next_transform_ <= NUM_TRANSFORMS); + + switch (type) { + case PREDICTOR_TRANSFORM: + case CROSS_COLOR_TRANSFORM: + transform->bits_ = VP8LReadBits(br, 3) + 2; + ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_, + transform->bits_), + VP8LSubSampleSize(transform->ysize_, + transform->bits_), + 0, dec, &transform->data_); + break; + case COLOR_INDEXING_TRANSFORM: { + const int num_colors = VP8LReadBits(br, 8) + 1; + const int bits = (num_colors > 16) ? 0 + : (num_colors > 4) ? 1 + : (num_colors > 2) ? 2 + : 3; + *xsize = VP8LSubSampleSize(transform->xsize_, bits); + transform->bits_ = bits; + ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_); + ok = ok && ExpandColorMap(num_colors, transform); + break; + } + case SUBTRACT_GREEN: + break; + default: + assert(0); // can't happen + break; + } + + return ok; +} + +// ----------------------------------------------------------------------------- +// VP8LMetadata + +static void InitMetadata(VP8LMetadata* const hdr) { + assert(hdr); + memset(hdr, 0, sizeof(*hdr)); +} + +static void ClearMetadata(VP8LMetadata* const hdr) { + assert(hdr); + + free(hdr->huffman_image_); + DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_); + VP8LColorCacheClear(&hdr->color_cache_); + InitMetadata(hdr); +} + +// ----------------------------------------------------------------------------- +// VP8LDecoder + +VP8LDecoder* VP8LNew(void) { + VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec)); + if (dec == NULL) return NULL; + dec->status_ = VP8_STATUS_OK; + dec->action_ = READ_DIM; + dec->state_ = READ_DIM; + return dec; +} + +void VP8LClear(VP8LDecoder* const dec) { + int i; + if (dec == NULL) return; + ClearMetadata(&dec->hdr_); + + free(dec->argb_); + dec->argb_ = NULL; + for (i = 0; i < dec->next_transform_; ++i) { + ClearTransform(&dec->transforms_[i]); + } + dec->next_transform_ = 0; + dec->transforms_seen_ = 0; + + free(dec->rescaler_memory); + dec->rescaler_memory = NULL; + + dec->output_ = NULL; // leave no trace behind +} + +void VP8LDelete(VP8LDecoder* const dec) { + if (dec != NULL) { + VP8LClear(dec); + free(dec); + } +} + +static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) { + VP8LMetadata* const hdr = &dec->hdr_; + const int num_bits = hdr->huffman_subsample_bits_; + dec->width_ = width; + dec->height_ = height; + + hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits); + hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; +} + +static int DecodeImageStream(int xsize, int ysize, + int is_level0, + VP8LDecoder* const dec, + uint32_t** const decoded_data) { + int ok = 1; + int transform_xsize = xsize; + int transform_ysize = ysize; + VP8LBitReader* const br = &dec->br_; + VP8LMetadata* const hdr = &dec->hdr_; + uint32_t* data = NULL; + int color_cache_bits = 0; + + // Read the transforms (may recurse). + if (is_level0) { + while (ok && VP8LReadBits(br, 1)) { + ok = ReadTransform(&transform_xsize, &transform_ysize, dec); + } + } + + // Color cache + if (ok && VP8LReadBits(br, 1)) { + color_cache_bits = VP8LReadBits(br, 4); + ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS); + if (!ok) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto End; + } + } + + // Read the Huffman codes (may recurse). + ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize, + color_cache_bits, is_level0); + if (!ok) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto End; + } + + // Finish setting up the color-cache + if (color_cache_bits > 0) { + hdr->color_cache_size_ = 1 << color_cache_bits; + if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + ok = 0; + goto End; + } + } else { + hdr->color_cache_size_ = 0; + } + UpdateDecoder(dec, transform_xsize, transform_ysize); + + if (is_level0) { // level 0 complete + dec->state_ = READ_HDR; + goto End; + } + + { + const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize; + data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data)); + if (data == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + ok = 0; + goto End; + } + } + + // Use the Huffman trees to decode the LZ77 encoded data. + ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL); + ok = ok && !br->error_; + + End: + + if (!ok) { + free(data); + ClearMetadata(hdr); + // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the + // status appropriately. + if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && dec->br_.eos_) { + dec->status_ = VP8_STATUS_SUSPENDED; + } + } else { + if (decoded_data != NULL) { + *decoded_data = data; + } else { + // We allocate image data in this function only for transforms. At level 0 + // (that is: not the transforms), we shouldn't have allocated anything. + assert(data == NULL); + assert(is_level0); + } + if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. + } + return ok; +} + +//------------------------------------------------------------------------------ +// Allocate dec->argb_ and dec->argb_cache_ using dec->width_ and dec->height_ + +static int AllocateARGBBuffers(VP8LDecoder* const dec, int final_width) { + const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; + // Scratch buffer corresponding to top-prediction row for transforming the + // first row in the row-blocks. + const uint64_t cache_top_pixels = final_width; + // Scratch buffer for temporary BGRA storage. + const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS; + const uint64_t total_num_pixels = + num_pixels + cache_top_pixels + cache_pixels; + + assert(dec->width_ <= final_width); + dec->argb_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(*dec->argb_)); + if (dec->argb_ == NULL) { + dec->argb_cache_ = NULL; // for sanity check + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + return 0; + } + dec->argb_cache_ = dec->argb_ + num_pixels + cache_top_pixels; + return 1; +} + +//------------------------------------------------------------------------------ +// Special row-processing that only stores the alpha data. + +static void ExtractAlphaRows(VP8LDecoder* const dec, int row) { + const int num_rows = row - dec->last_row_; + const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_; + + if (num_rows <= 0) return; // Nothing to be done. + ApplyInverseTransforms(dec, num_rows, in); + + // Extract alpha (which is stored in the green plane). + { + const int width = dec->io_->width; // the final width (!= dec->width_) + const int cache_pixs = width * num_rows; + uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_; + const uint32_t* const src = dec->argb_cache_; + int i; + for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff; + } + + dec->last_row_ = dec->last_out_row_ = row; +} + +int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data, + size_t data_size, uint8_t* const output) { + VP8Io io; + int ok = 0; + VP8LDecoder* const dec = VP8LNew(); + if (dec == NULL) return 0; + + dec->width_ = width; + dec->height_ = height; + dec->io_ = &io; + + VP8InitIo(&io); + WebPInitCustomIo(NULL, &io); // Just a sanity Init. io won't be used. + io.opaque = output; + io.width = width; + io.height = height; + + dec->status_ = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br_, data, data_size); + + dec->action_ = READ_HDR; + if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Err; + + // Allocate output (note that dec->width_ may have changed here). + if (!AllocateARGBBuffers(dec, width)) goto Err; + + // Decode (with special row processing). + dec->action_ = READ_DATA; + ok = DecodeImageData(dec, dec->argb_, dec->width_, dec->height_, + ExtractAlphaRows); + + Err: + VP8LDelete(dec); + return ok; +} + +//------------------------------------------------------------------------------ + +int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { + int width, height, has_alpha; + + if (dec == NULL) return 0; + if (io == NULL) { + dec->status_ = VP8_STATUS_INVALID_PARAM; + return 0; + } + + dec->io_ = io; + dec->status_ = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br_, io->data, io->data_size); + if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) { + dec->status_ = VP8_STATUS_BITSTREAM_ERROR; + goto Error; + } + dec->state_ = READ_DIM; + io->width = width; + io->height = height; + + dec->action_ = READ_HDR; + if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error; + return 1; + + Error: + VP8LClear(dec); + assert(dec->status_ != VP8_STATUS_OK); + return 0; +} + +int VP8LDecodeImage(VP8LDecoder* const dec) { + VP8Io* io = NULL; + WebPDecParams* params = NULL; + + // Sanity checks. + if (dec == NULL) return 0; + + io = dec->io_; + assert(io != NULL); + params = (WebPDecParams*)io->opaque; + assert(params != NULL); + dec->output_ = params->output; + assert(dec->output_ != NULL); + + // Initialization. + if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { + dec->status_ = VP8_STATUS_INVALID_PARAM; + goto Err; + } + + if (!AllocateARGBBuffers(dec, io->width)) goto Err; + + if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; + + // Decode. + dec->action_ = READ_DATA; + if (!DecodeImageData(dec, dec->argb_, dec->width_, dec->height_, + ProcessRows)) { + goto Err; + } + + // Cleanup. + params->last_y = dec->last_out_row_; + VP8LClear(dec); + return 1; + + Err: + VP8LClear(dec); + assert(dec->status_ != VP8_STATUS_OK); + return 0; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/vp8li.h b/external/libwebp/dec/vp8li.h new file mode 100644 index 0000000000..ee29eb5faf --- /dev/null +++ b/external/libwebp/dec/vp8li.h @@ -0,0 +1,121 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Lossless decoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora(vikaas.arora@gmail.com) + +#ifndef WEBP_DEC_VP8LI_H_ +#define WEBP_DEC_VP8LI_H_ + +#include // for memcpy() +#include "./webpi.h" +#include "../utils/bit_reader.h" +#include "../utils/color_cache.h" +#include "../utils/huffman.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef enum { + READ_DATA = 0, + READ_HDR = 1, + READ_DIM = 2 +} VP8LDecodeState; + +typedef struct VP8LTransform VP8LTransform; +struct VP8LTransform { + VP8LImageTransformType type_; // transform type. + int bits_; // subsampling bits defining transform window. + int xsize_; // transform window X index. + int ysize_; // transform window Y index. + uint32_t *data_; // transform data. +}; + +typedef struct { + HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE]; +} HTreeGroup; + +typedef struct { + int color_cache_size_; + VP8LColorCache color_cache_; + + int huffman_mask_; + int huffman_subsample_bits_; + int huffman_xsize_; + uint32_t *huffman_image_; + int num_htree_groups_; + HTreeGroup *htree_groups_; +} VP8LMetadata; + +typedef struct { + VP8StatusCode status_; + VP8LDecodeState action_; + VP8LDecodeState state_; + VP8Io *io_; + + const WebPDecBuffer *output_; // shortcut to io->opaque->output + + uint32_t *argb_; // Internal data: always in BGRA color mode. + uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage. + + VP8LBitReader br_; + + int width_; + int height_; + int last_row_; // last input row decoded so far. + int last_out_row_; // last row output so far. + + VP8LMetadata hdr_; + + int next_transform_; + VP8LTransform transforms_[NUM_TRANSFORMS]; + // or'd bitset storing the transforms types. + uint32_t transforms_seen_; + + uint8_t *rescaler_memory; // Working memory for rescaling work. + WebPRescaler *rescaler; // Common rescaler for all channels. +} VP8LDecoder; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// in vp8l.c + +// Decodes a raw image stream (without header) and store the alpha data +// into *output, which must be of size width x height. Returns false in case +// of error. +int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data, + size_t data_size, uint8_t* const output); + +// Allocates and initialize a new lossless decoder instance. +VP8LDecoder* VP8LNew(void); + +// Decodes the image header. Returns false in case of error. +int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io); + +// Decodes an image. It's required to decode the lossless header before calling +// this function. Returns false in case of error, with updated dec->status_. +int VP8LDecodeImage(VP8LDecoder* const dec); + +// Resets the decoder in its initial state, reclaiming memory. +// Preserves the dec->status_ value. +void VP8LClear(VP8LDecoder* const dec); + +// Clears and deallocate a lossless decoder instance. +void VP8LDelete(VP8LDecoder* const dec); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_DEC_VP8LI_H_ */ diff --git a/external/libwebp/dec/webp.c b/external/libwebp/dec/webp.c new file mode 100644 index 0000000000..7455da9415 --- /dev/null +++ b/external/libwebp/dec/webp.c @@ -0,0 +1,777 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Main decoding functions for WEBP images. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./vp8i.h" +#include "./vp8li.h" +#include "./webpi.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// RIFF layout is: +// Offset tag +// 0...3 "RIFF" 4-byte tag +// 4...7 size of image data (including metadata) starting at offset 8 +// 8...11 "WEBP" our form-type signature +// The RIFF container (12 bytes) is followed by appropriate chunks: +// 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format +// 16..19 size of the raw VP8 image data, starting at offset 20 +// 20.... the VP8 bytes +// Or, +// 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format +// 16..19 size of the raw VP8L image data, starting at offset 20 +// 20.... the VP8L bytes +// Or, +// 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk. +// 16..19 size of the VP8X chunk starting at offset 20. +// 20..23 VP8X flags bit-map corresponding to the chunk-types present. +// 24..26 Width of the Canvas Image. +// 27..29 Height of the Canvas Image. +// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, +// META ...) +// All sizes are in little-endian order. +// Note: chunk data size must be padded to multiple of 2 when written. + +static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) { + return data[0] | (data[1] << 8) | (data[2] << 16); +} + +static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) { + return (uint32_t)get_le24(data) | (data[3] << 24); +} + +// Validates the RIFF container (if detected) and skips over it. +// If a RIFF container is detected, +// Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and +// VP8_STATUS_OK otherwise. +// In case there are not enough bytes (partial RIFF container), return 0 for +// *riff_size. Else return the RIFF size extracted from the header. +static VP8StatusCode ParseRIFF(const uint8_t** const data, + size_t* const data_size, + size_t* const riff_size) { + assert(data != NULL); + assert(data_size != NULL); + assert(riff_size != NULL); + + *riff_size = 0; // Default: no RIFF present. + if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) { + if (memcmp(*data + 8, "WEBP", TAG_SIZE)) { + return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature. + } else { + const uint32_t size = get_le32(*data + TAG_SIZE); + // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn"). + if (size < TAG_SIZE + CHUNK_HEADER_SIZE) { + return VP8_STATUS_BITSTREAM_ERROR; + } + if (size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; + } + // We have a RIFF container. Skip it. + *riff_size = size; + *data += RIFF_HEADER_SIZE; + *data_size -= RIFF_HEADER_SIZE; + } + } + return VP8_STATUS_OK; +} + +// Validates the VP8X header and skips over it. +// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr, +// *height_ptr and *flags_ptr are set to the corresponding values extracted +// from the VP8X chunk. +static VP8StatusCode ParseVP8X(const uint8_t** const data, + size_t* const data_size, + int* const found_vp8x, + int* const width_ptr, int* const height_ptr, + uint32_t* const flags_ptr) { + const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + assert(data != NULL); + assert(data_size != NULL); + assert(found_vp8x != NULL); + + *found_vp8x = 0; + + if (*data_size < CHUNK_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + + if (!memcmp(*data, "VP8X", TAG_SIZE)) { + int width, height; + uint32_t flags; + const uint32_t chunk_size = get_le32(*data + TAG_SIZE); + if (chunk_size != VP8X_CHUNK_SIZE) { + return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size. + } + + // Verify if enough data is available to validate the VP8X chunk. + if (*data_size < vp8x_size) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + flags = get_le32(*data + 8); + width = 1 + get_le24(*data + 12); + height = 1 + get_le24(*data + 15); + if (width * (uint64_t)height >= MAX_IMAGE_AREA) { + return VP8_STATUS_BITSTREAM_ERROR; // image is too large + } + + if (flags_ptr != NULL) *flags_ptr = flags; + if (width_ptr != NULL) *width_ptr = width; + if (height_ptr != NULL) *height_ptr = height; + // Skip over VP8X header bytes. + *data += vp8x_size; + *data_size -= vp8x_size; + *found_vp8x = 1; + } + return VP8_STATUS_OK; +} + +// Skips to the next VP8/VP8L chunk header in the data given the size of the +// RIFF chunk 'riff_size'. +// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If an alpha chunk is found, *alpha_data and *alpha_size are set +// appropriately. +static VP8StatusCode ParseOptionalChunks(const uint8_t** const data, + size_t* const data_size, + size_t const riff_size, + const uint8_t** const alpha_data, + size_t* const alpha_size) { + const uint8_t* buf; + size_t buf_size; + uint32_t total_size = TAG_SIZE + // "WEBP". + CHUNK_HEADER_SIZE + // "VP8Xnnnn". + VP8X_CHUNK_SIZE; // data. + assert(data != NULL); + assert(data_size != NULL); + buf = *data; + buf_size = *data_size; + + assert(alpha_data != NULL); + assert(alpha_size != NULL); + *alpha_data = NULL; + *alpha_size = 0; + + while (1) { + uint32_t chunk_size; + uint32_t disk_chunk_size; // chunk_size with padding + + *data = buf; + *data_size = buf_size; + + if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + + chunk_size = get_le32(buf + TAG_SIZE); + if (chunk_size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size. + } + // For odd-sized chunk-payload, there's one byte padding at the end. + disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1; + total_size += disk_chunk_size; + + // Check that total bytes skipped so far does not exceed riff_size. + if (riff_size > 0 && (total_size > riff_size)) { + return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size. + } + + if (buf_size < disk_chunk_size) { // Insufficient data. + return VP8_STATUS_NOT_ENOUGH_DATA; + } + + if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header. + *alpha_data = buf + CHUNK_HEADER_SIZE; + *alpha_size = chunk_size; + } else if (!memcmp(buf, "VP8 ", TAG_SIZE) || + !memcmp(buf, "VP8L", TAG_SIZE)) { // A valid VP8/VP8L header. + return VP8_STATUS_OK; // Found. + } + + // We have a full and valid chunk; skip it. + buf += disk_chunk_size; + buf_size -= disk_chunk_size; + } +} + +// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it. +// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than +// riff_size) VP8/VP8L header, +// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and +// VP8_STATUS_OK otherwise. +// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes +// extracted from the VP8/VP8L chunk header. +// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data. +static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr, + size_t* const data_size, + size_t riff_size, + size_t* const chunk_size, + int* const is_lossless) { + const uint8_t* const data = *data_ptr; + const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE); + const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE); + const uint32_t minimal_size = + TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR + // "WEBP" + "VP8Lnnnn" + assert(data != NULL); + assert(data_size != NULL); + assert(chunk_size != NULL); + assert(is_lossless != NULL); + + if (*data_size < CHUNK_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data. + } + + if (is_vp8 || is_vp8l) { + // Bitstream contains VP8/VP8L header. + const uint32_t size = get_le32(data + TAG_SIZE); + if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) { + return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information. + } + // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header. + *chunk_size = size; + *data_ptr += CHUNK_HEADER_SIZE; + *data_size -= CHUNK_HEADER_SIZE; + *is_lossless = is_vp8l; + } else { + // Raw VP8/VP8L bitstream (no header). + *is_lossless = VP8LCheckSignature(data, *data_size); + *chunk_size = *data_size; + } + + return VP8_STATUS_OK; +} + +//------------------------------------------------------------------------------ + +// Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on +// 'data'. All the output parameters may be NULL. If 'headers' is NULL only the +// minimal amount will be read to fetch the remaining parameters. +// If 'headers' is non-NULL this function will attempt to locate both alpha +// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L). +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. +static VP8StatusCode ParseHeadersInternal(const uint8_t* data, + size_t data_size, + int* const width, + int* const height, + int* const has_alpha, + WebPHeaderStructure* const headers) { + int found_riff = 0; + int found_vp8x = 0; + VP8StatusCode status; + WebPHeaderStructure hdrs; + + if (data == NULL || data_size < RIFF_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; + } + memset(&hdrs, 0, sizeof(hdrs)); + hdrs.data = data; + hdrs.data_size = data_size; + + // Skip over RIFF header. + status = ParseRIFF(&data, &data_size, &hdrs.riff_size); + if (status != VP8_STATUS_OK) { + return status; // Wrong RIFF header / insufficient data. + } + found_riff = (hdrs.riff_size > 0); + + // Skip over VP8X. + { + uint32_t flags = 0; + status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags); + if (status != VP8_STATUS_OK) { + return status; // Wrong VP8X / insufficient data. + } + if (!found_riff && found_vp8x) { + // Note: This restriction may be removed in the future, if it becomes + // necessary to send VP8X chunk to the decoder. + return VP8_STATUS_BITSTREAM_ERROR; + } + if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT); + if (found_vp8x && headers == NULL) { + return VP8_STATUS_OK; // Return features from VP8X header. + } + } + + if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; + + // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". + if ((found_riff && found_vp8x) || + (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { + status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, + &hdrs.alpha_data, &hdrs.alpha_data_size); + if (status != VP8_STATUS_OK) { + return status; // Found an invalid chunk size / insufficient data. + } + } + + // Skip over VP8/VP8L header. + status = ParseVP8Header(&data, &data_size, hdrs.riff_size, + &hdrs.compressed_size, &hdrs.is_lossless); + if (status != VP8_STATUS_OK) { + return status; // Wrong VP8/VP8L chunk-header / insufficient data. + } + if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { + return VP8_STATUS_BITSTREAM_ERROR; + } + + if (!hdrs.is_lossless) { + if (data_size < VP8_FRAME_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; + } + // Validates raw VP8 data. + if (!VP8GetInfo(data, data_size, + (uint32_t)hdrs.compressed_size, width, height)) { + return VP8_STATUS_BITSTREAM_ERROR; + } + } else { + if (data_size < VP8L_FRAME_HEADER_SIZE) { + return VP8_STATUS_NOT_ENOUGH_DATA; + } + // Validates raw VP8L data. + if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) { + return VP8_STATUS_BITSTREAM_ERROR; + } + } + + if (has_alpha != NULL) { + // If the data did not contain a VP8X/VP8L chunk the only definitive way + // to set this is by looking for alpha data (from an ALPH chunk). + *has_alpha |= (hdrs.alpha_data != NULL); + } + if (headers != NULL) { + *headers = hdrs; + headers->offset = data - headers->data; + assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); + assert(headers->offset == headers->data_size - data_size); + } + return VP8_STATUS_OK; // Return features from VP8 header. +} + +VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) { + assert(headers != NULL); + // fill out headers, ignore width/height/has_alpha. + return ParseHeadersInternal(headers->data, headers->data_size, + NULL, NULL, NULL, headers); +} + +//------------------------------------------------------------------------------ +// WebPDecParams + +void WebPResetDecParams(WebPDecParams* const params) { + if (params) { + memset(params, 0, sizeof(*params)); + } +} + +//------------------------------------------------------------------------------ +// "Into" decoding variants + +// Main flow +static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size, + WebPDecParams* const params) { + VP8StatusCode status; + VP8Io io; + WebPHeaderStructure headers; + + headers.data = data; + headers.data_size = data_size; + status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks. + if (status != VP8_STATUS_OK) { + return status; + } + + assert(params != NULL); + VP8InitIo(&io); + io.data = headers.data + headers.offset; + io.data_size = headers.data_size - headers.offset; + WebPInitCustomIo(params, &io); // Plug the I/O functions. + + if (!headers.is_lossless) { + VP8Decoder* const dec = VP8New(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } +#ifdef WEBP_USE_THREAD + dec->use_threads_ = params->options && (params->options->use_threads > 0); +#else + dec->use_threads_ = 0; +#endif + dec->alpha_data_ = headers.alpha_data; + dec->alpha_data_size_ = headers.alpha_data_size; + + // Decode bitstream header, update io->width/io->height. + if (!VP8GetHeaders(dec, &io)) { + status = dec->status_; // An error occurred. Grab error status. + } else { + // Allocate/check output buffers. + status = WebPAllocateDecBuffer(io.width, io.height, params->options, + params->output); + if (status == VP8_STATUS_OK) { // Decode + if (!VP8Decode(dec, &io)) { + status = dec->status_; + } + } + } + VP8Delete(dec); + } else { + VP8LDecoder* const dec = VP8LNew(); + if (dec == NULL) { + return VP8_STATUS_OUT_OF_MEMORY; + } + if (!VP8LDecodeHeader(dec, &io)) { + status = dec->status_; // An error occurred. Grab error status. + } else { + // Allocate/check output buffers. + status = WebPAllocateDecBuffer(io.width, io.height, params->options, + params->output); + if (status == VP8_STATUS_OK) { // Decode + if (!VP8LDecodeImage(dec)) { + status = dec->status_; + } + } + } + VP8LDelete(dec); + } + + if (status != VP8_STATUS_OK) { + WebPFreeDecBuffer(params->output); + } + return status; +} + +// Helpers +static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace, + const uint8_t* const data, + size_t data_size, + uint8_t* const rgba, + int stride, size_t size) { + WebPDecParams params; + WebPDecBuffer buf; + if (rgba == NULL) { + return NULL; + } + WebPInitDecBuffer(&buf); + WebPResetDecParams(¶ms); + params.output = &buf; + buf.colorspace = colorspace; + buf.u.RGBA.rgba = rgba; + buf.u.RGBA.stride = stride; + buf.u.RGBA.size = size; + buf.is_external_memory = 1; + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + return rgba; +} + +uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size, + uint8_t* output, size_t size, int stride) { + return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size); +} + +uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride) { + WebPDecParams params; + WebPDecBuffer output; + if (luma == NULL) return NULL; + WebPInitDecBuffer(&output); + WebPResetDecParams(¶ms); + params.output = &output; + output.colorspace = MODE_YUV; + output.u.YUVA.y = luma; + output.u.YUVA.y_stride = luma_stride; + output.u.YUVA.y_size = luma_size; + output.u.YUVA.u = u; + output.u.YUVA.u_stride = u_stride; + output.u.YUVA.u_size = u_size; + output.u.YUVA.v = v; + output.u.YUVA.v_stride = v_stride; + output.u.YUVA.v_size = v_size; + output.is_external_memory = 1; + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + return luma; +} + +//------------------------------------------------------------------------------ + +static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data, + size_t data_size, int* const width, int* const height, + WebPDecBuffer* const keep_info) { + WebPDecParams params; + WebPDecBuffer output; + + WebPInitDecBuffer(&output); + WebPResetDecParams(¶ms); + params.output = &output; + output.colorspace = mode; + + // Retrieve (and report back) the required dimensions from bitstream. + if (!WebPGetInfo(data, data_size, &output.width, &output.height)) { + return NULL; + } + if (width != NULL) *width = output.width; + if (height != NULL) *height = output.height; + + // Decode + if (DecodeInto(data, data_size, ¶ms) != VP8_STATUS_OK) { + return NULL; + } + if (keep_info != NULL) { // keep track of the side-info + WebPCopyDecBuffer(&output, keep_info); + } + // return decoded samples (don't clear 'output'!) + return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y; +} + +uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_RGB, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_RGBA, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_ARGB, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_BGR, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, + int* width, int* height) { + return Decode(MODE_BGRA, data, data_size, width, height, NULL); +} + +uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, + int* width, int* height, uint8_t** u, uint8_t** v, + int* stride, int* uv_stride) { + WebPDecBuffer output; // only to preserve the side-infos + uint8_t* const out = Decode(MODE_YUV, data, data_size, + width, height, &output); + + if (out != NULL) { + const WebPYUVABuffer* const buf = &output.u.YUVA; + *u = buf->u; + *v = buf->v; + *stride = buf->y_stride; + *uv_stride = buf->u_stride; + assert(buf->u_stride == buf->v_stride); + } + return out; +} + +static void DefaultFeatures(WebPBitstreamFeatures* const features) { + assert(features != NULL); + memset(features, 0, sizeof(*features)); + features->bitstream_version = 0; +} + +static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size, + WebPBitstreamFeatures* const features) { + if (features == NULL || data == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + DefaultFeatures(features); + + // Only parse enough of the data to retrieve width/height/has_alpha. + return ParseHeadersInternal(data, data_size, + &features->width, &features->height, + &features->has_alpha, NULL); +} + +//------------------------------------------------------------------------------ +// WebPGetInfo() + +int WebPGetInfo(const uint8_t* data, size_t data_size, + int* width, int* height) { + WebPBitstreamFeatures features; + + if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) { + return 0; + } + + if (width != NULL) { + *width = features.width; + } + if (height != NULL) { + *height = features.height; + } + + return 1; +} + +//------------------------------------------------------------------------------ +// Advance decoding API + +int WebPInitDecoderConfigInternal(WebPDecoderConfig* config, + int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return 0; // version mismatch + } + if (config == NULL) { + return 0; + } + memset(config, 0, sizeof(*config)); + DefaultFeatures(&config->input); + WebPInitDecBuffer(&config->output); + return 1; +} + +VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, + WebPBitstreamFeatures* features, + int version) { + VP8StatusCode status; + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) { + return VP8_STATUS_INVALID_PARAM; // version mismatch + } + if (features == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + + status = GetFeatures(data, data_size, features); + if (status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error. + } + return status; +} + +VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config) { + WebPDecParams params; + VP8StatusCode status; + + if (config == NULL) { + return VP8_STATUS_INVALID_PARAM; + } + + status = GetFeatures(data, data_size, &config->input); + if (status != VP8_STATUS_OK) { + if (status == VP8_STATUS_NOT_ENOUGH_DATA) { + return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error. + } + return status; + } + + WebPResetDecParams(¶ms); + params.output = &config->output; + params.options = &config->options; + status = DecodeInto(data, data_size, ¶ms); + + return status; +} + +//------------------------------------------------------------------------------ +// Cropping and rescaling. + +int WebPIoInitFromOptions(const WebPDecoderOptions* const options, + VP8Io* const io, WEBP_CSP_MODE src_colorspace) { + const int W = io->width; + const int H = io->height; + int x = 0, y = 0, w = W, h = H; + + // Cropping + io->use_cropping = (options != NULL) && (options->use_cropping > 0); + if (io->use_cropping) { + w = options->crop_width; + h = options->crop_height; + x = options->crop_left; + y = options->crop_top; + if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420 or YUV422 + x &= ~1; + y &= ~1; // TODO(later): only for YUV420, not YUV422. + } + if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) { + return 0; // out of frame boundary error + } + } + io->crop_left = x; + io->crop_top = y; + io->crop_right = x + w; + io->crop_bottom = y + h; + io->mb_w = w; + io->mb_h = h; + + // Scaling + io->use_scaling = (options != NULL) && (options->use_scaling > 0); + if (io->use_scaling) { + if (options->scaled_width <= 0 || options->scaled_height <= 0) { + return 0; + } + io->scaled_width = options->scaled_width; + io->scaled_height = options->scaled_height; + } + + // Filter + io->bypass_filtering = options && options->bypass_filtering; + + // Fancy upsampler +#ifdef FANCY_UPSAMPLING + io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling); +#endif + + if (io->use_scaling) { + // disable filter (only for large downscaling ratio). + io->bypass_filtering = (io->scaled_width < W * 3 / 4) && + (io->scaled_height < H * 3 / 4); + io->fancy_upsampling = 0; + } + return 1; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dec/webpi.h b/external/libwebp/dec/webpi.h new file mode 100644 index 0000000000..44e5744411 --- /dev/null +++ b/external/libwebp/dec/webpi.h @@ -0,0 +1,114 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Internal header: WebP decoding parameters and custom IO on buffer +// +// Author: somnath@google.com (Somnath Banerjee) + +#ifndef WEBP_DEC_WEBPI_H_ +#define WEBP_DEC_WEBPI_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "../utils/rescaler.h" +#include "./decode_vp8.h" + +//------------------------------------------------------------------------------ +// WebPDecParams: Decoding output parameters. Transient internal object. + +typedef struct WebPDecParams WebPDecParams; +typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p); +typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos); + +struct WebPDecParams { + WebPDecBuffer* output; // output buffer. + uint8_t* tmp_y, *tmp_u, *tmp_v; // cache for the fancy upsampler + // or used for tmp rescaling + + int last_y; // coordinate of the line that was last output + const WebPDecoderOptions* options; // if not NULL, use alt decoding features + // rescalers + WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a; + void* memory; // overall scratch memory for the output work. + + OutputFunc emit; // output RGB or YUV samples + OutputFunc emit_alpha; // output alpha channel + OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values +}; + +// Should be called first, before any use of the WebPDecParams object. +void WebPResetDecParams(WebPDecParams* const params); + +//------------------------------------------------------------------------------ +// Header parsing helpers + +// Structure storing a description of the RIFF headers. +typedef struct { + const uint8_t* data; // input buffer + size_t data_size; // input buffer size + size_t offset; // offset to main data chunk (VP8 or VP8L) + const uint8_t* alpha_data; // points to alpha chunk (if present) + size_t alpha_data_size; // alpha chunk size + size_t compressed_size; // VP8/VP8L compressed data size + size_t riff_size; // size of the riff payload (or 0 if absent) + int is_lossless; // true if a VP8L chunk is present +} WebPHeaderStructure; + +// Skips over all valid chunks prior to the first VP8/VP8L frame header. +// Returns VP8_STATUS_OK on success, +// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and +// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data. +// In 'headers', compressed_size, offset, alpha_data, alpha_size and lossless +// fields are updated appropriately upon success. +VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers); + +//------------------------------------------------------------------------------ +// Misc utils + +// Initializes VP8Io with custom setup, io and teardown functions. The default +// hooks will use the supplied 'params' as io->opaque handle. +void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io); + +// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers +// to the *compressed* format, not the output one. +int WebPIoInitFromOptions(const WebPDecoderOptions* const options, + VP8Io* const io, WEBP_CSP_MODE src_colorspace); + +//------------------------------------------------------------------------------ +// Internal functions regarding WebPDecBuffer memory (in buffer.c). +// Don't really need to be externally visible for now. + +// Prepare 'buffer' with the requested initial dimensions width/height. +// If no external storage is supplied, initializes buffer by allocating output +// memory and setting up the stride information. Validate the parameters. Return +// an error code in case of problem (no memory, or invalid stride / size / +// dimension / etc.). If *options is not NULL, also verify that the options' +// parameters are valid and apply them to the width/height dimensions of the +// output buffer. This takes cropping / scaling / rotation into account. +VP8StatusCode WebPAllocateDecBuffer(int width, int height, + const WebPDecoderOptions* const options, + WebPDecBuffer* const buffer); + +// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the +// memory (still held by 'src'). +void WebPCopyDecBuffer(const WebPDecBuffer* const src, + WebPDecBuffer* const dst); + +// Copy and transfer ownership from src to dst (beware of parameter order!) +void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst); + + + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_DEC_WEBPI_H_ */ diff --git a/external/libwebp/dsp/Makefile.am b/external/libwebp/dsp/Makefile.am new file mode 100644 index 0000000000..c9dd7a552d --- /dev/null +++ b/external/libwebp/dsp/Makefile.am @@ -0,0 +1,26 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src +noinst_LTLIBRARIES = libwebpdsp.la + +libwebpdsp_la_SOURCES = +libwebpdsp_la_SOURCES += cpu.c +libwebpdsp_la_SOURCES += dec.c +libwebpdsp_la_SOURCES += dec_neon.c +libwebpdsp_la_SOURCES += dec_sse2.c +libwebpdsp_la_SOURCES += dsp.h +libwebpdsp_la_SOURCES += enc.c +libwebpdsp_la_SOURCES += enc_sse2.c +libwebpdsp_la_SOURCES += lossless.c +libwebpdsp_la_SOURCES += lossless.h +libwebpdsp_la_SOURCES += upsampling.c +libwebpdsp_la_SOURCES += upsampling_sse2.c +libwebpdsp_la_SOURCES += yuv.c +libwebpdsp_la_SOURCES += yuv.h + +libwebpdspinclude_HEADERS = ../webp/types.h +noinst_HEADERS = +noinst_HEADERS += ../dec/decode_vp8.h +noinst_HEADERS += ../webp/decode.h + +libwebpdsp_la_LDFLAGS = -lm +libwebpdsp_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) +libwebpdspincludedir = $(includedir)/webp diff --git a/external/libwebp/dsp/cpu.c b/external/libwebp/dsp/cpu.c new file mode 100644 index 0000000000..4e7845c7d2 --- /dev/null +++ b/external/libwebp/dsp/cpu.c @@ -0,0 +1,87 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// CPU detection +// +// Author: Christian Duvivier (cduvivier@google.com) + +#include "platform/CCPlatformConfig.h" + +#include "./dsp.h" + +#if defined(__ANDROID__) +#include +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// SSE2 detection. +// + +// apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC. +#if (defined(__pic__) || defined(__PIC__)) && defined(__i386__) +static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { + __asm__ volatile ( + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#elif (defined(__i386__) || defined(__x86_64__) ) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) +static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) { + __asm__ volatile ( + "cpuid\n" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#elif defined(WEBP_MSC_SSE2) +#define GetCPUInfo __cpuid +#endif + +#if (defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) +static int x86CPUInfo(CPUFeature feature) { + int cpu_info[4]; + GetCPUInfo(cpu_info, 1); + if (feature == kSSE2) { + return 0 != (cpu_info[3] & 0x04000000); + } + if (feature == kSSE3) { + return 0 != (cpu_info[2] & 0x00000001); + } + return 0; +} +VP8CPUInfo VP8GetCPUInfo = x86CPUInfo; +#elif defined(WEBP_ANDROID_NEON) +static int AndroidCPUInfo(CPUFeature feature) { + const AndroidCpuFamily cpu_family = android_getCpuFamily(); + const uint64_t cpu_features = android_getCpuFeatures(); + if (feature == kNEON) { + return (cpu_family == ANDROID_CPU_FAMILY_ARM && + 0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)); + } + return 0; +} +VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo; +#elif defined(__ARM_NEON__) +// define a dummy function to enable turning off NEON at runtime by setting +// VP8DecGetCPUInfo = NULL +static int armCPUInfo(CPUFeature feature) { + (void)feature; + return 1; +} +VP8CPUInfo VP8GetCPUInfo = armCPUInfo; +#else +VP8CPUInfo VP8GetCPUInfo = NULL; +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/dec.c b/external/libwebp/dsp/dec.c new file mode 100644 index 0000000000..9ae7b6fa76 --- /dev/null +++ b/external/libwebp/dsp/dec.c @@ -0,0 +1,732 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Speed-critical decoding functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./dsp.h" +#include "../dec/vp8i.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// run-time tables (~4k) + +static uint8_t abs0[255 + 255 + 1]; // abs(i) +static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1 +static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127] +static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15] +static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255] + +// We declare this variable 'volatile' to prevent instruction reordering +// and make sure it's set to true _last_ (so as to be thread-safe) +static volatile int tables_ok = 0; + +static void DspInitTables(void) { + if (!tables_ok) { + int i; + for (i = -255; i <= 255; ++i) { + abs0[255 + i] = (i < 0) ? -i : i; + abs1[255 + i] = abs0[255 + i] >> 1; + } + for (i = -1020; i <= 1020; ++i) { + sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i; + } + for (i = -112; i <= 112; ++i) { + sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i; + } + for (i = -255; i <= 255 + 255; ++i) { + clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i; + } + tables_ok = 1; + } +} + +static WEBP_INLINE uint8_t clip_8b(int v) { + return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; +} + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +#define STORE(x, y, v) \ + dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3)) + +static const int kC1 = 20091 + (1 << 16); +static const int kC2 = 35468; +#define MUL(a, b) (((a) * (b)) >> 16) + +static void TransformOne(const int16_t* in, uint8_t* dst) { + int C[4 * 4], *tmp; + int i; + tmp = C; + for (i = 0; i < 4; ++i) { // vertical pass + const int a = in[0] + in[8]; // [-4096, 4094] + const int b = in[0] - in[8]; // [-4095, 4095] + const int c = MUL(in[4], kC2) - MUL(in[12], kC1); // [-3783, 3783] + const int d = MUL(in[4], kC1) + MUL(in[12], kC2); // [-3785, 3781] + tmp[0] = a + d; // [-7881, 7875] + tmp[1] = b + c; // [-7878, 7878] + tmp[2] = b - c; // [-7878, 7878] + tmp[3] = a - d; // [-7877, 7879] + tmp += 4; + in++; + } + // Each pass is expanding the dynamic range by ~3.85 (upper bound). + // The exact value is (2. + (kC1 + kC2) / 65536). + // After the second pass, maximum interval is [-3794, 3794], assuming + // an input in [-2048, 2047] interval. We then need to add a dst value + // in the [0, 255] range. + // In the worst case scenario, the input to clip_8b() can be as large as + // [-60713, 60968]. + tmp = C; + for (i = 0; i < 4; ++i) { // horizontal pass + const int dc = tmp[0] + 4; + const int a = dc + tmp[8]; + const int b = dc - tmp[8]; + const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1); + const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2); + STORE(0, 0, a + d); + STORE(1, 0, b + c); + STORE(2, 0, b - c); + STORE(3, 0, a - d); + tmp++; + dst += BPS; + } +} +#undef MUL + +static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { + TransformOne(in, dst); + if (do_two) { + TransformOne(in + 16, dst + 4); + } +} + +static void TransformUV(const int16_t* in, uint8_t* dst) { + VP8Transform(in + 0 * 16, dst, 1); + VP8Transform(in + 2 * 16, dst + 4 * BPS, 1); +} + +static void TransformDC(const int16_t *in, uint8_t* dst) { + const int DC = in[0] + 4; + int i, j; + for (j = 0; j < 4; ++j) { + for (i = 0; i < 4; ++i) { + STORE(i, j, DC); + } + } +} + +static void TransformDCUV(const int16_t* in, uint8_t* dst) { + if (in[0 * 16]) TransformDC(in + 0 * 16, dst); + if (in[1 * 16]) TransformDC(in + 1 * 16, dst + 4); + if (in[2 * 16]) TransformDC(in + 2 * 16, dst + 4 * BPS); + if (in[3 * 16]) TransformDC(in + 3 * 16, dst + 4 * BPS + 4); +} + +#undef STORE + +//------------------------------------------------------------------------------ +// Paragraph 14.3 + +static void TransformWHT(const int16_t* in, int16_t* out) { + int tmp[16]; + int i; + for (i = 0; i < 4; ++i) { + const int a0 = in[0 + i] + in[12 + i]; + const int a1 = in[4 + i] + in[ 8 + i]; + const int a2 = in[4 + i] - in[ 8 + i]; + const int a3 = in[0 + i] - in[12 + i]; + tmp[0 + i] = a0 + a1; + tmp[8 + i] = a0 - a1; + tmp[4 + i] = a3 + a2; + tmp[12 + i] = a3 - a2; + } + for (i = 0; i < 4; ++i) { + const int dc = tmp[0 + i * 4] + 3; // w/ rounder + const int a0 = dc + tmp[3 + i * 4]; + const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4]; + const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4]; + const int a3 = dc - tmp[3 + i * 4]; + out[ 0] = (a0 + a1) >> 3; + out[16] = (a3 + a2) >> 3; + out[32] = (a0 - a1) >> 3; + out[48] = (a3 - a2) >> 3; + out += 64; + } +} + +void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT; + +//------------------------------------------------------------------------------ +// Intra predictions + +#define DST(x, y) dst[(x) + (y) * BPS] + +static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) { + const uint8_t* top = dst - BPS; + const uint8_t* const clip0 = clip1 + 255 - top[-1]; + int y; + for (y = 0; y < size; ++y) { + const uint8_t* const clip = clip0 + dst[-1]; + int x; + for (x = 0; x < size; ++x) { + dst[x] = clip[top[x]]; + } + dst += BPS; + } +} +static void TM4(uint8_t *dst) { TrueMotion(dst, 4); } +static void TM8uv(uint8_t *dst) { TrueMotion(dst, 8); } +static void TM16(uint8_t *dst) { TrueMotion(dst, 16); } + +//------------------------------------------------------------------------------ +// 16x16 + +static void VE16(uint8_t *dst) { // vertical + int j; + for (j = 0; j < 16; ++j) { + memcpy(dst + j * BPS, dst - BPS, 16); + } +} + +static void HE16(uint8_t *dst) { // horizontal + int j; + for (j = 16; j > 0; --j) { + memset(dst, dst[-1], 16); + dst += BPS; + } +} + +static WEBP_INLINE void Put16(int v, uint8_t* dst) { + int j; + for (j = 0; j < 16; ++j) { + memset(dst + j * BPS, v, 16); + } +} + +static void DC16(uint8_t *dst) { // DC + int DC = 16; + int j; + for (j = 0; j < 16; ++j) { + DC += dst[-1 + j * BPS] + dst[j - BPS]; + } + Put16(DC >> 5, dst); +} + +static void DC16NoTop(uint8_t *dst) { // DC with top samples not available + int DC = 8; + int j; + for (j = 0; j < 16; ++j) { + DC += dst[-1 + j * BPS]; + } + Put16(DC >> 4, dst); +} + +static void DC16NoLeft(uint8_t *dst) { // DC with left samples not available + int DC = 8; + int i; + for (i = 0; i < 16; ++i) { + DC += dst[i - BPS]; + } + Put16(DC >> 4, dst); +} + +static void DC16NoTopLeft(uint8_t *dst) { // DC with no top and left samples + Put16(0x80, dst); +} + +//------------------------------------------------------------------------------ +// 4x4 + +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +static void VE4(uint8_t *dst) { // vertical + const uint8_t* top = dst - BPS; + const uint8_t vals[4] = { + AVG3(top[-1], top[0], top[1]), + AVG3(top[ 0], top[1], top[2]), + AVG3(top[ 1], top[2], top[3]), + AVG3(top[ 2], top[3], top[4]) + }; + int i; + for (i = 0; i < 4; ++i) { + memcpy(dst + i * BPS, vals, sizeof(vals)); + } +} + +static void HE4(uint8_t *dst) { // horizontal + const int A = dst[-1 - BPS]; + const int B = dst[-1]; + const int C = dst[-1 + BPS]; + const int D = dst[-1 + 2 * BPS]; + const int E = dst[-1 + 3 * BPS]; + *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(A, B, C); + *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(B, C, D); + *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(C, D, E); + *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(D, E, E); +} + +static void DC4(uint8_t *dst) { // DC + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS]; + dc >>= 3; + for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4); +} + +static void RD4(uint8_t *dst) { // Down-right + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + DST(0, 3) = AVG3(J, K, L); + DST(0, 2) = DST(1, 3) = AVG3(I, J, K); + DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J); + DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I); + DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X); + DST(2, 0) = DST(3, 1) = AVG3(C, B, A); + DST(3, 0) = AVG3(D, C, B); +} + +static void LD4(uint8_t *dst) { // Down-Left + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + const int E = dst[4 - BPS]; + const int F = dst[5 - BPS]; + const int G = dst[6 - BPS]; + const int H = dst[7 - BPS]; + DST(0, 0) = AVG3(A, B, C); + DST(1, 0) = DST(0, 1) = AVG3(B, C, D); + DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E); + DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F); + DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G); + DST(3, 2) = DST(2, 3) = AVG3(F, G, H); + DST(3, 3) = AVG3(G, H, H); +} + +static void VR4(uint8_t *dst) { // Vertical-Right + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static void VL4(uint8_t *dst) { // Vertical-Left + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + const int D = dst[3 - BPS]; + const int E = dst[4 - BPS]; + const int F = dst[5 - BPS]; + const int G = dst[6 - BPS]; + const int H = dst[7 - BPS]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static void HU4(uint8_t *dst) { // Horizontal-Up + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static void HD4(uint8_t *dst) { // Horizontal-Down + const int I = dst[-1 + 0 * BPS]; + const int J = dst[-1 + 1 * BPS]; + const int K = dst[-1 + 2 * BPS]; + const int L = dst[-1 + 3 * BPS]; + const int X = dst[-1 - BPS]; + const int A = dst[0 - BPS]; + const int B = dst[1 - BPS]; + const int C = dst[2 - BPS]; + + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +#undef DST +#undef AVG3 +#undef AVG2 + +//------------------------------------------------------------------------------ +// Chroma + +static void VE8uv(uint8_t *dst) { // vertical + int j; + for (j = 0; j < 8; ++j) { + memcpy(dst + j * BPS, dst - BPS, 8); + } +} + +static void HE8uv(uint8_t *dst) { // horizontal + int j; + for (j = 0; j < 8; ++j) { + memset(dst, dst[-1], 8); + dst += BPS; + } +} + +// helper for chroma-DC predictions +static WEBP_INLINE void Put8x8uv(uint64_t v, uint8_t* dst) { + int j; + for (j = 0; j < 8; ++j) { + *(uint64_t*)(dst + j * BPS) = v; + } +} + +static void DC8uv(uint8_t *dst) { // DC + int dc0 = 8; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[i - BPS] + dst[-1 + i * BPS]; + } + Put8x8uv((uint64_t)((dc0 >> 4) * 0x0101010101010101ULL), dst); +} + +static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples + int dc0 = 4; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[i - BPS]; + } + Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst); +} + +static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples + int dc0 = 4; + int i; + for (i = 0; i < 8; ++i) { + dc0 += dst[-1 + i * BPS]; + } + Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst); +} + +static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing + Put8x8uv(0x8080808080808080ULL, dst); +} + +//------------------------------------------------------------------------------ +// default C implementations + +const VP8PredFunc VP8PredLuma4[NUM_BMODES] = { + DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4 +}; + +const VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES] = { + DC16, TM16, VE16, HE16, + DC16NoTop, DC16NoLeft, DC16NoTopLeft +}; + +const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = { + DC8uv, TM8uv, VE8uv, HE8uv, + DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft +}; + +//------------------------------------------------------------------------------ +// Edge filtering functions + +// 4 pixels in, 2 pixels out +static WEBP_INLINE void do_filter2(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1]; + const int a1 = sclip2[112 + ((a + 4) >> 3)]; + const int a2 = sclip2[112 + ((a + 3) >> 3)]; + p[-step] = clip1[255 + p0 + a2]; + p[ 0] = clip1[255 + q0 - a1]; +} + +// 4 pixels in, 4 pixels out +static WEBP_INLINE void do_filter4(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0); + const int a1 = sclip2[112 + ((a + 4) >> 3)]; + const int a2 = sclip2[112 + ((a + 3) >> 3)]; + const int a3 = (a1 + 1) >> 1; + p[-2*step] = clip1[255 + p1 + a3]; + p[- step] = clip1[255 + p0 + a2]; + p[ 0] = clip1[255 + q0 - a1]; + p[ step] = clip1[255 + q1 - a3]; +} + +// 6 pixels in, 6 pixels out +static WEBP_INLINE void do_filter6(uint8_t* p, int step) { + const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2*step]; + const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]]; + const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7 + const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7 + const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7 + p[-3*step] = clip1[255 + p2 + a3]; + p[-2*step] = clip1[255 + p1 + a2]; + p[- step] = clip1[255 + p0 + a1]; + p[ 0] = clip1[255 + q0 - a1]; + p[ step] = clip1[255 + q1 - a2]; + p[ 2*step] = clip1[255 + q2 - a3]; +} + +static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh); +} + +static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh; +} + +static WEBP_INLINE int needs_filter2(const uint8_t* p, + int step, int t, int it) { + const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step]; + if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t) + return 0; + return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it && + abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it && + abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it; +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16(uint8_t* p, int stride, int thresh) { + int i; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i, stride, thresh)) { + do_filter2(p + i, stride); + } + } +} + +static void SimpleHFilter16(uint8_t* p, int stride, int thresh) { + int i; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i * stride, 1, thresh)) { + do_filter2(p + i * stride, 1); + } + } +} + +static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16(p, stride, thresh); + } +} + +static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16(p, stride, thresh); + } +} + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +static WEBP_INLINE void FilterLoop26(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + while (size-- > 0) { + if (needs_filter2(p, hstride, thresh, ithresh)) { + if (hev(p, hstride, hev_thresh)) { + do_filter2(p, hstride); + } else { + do_filter6(p, hstride); + } + } + p += vstride; + } +} + +static WEBP_INLINE void FilterLoop24(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + while (size-- > 0) { + if (needs_filter2(p, hstride, thresh, ithresh)) { + if (hev(p, hstride, hev_thresh)) { + do_filter2(p, hstride); + } else { + do_filter4(p, hstride); + } + } + p += vstride; + } +} + +// on macroblock edges +static void VFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh); +} + +static void HFilter16(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh); +} + +// on three inner edges +static void VFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh); + } +} + +static void HFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh); + } +} + +// 8-pixels wide variant, for chroma filtering +static void VFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +static void VFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +//------------------------------------------------------------------------------ + +VP8DecIdct2 VP8Transform; +VP8DecIdct VP8TransformUV; +VP8DecIdct VP8TransformDC; +VP8DecIdct VP8TransformDCUV; + +VP8LumaFilterFunc VP8VFilter16; +VP8LumaFilterFunc VP8HFilter16; +VP8ChromaFilterFunc VP8VFilter8; +VP8ChromaFilterFunc VP8HFilter8; +VP8LumaFilterFunc VP8VFilter16i; +VP8LumaFilterFunc VP8HFilter16i; +VP8ChromaFilterFunc VP8VFilter8i; +VP8ChromaFilterFunc VP8HFilter8i; +VP8SimpleFilterFunc VP8SimpleVFilter16; +VP8SimpleFilterFunc VP8SimpleHFilter16; +VP8SimpleFilterFunc VP8SimpleVFilter16i; +VP8SimpleFilterFunc VP8SimpleHFilter16i; + +extern void VP8DspInitSSE2(void); +extern void VP8DspInitNEON(void); + +void VP8DspInit(void) { + DspInitTables(); + + VP8Transform = TransformTwo; + VP8TransformUV = TransformUV; + VP8TransformDC = TransformDC; + VP8TransformDCUV = TransformDCUV; + + VP8VFilter16 = VFilter16; + VP8HFilter16 = HFilter16; + VP8VFilter8 = VFilter8; + VP8HFilter8 = HFilter8; + VP8VFilter16i = VFilter16i; + VP8HFilter16i = HFilter16i; + VP8VFilter8i = VFilter8i; + VP8HFilter8i = HFilter8i; + VP8SimpleVFilter16 = SimpleVFilter16; + VP8SimpleHFilter16 = SimpleHFilter16; + VP8SimpleVFilter16i = SimpleVFilter16i; + VP8SimpleHFilter16i = SimpleHFilter16i; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo) { +#if defined(WEBP_USE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8DspInitSSE2(); + } +#elif defined(WEBP_USE_NEON) + if (VP8GetCPUInfo(kNEON)) { + VP8DspInitNEON(); + } +#endif + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/dec_neon.c b/external/libwebp/dsp/dec_neon.c new file mode 100644 index 0000000000..09cafeef1c --- /dev/null +++ b/external/libwebp/dsp/dec_neon.c @@ -0,0 +1,334 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// ARM NEON version of dsp functions and loop filtering. +// +// Authors: Somnath Banerjee (somnath@google.com) +// Johann Koenig (johannkoenig@google.com) + +#include "./dsp.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if defined(WEBP_USE_NEON) + +#include "../dec/vp8i.h" + +#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \ + "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" + +#define FLIP_SIGN_BIT2(a, b, s) \ + "veor " #a "," #a "," #s " \n" \ + "veor " #b "," #b "," #s " \n" \ + +#define FLIP_SIGN_BIT4(a, b, c, d, s) \ + FLIP_SIGN_BIT2(a, b, s) \ + FLIP_SIGN_BIT2(c, d, s) \ + +#define NEEDS_FILTER(p1, p0, q0, q1, thresh, mask) \ + "vabd.u8 q15," #p0 "," #q0 " \n" /* abs(p0 - q0) */ \ + "vabd.u8 q14," #p1 "," #q1 " \n" /* abs(p1 - q1) */ \ + "vqadd.u8 q15, q15, q15 \n" /* abs(p0 - q0) * 2 */ \ + "vshr.u8 q14, q14, #1 \n" /* abs(p1 - q1) / 2 */ \ + "vqadd.u8 q15, q15, q14 \n" /* abs(p0 - q0) * 2 + abs(p1 - q1) / 2 */ \ + "vdup.8 q14, " #thresh " \n" \ + "vcge.u8 " #mask ", q14, q15 \n" /* mask <= thresh */ + +#define GET_BASE_DELTA(p1, p0, q0, q1, o) \ + "vqsub.s8 q15," #q0 "," #p0 " \n" /* (q0 - p0) */ \ + "vqsub.s8 " #o "," #p1 "," #q1 " \n" /* (p1 - q1) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 1 * (p0 - q0) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 2 * (p0 - q0) */ \ + "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 3 * (p0 - q0) */ + +#define DO_SIMPLE_FILTER(p0, q0, fl) \ + "vmov.i8 q15, #0x03 \n" \ + "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 3 */ \ + "vshr.s8 q15, q15, #3 \n" /* filter1 >> 3 */ \ + "vqadd.s8 " #p0 "," #p0 ", q15 \n" /* p0 += filter1 */ \ + \ + "vmov.i8 q15, #0x04 \n" \ + "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 4 */ \ + "vshr.s8 q15, q15, #3 \n" /* filter2 >> 3 */ \ + "vqsub.s8 " #q0 "," #q0 ", q15 \n" /* q0 -= filter2 */ + +// Applies filter on 2 pixels (p0 and q0) +#define DO_FILTER2(p1, p0, q0, q1, thresh) \ + NEEDS_FILTER(p1, p0, q0, q1, thresh, q9) /* filter mask in q9 */ \ + "vmov.i8 q10, #0x80 \n" /* sign bit */ \ + FLIP_SIGN_BIT4(p1, p0, q0, q1, q10) /* convert to signed value */ \ + GET_BASE_DELTA(p1, p0, q0, q1, q11) /* get filter level */ \ + "vand q9, q9, q11 \n" /* apply filter mask */ \ + DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \ + FLIP_SIGN_BIT2(p0, q0, q10) + +// Load/Store vertical edge +#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \ + "vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \ + "vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \ + "vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \ + "vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \ + "vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \ + "vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \ + "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \ + "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n" + +#define STORE8x2(c1, c2, p,stride) \ + "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \ + "vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n" + +//----------------------------------------------------------------------------- +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) { + __asm__ volatile ( + "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride + + "vld1.u8 {q1}, [%[p]], %[stride] \n" // p1 + "vld1.u8 {q2}, [%[p]], %[stride] \n" // p0 + "vld1.u8 {q3}, [%[p]], %[stride] \n" // q0 + "vld1.u8 {q4}, [%[p]] \n" // q1 + + DO_FILTER2(q1, q2, q3, q4, %[thresh]) + + "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride + + "vst1.u8 {q2}, [%[p]], %[stride] \n" // store op0 + "vst1.u8 {q3}, [%[p]] \n" // store oq0 + : [p] "+r"(p) + : [stride] "r"(stride), [thresh] "r"(thresh) + : "memory", QRegs + ); +} + +static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) { + __asm__ volatile ( + "sub r4, %[p], #2 \n" // base1 = p - 2 + "lsl r6, %[stride], #1 \n" // r6 = 2 * stride + "add r5, r4, %[stride] \n" // base2 = base1 + stride + + LOAD8x4(d2, d3, d4, d5, [r4], [r5], r6) + LOAD8x4(d6, d7, d8, d9, [r4], [r5], r6) + "vswp d3, d6 \n" // p1:q1 p0:q3 + "vswp d5, d8 \n" // q0:q2 q1:q4 + "vswp q2, q3 \n" // p1:q1 p0:q2 q0:q3 q1:q4 + + DO_FILTER2(q1, q2, q3, q4, %[thresh]) + + "sub %[p], %[p], #1 \n" // p - 1 + + "vswp d5, d6 \n" + STORE8x2(d4, d5, [%[p]], %[stride]) + STORE8x2(d6, d7, [%[p]], %[stride]) + + : [p] "+r"(p) + : [stride] "r"(stride), [thresh] "r"(thresh) + : "memory", "r4", "r5", "r6", QRegs + ); +} + +static void SimpleVFilter16iNEON(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16NEON(p, stride, thresh); + } +} + +static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16NEON(p, stride, thresh); + } +} + +static void TransformOneNEON(const int16_t *in, uint8_t *dst) { + const int kBPS = BPS; + const int16_t constants[] = {20091, 17734, 0, 0}; + /* kC1, kC2. Padded because vld1.16 loads 8 bytes + * Technically these are unsigned but vqdmulh is only available in signed. + * vqdmulh returns high half (effectively >> 16) but also doubles the value, + * changing the >> 16 to >> 15 and requiring an additional >> 1. + * We use this to our advantage with kC2. The canonical value is 35468. + * However, the high bit is set so treating it as signed will give incorrect + * results. We avoid this by down shifting by 1 here to clear the highest bit. + * Combined with the doubling effect of vqdmulh we get >> 16. + * This can not be applied to kC1 because the lowest bit is set. Down shifting + * the constant would reduce precision. + */ + + /* libwebp uses a trick to avoid some extra addition that libvpx does. + * Instead of: + * temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16); + * libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the + * same issue with kC1 and vqdmulh that we work around by down shifting kC2 + */ + + /* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */ + __asm__ volatile ( + "vld1.16 {q1, q2}, [%[in]] \n" + "vld1.16 {d0}, [%[constants]] \n" + + /* d2: in[0] + * d3: in[8] + * d4: in[4] + * d5: in[12] + */ + "vswp d3, d4 \n" + + /* q8 = {in[4], in[12]} * kC1 * 2 >> 16 + * q9 = {in[4], in[12]} * kC2 >> 16 + */ + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + /* d22 = a = in[0] + in[8] + * d23 = b = in[0] - in[8] + */ + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + /* The multiplication should be x * kC1 >> 16 + * However, with vqdmulh we get x * kC1 * 2 >> 16 + * (multiply, double, return high half) + * We avoided this in kC2 by pre-shifting the constant. + * q8 = in[4]/[12] * kC1 >> 16 + */ + "vshr.s16 q8, q8, #1 \n" + + /* Add {in[4], in[12]} back after the multiplication. This is handled by + * adding 1 << 16 to kC1 in the libwebp C code. + */ + "vqadd.s16 q8, q2, q8 \n" + + /* d20 = c = in[4]*kC2 - in[12]*kC1 + * d21 = d = in[4]*kC1 + in[12]*kC2 + */ + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + /* d2 = tmp[0] = a + d + * d3 = tmp[1] = b + c + * d4 = tmp[2] = b - c + * d5 = tmp[3] = a - d + */ + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + "vswp d3, d4 \n" + + /* q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16 + * q9 = {tmp[4], tmp[12]} * kC2 >> 16 + */ + "vqdmulh.s16 q8, q2, d0[0] \n" + "vqdmulh.s16 q9, q2, d0[1] \n" + + /* d22 = a = tmp[0] + tmp[8] + * d23 = b = tmp[0] - tmp[8] + */ + "vqadd.s16 d22, d2, d3 \n" + "vqsub.s16 d23, d2, d3 \n" + + /* See long winded explanations prior */ + "vshr.s16 q8, q8, #1 \n" + "vqadd.s16 q8, q2, q8 \n" + + /* d20 = c = in[4]*kC2 - in[12]*kC1 + * d21 = d = in[4]*kC1 + in[12]*kC2 + */ + "vqsub.s16 d20, d18, d17 \n" + "vqadd.s16 d21, d19, d16 \n" + + /* d2 = tmp[0] = a + d + * d3 = tmp[1] = b + c + * d4 = tmp[2] = b - c + * d5 = tmp[3] = a - d + */ + "vqadd.s16 d2, d22, d21 \n" + "vqadd.s16 d3, d23, d20 \n" + "vqsub.s16 d4, d23, d20 \n" + "vqsub.s16 d5, d22, d21 \n" + + "vld1.32 d6[0], [%[dst]], %[kBPS] \n" + "vld1.32 d6[1], [%[dst]], %[kBPS] \n" + "vld1.32 d7[0], [%[dst]], %[kBPS] \n" + "vld1.32 d7[1], [%[dst]], %[kBPS] \n" + + "sub %[dst], %[dst], %[kBPS], lsl #2 \n" + + /* (val) + 4 >> 3 */ + "vrshr.s16 d2, d2, #3 \n" + "vrshr.s16 d3, d3, #3 \n" + "vrshr.s16 d4, d4, #3 \n" + "vrshr.s16 d5, d5, #3 \n" + + "vzip.16 q1, q2 \n" + "vzip.16 q1, q2 \n" + + /* Must accumulate before saturating */ + "vmovl.u8 q8, d6 \n" + "vmovl.u8 q9, d7 \n" + + "vqadd.s16 q1, q1, q8 \n" + "vqadd.s16 q2, q2, q9 \n" + + "vqmovun.s16 d0, q1 \n" + "vqmovun.s16 d1, q2 \n" + + "vst1.32 d0[0], [%[dst]], %[kBPS] \n" + "vst1.32 d0[1], [%[dst]], %[kBPS] \n" + "vst1.32 d1[0], [%[dst]], %[kBPS] \n" + "vst1.32 d1[1], [%[dst]] \n" + + : [in] "+r"(in), [dst] "+r"(dst) /* modified registers */ + : [kBPS] "r"(kBPS), [constants] "r"(constants) /* constants */ + : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" /* clobbered */ + ); +} + +static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) { + TransformOneNEON(in, dst); + if (do_two) { + TransformOneNEON(in + 16, dst + 4); + } +} + +#endif // WEBP_USE_NEON + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitNEON(void); + +void VP8DspInitNEON(void) { +#if defined(WEBP_USE_NEON) + VP8Transform = TransformTwoNEON; + + VP8SimpleVFilter16 = SimpleVFilter16NEON; + VP8SimpleHFilter16 = SimpleHFilter16NEON; + VP8SimpleVFilter16i = SimpleVFilter16iNEON; + VP8SimpleHFilter16i = SimpleHFilter16iNEON; +#endif // WEBP_USE_NEON +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/dec_sse2.c b/external/libwebp/dsp/dec_sse2.c new file mode 100644 index 0000000000..2cb55d013f --- /dev/null +++ b/external/libwebp/dsp/dec_sse2.c @@ -0,0 +1,908 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// SSE2 version of some decoding functions (idct, loop filtering). +// +// Author: somnath@google.com (Somnath Banerjee) +// cduvivier@google.com (Christian Duvivier) + +#include "./dsp.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if defined(WEBP_USE_SSE2) + +#include +#include "../dec/vp8i.h" + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) { + // This implementation makes use of 16-bit fixed point versions of two + // multiply constants: + // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 + // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 + // + // To be able to use signed 16-bit integers, we use the following trick to + // have constants within range: + // - Associated constants are obtained by subtracting the 16-bit fixed point + // version of one: + // k = K - (1 << 16) => K = k + (1 << 16) + // K1 = 85267 => k1 = 20091 + // K2 = 35468 => k2 = -30068 + // - The multiplication of a variable by a constant become the sum of the + // variable and the multiplication of that variable by the associated + // constant: + // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x + const __m128i k1 = _mm_set1_epi16(20091); + const __m128i k2 = _mm_set1_epi16(-30068); + __m128i T0, T1, T2, T3; + + // Load and concatenate the transform coefficients (we'll do two transforms + // in parallel). In the case of only one transform, the second half of the + // vectors will just contain random value we'll never use nor store. + __m128i in0, in1, in2, in3; + { + in0 = _mm_loadl_epi64((__m128i*)&in[0]); + in1 = _mm_loadl_epi64((__m128i*)&in[4]); + in2 = _mm_loadl_epi64((__m128i*)&in[8]); + in3 = _mm_loadl_epi64((__m128i*)&in[12]); + // a00 a10 a20 a30 x x x x + // a01 a11 a21 a31 x x x x + // a02 a12 a22 a32 x x x x + // a03 a13 a23 a33 x x x x + if (do_two) { + const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]); + const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]); + const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]); + const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]); + in0 = _mm_unpacklo_epi64(in0, inB0); + in1 = _mm_unpacklo_epi64(in1, inB1); + in2 = _mm_unpacklo_epi64(in2, inB2); + in3 = _mm_unpacklo_epi64(in3, inB3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + } + + // Vertical pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i a = _mm_add_epi16(in0, in2); + const __m128i b = _mm_sub_epi16(in0, in2); + // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 + const __m128i c1 = _mm_mulhi_epi16(in1, k2); + const __m128i c2 = _mm_mulhi_epi16(in3, k1); + const __m128i c3 = _mm_sub_epi16(in1, in3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 + const __m128i d1 = _mm_mulhi_epi16(in1, k1); + const __m128i d2 = _mm_mulhi_epi16(in3, k2); + const __m128i d3 = _mm_add_epi16(in1, in3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + + // Transpose the two 4x4. + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(tmp0, tmp1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(tmp2, tmp3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(tmp0, tmp1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(tmp2, tmp3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Horizontal pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i four = _mm_set1_epi16(4); + const __m128i dc = _mm_add_epi16(T0, four); + const __m128i a = _mm_add_epi16(dc, T2); + const __m128i b = _mm_sub_epi16(dc, T2); + // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 + const __m128i c1 = _mm_mulhi_epi16(T1, k2); + const __m128i c2 = _mm_mulhi_epi16(T3, k1); + const __m128i c3 = _mm_sub_epi16(T1, T3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 + const __m128i d1 = _mm_mulhi_epi16(T1, k1); + const __m128i d2 = _mm_mulhi_epi16(T3, k2); + const __m128i d3 = _mm_add_epi16(T1, T3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + const __m128i shifted0 = _mm_srai_epi16(tmp0, 3); + const __m128i shifted1 = _mm_srai_epi16(tmp1, 3); + const __m128i shifted2 = _mm_srai_epi16(tmp2, 3); + const __m128i shifted3 = _mm_srai_epi16(tmp3, 3); + + // Transpose the two 4x4. + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(shifted0, shifted1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(shifted2, shifted3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(shifted0, shifted1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(shifted2, shifted3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Add inverse transform to 'dst' and store. + { + const __m128i zero = _mm_set1_epi16(0); + // Load the reference(s). + __m128i dst0, dst1, dst2, dst3; + if (do_two) { + // Load eight bytes/pixels per line. + dst0 = _mm_loadl_epi64((__m128i*)&dst[0 * BPS]); + dst1 = _mm_loadl_epi64((__m128i*)&dst[1 * BPS]); + dst2 = _mm_loadl_epi64((__m128i*)&dst[2 * BPS]); + dst3 = _mm_loadl_epi64((__m128i*)&dst[3 * BPS]); + } else { + // Load four bytes/pixels per line. + dst0 = _mm_cvtsi32_si128(*(int*)&dst[0 * BPS]); + dst1 = _mm_cvtsi32_si128(*(int*)&dst[1 * BPS]); + dst2 = _mm_cvtsi32_si128(*(int*)&dst[2 * BPS]); + dst3 = _mm_cvtsi32_si128(*(int*)&dst[3 * BPS]); + } + // Convert to 16b. + dst0 = _mm_unpacklo_epi8(dst0, zero); + dst1 = _mm_unpacklo_epi8(dst1, zero); + dst2 = _mm_unpacklo_epi8(dst2, zero); + dst3 = _mm_unpacklo_epi8(dst3, zero); + // Add the inverse transform(s). + dst0 = _mm_add_epi16(dst0, T0); + dst1 = _mm_add_epi16(dst1, T1); + dst2 = _mm_add_epi16(dst2, T2); + dst3 = _mm_add_epi16(dst3, T3); + // Unsigned saturate to 8b. + dst0 = _mm_packus_epi16(dst0, dst0); + dst1 = _mm_packus_epi16(dst1, dst1); + dst2 = _mm_packus_epi16(dst2, dst2); + dst3 = _mm_packus_epi16(dst3, dst3); + // Store the results. + if (do_two) { + // Store eight bytes/pixels per line. + _mm_storel_epi64((__m128i*)&dst[0 * BPS], dst0); + _mm_storel_epi64((__m128i*)&dst[1 * BPS], dst1); + _mm_storel_epi64((__m128i*)&dst[2 * BPS], dst2); + _mm_storel_epi64((__m128i*)&dst[3 * BPS], dst3); + } else { + // Store four bytes/pixels per line. + *((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(dst0); + *((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(dst1); + *((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(dst2); + *((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(dst3); + } + } +} + +//------------------------------------------------------------------------------ +// Loop Filter (Paragraph 15) + +// Compute abs(p - q) = subs(p - q) OR subs(q - p) +#define MM_ABS(p, q) _mm_or_si128( \ + _mm_subs_epu8((q), (p)), \ + _mm_subs_epu8((p), (q))) + +// Shift each byte of "a" by N bits while preserving by the sign bit. +// +// It first shifts the lower bytes of the words and then the upper bytes and +// then merges the results together. +#define SIGNED_SHIFT_N(a, N) { \ + __m128i t = a; \ + t = _mm_slli_epi16(t, 8); \ + t = _mm_srai_epi16(t, N); \ + t = _mm_srli_epi16(t, 8); \ + \ + a = _mm_srai_epi16(a, N + 8); \ + a = _mm_slli_epi16(a, 8); \ + \ + a = _mm_or_si128(t, a); \ +} + +#define FLIP_SIGN_BIT2(a, b) { \ + a = _mm_xor_si128(a, sign_bit); \ + b = _mm_xor_si128(b, sign_bit); \ +} + +#define FLIP_SIGN_BIT4(a, b, c, d) { \ + FLIP_SIGN_BIT2(a, b); \ + FLIP_SIGN_BIT2(c, d); \ +} + +#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \ + const __m128i zero = _mm_setzero_si128(); \ + const __m128i t1 = MM_ABS(p1, p0); \ + const __m128i t2 = MM_ABS(q1, q0); \ + \ + const __m128i h = _mm_set1_epi8(hev_thresh); \ + const __m128i t3 = _mm_subs_epu8(t1, h); /* abs(p1 - p0) - hev_tresh */ \ + const __m128i t4 = _mm_subs_epu8(t2, h); /* abs(q1 - q0) - hev_tresh */ \ + \ + not_hev = _mm_or_si128(t3, t4); \ + not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\ +} + +#define GET_BASE_DELTA(p1, p0, q0, q1, o) { \ + const __m128i qp0 = _mm_subs_epi8(q0, p0); /* q0 - p0 */ \ + o = _mm_subs_epi8(p1, q1); /* p1 - q1 */ \ + o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 1 * (q0 - p0) */ \ + o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 2 * (q0 - p0) */ \ + o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 3 * (q0 - p0) */ \ +} + +#define DO_SIMPLE_FILTER(p0, q0, fl) { \ + const __m128i three = _mm_set1_epi8(3); \ + const __m128i four = _mm_set1_epi8(4); \ + __m128i v3 = _mm_adds_epi8(fl, three); \ + __m128i v4 = _mm_adds_epi8(fl, four); \ + \ + /* Do +4 side */ \ + SIGNED_SHIFT_N(v4, 3); /* v4 >> 3 */ \ + q0 = _mm_subs_epi8(q0, v4); /* q0 -= v4 */ \ + \ + /* Now do +3 side */ \ + SIGNED_SHIFT_N(v3, 3); /* v3 >> 3 */ \ + p0 = _mm_adds_epi8(p0, v3); /* p0 += v3 */ \ +} + +// Updates values of 2 pixels at MB edge during complex filtering. +// Update operations: +// q = q - a and p = p + a; where a = [(a_hi >> 7), (a_lo >> 7)] +#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \ + const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \ + const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \ + const __m128i a = _mm_packs_epi16(a_lo7, a_hi7); \ + pi = _mm_adds_epi8(pi, a); \ + qi = _mm_subs_epi8(qi, a); \ +} + +static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0, + const __m128i* q1, int thresh, __m128i *mask) { + __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1) + *mask = _mm_set1_epi8(0xFE); + t1 = _mm_and_si128(t1, *mask); // set lsb of each byte to zero + t1 = _mm_srli_epi16(t1, 1); // abs(p1 - q1) / 2 + + *mask = MM_ABS(*p0, *q0); // abs(p0 - q0) + *mask = _mm_adds_epu8(*mask, *mask); // abs(p0 - q0) * 2 + *mask = _mm_adds_epu8(*mask, t1); // abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + t1 = _mm_set1_epi8(thresh); + *mask = _mm_subs_epu8(*mask, t1); // mask <= thresh + *mask = _mm_cmpeq_epi8(*mask, _mm_setzero_si128()); +} + +//------------------------------------------------------------------------------ +// Edge filtering functions + +// Applies filter on 2 pixels (p0 and q0) +static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0, + const __m128i* q1, int thresh) { + __m128i a, mask; + const __m128i sign_bit = _mm_set1_epi8(0x80); + const __m128i p1s = _mm_xor_si128(*p1, sign_bit); + const __m128i q1s = _mm_xor_si128(*q1, sign_bit); + + NeedsFilter(p1, p0, q0, q1, thresh, &mask); + + // convert to signed values + FLIP_SIGN_BIT2(*p0, *q0); + + GET_BASE_DELTA(p1s, *p0, *q0, q1s, a); + a = _mm_and_si128(a, mask); // mask filter values we don't care about + DO_SIMPLE_FILTER(*p0, *q0, a); + + // unoffset + FLIP_SIGN_BIT2(*p0, *q0); +} + +// Applies filter on 4 pixels (p1, p0, q0 and q1) +static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0, + __m128i* q0, __m128i* q1, + const __m128i* mask, int hev_thresh) { + __m128i not_hev; + __m128i t1, t2, t3; + const __m128i sign_bit = _mm_set1_epi8(0x80); + + // compute hev mask + GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev); + + // convert to signed values + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); + + t1 = _mm_subs_epi8(*p1, *q1); // p1 - q1 + t1 = _mm_andnot_si128(not_hev, t1); // hev(p1 - q1) + t2 = _mm_subs_epi8(*q0, *p0); // q0 - p0 + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 1 * (q0 - p0) + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 2 * (q0 - p0) + t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0) + t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about + + // Do +4 side + t2 = _mm_set1_epi8(4); + t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 4 + SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3 + t3 = t2; // save t2 + *q0 = _mm_subs_epi8(*q0, t2); // q0 -= t2 + + // Now do +3 side + t2 = _mm_set1_epi8(3); + t2 = _mm_adds_epi8(t1, t2); // +3 instead of +4 + SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3 + *p0 = _mm_adds_epi8(*p0, t2); // p0 += t2 + + t2 = _mm_set1_epi8(1); + t3 = _mm_adds_epi8(t3, t2); + SIGNED_SHIFT_N(t3, 1); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 4 + + t3 = _mm_and_si128(not_hev, t3); // if !hev + *q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3 + *p1 = _mm_adds_epi8(*p1, t3); // p1 += t3 + + // unoffset + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); +} + +// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2) +static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0, + __m128i* q0, __m128i* q1, __m128i *q2, + const __m128i* mask, int hev_thresh) { + __m128i a, not_hev; + const __m128i sign_bit = _mm_set1_epi8(0x80); + + // compute hev mask + GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev); + + // convert to signed values + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); + FLIP_SIGN_BIT2(*p2, *q2); + + GET_BASE_DELTA(*p1, *p0, *q0, *q1, a); + + { // do simple filter on pixels with hev + const __m128i m = _mm_andnot_si128(not_hev, *mask); + const __m128i f = _mm_and_si128(a, m); + DO_SIMPLE_FILTER(*p0, *q0, f); + } + { // do strong filter on pixels with not hev + const __m128i zero = _mm_setzero_si128(); + const __m128i nine = _mm_set1_epi16(0x0900); + const __m128i sixty_three = _mm_set1_epi16(63); + + const __m128i m = _mm_and_si128(not_hev, *mask); + const __m128i f = _mm_and_si128(a, m); + const __m128i f_lo = _mm_unpacklo_epi8(zero, f); + const __m128i f_hi = _mm_unpackhi_epi8(zero, f); + + const __m128i f9_lo = _mm_mulhi_epi16(f_lo, nine); // Filter (lo) * 9 + const __m128i f9_hi = _mm_mulhi_epi16(f_hi, nine); // Filter (hi) * 9 + const __m128i f18_lo = _mm_add_epi16(f9_lo, f9_lo); // Filter (lo) * 18 + const __m128i f18_hi = _mm_add_epi16(f9_hi, f9_hi); // Filter (hi) * 18 + + const __m128i a2_lo = _mm_add_epi16(f9_lo, sixty_three); // Filter * 9 + 63 + const __m128i a2_hi = _mm_add_epi16(f9_hi, sixty_three); // Filter * 9 + 63 + + const __m128i a1_lo = _mm_add_epi16(f18_lo, sixty_three); // F... * 18 + 63 + const __m128i a1_hi = _mm_add_epi16(f18_hi, sixty_three); // F... * 18 + 63 + + const __m128i a0_lo = _mm_add_epi16(f18_lo, a2_lo); // Filter * 27 + 63 + const __m128i a0_hi = _mm_add_epi16(f18_hi, a2_hi); // Filter * 27 + 63 + + UPDATE_2PIXELS(*p2, *q2, a2_lo, a2_hi); + UPDATE_2PIXELS(*p1, *q1, a1_lo, a1_hi); + UPDATE_2PIXELS(*p0, *q0, a0_lo, a0_hi); + } + + // unoffset + FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1); + FLIP_SIGN_BIT2(*p2, *q2); +} + +// reads 8 rows across a vertical edge. +// +// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into +// two Load4x4() to avoid code duplication. +static WEBP_INLINE void Load8x4(const uint8_t* b, int stride, + __m128i* p, __m128i* q) { + __m128i t1, t2; + + // Load 0th, 1st, 4th and 5th rows + __m128i r0 = _mm_cvtsi32_si128(*((int*)&b[0 * stride])); // 03 02 01 00 + __m128i r1 = _mm_cvtsi32_si128(*((int*)&b[1 * stride])); // 13 12 11 10 + __m128i r4 = _mm_cvtsi32_si128(*((int*)&b[4 * stride])); // 43 42 41 40 + __m128i r5 = _mm_cvtsi32_si128(*((int*)&b[5 * stride])); // 53 52 51 50 + + r0 = _mm_unpacklo_epi32(r0, r4); // 43 42 41 40 03 02 01 00 + r1 = _mm_unpacklo_epi32(r1, r5); // 53 52 51 50 13 12 11 10 + + // t1 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00 + t1 = _mm_unpacklo_epi8(r0, r1); + + // Load 2nd, 3rd, 6th and 7th rows + r0 = _mm_cvtsi32_si128(*((int*)&b[2 * stride])); // 23 22 21 22 + r1 = _mm_cvtsi32_si128(*((int*)&b[3 * stride])); // 33 32 31 30 + r4 = _mm_cvtsi32_si128(*((int*)&b[6 * stride])); // 63 62 61 60 + r5 = _mm_cvtsi32_si128(*((int*)&b[7 * stride])); // 73 72 71 70 + + r0 = _mm_unpacklo_epi32(r0, r4); // 63 62 61 60 23 22 21 20 + r1 = _mm_unpacklo_epi32(r1, r5); // 73 72 71 70 33 32 31 30 + + // t2 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20 + t2 = _mm_unpacklo_epi8(r0, r1); + + // t1 = 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + // t2 = 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + r0 = t1; + t1 = _mm_unpacklo_epi16(t1, t2); + t2 = _mm_unpackhi_epi16(r0, t2); + + // *p = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + // *q = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + *p = _mm_unpacklo_epi32(t1, t2); + *q = _mm_unpackhi_epi32(t1, t2); +} + +static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8, + int stride, + __m128i* p1, __m128i* p0, + __m128i* q0, __m128i* q1) { + __m128i t1, t2; + // Assume the pixels around the edge (|) are numbered as follows + // 00 01 | 02 03 + // 10 11 | 12 13 + // ... | ... + // e0 e1 | e2 e3 + // f0 f1 | f2 f3 + // + // r0 is pointing to the 0th row (00) + // r8 is pointing to the 8th row (80) + + // Load + // p1 = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + // q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + // p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + // q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + Load8x4(r0, stride, p1, q0); + Load8x4(r8, stride, p0, q1); + + t1 = *p1; + t2 = *q0; + // p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + // p0 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + // q0 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + // q1 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + *p1 = _mm_unpacklo_epi64(t1, *p0); + *p0 = _mm_unpackhi_epi64(t1, *p0); + *q0 = _mm_unpacklo_epi64(t2, *q1); + *q1 = _mm_unpackhi_epi64(t2, *q1); +} + +static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) { + int i; + for (i = 0; i < 4; ++i, dst += stride) { + *((int32_t*)dst) = _mm_cvtsi128_si32(*x); + *x = _mm_srli_si128(*x, 4); + } +} + +// Transpose back and store +static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride, + __m128i* p1, __m128i* p0, + __m128i* q0, __m128i* q1) { + __m128i t1; + + // p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + // p1 = f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + t1 = *p0; + *p0 = _mm_unpacklo_epi8(*p1, t1); + *p1 = _mm_unpackhi_epi8(*p1, t1); + + // q0 = 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + // q1 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + t1 = *q0; + *q0 = _mm_unpacklo_epi8(t1, *q1); + *q1 = _mm_unpackhi_epi8(t1, *q1); + + // p0 = 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + // q0 = 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + t1 = *p0; + *p0 = _mm_unpacklo_epi16(t1, *q0); + *q0 = _mm_unpackhi_epi16(t1, *q0); + + // p1 = b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + // q1 = f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + t1 = *p1; + *p1 = _mm_unpacklo_epi16(t1, *q1); + *q1 = _mm_unpackhi_epi16(t1, *q1); + + Store4x4(p0, r0, stride); + r0 += 4 * stride; + Store4x4(q0, r0, stride); + + Store4x4(p1, r8, stride); + r8 += 4 * stride; + Store4x4(q1, r8, stride); +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) { + // Load + __m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]); + __m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]); + __m128i q0 = _mm_loadu_si128((__m128i*)&p[0]); + __m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]); + + DoFilter2(&p1, &p0, &q0, &q1, thresh); + + // Store + _mm_storeu_si128((__m128i*)&p[-stride], p0); + _mm_storeu_si128((__m128i*)p, q0); +} + +static void SimpleHFilter16SSE2(uint8_t* p, int stride, int thresh) { + __m128i p1, p0, q0, q1; + + p -= 2; // beginning of p1 + + Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1); + DoFilter2(&p1, &p0, &q0, &q1, thresh); + Store16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1); +} + +static void SimpleVFilter16iSSE2(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16SSE2(p, stride, thresh); + } +} + +static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16SSE2(p, stride, thresh); + } +} + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +#define MAX_DIFF1(p3, p2, p1, p0, m) { \ + m = MM_ABS(p3, p2); \ + m = _mm_max_epu8(m, MM_ABS(p2, p1)); \ + m = _mm_max_epu8(m, MM_ABS(p1, p0)); \ +} + +#define MAX_DIFF2(p3, p2, p1, p0, m) { \ + m = _mm_max_epu8(m, MM_ABS(p3, p2)); \ + m = _mm_max_epu8(m, MM_ABS(p2, p1)); \ + m = _mm_max_epu8(m, MM_ABS(p1, p0)); \ +} + +#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \ + e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \ + e2 = _mm_loadu_si128((__m128i*)&(p)[1 * stride]); \ + e3 = _mm_loadu_si128((__m128i*)&(p)[2 * stride]); \ + e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \ +} + +#define LOADUV_H_EDGE(p, u, v, stride) { \ + p = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \ + p = _mm_unpacklo_epi64(p, _mm_loadl_epi64((__m128i*)&(v)[(stride)])); \ +} + +#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \ + LOADUV_H_EDGE(e1, u, v, 0 * stride); \ + LOADUV_H_EDGE(e2, u, v, 1 * stride); \ + LOADUV_H_EDGE(e3, u, v, 2 * stride); \ + LOADUV_H_EDGE(e4, u, v, 3 * stride); \ +} + +#define STOREUV(p, u, v, stride) { \ + _mm_storel_epi64((__m128i*)&u[(stride)], p); \ + p = _mm_srli_si128(p, 8); \ + _mm_storel_epi64((__m128i*)&v[(stride)], p); \ +} + +#define COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask) { \ + __m128i fl_yes; \ + const __m128i it = _mm_set1_epi8(ithresh); \ + mask = _mm_subs_epu8(mask, it); \ + mask = _mm_cmpeq_epi8(mask, _mm_setzero_si128()); \ + NeedsFilter(&p1, &p0, &q0, &q1, thresh, &fl_yes); \ + mask = _mm_and_si128(mask, fl_yes); \ +} + +// on macroblock edges +static void VFilter16SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i t1; + __m128i mask; + __m128i p2, p1, p0, q0, q1, q2; + + // Load p3, p2, p1, p0 + LOAD_H_EDGES4(p - 4 * stride, stride, t1, p2, p1, p0); + MAX_DIFF1(t1, p2, p1, p0, mask); + + // Load q0, q1, q2, q3 + LOAD_H_EDGES4(p, stride, q0, q1, q2, t1); + MAX_DIFF2(t1, q2, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + // Store + _mm_storeu_si128((__m128i*)&p[-3 * stride], p2); + _mm_storeu_si128((__m128i*)&p[-2 * stride], p1); + _mm_storeu_si128((__m128i*)&p[-1 * stride], p0); + _mm_storeu_si128((__m128i*)&p[0 * stride], q0); + _mm_storeu_si128((__m128i*)&p[1 * stride], q1); + _mm_storeu_si128((__m128i*)&p[2 * stride], q2); +} + +static void HFilter16SSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i p3, p2, p1, p0, q0, q1, q2, q3; + + uint8_t* const b = p - 4; + Load16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0 + MAX_DIFF1(p3, p2, p1, p0, mask); + + Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3 + MAX_DIFF2(q3, q2, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + Store16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); + Store16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); +} + +// on three inner edges +static void VFilter16iSSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + + for (k = 3; k > 0; --k) { + // Load p3, p2, p1, p0 + LOAD_H_EDGES4(p, stride, t2, t1, p1, p0); + MAX_DIFF1(t2, t1, p1, p0, mask); + + p += 4 * stride; + + // Load q0, q1, q2, q3 + LOAD_H_EDGES4(p, stride, q0, q1, t1, t2); + MAX_DIFF2(t2, t1, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + // Store + _mm_storeu_si128((__m128i*)&p[-2 * stride], p1); + _mm_storeu_si128((__m128i*)&p[-1 * stride], p0); + _mm_storeu_si128((__m128i*)&p[0 * stride], q0); + _mm_storeu_si128((__m128i*)&p[1 * stride], q1); + } +} + +static void HFilter16iSSE2(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + uint8_t* b; + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + + for (k = 3; k > 0; --k) { + b = p; + Load16x4(b, b + 8 * stride, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0 + MAX_DIFF1(t2, t1, p1, p0, mask); + + b += 4; // beginning of q0 + Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3 + MAX_DIFF2(t2, t1, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + b -= 2; // beginning of p1 + Store16x4(b, b + 8 * stride, stride, &p1, &p0, &q0, &q1); + + p += 4; + } +} + +// 8-pixels wide variant, for chroma filtering +static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, p2, p1, p0, q0, q1, q2; + + // Load p3, p2, p1, p0 + LOADUV_H_EDGES4(u - 4 * stride, v - 4 * stride, stride, t1, p2, p1, p0); + MAX_DIFF1(t1, p2, p1, p0, mask); + + // Load q0, q1, q2, q3 + LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1); + MAX_DIFF2(t1, q2, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + // Store + STOREUV(p2, u, v, -3 * stride); + STOREUV(p1, u, v, -2 * stride); + STOREUV(p0, u, v, -1 * stride); + STOREUV(q0, u, v, 0 * stride); + STOREUV(q1, u, v, 1 * stride); + STOREUV(q2, u, v, 2 * stride); +} + +static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i p3, p2, p1, p0, q0, q1, q2, q3; + + uint8_t* const tu = u - 4; + uint8_t* const tv = v - 4; + Load16x4(tu, tv, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0 + MAX_DIFF1(p3, p2, p1, p0, mask); + + Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3 + MAX_DIFF2(q3, q2, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh); + + Store16x4(tu, tv, stride, &p3, &p2, &p1, &p0); + Store16x4(u, v, stride, &q0, &q1, &q2, &q3); +} + +static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + + // Load p3, p2, p1, p0 + LOADUV_H_EDGES4(u, v, stride, t2, t1, p1, p0); + MAX_DIFF1(t2, t1, p1, p0, mask); + + u += 4 * stride; + v += 4 * stride; + + // Load q0, q1, q2, q3 + LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2); + MAX_DIFF2(t2, t1, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + // Store + STOREUV(p1, u, v, -2 * stride); + STOREUV(p0, u, v, -1 * stride); + STOREUV(q0, u, v, 0 * stride); + STOREUV(q1, u, v, 1 * stride); +} + +static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + __m128i mask; + __m128i t1, t2, p1, p0, q0, q1; + Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0 + MAX_DIFF1(t2, t1, p1, p0, mask); + + u += 4; // beginning of q0 + v += 4; + Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3 + MAX_DIFF2(t2, t1, q1, q0, mask); + + COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask); + DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh); + + u -= 2; // beginning of p1 + v -= 2; + Store16x4(u, v, stride, &p1, &p0, &q0, &q1); +} + +#endif // WEBP_USE_SSE2 + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitSSE2(void); + +void VP8DspInitSSE2(void) { +#if defined(WEBP_USE_SSE2) + VP8Transform = TransformSSE2; + + VP8VFilter16 = VFilter16SSE2; + VP8HFilter16 = HFilter16SSE2; + VP8VFilter8 = VFilter8SSE2; + VP8HFilter8 = HFilter8SSE2; + VP8VFilter16i = VFilter16iSSE2; + VP8HFilter16i = HFilter16iSSE2; + VP8VFilter8i = VFilter8iSSE2; + VP8HFilter8i = HFilter8iSSE2; + + VP8SimpleVFilter16 = SimpleVFilter16SSE2; + VP8SimpleHFilter16 = SimpleHFilter16SSE2; + VP8SimpleVFilter16i = SimpleVFilter16iSSE2; + VP8SimpleHFilter16i = SimpleHFilter16iSSE2; +#endif // WEBP_USE_SSE2 +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/dsp.h b/external/libwebp/dsp/dsp.h new file mode 100644 index 0000000000..0982451520 --- /dev/null +++ b/external/libwebp/dsp/dsp.h @@ -0,0 +1,212 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Speed-critical functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_DSP_H_ +#define WEBP_DSP_DSP_H_ + +#include "platform/CCPlatformConfig.h" + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// CPU detection + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) +#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets +#endif + +#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) +#define WEBP_USE_SSE2 +#endif + +#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__) +#define WEBP_ANDROID_NEON // Android targets that might support NEON +#endif + +#if defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON) +#define WEBP_USE_NEON +#endif + +typedef enum { + kSSE2, + kSSE3, + kNEON +} CPUFeature; +// returns true if the CPU supports the feature. +typedef int (*VP8CPUInfo)(CPUFeature feature); +extern VP8CPUInfo VP8GetCPUInfo; + +//------------------------------------------------------------------------------ +// Encoding + +int VP8GetAlpha(const int histo[]); + +// Transforms +// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms +// will be done for (ref, in, dst) and (ref + 4, in + 16, dst + 4). +typedef void (*VP8Idct)(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two); +typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out); +typedef void (*VP8WHT)(const int16_t* in, int16_t* out); +extern VP8Idct VP8ITransform; +extern VP8Fdct VP8FTransform; +extern VP8WHT VP8ITransformWHT; +extern VP8WHT VP8FTransformWHT; +// Predictions +// *dst is the destination block. *top and *left can be NULL. +typedef void (*VP8IntraPreds)(uint8_t *dst, const uint8_t* left, + const uint8_t* top); +typedef void (*VP8Intra4Preds)(uint8_t *dst, const uint8_t* top); +extern VP8Intra4Preds VP8EncPredLuma4; +extern VP8IntraPreds VP8EncPredLuma16; +extern VP8IntraPreds VP8EncPredChroma8; + +typedef int (*VP8Metric)(const uint8_t* pix, const uint8_t* ref); +extern VP8Metric VP8SSE16x16, VP8SSE16x8, VP8SSE8x8, VP8SSE4x4; +typedef int (*VP8WMetric)(const uint8_t* pix, const uint8_t* ref, + const uint16_t* const weights); +extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16; + +typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst); +extern VP8BlockCopy VP8Copy4x4; +// Quantization +struct VP8Matrix; // forward declaration +typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16], + int n, const struct VP8Matrix* const mtx); +extern VP8QuantizeBlock VP8EncQuantizeBlock; + +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. +typedef int (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block); +extern const int VP8DspScan[16 + 4 + 4]; +extern VP8CHisto VP8CollectHistogram; + +void VP8EncDspInit(void); // must be called before using any of the above + +//------------------------------------------------------------------------------ +// Decoding + +typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst); +// when doing two transforms, coeffs is actually int16_t[2][16]. +typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two); +extern VP8DecIdct2 VP8Transform; +extern VP8DecIdct VP8TransformUV; +extern VP8DecIdct VP8TransformDC; +extern VP8DecIdct VP8TransformDCUV; +extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out); + +// *dst is the destination block, with stride BPS. Boundary samples are +// assumed accessible when needed. +typedef void (*VP8PredFunc)(uint8_t* dst); +extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */]; +extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */]; +extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */]; + +// simple filter (only for luma) +typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh); +extern VP8SimpleFilterFunc VP8SimpleVFilter16; +extern VP8SimpleFilterFunc VP8SimpleHFilter16; +extern VP8SimpleFilterFunc VP8SimpleVFilter16i; // filter 3 inner edges +extern VP8SimpleFilterFunc VP8SimpleHFilter16i; + +// regular filter (on both macroblock edges and inner edges) +typedef void (*VP8LumaFilterFunc)(uint8_t* luma, int stride, + int thresh, int ithresh, int hev_t); +typedef void (*VP8ChromaFilterFunc)(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_t); +// on outer edge +extern VP8LumaFilterFunc VP8VFilter16; +extern VP8LumaFilterFunc VP8HFilter16; +extern VP8ChromaFilterFunc VP8VFilter8; +extern VP8ChromaFilterFunc VP8HFilter8; + +// on inner edge +extern VP8LumaFilterFunc VP8VFilter16i; // filtering 3 inner edges altogether +extern VP8LumaFilterFunc VP8HFilter16i; +extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether +extern VP8ChromaFilterFunc VP8HFilter8i; + +// must be called before anything using the above +void VP8DspInit(void); + +//------------------------------------------------------------------------------ +// WebP I/O + +#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support + +typedef void (*WebPUpsampleLinePairFunc)( + const uint8_t* top_y, const uint8_t* bottom_y, + const uint8_t* top_u, const uint8_t* top_v, + const uint8_t* cur_u, const uint8_t* cur_v, + uint8_t* top_dst, uint8_t* bottom_dst, int len); + +#ifdef FANCY_UPSAMPLING + +// Fancy upsampling functions to convert YUV to RGB(A) modes +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +// Initializes SSE2 version of the fancy upsamplers. +void WebPInitUpsamplersSSE2(void); + +#endif // FANCY_UPSAMPLING + +// Point-sampling methods. +typedef void (*WebPSampleLinePairFunc)( + const uint8_t* top_y, const uint8_t* bottom_y, + const uint8_t* u, const uint8_t* v, + uint8_t* top_dst, uint8_t* bottom_dst, int len); + +extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */]; + +// General function for converting two lines of ARGB or RGBA. +// 'alpha_is_last' should be true if 0xff000000 is stored in memory as +// as 0x00, 0x00, 0x00, 0xff (little endian). +WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last); + +// YUV444->RGB converters +typedef void (*WebPYUV444Converter)(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len); + +extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; + +// Main function to be called +void WebPInitUpsamplers(void); + +//------------------------------------------------------------------------------ +// Pre-multiply planes with alpha values + +// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h. +// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last). +extern void (*WebPApplyAlphaMultiply)( + uint8_t* rgba, int alpha_first, int w, int h, int stride); + +// Same, buf specifically for RGBA4444 format +extern void (*WebPApplyAlphaMultiply4444)( + uint8_t* rgba4444, int w, int h, int stride); + +// To be called first before using the above. +void WebPInitPremultiply(void); + +void WebPInitPremultiplySSE2(void); // should not be called directly. + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_DSP_DSP_H_ */ diff --git a/external/libwebp/dsp/enc.c b/external/libwebp/dsp/enc.c new file mode 100644 index 0000000000..02234564be --- /dev/null +++ b/external/libwebp/dsp/enc.c @@ -0,0 +1,743 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Speed-critical encoding functions. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include // for abs() +#include "./dsp.h" +#include "../enc/vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. + +static int ClipAlpha(int alpha) { + return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha; +} + +int VP8GetAlpha(const int histo[MAX_COEFF_THRESH + 1]) { + int num = 0, den = 0, val = 0; + int k; + int alpha; + // note: changing this loop to avoid the numerous "k + 1" slows things down. + for (k = 0; k < MAX_COEFF_THRESH; ++k) { + if (histo[k + 1]) { + val += histo[k + 1]; + num += val * (k + 1); + den += (k + 1) * (k + 1); + } + } + // we scale the value to a usable [0..255] range + alpha = den ? 10 * num / den - 5 : 0; + return ClipAlpha(alpha); +} + +const int VP8DspScan[16 + 4 + 4] = { + // Luma + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, + + 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U + 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V +}; + +static int CollectHistogram(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block) { + int histo[MAX_COEFF_THRESH + 1] = { 0 }; + int16_t out[16]; + int j, k; + for (j = start_block; j < end_block; ++j) { + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin (within out[]). + for (k = 0; k < 16; ++k) { + const int v = abs(out[k]) >> 2; + out[k] = (v > MAX_COEFF_THRESH) ? MAX_COEFF_THRESH : v; + } + + // Use bin to update histogram. + for (k = 0; k < 16; ++k) { + histo[out[k]]++; + } + } + + return VP8GetAlpha(histo); +} + +//------------------------------------------------------------------------------ +// run-time tables (~4k) + +static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255] + +// We declare this variable 'volatile' to prevent instruction reordering +// and make sure it's set to true _last_ (so as to be thread-safe) +static volatile int tables_ok = 0; + +static void InitTables(void) { + if (!tables_ok) { + int i; + for (i = -255; i <= 255 + 255; ++i) { + clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i; + } + tables_ok = 1; + } +} + +static WEBP_INLINE uint8_t clip_8b(int v) { + return (!(v & ~0xff)) ? v : v < 0 ? 0 : 255; +} + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +#define STORE(x, y, v) \ + dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3)) + +static const int kC1 = 20091 + (1 << 16); +static const int kC2 = 35468; +#define MUL(a, b) (((a) * (b)) >> 16) + +static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, + uint8_t* dst) { + int C[4 * 4], *tmp; + int i; + tmp = C; + for (i = 0; i < 4; ++i) { // vertical pass + const int a = in[0] + in[8]; + const int b = in[0] - in[8]; + const int c = MUL(in[4], kC2) - MUL(in[12], kC1); + const int d = MUL(in[4], kC1) + MUL(in[12], kC2); + tmp[0] = a + d; + tmp[1] = b + c; + tmp[2] = b - c; + tmp[3] = a - d; + tmp += 4; + in++; + } + + tmp = C; + for (i = 0; i < 4; ++i) { // horizontal pass + const int dc = tmp[0] + 4; + const int a = dc + tmp[8]; + const int b = dc - tmp[8]; + const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1); + const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2); + STORE(0, i, a + d); + STORE(1, i, b + c); + STORE(2, i, b - c); + STORE(3, i, a - d); + tmp++; + } +} + +static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + ITransformOne(ref, in, dst); + if (do_two) { + ITransformOne(ref + 4, in + 16, dst + 4); + } +} + +static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) { + int i; + int tmp[16]; + for (i = 0; i < 4; ++i, src += BPS, ref += BPS) { + const int d0 = src[0] - ref[0]; + const int d1 = src[1] - ref[1]; + const int d2 = src[2] - ref[2]; + const int d3 = src[3] - ref[3]; + const int a0 = (d0 + d3) << 3; + const int a1 = (d1 + d2) << 3; + const int a2 = (d1 - d2) << 3; + const int a3 = (d0 - d3) << 3; + tmp[0 + i * 4] = (a0 + a1); + tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 14500) >> 12; + tmp[2 + i * 4] = (a0 - a1); + tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 7500) >> 12; + } + for (i = 0; i < 4; ++i) { + const int a0 = (tmp[0 + i] + tmp[12 + i]); + const int a1 = (tmp[4 + i] + tmp[ 8 + i]); + const int a2 = (tmp[4 + i] - tmp[ 8 + i]); + const int a3 = (tmp[0 + i] - tmp[12 + i]); + out[0 + i] = (a0 + a1 + 7) >> 4; + out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0); + out[8 + i] = (a0 - a1 + 7) >> 4; + out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16); + } +} + +static void ITransformWHT(const int16_t* in, int16_t* out) { + int tmp[16]; + int i; + for (i = 0; i < 4; ++i) { + const int a0 = in[0 + i] + in[12 + i]; + const int a1 = in[4 + i] + in[ 8 + i]; + const int a2 = in[4 + i] - in[ 8 + i]; + const int a3 = in[0 + i] - in[12 + i]; + tmp[0 + i] = a0 + a1; + tmp[8 + i] = a0 - a1; + tmp[4 + i] = a3 + a2; + tmp[12 + i] = a3 - a2; + } + for (i = 0; i < 4; ++i) { + const int dc = tmp[0 + i * 4] + 3; // w/ rounder + const int a0 = dc + tmp[3 + i * 4]; + const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4]; + const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4]; + const int a3 = dc - tmp[3 + i * 4]; + out[ 0] = (a0 + a1) >> 3; + out[16] = (a3 + a2) >> 3; + out[32] = (a0 - a1) >> 3; + out[48] = (a3 - a2) >> 3; + out += 64; + } +} + +static void FTransformWHT(const int16_t* in, int16_t* out) { + int tmp[16]; + int i; + for (i = 0; i < 4; ++i, in += 64) { + const int a0 = (in[0 * 16] + in[2 * 16]) << 2; + const int a1 = (in[1 * 16] + in[3 * 16]) << 2; + const int a2 = (in[1 * 16] - in[3 * 16]) << 2; + const int a3 = (in[0 * 16] - in[2 * 16]) << 2; + tmp[0 + i * 4] = (a0 + a1) + (a0 != 0); + tmp[1 + i * 4] = a3 + a2; + tmp[2 + i * 4] = a3 - a2; + tmp[3 + i * 4] = a0 - a1; + } + for (i = 0; i < 4; ++i) { + const int a0 = (tmp[0 + i] + tmp[8 + i]); + const int a1 = (tmp[4 + i] + tmp[12+ i]); + const int a2 = (tmp[4 + i] - tmp[12+ i]); + const int a3 = (tmp[0 + i] - tmp[8 + i]); + const int b0 = a0 + a1; + const int b1 = a3 + a2; + const int b2 = a3 - a2; + const int b3 = a0 - a1; + out[ 0 + i] = (b0 + (b0 > 0) + 3) >> 3; + out[ 4 + i] = (b1 + (b1 > 0) + 3) >> 3; + out[ 8 + i] = (b2 + (b2 > 0) + 3) >> 3; + out[12 + i] = (b3 + (b3 > 0) + 3) >> 3; + } +} + +#undef MUL +#undef STORE + +//------------------------------------------------------------------------------ +// Intra predictions + +#define DST(x, y) dst[(x) + (y) * BPS] + +static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) { + int j; + for (j = 0; j < size; ++j) { + memset(dst + j * BPS, value, size); + } +} + +static WEBP_INLINE void VerticalPred(uint8_t* dst, + const uint8_t* top, int size) { + int j; + if (top) { + for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size); + } else { + Fill(dst, 127, size); + } +} + +static WEBP_INLINE void HorizontalPred(uint8_t* dst, + const uint8_t* left, int size) { + if (left) { + int j; + for (j = 0; j < size; ++j) { + memset(dst + j * BPS, left[j], size); + } + } else { + Fill(dst, 129, size); + } +} + +static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left, + const uint8_t* top, int size) { + int y; + if (left) { + if (top) { + const uint8_t* const clip = clip1 + 255 - left[-1]; + for (y = 0; y < size; ++y) { + const uint8_t* const clip_table = clip + left[y]; + int x; + for (x = 0; x < size; ++x) { + dst[x] = clip_table[top[x]]; + } + dst += BPS; + } + } else { + HorizontalPred(dst, left, size); + } + } else { + // true motion without left samples (hence: with default 129 value) + // is equivalent to VE prediction where you just copy the top samples. + // Note that if top samples are not available, the default value is + // then 129, and not 127 as in the VerticalPred case. + if (top) { + VerticalPred(dst, top, size); + } else { + Fill(dst, 129, size); + } + } +} + +static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left, + const uint8_t* top, + int size, int round, int shift) { + int DC = 0; + int j; + if (top) { + for (j = 0; j < size; ++j) DC += top[j]; + if (left) { // top and left present + for (j = 0; j < size; ++j) DC += left[j]; + } else { // top, but no left + DC += DC; + } + DC = (DC + round) >> shift; + } else if (left) { // left but no top + for (j = 0; j < size; ++j) DC += left[j]; + DC += DC; + DC = (DC + round) >> shift; + } else { // no top, no left, nothing. + DC = 0x80; + } + Fill(dst, DC, size); +} + +//------------------------------------------------------------------------------ +// Chroma 8x8 prediction (paragraph 12.2) + +static void IntraChromaPreds(uint8_t* dst, const uint8_t* left, + const uint8_t* top) { + // U block + DCMode(C8DC8 + dst, left, top, 8, 8, 4); + VerticalPred(C8VE8 + dst, top, 8); + HorizontalPred(C8HE8 + dst, left, 8); + TrueMotion(C8TM8 + dst, left, top, 8); + // V block + dst += 8; + if (top) top += 8; + if (left) left += 16; + DCMode(C8DC8 + dst, left, top, 8, 8, 4); + VerticalPred(C8VE8 + dst, top, 8); + HorizontalPred(C8HE8 + dst, left, 8); + TrueMotion(C8TM8 + dst, left, top, 8); +} + +//------------------------------------------------------------------------------ +// luma 16x16 prediction (paragraph 12.3) + +static void Intra16Preds(uint8_t* dst, + const uint8_t* left, const uint8_t* top) { + DCMode(I16DC16 + dst, left, top, 16, 16, 5); + VerticalPred(I16VE16 + dst, top, 16); + HorizontalPred(I16HE16 + dst, left, 16); + TrueMotion(I16TM16 + dst, left, top, 16); +} + +//------------------------------------------------------------------------------ +// luma 4x4 prediction + +#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) +#define AVG2(a, b) (((a) + (b) + 1) >> 1) + +static void VE4(uint8_t* dst, const uint8_t* top) { // vertical + const uint8_t vals[4] = { + AVG3(top[-1], top[0], top[1]), + AVG3(top[ 0], top[1], top[2]), + AVG3(top[ 1], top[2], top[3]), + AVG3(top[ 2], top[3], top[4]) + }; + int i; + for (i = 0; i < 4; ++i) { + memcpy(dst + i * BPS, vals, 4); + } +} + +static void HE4(uint8_t* dst, const uint8_t* top) { // horizontal + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(X, I, J); + *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(I, J, K); + *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(J, K, L); + *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(K, L, L); +} + +static void DC4(uint8_t* dst, const uint8_t* top) { + uint32_t dc = 4; + int i; + for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; + Fill(dst, dc >> 3, 4); +} + +static void RD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 3) = AVG3(J, K, L); + DST(0, 2) = DST(1, 3) = AVG3(I, J, K); + DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J); + DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I); + DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X); + DST(2, 0) = DST(3, 1) = AVG3(C, B, A); + DST(3, 0) = AVG3(D, C, B); +} + +static void LD4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG3(A, B, C); + DST(1, 0) = DST(0, 1) = AVG3(B, C, D); + DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E); + DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F); + DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G); + DST(3, 2) = DST(2, 3) = AVG3(F, G, H); + DST(3, 3) = AVG3(G, H, H); +} + +static void VR4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + DST(0, 0) = DST(1, 2) = AVG2(X, A); + DST(1, 0) = DST(2, 2) = AVG2(A, B); + DST(2, 0) = DST(3, 2) = AVG2(B, C); + DST(3, 0) = AVG2(C, D); + + DST(0, 3) = AVG3(K, J, I); + DST(0, 2) = AVG3(J, I, X); + DST(0, 1) = DST(1, 3) = AVG3(I, X, A); + DST(1, 1) = DST(2, 3) = AVG3(X, A, B); + DST(2, 1) = DST(3, 3) = AVG3(A, B, C); + DST(3, 1) = AVG3(B, C, D); +} + +static void VL4(uint8_t* dst, const uint8_t* top) { + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + const int D = top[3]; + const int E = top[4]; + const int F = top[5]; + const int G = top[6]; + const int H = top[7]; + DST(0, 0) = AVG2(A, B); + DST(1, 0) = DST(0, 2) = AVG2(B, C); + DST(2, 0) = DST(1, 2) = AVG2(C, D); + DST(3, 0) = DST(2, 2) = AVG2(D, E); + + DST(0, 1) = AVG3(A, B, C); + DST(1, 1) = DST(0, 3) = AVG3(B, C, D); + DST(2, 1) = DST(1, 3) = AVG3(C, D, E); + DST(3, 1) = DST(2, 3) = AVG3(D, E, F); + DST(3, 2) = AVG3(E, F, G); + DST(3, 3) = AVG3(F, G, H); +} + +static void HU4(uint8_t* dst, const uint8_t* top) { + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + DST(0, 0) = AVG2(I, J); + DST(2, 0) = DST(0, 1) = AVG2(J, K); + DST(2, 1) = DST(0, 2) = AVG2(K, L); + DST(1, 0) = AVG3(I, J, K); + DST(3, 0) = DST(1, 1) = AVG3(J, K, L); + DST(3, 1) = DST(1, 2) = AVG3(K, L, L); + DST(3, 2) = DST(2, 2) = + DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; +} + +static void HD4(uint8_t* dst, const uint8_t* top) { + const int X = top[-1]; + const int I = top[-2]; + const int J = top[-3]; + const int K = top[-4]; + const int L = top[-5]; + const int A = top[0]; + const int B = top[1]; + const int C = top[2]; + + DST(0, 0) = DST(2, 1) = AVG2(I, X); + DST(0, 1) = DST(2, 2) = AVG2(J, I); + DST(0, 2) = DST(2, 3) = AVG2(K, J); + DST(0, 3) = AVG2(L, K); + + DST(3, 0) = AVG3(A, B, C); + DST(2, 0) = AVG3(X, A, B); + DST(1, 0) = DST(3, 1) = AVG3(I, X, A); + DST(1, 1) = DST(3, 2) = AVG3(J, I, X); + DST(1, 2) = DST(3, 3) = AVG3(K, J, I); + DST(1, 3) = AVG3(L, K, J); +} + +static void TM4(uint8_t* dst, const uint8_t* top) { + int x, y; + const uint8_t* const clip = clip1 + 255 - top[-1]; + for (y = 0; y < 4; ++y) { + const uint8_t* const clip_table = clip + top[-2 - y]; + for (x = 0; x < 4; ++x) { + dst[x] = clip_table[top[x]]; + } + dst += BPS; + } +} + +#undef DST +#undef AVG3 +#undef AVG2 + +// Left samples are top[-5 .. -2], top_left is top[-1], top are +// located at top[0..3], and top right is top[4..7] +static void Intra4Preds(uint8_t* dst, const uint8_t* top) { + DC4(I4DC4 + dst, top); + TM4(I4TM4 + dst, top); + VE4(I4VE4 + dst, top); + HE4(I4HE4 + dst, top); + RD4(I4RD4 + dst, top); + VR4(I4VR4 + dst, top); + LD4(I4LD4 + dst, top); + VL4(I4VL4 + dst, top); + HD4(I4HD4 + dst, top); + HU4(I4HU4 + dst, top); +} + +//------------------------------------------------------------------------------ +// Metric + +static WEBP_INLINE int GetSSE(const uint8_t* a, const uint8_t* b, + int w, int h) { + int count = 0; + int y, x; + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + const int diff = (int)a[x] - b[x]; + count += diff * diff; + } + a += BPS; + b += BPS; + } + return count; +} + +static int SSE16x16(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 16, 16); +} +static int SSE16x8(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 16, 8); +} +static int SSE8x8(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 8, 8); +} +static int SSE4x4(const uint8_t* a, const uint8_t* b) { + return GetSSE(a, b, 4, 4); +} + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +// Hadamard transform +// Returns the weighted sum of the absolute value of transformed coefficients. +static int TTransform(const uint8_t* in, const uint16_t* w) { + int sum = 0; + int tmp[16]; + int i; + // horizontal pass + for (i = 0; i < 4; ++i, in += BPS) { + const int a0 = (in[0] + in[2]) << 2; + const int a1 = (in[1] + in[3]) << 2; + const int a2 = (in[1] - in[3]) << 2; + const int a3 = (in[0] - in[2]) << 2; + tmp[0 + i * 4] = a0 + a1 + (a0 != 0); + tmp[1 + i * 4] = a3 + a2; + tmp[2 + i * 4] = a3 - a2; + tmp[3 + i * 4] = a0 - a1; + } + // vertical pass + for (i = 0; i < 4; ++i, ++w) { + const int a0 = (tmp[0 + i] + tmp[8 + i]); + const int a1 = (tmp[4 + i] + tmp[12+ i]); + const int a2 = (tmp[4 + i] - tmp[12+ i]); + const int a3 = (tmp[0 + i] - tmp[8 + i]); + const int b0 = a0 + a1; + const int b1 = a3 + a2; + const int b2 = a3 - a2; + const int b3 = a0 - a1; + // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3 + sum += w[ 0] * ((abs(b0) + 3) >> 3); + sum += w[ 4] * ((abs(b1) + 3) >> 3); + sum += w[ 8] * ((abs(b2) + 3) >> 3); + sum += w[12] * ((abs(b3) + 3) >> 3); + } + return sum; +} + +static int Disto4x4(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int sum1 = TTransform(a, w); + const int sum2 = TTransform(b, w); + return (abs(sum2 - sum1) + 8) >> 4; +} + +static int Disto16x16(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4(a + x + y, b + x + y, w); + } + } + return D; +} + +//------------------------------------------------------------------------------ +// Quantization +// + +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +// Simple quantization +static int QuantizeBlock(int16_t in[16], int16_t out[16], + int n, const VP8Matrix* const mtx) { + int last = -1; + for (; n < 16; ++n) { + const int j = kZigzag[n]; + const int sign = (in[j] < 0); + int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; + if (coeff > 2047) coeff = 2047; + if (coeff > mtx->zthresh_[j]) { + const int Q = mtx->q_[j]; + const int iQ = mtx->iq_[j]; + const int B = mtx->bias_[j]; + out[n] = QUANTDIV(coeff, iQ, B); + if (sign) out[n] = -out[n]; + in[j] = out[n] * Q; + if (out[n]) last = n; + } else { + out[n] = 0; + in[j] = 0; + } + } + return (last >= 0); +} + +//------------------------------------------------------------------------------ +// Block copy + +static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) { + int y; + for (y = 0; y < size; ++y) { + memcpy(dst, src, size); + src += BPS; + dst += BPS; + } +} + +static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); } + +//------------------------------------------------------------------------------ +// Initialization + +// Speed-critical function pointers. We have to initialize them to the default +// implementations within VP8EncDspInit(). +VP8CHisto VP8CollectHistogram; +VP8Idct VP8ITransform; +VP8Fdct VP8FTransform; +VP8WHT VP8ITransformWHT; +VP8WHT VP8FTransformWHT; +VP8Intra4Preds VP8EncPredLuma4; +VP8IntraPreds VP8EncPredLuma16; +VP8IntraPreds VP8EncPredChroma8; +VP8Metric VP8SSE16x16; +VP8Metric VP8SSE8x8; +VP8Metric VP8SSE16x8; +VP8Metric VP8SSE4x4; +VP8WMetric VP8TDisto4x4; +VP8WMetric VP8TDisto16x16; +VP8QuantizeBlock VP8EncQuantizeBlock; +VP8BlockCopy VP8Copy4x4; + +extern void VP8EncDspInitSSE2(void); + +void VP8EncDspInit(void) { + InitTables(); + + // default C implementations + VP8CollectHistogram = CollectHistogram; + VP8ITransform = ITransform; + VP8FTransform = FTransform; + VP8ITransformWHT = ITransformWHT; + VP8FTransformWHT = FTransformWHT; + VP8EncPredLuma4 = Intra4Preds; + VP8EncPredLuma16 = Intra16Preds; + VP8EncPredChroma8 = IntraChromaPreds; + VP8SSE16x16 = SSE16x16; + VP8SSE8x8 = SSE8x8; + VP8SSE16x8 = SSE16x8; + VP8SSE4x4 = SSE4x4; + VP8TDisto4x4 = Disto4x4; + VP8TDisto16x16 = Disto16x16; + VP8EncQuantizeBlock = QuantizeBlock; + VP8Copy4x4 = Copy4x4; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo) { +#if defined(WEBP_USE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + VP8EncDspInitSSE2(); + } +#endif + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/enc_sse2.c b/external/libwebp/dsp/enc_sse2.c new file mode 100644 index 0000000000..0986e82e31 --- /dev/null +++ b/external/libwebp/dsp/enc_sse2.c @@ -0,0 +1,843 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// SSE2 version of speed-critical encoding functions. +// +// Author: Christian Duvivier (cduvivier@google.com) + +#include "./dsp.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if defined(WEBP_USE_SSE2) +#include // for abs() +#include + +#include "../enc/vp8enci.h" + +//------------------------------------------------------------------------------ +// Compute susceptibility based on DCT-coeff histograms: +// the higher, the "easier" the macroblock is to compress. + +static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred, + int start_block, int end_block) { + int histo[MAX_COEFF_THRESH + 1] = { 0 }; + int16_t out[16]; + int j, k; + const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH); + for (j = start_block; j < end_block; ++j) { + VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); + + // Convert coefficients to bin (within out[]). + { + // Load. + const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]); + const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]); + // sign(out) = out >> 15 (0x0000 if positive, 0xffff if negative) + const __m128i sign0 = _mm_srai_epi16(out0, 15); + const __m128i sign1 = _mm_srai_epi16(out1, 15); + // abs(out) = (out ^ sign) - sign + const __m128i xor0 = _mm_xor_si128(out0, sign0); + const __m128i xor1 = _mm_xor_si128(out1, sign1); + const __m128i abs0 = _mm_sub_epi16(xor0, sign0); + const __m128i abs1 = _mm_sub_epi16(xor1, sign1); + // v = abs(out) >> 2 + const __m128i v0 = _mm_srai_epi16(abs0, 2); + const __m128i v1 = _mm_srai_epi16(abs1, 2); + // bin = min(v, MAX_COEFF_THRESH) + const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh); + const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh); + // Store. + _mm_storeu_si128((__m128i*)&out[0], bin0); + _mm_storeu_si128((__m128i*)&out[8], bin1); + } + + // Use bin to update histogram. + for (k = 0; k < 16; ++k) { + histo[out[k]]++; + } + } + + return VP8GetAlpha(histo); +} + +//------------------------------------------------------------------------------ +// Transforms (Paragraph 14.4) + +// Does one or two inverse transforms. +static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst, + int do_two) { + // This implementation makes use of 16-bit fixed point versions of two + // multiply constants: + // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 + // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 + // + // To be able to use signed 16-bit integers, we use the following trick to + // have constants within range: + // - Associated constants are obtained by subtracting the 16-bit fixed point + // version of one: + // k = K - (1 << 16) => K = k + (1 << 16) + // K1 = 85267 => k1 = 20091 + // K2 = 35468 => k2 = -30068 + // - The multiplication of a variable by a constant become the sum of the + // variable and the multiplication of that variable by the associated + // constant: + // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x + const __m128i k1 = _mm_set1_epi16(20091); + const __m128i k2 = _mm_set1_epi16(-30068); + __m128i T0, T1, T2, T3; + + // Load and concatenate the transform coefficients (we'll do two inverse + // transforms in parallel). In the case of only one inverse transform, the + // second half of the vectors will just contain random value we'll never + // use nor store. + __m128i in0, in1, in2, in3; + { + in0 = _mm_loadl_epi64((__m128i*)&in[0]); + in1 = _mm_loadl_epi64((__m128i*)&in[4]); + in2 = _mm_loadl_epi64((__m128i*)&in[8]); + in3 = _mm_loadl_epi64((__m128i*)&in[12]); + // a00 a10 a20 a30 x x x x + // a01 a11 a21 a31 x x x x + // a02 a12 a22 a32 x x x x + // a03 a13 a23 a33 x x x x + if (do_two) { + const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]); + const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]); + const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]); + const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]); + in0 = _mm_unpacklo_epi64(in0, inB0); + in1 = _mm_unpacklo_epi64(in1, inB1); + in2 = _mm_unpacklo_epi64(in2, inB2); + in3 = _mm_unpacklo_epi64(in3, inB3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + } + + // Vertical pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i a = _mm_add_epi16(in0, in2); + const __m128i b = _mm_sub_epi16(in0, in2); + // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 + const __m128i c1 = _mm_mulhi_epi16(in1, k2); + const __m128i c2 = _mm_mulhi_epi16(in3, k1); + const __m128i c3 = _mm_sub_epi16(in1, in3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 + const __m128i d1 = _mm_mulhi_epi16(in1, k1); + const __m128i d2 = _mm_mulhi_epi16(in3, k2); + const __m128i d3 = _mm_add_epi16(in1, in3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + + // Transpose the two 4x4. + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(tmp0, tmp1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(tmp2, tmp3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(tmp0, tmp1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(tmp2, tmp3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Horizontal pass and subsequent transpose. + { + // First pass, c and d calculations are longer because of the "trick" + // multiplications. + const __m128i four = _mm_set1_epi16(4); + const __m128i dc = _mm_add_epi16(T0, four); + const __m128i a = _mm_add_epi16(dc, T2); + const __m128i b = _mm_sub_epi16(dc, T2); + // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 + const __m128i c1 = _mm_mulhi_epi16(T1, k2); + const __m128i c2 = _mm_mulhi_epi16(T3, k1); + const __m128i c3 = _mm_sub_epi16(T1, T3); + const __m128i c4 = _mm_sub_epi16(c1, c2); + const __m128i c = _mm_add_epi16(c3, c4); + // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 + const __m128i d1 = _mm_mulhi_epi16(T1, k1); + const __m128i d2 = _mm_mulhi_epi16(T3, k2); + const __m128i d3 = _mm_add_epi16(T1, T3); + const __m128i d4 = _mm_add_epi16(d1, d2); + const __m128i d = _mm_add_epi16(d3, d4); + + // Second pass. + const __m128i tmp0 = _mm_add_epi16(a, d); + const __m128i tmp1 = _mm_add_epi16(b, c); + const __m128i tmp2 = _mm_sub_epi16(b, c); + const __m128i tmp3 = _mm_sub_epi16(a, d); + const __m128i shifted0 = _mm_srai_epi16(tmp0, 3); + const __m128i shifted1 = _mm_srai_epi16(tmp1, 3); + const __m128i shifted2 = _mm_srai_epi16(tmp2, 3); + const __m128i shifted3 = _mm_srai_epi16(tmp3, 3); + + // Transpose the two 4x4. + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(shifted0, shifted1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(shifted2, shifted3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(shifted0, shifted1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(shifted2, shifted3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Add inverse transform to 'ref' and store. + { + const __m128i zero = _mm_set1_epi16(0); + // Load the reference(s). + __m128i ref0, ref1, ref2, ref3; + if (do_two) { + // Load eight bytes/pixels per line. + ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]); + ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]); + ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]); + ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]); + } else { + // Load four bytes/pixels per line. + ref0 = _mm_cvtsi32_si128(*(int*)&ref[0 * BPS]); + ref1 = _mm_cvtsi32_si128(*(int*)&ref[1 * BPS]); + ref2 = _mm_cvtsi32_si128(*(int*)&ref[2 * BPS]); + ref3 = _mm_cvtsi32_si128(*(int*)&ref[3 * BPS]); + } + // Convert to 16b. + ref0 = _mm_unpacklo_epi8(ref0, zero); + ref1 = _mm_unpacklo_epi8(ref1, zero); + ref2 = _mm_unpacklo_epi8(ref2, zero); + ref3 = _mm_unpacklo_epi8(ref3, zero); + // Add the inverse transform(s). + ref0 = _mm_add_epi16(ref0, T0); + ref1 = _mm_add_epi16(ref1, T1); + ref2 = _mm_add_epi16(ref2, T2); + ref3 = _mm_add_epi16(ref3, T3); + // Unsigned saturate to 8b. + ref0 = _mm_packus_epi16(ref0, ref0); + ref1 = _mm_packus_epi16(ref1, ref1); + ref2 = _mm_packus_epi16(ref2, ref2); + ref3 = _mm_packus_epi16(ref3, ref3); + // Store the results. + if (do_two) { + // Store eight bytes/pixels per line. + _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0); + _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1); + _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2); + _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3); + } else { + // Store four bytes/pixels per line. + *((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(ref0); + *((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(ref1); + *((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(ref2); + *((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(ref3); + } + } +} + +static void FTransformSSE2(const uint8_t* src, const uint8_t* ref, + int16_t* out) { + const __m128i zero = _mm_setzero_si128(); + const __m128i seven = _mm_set1_epi16(7); + const __m128i k7500 = _mm_set1_epi32(7500); + const __m128i k14500 = _mm_set1_epi32(14500); + const __m128i k51000 = _mm_set1_epi32(51000); + const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16)); + const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217, + 5352, 2217, 5352, 2217); + const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352, + 2217, -5352, 2217, -5352); + + __m128i v01, v32; + + // Difference between src and ref and initial transpose. + { + // Load src and convert to 16b. + const __m128i src0 = _mm_loadl_epi64((__m128i*)&src[0 * BPS]); + const __m128i src1 = _mm_loadl_epi64((__m128i*)&src[1 * BPS]); + const __m128i src2 = _mm_loadl_epi64((__m128i*)&src[2 * BPS]); + const __m128i src3 = _mm_loadl_epi64((__m128i*)&src[3 * BPS]); + const __m128i src_0 = _mm_unpacklo_epi8(src0, zero); + const __m128i src_1 = _mm_unpacklo_epi8(src1, zero); + const __m128i src_2 = _mm_unpacklo_epi8(src2, zero); + const __m128i src_3 = _mm_unpacklo_epi8(src3, zero); + // Load ref and convert to 16b. + const __m128i ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]); + const __m128i ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]); + const __m128i ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]); + const __m128i ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]); + const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero); + const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero); + const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero); + const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero); + // Compute difference. + const __m128i diff0 = _mm_sub_epi16(src_0, ref_0); + const __m128i diff1 = _mm_sub_epi16(src_1, ref_1); + const __m128i diff2 = _mm_sub_epi16(src_2, ref_2); + const __m128i diff3 = _mm_sub_epi16(src_3, ref_3); + + // Transpose. + // 00 01 02 03 0 0 0 0 + // 10 11 12 13 0 0 0 0 + // 20 21 22 23 0 0 0 0 + // 30 31 32 33 0 0 0 0 + const __m128i transpose0_0 = _mm_unpacklo_epi16(diff0, diff1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(diff2, diff3); + // 00 10 01 11 02 12 03 13 + // 20 30 21 31 22 32 23 33 + const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); + // a02 a12 a22 a32 a03 a13 a23 a33 + // a00 a10 a20 a30 a01 a11 a21 a31 + // a03 a13 a23 a33 a02 a12 a22 a32 + } + + // First pass and subsequent transpose. + { + // Same operations are done on the (0,3) and (1,2) pairs. + // b0 = (a0 + a3) << 3 + // b1 = (a1 + a2) << 3 + // b3 = (a0 - a3) << 3 + // b2 = (a1 - a2) << 3 + const __m128i a01 = _mm_add_epi16(v01, v32); + const __m128i a32 = _mm_sub_epi16(v01, v32); + const __m128i b01 = _mm_slli_epi16(a01, 3); + const __m128i b32 = _mm_slli_epi16(a32, 3); + const __m128i b11 = _mm_unpackhi_epi64(b01, b01); + const __m128i b22 = _mm_unpackhi_epi64(b32, b32); + + // e0 = b0 + b1 + // e2 = b0 - b1 + const __m128i e0 = _mm_add_epi16(b01, b11); + const __m128i e2 = _mm_sub_epi16(b01, b11); + const __m128i e02 = _mm_unpacklo_epi64(e0, e2); + + // e1 = (b3 * 5352 + b2 * 2217 + 14500) >> 12 + // e3 = (b3 * 2217 - b2 * 5352 + 7500) >> 12 + const __m128i b23 = _mm_unpacklo_epi16(b22, b32); + const __m128i c1 = _mm_madd_epi16(b23, k5352_2217); + const __m128i c3 = _mm_madd_epi16(b23, k2217_5352); + const __m128i d1 = _mm_add_epi32(c1, k14500); + const __m128i d3 = _mm_add_epi32(c3, k7500); + const __m128i e1 = _mm_srai_epi32(d1, 12); + const __m128i e3 = _mm_srai_epi32(d3, 12); + const __m128i e13 = _mm_packs_epi32(e1, e3); + + // Transpose. + // 00 01 02 03 20 21 22 23 + // 10 11 12 13 30 31 32 33 + const __m128i transpose0_0 = _mm_unpacklo_epi16(e02, e13); + const __m128i transpose0_1 = _mm_unpackhi_epi16(e02, e13); + // 00 10 01 11 02 12 03 13 + // 20 30 21 31 22 32 23 33 + const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); + // 02 12 22 32 03 13 23 33 + // 00 10 20 30 01 11 21 31 + // 03 13 23 33 02 12 22 32 + } + + // Second pass + { + // Same operations are done on the (0,3) and (1,2) pairs. + // a0 = v0 + v3 + // a1 = v1 + v2 + // a3 = v0 - v3 + // a2 = v1 - v2 + const __m128i a01 = _mm_add_epi16(v01, v32); + const __m128i a32 = _mm_sub_epi16(v01, v32); + const __m128i a11 = _mm_unpackhi_epi64(a01, a01); + const __m128i a22 = _mm_unpackhi_epi64(a32, a32); + + // d0 = (a0 + a1 + 7) >> 4; + // d2 = (a0 - a1 + 7) >> 4; + const __m128i b0 = _mm_add_epi16(a01, a11); + const __m128i b2 = _mm_sub_epi16(a01, a11); + const __m128i c0 = _mm_add_epi16(b0, seven); + const __m128i c2 = _mm_add_epi16(b2, seven); + const __m128i d0 = _mm_srai_epi16(c0, 4); + const __m128i d2 = _mm_srai_epi16(c2, 4); + + // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16) + // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16) + const __m128i b23 = _mm_unpacklo_epi16(a22, a32); + const __m128i c1 = _mm_madd_epi16(b23, k5352_2217); + const __m128i c3 = _mm_madd_epi16(b23, k2217_5352); + const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one); + const __m128i d3 = _mm_add_epi32(c3, k51000); + const __m128i e1 = _mm_srai_epi32(d1, 16); + const __m128i e3 = _mm_srai_epi32(d3, 16); + const __m128i f1 = _mm_packs_epi32(e1, e1); + const __m128i f3 = _mm_packs_epi32(e3, e3); + // f1 = f1 + (a3 != 0); + // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the + // desired (0, 1), we add one earlier through k12000_plus_one. + const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero)); + + _mm_storel_epi64((__m128i*)&out[ 0], d0); + _mm_storel_epi64((__m128i*)&out[ 4], g1); + _mm_storel_epi64((__m128i*)&out[ 8], d2); + _mm_storel_epi64((__m128i*)&out[12], f3); + } +} + +//------------------------------------------------------------------------------ +// Metric + +static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) { + const __m128i zero = _mm_set1_epi16(0); + + // Load values. + const __m128i a0 = _mm_loadl_epi64((__m128i*)&a[BPS * 0]); + const __m128i a1 = _mm_loadl_epi64((__m128i*)&a[BPS * 1]); + const __m128i a2 = _mm_loadl_epi64((__m128i*)&a[BPS * 2]); + const __m128i a3 = _mm_loadl_epi64((__m128i*)&a[BPS * 3]); + const __m128i b0 = _mm_loadl_epi64((__m128i*)&b[BPS * 0]); + const __m128i b1 = _mm_loadl_epi64((__m128i*)&b[BPS * 1]); + const __m128i b2 = _mm_loadl_epi64((__m128i*)&b[BPS * 2]); + const __m128i b3 = _mm_loadl_epi64((__m128i*)&b[BPS * 3]); + + // Combine pair of lines and convert to 16b. + const __m128i a01 = _mm_unpacklo_epi32(a0, a1); + const __m128i a23 = _mm_unpacklo_epi32(a2, a3); + const __m128i b01 = _mm_unpacklo_epi32(b0, b1); + const __m128i b23 = _mm_unpacklo_epi32(b2, b3); + const __m128i a01s = _mm_unpacklo_epi8(a01, zero); + const __m128i a23s = _mm_unpacklo_epi8(a23, zero); + const __m128i b01s = _mm_unpacklo_epi8(b01, zero); + const __m128i b23s = _mm_unpacklo_epi8(b23, zero); + + // Compute differences; (a-b)^2 = (abs(a-b))^2 = (sat8(a-b) + sat8(b-a))^2 + // TODO(cduvivier): Dissassemble and figure out why this is fastest. We don't + // need absolute values, there is no need to do calculation + // in 8bit as we are already in 16bit, ... Yet this is what + // benchmarks the fastest! + const __m128i d0 = _mm_subs_epu8(a01s, b01s); + const __m128i d1 = _mm_subs_epu8(b01s, a01s); + const __m128i d2 = _mm_subs_epu8(a23s, b23s); + const __m128i d3 = _mm_subs_epu8(b23s, a23s); + + // Square and add them all together. + const __m128i madd0 = _mm_madd_epi16(d0, d0); + const __m128i madd1 = _mm_madd_epi16(d1, d1); + const __m128i madd2 = _mm_madd_epi16(d2, d2); + const __m128i madd3 = _mm_madd_epi16(d3, d3); + const __m128i sum0 = _mm_add_epi32(madd0, madd1); + const __m128i sum1 = _mm_add_epi32(madd2, madd3); + const __m128i sum2 = _mm_add_epi32(sum0, sum1); + int32_t tmp[4]; + _mm_storeu_si128((__m128i*)tmp, sum2); + return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); +} + +//------------------------------------------------------------------------------ +// Texture distortion +// +// We try to match the spectral content (weighted) between source and +// reconstructed samples. + +// Hadamard transform +// Returns the difference between the weighted sum of the absolute value of +// transformed coefficients. +static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB, + const uint16_t* const w) { + int32_t sum[4]; + __m128i tmp_0, tmp_1, tmp_2, tmp_3; + const __m128i zero = _mm_setzero_si128(); + const __m128i one = _mm_set1_epi16(1); + const __m128i three = _mm_set1_epi16(3); + + // Load, combine and tranpose inputs. + { + const __m128i inA_0 = _mm_loadl_epi64((__m128i*)&inA[BPS * 0]); + const __m128i inA_1 = _mm_loadl_epi64((__m128i*)&inA[BPS * 1]); + const __m128i inA_2 = _mm_loadl_epi64((__m128i*)&inA[BPS * 2]); + const __m128i inA_3 = _mm_loadl_epi64((__m128i*)&inA[BPS * 3]); + const __m128i inB_0 = _mm_loadl_epi64((__m128i*)&inB[BPS * 0]); + const __m128i inB_1 = _mm_loadl_epi64((__m128i*)&inB[BPS * 1]); + const __m128i inB_2 = _mm_loadl_epi64((__m128i*)&inB[BPS * 2]); + const __m128i inB_3 = _mm_loadl_epi64((__m128i*)&inB[BPS * 3]); + + // Combine inA and inB (we'll do two transforms in parallel). + const __m128i inAB_0 = _mm_unpacklo_epi8(inA_0, inB_0); + const __m128i inAB_1 = _mm_unpacklo_epi8(inA_1, inB_1); + const __m128i inAB_2 = _mm_unpacklo_epi8(inA_2, inB_2); + const __m128i inAB_3 = _mm_unpacklo_epi8(inA_3, inB_3); + // a00 b00 a01 b01 a02 b03 a03 b03 0 0 0 0 0 0 0 0 + // a10 b10 a11 b11 a12 b12 a13 b13 0 0 0 0 0 0 0 0 + // a20 b20 a21 b21 a22 b22 a23 b23 0 0 0 0 0 0 0 0 + // a30 b30 a31 b31 a32 b32 a33 b33 0 0 0 0 0 0 0 0 + + // Transpose the two 4x4, discarding the filling zeroes. + const __m128i transpose0_0 = _mm_unpacklo_epi8(inAB_0, inAB_2); + const __m128i transpose0_1 = _mm_unpacklo_epi8(inAB_1, inAB_3); + // a00 a20 b00 b20 a01 a21 b01 b21 a02 a22 b02 b22 a03 a23 b03 b23 + // a10 a30 b10 b30 a11 a31 b11 b31 a12 a32 b12 b32 a13 a33 b13 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi8(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpackhi_epi8(transpose0_0, transpose0_1); + // a00 a10 a20 a30 b00 b10 b20 b30 a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 a03 a13 a23 a33 b03 b13 b23 b33 + + // Convert to 16b. + tmp_0 = _mm_unpacklo_epi8(transpose1_0, zero); + tmp_1 = _mm_unpackhi_epi8(transpose1_0, zero); + tmp_2 = _mm_unpacklo_epi8(transpose1_1, zero); + tmp_3 = _mm_unpackhi_epi8(transpose1_1, zero); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Horizontal pass and subsequent transpose. + { + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_slli_epi16(_mm_add_epi16(tmp_0, tmp_2), 2); + const __m128i a1 = _mm_slli_epi16(_mm_add_epi16(tmp_1, tmp_3), 2); + const __m128i a2 = _mm_slli_epi16(_mm_sub_epi16(tmp_1, tmp_3), 2); + const __m128i a3 = _mm_slli_epi16(_mm_sub_epi16(tmp_0, tmp_2), 2); + // b0_extra = (a0 != 0); + const __m128i b0_extra = _mm_andnot_si128(_mm_cmpeq_epi16 (a0, zero), one); + const __m128i b0_base = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + const __m128i b0 = _mm_add_epi16(b0_base, b0_extra); + // a00 a01 a02 a03 b00 b01 b02 b03 + // a10 a11 a12 a13 b10 b11 b12 b13 + // a20 a21 a22 a23 b20 b21 b22 b23 + // a30 a31 a32 a33 b30 b31 b32 b33 + + // Transpose the two 4x4. + const __m128i transpose0_0 = _mm_unpacklo_epi16(b0, b1); + const __m128i transpose0_1 = _mm_unpacklo_epi16(b2, b3); + const __m128i transpose0_2 = _mm_unpackhi_epi16(b0, b1); + const __m128i transpose0_3 = _mm_unpackhi_epi16(b2, b3); + // a00 a10 a01 a11 a02 a12 a03 a13 + // a20 a30 a21 a31 a22 a32 a23 a33 + // b00 b10 b01 b11 b02 b12 b03 b13 + // b20 b30 b21 b31 b22 b32 b23 b33 + const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3); + const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1); + const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3); + // a00 a10 a20 a30 a01 a11 a21 a31 + // b00 b10 b20 b30 b01 b11 b21 b31 + // a02 a12 a22 a32 a03 a13 a23 a33 + // b02 b12 a22 b32 b03 b13 b23 b33 + tmp_0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1); + tmp_1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1); + tmp_2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3); + tmp_3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3); + // a00 a10 a20 a30 b00 b10 b20 b30 + // a01 a11 a21 a31 b01 b11 b21 b31 + // a02 a12 a22 a32 b02 b12 b22 b32 + // a03 a13 a23 a33 b03 b13 b23 b33 + } + + // Vertical pass and difference of weighted sums. + { + // Load all inputs. + // TODO(cduvivier): Make variable declarations and allocations aligned so + // we can use _mm_load_si128 instead of _mm_loadu_si128. + const __m128i w_0 = _mm_loadu_si128((__m128i*)&w[0]); + const __m128i w_8 = _mm_loadu_si128((__m128i*)&w[8]); + + // Calculate a and b (two 4x4 at once). + const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); + const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); + const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); + const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); + const __m128i b0 = _mm_add_epi16(a0, a1); + const __m128i b1 = _mm_add_epi16(a3, a2); + const __m128i b2 = _mm_sub_epi16(a3, a2); + const __m128i b3 = _mm_sub_epi16(a0, a1); + + // Separate the transforms of inA and inB. + __m128i A_b0 = _mm_unpacklo_epi64(b0, b1); + __m128i A_b2 = _mm_unpacklo_epi64(b2, b3); + __m128i B_b0 = _mm_unpackhi_epi64(b0, b1); + __m128i B_b2 = _mm_unpackhi_epi64(b2, b3); + + { + // sign(b) = b >> 15 (0x0000 if positive, 0xffff if negative) + const __m128i sign_A_b0 = _mm_srai_epi16(A_b0, 15); + const __m128i sign_A_b2 = _mm_srai_epi16(A_b2, 15); + const __m128i sign_B_b0 = _mm_srai_epi16(B_b0, 15); + const __m128i sign_B_b2 = _mm_srai_epi16(B_b2, 15); + + // b = abs(b) = (b ^ sign) - sign + A_b0 = _mm_xor_si128(A_b0, sign_A_b0); + A_b2 = _mm_xor_si128(A_b2, sign_A_b2); + B_b0 = _mm_xor_si128(B_b0, sign_B_b0); + B_b2 = _mm_xor_si128(B_b2, sign_B_b2); + A_b0 = _mm_sub_epi16(A_b0, sign_A_b0); + A_b2 = _mm_sub_epi16(A_b2, sign_A_b2); + B_b0 = _mm_sub_epi16(B_b0, sign_B_b0); + B_b2 = _mm_sub_epi16(B_b2, sign_B_b2); + } + + // b = abs(b) + 3 + A_b0 = _mm_add_epi16(A_b0, three); + A_b2 = _mm_add_epi16(A_b2, three); + B_b0 = _mm_add_epi16(B_b0, three); + B_b2 = _mm_add_epi16(B_b2, three); + + // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3 + // b = (abs(b) + 3) >> 3 + A_b0 = _mm_srai_epi16(A_b0, 3); + A_b2 = _mm_srai_epi16(A_b2, 3); + B_b0 = _mm_srai_epi16(B_b0, 3); + B_b2 = _mm_srai_epi16(B_b2, 3); + + // weighted sums + A_b0 = _mm_madd_epi16(A_b0, w_0); + A_b2 = _mm_madd_epi16(A_b2, w_8); + B_b0 = _mm_madd_epi16(B_b0, w_0); + B_b2 = _mm_madd_epi16(B_b2, w_8); + A_b0 = _mm_add_epi32(A_b0, A_b2); + B_b0 = _mm_add_epi32(B_b0, B_b2); + + // difference of weighted sums + A_b0 = _mm_sub_epi32(A_b0, B_b0); + _mm_storeu_si128((__m128i*)&sum[0], A_b0); + } + return sum[0] + sum[1] + sum[2] + sum[3]; +} + +static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + const int diff_sum = TTransformSSE2(a, b, w); + return (abs(diff_sum) + 8) >> 4; +} + +static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b, + const uint16_t* const w) { + int D = 0; + int x, y; + for (y = 0; y < 16 * BPS; y += 4 * BPS) { + for (x = 0; x < 16; x += 4) { + D += Disto4x4SSE2(a + x + y, b + x + y, w); + } + } + return D; +} + + +//------------------------------------------------------------------------------ +// Quantization +// + +// Simple quantization +static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16], + int n, const VP8Matrix* const mtx) { + const __m128i max_coeff_2047 = _mm_set1_epi16(2047); + const __m128i zero = _mm_set1_epi16(0); + __m128i sign0, sign8; + __m128i coeff0, coeff8; + __m128i out0, out8; + __m128i packed_out; + + // Load all inputs. + // TODO(cduvivier): Make variable declarations and allocations aligned so that + // we can use _mm_load_si128 instead of _mm_loadu_si128. + __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); + __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); + const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[0]); + const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[8]); + const __m128i iq0 = _mm_loadu_si128((__m128i*)&mtx->iq_[0]); + const __m128i iq8 = _mm_loadu_si128((__m128i*)&mtx->iq_[8]); + const __m128i bias0 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]); + const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]); + const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]); + const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]); + const __m128i zthresh0 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[0]); + const __m128i zthresh8 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[8]); + + // sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative) + sign0 = _mm_srai_epi16(in0, 15); + sign8 = _mm_srai_epi16(in8, 15); + + // coeff = abs(in) = (in ^ sign) - sign + coeff0 = _mm_xor_si128(in0, sign0); + coeff8 = _mm_xor_si128(in8, sign8); + coeff0 = _mm_sub_epi16(coeff0, sign0); + coeff8 = _mm_sub_epi16(coeff8, sign8); + + // coeff = abs(in) + sharpen + coeff0 = _mm_add_epi16(coeff0, sharpen0); + coeff8 = _mm_add_epi16(coeff8, sharpen8); + + // if (coeff > 2047) coeff = 2047 + coeff0 = _mm_min_epi16(coeff0, max_coeff_2047); + coeff8 = _mm_min_epi16(coeff8, max_coeff_2047); + + // out = (coeff * iQ + B) >> QFIX; + { + // doing calculations with 32b precision (QFIX=17) + // out = (coeff * iQ) + __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0); + __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0); + __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8); + __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8); + __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); + __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); + __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); + // expand bias from 16b to 32b + __m128i bias_00 = _mm_unpacklo_epi16(bias0, zero); + __m128i bias_04 = _mm_unpackhi_epi16(bias0, zero); + __m128i bias_08 = _mm_unpacklo_epi16(bias8, zero); + __m128i bias_12 = _mm_unpackhi_epi16(bias8, zero); + // out = (coeff * iQ + B) + out_00 = _mm_add_epi32(out_00, bias_00); + out_04 = _mm_add_epi32(out_04, bias_04); + out_08 = _mm_add_epi32(out_08, bias_08); + out_12 = _mm_add_epi32(out_12, bias_12); + // out = (coeff * iQ + B) >> QFIX; + out_00 = _mm_srai_epi32(out_00, QFIX); + out_04 = _mm_srai_epi32(out_04, QFIX); + out_08 = _mm_srai_epi32(out_08, QFIX); + out_12 = _mm_srai_epi32(out_12, QFIX); + // pack result as 16b + out0 = _mm_packs_epi32(out_00, out_04); + out8 = _mm_packs_epi32(out_08, out_12); + } + + // get sign back (if (sign[j]) out_n = -out_n) + out0 = _mm_xor_si128(out0, sign0); + out8 = _mm_xor_si128(out8, sign8); + out0 = _mm_sub_epi16(out0, sign0); + out8 = _mm_sub_epi16(out8, sign8); + + // in = out * Q + in0 = _mm_mullo_epi16(out0, q0); + in8 = _mm_mullo_epi16(out8, q8); + + // if (coeff <= mtx->zthresh_) {in=0; out=0;} + { + __m128i cmp0 = _mm_cmpgt_epi16(coeff0, zthresh0); + __m128i cmp8 = _mm_cmpgt_epi16(coeff8, zthresh8); + in0 = _mm_and_si128(in0, cmp0); + in8 = _mm_and_si128(in8, cmp8); + _mm_storeu_si128((__m128i*)&in[0], in0); + _mm_storeu_si128((__m128i*)&in[8], in8); + out0 = _mm_and_si128(out0, cmp0); + out8 = _mm_and_si128(out8, cmp8); + } + + // zigzag the output before storing it. + // + // The zigzag pattern can almost be reproduced with a small sequence of + // shuffles. After it, we only need to swap the 7th (ending up in third + // position instead of twelfth) and 8th values. + { + __m128i outZ0, outZ8; + outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0)); + outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0)); + outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2)); + outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1)); + outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0)); + outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0)); + _mm_storeu_si128((__m128i*)&out[0], outZ0); + _mm_storeu_si128((__m128i*)&out[8], outZ8); + packed_out = _mm_packs_epi16(outZ0, outZ8); + } + { + const int16_t outZ_12 = out[12]; + const int16_t outZ_3 = out[3]; + out[3] = outZ_12; + out[12] = outZ_3; + } + + // detect if all 'out' values are zeroes or not + { + int32_t tmp[4]; + _mm_storeu_si128((__m128i*)tmp, packed_out); + if (n) { + tmp[0] &= ~0xff; + } + return (tmp[3] || tmp[2] || tmp[1] || tmp[0]); + } +} + +#endif // WEBP_USE_SSE2 + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8EncDspInitSSE2(void); + +void VP8EncDspInitSSE2(void) { +#if defined(WEBP_USE_SSE2) + VP8CollectHistogram = CollectHistogramSSE2; + VP8EncQuantizeBlock = QuantizeBlockSSE2; + VP8ITransform = ITransformSSE2; + VP8FTransform = FTransformSSE2; + VP8SSE4x4 = SSE4x4SSE2; + VP8TDisto4x4 = Disto4x4SSE2; + VP8TDisto16x16 = Disto16x16SSE2; +#endif // WEBP_USE_SSE2 +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/lossless.c b/external/libwebp/dsp/lossless.c new file mode 100644 index 0000000000..a077f6e759 --- /dev/null +++ b/external/libwebp/dsp/lossless.c @@ -0,0 +1,1140 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) + +#include "platform/CCPlatformConfig.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include +#include +#include "./lossless.h" +#include "../dec/vp8li.h" +#include "../dsp/yuv.h" +#include "../dsp/dsp.h" +#include "../enc/histogram.h" + +#define MAX_DIFF_COST (1e30f) + +// lookup table for small values of log2(int) +#define APPROX_LOG_MAX 4096 +#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086 +#define LOG_LOOKUP_IDX_MAX 256 +static const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { + 0.0000000000000000f, 0.0000000000000000f, + 1.0000000000000000f, 1.5849625007211560f, + 2.0000000000000000f, 2.3219280948873621f, + 2.5849625007211560f, 2.8073549220576041f, + 3.0000000000000000f, 3.1699250014423121f, + 3.3219280948873621f, 3.4594316186372973f, + 3.5849625007211560f, 3.7004397181410921f, + 3.8073549220576041f, 3.9068905956085187f, + 4.0000000000000000f, 4.0874628412503390f, + 4.1699250014423121f, 4.2479275134435852f, + 4.3219280948873626f, 4.3923174227787606f, + 4.4594316186372973f, 4.5235619560570130f, + 4.5849625007211560f, 4.6438561897747243f, + 4.7004397181410917f, 4.7548875021634682f, + 4.8073549220576037f, 4.8579809951275718f, + 4.9068905956085187f, 4.9541963103868749f, + 5.0000000000000000f, 5.0443941193584533f, + 5.0874628412503390f, 5.1292830169449663f, + 5.1699250014423121f, 5.2094533656289501f, + 5.2479275134435852f, 5.2854022188622487f, + 5.3219280948873626f, 5.3575520046180837f, + 5.3923174227787606f, 5.4262647547020979f, + 5.4594316186372973f, 5.4918530963296747f, + 5.5235619560570130f, 5.5545888516776376f, + 5.5849625007211560f, 5.6147098441152083f, + 5.6438561897747243f, 5.6724253419714951f, + 5.7004397181410917f, 5.7279204545631987f, + 5.7548875021634682f, 5.7813597135246599f, + 5.8073549220576037f, 5.8328900141647412f, + 5.8579809951275718f, 5.8826430493618415f, + 5.9068905956085187f, 5.9307373375628866f, + 5.9541963103868749f, 5.9772799234999167f, + 6.0000000000000000f, 6.0223678130284543f, + 6.0443941193584533f, 6.0660891904577720f, + 6.0874628412503390f, 6.1085244567781691f, + 6.1292830169449663f, 6.1497471195046822f, + 6.1699250014423121f, 6.1898245588800175f, + 6.2094533656289501f, 6.2288186904958804f, + 6.2479275134435852f, 6.2667865406949010f, + 6.2854022188622487f, 6.3037807481771030f, + 6.3219280948873626f, 6.3398500028846243f, + 6.3575520046180837f, 6.3750394313469245f, + 6.3923174227787606f, 6.4093909361377017f, + 6.4262647547020979f, 6.4429434958487279f, + 6.4594316186372973f, 6.4757334309663976f, + 6.4918530963296747f, 6.5077946401986963f, + 6.5235619560570130f, 6.5391588111080309f, + 6.5545888516776376f, 6.5698556083309478f, + 6.5849625007211560f, 6.5999128421871278f, + 6.6147098441152083f, 6.6293566200796094f, + 6.6438561897747243f, 6.6582114827517946f, + 6.6724253419714951f, 6.6865005271832185f, + 6.7004397181410917f, 6.7142455176661224f, + 6.7279204545631987f, 6.7414669864011464f, + 6.7548875021634682f, 6.7681843247769259f, + 6.7813597135246599f, 6.7944158663501061f, + 6.8073549220576037f, 6.8201789624151878f, + 6.8328900141647412f, 6.8454900509443747f, + 6.8579809951275718f, 6.8703647195834047f, + 6.8826430493618415f, 6.8948177633079437f, + 6.9068905956085187f, 6.9188632372745946f, + 6.9307373375628866f, 6.9425145053392398f, + 6.9541963103868749f, 6.9657842846620869f, + 6.9772799234999167f, 6.9886846867721654f, + 7.0000000000000000f, 7.0112272554232539f, + 7.0223678130284543f, 7.0334230015374501f, + 7.0443941193584533f, 7.0552824355011898f, + 7.0660891904577720f, 7.0768155970508308f, + 7.0874628412503390f, 7.0980320829605263f, + 7.1085244567781691f, 7.1189410727235076f, + 7.1292830169449663f, 7.1395513523987936f, + 7.1497471195046822f, 7.1598713367783890f, + 7.1699250014423121f, 7.1799090900149344f, + 7.1898245588800175f, 7.1996723448363644f, + 7.2094533656289501f, 7.2191685204621611f, + 7.2288186904958804f, 7.2384047393250785f, + 7.2479275134435852f, 7.2573878426926521f, + 7.2667865406949010f, 7.2761244052742375f, + 7.2854022188622487f, 7.2946207488916270f, + 7.3037807481771030f, 7.3128829552843557f, + 7.3219280948873626f, 7.3309168781146167f, + 7.3398500028846243f, 7.3487281542310771f, + 7.3575520046180837f, 7.3663222142458160f, + 7.3750394313469245f, 7.3837042924740519f, + 7.3923174227787606f, 7.4008794362821843f, + 7.4093909361377017f, 7.4178525148858982f, + 7.4262647547020979f, 7.4346282276367245f, + 7.4429434958487279f, 7.4512111118323289f, + 7.4594316186372973f, 7.4676055500829976f, + 7.4757334309663976f, 7.4838157772642563f, + 7.4918530963296747f, 7.4998458870832056f, + 7.5077946401986963f, 7.5156998382840427f, + 7.5235619560570130f, 7.5313814605163118f, + 7.5391588111080309f, 7.5468944598876364f, + 7.5545888516776376f, 7.5622424242210728f, + 7.5698556083309478f, 7.5774288280357486f, + 7.5849625007211560f, 7.5924570372680806f, + 7.5999128421871278f, 7.6073303137496104f, + 7.6147098441152083f, 7.6220518194563764f, + 7.6293566200796094f, 7.6366246205436487f, + 7.6438561897747243f, 7.6510516911789281f, + 7.6582114827517946f, 7.6653359171851764f, + 7.6724253419714951f, 7.6794800995054464f, + 7.6865005271832185f, 7.6934869574993252f, + 7.7004397181410917f, 7.7073591320808825f, + 7.7142455176661224f, 7.7210991887071855f, + 7.7279204545631987f, 7.7347096202258383f, + 7.7414669864011464f, 7.7481928495894605f, + 7.7548875021634682f, 7.7615512324444795f, + 7.7681843247769259f, 7.7747870596011736f, + 7.7813597135246599f, 7.7879025593914317f, + 7.7944158663501061f, 7.8008998999203047f, + 7.8073549220576037f, 7.8137811912170374f, + 7.8201789624151878f, 7.8265484872909150f, + 7.8328900141647412f, 7.8392037880969436f, + 7.8454900509443747f, 7.8517490414160571f, + 7.8579809951275718f, 7.8641861446542797f, + 7.8703647195834047f, 7.8765169465649993f, + 7.8826430493618415f, 7.8887432488982591f, + 7.8948177633079437f, 7.9008668079807486f, + 7.9068905956085187f, 7.9128893362299619f, + 7.9188632372745946f, 7.9248125036057812f, + 7.9307373375628866f, 7.9366379390025709f, + 7.9425145053392398f, 7.9483672315846778f, + 7.9541963103868749f, 7.9600019320680805f, + 7.9657842846620869f, 7.9715435539507719f, + 7.9772799234999167f, 7.9829935746943103f, + 7.9886846867721654f, 7.9943534368588577f +}; + +float VP8LFastLog2(int v) { + if (v < LOG_LOOKUP_IDX_MAX) { + return kLog2Table[v]; + } else if (v < APPROX_LOG_MAX) { + int log_cnt = 0; + while (v >= LOG_LOOKUP_IDX_MAX) { + ++log_cnt; + v = v >> 1; + } + return kLog2Table[v] + (float)log_cnt; + } else { + return (float)(LOG_2_RECIPROCAL * log((double)v)); + } +} + +//------------------------------------------------------------------------------ +// Image transforms. + +// In-place sum of each component with mod 256. +static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) { + const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u); + const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu); + *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) { + return (((a0 ^ a1) & 0xfefefefeL) >> 1) + (a0 & a1); +} + +static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) { + return Average2(Average2(a0, a2), a1); +} + +static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1, + uint32_t a2, uint32_t a3) { + return Average2(Average2(a0, a1), Average2(a2, a3)); +} + +static WEBP_INLINE uint32_t Clip255(uint32_t a) { + if (a < 256) { + return a; + } + // return 0, when a is a negative integer. + // return 255, when a is positive. + return ~a >> 24; +} + +static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) { + return Clip255(a + b - c); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, + uint32_t c2) { + const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24); + const int r = AddSubtractComponentFull((c0 >> 16) & 0xff, + (c1 >> 16) & 0xff, + (c2 >> 16) & 0xff); + const int g = AddSubtractComponentFull((c0 >> 8) & 0xff, + (c1 >> 8) & 0xff, + (c2 >> 8) & 0xff); + const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff); + return (a << 24) | (r << 16) | (g << 8) | b; +} + +static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) { + return Clip255(a + (a - b) / 2); +} + +static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, + uint32_t c2) { + const uint32_t ave = Average2(c0, c1); + const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24); + const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff); + const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff); + const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff); + return (a << 24) | (r << 16) | (g << 8) | b; +} + +static WEBP_INLINE int Sub3(int a, int b, int c) { + const int pa = b - c; + const int pb = a - c; + return abs(pa) - abs(pb); +} + +static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { + const int pa_minus_pb = + Sub3((a >> 24) , (b >> 24) , (c >> 24) ) + + Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) + + Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) + + Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff); + + return (pa_minus_pb <= 0) ? a : b; +} + +//------------------------------------------------------------------------------ +// Predictors + +static uint32_t Predictor0(uint32_t left, const uint32_t* const top) { + (void)top; + (void)left; + return ARGB_BLACK; +} +static uint32_t Predictor1(uint32_t left, const uint32_t* const top) { + (void)top; + return left; +} +static uint32_t Predictor2(uint32_t left, const uint32_t* const top) { + (void)left; + return top[0]; +} +static uint32_t Predictor3(uint32_t left, const uint32_t* const top) { + (void)left; + return top[1]; +} +static uint32_t Predictor4(uint32_t left, const uint32_t* const top) { + (void)left; + return top[-1]; +} +static uint32_t Predictor5(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average3(left, top[0], top[1]); + return pred; +} +static uint32_t Predictor6(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(left, top[-1]); + return pred; +} +static uint32_t Predictor7(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(left, top[0]); + return pred; +} +static uint32_t Predictor8(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(top[-1], top[0]); + (void)left; + return pred; +} +static uint32_t Predictor9(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average2(top[0], top[1]); + (void)left; + return pred; +} +static uint32_t Predictor10(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Average4(left, top[-1], top[0], top[1]); + return pred; +} +static uint32_t Predictor11(uint32_t left, const uint32_t* const top) { + const uint32_t pred = Select(top[0], left, top[-1]); + return pred; +} +static uint32_t Predictor12(uint32_t left, const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]); + return pred; +} +static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { + const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); + return pred; +} + +typedef uint32_t (*PredictorFunc)(uint32_t left, const uint32_t* const top); +static const PredictorFunc kPredictors[16] = { + Predictor0, Predictor1, Predictor2, Predictor3, + Predictor4, Predictor5, Predictor6, Predictor7, + Predictor8, Predictor9, Predictor10, Predictor11, + Predictor12, Predictor13, + Predictor0, Predictor0 // <- padding security sentinels +}; + +// TODO(vikasa): Replace 256 etc with defines. +static float PredictionCostSpatial(const int* counts, + int weight_0, double exp_val) { + const int significant_symbols = 16; + const double exp_decay_factor = 0.6; + double bits = weight_0 * counts[0]; + int i; + for (i = 1; i < significant_symbols; ++i) { + bits += exp_val * (counts[i] + counts[256 - i]); + exp_val *= exp_decay_factor; + } + return (float)(-0.1 * bits); +} + +// Compute the Shanon's entropy: Sum(p*log2(p)) +static float ShannonEntropy(const int* const array, int n) { + int i; + float retval = 0.f; + int sum = 0; + for (i = 0; i < n; ++i) { + if (array[i] != 0) { + sum += array[i]; + retval -= VP8LFastSLog2(array[i]); + } + } + retval += VP8LFastSLog2(sum); + return retval; +} + +static float PredictionCostSpatialHistogram(int accumulated[4][256], + int tile[4][256]) { + int i; + int k; + int combo[256]; + double retval = 0; + for (i = 0; i < 4; ++i) { + const double exp_val = 0.94; + retval += PredictionCostSpatial(&tile[i][0], 1, exp_val); + retval += ShannonEntropy(&tile[i][0], 256); + for (k = 0; k < 256; ++k) { + combo[k] = accumulated[i][k] + tile[i][k]; + } + retval += ShannonEntropy(&combo[0], 256); + } + return (float)retval; +} + +static int GetBestPredictorForTile(int width, int height, + int tile_x, int tile_y, int bits, + int accumulated[4][256], + const uint32_t* const argb_scratch) { + const int kNumPredModes = 14; + const int col_start = tile_x << bits; + const int row_start = tile_y << bits; + const int tile_size = 1 << bits; + const int ymax = (tile_size <= height - row_start) ? + tile_size : height - row_start; + const int xmax = (tile_size <= width - col_start) ? + tile_size : width - col_start; + int histo[4][256]; + float best_diff = MAX_DIFF_COST; + int best_mode = 0; + + int mode; + for (mode = 0; mode < kNumPredModes; ++mode) { + const uint32_t* current_row = argb_scratch; + const PredictorFunc pred_func = kPredictors[mode]; + float cur_diff; + int y; + memset(&histo[0][0], 0, sizeof(histo)); + for (y = 0; y < ymax; ++y) { + int x; + const int row = row_start + y; + const uint32_t* const upper_row = current_row; + current_row = upper_row + width; + for (x = 0; x < xmax; ++x) { + const int col = col_start + x; + uint32_t predict; + uint32_t predict_diff; + if (row == 0) { + predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left. + } else if (col == 0) { + predict = upper_row[col]; // Top. + } else { + predict = pred_func(current_row[col - 1], upper_row + col); + } + predict_diff = VP8LSubPixels(current_row[col], predict); + ++histo[0][predict_diff >> 24]; + ++histo[1][((predict_diff >> 16) & 0xff)]; + ++histo[2][((predict_diff >> 8) & 0xff)]; + ++histo[3][(predict_diff & 0xff)]; + } + } + cur_diff = PredictionCostSpatialHistogram(accumulated, histo); + if (cur_diff < best_diff) { + best_diff = cur_diff; + best_mode = mode; + } + } + + return best_mode; +} + +static void CopyTileWithPrediction(int width, int height, + int tile_x, int tile_y, int bits, int mode, + const uint32_t* const argb_scratch, + uint32_t* const argb) { + const int col_start = tile_x << bits; + const int row_start = tile_y << bits; + const int tile_size = 1 << bits; + const int ymax = (tile_size <= height - row_start) ? + tile_size : height - row_start; + const int xmax = (tile_size <= width - col_start) ? + tile_size : width - col_start; + const PredictorFunc pred_func = kPredictors[mode]; + const uint32_t* current_row = argb_scratch; + + int y; + for (y = 0; y < ymax; ++y) { + int x; + const int row = row_start + y; + const uint32_t* const upper_row = current_row; + current_row = upper_row + width; + for (x = 0; x < xmax; ++x) { + const int col = col_start + x; + const int pix = row * width + col; + uint32_t predict; + if (row == 0) { + predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left. + } else if (col == 0) { + predict = upper_row[col]; // Top. + } else { + predict = pred_func(current_row[col - 1], upper_row + col); + } + argb[pix] = VP8LSubPixels(current_row[col], predict); + } + } +} + +void VP8LResidualImage(int width, int height, int bits, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image) { + const int max_tile_size = 1 << bits; + const int tiles_per_row = VP8LSubSampleSize(width, bits); + const int tiles_per_col = VP8LSubSampleSize(height, bits); + uint32_t* const upper_row = argb_scratch; + uint32_t* const current_tile_rows = argb_scratch + width; + int tile_y; + int histo[4][256]; + memset(histo, 0, sizeof(histo)); + for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { + const int tile_y_offset = tile_y * max_tile_size; + const int this_tile_height = + (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset; + int tile_x; + if (tile_y > 0) { + memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width, + width * sizeof(*upper_row)); + } + memcpy(current_tile_rows, &argb[tile_y_offset * width], + this_tile_height * width * sizeof(*current_tile_rows)); + for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { + int pred; + int y; + const int tile_x_offset = tile_x * max_tile_size; + int all_x_max = tile_x_offset + max_tile_size; + if (all_x_max > width) { + all_x_max = width; + } + pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo, + argb_scratch); + image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8); + CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred, + argb_scratch, argb); + for (y = 0; y < max_tile_size; ++y) { + int ix; + int all_x; + int all_y = tile_y_offset + y; + if (all_y >= height) { + break; + } + ix = all_y * width + tile_x_offset; + for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) { + const uint32_t a = argb[ix]; + ++histo[0][a >> 24]; + ++histo[1][((a >> 16) & 0xff)]; + ++histo[2][((a >> 8) & 0xff)]; + ++histo[3][(a & 0xff)]; + } + } + } + } +} + +// Inverse prediction. +static void PredictorInverseTransform(const VP8LTransform* const transform, + int y_start, int y_end, uint32_t* data) { + const int width = transform->xsize_; + if (y_start == 0) { // First Row follows the L (mode=1) mode. + int x; + const uint32_t pred0 = Predictor0(data[-1], NULL); + AddPixelsEq(data, pred0); + for (x = 1; x < width; ++x) { + const uint32_t pred1 = Predictor1(data[x - 1], NULL); + AddPixelsEq(data + x, pred1); + } + data += width; + ++y_start; + } + + { + int y = y_start; + const int mask = (1 << transform->bits_) - 1; + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const uint32_t* pred_mode_base = + transform->data_ + (y >> transform->bits_) * tiles_per_row; + + while (y < y_end) { + int x; + const uint32_t pred2 = Predictor2(data[-1], data - width); + const uint32_t* pred_mode_src = pred_mode_base; + PredictorFunc pred_func; + + // First pixel follows the T (mode=2) mode. + AddPixelsEq(data, pred2); + + // .. the rest: + pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf]; + for (x = 1; x < width; ++x) { + uint32_t pred; + if ((x & mask) == 0) { // start of tile. Read predictor function. + pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf]; + } + pred = pred_func(data[x - 1], data + x - width); + AddPixelsEq(data + x, pred); + } + data += width; + ++y; + if ((y & mask) == 0) { // Use the same mask, since tiles are squares. + pred_mode_base += tiles_per_row; + } + } + } +} + +void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) { + int i; + for (i = 0; i < num_pixs; ++i) { + const uint32_t argb = argb_data[i]; + const uint32_t green = (argb >> 8) & 0xff; + const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; + const uint32_t new_b = ((argb & 0xff) - green) & 0xff; + argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b; + } +} + +// Add green to blue and red channels (i.e. perform the inverse transform of +// 'subtract green'). +static void AddGreenToBlueAndRed(const VP8LTransform* const transform, + int y_start, int y_end, uint32_t* data) { + const int width = transform->xsize_; + const uint32_t* const data_end = data + (y_end - y_start) * width; + while (data < data_end) { + const uint32_t argb = *data; + // "* 0001001u" is equivalent to "(green << 16) + green)" + const uint32_t green = ((argb >> 8) & 0xff); + uint32_t red_blue = (argb & 0x00ff00ffu); + red_blue += (green << 16) | green; + red_blue &= 0x00ff00ffu; + *data++ = (argb & 0xff00ff00u) | red_blue; + } +} + +typedef struct { + // Note: the members are uint8_t, so that any negative values are + // automatically converted to "mod 256" values. + uint8_t green_to_red_; + uint8_t green_to_blue_; + uint8_t red_to_blue_; +} Multipliers; + +static WEBP_INLINE void MultipliersClear(Multipliers* m) { + m->green_to_red_ = 0; + m->green_to_blue_ = 0; + m->red_to_blue_ = 0; +} + +static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, + int8_t color) { + return (uint32_t)((int)(color_pred) * color) >> 5; +} + +static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, + Multipliers* const m) { + m->green_to_red_ = (color_code >> 0) & 0xff; + m->green_to_blue_ = (color_code >> 8) & 0xff; + m->red_to_blue_ = (color_code >> 16) & 0xff; +} + +static WEBP_INLINE uint32_t MultipliersToColorCode(Multipliers* const m) { + return 0xff000000u | + ((uint32_t)(m->red_to_blue_) << 16) | + ((uint32_t)(m->green_to_blue_) << 8) | + m->green_to_red_; +} + +static WEBP_INLINE uint32_t TransformColor(const Multipliers* const m, + uint32_t argb, int inverse) { + const uint32_t green = argb >> 8; + const uint32_t red = argb >> 16; + uint32_t new_red = red; + uint32_t new_blue = argb; + + if (inverse) { + new_red += ColorTransformDelta(m->green_to_red_, green); + new_red &= 0xff; + new_blue += ColorTransformDelta(m->green_to_blue_, green); + new_blue += ColorTransformDelta(m->red_to_blue_, new_red); + new_blue &= 0xff; + } else { + new_red -= ColorTransformDelta(m->green_to_red_, green); + new_red &= 0xff; + new_blue -= ColorTransformDelta(m->green_to_blue_, green); + new_blue -= ColorTransformDelta(m->red_to_blue_, red); + new_blue &= 0xff; + } + return (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); +} + +static WEBP_INLINE int SkipRepeatedPixels(const uint32_t* const argb, + int ix, int xsize) { + const uint32_t v = argb[ix]; + if (ix >= xsize + 3) { + if (v == argb[ix - xsize] && + argb[ix - 1] == argb[ix - xsize - 1] && + argb[ix - 2] == argb[ix - xsize - 2] && + argb[ix - 3] == argb[ix - xsize - 3]) { + return 1; + } + return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1]; + } else if (ix >= 3) { + return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1]; + } + return 0; +} + +static float PredictionCostCrossColor(const int accumulated[256], + const int counts[256]) { + // Favor low entropy, locally and globally. + int i; + int combo[256]; + for (i = 0; i < 256; ++i) { + combo[i] = accumulated[i] + counts[i]; + } + return ShannonEntropy(combo, 256) + + ShannonEntropy(counts, 256) + + PredictionCostSpatial(counts, 3, 2.4); // Favor small absolute values. +} + +static Multipliers GetBestColorTransformForTile( + int tile_x, int tile_y, int bits, + Multipliers prevX, + Multipliers prevY, + int step, int xsize, int ysize, + int* accumulated_red_histo, + int* accumulated_blue_histo, + const uint32_t* const argb) { + float best_diff = MAX_DIFF_COST; + float cur_diff; + const int halfstep = step / 2; + const int max_tile_size = 1 << bits; + const int tile_y_offset = tile_y * max_tile_size; + const int tile_x_offset = tile_x * max_tile_size; + int green_to_red; + int green_to_blue; + int red_to_blue; + int all_x_max = tile_x_offset + max_tile_size; + int all_y_max = tile_y_offset + max_tile_size; + Multipliers best_tx; + MultipliersClear(&best_tx); + if (all_x_max > xsize) { + all_x_max = xsize; + } + if (all_y_max > ysize) { + all_y_max = ysize; + } + for (green_to_red = -64; green_to_red <= 64; green_to_red += halfstep) { + int histo[256] = { 0 }; + int all_y; + Multipliers tx; + MultipliersClear(&tx); + tx.green_to_red_ = green_to_red & 0xff; + + for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) { + uint32_t predict; + int ix = all_y * xsize + tile_x_offset; + int all_x; + for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) { + if (SkipRepeatedPixels(argb, ix, xsize)) { + continue; + } + predict = TransformColor(&tx, argb[ix], 0); + ++histo[(predict >> 16) & 0xff]; // red. + } + } + cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]); + if (tx.green_to_red_ == prevX.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.green_to_red_ == prevY.green_to_red_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.green_to_red_ == 0) { + cur_diff -= 3; + } + if (cur_diff < best_diff) { + best_diff = cur_diff; + best_tx = tx; + } + } + best_diff = MAX_DIFF_COST; + green_to_red = best_tx.green_to_red_; + for (green_to_blue = -32; green_to_blue <= 32; green_to_blue += step) { + for (red_to_blue = -32; red_to_blue <= 32; red_to_blue += step) { + int all_y; + int histo[256] = { 0 }; + Multipliers tx; + tx.green_to_red_ = green_to_red; + tx.green_to_blue_ = green_to_blue; + tx.red_to_blue_ = red_to_blue; + for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) { + uint32_t predict; + int all_x; + int ix = all_y * xsize + tile_x_offset; + for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) { + if (SkipRepeatedPixels(argb, ix, xsize)) { + continue; + } + predict = TransformColor(&tx, argb[ix], 0); + ++histo[predict & 0xff]; // blue. + } + } + cur_diff = + PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]); + if (tx.green_to_blue_ == prevX.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.green_to_blue_ == prevY.green_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.red_to_blue_ == prevX.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.red_to_blue_ == prevY.red_to_blue_) { + cur_diff -= 3; // favor keeping the areas locally similar + } + if (tx.green_to_blue_ == 0) { + cur_diff -= 3; + } + if (tx.red_to_blue_ == 0) { + cur_diff -= 3; + } + if (cur_diff < best_diff) { + best_diff = cur_diff; + best_tx = tx; + } + } + } + return best_tx; +} + +static void CopyTileWithColorTransform(int xsize, int ysize, + int tile_x, int tile_y, int bits, + Multipliers color_transform, + uint32_t* const argb) { + int y; + int xscan = 1 << bits; + int yscan = 1 << bits; + tile_x <<= bits; + tile_y <<= bits; + if (xscan > xsize - tile_x) { + xscan = xsize - tile_x; + } + if (yscan > ysize - tile_y) { + yscan = ysize - tile_y; + } + yscan += tile_y; + for (y = tile_y; y < yscan; ++y) { + int ix = y * xsize + tile_x; + const int end_ix = ix + xscan; + for (; ix < end_ix; ++ix) { + argb[ix] = TransformColor(&color_transform, argb[ix], 0); + } + } +} + +void VP8LColorSpaceTransform(int width, int height, int bits, int step, + uint32_t* const argb, uint32_t* image) { + const int max_tile_size = 1 << bits; + int tile_xsize = VP8LSubSampleSize(width, bits); + int tile_ysize = VP8LSubSampleSize(height, bits); + int accumulated_red_histo[256] = { 0 }; + int accumulated_blue_histo[256] = { 0 }; + int tile_y; + int tile_x; + Multipliers prevX; + Multipliers prevY; + MultipliersClear(&prevY); + MultipliersClear(&prevX); + for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { + for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { + Multipliers color_transform; + int all_x_max; + int y; + const int tile_y_offset = tile_y * max_tile_size; + const int tile_x_offset = tile_x * max_tile_size; + if (tile_y != 0) { + ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX); + ColorCodeToMultipliers(image[(tile_y - 1) * tile_xsize + tile_x], + &prevY); + } else if (tile_x != 0) { + ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX); + } + color_transform = + GetBestColorTransformForTile(tile_x, tile_y, bits, + prevX, prevY, + step, width, height, + &accumulated_red_histo[0], + &accumulated_blue_histo[0], + argb); + image[tile_y * tile_xsize + tile_x] = + MultipliersToColorCode(&color_transform); + CopyTileWithColorTransform(width, height, tile_x, tile_y, bits, + color_transform, argb); + + // Gather accumulated histogram data. + all_x_max = tile_x_offset + max_tile_size; + if (all_x_max > width) { + all_x_max = width; + } + for (y = 0; y < max_tile_size; ++y) { + int ix; + int all_x; + int all_y = tile_y_offset + y; + if (all_y >= height) { + break; + } + ix = all_y * width + tile_x_offset; + for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) { + if (ix >= 2 && + argb[ix] == argb[ix - 2] && + argb[ix] == argb[ix - 1]) { + continue; // repeated pixels are handled by backward references + } + if (ix >= width + 2 && + argb[ix - 2] == argb[ix - width - 2] && + argb[ix - 1] == argb[ix - width - 1] && + argb[ix] == argb[ix - width]) { + continue; // repeated pixels are handled by backward references + } + ++accumulated_red_histo[(argb[ix] >> 16) & 0xff]; + ++accumulated_blue_histo[argb[ix] & 0xff]; + } + } + } + } +} + +// Color space inverse transform. +static void ColorSpaceInverseTransform(const VP8LTransform* const transform, + int y_start, int y_end, uint32_t* data) { + const int width = transform->xsize_; + const int mask = (1 << transform->bits_) - 1; + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + int y = y_start; + const uint32_t* pred_row = + transform->data_ + (y >> transform->bits_) * tiles_per_row; + + while (y < y_end) { + const uint32_t* pred = pred_row; + Multipliers m = { 0, 0, 0 }; + int x; + + for (x = 0; x < width; ++x) { + if ((x & mask) == 0) ColorCodeToMultipliers(*pred++, &m); + data[x] = TransformColor(&m, data[x], 1); + } + data += width; + ++y; + if ((y & mask) == 0) pred_row += tiles_per_row;; + } +} + +// Separate out pixels packed together using pixel-bundling. +static void ColorIndexInverseTransform( + const VP8LTransform* const transform, + int y_start, int y_end, const uint32_t* src, uint32_t* dst) { + int y; + const int bits_per_pixel = 8 >> transform->bits_; + const int width = transform->xsize_; + const uint32_t* const color_map = transform->data_; + if (bits_per_pixel < 8) { + const int pixels_per_byte = 1 << transform->bits_; + const int count_mask = pixels_per_byte - 1; + const uint32_t bit_mask = (1 << bits_per_pixel) - 1; + for (y = y_start; y < y_end; ++y) { + uint32_t packed_pixels = 0; + int x; + for (x = 0; x < width; ++x) { + // We need to load fresh 'packed_pixels' once every 'pixels_per_byte' + // increments of x. Fortunately, pixels_per_byte is a power of 2, so + // can just use a mask for that, instead of decrementing a counter. + if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff; + *dst++ = color_map[packed_pixels & bit_mask]; + packed_pixels >>= bits_per_pixel; + } + } + } else { + for (y = y_start; y < y_end; ++y) { + int x; + for (x = 0; x < width; ++x) { + *dst++ = color_map[((*src++) >> 8) & 0xff]; + } + } + } +} + +void VP8LInverseTransform(const VP8LTransform* const transform, + int row_start, int row_end, + const uint32_t* const in, uint32_t* const out) { + assert(row_start < row_end); + assert(row_end <= transform->ysize_); + switch (transform->type_) { + case SUBTRACT_GREEN: + AddGreenToBlueAndRed(transform, row_start, row_end, out); + break; + case PREDICTOR_TRANSFORM: + PredictorInverseTransform(transform, row_start, row_end, out); + if (row_end != transform->ysize_) { + // The last predicted row in this iteration will be the top-pred row + // for the first row in next iteration. + const int width = transform->xsize_; + memcpy(out - width, out + (row_end - row_start - 1) * width, + width * sizeof(*out)); + } + break; + case CROSS_COLOR_TRANSFORM: + ColorSpaceInverseTransform(transform, row_start, row_end, out); + break; + case COLOR_INDEXING_TRANSFORM: + if (in == out && transform->bits_ > 0) { + // Move packed pixels to the end of unpacked region, so that unpacking + // can occur seamlessly. + // Also, note that this is the only transform that applies on + // the effective width of VP8LSubSampleSize(xsize_, bits_). All other + // transforms work on effective width of xsize_. + const int out_stride = (row_end - row_start) * transform->xsize_; + const int in_stride = (row_end - row_start) * + VP8LSubSampleSize(transform->xsize_, transform->bits_); + uint32_t* const src = out + out_stride - in_stride; + memmove(src, out, in_stride * sizeof(*src)); + ColorIndexInverseTransform(transform, row_start, row_end, src, out); + } else { + ColorIndexInverseTransform(transform, row_start, row_end, in, out); + } + break; + } +} + +//------------------------------------------------------------------------------ +// Color space conversion. + +static int is_big_endian(void) { + static const union { + uint16_t w; + uint8_t b[2]; + } tmp = { 1 }; + return (tmp.b[0] != 1); +} + +static void ConvertBGRAToRGB(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 16) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 0) & 0xff; + } +} + +static void ConvertBGRAToRGBA(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 16) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 0) & 0xff; + *dst++ = (argb >> 24) & 0xff; + } +} + +static void ConvertBGRAToRGBA4444(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf); + *dst++ = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf); + } +} + +static void ConvertBGRAToRGB565(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7); + *dst++ = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f); + } +} + +static void ConvertBGRAToBGR(const uint32_t* src, + int num_pixels, uint8_t* dst) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + const uint32_t argb = *src++; + *dst++ = (argb >> 0) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 16) & 0xff; + } +} + +static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst, + int swap_on_big_endian) { + if (is_big_endian() == swap_on_big_endian) { + const uint32_t* const src_end = src + num_pixels; + while (src < src_end) { + uint32_t argb = *src++; +#if (!defined(__BIG_ENDIAN__) && (defined(__i386__) || defined(__x86_64__))) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + __asm__ volatile("bswap %0" : "=r"(argb) : "0"(argb)); + *(uint32_t*)dst = argb; + dst += sizeof(argb); +#elif (!defined(__BIG_ENDIAN__) && defined(_MSC_VER)) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + argb = _byteswap_ulong(argb); + *(uint32_t*)dst = argb; + dst += sizeof(argb); +#else + *dst++ = (argb >> 24) & 0xff; + *dst++ = (argb >> 16) & 0xff; + *dst++ = (argb >> 8) & 0xff; + *dst++ = (argb >> 0) & 0xff; +#endif + } + } else { + memcpy(dst, src, num_pixels * sizeof(*src)); + } +} + +void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, + WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) { + switch (out_colorspace) { + case MODE_RGB: + ConvertBGRAToRGB(in_data, num_pixels, rgba); + break; + case MODE_RGBA: + ConvertBGRAToRGBA(in_data, num_pixels, rgba); + break; + case MODE_rgbA: + ConvertBGRAToRGBA(in_data, num_pixels, rgba); + WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0); + break; + case MODE_BGR: + ConvertBGRAToBGR(in_data, num_pixels, rgba); + break; + case MODE_BGRA: + CopyOrSwap(in_data, num_pixels, rgba, 1); + break; + case MODE_bgrA: + CopyOrSwap(in_data, num_pixels, rgba, 1); + WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0); + break; + case MODE_ARGB: + CopyOrSwap(in_data, num_pixels, rgba, 0); + break; + case MODE_Argb: + CopyOrSwap(in_data, num_pixels, rgba, 0); + WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0); + break; + case MODE_RGBA_4444: + ConvertBGRAToRGBA4444(in_data, num_pixels, rgba); + break; + case MODE_rgbA_4444: + ConvertBGRAToRGBA4444(in_data, num_pixels, rgba); + WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0); + break; + case MODE_RGB_565: + ConvertBGRAToRGB565(in_data, num_pixels, rgba); + break; + default: + assert(0); // Code flow should not reach here. + } +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/lossless.h b/external/libwebp/dsp/lossless.h new file mode 100644 index 0000000000..992516fcdf --- /dev/null +++ b/external/libwebp/dsp/lossless.h @@ -0,0 +1,82 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Image transforms and color space conversion methods for lossless decoder. +// +// Authors: Vikas Arora (vikaas.arora@gmail.com) +// Jyrki Alakuijala (jyrki@google.com) + +#ifndef WEBP_DSP_LOSSLESS_H_ +#define WEBP_DSP_LOSSLESS_H_ + +#include "../webp/types.h" +#include "../webp/decode.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Image transforms. + +struct VP8LTransform; // Defined in dec/vp8li.h. + +// Performs inverse transform of data given transform information, start and end +// rows. Transform will be applied to rows [row_start, row_end[. +// The *in and *out pointers refer to source and destination data respectively +// corresponding to the intermediate row (row_start). +void VP8LInverseTransform(const struct VP8LTransform* const transform, + int row_start, int row_end, + const uint32_t* const in, uint32_t* const out); + +// Subtracts green from blue and red channels. +void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs); + +void VP8LResidualImage(int width, int height, int bits, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image); + +void VP8LColorSpaceTransform(int width, int height, int bits, int step, + uint32_t* const argb, uint32_t* image); + +//------------------------------------------------------------------------------ +// Color space conversion. + +// Converts from BGRA to other color spaces. +void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, + WEBP_CSP_MODE out_colorspace, uint8_t* const rgba); + +//------------------------------------------------------------------------------ +// Misc methods. + +// Computes sampled size of 'size' when sampling using 'sampling bits'. +static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size, + uint32_t sampling_bits) { + return (size + (1 << sampling_bits) - 1) >> sampling_bits; +} + +// Faster logarithm for integers, with the property of log2(0) == 0. +float VP8LFastLog2(int v); +// Fast calculation of v * log2(v) for integer input. +static WEBP_INLINE float VP8LFastSLog2(int v) { return VP8LFastLog2(v) * v; } + +// In-place difference of each component with mod 256. +static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { + const uint32_t alpha_and_green = + 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u); + const uint32_t red_and_blue = + 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu); + return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu); +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBP_DSP_LOSSLESS_H_ diff --git a/external/libwebp/dsp/upsampling.c b/external/libwebp/dsp/upsampling.c new file mode 100644 index 0000000000..4855eb1432 --- /dev/null +++ b/external/libwebp/dsp/upsampling.c @@ -0,0 +1,357 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "./dsp.h" +#include "./yuv.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Fancy upsampler + +#ifdef FANCY_UPSAMPLING + +// Fancy upsampling functions to convert YUV to RGB +WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST]; + +// Given samples laid out in a square as: +// [a b] +// [c d] +// we interpolate u/v as: +// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16 +// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16 + +// We process u and v together stashed into 32bit (16bit each). +#define LOAD_UV(u,v) ((u) | ((v) << 16)) + +#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int x; \ + const int last_pixel_pair = (len - 1) >> 1; \ + uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ + uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \ + if (top_y) { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ + } \ + if (bottom_y) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \ + } \ + for (x = 1; x <= last_pixel_pair; ++x) { \ + const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \ + const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \ + /* precompute invariant values associated with first and second diagonals*/\ + const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \ + const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \ + const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \ + if (top_y) { \ + const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \ + const uint32_t uv1 = (diag_03 + t_uv) >> 1; \ + FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (2 * x - 1) * XSTEP); \ + FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \ + top_dst + (2 * x - 0) * XSTEP); \ + } \ + if (bottom_y) { \ + const uint32_t uv0 = (diag_03 + l_uv) >> 1; \ + const uint32_t uv1 = (diag_12 + uv) >> 1; \ + FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (2 * x - 1) * XSTEP); \ + FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \ + bottom_dst + (2 * x + 0) * XSTEP); \ + } \ + tl_uv = t_uv; \ + l_uv = uv; \ + } \ + if (!(len & 1)) { \ + if (top_y) { \ + const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ + FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + top_dst + (len - 1) * XSTEP); \ + } \ + if (bottom_y) { \ + const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ + FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ + bottom_dst + (len - 1) * XSTEP); \ + } \ + } \ +} + +// All variants implemented. +UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3) +UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3) +UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4) +UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4) +UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4) +UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2) +UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2) + +#undef LOAD_UV +#undef UPSAMPLE_FUNC + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ +// simple point-sampling + +#define SAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* u, const uint8_t* v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int i; \ + for (i = 0; i < len - 1; i += 2) { \ + FUNC(top_y[0], u[0], v[0], top_dst); \ + FUNC(top_y[1], u[0], v[0], top_dst + XSTEP); \ + FUNC(bottom_y[0], u[0], v[0], bottom_dst); \ + FUNC(bottom_y[1], u[0], v[0], bottom_dst + XSTEP); \ + top_y += 2; \ + bottom_y += 2; \ + u++; \ + v++; \ + top_dst += 2 * XSTEP; \ + bottom_dst += 2 * XSTEP; \ + } \ + if (i == len - 1) { /* last one */ \ + FUNC(top_y[0], u[0], v[0], top_dst); \ + FUNC(bottom_y[0], u[0], v[0], bottom_dst); \ + } \ +} + +// All variants implemented. +SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3) +SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3) +SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4) +SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4) +SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4) +SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2) +SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2) + +#undef SAMPLE_FUNC + +const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = { + SampleRgbLinePair, // MODE_RGB + SampleRgbaLinePair, // MODE_RGBA + SampleBgrLinePair, // MODE_BGR + SampleBgraLinePair, // MODE_BGRA + SampleArgbLinePair, // MODE_ARGB + SampleRgba4444LinePair, // MODE_RGBA_4444 + SampleRgb565LinePair, // MODE_RGB_565 + SampleRgbaLinePair, // MODE_rgbA + SampleBgraLinePair, // MODE_bgrA + SampleArgbLinePair, // MODE_Argb + SampleRgba4444LinePair // MODE_rgbA_4444 +}; + +//------------------------------------------------------------------------------ + +#if !defined(FANCY_UPSAMPLING) +#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* bot_u, const uint8_t* bot_v, \ + uint8_t* top_dst, uint8_t* bot_dst, int len) { \ + const int half_len = len >> 1; \ + int x; \ + if (top_dst != NULL) { \ + for (x = 0; x < half_len; ++x) { \ + FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \ + FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \ + } \ + if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \ + } \ + if (bot_dst != NULL) { \ + for (x = 0; x < half_len; ++x) { \ + FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \ + FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \ + } \ + if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \ + } \ +} + +DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra) +DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb) +#undef DUAL_SAMPLE_FUNC + +#endif // !FANCY_UPSAMPLING + +WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) { + WebPInitUpsamplers(); + VP8YUVInit(); +#ifdef FANCY_UPSAMPLING + return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB]; +#else + return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB); +#endif +} + +//------------------------------------------------------------------------------ +// YUV444 converter + +#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \ +} + +YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3) +YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3) +YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4) +YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4) +YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4) +YUV444_FUNC(Yuv444ToRgba4444, VP8YuvToRgba4444, 2) +YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2) + +#undef YUV444_FUNC + +const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = { + Yuv444ToRgb, // MODE_RGB + Yuv444ToRgba, // MODE_RGBA + Yuv444ToBgr, // MODE_BGR + Yuv444ToBgra, // MODE_BGRA + Yuv444ToArgb, // MODE_ARGB + Yuv444ToRgba4444, // MODE_RGBA_4444 + Yuv444ToRgb565, // MODE_RGB_565 + Yuv444ToRgba, // MODE_rgbA + Yuv444ToBgra, // MODE_bgrA + Yuv444ToArgb, // MODE_Argb + Yuv444ToRgba4444 // MODE_rgbA_4444 +}; + +//------------------------------------------------------------------------------ +// Premultiplied modes + +// non dithered-modes + +// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.) +// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5), +// one can use instead: (x * a * 65793 + (1 << 23)) >> 24 +#if 1 // (int)(x * a / 255.) +#define MULTIPLIER(a) ((a) * 32897UL) +#define PREMULTIPLY(x, m) (((x) * (m)) >> 23) +#else // (int)(x * a / 255. + .5) +#define MULTIPLIER(a) ((a) * 65793UL) +#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24) +#endif + +static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first, + int w, int h, int stride) { + while (h-- > 0) { + uint8_t* const rgb = rgba + (alpha_first ? 1 : 0); + const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3); + int i; + for (i = 0; i < w; ++i) { + const uint32_t a = alpha[4 * i]; + if (a != 0xff) { + const uint32_t mult = MULTIPLIER(a); + rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult); + rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult); + rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult); + } + } + rgba += stride; + } +} +#undef MULTIPLIER +#undef PREMULTIPLY + +// rgbA4444 + +#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15 + +static WEBP_INLINE uint8_t dither_hi(uint8_t x) { + return (x & 0xf0) | (x >> 4); +} + +static WEBP_INLINE uint8_t dither_lo(uint8_t x) { + return (x & 0x0f) | (x << 4); +} + +static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) { + return (x * m) >> 16; +} + +static void ApplyAlphaMultiply4444(uint8_t* rgba4444, + int w, int h, int stride) { + while (h-- > 0) { + int i; + for (i = 0; i < w; ++i) { + const uint8_t a = (rgba4444[2 * i + 1] & 0x0f); + const uint32_t mult = MULTIPLIER(a); + const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult); + const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult); + const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult); + rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f); + rgba4444[2 * i + 1] = (b & 0xf0) | a; + } + rgba4444 += stride; + } +} +#undef MULTIPLIER + +void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int) + = ApplyAlphaMultiply; +void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int) + = ApplyAlphaMultiply4444; + +//------------------------------------------------------------------------------ +// Main call + +void WebPInitUpsamplers(void) { +#ifdef FANCY_UPSAMPLING + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair; + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair; + WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair; + + // If defined, use CPUInfo() to overwrite some pointers with faster versions. + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_USE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitUpsamplersSSE2(); + } +#endif + } +#endif // FANCY_UPSAMPLING +} + +void WebPInitPremultiply(void) { + WebPApplyAlphaMultiply = ApplyAlphaMultiply; + WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444; + +#ifdef FANCY_UPSAMPLING + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair; + WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair; + WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair; + + if (VP8GetCPUInfo != NULL) { +#if defined(WEBP_USE_SSE2) + if (VP8GetCPUInfo(kSSE2)) { + WebPInitPremultiplySSE2(); + } +#endif + } +#endif // FANCY_UPSAMPLING +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/upsampling_sse2.c b/external/libwebp/dsp/upsampling_sse2.c new file mode 100644 index 0000000000..500760546b --- /dev/null +++ b/external/libwebp/dsp/upsampling_sse2.c @@ -0,0 +1,215 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// SSE2 version of YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "./dsp.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if defined(WEBP_USE_SSE2) + +#include +#include +#include +#include "./yuv.h" + +#ifdef FANCY_UPSAMPLING + +// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows +// u = (9*a + 3*b + 3*c + d + 8) / 16 +// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2 +// = (a + m + 1) / 2 +// where m = (a + 3*b + 3*c + d) / 8 +// = ((a + b + c + d) / 2 + b + c) / 4 +// +// Let's say k = (a + b + c + d) / 4. +// We can compute k as +// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1 +// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2 +// +// Then m can be written as +// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1 + +// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1 +#define GET_M(ij, in, out) do { \ + const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \ + const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \ + const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \ + const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\ + const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \ + (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \ +} while (0) + +// pack and store two alterning pixel rows +#define PACK_AND_STORE(a, b, da, db, out) do { \ + const __m128i ta = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \ + const __m128i tb = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \ + const __m128i t1 = _mm_unpacklo_epi8(ta, tb); \ + const __m128i t2 = _mm_unpackhi_epi8(ta, tb); \ + _mm_store_si128(((__m128i*)(out)) + 0, t1); \ + _mm_store_si128(((__m128i*)(out)) + 1, t2); \ +} while (0) + +// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. +#define UPSAMPLE_32PIXELS(r1, r2, out) { \ + const __m128i one = _mm_set1_epi8(1); \ + const __m128i a = _mm_loadu_si128((__m128i*)&(r1)[0]); \ + const __m128i b = _mm_loadu_si128((__m128i*)&(r1)[1]); \ + const __m128i c = _mm_loadu_si128((__m128i*)&(r2)[0]); \ + const __m128i d = _mm_loadu_si128((__m128i*)&(r2)[1]); \ + \ + const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \ + const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \ + const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \ + \ + const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \ + const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \ + \ + const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \ + const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \ + const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \ + const __m128i t4 = _mm_avg_epu8(s, t); \ + const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \ + __m128i diag1, diag2; \ + \ + GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \ + GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \ + \ + /* pack the alternate pixels */ \ + PACK_AND_STORE(a, b, diag1, diag2, &(out)[0 * 32]); \ + PACK_AND_STORE(c, d, diag2, diag1, &(out)[2 * 32]); \ +} + +// Turn the macro into a function for reducing code-size when non-critical +static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[], + uint8_t* const out) { + UPSAMPLE_32PIXELS(r1, r2, out); +} + +#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \ + uint8_t r1[17], r2[17]; \ + memcpy(r1, (tb), (num_pixels)); \ + memcpy(r2, (bb), (num_pixels)); \ + /* replicate last byte */ \ + memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \ + memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \ + /* using the shared function instead of the macro saves ~3k code size */ \ + Upsample32Pixels(r1, r2, out); \ +} + +#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, uv, \ + top_dst, bottom_dst, cur_x, num_pixels) { \ + int n; \ + if (top_y) { \ + for (n = 0; n < (num_pixels); ++n) { \ + FUNC(top_y[(cur_x) + n], (uv)[n], (uv)[32 + n], \ + top_dst + ((cur_x) + n) * XSTEP); \ + } \ + } \ + if (bottom_y) { \ + for (n = 0; n < (num_pixels); ++n) { \ + FUNC(bottom_y[(cur_x) + n], (uv)[64 + n], (uv)[64 + 32 + n], \ + bottom_dst + ((cur_x) + n) * XSTEP); \ + } \ + } \ +} + +#define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int b; \ + /* 16 byte aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[4 * 32 + 15]; \ + uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + const int uv_len = (len + 1) >> 1; \ + /* 17 pixels must be read-able for each block */ \ + const int num_blocks = (uv_len - 1) >> 4; \ + const int leftover = uv_len - num_blocks * 16; \ + const int last_pos = 1 + 32 * num_blocks; \ + \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + \ + assert(len > 0); \ + /* Treat the first pixel in regular way */ \ + if (top_y) { \ + const int u0 = (top_u[0] + u_diag) >> 1; \ + const int v0 = (top_v[0] + v_diag) >> 1; \ + FUNC(top_y[0], u0, v0, top_dst); \ + } \ + if (bottom_y) { \ + const int u0 = (cur_u[0] + u_diag) >> 1; \ + const int v0 = (cur_v[0] + v_diag) >> 1; \ + FUNC(bottom_y[0], u0, v0, bottom_dst); \ + } \ + \ + for (b = 0; b < num_blocks; ++b) { \ + UPSAMPLE_32PIXELS(top_u, cur_u, r_uv + 0 * 32); \ + UPSAMPLE_32PIXELS(top_v, cur_v, r_uv + 1 * 32); \ + CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \ + 32 * b + 1, 32) \ + top_u += 16; \ + cur_u += 16; \ + top_v += 16; \ + cur_v += 16; \ + } \ + \ + UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv + 0 * 32); \ + UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 1 * 32); \ + CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \ + last_pos, len - last_pos); \ +} + +// SSE2 variants of the fancy upsampler. +SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3) +SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3) +SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4) +SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4) + +#undef GET_M +#undef PACK_AND_STORE +#undef UPSAMPLE_32PIXELS +#undef UPSAMPLE_LAST_BLOCK +#undef CONVERT2RGB +#undef SSE2_UPSAMPLE_FUNC + +#endif // FANCY_UPSAMPLING + +#endif // WEBP_USE_SSE2 + +//------------------------------------------------------------------------------ + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +void WebPInitUpsamplersSSE2(void) { +#if defined(WEBP_USE_SSE2) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2; + WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2; + WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2; +#endif // WEBP_USE_SSE2 +} + +void WebPInitPremultiplySSE2(void) { +#if defined(WEBP_USE_SSE2) + WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2; + WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2; +#endif // WEBP_USE_SSE2 +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + + diff --git a/external/libwebp/dsp/yuv.c b/external/libwebp/dsp/yuv.c new file mode 100644 index 0000000000..7f05f9a3aa --- /dev/null +++ b/external/libwebp/dsp/yuv.c @@ -0,0 +1,52 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion function +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./yuv.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +enum { YUV_HALF = 1 << (YUV_FIX - 1) }; + +int16_t VP8kVToR[256], VP8kUToB[256]; +int32_t VP8kVToG[256], VP8kUToG[256]; +uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN]; +uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN]; + +static int done = 0; + +static WEBP_INLINE uint8_t clip(int v, int max_value) { + return v < 0 ? 0 : v > max_value ? max_value : v; +} + +void VP8YUVInit(void) { + int i; + if (done) { + return; + } + for (i = 0; i < 256; ++i) { + VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX; + VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF; + VP8kVToG[i] = -45773 * (i - 128); + VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX; + } + for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) { + const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX; + VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255); + VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15); + } + done = 1; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/dsp/yuv.h b/external/libwebp/dsp/yuv.h new file mode 100644 index 0000000000..a569109c54 --- /dev/null +++ b/external/libwebp/dsp/yuv.h @@ -0,0 +1,128 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// inline YUV<->RGB conversion function +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_YUV_H_ +#define WEBP_DSP_YUV_H_ + +#include "../dec/decode_vp8.h" + +//------------------------------------------------------------------------------ +// YUV -> RGB conversion + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +enum { YUV_FIX = 16, // fixed-point precision + YUV_RANGE_MIN = -227, // min value of r/g/b output + YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output +}; +extern int16_t VP8kVToR[256], VP8kUToB[256]; +extern int32_t VP8kVToG[256], VP8kUToG[256]; +extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN]; +extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN]; + +static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const rgb) { + const int r_off = VP8kVToR[v]; + const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; + const int b_off = VP8kUToB[u]; + rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN]; + rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; + rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN]; +} + +static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const rgb) { + const int r_off = VP8kVToR[v]; + const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; + const int b_off = VP8kUToB[u]; + rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) | + (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5)); + rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) | + (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3)); +} + +static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const argb) { + argb[0] = 0xff; + VP8YuvToRgb(y, u, v, argb + 1); +} + +static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const argb) { + const int r_off = VP8kVToR[v]; + const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; + const int b_off = VP8kUToB[u]; + // Don't update alpha (last 4 bits of argb[1]) + argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) | + VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]); + argb[1] = 0x0f | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4); +} + +static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const bgr) { + const int r_off = VP8kVToR[v]; + const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; + const int b_off = VP8kUToB[u]; + bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN]; + bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; + bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN]; +} + +static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const bgra) { + VP8YuvToBgr(y, u, v, bgra); + bgra[3] = 0xff; +} + +static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, + uint8_t* const rgba) { + VP8YuvToRgb(y, u, v, rgba); + rgba[3] = 0xff; +} + +// Must be called before everything, to initialize the tables. +void VP8YUVInit(void); + +//------------------------------------------------------------------------------ +// RGB -> YUV conversion +// The exact naming is Y'CbCr, following the ITU-R BT.601 standard. +// More information at: http://en.wikipedia.org/wiki/YCbCr +// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 +// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 +// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 +// We use 16bit fixed point operations. + +static WEBP_INLINE int VP8ClipUV(int v) { + v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2); + return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255; +} + +static WEBP_INLINE int VP8RGBToY(int r, int g, int b) { + const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX); + const int luma = 16839 * r + 33059 * g + 6420 * b; + return (luma + kRound) >> YUV_FIX; // no need to clip +} + +static WEBP_INLINE int VP8RGBToU(int r, int g, int b) { + return VP8ClipUV(-9719 * r - 19081 * g + 28800 * b); +} + +static WEBP_INLINE int VP8RGBToV(int r, int g, int b) { + return VP8ClipUV(+28800 * r - 24116 * g - 4684 * b); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_DSP_YUV_H_ */ diff --git a/external/libwebp/enc/Makefile.am b/external/libwebp/enc/Makefile.am new file mode 100644 index 0000000000..26698d2efa --- /dev/null +++ b/external/libwebp/enc/Makefile.am @@ -0,0 +1,32 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src +noinst_LTLIBRARIES = libwebpencode.la + +libwebpencode_la_SOURCES = +libwebpencode_la_SOURCES += alpha.c +libwebpencode_la_SOURCES += analysis.c +libwebpencode_la_SOURCES += backward_references.c +libwebpencode_la_SOURCES += config.c +libwebpencode_la_SOURCES += cost.c +libwebpencode_la_SOURCES += cost.h +libwebpencode_la_SOURCES += filter.c +libwebpencode_la_SOURCES += frame.c +libwebpencode_la_SOURCES += histogram.c +libwebpencode_la_SOURCES += iterator.c +libwebpencode_la_SOURCES += layer.c +libwebpencode_la_SOURCES += picture.c +libwebpencode_la_SOURCES += quant.c +libwebpencode_la_SOURCES += syntax.c +libwebpencode_la_SOURCES += tree.c +libwebpencode_la_SOURCES += vp8enci.h +libwebpencode_la_SOURCES += vp8l.c +libwebpencode_la_SOURCES += webpenc.c + +libwebpencodeinclude_HEADERS = +libwebpencodeinclude_HEADERS += ../webp/encode.h +libwebpencodeinclude_HEADERS += ../webp/types.h +noinst_HEADERS = +noinst_HEADERS += ../webp/format_constants.h + +libwebpencode_la_LDFLAGS = -lm +libwebpencode_la_CPPFLAGS = $(USE_EXPERIMENTAL_CODE) +libwebpencodeincludedir = $(includedir)/webp diff --git a/external/libwebp/enc/alpha.c b/external/libwebp/enc/alpha.c new file mode 100644 index 0000000000..0e519b6c66 --- /dev/null +++ b/external/libwebp/enc/alpha.c @@ -0,0 +1,330 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Alpha-plane compression. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include + +#include "./vp8enci.h" +#include "../utils/filters.h" +#include "../utils/quant_levels.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// Encodes the given alpha data via specified compression method 'method'. +// The pre-processing (quantization) is performed if 'quality' is less than 100. +// For such cases, the encoding is lossy. The valid range is [0, 100] for +// 'quality' and [0, 1] for 'method': +// 'method = 0' - No compression; +// 'method = 1' - Use lossless coder on the alpha plane only +// 'filter' values [0, 4] correspond to prediction modes none, horizontal, +// vertical & gradient filters. The prediction mode 4 will try all the +// prediction modes 0 to 3 and pick the best one. +// 'effort_level': specifies how much effort must be spent to try and reduce +// the compressed output size. In range 0 (quick) to 6 (slow). +// +// 'output' corresponds to the buffer containing compressed alpha data. +// This buffer is allocated by this method and caller should call +// free(*output) when done. +// 'output_size' corresponds to size of this compressed alpha buffer. +// +// Returns 1 on successfully encoding the alpha and +// 0 if either: +// invalid quality or method, or +// memory allocation for the compressed data fails. + +#include "../enc/vp8li.h" + +static int EncodeLossless(const uint8_t* const data, int width, int height, + int effort_level, // in [0..6] range + VP8BitWriter* const bw, + WebPAuxStats* const stats) { + int ok = 0; + WebPConfig config; + WebPPicture picture; + VP8LBitWriter tmp_bw; + + WebPPictureInit(&picture); + picture.width = width; + picture.height = height; + picture.use_argb = 1; + picture.stats = stats; + if (!WebPPictureAlloc(&picture)) return 0; + + // Transfer the alpha values to the green channel. + { + int i, j; + uint32_t* dst = picture.argb; + const uint8_t* src = data; + for (j = 0; j < picture.height; ++j) { + for (i = 0; i < picture.width; ++i) { + dst[i] = (src[i] << 8) | 0xff000000u; + } + src += width; + dst += picture.argb_stride; + } + } + + WebPConfigInit(&config); + config.lossless = 1; + config.method = effort_level; // impact is very small + // Set moderate default quality setting for alpha. Higher qualities (80 and + // above) could be very slow. + config.quality = 10.f + 15.f * effort_level; + if (config.quality > 100.f) config.quality = 100.f; + + ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3); + ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK); + WebPPictureFree(&picture); + if (ok) { + const uint8_t* const data = VP8LBitWriterFinish(&tmp_bw); + const size_t data_size = VP8LBitWriterNumBytes(&tmp_bw); + VP8BitWriterAppend(bw, data, data_size); + } + VP8LBitWriterDestroy(&tmp_bw); + return ok && !bw->error_; +} + +// ----------------------------------------------------------------------------- + +static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, + int method, int filter, int reduce_levels, + int effort_level, // in [0..6] range + uint8_t* const tmp_alpha, + VP8BitWriter* const bw, + WebPAuxStats* const stats) { + int ok = 0; + const uint8_t* alpha_src; + WebPFilterFunc filter_func; + uint8_t header; + size_t expected_size; + const size_t data_size = width * height; + + assert((uint64_t)data_size == (uint64_t)width * height); // as per spec + assert(filter >= 0 && filter < WEBP_FILTER_LAST); + assert(method >= ALPHA_NO_COMPRESSION); + assert(method <= ALPHA_LOSSLESS_COMPRESSION); + assert(sizeof(header) == ALPHA_HEADER_LEN); + // TODO(skal): have a common function and #define's to validate alpha params. + + expected_size = + (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size) + : (data_size >> 5); + header = method | (filter << 2); + if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; + + VP8BitWriterInit(bw, expected_size); + VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN); + + filter_func = WebPFilters[filter]; + if (filter_func) { + filter_func(data, width, height, 1, width, tmp_alpha); + alpha_src = tmp_alpha; + } else { + alpha_src = data; + } + + if (method == ALPHA_NO_COMPRESSION) { + ok = VP8BitWriterAppend(bw, alpha_src, width * height); + ok = ok && !bw->error_; + } else { + ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats); + VP8BitWriterFinish(bw); + } + return ok; +} + +// ----------------------------------------------------------------------------- + +// TODO(skal): move to dsp/ ? +static void CopyPlane(const uint8_t* src, int src_stride, + uint8_t* dst, int dst_stride, int width, int height) { + while (height-- > 0) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } +} + +static int EncodeAlpha(VP8Encoder* const enc, + int quality, int method, int filter, + int effort_level, + uint8_t** const output, size_t* const output_size) { + const WebPPicture* const pic = enc->pic_; + const int width = pic->width; + const int height = pic->height; + + uint8_t* quant_alpha = NULL; + const size_t data_size = width * height; + uint64_t sse = 0; + int ok = 1; + const int reduce_levels = (quality < 100); + + // quick sanity checks + assert((uint64_t)data_size == (uint64_t)width * height); // as per spec + assert(enc != NULL && pic != NULL && pic->a != NULL); + assert(output != NULL && output_size != NULL); + assert(width > 0 && height > 0); + assert(pic->a_stride >= width); + assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST); + + if (quality < 0 || quality > 100) { + return 0; + } + + if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) { + return 0; + } + + quant_alpha = (uint8_t*)malloc(data_size); + if (quant_alpha == NULL) { + return 0; + } + + // Extract alpha data (width x height) from raw_data (stride x height). + CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height); + + if (reduce_levels) { // No Quantization required for 'quality = 100'. + // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence + // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16] + // and Quality:]70, 100] -> Levels:]16, 256]. + const int alpha_levels = (quality <= 70) ? (2 + quality / 5) + : (16 + (quality - 70) * 8); + ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse); + } + + if (ok) { + VP8BitWriter bw; + int test_filter; + uint8_t* filtered_alpha = NULL; + + // We always test WEBP_FILTER_NONE first. + ok = EncodeAlphaInternal(quant_alpha, width, height, + method, WEBP_FILTER_NONE, reduce_levels, + effort_level, NULL, &bw, pic->stats); + if (!ok) { + VP8BitWriterWipeOut(&bw); + goto End; + } + + if (filter == WEBP_FILTER_FAST) { // Quick estimate of a second candidate? + filter = EstimateBestFilter(quant_alpha, width, height, width); + } + // Stop? + if (filter == WEBP_FILTER_NONE) { + goto Ok; + } + + filtered_alpha = (uint8_t*)malloc(data_size); + ok = (filtered_alpha != NULL); + if (!ok) { + goto End; + } + + // Try the other mode(s). + { + WebPAuxStats best_stats; + size_t best_score = VP8BitWriterSize(&bw); + + memset(&best_stats, 0, sizeof(best_stats)); // prevent spurious warning + if (pic->stats != NULL) best_stats = *pic->stats; + for (test_filter = WEBP_FILTER_HORIZONTAL; + ok && (test_filter <= WEBP_FILTER_GRADIENT); + ++test_filter) { + VP8BitWriter tmp_bw; + if (filter != WEBP_FILTER_BEST && test_filter != filter) { + continue; + } + ok = EncodeAlphaInternal(quant_alpha, width, height, + method, test_filter, reduce_levels, + effort_level, filtered_alpha, &tmp_bw, + pic->stats); + if (ok) { + const size_t score = VP8BitWriterSize(&tmp_bw); + if (score < best_score) { + // swap bitwriter objects. + VP8BitWriter tmp = tmp_bw; + tmp_bw = bw; + bw = tmp; + best_score = score; + if (pic->stats != NULL) best_stats = *pic->stats; + } + } else { + VP8BitWriterWipeOut(&bw); + } + VP8BitWriterWipeOut(&tmp_bw); + } + if (pic->stats != NULL) *pic->stats = best_stats; + } + Ok: + if (ok) { + *output_size = VP8BitWriterSize(&bw); + *output = VP8BitWriterBuf(&bw); + if (pic->stats != NULL) { // need stats? + pic->stats->coded_size += (int)(*output_size); + enc->sse_[3] = sse; + } + } + free(filtered_alpha); + } + End: + free(quant_alpha); + return ok; +} + + +//------------------------------------------------------------------------------ +// Main calls + +void VP8EncInitAlpha(VP8Encoder* const enc) { + enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); + enc->alpha_data_ = NULL; + enc->alpha_data_size_ = 0; +} + +int VP8EncFinishAlpha(VP8Encoder* const enc) { + if (enc->has_alpha_) { + const WebPConfig* config = enc->config_; + uint8_t* tmp_data = NULL; + size_t tmp_size = 0; + const int effort_level = config->method; // maps to [0..6] + const WEBP_FILTER_TYPE filter = + (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : + (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : + WEBP_FILTER_BEST; + + if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, + filter, effort_level, &tmp_data, &tmp_size)) { + return 0; + } + if (tmp_size != (uint32_t)tmp_size) { // Sanity check. + free(tmp_data); + return 0; + } + enc->alpha_data_size_ = (uint32_t)tmp_size; + enc->alpha_data_ = tmp_data; + } + return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); +} + +void VP8EncDeleteAlpha(VP8Encoder* const enc) { + free(enc->alpha_data_); + enc->alpha_data_ = NULL; + enc->alpha_data_size_ = 0; + enc->has_alpha_ = 0; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/analysis.c b/external/libwebp/enc/analysis.c new file mode 100644 index 0000000000..22cfb492e7 --- /dev/null +++ b/external/libwebp/enc/analysis.c @@ -0,0 +1,364 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Macroblock analysis +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "./vp8enci.h" +#include "./cost.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MAX_ITERS_K_MEANS 6 + +static int ClipAlpha(int alpha) { + return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha; +} + +//------------------------------------------------------------------------------ +// Smooth the segment map by replacing isolated block by the majority of its +// neighbours. + +static void SmoothSegmentMap(VP8Encoder* const enc) { + int n, x, y; + const int w = enc->mb_w_; + const int h = enc->mb_h_; + const int majority_cnt_3_x_3_grid = 5; + uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp)); + assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec + + if (tmp == NULL) return; + for (y = 1; y < h - 1; ++y) { + for (x = 1; x < w - 1; ++x) { + int cnt[NUM_MB_SEGMENTS] = { 0 }; + const VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; + int majority_seg = mb->segment_; + // Check the 8 neighbouring segment values. + cnt[mb[-w - 1].segment_]++; // top-left + cnt[mb[-w + 0].segment_]++; // top + cnt[mb[-w + 1].segment_]++; // top-right + cnt[mb[ - 1].segment_]++; // left + cnt[mb[ + 1].segment_]++; // right + cnt[mb[ w - 1].segment_]++; // bottom-left + cnt[mb[ w + 0].segment_]++; // bottom + cnt[mb[ w + 1].segment_]++; // bottom-right + for (n = 0; n < NUM_MB_SEGMENTS; ++n) { + if (cnt[n] >= majority_cnt_3_x_3_grid) { + majority_seg = n; + } + } + tmp[x + y * w] = majority_seg; + } + } + for (y = 1; y < h - 1; ++y) { + for (x = 1; x < w - 1; ++x) { + VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; + mb->segment_ = tmp[x + y * w]; + } + } + free(tmp); +} + +//------------------------------------------------------------------------------ +// Finalize Segment probability based on the coding tree + +static int GetProba(int a, int b) { + int proba; + const int total = a + b; + if (total == 0) return 255; // that's the default probability. + proba = (255 * a + total / 2) / total; + return proba; +} + +static void SetSegmentProbas(VP8Encoder* const enc) { + int p[NUM_MB_SEGMENTS] = { 0 }; + int n; + + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + const VP8MBInfo* const mb = &enc->mb_info_[n]; + p[mb->segment_]++; + } + if (enc->pic_->stats) { + for (n = 0; n < NUM_MB_SEGMENTS; ++n) { + enc->pic_->stats->segment_size[n] = p[n]; + } + } + if (enc->segment_hdr_.num_segments_ > 1) { + uint8_t* const probas = enc->proba_.segments_; + probas[0] = GetProba(p[0] + p[1], p[2] + p[3]); + probas[1] = GetProba(p[0], p[1]); + probas[2] = GetProba(p[2], p[3]); + + enc->segment_hdr_.update_map_ = + (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255); + enc->segment_hdr_.size_ = + p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) + + p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) + + p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) + + p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2])); + } else { + enc->segment_hdr_.update_map_ = 0; + enc->segment_hdr_.size_ = 0; + } +} + +static WEBP_INLINE int clip(int v, int m, int M) { + return v < m ? m : v > M ? M : v; +} + +static void SetSegmentAlphas(VP8Encoder* const enc, + const int centers[NUM_MB_SEGMENTS], + int mid) { + const int nb = enc->segment_hdr_.num_segments_; + int min = centers[0], max = centers[0]; + int n; + + if (nb > 1) { + for (n = 0; n < nb; ++n) { + if (min > centers[n]) min = centers[n]; + if (max < centers[n]) max = centers[n]; + } + } + if (max == min) max = min + 1; + assert(mid <= max && mid >= min); + for (n = 0; n < nb; ++n) { + const int alpha = 255 * (centers[n] - mid) / (max - min); + const int beta = 255 * (centers[n] - min) / (max - min); + enc->dqm_[n].alpha_ = clip(alpha, -127, 127); + enc->dqm_[n].beta_ = clip(beta, 0, 255); + } +} + +//------------------------------------------------------------------------------ +// Simplified k-Means, to assign Nb segments based on alpha-histogram + +static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) { + const int nb = enc->segment_hdr_.num_segments_; + int centers[NUM_MB_SEGMENTS]; + int weighted_average = 0; + int map[256]; + int a, n, k; + int min_a = 0, max_a = 255, range_a; + // 'int' type is ok for histo, and won't overflow + int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; + + // bracket the input + for (n = 0; n < 256 && alphas[n] == 0; ++n) {} + min_a = n; + for (n = 255; n > min_a && alphas[n] == 0; --n) {} + max_a = n; + range_a = max_a - min_a; + + // Spread initial centers evenly + for (n = 1, k = 0; n < 2 * nb; n += 2) { + centers[k++] = min_a + (n * range_a) / (2 * nb); + } + + for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough + int total_weight; + int displaced; + // Reset stats + for (n = 0; n < nb; ++n) { + accum[n] = 0; + dist_accum[n] = 0; + } + // Assign nearest center for each 'a' + n = 0; // track the nearest center for current 'a' + for (a = min_a; a <= max_a; ++a) { + if (alphas[a]) { + while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) { + n++; + } + map[a] = n; + // accumulate contribution into best centroid + dist_accum[n] += a * alphas[a]; + accum[n] += alphas[a]; + } + } + // All point are classified. Move the centroids to the + // center of their respective cloud. + displaced = 0; + weighted_average = 0; + total_weight = 0; + for (n = 0; n < nb; ++n) { + if (accum[n]) { + const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n]; + displaced += abs(centers[n] - new_center); + centers[n] = new_center; + weighted_average += new_center * accum[n]; + total_weight += accum[n]; + } + } + weighted_average = (weighted_average + total_weight / 2) / total_weight; + if (displaced < 5) break; // no need to keep on looping... + } + + // Map each original value to the closest centroid + for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { + VP8MBInfo* const mb = &enc->mb_info_[n]; + const int alpha = mb->alpha_; + mb->segment_ = map[alpha]; + mb->alpha_ = centers[map[alpha]]; // just for the record. + } + + if (nb > 1) { + const int smooth = (enc->config_->preprocessing & 1); + if (smooth) SmoothSegmentMap(enc); + } + + SetSegmentProbas(enc); // Assign final proba + SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas. +} + +//------------------------------------------------------------------------------ +// Macroblock analysis: collect histogram for each mode, deduce the maximal +// susceptibility and set best modes for this macroblock. +// Segment assignment is done later. + +// Number of modes to inspect for alpha_ evaluation. For high-quality settings, +// we don't need to test all the possible modes during the analysis phase. +#define MAX_INTRA16_MODE 2 +#define MAX_INTRA4_MODE 2 +#define MAX_UV_MODE 2 + +static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) { + const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA16_MODE : 4; + int mode; + int best_alpha = -1; + int best_mode = 0; + + VP8MakeLuma16Preds(it); + for (mode = 0; mode < max_mode; ++mode) { + const int alpha = VP8CollectHistogram(it->yuv_in_ + Y_OFF, + it->yuv_p_ + VP8I16ModeOffsets[mode], + 0, 16); + if (alpha > best_alpha) { + best_alpha = alpha; + best_mode = mode; + } + } + VP8SetIntra16Mode(it, best_mode); + return best_alpha; +} + +static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it, + int best_alpha) { + uint8_t modes[16]; + const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA4_MODE : NUM_BMODES; + int i4_alpha = 0; + VP8IteratorStartI4(it); + do { + int mode; + int best_mode_alpha = -1; + const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_]; + + VP8MakeIntra4Preds(it); + for (mode = 0; mode < max_mode; ++mode) { + const int alpha = VP8CollectHistogram(src, + it->yuv_p_ + VP8I4ModeOffsets[mode], + 0, 1); + if (alpha > best_mode_alpha) { + best_mode_alpha = alpha; + modes[it->i4_] = mode; + } + } + i4_alpha += best_mode_alpha; + // Note: we reuse the original samples for predictors + } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF)); + + if (i4_alpha > best_alpha) { + VP8SetIntra4Mode(it, modes); + best_alpha = ClipAlpha(i4_alpha); + } + return best_alpha; +} + +static int MBAnalyzeBestUVMode(VP8EncIterator* const it) { + int best_alpha = -1; + int best_mode = 0; + const int max_mode = (it->enc_->method_ >= 3) ? MAX_UV_MODE : 4; + int mode; + VP8MakeChroma8Preds(it); + for (mode = 0; mode < max_mode; ++mode) { + const int alpha = VP8CollectHistogram(it->yuv_in_ + U_OFF, + it->yuv_p_ + VP8UVModeOffsets[mode], + 16, 16 + 4 + 4); + if (alpha > best_alpha) { + best_alpha = alpha; + best_mode = mode; + } + } + VP8SetIntraUVMode(it, best_mode); + return best_alpha; +} + +static void MBAnalyze(VP8EncIterator* const it, + int alphas[256], int* const uv_alpha) { + const VP8Encoder* const enc = it->enc_; + int best_alpha, best_uv_alpha; + + VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED + VP8SetSkip(it, 0); // not skipped + VP8SetSegment(it, 0); // default segment, spec-wise. + + best_alpha = MBAnalyzeBestIntra16Mode(it); + if (enc->method_ != 3) { + // We go and make a fast decision for intra4/intra16. + // It's usually not a good and definitive pick, but helps seeding the stats + // about level bit-cost. + // TODO(skal): improve criterion. + best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha); + } + best_uv_alpha = MBAnalyzeBestUVMode(it); + + // Final susceptibility mix + best_alpha = (best_alpha + best_uv_alpha + 1) / 2; + alphas[best_alpha]++; + *uv_alpha += best_uv_alpha; + it->mb_->alpha_ = best_alpha; // Informative only. +} + +//------------------------------------------------------------------------------ +// Main analysis loop: +// Collect all susceptibilities for each macroblock and record their +// distribution in alphas[]. Segments is assigned a-posteriori, based on +// this histogram. +// We also pick an intra16 prediction mode, which shouldn't be considered +// final except for fast-encode settings. We can also pick some intra4 modes +// and decide intra4/intra16, but that's usually almost always a bad choice at +// this stage. + +int VP8EncAnalyze(VP8Encoder* const enc) { + int ok = 1; + int alphas[256] = { 0 }; + VP8EncIterator it; + + VP8IteratorInit(enc, &it); + enc->uv_alpha_ = 0; + do { + VP8IteratorImport(&it); + MBAnalyze(&it, alphas, &enc->uv_alpha_); + ok = VP8IteratorProgress(&it, 20); + // Let's pretend we have perfect lossless reconstruction. + } while (ok && VP8IteratorNext(&it, it.yuv_in_)); + enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_; + if (ok) AssignSegments(enc, alphas); + + return ok; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/backward_references.c b/external/libwebp/enc/backward_references.c new file mode 100644 index 0000000000..fd30f307df --- /dev/null +++ b/external/libwebp/enc/backward_references.c @@ -0,0 +1,873 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// + +#include +#include +#include + +#include "./backward_references.h" +#include "./histogram.h" +#include "../dsp/lossless.h" +#include "../utils/color_cache.h" +#include "../utils/utils.h" + +#define VALUES_IN_BYTE 256 + +#define HASH_BITS 18 +#define HASH_SIZE (1 << HASH_BITS) +#define HASH_MULTIPLIER (0xc6a4a7935bd1e995ULL) + +// 1M window (4M bytes) minus 120 special codes for short distances. +#define WINDOW_SIZE ((1 << 20) - 120) + +// Bounds for the match length. +#define MIN_LENGTH 2 +#define MAX_LENGTH 4096 + +typedef struct { + // Stores the most recently added position with the given hash value. + int32_t hash_to_first_index_[HASH_SIZE]; + // chain_[pos] stores the previous position with the same hash value + // for every pixel in the image. + int32_t* chain_; +} HashChain; + +// ----------------------------------------------------------------------------- + +static const uint8_t plane_to_code_lut[128] = { + 96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255, + 101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79, + 102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87, + 105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91, + 110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100, + 115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109, + 118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114, + 119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117 +}; + +static int DistanceToPlaneCode(int xsize, int dist) { + const int yoffset = dist / xsize; + const int xoffset = dist - yoffset * xsize; + if (xoffset <= 8 && yoffset < 8) { + return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1; + } else if (xoffset > xsize - 8 && yoffset < 7) { + return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1; + } + return dist + 120; +} + +static WEBP_INLINE int FindMatchLength(const uint32_t* const array1, + const uint32_t* const array2, + const int max_limit) { + int match_len = 0; + while (match_len < max_limit && array1[match_len] == array2[match_len]) { + ++match_len; + } + return match_len; +} + +// ----------------------------------------------------------------------------- +// VP8LBackwardRefs + +void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) { + if (refs != NULL) { + refs->refs = NULL; + refs->size = 0; + refs->max_size = 0; + } +} + +void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { + if (refs != NULL) { + free(refs->refs); + VP8LInitBackwardRefs(refs); + } +} + +int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size) { + assert(refs != NULL); + refs->size = 0; + refs->max_size = 0; + refs->refs = (PixOrCopy*)WebPSafeMalloc((uint64_t)max_size, + sizeof(*refs->refs)); + if (refs->refs == NULL) return 0; + refs->max_size = max_size; + return 1; +} + +// ----------------------------------------------------------------------------- +// Hash chains + +static WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) { + uint64_t key = ((uint64_t)(argb[1]) << 32) | argb[0]; + key = (key * HASH_MULTIPLIER) >> (64 - HASH_BITS); + return key; +} + +static int HashChainInit(HashChain* const p, int size) { + int i; + p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_)); + if (p->chain_ == NULL) { + return 0; + } + for (i = 0; i < size; ++i) { + p->chain_[i] = -1; + } + for (i = 0; i < HASH_SIZE; ++i) { + p->hash_to_first_index_[i] = -1; + } + return 1; +} + +static void HashChainDelete(HashChain* const p) { + if (p != NULL) { + free(p->chain_); + free(p); + } +} + +// Insertion of two pixels at a time. +static void HashChainInsert(HashChain* const p, + const uint32_t* const argb, int pos) { + const uint64_t hash_code = GetPixPairHash64(argb); + p->chain_[pos] = p->hash_to_first_index_[hash_code]; + p->hash_to_first_index_[hash_code] = pos; +} + +static int HashChainFindCopy(const HashChain* const p, + int quality, int index, int xsize, + const uint32_t* const argb, int maxlen, + int* const distance_ptr, + int* const length_ptr) { + const uint64_t hash_code = GetPixPairHash64(&argb[index]); + int prev_length = 0; + int64_t best_val = 0; + int best_length = 0; + int best_distance = 0; + const uint32_t* const argb_start = argb + index; + const int iter_min_mult = (quality < 50) ? 2 : (quality < 75) ? 4 : 8; + const int iter_min = -quality * iter_min_mult; + int iter_cnt = 10 + (quality >> 1); + const int min_pos = (index > WINDOW_SIZE) ? index - WINDOW_SIZE : 0; + int pos; + + assert(xsize > 0); + for (pos = p->hash_to_first_index_[hash_code]; + pos >= min_pos; + pos = p->chain_[pos]) { + int64_t val; + int curr_length; + if (iter_cnt < 0) { + if (iter_cnt < iter_min || best_val >= 0xff0000) { + break; + } + } + --iter_cnt; + if (best_length != 0 && + argb[pos + best_length - 1] != argb_start[best_length - 1]) { + continue; + } + curr_length = FindMatchLength(argb + pos, argb_start, maxlen); + if (curr_length < prev_length) { + continue; + } + val = 65536 * curr_length; + // Favoring 2d locality here gives savings for certain images. + if (index - pos < 9 * xsize) { + const int y = (index - pos) / xsize; + int x = (index - pos) % xsize; + if (x > xsize / 2) { + x = xsize - x; + } + if (x <= 7 && x >= -8) { + val -= y * y + x * x; + } else { + val -= 9 * 9 + 9 * 9; + } + } else { + val -= 9 * 9 + 9 * 9; + } + if (best_val < val) { + prev_length = curr_length; + best_val = val; + best_length = curr_length; + best_distance = index - pos; + if (curr_length >= MAX_LENGTH) { + break; + } + if ((best_distance == 1 || best_distance == xsize) && + best_length >= 128) { + break; + } + } + } + *distance_ptr = best_distance; + *length_ptr = best_length; + return (best_length >= MIN_LENGTH); +} + +static WEBP_INLINE void PushBackCopy(VP8LBackwardRefs* const refs, int length) { + int size = refs->size; + while (length >= MAX_LENGTH) { + refs->refs[size++] = PixOrCopyCreateCopy(1, MAX_LENGTH); + length -= MAX_LENGTH; + } + if (length > 0) { + refs->refs[size++] = PixOrCopyCreateCopy(1, length); + } + refs->size = size; +} + +static void BackwardReferencesRle(int xsize, int ysize, + const uint32_t* const argb, + VP8LBackwardRefs* const refs) { + const int pix_count = xsize * ysize; + int match_len = 0; + int i; + refs->size = 0; + PushBackCopy(refs, match_len); // i=0 case + refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[0]); + for (i = 1; i < pix_count; ++i) { + if (argb[i] == argb[i - 1]) { + ++match_len; + } else { + PushBackCopy(refs, match_len); + match_len = 0; + refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[i]); + } + } + PushBackCopy(refs, match_len); +} + +static int BackwardReferencesHashChain(int xsize, int ysize, + const uint32_t* const argb, + int cache_bits, int quality, + VP8LBackwardRefs* const refs) { + int i; + int ok = 0; + int cc_init = 0; + const int use_color_cache = (cache_bits > 0); + const int pix_count = xsize * ysize; + HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); + VP8LColorCache hashers; + + if (hash_chain == NULL) return 0; + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + + if (!HashChainInit(hash_chain, pix_count)) goto Error; + + refs->size = 0; + for (i = 0; i < pix_count; ) { + // Alternative#1: Code the pixels starting at 'i' using backward reference. + int offset = 0; + int len = 0; + if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1]. + int maxlen = pix_count - i; + if (maxlen > MAX_LENGTH) { + maxlen = MAX_LENGTH; + } + HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen, + &offset, &len); + } + if (len >= MIN_LENGTH) { + // Alternative#2: Insert the pixel at 'i' as literal, and code the + // pixels starting at 'i + 1' using backward reference. + int offset2 = 0; + int len2 = 0; + int k; + HashChainInsert(hash_chain, &argb[i], i); + if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2]. + int maxlen = pix_count - (i + 1); + if (maxlen > MAX_LENGTH) { + maxlen = MAX_LENGTH; + } + HashChainFindCopy(hash_chain, quality, + i + 1, xsize, argb, maxlen, &offset2, &len2); + if (len2 > len + 1) { + const uint32_t pixel = argb[i]; + // Alternative#2 is a better match. So push pixel at 'i' as literal. + if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { + const int ix = VP8LColorCacheGetIndex(&hashers, pixel); + refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); + } else { + refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); + } + ++refs->size; + if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); + i++; // Backward reference to be done for next pixel. + len = len2; + offset = offset2; + } + } + if (len >= MAX_LENGTH) { + len = MAX_LENGTH - 1; + } + refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len); + if (use_color_cache) { + for (k = 0; k < len; ++k) { + VP8LColorCacheInsert(&hashers, argb[i + k]); + } + } + // Add to the hash_chain (but cannot add the last pixel). + { + const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; + for (k = 1; k < last; ++k) { + HashChainInsert(hash_chain, &argb[i + k], i + k); + } + } + i += len; + } else { + const uint32_t pixel = argb[i]; + if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) { + // push pixel as a PixOrCopyCreateCacheIdx pixel + const int ix = VP8LColorCacheGetIndex(&hashers, pixel); + refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix); + } else { + refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel); + } + ++refs->size; + if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel); + if (i + 1 < pix_count) { + HashChainInsert(hash_chain, &argb[i], i); + } + ++i; + } + } + ok = 1; +Error: + if (cc_init) VP8LColorCacheClear(&hashers); + HashChainDelete(hash_chain); + return ok; +} + +// ----------------------------------------------------------------------------- + +typedef struct { + double alpha_[VALUES_IN_BYTE]; + double red_[VALUES_IN_BYTE]; + double literal_[PIX_OR_COPY_CODES_MAX]; + double blue_[VALUES_IN_BYTE]; + double distance_[NUM_DISTANCE_CODES]; +} CostModel; + +static int BackwardReferencesTraceBackwards( + int xsize, int ysize, int recursive_cost_model, + const uint32_t* const argb, int cache_bits, VP8LBackwardRefs* const refs); + +static void ConvertPopulationCountTableToBitEstimates( + int num_symbols, const int population_counts[], double output[]) { + int sum = 0; + int nonzeros = 0; + int i; + for (i = 0; i < num_symbols; ++i) { + sum += population_counts[i]; + if (population_counts[i] > 0) { + ++nonzeros; + } + } + if (nonzeros <= 1) { + memset(output, 0, num_symbols * sizeof(*output)); + } else { + const double logsum = VP8LFastLog2(sum); + for (i = 0; i < num_symbols; ++i) { + output[i] = logsum - VP8LFastLog2(population_counts[i]); + } + } +} + +static int CostModelBuild(CostModel* const m, int xsize, int ysize, + int recursion_level, const uint32_t* const argb, + int cache_bits) { + int ok = 0; + VP8LHistogram histo; + VP8LBackwardRefs refs; + const int quality = 100; + + if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error; + + if (recursion_level > 0) { + if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1, + argb, cache_bits, &refs)) { + goto Error; + } + } else { + if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality, + &refs)) { + goto Error; + } + } + VP8LHistogramCreate(&histo, &refs, cache_bits); + ConvertPopulationCountTableToBitEstimates( + VP8LHistogramNumCodes(&histo), histo.literal_, m->literal_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo.red_, m->red_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo.blue_, m->blue_); + ConvertPopulationCountTableToBitEstimates( + VALUES_IN_BYTE, histo.alpha_, m->alpha_); + ConvertPopulationCountTableToBitEstimates( + NUM_DISTANCE_CODES, histo.distance_, m->distance_); + ok = 1; + + Error: + VP8LClearBackwardRefs(&refs); + return ok; +} + +static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) { + return m->alpha_[v >> 24] + + m->red_[(v >> 16) & 0xff] + + m->literal_[(v >> 8) & 0xff] + + m->blue_[v & 0xff]; +} + +static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) { + const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; + return m->literal_[literal_idx]; +} + +static WEBP_INLINE double GetLengthCost(const CostModel* const m, + uint32_t length) { + int code, extra_bits_count, extra_bits_value; + PrefixEncode(length, &code, &extra_bits_count, &extra_bits_value); + return m->literal_[VALUES_IN_BYTE + code] + extra_bits_count; +} + +static WEBP_INLINE double GetDistanceCost(const CostModel* const m, + uint32_t distance) { + int code, extra_bits_count, extra_bits_value; + PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value); + return m->distance_[code] + extra_bits_count; +} + +static int BackwardReferencesHashChainDistanceOnly( + int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb, + int cache_bits, uint32_t* const dist_array) { + int i; + int ok = 0; + int cc_init = 0; + const int quality = 100; + const int pix_count = xsize * ysize; + const int use_color_cache = (cache_bits > 0); + float* const cost = + (float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost)); + CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model)); + HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); + VP8LColorCache hashers; + const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68; + const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82; + + if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error; + + if (!HashChainInit(hash_chain, pix_count)) goto Error; + + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + + if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb, + cache_bits)) { + goto Error; + } + + for (i = 0; i < pix_count; ++i) cost[i] = 1e38f; + + // We loop one pixel at a time, but store all currently best points to + // non-processed locations from this point. + dist_array[0] = 0; + for (i = 0; i < pix_count; ++i) { + double prev_cost = 0.0; + int shortmax; + if (i > 0) { + prev_cost = cost[i - 1]; + } + for (shortmax = 0; shortmax < 2; ++shortmax) { + int offset = 0; + int len = 0; + if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1]. + int maxlen = shortmax ? 2 : MAX_LENGTH; + if (maxlen > pix_count - i) { + maxlen = pix_count - i; + } + HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen, + &offset, &len); + } + if (len >= MIN_LENGTH) { + const int code = DistanceToPlaneCode(xsize, offset); + const double distance_cost = + prev_cost + GetDistanceCost(cost_model, code); + int k; + for (k = 1; k < len; ++k) { + const double cost_val = distance_cost + GetLengthCost(cost_model, k); + if (cost[i + k] > cost_val) { + cost[i + k] = (float)cost_val; + dist_array[i + k] = k + 1; + } + } + // This if is for speedup only. It roughly doubles the speed, and + // makes compression worse by .1 %. + if (len >= 128 && code < 2) { + // Long copy for short distances, let's skip the middle + // lookups for better copies. + // 1) insert the hashes. + if (use_color_cache) { + for (k = 0; k < len; ++k) { + VP8LColorCacheInsert(&hashers, argb[i + k]); + } + } + // 2) Add to the hash_chain (but cannot add the last pixel) + { + const int last = (len < pix_count - 1 - i) ? len + : pix_count - 1 - i; + for (k = 0; k < last; ++k) { + HashChainInsert(hash_chain, &argb[i + k], i + k); + } + } + // 3) jump. + i += len - 1; // for loop does ++i, thus -1 here. + goto next_symbol; + } + } + } + if (i < pix_count - 1) { + HashChainInsert(hash_chain, &argb[i], i); + } + { + // inserting a literal pixel + double cost_val = prev_cost; + if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { + const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]); + cost_val += GetCacheCost(cost_model, ix) * mul0; + } else { + cost_val += GetLiteralCost(cost_model, argb[i]) * mul1; + } + if (cost[i] > cost_val) { + cost[i] = (float)cost_val; + dist_array[i] = 1; // only one is inserted. + } + if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); + } + next_symbol: ; + } + // Last pixel still to do, it can only be a single step if not reached + // through cheaper means already. + ok = 1; +Error: + if (cc_init) VP8LColorCacheClear(&hashers); + HashChainDelete(hash_chain); + free(cost_model); + free(cost); + return ok; +} + +static int TraceBackwards(const uint32_t* const dist_array, + int dist_array_size, + uint32_t** const chosen_path, + int* const chosen_path_size) { + int i; + // Count how many. + int count = 0; + for (i = dist_array_size - 1; i >= 0; ) { + int k = dist_array[i]; + assert(k >= 1); + ++count; + i -= k; + } + // Allocate. + *chosen_path_size = count; + *chosen_path = + (uint32_t*)WebPSafeMalloc((uint64_t)count, sizeof(**chosen_path)); + if (*chosen_path == NULL) return 0; + + // Write in reverse order. + for (i = dist_array_size - 1; i >= 0; ) { + int k = dist_array[i]; + assert(k >= 1); + (*chosen_path)[--count] = k; + i -= k; + } + return 1; +} + +static int BackwardReferencesHashChainFollowChosenPath( + int xsize, int ysize, const uint32_t* const argb, int cache_bits, + const uint32_t* const chosen_path, int chosen_path_size, + VP8LBackwardRefs* const refs) { + const int quality = 100; + const int pix_count = xsize * ysize; + const int use_color_cache = (cache_bits > 0); + int size = 0; + int i = 0; + int k; + int ix; + int ok = 0; + int cc_init = 0; + HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain)); + VP8LColorCache hashers; + + if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) { + goto Error; + } + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) goto Error; + } + + refs->size = 0; + for (ix = 0; ix < chosen_path_size; ++ix, ++size) { + int offset = 0; + int len = 0; + int maxlen = chosen_path[ix]; + if (maxlen != 1) { + HashChainFindCopy(hash_chain, quality, + i, xsize, argb, maxlen, &offset, &len); + assert(len == maxlen); + refs->refs[size] = PixOrCopyCreateCopy(offset, len); + if (use_color_cache) { + for (k = 0; k < len; ++k) { + VP8LColorCacheInsert(&hashers, argb[i + k]); + } + } + { + const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i; + for (k = 0; k < last; ++k) { + HashChainInsert(hash_chain, &argb[i + k], i + k); + } + } + i += len; + } else { + if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) { + // push pixel as a color cache index + const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]); + refs->refs[size] = PixOrCopyCreateCacheIdx(idx); + } else { + refs->refs[size] = PixOrCopyCreateLiteral(argb[i]); + } + if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); + if (i + 1 < pix_count) { + HashChainInsert(hash_chain, &argb[i], i); + } + ++i; + } + } + assert(size <= refs->max_size); + refs->size = size; + ok = 1; +Error: + if (cc_init) VP8LColorCacheClear(&hashers); + HashChainDelete(hash_chain); + return ok; +} + +// Returns 1 on success. +static int BackwardReferencesTraceBackwards(int xsize, int ysize, + int recursive_cost_model, + const uint32_t* const argb, + int cache_bits, + VP8LBackwardRefs* const refs) { + int ok = 0; + const int dist_array_size = xsize * ysize; + uint32_t* chosen_path = NULL; + int chosen_path_size = 0; + uint32_t* dist_array = + (uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array)); + + if (dist_array == NULL) goto Error; + + if (!BackwardReferencesHashChainDistanceOnly( + xsize, ysize, recursive_cost_model, argb, cache_bits, dist_array)) { + goto Error; + } + if (!TraceBackwards(dist_array, dist_array_size, + &chosen_path, &chosen_path_size)) { + goto Error; + } + free(dist_array); // no need to retain this memory any longer + dist_array = NULL; + if (!BackwardReferencesHashChainFollowChosenPath( + xsize, ysize, argb, cache_bits, chosen_path, chosen_path_size, refs)) { + goto Error; + } + ok = 1; + Error: + free(chosen_path); + free(dist_array); + return ok; +} + +static void BackwardReferences2DLocality(int xsize, + VP8LBackwardRefs* const refs) { + int i; + for (i = 0; i < refs->size; ++i) { + if (PixOrCopyIsCopy(&refs->refs[i])) { + const int dist = refs->refs[i].argb_or_distance; + const int transformed_dist = DistanceToPlaneCode(xsize, dist); + refs->refs[i].argb_or_distance = transformed_dist; + } + } +} + +int VP8LGetBackwardReferences(int width, int height, + const uint32_t* const argb, + int quality, int cache_bits, int use_2d_locality, + VP8LBackwardRefs* const best) { + int ok = 0; + int lz77_is_useful; + VP8LBackwardRefs refs_rle, refs_lz77; + const int num_pix = width * height; + + VP8LBackwardRefsAlloc(&refs_rle, num_pix); + VP8LBackwardRefsAlloc(&refs_lz77, num_pix); + VP8LInitBackwardRefs(best); + if (refs_rle.refs == NULL || refs_lz77.refs == NULL) { + Error1: + VP8LClearBackwardRefs(&refs_rle); + VP8LClearBackwardRefs(&refs_lz77); + goto End; + } + + if (!BackwardReferencesHashChain(width, height, argb, cache_bits, quality, + &refs_lz77)) { + goto End; + } + // Backward Reference using RLE only. + BackwardReferencesRle(width, height, argb, &refs_rle); + + { + double bit_cost_lz77, bit_cost_rle; + VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo)); + if (histo == NULL) goto Error1; + // Evaluate lz77 coding + VP8LHistogramCreate(histo, &refs_lz77, cache_bits); + bit_cost_lz77 = VP8LHistogramEstimateBits(histo); + // Evaluate RLE coding + VP8LHistogramCreate(histo, &refs_rle, cache_bits); + bit_cost_rle = VP8LHistogramEstimateBits(histo); + // Decide if LZ77 is useful. + lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); + free(histo); + } + + // Choose appropriate backward reference. + if (lz77_is_useful) { + // TraceBackwards is costly. Run it for higher qualities. + const int try_lz77_trace_backwards = (quality >= 75); + *best = refs_lz77; // default guess: lz77 is better + VP8LClearBackwardRefs(&refs_rle); + if (try_lz77_trace_backwards) { + const int recursion_level = (num_pix < 320 * 200) ? 1 : 0; + VP8LBackwardRefs refs_trace; + if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) { + goto End; + } + if (BackwardReferencesTraceBackwards( + width, height, recursion_level, argb, cache_bits, &refs_trace)) { + VP8LClearBackwardRefs(&refs_lz77); + *best = refs_trace; + } + } + } else { + VP8LClearBackwardRefs(&refs_lz77); + *best = refs_rle; + } + + if (use_2d_locality) BackwardReferences2DLocality(width, best); + + ok = 1; + + End: + if (!ok) { + VP8LClearBackwardRefs(best); + } + return ok; +} + +// Returns 1 on success. +static int ComputeCacheHistogram(const uint32_t* const argb, + int xsize, int ysize, + const VP8LBackwardRefs* const refs, + int cache_bits, + VP8LHistogram* const histo) { + int pixel_index = 0; + int i; + uint32_t k; + VP8LColorCache hashers; + const int use_color_cache = (cache_bits > 0); + int cc_init = 0; + + if (use_color_cache) { + cc_init = VP8LColorCacheInit(&hashers, cache_bits); + if (!cc_init) return 0; + } + + for (i = 0; i < refs->size; ++i) { + const PixOrCopy* const v = &refs->refs[i]; + if (PixOrCopyIsLiteral(v)) { + if (use_color_cache && + VP8LColorCacheContains(&hashers, argb[pixel_index])) { + // push pixel as a cache index + const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]); + const PixOrCopy token = PixOrCopyCreateCacheIdx(ix); + VP8LHistogramAddSinglePixOrCopy(histo, &token); + } else { + VP8LHistogramAddSinglePixOrCopy(histo, v); + } + } else { + VP8LHistogramAddSinglePixOrCopy(histo, v); + } + if (use_color_cache) { + for (k = 0; k < PixOrCopyLength(v); ++k) { + VP8LColorCacheInsert(&hashers, argb[pixel_index + k]); + } + } + pixel_index += PixOrCopyLength(v); + } + assert(pixel_index == xsize * ysize); + (void)xsize; // xsize is not used in non-debug compilations otherwise. + (void)ysize; // ysize is not used in non-debug compilations otherwise. + if (cc_init) VP8LColorCacheClear(&hashers); + return 1; +} + +// Returns how many bits are to be used for a color cache. +int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb, + int xsize, int ysize, + int* const best_cache_bits) { + int ok = 0; + int cache_bits; + double lowest_entropy = 1e99; + VP8LBackwardRefs refs; + static const double kSmallPenaltyForLargeCache = 4.0; + static const int quality = 30; + if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) || + !BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) { + goto Error; + } + for (cache_bits = 0; cache_bits <= MAX_COLOR_CACHE_BITS; ++cache_bits) { + double cur_entropy; + VP8LHistogram histo; + VP8LHistogramInit(&histo, cache_bits); + ComputeCacheHistogram(argb, xsize, ysize, &refs, cache_bits, &histo); + cur_entropy = VP8LHistogramEstimateBits(&histo) + + kSmallPenaltyForLargeCache * cache_bits; + if (cache_bits == 0 || cur_entropy < lowest_entropy) { + *best_cache_bits = cache_bits; + lowest_entropy = cur_entropy; + } + } + ok = 1; + Error: + VP8LClearBackwardRefs(&refs); + return ok; +} diff --git a/external/libwebp/enc/backward_references.h b/external/libwebp/enc/backward_references.h new file mode 100644 index 0000000000..2fb1aecc5d --- /dev/null +++ b/external/libwebp/enc/backward_references.h @@ -0,0 +1,214 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// + +#ifndef WEBP_ENC_BACKWARD_REFERENCES_H_ +#define WEBP_ENC_BACKWARD_REFERENCES_H_ + +#include "platform/CCPlatformConfig.h" + +#include +#include +#include "../webp/types.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// The spec allows 11, we use 9 bits to reduce memory consumption in encoding. +// Having 9 instead of 11 only removes about 0.25 % of compression density. +#define MAX_COLOR_CACHE_BITS 9 + +// Max ever number of codes we'll use: +#define PIX_OR_COPY_CODES_MAX \ + (NUM_LITERAL_CODES + NUM_LENGTH_CODES + (1 << MAX_COLOR_CACHE_BITS)) + +// ----------------------------------------------------------------------------- +// PrefixEncode() + +// use GNU builtins where available. +#if defined(__GNUC__) && \ + ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4) +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { + return n == 0 ? -1 : 31 ^ __builtin_clz(n); +} +#elif (defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) +#include +#pragma intrinsic(_BitScanReverse) + +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { + unsigned long first_set_bit; + return _BitScanReverse(&first_set_bit, n) ? first_set_bit : -1; +} +#else +static WEBP_INLINE int BitsLog2Floor(uint32_t n) { + int log = 0; + uint32_t value = n; + int i; + + if (value == 0) return -1; + for (i = 4; i >= 0; --i) { + const int shift = (1 << i); + const uint32_t x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + return log; +} +#endif + +static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) { + const int floor = BitsLog2Floor(n); + if (n == (n & ~(n - 1))) // zero or a power of two. + return floor; + else + return floor + 1; +} + +// Splitting of distance and length codes into prefixes and +// extra bits. The prefixes are encoded with an entropy code +// while the extra bits are stored just as normal bits. +static WEBP_INLINE void PrefixEncode(int distance, int* const code, + int* const extra_bits_count, + int* const extra_bits_value) { + // Collect the two most significant bits where the highest bit is 1. + const int highest_bit = BitsLog2Floor(--distance); + // & 0x3f is to make behavior well defined when highest_bit + // does not exist or is the least significant bit. + const int second_highest_bit = + (distance >> ((highest_bit - 1) & 0x3f)) & 1; + *extra_bits_count = (highest_bit > 0) ? (highest_bit - 1) : 0; + *extra_bits_value = distance & ((1 << *extra_bits_count) - 1); + *code = (highest_bit > 0) ? (2 * highest_bit + second_highest_bit) + : (highest_bit == 0) ? 1 : 0; +} + +// ----------------------------------------------------------------------------- +// PixOrCopy + +enum Mode { + kLiteral, + kCacheIdx, + kCopy, + kNone +}; + +typedef struct { + // mode as uint8_t to make the memory layout to be exactly 8 bytes. + uint8_t mode; + uint16_t len; + uint32_t argb_or_distance; +} PixOrCopy; + +static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance, + uint16_t len) { + PixOrCopy retval; + retval.mode = kCopy; + retval.argb_or_distance = distance; + retval.len = len; + return retval; +} + +static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) { + PixOrCopy retval; + assert(idx >= 0); + assert(idx < (1 << MAX_COLOR_CACHE_BITS)); + retval.mode = kCacheIdx; + retval.argb_or_distance = idx; + retval.len = 1; + return retval; +} + +static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) { + PixOrCopy retval; + retval.mode = kLiteral; + retval.argb_or_distance = argb; + retval.len = 1; + return retval; +} + +static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) { + return (p->mode == kLiteral); +} + +static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) { + return (p->mode == kCacheIdx); +} + +static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) { + return (p->mode == kCopy); +} + +static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p, + int component) { + assert(p->mode == kLiteral); + return (p->argb_or_distance >> (component * 8)) & 0xff; +} + +static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) { + return p->len; +} + +static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) { + assert(p->mode == kLiteral); + return p->argb_or_distance; +} + +static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) { + assert(p->mode == kCacheIdx); + assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS)); + return p->argb_or_distance; +} + +static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) { + assert(p->mode == kCopy); + return p->argb_or_distance; +} + +// ----------------------------------------------------------------------------- +// VP8LBackwardRefs + +typedef struct { + PixOrCopy* refs; + int size; // currently used + int max_size; // maximum capacity +} VP8LBackwardRefs; + +// Initialize the object. Must be called first. 'refs' can be NULL. +void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs); + +// Release memory and re-initialize the object. 'refs' can be NULL. +void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); + +// Allocate 'max_size' references. Returns false in case of memory error. +int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size); + +// ----------------------------------------------------------------------------- +// Main entry points + +// Evaluates best possible backward references for specified quality. +// Further optimize for 2D locality if use_2d_locality flag is set. +int VP8LGetBackwardReferences(int width, int height, + const uint32_t* const argb, + int quality, int cache_bits, int use_2d_locality, + VP8LBackwardRefs* const best); + +// Produce an estimate for a good color cache size for the image. +int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb, + int xsize, int ysize, + int* const best_cache_bits); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif // WEBP_ENC_BACKWARD_REFERENCES_H_ diff --git a/external/libwebp/enc/config.c b/external/libwebp/enc/config.c new file mode 100644 index 0000000000..1a26113554 --- /dev/null +++ b/external/libwebp/enc/config.c @@ -0,0 +1,132 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Coding tools configuration +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "../webp/encode.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// WebPConfig +//------------------------------------------------------------------------------ + +int WebPConfigInitInternal(WebPConfig* config, + WebPPreset preset, float quality, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { + return 0; // caller/system version mismatch! + } + if (config == NULL) return 0; + + config->quality = quality; + config->target_size = 0; + config->target_PSNR = 0.; + config->method = 4; + config->sns_strength = 50; + config->filter_strength = 20; // default: light filtering + config->filter_sharpness = 0; + config->filter_type = 0; // default: simple + config->partitions = 0; + config->segments = 4; + config->pass = 1; + config->show_compressed = 0; + config->preprocessing = 0; + config->autofilter = 0; + config->partition_limit = 0; + config->alpha_compression = 1; + config->alpha_filtering = 1; + config->alpha_quality = 100; + config->lossless = 0; + config->image_hint = WEBP_HINT_DEFAULT; + + // TODO(skal): tune. + switch (preset) { + case WEBP_PRESET_PICTURE: + config->sns_strength = 80; + config->filter_sharpness = 4; + config->filter_strength = 35; + break; + case WEBP_PRESET_PHOTO: + config->sns_strength = 80; + config->filter_sharpness = 3; + config->filter_strength = 30; + break; + case WEBP_PRESET_DRAWING: + config->sns_strength = 25; + config->filter_sharpness = 6; + config->filter_strength = 10; + break; + case WEBP_PRESET_ICON: + config->sns_strength = 0; + config->filter_strength = 0; // disable filtering to retain sharpness + break; + case WEBP_PRESET_TEXT: + config->sns_strength = 0; + config->filter_strength = 0; // disable filtering to retain sharpness + config->segments = 2; + break; + case WEBP_PRESET_DEFAULT: + default: + break; + } + return WebPValidateConfig(config); +} + +int WebPValidateConfig(const WebPConfig* config) { + if (config == NULL) return 0; + if (config->quality < 0 || config->quality > 100) + return 0; + if (config->target_size < 0) + return 0; + if (config->target_PSNR < 0) + return 0; + if (config->method < 0 || config->method > 6) + return 0; + if (config->segments < 1 || config->segments > 4) + return 0; + if (config->sns_strength < 0 || config->sns_strength > 100) + return 0; + if (config->filter_strength < 0 || config->filter_strength > 100) + return 0; + if (config->filter_sharpness < 0 || config->filter_sharpness > 7) + return 0; + if (config->filter_type < 0 || config->filter_type > 1) + return 0; + if (config->autofilter < 0 || config->autofilter > 1) + return 0; + if (config->pass < 1 || config->pass > 10) + return 0; + if (config->show_compressed < 0 || config->show_compressed > 1) + return 0; + if (config->preprocessing < 0 || config->preprocessing > 1) + return 0; + if (config->partitions < 0 || config->partitions > 3) + return 0; + if (config->partition_limit < 0 || config->partition_limit > 100) + return 0; + if (config->alpha_compression < 0) + return 0; + if (config->alpha_filtering < 0) + return 0; + if (config->alpha_quality < 0 || config->alpha_quality > 100) + return 0; + if (config->lossless < 0 || config->lossless > 1) + return 0; + if (config->image_hint >= WEBP_HINT_LAST) + return 0; + return 1; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/cost.c b/external/libwebp/enc/cost.c new file mode 100644 index 0000000000..92e0cc713c --- /dev/null +++ b/external/libwebp/enc/cost.c @@ -0,0 +1,494 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Cost tables for level and modes +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./cost.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Boolean-cost cost table + +const uint16_t VP8EntropyCost[256] = { + 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216, + 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951, + 939, 911, 896, 878, 871, 854, 838, 820, 811, 794, + 786, 768, 768, 752, 740, 732, 720, 709, 704, 690, + 683, 672, 666, 655, 647, 640, 631, 622, 615, 607, + 598, 592, 586, 576, 572, 564, 559, 555, 547, 541, + 534, 528, 522, 512, 512, 504, 500, 494, 488, 483, + 477, 473, 467, 461, 458, 452, 448, 443, 438, 434, + 427, 424, 419, 415, 410, 406, 403, 399, 394, 390, + 384, 384, 377, 374, 370, 366, 362, 359, 355, 351, + 347, 342, 342, 336, 333, 330, 326, 323, 320, 316, + 312, 308, 305, 302, 299, 296, 293, 288, 287, 283, + 280, 277, 274, 272, 268, 266, 262, 256, 256, 256, + 251, 248, 245, 242, 240, 237, 234, 232, 228, 226, + 223, 221, 218, 216, 214, 211, 208, 205, 203, 201, + 198, 196, 192, 191, 188, 187, 183, 181, 179, 176, + 175, 171, 171, 168, 165, 163, 160, 159, 156, 154, + 152, 150, 148, 146, 144, 142, 139, 138, 135, 133, + 131, 128, 128, 125, 123, 121, 119, 117, 115, 113, + 111, 110, 107, 105, 103, 102, 100, 98, 96, 94, + 92, 91, 89, 86, 86, 83, 82, 80, 77, 76, + 74, 73, 71, 69, 67, 66, 64, 63, 61, 59, + 57, 55, 54, 52, 51, 49, 47, 46, 44, 43, + 41, 40, 38, 36, 35, 33, 32, 30, 29, 27, + 25, 24, 22, 21, 19, 18, 16, 15, 13, 12, + 10, 9, 7, 6, 4, 3 +}; + +//------------------------------------------------------------------------------ +// Level cost tables + +// For each given level, the following table gives the pattern of contexts to +// use for coding it (in [][0]) as well as the bit value to use for each +// context (in [][1]). +const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = { + {0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005}, + {0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023}, + {0x033, 0x023}, {0x033, 0x023}, {0x033, 0x023}, {0x0d3, 0x013}, + {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, + {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, + {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, + {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153} +}; + +// fixed costs for coding levels, deduce from the coding tree. +// This is only the part that doesn't depend on the probability state. +const uint16_t VP8LevelFixedCosts[2048] = { + 0, 256, 256, 256, 256, 432, 618, 630, + 731, 640, 640, 828, 901, 948, 1021, 1101, + 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202, + 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497, + 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358, + 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532, + 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679, + 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853, + 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759, + 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832, + 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910, + 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983, + 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059, + 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132, + 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210, + 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283, + 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200, + 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273, + 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351, + 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424, + 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500, + 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573, + 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651, + 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724, + 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572, + 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645, + 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723, + 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796, + 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872, + 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945, + 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023, + 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096, + 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013, + 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086, + 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164, + 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237, + 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313, + 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386, + 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464, + 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537, + 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848, + 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921, + 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999, + 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072, + 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148, + 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221, + 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299, + 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372, + 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289, + 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362, + 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440, + 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513, + 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589, + 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662, + 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740, + 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813, + 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661, + 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734, + 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812, + 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885, + 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961, + 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034, + 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112, + 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185, + 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102, + 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175, + 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253, + 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326, + 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402, + 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475, + 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553, + 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626, + 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547, + 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, + 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, + 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, + 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, + 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, + 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, + 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, + 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, + 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, + 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, + 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, + 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, + 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, + 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, + 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, + 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, + 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, + 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, + 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, + 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, + 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, + 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, + 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, + 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, + 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, + 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, + 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, + 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, + 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, + 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, + 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, + 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, + 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, + 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, + 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, + 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, + 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, + 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, + 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, + 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, + 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, + 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, + 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, + 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, + 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, + 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, + 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, + 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, + 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, + 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, + 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, + 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, + 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, + 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, + 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, + 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, + 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, + 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, + 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, + 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, + 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, + 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, + 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, + 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547, + 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, + 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, + 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, + 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, + 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, + 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, + 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, + 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, + 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, + 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, + 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, + 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, + 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, + 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, + 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, + 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, + 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, + 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, + 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, + 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, + 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, + 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, + 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, + 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, + 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, + 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, + 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, + 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, + 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, + 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, + 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, + 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, + 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, + 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, + 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, + 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, + 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, + 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, + 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, + 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, + 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, + 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, + 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, + 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, + 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, + 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, + 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, + 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, + 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, + 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, + 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, + 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, + 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, + 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, + 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, + 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, + 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, + 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, + 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, + 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, + 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, + 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, + 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, + 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335, + 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408, + 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486, + 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559, + 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635, + 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708, + 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786, + 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859, + 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776, + 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849, + 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927, + 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000, + 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076, + 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149, + 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227, + 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300, + 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148, + 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221, + 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299, + 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372, + 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448, + 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521, + 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599, + 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672, + 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589, + 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662, + 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740, + 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813, + 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889, + 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962, + 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040, + 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113, + 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424, + 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497, + 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575, + 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648, + 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724, + 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797, + 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875, + 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948, + 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865, + 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938, + 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016, + 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089, + 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165, + 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238, + 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316, + 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389, + 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237, + 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310, + 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388, + 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461, + 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537, + 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610, + 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688, + 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761 +}; + +static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) { + int pattern = VP8LevelCodes[level - 1][0]; + int bits = VP8LevelCodes[level - 1][1]; + int cost = 0; + int i; + for (i = 2; pattern; ++i) { + if (pattern & 1) { + cost += VP8BitCost(bits & 1, probas[i]); + } + bits >>= 1; + pattern >>= 1; + } + return cost; +} + +//------------------------------------------------------------------------------ +// Pre-calc level costs once for all + +void VP8CalculateLevelCosts(VP8Proba* const proba) { + int ctype, band, ctx; + + if (!proba->dirty_) return; // nothing to do. + + for (ctype = 0; ctype < NUM_TYPES; ++ctype) { + for (band = 0; band < NUM_BANDS; ++band) { + for(ctx = 0; ctx < NUM_CTX; ++ctx) { + const uint8_t* const p = proba->coeffs_[ctype][band][ctx]; + uint16_t* const table = proba->level_cost_[ctype][band][ctx]; + const int cost_base = VP8BitCost(1, p[1]); + int v; + table[0] = VP8BitCost(0, p[1]); + for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) { + table[v] = cost_base + VariableLevelCost(v, p); + } + // Starting at level 67 and up, the variable part of the cost is + // actually constant. + } + } + } + proba->dirty_ = 0; +} + +//------------------------------------------------------------------------------ +// Mode cost tables. + +// These are the fixed probabilities (in the coding trees) turned into bit-cost +// by calling VP8BitCost(). +const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 }; +// note: these values include the fixed VP8BitCost(1, 145) mode selection cost. +const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 }; +const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = { + { { 251, 1362, 1934, 2085, 2314, 2230, 1839, 1988, 2437, 2348 }, + { 403, 680, 1507, 1519, 2060, 2005, 1992, 1914, 1924, 1733 }, + { 353, 1121, 973, 1895, 2060, 1787, 1671, 1516, 2012, 1868 }, + { 770, 852, 1581, 632, 1393, 1780, 1823, 1936, 1074, 1218 }, + { 510, 1270, 1467, 1319, 847, 1279, 1792, 2094, 1080, 1353 }, + { 488, 1322, 918, 1573, 1300, 883, 1814, 1752, 1756, 1502 }, + { 425, 992, 1820, 1514, 1843, 2440, 937, 1771, 1924, 1129 }, + { 363, 1248, 1257, 1970, 2194, 2385, 1569, 953, 1951, 1601 }, + { 723, 1257, 1631, 964, 963, 1508, 1697, 1824, 671, 1418 }, + { 635, 1038, 1573, 930, 1673, 1413, 1410, 1687, 1410, 749 } }, + { { 451, 613, 1345, 1702, 1870, 1716, 1728, 1766, 2190, 2310 }, + { 678, 453, 1171, 1443, 1925, 1831, 2045, 1781, 1887, 1602 }, + { 711, 666, 674, 1718, 1910, 1493, 1775, 1193, 2325, 2325 }, + { 883, 854, 1583, 542, 1800, 1878, 1664, 2149, 1207, 1087 }, + { 669, 994, 1248, 1122, 949, 1179, 1376, 1729, 1070, 1244 }, + { 715, 1026, 715, 1350, 1430, 930, 1717, 1296, 1479, 1479 }, + { 544, 841, 1656, 1450, 2094, 3883, 1010, 1759, 2076, 809 }, + { 610, 855, 957, 1553, 2067, 1561, 1704, 824, 2066, 1226 }, + { 833, 960, 1416, 819, 1277, 1619, 1501, 1617, 757, 1182 }, + { 711, 964, 1252, 879, 1441, 1828, 1508, 1636, 1594, 734 } }, + { { 605, 764, 734, 1713, 1747, 1192, 1819, 1353, 1877, 2392 }, + { 866, 641, 586, 1622, 2072, 1431, 1888, 1346, 2189, 1764 }, + { 901, 851, 456, 2165, 2281, 1405, 1739, 1193, 2183, 2443 }, + { 770, 1045, 952, 1078, 1342, 1191, 1436, 1063, 1303, 995 }, + { 901, 1086, 727, 1170, 884, 1105, 1267, 1401, 1739, 1337 }, + { 951, 1162, 595, 1488, 1388, 703, 1790, 1366, 2057, 1724 }, + { 534, 986, 1273, 1987, 3273, 1485, 1024, 1399, 1583, 866 }, + { 699, 1182, 695, 1978, 1726, 1986, 1326, 714, 1750, 1672 }, + { 951, 1217, 1209, 920, 1062, 1441, 1548, 999, 952, 932 }, + { 733, 1284, 784, 1256, 1557, 1098, 1257, 1357, 1414, 908 } }, + { { 316, 1075, 1653, 1220, 2145, 2051, 1730, 2131, 1884, 1790 }, + { 745, 516, 1404, 894, 1599, 2375, 2013, 2105, 1475, 1381 }, + { 516, 729, 1088, 1319, 1637, 3426, 1636, 1275, 1531, 1453 }, + { 894, 943, 2138, 468, 1704, 2259, 2069, 1763, 1266, 1158 }, + { 605, 1025, 1235, 871, 1170, 1767, 1493, 1500, 1104, 1258 }, + { 739, 826, 1207, 1151, 1412, 846, 1305, 2726, 1014, 1569 }, + { 558, 825, 1820, 1398, 3344, 1556, 1218, 1550, 1228, 878 }, + { 429, 951, 1089, 1816, 3861, 3861, 1556, 969, 1568, 1828 }, + { 883, 961, 1752, 769, 1468, 1810, 2081, 2346, 613, 1298 }, + { 803, 895, 1372, 641, 1303, 1708, 1686, 1700, 1306, 1033 } }, + { { 439, 1267, 1270, 1579, 963, 1193, 1723, 1729, 1198, 1993 }, + { 705, 725, 1029, 1153, 1176, 1103, 1821, 1567, 1259, 1574 }, + { 723, 859, 802, 1253, 972, 1202, 1407, 1665, 1520, 1674 }, + { 894, 960, 1254, 887, 1052, 1607, 1344, 1349, 865, 1150 }, + { 833, 1312, 1337, 1205, 572, 1288, 1414, 1529, 1088, 1430 }, + { 842, 1279, 1068, 1861, 862, 688, 1861, 1630, 1039, 1381 }, + { 766, 938, 1279, 1546, 3338, 1550, 1031, 1542, 1288, 640 }, + { 715, 1090, 835, 1609, 1100, 1100, 1603, 1019, 1102, 1617 }, + { 894, 1813, 1500, 1188, 789, 1194, 1491, 1919, 617, 1333 }, + { 610, 1076, 1644, 1281, 1283, 975, 1179, 1688, 1434, 889 } }, + { { 544, 971, 1146, 1849, 1221, 740, 1857, 1621, 1683, 2430 }, + { 723, 705, 961, 1371, 1426, 821, 2081, 2079, 1839, 1380 }, + { 783, 857, 703, 2145, 1419, 814, 1791, 1310, 1609, 2206 }, + { 997, 1000, 1153, 792, 1229, 1162, 1810, 1418, 942, 979 }, + { 901, 1226, 883, 1289, 793, 715, 1904, 1649, 1319, 3108 }, + { 979, 1478, 782, 2216, 1454, 455, 3092, 1591, 1997, 1664 }, + { 663, 1110, 1504, 1114, 1522, 3311, 676, 1522, 1530, 1024 }, + { 605, 1138, 1153, 1314, 1569, 1315, 1157, 804, 1574, 1320 }, + { 770, 1216, 1218, 1227, 869, 1384, 1232, 1375, 834, 1239 }, + { 775, 1007, 843, 1216, 1225, 1074, 2527, 1479, 1149, 975 } }, + { { 477, 817, 1309, 1439, 1708, 1454, 1159, 1241, 1945, 1672 }, + { 577, 796, 1112, 1271, 1618, 1458, 1087, 1345, 1831, 1265 }, + { 663, 776, 753, 1940, 1690, 1690, 1227, 1097, 3149, 1361 }, + { 766, 1299, 1744, 1161, 1565, 1106, 1045, 1230, 1232, 707 }, + { 915, 1026, 1404, 1182, 1184, 851, 1428, 2425, 1043, 789 }, + { 883, 1456, 790, 1082, 1086, 985, 1083, 1484, 1238, 1160 }, + { 507, 1345, 2261, 1995, 1847, 3636, 653, 1761, 2287, 933 }, + { 553, 1193, 1470, 2057, 2059, 2059, 833, 779, 2058, 1263 }, + { 766, 1275, 1515, 1039, 957, 1554, 1286, 1540, 1289, 705 }, + { 499, 1378, 1496, 1385, 1850, 1850, 1044, 2465, 1515, 720 } }, + { { 553, 930, 978, 2077, 1968, 1481, 1457, 761, 1957, 2362 }, + { 694, 864, 905, 1720, 1670, 1621, 1429, 718, 2125, 1477 }, + { 699, 968, 658, 3190, 2024, 1479, 1865, 750, 2060, 2320 }, + { 733, 1308, 1296, 1062, 1576, 1322, 1062, 1112, 1172, 816 }, + { 920, 927, 1052, 939, 947, 1156, 1152, 1073, 3056, 1268 }, + { 723, 1534, 711, 1547, 1294, 892, 1553, 928, 1815, 1561 }, + { 663, 1366, 1583, 2111, 1712, 3501, 522, 1155, 2130, 1133 }, + { 614, 1731, 1188, 2343, 1944, 3733, 1287, 487, 3546, 1758 }, + { 770, 1585, 1312, 826, 884, 2673, 1185, 1006, 1195, 1195 }, + { 758, 1333, 1273, 1023, 1621, 1162, 1351, 833, 1479, 862 } }, + { { 376, 1193, 1446, 1149, 1545, 1577, 1870, 1789, 1175, 1823 }, + { 803, 633, 1136, 1058, 1350, 1323, 1598, 2247, 1072, 1252 }, + { 614, 1048, 943, 981, 1152, 1869, 1461, 1020, 1618, 1618 }, + { 1107, 1085, 1282, 592, 1779, 1933, 1648, 2403, 691, 1246 }, + { 851, 1309, 1223, 1243, 895, 1593, 1792, 2317, 627, 1076 }, + { 770, 1216, 1030, 1125, 921, 981, 1629, 1131, 1049, 1646 }, + { 626, 1469, 1456, 1081, 1489, 3278, 981, 1232, 1498, 733 }, + { 617, 1201, 812, 1220, 1476, 1476, 1478, 970, 1228, 1488 }, + { 1179, 1393, 1540, 999, 1243, 1503, 1916, 1925, 414, 1614 }, + { 943, 1088, 1490, 682, 1112, 1372, 1756, 1505, 966, 966 } }, + { { 322, 1142, 1589, 1396, 2144, 1859, 1359, 1925, 2084, 1518 }, + { 617, 625, 1241, 1234, 2121, 1615, 1524, 1858, 1720, 1004 }, + { 553, 851, 786, 1299, 1452, 1560, 1372, 1561, 1967, 1713 }, + { 770, 977, 1396, 568, 1893, 1639, 1540, 2108, 1430, 1013 }, + { 684, 1120, 1375, 982, 930, 2719, 1638, 1643, 933, 993 }, + { 553, 1103, 996, 1356, 1361, 1005, 1507, 1761, 1184, 1268 }, + { 419, 1247, 1537, 1554, 1817, 3606, 1026, 1666, 1829, 923 }, + { 439, 1139, 1101, 1257, 3710, 1922, 1205, 1040, 1931, 1529 }, + { 979, 935, 1269, 847, 1202, 1286, 1530, 1535, 827, 1036 }, + { 516, 1378, 1569, 1110, 1798, 1798, 1198, 2199, 1543, 712 } }, +}; + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/cost.h b/external/libwebp/enc/cost.h new file mode 100644 index 0000000000..09b75b699d --- /dev/null +++ b/external/libwebp/enc/cost.h @@ -0,0 +1,48 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Cost tables for level and modes. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_ENC_COST_H_ +#define WEBP_ENC_COST_H_ + +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level +extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p) + +// Cost of coding one event with probability 'proba'. +static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) { + return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba]; +} + +// Level cost calculations +extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2]; +void VP8CalculateLevelCosts(VP8Proba* const proba); +static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) { + return VP8LevelFixedCosts[level] + + table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level]; +} + +// Mode costs +extern const uint16_t VP8FixedCostsUV[4]; +extern const uint16_t VP8FixedCostsI16[4]; +extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES]; + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_ENC_COST_H_ */ diff --git a/external/libwebp/enc/filter.c b/external/libwebp/enc/filter.c new file mode 100644 index 0000000000..7fb78a3949 --- /dev/null +++ b/external/libwebp/enc/filter.c @@ -0,0 +1,409 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Selecting filter level +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// NOTE: clip1, tables and InitTables are repeated entries of dsp.c +static uint8_t abs0[255 + 255 + 1]; // abs(i) +static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1 +static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127] +static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15] +static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255] + +static int tables_ok = 0; + +static void InitTables(void) { + if (!tables_ok) { + int i; + for (i = -255; i <= 255; ++i) { + abs0[255 + i] = (i < 0) ? -i : i; + abs1[255 + i] = abs0[255 + i] >> 1; + } + for (i = -1020; i <= 1020; ++i) { + sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i; + } + for (i = -112; i <= 112; ++i) { + sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i; + } + for (i = -255; i <= 255 + 255; ++i) { + clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i; + } + tables_ok = 1; + } +} + +//------------------------------------------------------------------------------ +// Edge filtering functions + +// 4 pixels in, 2 pixels out +static WEBP_INLINE void do_filter2(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1]; + const int a1 = sclip2[112 + ((a + 4) >> 3)]; + const int a2 = sclip2[112 + ((a + 3) >> 3)]; + p[-step] = clip1[255 + p0 + a2]; + p[ 0] = clip1[255 + q0 - a1]; +} + +// 4 pixels in, 4 pixels out +static WEBP_INLINE void do_filter4(uint8_t* p, int step) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + const int a = 3 * (q0 - p0); + const int a1 = sclip2[112 + ((a + 4) >> 3)]; + const int a2 = sclip2[112 + ((a + 3) >> 3)]; + const int a3 = (a1 + 1) >> 1; + p[-2*step] = clip1[255 + p1 + a3]; + p[- step] = clip1[255 + p0 + a2]; + p[ 0] = clip1[255 + q0 - a1]; + p[ step] = clip1[255 + q1 - a3]; +} + +// high edge-variance +static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh); +} + +static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) { + const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step]; + return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh; +} + +static WEBP_INLINE int needs_filter2(const uint8_t* p, + int step, int t, int it) { + const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step]; + const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step]; + if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t) + return 0; + return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it && + abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it && + abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it; +} + +//------------------------------------------------------------------------------ +// Simple In-loop filtering (Paragraph 15.2) + +static void SimpleVFilter16(uint8_t* p, int stride, int thresh) { + int i; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i, stride, thresh)) { + do_filter2(p + i, stride); + } + } +} + +static void SimpleHFilter16(uint8_t* p, int stride, int thresh) { + int i; + for (i = 0; i < 16; ++i) { + if (needs_filter(p + i * stride, 1, thresh)) { + do_filter2(p + i * stride, 1); + } + } +} + +static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + SimpleVFilter16(p, stride, thresh); + } +} + +static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + SimpleHFilter16(p, stride, thresh); + } +} + +//------------------------------------------------------------------------------ +// Complex In-loop filtering (Paragraph 15.3) + +static WEBP_INLINE void FilterLoop24(uint8_t* p, + int hstride, int vstride, int size, + int thresh, int ithresh, int hev_thresh) { + while (size-- > 0) { + if (needs_filter2(p, hstride, thresh, ithresh)) { + if (hev(p, hstride, hev_thresh)) { + do_filter2(p, hstride); + } else { + do_filter4(p, hstride); + } + } + p += vstride; + } +} + +// on three inner edges +static void VFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4 * stride; + FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh); + } +} + +static void HFilter16i(uint8_t* p, int stride, + int thresh, int ithresh, int hev_thresh) { + int k; + for (k = 3; k > 0; --k) { + p += 4; + FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh); + } +} + +static void VFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); +} + +static void HFilter8i(uint8_t* u, uint8_t* v, int stride, + int thresh, int ithresh, int hev_thresh) { + FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); + FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); +} + +//------------------------------------------------------------------------------ + +void (*VP8EncVFilter16i)(uint8_t*, int, int, int, int) = VFilter16i; +void (*VP8EncHFilter16i)(uint8_t*, int, int, int, int) = HFilter16i; +void (*VP8EncVFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = VFilter8i; +void (*VP8EncHFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = HFilter8i; + +void (*VP8EncSimpleVFilter16i)(uint8_t*, int, int) = SimpleVFilter16i; +void (*VP8EncSimpleHFilter16i)(uint8_t*, int, int) = SimpleHFilter16i; + +//------------------------------------------------------------------------------ +// Paragraph 15.4: compute the inner-edge filtering strength + +static int GetILevel(int sharpness, int level) { + if (sharpness > 0) { + if (sharpness > 4) { + level >>= 2; + } else { + level >>= 1; + } + if (level > 9 - sharpness) { + level = 9 - sharpness; + } + } + if (level < 1) level = 1; + return level; +} + +static void DoFilter(const VP8EncIterator* const it, int level) { + const VP8Encoder* const enc = it->enc_; + const int ilevel = GetILevel(enc->config_->filter_sharpness, level); + const int limit = 2 * level + ilevel; + + uint8_t* const y_dst = it->yuv_out2_ + Y_OFF; + uint8_t* const u_dst = it->yuv_out2_ + U_OFF; + uint8_t* const v_dst = it->yuv_out2_ + V_OFF; + + // copy current block to yuv_out2_ + memcpy(y_dst, it->yuv_out_, YUV_SIZE * sizeof(uint8_t)); + + if (enc->filter_hdr_.simple_ == 1) { // simple + VP8EncSimpleHFilter16i(y_dst, BPS, limit); + VP8EncSimpleVFilter16i(y_dst, BPS, limit); + } else { // complex + const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + VP8EncHFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); + VP8EncHFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); + VP8EncVFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); + VP8EncVFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); + } +} + +//------------------------------------------------------------------------------ +// SSIM metric + +enum { KERNEL = 3 }; +static const double kMinValue = 1.e-10; // minimal threshold + +void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst) { + dst->w += src->w; + dst->xm += src->xm; + dst->ym += src->ym; + dst->xxm += src->xxm; + dst->xym += src->xym; + dst->yym += src->yym; +} + +static void VP8SSIMAccumulate(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int xo, int yo, int W, int H, + DistoStats* const stats) { + const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL; + const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL; + const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL; + const int xmax = (xo + KERNEL > W - 1) ? W - 1 : xo + KERNEL; + int x, y; + src1 += ymin * stride1; + src2 += ymin * stride2; + for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) { + for (x = xmin; x <= xmax; ++x) { + const int s1 = src1[x]; + const int s2 = src2[x]; + stats->w += 1; + stats->xm += s1; + stats->ym += s2; + stats->xxm += s1 * s1; + stats->xym += s1 * s2; + stats->yym += s2 * s2; + } + } +} + +double VP8SSIMGet(const DistoStats* const stats) { + const double xmxm = stats->xm * stats->xm; + const double ymym = stats->ym * stats->ym; + const double xmym = stats->xm * stats->ym; + const double w2 = stats->w * stats->w; + double sxx = stats->xxm * stats->w - xmxm; + double syy = stats->yym * stats->w - ymym; + double sxy = stats->xym * stats->w - xmym; + double C1, C2; + double fnum; + double fden; + // small errors are possible, due to rounding. Clamp to zero. + if (sxx < 0.) sxx = 0.; + if (syy < 0.) syy = 0.; + C1 = 6.5025 * w2; + C2 = 58.5225 * w2; + fnum = (2 * xmym + C1) * (2 * sxy + C2); + fden = (xmxm + ymym + C1) * (sxx + syy + C2); + return (fden != 0.) ? fnum / fden : kMinValue; +} + +double VP8SSIMGetSquaredError(const DistoStats* const s) { + if (s->w > 0.) { + const double iw2 = 1. / (s->w * s->w); + const double sxx = s->xxm * s->w - s->xm * s->xm; + const double syy = s->yym * s->w - s->ym * s->ym; + const double sxy = s->xym * s->w - s->xm * s->ym; + const double SSE = iw2 * (sxx + syy - 2. * sxy); + if (SSE > kMinValue) return SSE; + } + return kMinValue; +} + +void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int W, int H, DistoStats* const stats) { + int x, y; + for (y = 0; y < H; ++y) { + for (x = 0; x < W; ++x) { + VP8SSIMAccumulate(src1, stride1, src2, stride2, x, y, W, H, stats); + } + } +} + +static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) { + int x, y; + DistoStats s = { .0, .0, .0, .0, .0, .0 }; + + // compute SSIM in a 10 x 10 window + for (x = 3; x < 13; x++) { + for (y = 3; y < 13; y++) { + VP8SSIMAccumulate(yuv1 + Y_OFF, BPS, yuv2 + Y_OFF, BPS, x, y, 16, 16, &s); + } + } + for (x = 1; x < 7; x++) { + for (y = 1; y < 7; y++) { + VP8SSIMAccumulate(yuv1 + U_OFF, BPS, yuv2 + U_OFF, BPS, x, y, 8, 8, &s); + VP8SSIMAccumulate(yuv1 + V_OFF, BPS, yuv2 + V_OFF, BPS, x, y, 8, 8, &s); + } + } + return VP8SSIMGet(&s); +} + +//------------------------------------------------------------------------------ +// Exposed APIs: Encoder should call the following 3 functions to adjust +// loop filter strength + +void VP8InitFilter(VP8EncIterator* const it) { + int s, i; + if (!it->lf_stats_) return; + + InitTables(); + for (s = 0; s < NUM_MB_SEGMENTS; s++) { + for (i = 0; i < MAX_LF_LEVELS; i++) { + (*it->lf_stats_)[s][i] = 0; + } + } +} + +void VP8StoreFilterStats(VP8EncIterator* const it) { + int d; + const int s = it->mb_->segment_; + const int level0 = it->enc_->dqm_[s].fstrength_; // TODO: ref_lf_delta[] + + // explore +/-quant range of values around level0 + const int delta_min = -it->enc_->dqm_[s].quant_; + const int delta_max = it->enc_->dqm_[s].quant_; + const int step_size = (delta_max - delta_min >= 4) ? 4 : 1; + + if (!it->lf_stats_) return; + + // NOTE: Currently we are applying filter only across the sublock edges + // There are two reasons for that. + // 1. Applying filter on macro block edges will change the pixels in + // the left and top macro blocks. That will be hard to restore + // 2. Macro Blocks on the bottom and right are not yet compressed. So we + // cannot apply filter on the right and bottom macro block edges. + if (it->mb_->type_ == 1 && it->mb_->skip_) return; + + // Always try filter level zero + (*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_); + + for (d = delta_min; d <= delta_max; d += step_size) { + const int level = level0 + d; + if (level <= 0 || level >= MAX_LF_LEVELS) { + continue; + } + DoFilter(it, level); + (*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_); + } +} + +void VP8AdjustFilterStrength(VP8EncIterator* const it) { + int s; + VP8Encoder* const enc = it->enc_; + + if (!it->lf_stats_) { + return; + } + for (s = 0; s < NUM_MB_SEGMENTS; s++) { + int i, best_level = 0; + // Improvement over filter level 0 should be at least 1e-5 (relatively) + double best_v = 1.00001 * (*it->lf_stats_)[s][0]; + for (i = 1; i < MAX_LF_LEVELS; i++) { + const double v = (*it->lf_stats_)[s][i]; + if (v > best_v) { + best_v = v; + best_level = i; + } + } + enc->dqm_[s].fstrength_ = best_level; + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/frame.c b/external/libwebp/enc/frame.c new file mode 100644 index 0000000000..bdd360069b --- /dev/null +++ b/external/libwebp/enc/frame.c @@ -0,0 +1,939 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// frame coding and analysis +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include +#include + +#include "./vp8enci.h" +#include "./cost.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define SEGMENT_VISU 0 +#define DEBUG_SEARCH 0 // useful to track search convergence + +// On-the-fly info about the current set of residuals. Handy to avoid +// passing zillions of params. +typedef struct { + int first; + int last; + const int16_t* coeffs; + + int coeff_type; + ProbaArray* prob; + StatsArray* stats; + CostArray* cost; +} VP8Residual; + +//------------------------------------------------------------------------------ +// Tables for level coding + +const uint8_t VP8EncBands[16 + 1] = { + 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, + 0 // sentinel +}; + +static const uint8_t kCat3[] = { 173, 148, 140 }; +static const uint8_t kCat4[] = { 176, 155, 140, 135 }; +static const uint8_t kCat5[] = { 180, 157, 141, 134, 130 }; +static const uint8_t kCat6[] = + { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; + +//------------------------------------------------------------------------------ +// Reset the statistics about: number of skips, token proba, level cost,... + +static void ResetStats(VP8Encoder* const enc) { + VP8Proba* const proba = &enc->proba_; + VP8CalculateLevelCosts(proba); + proba->nb_skip_ = 0; +} + +//------------------------------------------------------------------------------ +// Skip decision probability + +#define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. + +static int CalcSkipProba(uint64_t nb, uint64_t total) { + return (int)(total ? (total - nb) * 255 / total : 255); +} + +// Returns the bit-cost for coding the skip probability. +static int FinalizeSkipProba(VP8Encoder* const enc) { + VP8Proba* const proba = &enc->proba_; + const int nb_mbs = enc->mb_w_ * enc->mb_h_; + const int nb_events = proba->nb_skip_; + int size; + proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); + proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); + size = 256; // 'use_skip_proba' bit + if (proba->use_skip_proba_) { + size += nb_events * VP8BitCost(1, proba->skip_proba_) + + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); + size += 8 * 256; // cost of signaling the skip_proba_ itself. + } + return size; +} + +//------------------------------------------------------------------------------ +// Recording of token probabilities. + +static void ResetTokenStats(VP8Encoder* const enc) { + VP8Proba* const proba = &enc->proba_; + memset(proba->stats_, 0, sizeof(proba->stats_)); +} + +// Record proba context used +static int Record(int bit, proba_t* const stats) { + proba_t p = *stats; + if (p >= 0xffff0000u) { // an overflow is inbound. + p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2. + } + // record bit count (lower 16 bits) and increment total count (upper 16 bits). + p += 0x00010000u + bit; + *stats = p; + return bit; +} + +// We keep the table free variant around for reference, in case. +#define USE_LEVEL_CODE_TABLE + +// Simulate block coding, but only record statistics. +// Note: no need to record the fixed probas. +static int RecordCoeffs(int ctx, const VP8Residual* const res) { + int n = res->first; + proba_t* s = res->stats[VP8EncBands[n]][ctx]; + if (res->last < 0) { + Record(0, s + 0); + return 0; + } + while (n <= res->last) { + int v; + Record(1, s + 0); + while ((v = res->coeffs[n++]) == 0) { + Record(0, s + 1); + s = res->stats[VP8EncBands[n]][0]; + } + Record(1, s + 1); + if (!Record(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1 + s = res->stats[VP8EncBands[n]][1]; + } else { + v = abs(v); +#if !defined(USE_LEVEL_CODE_TABLE) + if (!Record(v > 4, s + 3)) { + if (Record(v != 2, s + 4)) + Record(v == 4, s + 5); + } else if (!Record(v > 10, s + 6)) { + Record(v > 6, s + 7); + } else if (!Record((v >= 3 + (8 << 2)), s + 8)) { + Record((v >= 3 + (8 << 1)), s + 9); + } else { + Record((v >= 3 + (8 << 3)), s + 10); + } +#else + if (v > MAX_VARIABLE_LEVEL) + v = MAX_VARIABLE_LEVEL; + + { + const int bits = VP8LevelCodes[v - 1][1]; + int pattern = VP8LevelCodes[v - 1][0]; + int i; + for (i = 0; (pattern >>= 1) != 0; ++i) { + const int mask = 2 << i; + if (pattern & 1) Record(!!(bits & mask), s + 3 + i); + } + } +#endif + s = res->stats[VP8EncBands[n]][2]; + } + } + if (n < 16) Record(0, s + 0); + return 1; +} + +// Collect statistics and deduce probabilities for next coding pass. +// Return the total bit-cost for coding the probability updates. +static int CalcTokenProba(int nb, int total) { + assert(nb <= total); + return nb ? (255 - nb * 255 / total) : 255; +} + +// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability. +static int BranchCost(int nb, int total, int proba) { + return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); +} + +static int FinalizeTokenProbas(VP8Encoder* const enc) { + VP8Proba* const proba = &enc->proba_; + int has_changed = 0; + int size = 0; + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + const proba_t stats = proba->stats_[t][b][c][p]; + const int nb = (stats >> 0) & 0xffff; + const int total = (stats >> 16) & 0xffff; + const int update_proba = VP8CoeffsUpdateProba[t][b][c][p]; + const int old_p = VP8CoeffsProba0[t][b][c][p]; + const int new_p = CalcTokenProba(nb, total); + const int old_cost = BranchCost(nb, total, old_p) + + VP8BitCost(0, update_proba); + const int new_cost = BranchCost(nb, total, new_p) + + VP8BitCost(1, update_proba) + + 8 * 256; + const int use_new_p = (old_cost > new_cost); + size += VP8BitCost(use_new_p, update_proba); + if (use_new_p) { // only use proba that seem meaningful enough. + proba->coeffs_[t][b][c][p] = new_p; + has_changed |= (new_p != old_p); + size += 8 * 256; + } else { + proba->coeffs_[t][b][c][p] = old_p; + } + } + } + } + } + proba->dirty_ = has_changed; + return size; +} + +//------------------------------------------------------------------------------ +// helper functions for residuals struct VP8Residual. + +static void InitResidual(int first, int coeff_type, + VP8Encoder* const enc, VP8Residual* const res) { + res->coeff_type = coeff_type; + res->prob = enc->proba_.coeffs_[coeff_type]; + res->stats = enc->proba_.stats_[coeff_type]; + res->cost = enc->proba_.level_cost_[coeff_type]; + res->first = first; +} + +static void SetResidualCoeffs(const int16_t* const coeffs, + VP8Residual* const res) { + int n; + res->last = -1; + for (n = 15; n >= res->first; --n) { + if (coeffs[n]) { + res->last = n; + break; + } + } + res->coeffs = coeffs; +} + +//------------------------------------------------------------------------------ +// Mode costs + +static int GetResidualCost(int ctx, const VP8Residual* const res) { + int n = res->first; + int p0 = res->prob[VP8EncBands[n]][ctx][0]; + const uint16_t* t = res->cost[VP8EncBands[n]][ctx]; + int cost; + + if (res->last < 0) { + return VP8BitCost(0, p0); + } + cost = 0; + while (n <= res->last) { + const int v = res->coeffs[n]; + const int b = VP8EncBands[n + 1]; + ++n; + if (v == 0) { + // short-case for VP8LevelCost(t, 0) (note: VP8LevelFixedCosts[0] == 0): + cost += t[0]; + t = res->cost[b][0]; + continue; + } + cost += VP8BitCost(1, p0); + if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1 + // short-case for "VP8LevelCost(t, 1)" (256 is VP8LevelFixedCosts[1]): + cost += 256 + t[1]; + p0 = res->prob[b][1][0]; + t = res->cost[b][1]; + } else { + cost += VP8LevelCost(t, abs(v)); + p0 = res->prob[b][2][0]; + t = res->cost[b][2]; + } + } + if (n < 16) cost += VP8BitCost(0, p0); + return cost; +} + +int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { + const int x = (it->i4_ & 3), y = (it->i4_ >> 2); + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int R = 0; + int ctx; + + InitResidual(0, 3, enc, &res); + ctx = it->top_nz_[x] + it->left_nz_[y]; + SetResidualCoeffs(levels, &res); + R += GetResidualCost(ctx, &res); + return R; +} + +int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int x, y; + int R = 0; + + VP8IteratorNzToBytes(it); // re-import the non-zero context + + // DC + InitResidual(0, 1, enc, &res); + SetResidualCoeffs(rd->y_dc_levels, &res); + R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); + + // AC + InitResidual(1, 0, enc, &res); + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + R += GetResidualCost(ctx, &res); + it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); + } + } + return R; +} + +int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { + VP8Residual res; + VP8Encoder* const enc = it->enc_; + int ch, x, y; + int R = 0; + + VP8IteratorNzToBytes(it); // re-import the non-zero context + + InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + R += GetResidualCost(ctx, &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); + } + } + } + return R; +} + +//------------------------------------------------------------------------------ +// Coefficient coding + +static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) { + int n = res->first; + const uint8_t* p = res->prob[VP8EncBands[n]][ctx]; + if (!VP8PutBit(bw, res->last >= 0, p[0])) { + return 0; + } + + while (n < 16) { + const int c = res->coeffs[n++]; + const int sign = c < 0; + int v = sign ? -c : c; + if (!VP8PutBit(bw, v != 0, p[1])) { + p = res->prob[VP8EncBands[n]][0]; + continue; + } + if (!VP8PutBit(bw, v > 1, p[2])) { + p = res->prob[VP8EncBands[n]][1]; + } else { + if (!VP8PutBit(bw, v > 4, p[3])) { + if (VP8PutBit(bw, v != 2, p[4])) + VP8PutBit(bw, v == 4, p[5]); + } else if (!VP8PutBit(bw, v > 10, p[6])) { + if (!VP8PutBit(bw, v > 6, p[7])) { + VP8PutBit(bw, v == 6, 159); + } else { + VP8PutBit(bw, v >= 9, 165); + VP8PutBit(bw, !(v & 1), 145); + } + } else { + int mask; + const uint8_t* tab; + if (v < 3 + (8 << 1)) { // kCat3 (3b) + VP8PutBit(bw, 0, p[8]); + VP8PutBit(bw, 0, p[9]); + v -= 3 + (8 << 0); + mask = 1 << 2; + tab = kCat3; + } else if (v < 3 + (8 << 2)) { // kCat4 (4b) + VP8PutBit(bw, 0, p[8]); + VP8PutBit(bw, 1, p[9]); + v -= 3 + (8 << 1); + mask = 1 << 3; + tab = kCat4; + } else if (v < 3 + (8 << 3)) { // kCat5 (5b) + VP8PutBit(bw, 1, p[8]); + VP8PutBit(bw, 0, p[10]); + v -= 3 + (8 << 2); + mask = 1 << 4; + tab = kCat5; + } else { // kCat6 (11b) + VP8PutBit(bw, 1, p[8]); + VP8PutBit(bw, 1, p[10]); + v -= 3 + (8 << 3); + mask = 1 << 10; + tab = kCat6; + } + while (mask) { + VP8PutBit(bw, !!(v & mask), *tab++); + mask >>= 1; + } + } + p = res->prob[VP8EncBands[n]][2]; + } + VP8PutBitUniform(bw, sign); + if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) { + return 1; // EOB + } + } + return 1; +} + +static void CodeResiduals(VP8BitWriter* const bw, + VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int x, y, ch; + VP8Residual res; + uint64_t pos1, pos2, pos3; + const int i16 = (it->mb_->type_ == 1); + const int segment = it->mb_->segment_; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + + pos1 = VP8BitWriterPos(bw); + if (i16) { + InitResidual(0, 1, enc, &res); + SetResidualCoeffs(rd->y_dc_levels, &res); + it->top_nz_[8] = it->left_nz_[8] = + PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); + InitResidual(1, 0, enc, &res); + } else { + InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); + } + } + pos2 = VP8BitWriterPos(bw); + + // U/V + InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + PutCoeffs(bw, ctx, &res); + } + } + } + pos3 = VP8BitWriterPos(bw); + it->luma_bits_ = pos2 - pos1; + it->uv_bits_ = pos3 - pos2; + it->bit_count_[segment][i16] += it->luma_bits_; + it->bit_count_[segment][2] += it->uv_bits_; + VP8IteratorBytesToNz(it); +} + +// Same as CodeResiduals, but doesn't actually write anything. +// Instead, it just records the event distribution. +static void RecordResiduals(VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int x, y, ch; + VP8Residual res; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + + if (it->mb_->type_ == 1) { // i16x16 + InitResidual(0, 1, enc, &res); + SetResidualCoeffs(rd->y_dc_levels, &res); + it->top_nz_[8] = it->left_nz_[8] = + RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); + InitResidual(1, 0, enc, &res); + } else { + InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res); + } + } + + // U/V + InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + RecordCoeffs(ctx, &res); + } + } + } + + VP8IteratorBytesToNz(it); +} + +//------------------------------------------------------------------------------ +// Token buffer + +#ifdef USE_TOKEN_BUFFER + +void VP8TBufferInit(VP8TBuffer* const b) { + b->rows_ = NULL; + b->tokens_ = NULL; + b->last_ = &b->rows_; + b->left_ = 0; + b->error_ = 0; +} + +int VP8TBufferNewPage(VP8TBuffer* const b) { + VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page)); + if (page == NULL) { + b->error_ = 1; + return 0; + } + *b->last_ = page; + b->last_ = &page->next_; + b->left_ = MAX_NUM_TOKEN; + b->tokens_ = page->tokens_; + return 1; +} + +void VP8TBufferClear(VP8TBuffer* const b) { + if (b != NULL) { + const VP8Tokens* p = b->rows_; + while (p != NULL) { + const VP8Tokens* const next = p->next_; + free((void*)p); + p = next; + } + VP8TBufferInit(b); + } +} + +int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw, + const uint8_t* const probas) { + VP8Tokens* p = b->rows_; + if (b->error_) return 0; + while (p != NULL) { + const int N = (p->next_ == NULL) ? b->left_ : 0; + int n = MAX_NUM_TOKEN; + while (n-- > N) { + VP8PutBit(bw, (p->tokens_[n] >> 15) & 1, probas[p->tokens_[n] & 0x7fff]); + } + p = p->next_; + } + return 1; +} + +#define TOKEN_ID(b, ctx, p) ((p) + NUM_PROBAS * ((ctx) + (b) * NUM_CTX)) + +static int RecordCoeffTokens(int ctx, const VP8Residual* const res, + VP8TBuffer* tokens) { + int n = res->first; + int b = VP8EncBands[n]; + if (!VP8AddToken(tokens, res->last >= 0, TOKEN_ID(b, ctx, 0))) { + return 0; + } + + while (n < 16) { + const int c = res->coeffs[n++]; + const int sign = c < 0; + int v = sign ? -c : c; + const int base_id = TOKEN_ID(b, ctx, 0); + if (!VP8AddToken(tokens, v != 0, base_id + 1)) { + b = VP8EncBands[n]; + ctx = 0; + continue; + } + if (!VP8AddToken(tokens, v > 1, base_id + 2)) { + b = VP8EncBands[n]; + ctx = 1; + } else { + if (!VP8AddToken(tokens, v > 4, base_id + 3)) { + if (VP8AddToken(tokens, v != 2, base_id + 4)) + VP8AddToken(tokens, v == 4, base_id + 5); + } else if (!VP8AddToken(tokens, v > 10, base_id + 6)) { + if (!VP8AddToken(tokens, v > 6, base_id + 7)) { +// VP8AddToken(tokens, v == 6, 159); + } else { +// VP8AddToken(tokens, v >= 9, 165); +// VP8AddToken(tokens, !(v & 1), 145); + } + } else { + int mask; + const uint8_t* tab; + if (v < 3 + (8 << 1)) { // kCat3 (3b) + VP8AddToken(tokens, 0, base_id + 8); + VP8AddToken(tokens, 0, base_id + 9); + v -= 3 + (8 << 0); + mask = 1 << 2; + tab = kCat3; + } else if (v < 3 + (8 << 2)) { // kCat4 (4b) + VP8AddToken(tokens, 0, base_id + 8); + VP8AddToken(tokens, 1, base_id + 9); + v -= 3 + (8 << 1); + mask = 1 << 3; + tab = kCat4; + } else if (v < 3 + (8 << 3)) { // kCat5 (5b) + VP8AddToken(tokens, 1, base_id + 8); + VP8AddToken(tokens, 0, base_id + 10); + v -= 3 + (8 << 2); + mask = 1 << 4; + tab = kCat5; + } else { // kCat6 (11b) + VP8AddToken(tokens, 1, base_id + 8); + VP8AddToken(tokens, 1, base_id + 10); + v -= 3 + (8 << 3); + mask = 1 << 10; + tab = kCat6; + } + while (mask) { + // VP8AddToken(tokens, !!(v & mask), *tab++); + mask >>= 1; + } + } + ctx = 2; + } + b = VP8EncBands[n]; + // VP8PutBitUniform(bw, sign); + if (n == 16 || !VP8AddToken(tokens, n <= res->last, TOKEN_ID(b, ctx, 0))) { + return 1; // EOB + } + } + return 1; +} + +static void RecordTokens(VP8EncIterator* const it, + const VP8ModeScore* const rd, VP8TBuffer tokens[2]) { + int x, y, ch; + VP8Residual res; + VP8Encoder* const enc = it->enc_; + + VP8IteratorNzToBytes(it); + if (it->mb_->type_ == 1) { // i16x16 + InitResidual(0, 1, enc, &res); + SetResidualCoeffs(rd->y_dc_levels, &res); +// TODO(skal): FIX -> it->top_nz_[8] = it->left_nz_[8] = + RecordCoeffTokens(it->top_nz_[8] + it->left_nz_[8], &res, &tokens[0]); + InitResidual(1, 0, enc, &res); + } else { + InitResidual(0, 3, enc, &res); + } + + // luma-AC + for (y = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); + it->top_nz_[x] = it->left_nz_[y] = + RecordCoeffTokens(ctx, &res, &tokens[0]); + } + } + + // U/V + InitResidual(0, 2, enc, &res); + for (ch = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = + RecordCoeffTokens(ctx, &res, &tokens[1]); + } + } + } +} + +#endif // USE_TOKEN_BUFFER + +//------------------------------------------------------------------------------ +// ExtraInfo map / Debug function + +#if SEGMENT_VISU +static void SetBlock(uint8_t* p, int value, int size) { + int y; + for (y = 0; y < size; ++y) { + memset(p, value, size); + p += BPS; + } +} +#endif + +static void ResetSSE(VP8Encoder* const enc) { + memset(enc->sse_, 0, sizeof(enc->sse_)); + enc->sse_count_ = 0; +} + +static void StoreSSE(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + const uint8_t* const in = it->yuv_in_; + const uint8_t* const out = it->yuv_out_; + // Note: not totally accurate at boundary. And doesn't include in-loop filter. + enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF); + enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF); + enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF); + enc->sse_count_ += 16 * 16; +} + +static void StoreSideInfo(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + const VP8MBInfo* const mb = it->mb_; + WebPPicture* const pic = enc->pic_; + + if (pic->stats != NULL) { + StoreSSE(it); + enc->block_count_[0] += (mb->type_ == 0); + enc->block_count_[1] += (mb->type_ == 1); + enc->block_count_[2] += (mb->skip_ != 0); + } + + if (pic->extra_info != NULL) { + uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; + switch (pic->extra_info_type) { + case 1: *info = mb->type_; break; + case 2: *info = mb->segment_; break; + case 3: *info = enc->dqm_[mb->segment_].quant_; break; + case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; + case 5: *info = mb->uv_mode_; break; + case 6: { + const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); + *info = (b > 255) ? 255 : b; break; + } + default: *info = 0; break; + }; + } +#if SEGMENT_VISU // visualize segments and prediction modes + SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16); + SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8); + SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8); +#endif +} + +//------------------------------------------------------------------------------ +// Main loops +// +// VP8EncLoop(): does the final bitstream coding. + +static void ResetAfterSkip(VP8EncIterator* const it) { + if (it->mb_->type_ == 1) { + *it->nz_ = 0; // reset all predictors + it->left_nz_[8] = 0; + } else { + *it->nz_ &= (1 << 24); // preserve the dc_nz bit + } +} + +int VP8EncLoop(VP8Encoder* const enc) { + int i, s, p; + int ok = 1; + VP8EncIterator it; + VP8ModeScore info; + const int dont_use_skip = !enc->proba_.use_skip_proba_; + const int rd_opt = enc->rd_opt_level_; + const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10] + const int bytes_per_parts = + enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_; + + // Initialize the bit-writers + for (p = 0; p < enc->num_parts_; ++p) { + VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); + } + + ResetStats(enc); + ResetSSE(enc); + + VP8IteratorInit(enc, &it); + VP8InitFilter(&it); + do { + VP8IteratorImport(&it); + // Warning! order is important: first call VP8Decimate() and + // *then* decide how to code the skip decision if there's one. + if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { + CodeResiduals(it.bw_, &it, &info); + } else { // reset predictors after a skip + ResetAfterSkip(&it); + } +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (enc->use_layer_) { + VP8EncCodeLayerBlock(&it); + } +#endif + StoreSideInfo(&it); + VP8StoreFilterStats(&it); + VP8IteratorExport(&it); + ok = VP8IteratorProgress(&it, 20); + } while (ok && VP8IteratorNext(&it, it.yuv_out_)); + + if (ok) { // Finalize the partitions, check for extra errors. + for (p = 0; p < enc->num_parts_; ++p) { + VP8BitWriterFinish(enc->parts_ + p); + ok &= !enc->parts_[p].error_; + } + } + + if (ok) { // All good. Finish up. + if (enc->pic_->stats) { // finalize byte counters... + for (i = 0; i <= 2; ++i) { + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3); + } + } + } + VP8AdjustFilterStrength(&it); // ...and store filter stats. + } else { + // Something bad happened -> need to do some memory cleanup. + VP8EncFreeBitWriters(enc); + } + + return ok; +} + +//------------------------------------------------------------------------------ +// VP8StatLoop(): only collect statistics (number of skips, token usage, ...) +// This is used for deciding optimal probabilities. It also +// modifies the quantizer value if some target (size, PNSR) +// was specified. + +#define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better + +static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs, + float* const PSNR, int percent_delta) { + VP8EncIterator it; + uint64_t size = 0; + uint64_t distortion = 0; + const uint64_t pixel_count = nb_mbs * 384; + + // Make sure the quality parameter is inside valid bounds + if (q < 0.) { + q = 0; + } else if (q > 100.) { + q = 100; + } + + VP8SetSegmentParams(enc, q); // setup segment quantizations and filters + + ResetStats(enc); + ResetTokenStats(enc); + + VP8IteratorInit(enc, &it); + do { + VP8ModeScore info; + VP8IteratorImport(&it); + if (VP8Decimate(&it, &info, rd_opt)) { + // Just record the number of skips and act like skip_proba is not used. + enc->proba_.nb_skip_++; + } + RecordResiduals(&it, &info); + size += info.R; + distortion += info.D; + if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) + return 0; + } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0); + size += FinalizeSkipProba(enc); + size += FinalizeTokenProbas(enc); + size += enc->segment_hdr_.size_; + size = ((size + 1024) >> 11) + kHeaderSizeEstimate; + + if (PSNR) { + *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion)); + } + return (int)size; +} + +// successive refinement increments. +static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 }; + +int VP8StatLoop(VP8Encoder* const enc) { + const int do_search = + (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0); + const int fast_probe = (enc->method_ < 2 && !do_search); + float q = enc->config_->quality; + const int max_passes = enc->config_->pass; + const int task_percent = 20; + const int percent_per_pass = (task_percent + max_passes / 2) / max_passes; + const int final_percent = enc->percent_ + task_percent; + int pass; + int nb_mbs; + + // Fast mode: quick analysis pass over few mbs. Better than nothing. + nb_mbs = enc->mb_w_ * enc->mb_h_; + if (fast_probe && nb_mbs > 100) nb_mbs = 100; + + // No target size: just do several pass without changing 'q' + if (!do_search) { + for (pass = 0; pass < max_passes; ++pass) { + const int rd_opt = (enc->method_ > 2); + if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) { + return 0; + } + } + } else { + // binary search for a size close to target + for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) { + const int rd_opt = 1; + float PSNR; + int criterion; + const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR, + percent_per_pass); +#if DEBUG_SEARCH + printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q); +#endif + if (!size) return 0; + if (enc->config_->target_PSNR > 0) { + criterion = (PSNR < enc->config_->target_PSNR); + } else { + criterion = (size < enc->config_->target_size); + } + // dichotomize + if (criterion) { + q += dqs[pass]; + } else { + q -= dqs[pass]; + } + } + } + return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/histogram.c b/external/libwebp/enc/histogram.c new file mode 100644 index 0000000000..fb4044bfd3 --- /dev/null +++ b/external/libwebp/enc/histogram.c @@ -0,0 +1,406 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "./backward_references.h" +#include "./histogram.h" +#include "../dsp/lossless.h" +#include "../utils/utils.h" + +static void HistogramClear(VP8LHistogram* const p) { + memset(p->literal_, 0, sizeof(p->literal_)); + memset(p->red_, 0, sizeof(p->red_)); + memset(p->blue_, 0, sizeof(p->blue_)); + memset(p->alpha_, 0, sizeof(p->alpha_)); + memset(p->distance_, 0, sizeof(p->distance_)); + p->bit_cost_ = 0; +} + +void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + VP8LHistogram* const histo) { + int i; + for (i = 0; i < refs->size; ++i) { + VP8LHistogramAddSinglePixOrCopy(histo, &refs->refs[i]); + } +} + +void VP8LHistogramCreate(VP8LHistogram* const p, + const VP8LBackwardRefs* const refs, + int palette_code_bits) { + if (palette_code_bits >= 0) { + p->palette_code_bits_ = palette_code_bits; + } + HistogramClear(p); + VP8LHistogramStoreRefs(refs, p); +} + +void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) { + p->palette_code_bits_ = palette_code_bits; + HistogramClear(p); +} + +VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { + int i; + VP8LHistogramSet* set; + VP8LHistogram* bulk; + const uint64_t total_size = sizeof(*set) + + (uint64_t)size * sizeof(*set->histograms) + + (uint64_t)size * sizeof(**set->histograms); + uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); + if (memory == NULL) return NULL; + + set = (VP8LHistogramSet*)memory; + memory += sizeof(*set); + set->histograms = (VP8LHistogram**)memory; + memory += size * sizeof(*set->histograms); + bulk = (VP8LHistogram*)memory; + set->max_size = size; + set->size = size; + for (i = 0; i < size; ++i) { + set->histograms[i] = bulk + i; + VP8LHistogramInit(set->histograms[i], cache_bits); + } + return set; +} + +// ----------------------------------------------------------------------------- + +void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, + const PixOrCopy* const v) { + if (PixOrCopyIsLiteral(v)) { + ++histo->alpha_[PixOrCopyLiteral(v, 3)]; + ++histo->red_[PixOrCopyLiteral(v, 2)]; + ++histo->literal_[PixOrCopyLiteral(v, 1)]; + ++histo->blue_[PixOrCopyLiteral(v, 0)]; + } else if (PixOrCopyIsCacheIdx(v)) { + int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v); + ++histo->literal_[literal_ix]; + } else { + int code, extra_bits_count, extra_bits_value; + PrefixEncode(PixOrCopyLength(v), + &code, &extra_bits_count, &extra_bits_value); + ++histo->literal_[256 + code]; + PrefixEncode(PixOrCopyDistance(v), + &code, &extra_bits_count, &extra_bits_value); + ++histo->distance_[code]; + } +} + + + +static double BitsEntropy(const int* const array, int n) { + double retval = 0.; + int sum = 0; + int nonzeros = 0; + int max_val = 0; + int i; + double mix; + for (i = 0; i < n; ++i) { + if (array[i] != 0) { + sum += array[i]; + ++nonzeros; + retval -= VP8LFastSLog2(array[i]); + if (max_val < array[i]) { + max_val = array[i]; + } + } + } + retval += VP8LFastSLog2(sum); + + if (nonzeros < 5) { + if (nonzeros <= 1) { + return 0; + } + // Two symbols, they will be 0 and 1 in a Huffman code. + // Let's mix in a bit of entropy to favor good clustering when + // distributions of these are combined. + if (nonzeros == 2) { + return 0.99 * sum + 0.01 * retval; + } + // No matter what the entropy says, we cannot be better than min_limit + // with Huffman coding. I am mixing a bit of entropy into the + // min_limit since it produces much better (~0.5 %) compression results + // perhaps because of better entropy clustering. + if (nonzeros == 3) { + mix = 0.95; + } else { + mix = 0.7; // nonzeros == 4. + } + } else { + mix = 0.627; + } + + { + double min_limit = 2 * sum - max_val; + min_limit = mix * min_limit + (1.0 - mix) * retval; + return (retval < min_limit) ? min_limit : retval; + } +} + +double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) { + double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p)) + + BitsEntropy(&p->red_[0], 256) + + BitsEntropy(&p->blue_[0], 256) + + BitsEntropy(&p->alpha_[0], 256) + + BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES); + // Compute the extra bits cost. + int i; + for (i = 2; i < NUM_LENGTH_CODES - 2; ++i) { + retval += + (i >> 1) * p->literal_[256 + i + 2]; + } + for (i = 2; i < NUM_DISTANCE_CODES - 2; ++i) { + retval += (i >> 1) * p->distance_[i + 2]; + } + return retval; +} + + +// Returns the cost encode the rle-encoded entropy code. +// The constants in this function are experimental. +static double HuffmanCost(const int* const population, int length) { + // Small bias because Huffman code length is typically not stored in + // full length. + static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3; + static const double kSmallBias = 9.1; + double retval = kHuffmanCodeOfHuffmanCodeSize - kSmallBias; + int streak = 0; + int i = 0; + for (; i < length - 1; ++i) { + ++streak; + if (population[i] == population[i + 1]) { + continue; + } + last_streak_hack: + // population[i] points now to the symbol in the streak of same values. + if (streak > 3) { + if (population[i] == 0) { + retval += 1.5625 + 0.234375 * streak; + } else { + retval += 2.578125 + 0.703125 * streak; + } + } else { + if (population[i] == 0) { + retval += 1.796875 * streak; + } else { + retval += 3.28125 * streak; + } + } + streak = 0; + } + if (i == length - 1) { + ++streak; + goto last_streak_hack; + } + return retval; +} + +// Estimates the Huffman dictionary + other block overhead size. +static double HistogramEstimateBitsHeader(const VP8LHistogram* const p) { + return HuffmanCost(&p->alpha_[0], 256) + + HuffmanCost(&p->red_[0], 256) + + HuffmanCost(&p->literal_[0], VP8LHistogramNumCodes(p)) + + HuffmanCost(&p->blue_[0], 256) + + HuffmanCost(&p->distance_[0], NUM_DISTANCE_CODES); +} + +double VP8LHistogramEstimateBits(const VP8LHistogram* const p) { + return HistogramEstimateBitsHeader(p) + VP8LHistogramEstimateBitsBulk(p); +} + +static void HistogramBuildImage(int xsize, int histo_bits, + const VP8LBackwardRefs* const backward_refs, + VP8LHistogramSet* const image) { + int i; + int x = 0, y = 0; + const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); + VP8LHistogram** const histograms = image->histograms; + assert(histo_bits > 0); + for (i = 0; i < backward_refs->size; ++i) { + const PixOrCopy* const v = &backward_refs->refs[i]; + const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); + VP8LHistogramAddSinglePixOrCopy(histograms[ix], v); + x += PixOrCopyLength(v); + while (x >= xsize) { + x -= xsize; + ++y; + } + } +} + +static uint32_t MyRand(uint32_t *seed) { + *seed *= 16807U; + if (*seed == 0) { + *seed = 1; + } + return *seed; +} + +static int HistogramCombine(const VP8LHistogramSet* const in, + VP8LHistogramSet* const out, int num_pairs) { + int ok = 0; + int i, iter; + uint32_t seed = 0; + int tries_with_no_success = 0; + const int min_cluster_size = 2; + int out_size = in->size; + const int outer_iters = in->size * 3; + VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos)); + VP8LHistogram* cur_combo = histos + 0; // trial merged histogram + VP8LHistogram* best_combo = histos + 1; // best merged histogram so far + if (histos == NULL) goto End; + + // Copy histograms from in[] to out[]. + assert(in->size <= out->size); + for (i = 0; i < in->size; ++i) { + in->histograms[i]->bit_cost_ = VP8LHistogramEstimateBits(in->histograms[i]); + *out->histograms[i] = *in->histograms[i]; + } + + // Collapse similar histograms in 'out'. + for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) { + // We pick the best pair to be combined out of 'inner_iters' pairs. + double best_cost_diff = 0.; + int best_idx1 = 0, best_idx2 = 1; + int j; + seed += iter; + for (j = 0; j < num_pairs; ++j) { + double curr_cost_diff; + // Choose two histograms at random and try to combine them. + const uint32_t idx1 = MyRand(&seed) % out_size; + const uint32_t tmp = ((j & 7) + 1) % (out_size - 1); + const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1); + const uint32_t idx2 = (idx1 + diff + 1) % out_size; + if (idx1 == idx2) { + continue; + } + *cur_combo = *out->histograms[idx1]; + VP8LHistogramAdd(cur_combo, out->histograms[idx2]); + cur_combo->bit_cost_ = VP8LHistogramEstimateBits(cur_combo); + // Calculate cost reduction on combining. + curr_cost_diff = cur_combo->bit_cost_ + - out->histograms[idx1]->bit_cost_ + - out->histograms[idx2]->bit_cost_; + if (best_cost_diff > curr_cost_diff) { // found a better pair? + { // swap cur/best combo histograms + VP8LHistogram* const tmp_histo = cur_combo; + cur_combo = best_combo; + best_combo = tmp_histo; + } + best_cost_diff = curr_cost_diff; + best_idx1 = idx1; + best_idx2 = idx2; + } + } + + if (best_cost_diff < 0.0) { + *out->histograms[best_idx1] = *best_combo; + // swap best_idx2 slot with last one (which is now unused) + --out_size; + if (best_idx2 != out_size) { + out->histograms[best_idx2] = out->histograms[out_size]; + out->histograms[out_size] = NULL; // just for sanity check. + } + tries_with_no_success = 0; + } + if (++tries_with_no_success >= 50) { + break; + } + } + out->size = out_size; + ok = 1; + + End: + free(histos); + return ok; +} + +// ----------------------------------------------------------------------------- +// Histogram refinement + +// What is the bit cost of moving square_histogram from +// cur_symbol to candidate_symbol. +// TODO(skal): we don't really need to copy the histogram and Add(). Instead +// we just need VP8LDualHistogramEstimateBits(A, B) estimation function. +static double HistogramDistance(const VP8LHistogram* const square_histogram, + const VP8LHistogram* const candidate) { + const double previous_bit_cost = candidate->bit_cost_; + double new_bit_cost; + VP8LHistogram modified_histo; + modified_histo = *candidate; + VP8LHistogramAdd(&modified_histo, square_histogram); + new_bit_cost = VP8LHistogramEstimateBits(&modified_histo); + + return new_bit_cost - previous_bit_cost; +} + +// Find the best 'out' histogram for each of the 'in' histograms. +// Note: we assume that out[]->bit_cost_ is already up-to-date. +static void HistogramRemap(const VP8LHistogramSet* const in, + const VP8LHistogramSet* const out, + uint16_t* const symbols) { + int i; + for (i = 0; i < in->size; ++i) { + int best_out = 0; + double best_bits = HistogramDistance(in->histograms[i], out->histograms[0]); + int k; + for (k = 1; k < out->size; ++k) { + const double cur_bits = + HistogramDistance(in->histograms[i], out->histograms[k]); + if (cur_bits < best_bits) { + best_bits = cur_bits; + best_out = k; + } + } + symbols[i] = best_out; + } + + // Recompute each out based on raw and symbols. + for (i = 0; i < out->size; ++i) { + HistogramClear(out->histograms[i]); + } + for (i = 0; i < in->size; ++i) { + VP8LHistogramAdd(out->histograms[symbols[i]], in->histograms[i]); + } +} + +int VP8LGetHistoImageSymbols(int xsize, int ysize, + const VP8LBackwardRefs* const refs, + int quality, int histo_bits, int cache_bits, + VP8LHistogramSet* const image_in, + uint16_t* const histogram_symbols) { + int ok = 0; + const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1; + const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1; + const int num_histo_pairs = 10 + quality / 2; // For HistogramCombine(). + const int histo_image_raw_size = histo_xsize * histo_ysize; + VP8LHistogramSet* const image_out = + VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits); + if (image_out == NULL) return 0; + + // Build histogram image. + HistogramBuildImage(xsize, histo_bits, refs, image_out); + // Collapse similar histograms. + if (!HistogramCombine(image_out, image_in, num_histo_pairs)) { + goto Error; + } + // Find the optimal map from original histograms to the final ones. + HistogramRemap(image_out, image_in, histogram_symbols); + ok = 1; + +Error: + free(image_out); + return ok; +} diff --git a/external/libwebp/enc/histogram.h b/external/libwebp/enc/histogram.h new file mode 100644 index 0000000000..ec573c5c85 --- /dev/null +++ b/external/libwebp/enc/histogram.h @@ -0,0 +1,115 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Models the histograms of literal and distance codes. + +#ifndef WEBP_ENC_HISTOGRAM_H_ +#define WEBP_ENC_HISTOGRAM_H_ + +#include +#include +#include +#include +#include + +#include "./backward_references.h" +#include "../webp/format_constants.h" +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// A simple container for histograms of data. +typedef struct { + // literal_ contains green literal, palette-code and + // copy-length-prefix histogram + int literal_[PIX_OR_COPY_CODES_MAX]; + int red_[256]; + int blue_[256]; + int alpha_[256]; + // Backward reference prefix-code histogram. + int distance_[NUM_DISTANCE_CODES]; + int palette_code_bits_; + double bit_cost_; // cached value of VP8LHistogramEstimateBits(this) +} VP8LHistogram; + +// Collection of histograms with fixed capacity, allocated as one +// big memory chunk. Can be destroyed by simply calling 'free()'. +typedef struct { + int size; // number of slots currently in use + int max_size; // maximum capacity + VP8LHistogram** histograms; +} VP8LHistogramSet; + +// Create the histogram. +// +// The input data is the PixOrCopy data, which models the literals, stop +// codes and backward references (both distances and lengths). Also: if +// palette_code_bits is >= 0, initialize the histogram with this value. +void VP8LHistogramCreate(VP8LHistogram* const p, + const VP8LBackwardRefs* const refs, + int palette_code_bits); + +// Set the palette_code_bits and reset the stats. +void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits); + +// Collect all the references into a histogram (without reset) +void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, + VP8LHistogram* const histo); + +// Allocate an array of pointer to histograms, allocated and initialized +// using 'cache_bits'. Return NULL in case of memory error. +VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); + +// Accumulate a token 'v' into a histogram. +void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, + const PixOrCopy* const v); + +// Estimate how many bits the combined entropy of literals and distance +// approximately maps to. +double VP8LHistogramEstimateBits(const VP8LHistogram* const p); + +// This function estimates the cost in bits excluding the bits needed to +// represent the entropy code itself. +double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p); + +static WEBP_INLINE void VP8LHistogramAdd(VP8LHistogram* const p, + const VP8LHistogram* const a) { + int i; + for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) { + p->literal_[i] += a->literal_[i]; + } + for (i = 0; i < NUM_DISTANCE_CODES; ++i) { + p->distance_[i] += a->distance_[i]; + } + for (i = 0; i < 256; ++i) { + p->red_[i] += a->red_[i]; + p->blue_[i] += a->blue_[i]; + p->alpha_[i] += a->alpha_[i]; + } +} + +static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) { + return 256 + NUM_LENGTH_CODES + + ((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0); +} + +// Builds the histogram image. +int VP8LGetHistoImageSymbols(int xsize, int ysize, + const VP8LBackwardRefs* const refs, + int quality, int histogram_bits, int cache_bits, + VP8LHistogramSet* const image_in, + uint16_t* const histogram_symbols); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif // WEBP_ENC_HISTOGRAM_H_ diff --git a/external/libwebp/enc/iterator.c b/external/libwebp/enc/iterator.c new file mode 100644 index 0000000000..86e473bcf0 --- /dev/null +++ b/external/libwebp/enc/iterator.c @@ -0,0 +1,422 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// VP8Iterator: block iterator +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// VP8Iterator +//------------------------------------------------------------------------------ + +static void InitLeft(VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] = + (it->y_ > 0) ? 129 : 127; + memset(enc->y_left_, 129, 16); + memset(enc->u_left_, 129, 8); + memset(enc->v_left_, 129, 8); + it->left_nz_[8] = 0; +} + +static void InitTop(VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + const size_t top_size = enc->mb_w_ * 16; + memset(enc->y_top_, 127, 2 * top_size); + memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); +} + +void VP8IteratorReset(VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + it->x_ = 0; + it->y_ = 0; + it->y_offset_ = 0; + it->uv_offset_ = 0; + it->mb_ = enc->mb_info_; + it->preds_ = enc->preds_; + it->nz_ = enc->nz_; + it->bw_ = &enc->parts_[0]; + it->done_ = enc->mb_w_* enc->mb_h_; + InitTop(it); + InitLeft(it); + memset(it->bit_count_, 0, sizeof(it->bit_count_)); + it->do_trellis_ = 0; +} + +void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { + it->enc_ = enc; + it->y_stride_ = enc->pic_->y_stride; + it->uv_stride_ = enc->pic_->uv_stride; + // TODO(later): for multithreading, these should be owned by 'it'. + it->yuv_in_ = enc->yuv_in_; + it->yuv_out_ = enc->yuv_out_; + it->yuv_out2_ = enc->yuv_out2_; + it->yuv_p_ = enc->yuv_p_; + it->lf_stats_ = enc->lf_stats_; + it->percent0_ = enc->percent_; + VP8IteratorReset(it); +} + +int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { + VP8Encoder* const enc = it->enc_; + if (delta && enc->pic_->progress_hook) { + const int percent = (enc->mb_h_ <= 1) + ? it->percent0_ + : it->percent0_ + delta * it->y_ / (enc->mb_h_ - 1); + return WebPReportProgress(enc->pic_, percent, &enc->percent_); + } + return 1; +} + +//------------------------------------------------------------------------------ +// Import the source samples into the cache. Takes care of replicating +// boundary pixels if necessary. + +static void ImportBlock(const uint8_t* src, int src_stride, + uint8_t* dst, int w, int h, int size) { + int i; + for (i = 0; i < h; ++i) { + memcpy(dst, src, w); + if (w < size) { + memset(dst + w, dst[w - 1], size - w); + } + dst += BPS; + src += src_stride; + } + for (i = h; i < size; ++i) { + memcpy(dst, dst - BPS, size); + dst += BPS; + } +} + +void VP8IteratorImport(const VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + const int x = it->x_, y = it->y_; + const WebPPicture* const pic = enc->pic_; + const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; + const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; + const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; + uint8_t* const ydst = it->yuv_in_ + Y_OFF; + uint8_t* const udst = it->yuv_in_ + U_OFF; + uint8_t* const vdst = it->yuv_in_ + V_OFF; + int w = (pic->width - x * 16); + int h = (pic->height - y * 16); + + if (w > 16) w = 16; + if (h > 16) h = 16; + + // Luma plane + ImportBlock(ysrc, pic->y_stride, ydst, w, h, 16); + + { // U/V planes + const int uv_w = (w + 1) >> 1; + const int uv_h = (h + 1) >> 1; + ImportBlock(usrc, pic->uv_stride, udst, uv_w, uv_h, 8); + ImportBlock(vsrc, pic->uv_stride, vdst, uv_w, uv_h, 8); + } +} + +//------------------------------------------------------------------------------ +// Copy back the compressed samples into user space if requested. + +static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride, + int w, int h) { + while (h-- > 0) { + memcpy(dst, src, w); + dst += dst_stride; + src += BPS; + } +} + +void VP8IteratorExport(const VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + if (enc->config_->show_compressed) { + const int x = it->x_, y = it->y_; + const uint8_t* const ysrc = it->yuv_out_ + Y_OFF; + const uint8_t* const usrc = it->yuv_out_ + U_OFF; + const uint8_t* const vsrc = it->yuv_out_ + V_OFF; + const WebPPicture* const pic = enc->pic_; + uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16; + uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8; + uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8; + int w = (pic->width - x * 16); + int h = (pic->height - y * 16); + + if (w > 16) w = 16; + if (h > 16) h = 16; + + // Luma plane + ExportBlock(ysrc, ydst, pic->y_stride, w, h); + + { // U/V planes + const int uv_w = (w + 1) >> 1; + const int uv_h = (h + 1) >> 1; + ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h); + ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h); + } + } +} + +//------------------------------------------------------------------------------ +// Non-zero contexts setup/teardown + +// Nz bits: +// 0 1 2 3 Y +// 4 5 6 7 +// 8 9 10 11 +// 12 13 14 15 +// 16 17 U +// 18 19 +// 20 21 V +// 22 23 +// 24 DC-intra16 + +// Convert packed context to byte array +#define BIT(nz, n) (!!((nz) & (1 << (n)))) + +void VP8IteratorNzToBytes(VP8EncIterator* const it) { + const int tnz = it->nz_[0], lnz = it->nz_[-1]; + int* const top_nz = it->top_nz_; + int* const left_nz = it->left_nz_; + + // Top-Y + top_nz[0] = BIT(tnz, 12); + top_nz[1] = BIT(tnz, 13); + top_nz[2] = BIT(tnz, 14); + top_nz[3] = BIT(tnz, 15); + // Top-U + top_nz[4] = BIT(tnz, 18); + top_nz[5] = BIT(tnz, 19); + // Top-V + top_nz[6] = BIT(tnz, 22); + top_nz[7] = BIT(tnz, 23); + // DC + top_nz[8] = BIT(tnz, 24); + + // left-Y + left_nz[0] = BIT(lnz, 3); + left_nz[1] = BIT(lnz, 7); + left_nz[2] = BIT(lnz, 11); + left_nz[3] = BIT(lnz, 15); + // left-U + left_nz[4] = BIT(lnz, 17); + left_nz[5] = BIT(lnz, 19); + // left-V + left_nz[6] = BIT(lnz, 21); + left_nz[7] = BIT(lnz, 23); + // left-DC is special, iterated separately +} + +void VP8IteratorBytesToNz(VP8EncIterator* const it) { + uint32_t nz = 0; + const int* const top_nz = it->top_nz_; + const int* const left_nz = it->left_nz_; + // top + nz |= (top_nz[0] << 12) | (top_nz[1] << 13); + nz |= (top_nz[2] << 14) | (top_nz[3] << 15); + nz |= (top_nz[4] << 18) | (top_nz[5] << 19); + nz |= (top_nz[6] << 22) | (top_nz[7] << 23); + nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4 + // left + nz |= (left_nz[0] << 3) | (left_nz[1] << 7); + nz |= (left_nz[2] << 11); + nz |= (left_nz[4] << 17) | (left_nz[6] << 21); + + *it->nz_ = nz; +} + +#undef BIT + +//------------------------------------------------------------------------------ +// Advance to the next position, doing the bookeeping. + +int VP8IteratorNext(VP8EncIterator* const it, + const uint8_t* const block_to_save) { + VP8Encoder* const enc = it->enc_; + if (block_to_save) { + const int x = it->x_, y = it->y_; + const uint8_t* const ysrc = block_to_save + Y_OFF; + const uint8_t* const usrc = block_to_save + U_OFF; + if (x < enc->mb_w_ - 1) { // left + int i; + for (i = 0; i < 16; ++i) { + enc->y_left_[i] = ysrc[15 + i * BPS]; + } + for (i = 0; i < 8; ++i) { + enc->u_left_[i] = usrc[7 + i * BPS]; + enc->v_left_[i] = usrc[15 + i * BPS]; + } + // top-left (before 'top'!) + enc->y_left_[-1] = enc->y_top_[x * 16 + 15]; + enc->u_left_[-1] = enc->uv_top_[x * 16 + 0 + 7]; + enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7]; + } + if (y < enc->mb_h_ - 1) { // top + memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16); + memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8); + } + } + + it->mb_++; + it->preds_ += 4; + it->nz_++; + it->x_++; + if (it->x_ == enc->mb_w_) { + it->x_ = 0; + it->y_++; + it->bw_ = &enc->parts_[it->y_ & (enc->num_parts_ - 1)]; + it->preds_ = enc->preds_ + it->y_ * 4 * enc->preds_w_; + it->nz_ = enc->nz_; + InitLeft(it); + } + return (0 < --it->done_); +} + +//------------------------------------------------------------------------------ +// Helper function to set mode properties + +void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { + uint8_t* preds = it->preds_; + int y; + for (y = 0; y < 4; ++y) { + memset(preds, mode, 4); + preds += it->enc_->preds_w_; + } + it->mb_->type_ = 1; +} + +void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) { + uint8_t* preds = it->preds_; + int y; + for (y = 4; y > 0; --y) { + memcpy(preds, modes, 4 * sizeof(*modes)); + preds += it->enc_->preds_w_; + modes += 4; + } + it->mb_->type_ = 0; +} + +void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) { + it->mb_->uv_mode_ = mode; +} + +void VP8SetSkip(const VP8EncIterator* const it, int skip) { + it->mb_->skip_ = skip; +} + +void VP8SetSegment(const VP8EncIterator* const it, int segment) { + it->mb_->segment_ = segment; +} + +//------------------------------------------------------------------------------ +// Intra4x4 sub-blocks iteration +// +// We store and update the boundary samples into an array of 37 pixels. They +// are updated as we iterate and reconstructs each intra4x4 blocks in turn. +// The position of the samples has the following snake pattern: +// +// 16|17 18 19 20|21 22 23 24|25 26 27 28|29 30 31 32|33 34 35 36 <- Top-right +// --+-----------+-----------+-----------+-----------+ +// 15| 19| 23| 27| 31| +// 14| 18| 22| 26| 30| +// 13| 17| 21| 25| 29| +// 12|13 14 15 16|17 18 19 20|21 22 23 24|25 26 27 28| +// --+-----------+-----------+-----------+-----------+ +// 11| 15| 19| 23| 27| +// 10| 14| 18| 22| 26| +// 9| 13| 17| 21| 25| +// 8| 9 10 11 12|13 14 15 16|17 18 19 20|21 22 23 24| +// --+-----------+-----------+-----------+-----------+ +// 7| 11| 15| 19| 23| +// 6| 10| 14| 18| 22| +// 5| 9| 13| 17| 21| +// 4| 5 6 7 8| 9 10 11 12|13 14 15 16|17 18 19 20| +// --+-----------+-----------+-----------+-----------+ +// 3| 7| 11| 15| 19| +// 2| 6| 10| 14| 18| +// 1| 5| 9| 13| 17| +// 0| 1 2 3 4| 5 6 7 8| 9 10 11 12|13 14 15 16| +// --+-----------+-----------+-----------+-----------+ + +// Array to record the position of the top sample to pass to the prediction +// functions in dsp.c. +static const uint8_t VP8TopLeftI4[16] = { + 17, 21, 25, 29, + 13, 17, 21, 25, + 9, 13, 17, 21, + 5, 9, 13, 17 +}; + +void VP8IteratorStartI4(VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + int i; + + it->i4_ = 0; // first 4x4 sub-block + it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; + + // Import the boundary samples + for (i = 0; i < 17; ++i) { // left + it->i4_boundary_[i] = enc->y_left_[15 - i]; + } + for (i = 0; i < 16; ++i) { // top + it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i]; + } + // top-right samples have a special case on the far right of the picture + if (it->x_ < enc->mb_w_ - 1) { + for (i = 16; i < 16 + 4; ++i) { + it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i]; + } + } else { // else, replicate the last valid pixel four times + for (i = 16; i < 16 + 4; ++i) { + it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; + } + } + VP8IteratorNzToBytes(it); // import the non-zero context +} + +int VP8IteratorRotateI4(VP8EncIterator* const it, + const uint8_t* const yuv_out) { + const uint8_t* const blk = yuv_out + VP8Scan[it->i4_]; + uint8_t* const top = it->i4_top_; + int i; + + // Update the cache with 7 fresh samples + for (i = 0; i <= 3; ++i) { + top[-4 + i] = blk[i + 3 * BPS]; // store future top samples + } + if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15 + for (i = 0; i <= 2; ++i) { // store future left samples + top[i] = blk[3 + (2 - i) * BPS]; + } + } else { // else replicate top-right samples, as says the specs. + for (i = 0; i <= 3; ++i) { + top[i] = top[i + 4]; + } + } + // move pointers to next sub-block + ++it->i4_; + if (it->i4_ == 16) { // we're done + return 0; + } + + it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; + return 1; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/layer.c b/external/libwebp/enc/layer.c new file mode 100644 index 0000000000..423127df63 --- /dev/null +++ b/external/libwebp/enc/layer.c @@ -0,0 +1,49 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Enhancement layer (for YUV444/422) +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ + +void VP8EncInitLayer(VP8Encoder* const enc) { + enc->use_layer_ = (enc->pic_->u0 != NULL); + enc->layer_data_size_ = 0; + enc->layer_data_ = NULL; + if (enc->use_layer_) { + VP8BitWriterInit(&enc->layer_bw_, enc->mb_w_ * enc->mb_h_ * 3); + } +} + +void VP8EncCodeLayerBlock(VP8EncIterator* it) { + (void)it; // remove a warning +} + +int VP8EncFinishLayer(VP8Encoder* const enc) { + if (enc->use_layer_) { + enc->layer_data_ = VP8BitWriterFinish(&enc->layer_bw_); + enc->layer_data_size_ = VP8BitWriterSize(&enc->layer_bw_); + } + return 1; +} + +void VP8EncDeleteLayer(VP8Encoder* enc) { + free(enc->layer_data_); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/picture.c b/external/libwebp/enc/picture.c new file mode 100644 index 0000000000..44eed06083 --- /dev/null +++ b/external/libwebp/enc/picture.c @@ -0,0 +1,1041 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// WebPPicture utils: colorspace conversion, crop, ... +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "./vp8enci.h" +#include "../utils/rescaler.h" +#include "../utils/utils.h" +#include "../dsp/dsp.h" +#include "../dsp/yuv.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define HALVE(x) (((x) + 1) >> 1) +#define IS_YUV_CSP(csp, YUV_CSP) (((csp) & WEBP_CSP_UV_MASK) == (YUV_CSP)) + +static const union { + uint32_t argb; + uint8_t bytes[4]; +} test_endian = { 0xff000000u }; +#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff) + +//------------------------------------------------------------------------------ +// WebPPicture +//------------------------------------------------------------------------------ + +int WebPPictureAlloc(WebPPicture* picture) { + if (picture != NULL) { + const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK; + const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT; + const int width = picture->width; + const int height = picture->height; + + if (!picture->use_argb) { + const int y_stride = width; + const int uv_width = HALVE(width); + const int uv_height = HALVE(height); + const int uv_stride = uv_width; + int uv0_stride = 0; + int a_width, a_stride; + uint64_t y_size, uv_size, uv0_size, a_size, total_size; + uint8_t* mem; + + // U/V + switch (uv_csp) { + case WEBP_YUV420: + break; +#ifdef WEBP_EXPERIMENTAL_FEATURES + case WEBP_YUV400: // for now, we'll just reset the U/V samples + break; + case WEBP_YUV422: + uv0_stride = uv_width; + break; + case WEBP_YUV444: + uv0_stride = width; + break; +#endif + default: + return 0; + } + uv0_size = height * uv0_stride; + + // alpha + a_width = has_alpha ? width : 0; + a_stride = a_width; + y_size = (uint64_t)y_stride * height; + uv_size = (uint64_t)uv_stride * uv_height; + a_size = (uint64_t)a_stride * height; + + total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size; + + // Security and validation checks + if (width <= 0 || height <= 0 || // luma/alpha param error + uv_width < 0 || uv_height < 0) { // u/v param error + return 0; + } + // Clear previous buffer and allocate a new one. + WebPPictureFree(picture); // erase previous buffer + mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem)); + if (mem == NULL) return 0; + + // From now on, we're in the clear, we can no longer fail... + picture->memory_ = (void*)mem; + picture->y_stride = y_stride; + picture->uv_stride = uv_stride; + picture->a_stride = a_stride; + picture->uv0_stride = uv0_stride; + // TODO(skal): we could align the y/u/v planes and adjust stride. + picture->y = mem; + mem += y_size; + + picture->u = mem; + mem += uv_size; + picture->v = mem; + mem += uv_size; + + if (a_size) { + picture->a = mem; + mem += a_size; + } + if (uv0_size) { + picture->u0 = mem; + mem += uv0_size; + picture->v0 = mem; + mem += uv0_size; + } + } else { + void* memory; + const uint64_t argb_size = (uint64_t)width * height; + if (width <= 0 || height <= 0) { + return 0; + } + // Clear previous buffer and allocate a new one. + WebPPictureFree(picture); // erase previous buffer + memory = WebPSafeMalloc(argb_size, sizeof(*picture->argb)); + if (memory == NULL) return 0; + + // TODO(skal): align plane to cache line? + picture->memory_argb_ = memory; + picture->argb = (uint32_t*)memory; + picture->argb_stride = width; + } + } + return 1; +} + +// Remove reference to the ARGB buffer (doesn't free anything). +static void PictureResetARGB(WebPPicture* const picture) { + picture->memory_argb_ = NULL; + picture->argb = NULL; + picture->argb_stride = 0; +} + +// Remove reference to the YUVA buffer (doesn't free anything). +static void PictureResetYUVA(WebPPicture* const picture) { + picture->memory_ = NULL; + picture->y = picture->u = picture->v = picture->a = NULL; + picture->u0 = picture->v0 = NULL; + picture->y_stride = picture->uv_stride = 0; + picture->a_stride = 0; + picture->uv0_stride = 0; +} + +// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them +// into 'dst'. Mark 'dst' as not owning any memory. +static void WebPPictureGrabSpecs(const WebPPicture* const src, + WebPPicture* const dst) { + assert(src != NULL && dst != NULL); + *dst = *src; + PictureResetYUVA(dst); + PictureResetARGB(dst); +} + +// Allocate a new argb buffer, discarding any existing one and preserving +// the other YUV(A) buffer. +static int PictureAllocARGB(WebPPicture* const picture) { + WebPPicture tmp; + free(picture->memory_argb_); + PictureResetARGB(picture); + picture->use_argb = 1; + WebPPictureGrabSpecs(picture, &tmp); + if (!WebPPictureAlloc(&tmp)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + picture->memory_argb_ = tmp.memory_argb_; + picture->argb = tmp.argb; + picture->argb_stride = tmp.argb_stride; + return 1; +} + +// Release memory owned by 'picture' (both YUV and ARGB buffers). +void WebPPictureFree(WebPPicture* picture) { + if (picture != NULL) { + free(picture->memory_); + free(picture->memory_argb_); + PictureResetYUVA(picture); + PictureResetARGB(picture); + } +} + +//------------------------------------------------------------------------------ +// Picture copying + +// Not worth moving to dsp/enc.c (only used here). +static void CopyPlane(const uint8_t* src, int src_stride, + uint8_t* dst, int dst_stride, int width, int height) { + while (height-- > 0) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } +} + +// Adjust top-left corner to chroma sample position. +static void SnapTopLeftPosition(const WebPPicture* const pic, + int* const left, int* const top) { + if (!pic->use_argb) { + const int is_yuv422 = IS_YUV_CSP(pic->colorspace, WEBP_YUV422); + if (IS_YUV_CSP(pic->colorspace, WEBP_YUV420) || is_yuv422) { + *left &= ~1; + if (!is_yuv422) *top &= ~1; + } + } +} + +// Adjust top-left corner and verify that the sub-rectangle is valid. +static int AdjustAndCheckRectangle(const WebPPicture* const pic, + int* const left, int* const top, + int width, int height) { + SnapTopLeftPosition(pic, left, top); + if ((*left) < 0 || (*top) < 0) return 0; + if (width <= 0 || height <= 0) return 0; + if ((*left) + width > pic->width) return 0; + if ((*top) + height > pic->height) return 0; + return 1; +} + +int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { + if (src == NULL || dst == NULL) return 0; + if (src == dst) return 1; + + WebPPictureGrabSpecs(src, dst); + if (!WebPPictureAlloc(dst)) return 0; + + if (!src->use_argb) { + CopyPlane(src->y, src->y_stride, + dst->y, dst->y_stride, dst->width, dst->height); + CopyPlane(src->u, src->uv_stride, + dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height)); + CopyPlane(src->v, src->uv_stride, + dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height)); + if (dst->a != NULL) { + CopyPlane(src->a, src->a_stride, + dst->a, dst->a_stride, dst->width, dst->height); + } +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (dst->u0 != NULL) { + int uv0_width = src->width; + if (IS_YUV_CSP(dst->colorspace, WEBP_YUV422)) { + uv0_width = HALVE(uv0_width); + } + CopyPlane(src->u0, src->uv0_stride, + dst->u0, dst->uv0_stride, uv0_width, dst->height); + CopyPlane(src->v0, src->uv0_stride, + dst->v0, dst->uv0_stride, uv0_width, dst->height); + } +#endif + } else { + CopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride, + (uint8_t*)dst->argb, 4 * dst->argb_stride, + 4 * dst->width, dst->height); + } + return 1; +} + +int WebPPictureIsView(const WebPPicture* picture) { + if (picture == NULL) return 0; + if (picture->use_argb) { + return (picture->memory_argb_ == NULL); + } + return (picture->memory_ == NULL); +} + +int WebPPictureView(const WebPPicture* src, + int left, int top, int width, int height, + WebPPicture* dst) { + if (src == NULL || dst == NULL) return 0; + + // verify rectangle position. + if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0; + + if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'. + WebPPictureGrabSpecs(src, dst); + } + dst->width = width; + dst->height = height; + if (!src->use_argb) { + dst->y = src->y + top * src->y_stride + left; + dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1); + dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1); + if (src->a != NULL) { + dst->a = src->a + top * src->a_stride + left; + } +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (src->u0 != NULL) { + const int left_pos = + IS_YUV_CSP(dst->colorspace, WEBP_YUV422) ? (left >> 1) : left; + dst->u0 = src->u0 + top * src->uv0_stride + left_pos; + dst->v0 = src->v0 + top * src->uv0_stride + left_pos; + } +#endif + } else { + dst->argb = src->argb + top * src->argb_stride + left; + } + return 1; +} + +//------------------------------------------------------------------------------ +// Picture cropping + +int WebPPictureCrop(WebPPicture* pic, + int left, int top, int width, int height) { + WebPPicture tmp; + + if (pic == NULL) return 0; + if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0; + + WebPPictureGrabSpecs(pic, &tmp); + tmp.width = width; + tmp.height = height; + if (!WebPPictureAlloc(&tmp)) return 0; + + if (!pic->use_argb) { + const int y_offset = top * pic->y_stride + left; + const int uv_offset = (top / 2) * pic->uv_stride + left / 2; + CopyPlane(pic->y + y_offset, pic->y_stride, + tmp.y, tmp.y_stride, width, height); + CopyPlane(pic->u + uv_offset, pic->uv_stride, + tmp.u, tmp.uv_stride, HALVE(width), HALVE(height)); + CopyPlane(pic->v + uv_offset, pic->uv_stride, + tmp.v, tmp.uv_stride, HALVE(width), HALVE(height)); + + if (tmp.a != NULL) { + const int a_offset = top * pic->a_stride + left; + CopyPlane(pic->a + a_offset, pic->a_stride, + tmp.a, tmp.a_stride, width, height); + } +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (tmp.u0 != NULL) { + int w = width; + int left_pos = left; + if (IS_YUV_CSP(tmp.colorspace, WEBP_YUV422)) { + w = HALVE(w); + left_pos = HALVE(left_pos); + } + CopyPlane(pic->u0 + top * pic->uv0_stride + left_pos, pic->uv0_stride, + tmp.u0, tmp.uv0_stride, w, height); + CopyPlane(pic->v0 + top * pic->uv0_stride + left_pos, pic->uv0_stride, + tmp.v0, tmp.uv0_stride, w, height); + } +#endif + } else { + const uint8_t* const src = + (const uint8_t*)(pic->argb + top * pic->argb_stride + left); + CopyPlane(src, pic->argb_stride * 4, + (uint8_t*)tmp.argb, tmp.argb_stride * 4, + width * 4, height); + } + WebPPictureFree(pic); + *pic = tmp; + return 1; +} + +//------------------------------------------------------------------------------ +// Simple picture rescaler + +static void RescalePlane(const uint8_t* src, + int src_width, int src_height, int src_stride, + uint8_t* dst, + int dst_width, int dst_height, int dst_stride, + int32_t* const work, + int num_channels) { + WebPRescaler rescaler; + int y = 0; + WebPRescalerInit(&rescaler, src_width, src_height, + dst, dst_width, dst_height, dst_stride, + num_channels, + src_width, dst_width, + src_height, dst_height, + work); + memset(work, 0, 2 * dst_width * num_channels * sizeof(*work)); + while (y < src_height) { + y += WebPRescalerImport(&rescaler, src_height - y, + src + y * src_stride, src_stride); + WebPRescalerExport(&rescaler); + } +} + +int WebPPictureRescale(WebPPicture* pic, int width, int height) { + WebPPicture tmp; + int prev_width, prev_height; + int32_t* work; + + if (pic == NULL) return 0; + prev_width = pic->width; + prev_height = pic->height; + // if width is unspecified, scale original proportionally to height ratio. + if (width == 0) { + width = (prev_width * height + prev_height / 2) / prev_height; + } + // if height is unspecified, scale original proportionally to width ratio. + if (height == 0) { + height = (prev_height * width + prev_width / 2) / prev_width; + } + // Check if the overall dimensions still make sense. + if (width <= 0 || height <= 0) return 0; + + WebPPictureGrabSpecs(pic, &tmp); + tmp.width = width; + tmp.height = height; + if (!WebPPictureAlloc(&tmp)) return 0; + + if (!pic->use_argb) { + work = (int32_t*)WebPSafeMalloc(2ULL * width, sizeof(*work)); + if (work == NULL) { + WebPPictureFree(&tmp); + return 0; + } + + RescalePlane(pic->y, prev_width, prev_height, pic->y_stride, + tmp.y, width, height, tmp.y_stride, work, 1); + RescalePlane(pic->u, + HALVE(prev_width), HALVE(prev_height), pic->uv_stride, + tmp.u, + HALVE(width), HALVE(height), tmp.uv_stride, work, 1); + RescalePlane(pic->v, + HALVE(prev_width), HALVE(prev_height), pic->uv_stride, + tmp.v, + HALVE(width), HALVE(height), tmp.uv_stride, work, 1); + + if (tmp.a != NULL) { + RescalePlane(pic->a, prev_width, prev_height, pic->a_stride, + tmp.a, width, height, tmp.a_stride, work, 1); + } +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (tmp.u0 != NULL) { + const int s = IS_YUV_CSP(tmp.colorspace, WEBP_YUV422) ? 2 : 1; + RescalePlane( + pic->u0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride, + tmp.u0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1); + RescalePlane( + pic->v0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride, + tmp.v0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1); + } +#endif + } else { + work = (int32_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work)); + if (work == NULL) { + WebPPictureFree(&tmp); + return 0; + } + + RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height, + pic->argb_stride * 4, + (uint8_t*)tmp.argb, width, height, + tmp.argb_stride * 4, + work, 4); + + } + WebPPictureFree(pic); + free(work); + *pic = tmp; + return 1; +} + +//------------------------------------------------------------------------------ +// WebPMemoryWriter: Write-to-memory + +void WebPMemoryWriterInit(WebPMemoryWriter* writer) { + writer->mem = NULL; + writer->size = 0; + writer->max_size = 0; +} + +int WebPMemoryWrite(const uint8_t* data, size_t data_size, + const WebPPicture* picture) { + WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr; + uint64_t next_size; + if (w == NULL) { + return 1; + } + next_size = (uint64_t)w->size + data_size; + if (next_size > w->max_size) { + uint8_t* new_mem; + uint64_t next_max_size = 2ULL * w->max_size; + if (next_max_size < next_size) next_max_size = next_size; + if (next_max_size < 8192ULL) next_max_size = 8192ULL; + new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1); + if (new_mem == NULL) { + return 0; + } + if (w->size > 0) { + memcpy(new_mem, w->mem, w->size); + } + free(w->mem); + w->mem = new_mem; + // down-cast is ok, thanks to WebPSafeMalloc + w->max_size = (size_t)next_max_size; + } + if (data_size > 0) { + memcpy(w->mem + w->size, data, data_size); + w->size += data_size; + } + return 1; +} + +//------------------------------------------------------------------------------ +// Detection of non-trivial transparency + +// Returns true if alpha[] has non-0xff values. +static int CheckNonOpaque(const uint8_t* alpha, int width, int height, + int x_step, int y_step) { + if (alpha == NULL) return 0; + while (height-- > 0) { + int x; + for (x = 0; x < width * x_step; x += x_step) { + if (alpha[x] != 0xff) return 1; // TODO(skal): check 4/8 bytes at a time. + } + alpha += y_step; + } + return 0; +} + +// Checking for the presence of non-opaque alpha. +int WebPPictureHasTransparency(const WebPPicture* picture) { + if (picture == NULL) return 0; + if (!picture->use_argb) { + return CheckNonOpaque(picture->a, picture->width, picture->height, + 1, picture->a_stride); + } else { + int x, y; + const uint32_t* argb = picture->argb; + if (argb == NULL) return 0; + for (y = 0; y < picture->height; ++y) { + for (x = 0; x < picture->width; ++x) { + if (argb[x] < 0xff000000u) return 1; // test any alpha values != 0xff + } + argb += picture->argb_stride; + } + } + return 0; +} + +//------------------------------------------------------------------------------ +// RGB -> YUV conversion + +// TODO: we can do better than simply 2x2 averaging on U/V samples. +#define SUM4(ptr) ((ptr)[0] + (ptr)[step] + \ + (ptr)[rgb_stride] + (ptr)[rgb_stride + step]) +#define SUM2H(ptr) (2 * (ptr)[0] + 2 * (ptr)[step]) +#define SUM2V(ptr) (2 * (ptr)[0] + 2 * (ptr)[rgb_stride]) +#define SUM1(ptr) (4 * (ptr)[0]) +#define RGB_TO_UV(x, y, SUM) { \ + const int src = (2 * (step * (x) + (y) * rgb_stride)); \ + const int dst = (x) + (y) * picture->uv_stride; \ + const int r = SUM(r_ptr + src); \ + const int g = SUM(g_ptr + src); \ + const int b = SUM(b_ptr + src); \ + picture->u[dst] = VP8RGBToU(r, g, b); \ + picture->v[dst] = VP8RGBToV(r, g, b); \ +} + +#define RGB_TO_UV0(x_in, x_out, y, SUM) { \ + const int src = (step * (x_in) + (y) * rgb_stride); \ + const int dst = (x_out) + (y) * picture->uv0_stride; \ + const int r = SUM(r_ptr + src); \ + const int g = SUM(g_ptr + src); \ + const int b = SUM(b_ptr + src); \ + picture->u0[dst] = VP8RGBToU(r, g, b); \ + picture->v0[dst] = VP8RGBToV(r, g, b); \ +} + +static void MakeGray(WebPPicture* const picture) { + int y; + const int uv_width = HALVE(picture->width); + const int uv_height = HALVE(picture->height); + for (y = 0; y < uv_height; ++y) { + memset(picture->u + y * picture->uv_stride, 128, uv_width); + memset(picture->v + y * picture->uv_stride, 128, uv_width); + } +} + +static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + const uint8_t* const a_ptr, + int step, // bytes per pixel + int rgb_stride, // bytes per scanline + WebPPicture* const picture) { + const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK; + int x, y; + const int width = picture->width; + const int height = picture->height; + const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); + + picture->colorspace = uv_csp; + picture->use_argb = 0; + if (has_alpha) { + picture->colorspace |= WEBP_CSP_ALPHA_BIT; + } + if (!WebPPictureAlloc(picture)) return 0; + + // Import luma plane + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const int offset = step * x + y * rgb_stride; + picture->y[x + y * picture->y_stride] = + VP8RGBToY(r_ptr[offset], g_ptr[offset], b_ptr[offset]); + } + } + + // Downsample U/V plane + if (uv_csp != WEBP_YUV400) { + for (y = 0; y < (height >> 1); ++y) { + for (x = 0; x < (width >> 1); ++x) { + RGB_TO_UV(x, y, SUM4); + } + if (width & 1) { + RGB_TO_UV(x, y, SUM2V); + } + } + if (height & 1) { + for (x = 0; x < (width >> 1); ++x) { + RGB_TO_UV(x, y, SUM2H); + } + if (width & 1) { + RGB_TO_UV(x, y, SUM1); + } + } + +#ifdef WEBP_EXPERIMENTAL_FEATURES + // Store original U/V samples too + if (uv_csp == WEBP_YUV422) { + for (y = 0; y < height; ++y) { + for (x = 0; x < (width >> 1); ++x) { + RGB_TO_UV0(2 * x, x, y, SUM2H); + } + if (width & 1) { + RGB_TO_UV0(2 * x, x, y, SUM1); + } + } + } else if (uv_csp == WEBP_YUV444) { + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + RGB_TO_UV0(x, x, y, SUM1); + } + } + } +#endif + } else { + MakeGray(picture); + } + + if (has_alpha) { + assert(step >= 4); + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + picture->a[x + y * picture->a_stride] = + a_ptr[step * x + y * rgb_stride]; + } + } + } + return 1; +} + +static int Import(WebPPicture* const picture, + const uint8_t* const rgb, int rgb_stride, + int step, int swap_rb, int import_alpha) { + const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0); + const uint8_t* const g_ptr = rgb + 1; + const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2); + const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL; + const int width = picture->width; + const int height = picture->height; + + if (!picture->use_argb) { + return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, + picture); + } + if (import_alpha) { + picture->colorspace |= WEBP_CSP_ALPHA_BIT; + } else { + picture->colorspace &= ~WEBP_CSP_ALPHA_BIT; + } + if (!WebPPictureAlloc(picture)) return 0; + + if (!import_alpha) { + int x, y; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const int offset = step * x + y * rgb_stride; + const uint32_t argb = + 0xff000000u | + (r_ptr[offset] << 16) | + (g_ptr[offset] << 8) | + (b_ptr[offset]); + picture->argb[x + y * picture->argb_stride] = argb; + } + } + } else { + int x, y; + assert(step >= 4); + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const int offset = step * x + y * rgb_stride; + const uint32_t argb = (a_ptr[offset] << 24) | + (r_ptr[offset] << 16) | + (g_ptr[offset] << 8) | + (b_ptr[offset]); + picture->argb[x + y * picture->argb_stride] = argb; + } + } + } + return 1; +} +#undef SUM4 +#undef SUM2V +#undef SUM2H +#undef SUM1 +#undef RGB_TO_UV + +int WebPPictureImportRGB(WebPPicture* picture, + const uint8_t* rgb, int rgb_stride) { + return Import(picture, rgb, rgb_stride, 3, 0, 0); +} + +int WebPPictureImportBGR(WebPPicture* picture, + const uint8_t* rgb, int rgb_stride) { + return Import(picture, rgb, rgb_stride, 3, 1, 0); +} + +int WebPPictureImportRGBA(WebPPicture* picture, + const uint8_t* rgba, int rgba_stride) { + return Import(picture, rgba, rgba_stride, 4, 0, 1); +} + +int WebPPictureImportBGRA(WebPPicture* picture, + const uint8_t* rgba, int rgba_stride) { + return Import(picture, rgba, rgba_stride, 4, 1, 1); +} + +int WebPPictureImportRGBX(WebPPicture* picture, + const uint8_t* rgba, int rgba_stride) { + return Import(picture, rgba, rgba_stride, 4, 0, 0); +} + +int WebPPictureImportBGRX(WebPPicture* picture, + const uint8_t* rgba, int rgba_stride) { + return Import(picture, rgba, rgba_stride, 4, 1, 0); +} + +//------------------------------------------------------------------------------ +// Automatic YUV <-> ARGB conversions. + +int WebPPictureYUVAToARGB(WebPPicture* picture) { + if (picture == NULL) return 0; + if (picture->memory_ == NULL || picture->y == NULL || + picture->u == NULL || picture->v == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } + if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } + if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + // Allocate a new argb buffer (discarding the previous one). + if (!PictureAllocARGB(picture)) return 0; + + // Convert + { + int y; + const int width = picture->width; + const int height = picture->height; + const int argb_stride = 4 * picture->argb_stride; + uint8_t* dst = (uint8_t*)picture->argb; + const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; + WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST); + + // First row, with replicated top samples. + upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, width); + cur_y += picture->y_stride; + dst += argb_stride; + // Center rows. + for (y = 1; y + 1 < height; y += 2) { + const uint8_t* const top_u = cur_u; + const uint8_t* const top_v = cur_v; + cur_u += picture->uv_stride; + cur_v += picture->uv_stride; + upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v, + dst, dst + argb_stride, width); + cur_y += 2 * picture->y_stride; + dst += 2 * argb_stride; + } + // Last row (if needed), with replicated bottom samples. + if (height > 1 && !(height & 1)) { + upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); + } + // Insert alpha values if needed, in replacement for the default 0xff ones. + if (picture->colorspace & WEBP_CSP_ALPHA_BIT) { + for (y = 0; y < height; ++y) { + uint32_t* const dst = picture->argb + y * picture->argb_stride; + const uint8_t* const src = picture->a + y * picture->a_stride; + int x; + for (x = 0; x < width; ++x) { + dst[x] = (dst[x] & 0x00ffffffu) | (src[x] << 24); + } + } + } + } + return 1; +} + +int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { + if (picture == NULL) return 0; + if (picture->argb == NULL) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); + } else { + const uint8_t* const argb = (const uint8_t*)picture->argb; + const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1; + const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2; + const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3; + const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0; + // We work on a tmp copy of 'picture', because ImportYUVAFromRGBA() + // would be calling WebPPictureFree(picture) otherwise. + WebPPicture tmp = *picture; + PictureResetARGB(&tmp); // reset ARGB buffer so that it's not free()'d. + tmp.use_argb = 0; + tmp.colorspace = colorspace & WEBP_CSP_UV_MASK; + if (!ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, &tmp)) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + } + // Copy back the YUV specs into 'picture'. + tmp.argb = picture->argb; + tmp.argb_stride = picture->argb_stride; + tmp.memory_argb_ = picture->memory_argb_; + *picture = tmp; + } + return 1; +} + +//------------------------------------------------------------------------------ +// Helper: clean up fully transparent area to help compressibility. + +#define SIZE 8 +#define SIZE2 (SIZE / 2) +static int is_transparent_area(const uint8_t* ptr, int stride, int size) { + int y, x; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (ptr[x]) { + return 0; + } + } + ptr += stride; + } + return 1; +} + +static WEBP_INLINE void flatten(uint8_t* ptr, int v, int stride, int size) { + int y; + for (y = 0; y < size; ++y) { + memset(ptr, v, size); + ptr += stride; + } +} + +void WebPCleanupTransparentArea(WebPPicture* pic) { + int x, y, w, h; + const uint8_t* a_ptr; + int values[3] = { 0 }; + + if (pic == NULL) return; + + a_ptr = pic->a; + if (a_ptr == NULL) return; // nothing to do + + w = pic->width / SIZE; + h = pic->height / SIZE; + for (y = 0; y < h; ++y) { + int need_reset = 1; + for (x = 0; x < w; ++x) { + const int off_a = (y * pic->a_stride + x) * SIZE; + const int off_y = (y * pic->y_stride + x) * SIZE; + const int off_uv = (y * pic->uv_stride + x) * SIZE2; + if (is_transparent_area(a_ptr + off_a, pic->a_stride, SIZE)) { + if (need_reset) { + values[0] = pic->y[off_y]; + values[1] = pic->u[off_uv]; + values[2] = pic->v[off_uv]; + need_reset = 0; + } + flatten(pic->y + off_y, values[0], pic->y_stride, SIZE); + flatten(pic->u + off_uv, values[1], pic->uv_stride, SIZE2); + flatten(pic->v + off_uv, values[2], pic->uv_stride, SIZE2); + } else { + need_reset = 1; + } + } + // ignore the left-overs on right/bottom + } +} + +#undef SIZE +#undef SIZE2 + + +//------------------------------------------------------------------------------ +// Distortion + +// Max value returned in case of exact similarity. +static const double kMinDistortion_dB = 99.; + +int WebPPictureDistortion(const WebPPicture* pic1, const WebPPicture* pic2, + int type, float result[5]) { + int c; + DistoStats stats[5]; + int has_alpha; + + if (pic1 == NULL || pic2 == NULL || + pic1->width != pic2->width || pic1->height != pic2->height || + pic1->y == NULL || pic2->y == NULL || + pic1->u == NULL || pic2->u == NULL || + pic1->v == NULL || pic2->v == NULL || + result == NULL) { + return 0; + } + // TODO(skal): provide distortion for ARGB too. + if (pic1->use_argb == 1 || pic1->use_argb != pic2->use_argb) { + return 0; + } + + has_alpha = !!(pic1->colorspace & WEBP_CSP_ALPHA_BIT); + if (has_alpha != !!(pic2->colorspace & WEBP_CSP_ALPHA_BIT) || + (has_alpha && (pic1->a == NULL || pic2->a == NULL))) { + return 0; + } + + memset(stats, 0, sizeof(stats)); + VP8SSIMAccumulatePlane(pic1->y, pic1->y_stride, + pic2->y, pic2->y_stride, + pic1->width, pic1->height, &stats[0]); + VP8SSIMAccumulatePlane(pic1->u, pic1->uv_stride, + pic2->u, pic2->uv_stride, + (pic1->width + 1) >> 1, (pic1->height + 1) >> 1, + &stats[1]); + VP8SSIMAccumulatePlane(pic1->v, pic1->uv_stride, + pic2->v, pic2->uv_stride, + (pic1->width + 1) >> 1, (pic1->height + 1) >> 1, + &stats[2]); + if (has_alpha) { + VP8SSIMAccumulatePlane(pic1->a, pic1->a_stride, + pic2->a, pic2->a_stride, + pic1->width, pic1->height, &stats[3]); + } + for (c = 0; c <= 4; ++c) { + if (type == 1) { + const double v = VP8SSIMGet(&stats[c]); + result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v) + : kMinDistortion_dB); + } else { + const double v = VP8SSIMGetSquaredError(&stats[c]); + result[c] = (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.)) + : kMinDistortion_dB); + } + // Accumulate forward + if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]); + } + return 1; +} + +//------------------------------------------------------------------------------ +// Simplest high-level calls: + +typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int); + +static size_t Encode(const uint8_t* rgba, int width, int height, int stride, + Importer import, float quality_factor, int lossless, + uint8_t** output) { + WebPPicture pic; + WebPConfig config; + WebPMemoryWriter wrt; + int ok; + + if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) || + !WebPPictureInit(&pic)) { + return 0; // shouldn't happen, except if system installation is broken + } + + config.lossless = !!lossless; + pic.use_argb = !!lossless; + pic.width = width; + pic.height = height; + pic.writer = WebPMemoryWrite; + pic.custom_ptr = &wrt; + WebPMemoryWriterInit(&wrt); + + ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic); + WebPPictureFree(&pic); + if (!ok) { + free(wrt.mem); + *output = NULL; + return 0; + } + *output = wrt.mem; + return wrt.size; +} + +#define ENCODE_FUNC(NAME, IMPORTER) \ +size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \ + uint8_t** out) { \ + return Encode(in, w, h, bps, IMPORTER, q, 0, out); \ +} + +ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB); +ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR); +ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA); +ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA); + +#undef ENCODE_FUNC + +#define LOSSLESS_DEFAULT_QUALITY 70. +#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \ +size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \ + return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \ +} + +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB); +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR); +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA); +LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA); + +#undef LOSSLESS_ENCODE_FUNC + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/quant.c b/external/libwebp/enc/quant.c new file mode 100644 index 0000000000..ea153849c8 --- /dev/null +++ b/external/libwebp/enc/quant.c @@ -0,0 +1,930 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Quantization +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include + +#include "./vp8enci.h" +#include "./cost.h" + +#define DO_TRELLIS_I4 1 +#define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. +#define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. +#define USE_TDISTO 1 + +#define MID_ALPHA 64 // neutral value for susceptibility +#define MIN_ALPHA 30 // lowest usable value for susceptibility +#define MAX_ALPHA 100 // higher meaninful value for susceptibility + +#define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP + // power-law modulation. Must be strictly less than 1. + +#define MULT_8B(a, b) (((a) * (b) + 128) >> 8) + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int clip(int v, int m, int M) { + return v < m ? m : v > M ? M : v; +} + +static const uint8_t kZigzag[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +static const uint8_t kDcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, + 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, + 138, 140, 143, 145, 148, 151, 154, 157 +}; + +static const uint16_t kAcTable[128] = { + 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, + 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, + 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, + 249, 254, 259, 264, 269, 274, 279, 284 +}; + +static const uint16_t kAcTable2[128] = { + 8, 8, 9, 10, 12, 13, 15, 17, + 18, 20, 21, 23, 24, 26, 27, 29, + 31, 32, 34, 35, 37, 38, 40, 41, + 43, 44, 46, 48, 49, 51, 52, 54, + 55, 57, 58, 60, 62, 63, 65, 66, + 68, 69, 71, 72, 74, 75, 77, 79, + 80, 82, 83, 85, 86, 88, 89, 93, + 96, 99, 102, 105, 108, 111, 114, 117, + 120, 124, 127, 130, 133, 136, 139, 142, + 145, 148, 151, 155, 158, 161, 164, 167, + 170, 173, 176, 179, 184, 189, 193, 198, + 203, 207, 212, 217, 221, 226, 230, 235, + 240, 244, 249, 254, 258, 263, 268, 274, + 280, 286, 292, 299, 305, 311, 317, 323, + 330, 336, 342, 348, 354, 362, 370, 379, + 385, 393, 401, 409, 416, 424, 432, 440 +}; + +static const uint16_t kCoeffThresh[16] = { + 0, 10, 20, 30, + 10, 20, 30, 30, + 20, 30, 30, 30, + 30, 30, 30, 30 +}; + +// TODO(skal): tune more. Coeff thresholding? +static const uint8_t kBiasMatrices[3][16] = { // [3] = [luma-ac,luma-dc,chroma] + { 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96 }, + { 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96 }, + { 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96, + 96, 96, 96, 96 } +}; + +// Sharpening by (slightly) raising the hi-frequency coeffs (only for trellis). +// Hack-ish but helpful for mid-bitrate range. Use with care. +static const uint8_t kFreqSharpening[16] = { + 0, 30, 60, 90, + 30, 60, 90, 90, + 60, 90, 90, 90, + 90, 90, 90, 90 +}; + +//------------------------------------------------------------------------------ +// Initialize quantization parameters in VP8Matrix + +// Returns the average quantizer +static int ExpandMatrix(VP8Matrix* const m, int type) { + int i; + int sum = 0; + for (i = 2; i < 16; ++i) { + m->q_[i] = m->q_[1]; + } + for (i = 0; i < 16; ++i) { + const int j = kZigzag[i]; + const int bias = kBiasMatrices[type][j]; + m->iq_[j] = (1 << QFIX) / m->q_[j]; + m->bias_[j] = BIAS(bias); + // TODO(skal): tune kCoeffThresh[] + m->zthresh_[j] = ((256 /*+ kCoeffThresh[j]*/ - bias) * m->q_[j] + 127) >> 8; + m->sharpen_[j] = (kFreqSharpening[j] * m->q_[j]) >> 11; + sum += m->q_[j]; + } + return (sum + 8) >> 4; +} + +static void SetupMatrices(VP8Encoder* enc) { + int i; + const int tlambda_scale = + (enc->method_ >= 4) ? enc->config_->sns_strength + : 0; + const int num_segments = enc->segment_hdr_.num_segments_; + for (i = 0; i < num_segments; ++i) { + VP8SegmentInfo* const m = &enc->dqm_[i]; + const int q = m->quant_; + int q4, q16, quv; + m->y1_.q_[0] = kDcTable[clip(q + enc->dq_y1_dc_, 0, 127)]; + m->y1_.q_[1] = kAcTable[clip(q, 0, 127)]; + + m->y2_.q_[0] = kDcTable[ clip(q + enc->dq_y2_dc_, 0, 127)] * 2; + m->y2_.q_[1] = kAcTable2[clip(q + enc->dq_y2_ac_, 0, 127)]; + + m->uv_.q_[0] = kDcTable[clip(q + enc->dq_uv_dc_, 0, 117)]; + m->uv_.q_[1] = kAcTable[clip(q + enc->dq_uv_ac_, 0, 127)]; + + q4 = ExpandMatrix(&m->y1_, 0); + q16 = ExpandMatrix(&m->y2_, 1); + quv = ExpandMatrix(&m->uv_, 2); + + // TODO: Switch to kLambda*[] tables? + { + m->lambda_i4_ = (3 * q4 * q4) >> 7; + m->lambda_i16_ = (3 * q16 * q16); + m->lambda_uv_ = (3 * quv * quv) >> 6; + m->lambda_mode_ = (1 * q4 * q4) >> 7; + m->lambda_trellis_i4_ = (7 * q4 * q4) >> 3; + m->lambda_trellis_i16_ = (q16 * q16) >> 2; + m->lambda_trellis_uv_ = (quv *quv) << 1; + m->tlambda_ = (tlambda_scale * q4) >> 5; + } + } +} + +//------------------------------------------------------------------------------ +// Initialize filtering parameters + +// Very small filter-strength values have close to no visual effect. So we can +// save a little decoding-CPU by turning filtering off for these. +#define FSTRENGTH_CUTOFF 3 + +static void SetupFilterStrength(VP8Encoder* const enc) { + int i; + const int level0 = enc->config_->filter_strength; + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + // Segments with lower quantizer will be less filtered. TODO: tune (wrt SNS) + const int level = level0 * 256 * enc->dqm_[i].quant_ / 128; + const int f = level / (256 + enc->dqm_[i].beta_); + enc->dqm_[i].fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f; + } + // We record the initial strength (mainly for the case of 1-segment only). + enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_; + enc->filter_hdr_.simple_ = (enc->config_->filter_type == 0); + enc->filter_hdr_.sharpness_ = enc->config_->filter_sharpness; +} + +//------------------------------------------------------------------------------ + +// Note: if you change the values below, remember that the max range +// allowed by the syntax for DQ_UV is [-16,16]. +#define MAX_DQ_UV (6) +#define MIN_DQ_UV (-4) + +// We want to emulate jpeg-like behaviour where the expected "good" quality +// is around q=75. Internally, our "good" middle is around c=50. So we +// map accordingly using linear piece-wise function +static double QualityToCompression(double q) { + const double c = q / 100.; + return (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.; +} + +void VP8SetSegmentParams(VP8Encoder* const enc, float quality) { + int i; + int dq_uv_ac, dq_uv_dc; + const int num_segments = enc->config_->segments; + const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.; + const double c_base = QualityToCompression(quality); + for (i = 0; i < num_segments; ++i) { + // The file size roughly scales as pow(quantizer, 3.). Actually, the + // exponent is somewhere between 2.8 and 3.2, but we're mostly interested + // in the mid-quant range. So we scale the compressibility inversely to + // this power-law: quant ~= compression ^ 1/3. This law holds well for + // low quant. Finer modelling for high-quant would make use of kAcTable[] + // more explicitely. + // Additionally, we modulate the base exponent 1/3 to accommodate for the + // quantization susceptibility and allow denser segments to be quantized + // more. + const double expn = (1. - amp * enc->dqm_[i].alpha_) / 3.; + const double c = pow(c_base, expn); + const int q = (int)(127. * (1. - c)); + assert(expn > 0.); + enc->dqm_[i].quant_ = clip(q, 0, 127); + } + + // purely indicative in the bitstream (except for the 1-segment case) + enc->base_quant_ = enc->dqm_[0].quant_; + + // fill-in values for the unused segments (required by the syntax) + for (i = num_segments; i < NUM_MB_SEGMENTS; ++i) { + enc->dqm_[i].quant_ = enc->base_quant_; + } + + // uv_alpha_ is normally spread around ~60. The useful range is + // typically ~30 (quite bad) to ~100 (ok to decimate UV more). + // We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv. + dq_uv_ac = (enc->uv_alpha_ - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV) + / (MAX_ALPHA - MIN_ALPHA); + // we rescale by the user-defined strength of adaptation + dq_uv_ac = dq_uv_ac * enc->config_->sns_strength / 100; + // and make it safe. + dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV); + // We also boost the dc-uv-quant a little, based on sns-strength, since + // U/V channels are quite more reactive to high quants (flat DC-blocks + // tend to appear, and are displeasant). + dq_uv_dc = -4 * enc->config_->sns_strength / 100; + dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed + + enc->dq_y1_dc_ = 0; // TODO(skal): dq-lum + enc->dq_y2_dc_ = 0; + enc->dq_y2_ac_ = 0; + enc->dq_uv_dc_ = dq_uv_dc; + enc->dq_uv_ac_ = dq_uv_ac; + + SetupMatrices(enc); + + SetupFilterStrength(enc); // initialize segments' filtering, eventually +} + +//------------------------------------------------------------------------------ +// Form the predictions in cache + +// Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index +const int VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 }; +const int VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 }; + +// Must be indexed using {B_DC_PRED -> B_HU_PRED} as index +const int VP8I4ModeOffsets[NUM_BMODES] = { + I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 +}; + +void VP8MakeLuma16Preds(const VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const left = it->x_ ? enc->y_left_ : NULL; + const uint8_t* const top = it->y_ ? enc->y_top_ + it->x_ * 16 : NULL; + VP8EncPredLuma16(it->yuv_p_, left, top); +} + +void VP8MakeChroma8Preds(const VP8EncIterator* const it) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const left = it->x_ ? enc->u_left_ : NULL; + const uint8_t* const top = it->y_ ? enc->uv_top_ + it->x_ * 16 : NULL; + VP8EncPredChroma8(it->yuv_p_, left, top); +} + +void VP8MakeIntra4Preds(const VP8EncIterator* const it) { + VP8EncPredLuma4(it->yuv_p_, it->i4_top_); +} + +//------------------------------------------------------------------------------ +// Quantize + +// Layout: +// +----+ +// |YYYY| 0 +// |YYYY| 4 +// |YYYY| 8 +// |YYYY| 12 +// +----+ +// |UUVV| 16 +// |UUVV| 20 +// +----+ + +const int VP8Scan[16 + 4 + 4] = { + // Luma + 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, + 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, + 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, + 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, + + 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U + 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V +}; + +//------------------------------------------------------------------------------ +// Distortion measurement + +static const uint16_t kWeightY[16] = { + 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2 +}; + +static const uint16_t kWeightTrellis[16] = { +#if USE_TDISTO == 0 + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 +#else + 30, 27, 19, 11, + 27, 24, 17, 10, + 19, 17, 12, 8, + 11, 10, 8, 6 +#endif +}; + +// Init/Copy the common fields in score. +static void InitScore(VP8ModeScore* const rd) { + rd->D = 0; + rd->SD = 0; + rd->R = 0; + rd->nz = 0; + rd->score = MAX_COST; +} + +static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) { + dst->D = src->D; + dst->SD = src->SD; + dst->R = src->R; + dst->nz = src->nz; // note that nz is not accumulated, but just copied. + dst->score = src->score; +} + +static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) { + dst->D += src->D; + dst->SD += src->SD; + dst->R += src->R; + dst->nz |= src->nz; // here, new nz bits are accumulated. + dst->score += src->score; +} + +//------------------------------------------------------------------------------ +// Performs trellis-optimized quantization. + +// Trellis + +typedef struct { + int prev; // best previous + int level; // level + int sign; // sign of coeff_i + score_t cost; // bit cost + score_t error; // distortion = sum of (|coeff_i| - level_i * Q_i)^2 + int ctx; // context (only depends on 'level'. Could be spared.) +} Node; + +// If a coefficient was quantized to a value Q (using a neutral bias), +// we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA] +// We don't test negative values though. +#define MIN_DELTA 0 // how much lower level to try +#define MAX_DELTA 1 // how much higher +#define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA) +#define NODE(n, l) (nodes[(n) + 1][(l) + MIN_DELTA]) + +static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) { + // TODO: incorporate the "* 256" in the tables? + rd->score = rd->R * lambda + 256 * (rd->D + rd->SD); +} + +static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate, + score_t distortion) { + return rate * lambda + 256 * distortion; +} + +static int TrellisQuantizeBlock(const VP8EncIterator* const it, + int16_t in[16], int16_t out[16], + int ctx0, int coeff_type, + const VP8Matrix* const mtx, + int lambda) { + ProbaArray* const last_costs = it->enc_->proba_.coeffs_[coeff_type]; + CostArray* const costs = it->enc_->proba_.level_cost_[coeff_type]; + const int first = (coeff_type == 0) ? 1 : 0; + Node nodes[17][NUM_NODES]; + int best_path[3] = {-1, -1, -1}; // store best-last/best-level/best-previous + score_t best_score; + int best_node; + int last = first - 1; + int n, m, p, nz; + + { + score_t cost; + score_t max_error; + const int thresh = mtx->q_[1] * mtx->q_[1] / 4; + const int last_proba = last_costs[VP8EncBands[first]][ctx0][0]; + + // compute maximal distortion. + max_error = 0; + for (n = first; n < 16; ++n) { + const int j = kZigzag[n]; + const int err = in[j] * in[j]; + max_error += kWeightTrellis[j] * err; + if (err > thresh) last = n; + } + // we don't need to go inspect up to n = 16 coeffs. We can just go up + // to last + 1 (inclusive) without losing much. + if (last < 15) ++last; + + // compute 'skip' score. This is the max score one can do. + cost = VP8BitCost(0, last_proba); + best_score = RDScoreTrellis(lambda, cost, max_error); + + // initialize source node. + n = first - 1; + for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { + NODE(n, m).cost = 0; + NODE(n, m).error = max_error; + NODE(n, m).ctx = ctx0; + } + } + + // traverse trellis. + for (n = first; n <= last; ++n) { + const int j = kZigzag[n]; + const int Q = mtx->q_[j]; + const int iQ = mtx->iq_[j]; + const int B = BIAS(0x00); // neutral bias + // note: it's important to take sign of the _original_ coeff, + // so we don't have to consider level < 0 afterward. + const int sign = (in[j] < 0); + int coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; + int level0; + if (coeff0 > 2047) coeff0 = 2047; + + level0 = QUANTDIV(coeff0, iQ, B); + // test all alternate level values around level0. + for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { + Node* const cur = &NODE(n, m); + int delta_error, new_error; + score_t cur_score = MAX_COST; + int level = level0 + m; + int last_proba; + + cur->sign = sign; + cur->level = level; + cur->ctx = (level == 0) ? 0 : (level == 1) ? 1 : 2; + if (level >= 2048 || level < 0) { // node is dead? + cur->cost = MAX_COST; + continue; + } + last_proba = last_costs[VP8EncBands[n + 1]][cur->ctx][0]; + + // Compute delta_error = how much coding this level will + // subtract as distortion to max_error + new_error = coeff0 - level * Q; + delta_error = + kWeightTrellis[j] * (coeff0 * coeff0 - new_error * new_error); + + // Inspect all possible non-dead predecessors. Retain only the best one. + for (p = -MIN_DELTA; p <= MAX_DELTA; ++p) { + const Node* const prev = &NODE(n - 1, p); + const int prev_ctx = prev->ctx; + const uint16_t* const tcost = costs[VP8EncBands[n]][prev_ctx]; + const score_t total_error = prev->error - delta_error; + score_t cost, base_cost, score; + + if (prev->cost >= MAX_COST) { // dead node? + continue; + } + + // Base cost of both terminal/non-terminal + base_cost = prev->cost + VP8LevelCost(tcost, level); + + // Examine node assuming it's a non-terminal one. + cost = base_cost; + if (level && n < 15) { + cost += VP8BitCost(1, last_proba); + } + score = RDScoreTrellis(lambda, cost, total_error); + if (score < cur_score) { + cur_score = score; + cur->cost = cost; + cur->error = total_error; + cur->prev = p; + } + + // Now, record best terminal node (and thus best entry in the graph). + if (level) { + cost = base_cost; + if (n < 15) cost += VP8BitCost(0, last_proba); + score = RDScoreTrellis(lambda, cost, total_error); + if (score < best_score) { + best_score = score; + best_path[0] = n; // best eob position + best_path[1] = m; // best level + best_path[2] = p; // best predecessor + } + } + } + } + } + + // Fresh start + memset(in + first, 0, (16 - first) * sizeof(*in)); + memset(out + first, 0, (16 - first) * sizeof(*out)); + if (best_path[0] == -1) { + return 0; // skip! + } + + // Unwind the best path. + // Note: best-prev on terminal node is not necessarily equal to the + // best_prev for non-terminal. So we patch best_path[2] in. + n = best_path[0]; + best_node = best_path[1]; + NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal + nz = 0; + + for (; n >= first; --n) { + const Node* const node = &NODE(n, best_node); + const int j = kZigzag[n]; + out[n] = node->sign ? -node->level : node->level; + nz |= (node->level != 0); + in[j] = out[n] * mtx->q_[j]; + best_node = node->prev; + } + return nz; +} + +#undef NODE + +//------------------------------------------------------------------------------ +// Performs: difference, transform, quantize, back-transform, add +// all at once. Output is the reconstructed block in *yuv_out, and the +// quantized levels in *levels. + +static int ReconstructIntra16(VP8EncIterator* const it, + VP8ModeScore* const rd, + uint8_t* const yuv_out, + int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; + const uint8_t* const src = it->yuv_in_ + Y_OFF; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int n; + int16_t tmp[16][16], dc_tmp[16]; + + for (n = 0; n < 16; ++n) { + VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]); + } + VP8FTransformWHT(tmp[0], dc_tmp); + nz |= VP8EncQuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24; + + if (DO_TRELLIS_I16 && it->do_trellis_) { + int x, y; + VP8IteratorNzToBytes(it); + for (y = 0, n = 0; y < 4; ++y) { + for (x = 0; x < 4; ++x, ++n) { + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + const int non_zero = + TrellisQuantizeBlock(it, tmp[n], rd->y_ac_levels[n], ctx, 0, + &dqm->y1_, dqm->lambda_trellis_i16_); + it->top_nz_[x] = it->left_nz_[y] = non_zero; + nz |= non_zero << n; + } + } + } else { + for (n = 0; n < 16; ++n) { + nz |= VP8EncQuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n; + } + } + + // Transform back + VP8ITransformWHT(dc_tmp, tmp[0]); + for (n = 0; n < 16; n += 2) { + VP8ITransform(ref + VP8Scan[n], tmp[n], yuv_out + VP8Scan[n], 1); + } + + return nz; +} + +static int ReconstructIntra4(VP8EncIterator* const it, + int16_t levels[16], + const uint8_t* const src, + uint8_t* const yuv_out, + int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int16_t tmp[16]; + + VP8FTransform(src, ref, tmp); + if (DO_TRELLIS_I4 && it->do_trellis_) { + const int x = it->i4_ & 3, y = it->i4_ >> 2; + const int ctx = it->top_nz_[x] + it->left_nz_[y]; + nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_, + dqm->lambda_trellis_i4_); + } else { + nz = VP8EncQuantizeBlock(tmp, levels, 0, &dqm->y1_); + } + VP8ITransform(ref, tmp, yuv_out, 0); + return nz; +} + +static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd, + uint8_t* const yuv_out, int mode) { + const VP8Encoder* const enc = it->enc_; + const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; + const uint8_t* const src = it->yuv_in_ + U_OFF; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + int nz = 0; + int n; + int16_t tmp[8][16]; + + for (n = 0; n < 8; ++n) { + VP8FTransform(src + VP8Scan[16 + n], ref + VP8Scan[16 + n], tmp[n]); + } + if (DO_TRELLIS_UV && it->do_trellis_) { + int ch, x, y; + for (ch = 0, n = 0; ch <= 2; ch += 2) { + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x, ++n) { + const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; + const int non_zero = + TrellisQuantizeBlock(it, tmp[n], rd->uv_levels[n], ctx, 2, + &dqm->uv_, dqm->lambda_trellis_uv_); + it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero; + nz |= non_zero << n; + } + } + } + } else { + for (n = 0; n < 8; ++n) { + nz |= VP8EncQuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n; + } + } + + for (n = 0; n < 8; n += 2) { + VP8ITransform(ref + VP8Scan[16 + n], tmp[n], yuv_out + VP8Scan[16 + n], 1); + } + return (nz << 16); +} + +//------------------------------------------------------------------------------ +// RD-opt decision. Reconstruct each modes, evalue distortion and bit-cost. +// Pick the mode is lower RD-cost = Rate + lamba * Distortion. + +static void SwapPtr(uint8_t** a, uint8_t** b) { + uint8_t* const tmp = *a; + *a = *b; + *b = tmp; +} + +static void SwapOut(VP8EncIterator* const it) { + SwapPtr(&it->yuv_out_, &it->yuv_out2_); +} + +static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* const rd) { + const VP8Encoder* const enc = it->enc_; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_i16_; + const int tlambda = dqm->tlambda_; + const uint8_t* const src = it->yuv_in_ + Y_OFF; + VP8ModeScore rd16; + int mode; + + rd->mode_i16 = -1; + for (mode = 0; mode < 4; ++mode) { + uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF; // scratch buffer + int nz; + + // Reconstruct + nz = ReconstructIntra16(it, &rd16, tmp_dst, mode); + + // Measure RD-score + rd16.D = VP8SSE16x16(src, tmp_dst); + rd16.SD = tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) + : 0; + rd16.R = VP8GetCostLuma16(it, &rd16); + rd16.R += VP8FixedCostsI16[mode]; + + // Since we always examine Intra16 first, we can overwrite *rd directly. + SetRDScore(lambda, &rd16); + if (mode == 0 || rd16.score < rd->score) { + CopyScore(rd, &rd16); + rd->mode_i16 = mode; + rd->nz = nz; + memcpy(rd->y_ac_levels, rd16.y_ac_levels, sizeof(rd16.y_ac_levels)); + memcpy(rd->y_dc_levels, rd16.y_dc_levels, sizeof(rd16.y_dc_levels)); + SwapOut(it); + } + } + SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. + VP8SetIntra16Mode(it, rd->mode_i16); +} + +//------------------------------------------------------------------------------ + +// return the cost array corresponding to the surrounding prediction modes. +static const uint16_t* GetCostModeI4(VP8EncIterator* const it, + const uint8_t modes[16]) { + const int preds_w = it->enc_->preds_w_; + const int x = (it->i4_ & 3), y = it->i4_ >> 2; + const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; + const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; + return VP8FixedCostsI4[top][left]; +} + +static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) { + const VP8Encoder* const enc = it->enc_; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_i4_; + const int tlambda = dqm->tlambda_; + const uint8_t* const src0 = it->yuv_in_ + Y_OFF; + uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF; + int total_header_bits = 0; + VP8ModeScore rd_best; + + if (enc->max_i4_header_bits_ == 0) { + return 0; + } + + InitScore(&rd_best); + rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145) + VP8IteratorStartI4(it); + do { + VP8ModeScore rd_i4; + int mode; + int best_mode = -1; + const uint8_t* const src = src0 + VP8Scan[it->i4_]; + const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); + uint8_t* best_block = best_blocks + VP8Scan[it->i4_]; + uint8_t* tmp_dst = it->yuv_p_ + I4TMP; // scratch buffer. + + InitScore(&rd_i4); + VP8MakeIntra4Preds(it); + for (mode = 0; mode < NUM_BMODES; ++mode) { + VP8ModeScore rd_tmp; + int16_t tmp_levels[16]; + + // Reconstruct + rd_tmp.nz = + ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4_; + + // Compute RD-score + rd_tmp.D = VP8SSE4x4(src, tmp_dst); + rd_tmp.SD = + tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY)) + : 0; + rd_tmp.R = VP8GetCostLuma4(it, tmp_levels); + rd_tmp.R += mode_costs[mode]; + + SetRDScore(lambda, &rd_tmp); + if (best_mode < 0 || rd_tmp.score < rd_i4.score) { + CopyScore(&rd_i4, &rd_tmp); + best_mode = mode; + SwapPtr(&tmp_dst, &best_block); + memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, sizeof(tmp_levels)); + } + } + SetRDScore(dqm->lambda_mode_, &rd_i4); + AddScore(&rd_best, &rd_i4); + total_header_bits += mode_costs[best_mode]; + if (rd_best.score >= rd->score || + total_header_bits > enc->max_i4_header_bits_) { + return 0; + } + // Copy selected samples if not in the right place already. + if (best_block != best_blocks + VP8Scan[it->i4_]) + VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]); + rd->modes_i4[it->i4_] = best_mode; + it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0); + } while (VP8IteratorRotateI4(it, best_blocks)); + + // finalize state + CopyScore(rd, &rd_best); + VP8SetIntra4Mode(it, rd->modes_i4); + SwapOut(it); + memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels)); + return 1; // select intra4x4 over intra16x16 +} + +//------------------------------------------------------------------------------ + +static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { + const VP8Encoder* const enc = it->enc_; + const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; + const int lambda = dqm->lambda_uv_; + const uint8_t* const src = it->yuv_in_ + U_OFF; + uint8_t* const tmp_dst = it->yuv_out2_ + U_OFF; // scratch buffer + uint8_t* const dst0 = it->yuv_out_ + U_OFF; + VP8ModeScore rd_best; + int mode; + + rd->mode_uv = -1; + InitScore(&rd_best); + for (mode = 0; mode < 4; ++mode) { + VP8ModeScore rd_uv; + + // Reconstruct + rd_uv.nz = ReconstructUV(it, &rd_uv, tmp_dst, mode); + + // Compute RD-score + rd_uv.D = VP8SSE16x8(src, tmp_dst); + rd_uv.SD = 0; // TODO: should we call TDisto? it tends to flatten areas. + rd_uv.R = VP8GetCostUV(it, &rd_uv); + rd_uv.R += VP8FixedCostsUV[mode]; + + SetRDScore(lambda, &rd_uv); + if (mode == 0 || rd_uv.score < rd_best.score) { + CopyScore(&rd_best, &rd_uv); + rd->mode_uv = mode; + memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels)); + memcpy(dst0, tmp_dst, UV_SIZE); // TODO: SwapUVOut() ? + } + } + VP8SetIntraUVMode(it, rd->mode_uv); + AddScore(rd, &rd_best); +} + +//------------------------------------------------------------------------------ +// Final reconstruction and quantization. + +static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) { + const VP8Encoder* const enc = it->enc_; + const int i16 = (it->mb_->type_ == 1); + int nz = 0; + + if (i16) { + nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF, it->preds_[0]); + } else { + VP8IteratorStartI4(it); + do { + const int mode = + it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_]; + const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_]; + uint8_t* const dst = it->yuv_out_ + Y_OFF + VP8Scan[it->i4_]; + VP8MakeIntra4Preds(it); + nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], + src, dst, mode) << it->i4_; + } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF)); + } + + nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF, it->mb_->uv_mode_); + rd->nz = nz; +} + +//------------------------------------------------------------------------------ +// Entry point + +int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt) { + int is_skipped; + + InitScore(rd); + + // We can perform predictions for Luma16x16 and Chroma8x8 already. + // Luma4x4 predictions needs to be done as-we-go. + VP8MakeLuma16Preds(it); + VP8MakeChroma8Preds(it); + + // for rd_opt = 2, we perform trellis-quant on the final decision only. + // for rd_opt > 2, we use it for every scoring (=much slower). + if (rd_opt > 0) { + it->do_trellis_ = (rd_opt > 2); + PickBestIntra16(it, rd); + if (it->enc_->method_ >= 2) { + PickBestIntra4(it, rd); + } + PickBestUV(it, rd); + if (rd_opt == 2) { + it->do_trellis_ = 1; + SimpleQuantize(it, rd); + } + } else { + // TODO: for method_ == 2, pick the best intra4/intra16 based on SSE + it->do_trellis_ = (it->enc_->method_ == 2); + SimpleQuantize(it, rd); + } + is_skipped = (rd->nz == 0); + VP8SetSkip(it, is_skipped); + return is_skipped; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/syntax.c b/external/libwebp/enc/syntax.c new file mode 100644 index 0000000000..7c8c7b1a84 --- /dev/null +++ b/external/libwebp/enc/syntax.c @@ -0,0 +1,437 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Header syntax writing +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "../webp/format_constants.h" +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Helper functions + +// TODO(later): Move to webp/format_constants.h? +static void PutLE24(uint8_t* const data, uint32_t val) { + data[0] = (val >> 0) & 0xff; + data[1] = (val >> 8) & 0xff; + data[2] = (val >> 16) & 0xff; +} + +static void PutLE32(uint8_t* const data, uint32_t val) { + PutLE24(data, val); + data[3] = (val >> 24) & 0xff; +} + +static int IsVP8XNeeded(const VP8Encoder* const enc) { + return !!enc->has_alpha_; // Currently the only case when VP8X is needed. + // This could change in the future. +} + +static int PutPaddingByte(const WebPPicture* const pic) { + + const uint8_t pad_byte[1] = { 0 }; + return !!pic->writer(pad_byte, 1, pic); +} + +//------------------------------------------------------------------------------ +// Writers for header's various pieces (in order of appearance) + +static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc, + size_t riff_size) { + const WebPPicture* const pic = enc->pic_; + uint8_t riff[RIFF_HEADER_SIZE] = { + 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P' + }; + assert(riff_size == (uint32_t)riff_size); + PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); + if (!pic->writer(riff, sizeof(riff), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { + const WebPPicture* const pic = enc->pic_; + uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = { + 'V', 'P', '8', 'X' + }; + uint32_t flags = 0; + + assert(IsVP8XNeeded(enc)); + assert(pic->width >= 1 && pic->height >= 1); + assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE); + + if (enc->has_alpha_) { + flags |= ALPHA_FLAG_BIT; + } + + PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); + PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1); + PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1); + if(!pic->writer(vp8x, sizeof(vp8x), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) { + const WebPPicture* const pic = enc->pic_; + uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = { + 'A', 'L', 'P', 'H' + }; + + assert(enc->has_alpha_); + + // Alpha chunk header. + PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_); + if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + + // Alpha chunk data. + if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + + // Padding. + if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8Header(const WebPPicture* const pic, + size_t vp8_size) { + uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = { + 'V', 'P', '8', ' ' + }; + assert(vp8_size == (uint32_t)vp8_size); + PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size); + if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic, + int profile, size_t size0) { + uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE]; + uint32_t bits; + + if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit + return VP8_ENC_ERROR_PARTITION0_OVERFLOW; + } + + // Paragraph 9.1. + bits = 0 // keyframe (1b) + | (profile << 1) // profile (3b) + | (1 << 4) // visible (1b) + | ((uint32_t)size0 << 5); // partition length (19b) + vp8_frm_hdr[0] = (bits >> 0) & 0xff; + vp8_frm_hdr[1] = (bits >> 8) & 0xff; + vp8_frm_hdr[2] = (bits >> 16) & 0xff; + // signature + vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff; + vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff; + vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff; + // dimensions + vp8_frm_hdr[6] = pic->width & 0xff; + vp8_frm_hdr[7] = pic->width >> 8; + vp8_frm_hdr[8] = pic->height & 0xff; + vp8_frm_hdr[9] = pic->height >> 8; + + if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +// WebP Headers. +static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0, + size_t vp8_size, size_t riff_size) { + WebPPicture* const pic = enc->pic_; + WebPEncodingError err = VP8_ENC_OK; + + // RIFF header. + err = PutRIFFHeader(enc, riff_size); + if (err != VP8_ENC_OK) goto Error; + + // VP8X. + if (IsVP8XNeeded(enc)) { + err = PutVP8XHeader(enc); + if (err != VP8_ENC_OK) goto Error; + } + + // Alpha. + if (enc->has_alpha_) { + err = PutAlphaChunk(enc); + if (err != VP8_ENC_OK) goto Error; + } + + // VP8 header. + err = PutVP8Header(pic, vp8_size); + if (err != VP8_ENC_OK) goto Error; + + // VP8 frame header. + err = PutVP8FrameHeader(pic, enc->profile_, size0); + if (err != VP8_ENC_OK) goto Error; + + // All OK. + return 1; + + // Error. + Error: + return WebPEncodingSetError(pic, err); +} + +// Segmentation header +static void PutSegmentHeader(VP8BitWriter* const bw, + const VP8Encoder* const enc) { + const VP8SegmentHeader* const hdr = &enc->segment_hdr_; + const VP8Proba* const proba = &enc->proba_; + if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) { + // We always 'update' the quant and filter strength values + const int update_data = 1; + int s; + VP8PutBitUniform(bw, hdr->update_map_); + if (VP8PutBitUniform(bw, update_data)) { + // we always use absolute values, not relative ones + VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.) + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + VP8PutSignedValue(bw, enc->dqm_[s].quant_, 7); + } + for (s = 0; s < NUM_MB_SEGMENTS; ++s) { + VP8PutSignedValue(bw, enc->dqm_[s].fstrength_, 6); + } + } + if (hdr->update_map_) { + for (s = 0; s < 3; ++s) { + if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) { + VP8PutValue(bw, proba->segments_[s], 8); + } + } + } + } +} + +// Filtering parameters header +static void PutFilterHeader(VP8BitWriter* const bw, + const VP8FilterHeader* const hdr) { + const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0); + VP8PutBitUniform(bw, hdr->simple_); + VP8PutValue(bw, hdr->level_, 6); + VP8PutValue(bw, hdr->sharpness_, 3); + if (VP8PutBitUniform(bw, use_lf_delta)) { + // '0' is the default value for i4x4_lf_delta_ at frame #0. + const int need_update = (hdr->i4x4_lf_delta_ != 0); + if (VP8PutBitUniform(bw, need_update)) { + // we don't use ref_lf_delta => emit four 0 bits + VP8PutValue(bw, 0, 4); + // we use mode_lf_delta for i4x4 + VP8PutSignedValue(bw, hdr->i4x4_lf_delta_, 6); + VP8PutValue(bw, 0, 3); // all others unused + } + } +} + +// Nominal quantization parameters +static void PutQuant(VP8BitWriter* const bw, + const VP8Encoder* const enc) { + VP8PutValue(bw, enc->base_quant_, 7); + VP8PutSignedValue(bw, enc->dq_y1_dc_, 4); + VP8PutSignedValue(bw, enc->dq_y2_dc_, 4); + VP8PutSignedValue(bw, enc->dq_y2_ac_, 4); + VP8PutSignedValue(bw, enc->dq_uv_dc_, 4); + VP8PutSignedValue(bw, enc->dq_uv_ac_, 4); +} + +// Partition sizes +static int EmitPartitionsSize(const VP8Encoder* const enc, + WebPPicture* const pic) { + uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; + int p; + for (p = 0; p < enc->num_parts_ - 1; ++p) { + const size_t part_size = VP8BitWriterSize(enc->parts_ + p); + if (part_size >= VP8_MAX_PARTITION_SIZE) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW); + } + buf[3 * p + 0] = (part_size >> 0) & 0xff; + buf[3 * p + 1] = (part_size >> 8) & 0xff; + buf[3 * p + 2] = (part_size >> 16) & 0xff; + } + return p ? pic->writer(buf, 3 * p, pic) : 1; +} + +//------------------------------------------------------------------------------ + +#ifdef WEBP_EXPERIMENTAL_FEATURES + +#define KTRAILER_SIZE 8 + +static int WriteExtensions(VP8Encoder* const enc) { + uint8_t buffer[KTRAILER_SIZE]; + VP8BitWriter* const bw = &enc->bw_; + WebPPicture* const pic = enc->pic_; + + // Layer (bytes 0..3) + PutLE24(buffer + 0, enc->layer_data_size_); + buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK; + if (enc->layer_data_size_ > 0) { + assert(enc->use_layer_); + // append layer data to last partition + if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1], + enc->layer_data_, enc->layer_data_size_)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY); + } + } + + buffer[KTRAILER_SIZE - 1] = 0x01; // marker + if (!VP8BitWriterAppend(bw, buffer, KTRAILER_SIZE)) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY); + } + return 1; +} + +#endif /* WEBP_EXPERIMENTAL_FEATURES */ + +//------------------------------------------------------------------------------ + +static size_t GeneratePartition0(VP8Encoder* const enc) { + VP8BitWriter* const bw = &enc->bw_; + const int mb_size = enc->mb_w_ * enc->mb_h_; + uint64_t pos1, pos2, pos3; +#ifdef WEBP_EXPERIMENTAL_FEATURES + const int need_extensions = enc->use_layer_; +#endif + + pos1 = VP8BitWriterPos(bw); + VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock +#ifdef WEBP_EXPERIMENTAL_FEATURES + VP8PutBitUniform(bw, need_extensions); // extensions +#else + VP8PutBitUniform(bw, 0); // colorspace +#endif + VP8PutBitUniform(bw, 0); // clamp type + + PutSegmentHeader(bw, enc); + PutFilterHeader(bw, &enc->filter_hdr_); + VP8PutValue(bw, enc->config_->partitions, 2); + PutQuant(bw, enc); + VP8PutBitUniform(bw, 0); // no proba update + VP8WriteProbas(bw, &enc->proba_); + pos2 = VP8BitWriterPos(bw); + VP8CodeIntraModes(enc); + VP8BitWriterFinish(bw); + +#ifdef WEBP_EXPERIMENTAL_FEATURES + if (need_extensions && !WriteExtensions(enc)) { + return 0; + } +#endif + + pos3 = VP8BitWriterPos(bw); + + if (enc->pic_->stats) { + enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); + enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); + enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_; + enc->pic_->stats->layer_data_size = (int)enc->layer_data_size_; + } + return !bw->error_; +} + +void VP8EncFreeBitWriters(VP8Encoder* const enc) { + int p; + VP8BitWriterWipeOut(&enc->bw_); + for (p = 0; p < enc->num_parts_; ++p) { + VP8BitWriterWipeOut(enc->parts_ + p); + } +} + +int VP8EncWrite(VP8Encoder* const enc) { + WebPPicture* const pic = enc->pic_; + VP8BitWriter* const bw = &enc->bw_; + const int task_percent = 19; + const int percent_per_part = task_percent / enc->num_parts_; + const int final_percent = enc->percent_ + task_percent; + int ok = 0; + size_t vp8_size, pad, riff_size; + int p; + + // Partition #0 with header and partition sizes + ok = !!GeneratePartition0(enc); + + // Compute VP8 size + vp8_size = VP8_FRAME_HEADER_SIZE + + VP8BitWriterSize(bw) + + 3 * (enc->num_parts_ - 1); + for (p = 0; p < enc->num_parts_; ++p) { + vp8_size += VP8BitWriterSize(enc->parts_ + p); + } + pad = vp8_size & 1; + vp8_size += pad; + + // Compute RIFF size + // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size. + riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size; + if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data. + riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + } + if (enc->has_alpha_) { // Add size for: ALPH header + data. + const uint32_t padded_alpha_size = enc->alpha_data_size_ + + (enc->alpha_data_size_ & 1); + riff_size += CHUNK_HEADER_SIZE + padded_alpha_size; + } + // Sanity check. + if (riff_size > 0xfffffffeU) { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG); + } + + // Emit headers and partition #0 + { + const uint8_t* const part0 = VP8BitWriterBuf(bw); + const size_t size0 = VP8BitWriterSize(bw); + ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size) + && pic->writer(part0, size0, pic) + && EmitPartitionsSize(enc, pic); + VP8BitWriterWipeOut(bw); // will free the internal buffer. + } + + // Token partitions + for (p = 0; p < enc->num_parts_; ++p) { + const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); + const size_t size = VP8BitWriterSize(enc->parts_ + p); + if (size) + ok = ok && pic->writer(buf, size, pic); + VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer. + ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part, + &enc->percent_); + } + + // Padding byte + if (ok && pad) { + ok = PutPaddingByte(pic); + } + + enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size); + ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_); + return ok; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/tree.c b/external/libwebp/enc/tree.c new file mode 100644 index 0000000000..8b25e5e488 --- /dev/null +++ b/external/libwebp/enc/tree.c @@ -0,0 +1,510 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Token probabilities +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./vp8enci.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Default probabilities + +// Paragraph 13.5 +const uint8_t + VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + // genereated using vp8_default_coef_probs() in entropy.c:129 + { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, + { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, + { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } + }, + { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, + { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, + { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 }, + }, + { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, + { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, + { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 }, + }, + { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, + { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, + { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } + }, + { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, + { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, + { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } + }, + { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, + { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, + { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, + { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, + { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } + }, + { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, + { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, + { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } + }, + { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, + { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, + { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } + }, + { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, + { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, + { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } + }, + { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, + { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, + { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } + }, + { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, + { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, + { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } + }, + { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, + { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, + { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } + }, + { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } + } + }, + { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, + { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, + { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } + }, + { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, + { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, + { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } + }, + { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, + { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, + { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } + }, + { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, + { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, + { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, + { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + }, + { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } + } + }, + { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, + { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, + { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } + }, + { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, + { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, + { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } + }, + { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, + { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, + { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } + }, + { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, + { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, + { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } + }, + { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, + { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, + { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } + }, + { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, + { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, + { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } + }, + { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, + { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, + { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } + }, + { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, + { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } + } + } +}; + +void VP8DefaultProbas(VP8Encoder* const enc) { + VP8Proba* const probas = &enc->proba_; + probas->use_skip_proba_ = 0; + memset(probas->segments_, 255u, sizeof(probas->segments_)); + memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0)); + // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0, + // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later. + probas->dirty_ = 1; +} + +// Paragraph 11.5. 900bytes. +static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { + { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, + { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, + { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, + { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, + { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, + { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, + { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, + { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, + { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, + { 81, 40, 11, 96, 182, 84, 29, 16, 36 } }, + { { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, + { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, + { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, + { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, + { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, + { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, + { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, + { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, + { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, + { 66, 45, 25, 102, 197, 189, 23, 18, 22 } }, + { { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, + { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, + { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, + { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, + { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, + { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, + { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, + { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, + { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, + { 62, 18, 78, 95, 85, 57, 50, 48, 51 } }, + { { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, + { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, + { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, + { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, + { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, + { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, + { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, + { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, + { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, + { 51, 50, 17, 168, 209, 192, 23, 25, 82 } }, + { { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, + { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, + { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, + { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, + { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, + { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, + { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, + { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, + { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, + { 87, 37, 9, 115, 59, 77, 64, 21, 47 } }, + { { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, + { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, + { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, + { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, + { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, + { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, + { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, + { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, + { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, + { 55, 38, 70, 124, 73, 102, 1, 34, 98 } }, + { { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, + { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, + { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, + { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, + { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, + { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, + { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, + { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, + { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, + { 117, 20, 15, 36, 163, 128, 68, 1, 26 } }, + { { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, + { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, + { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, + { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, + { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, + { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, + { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, + { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, + { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, + { 58, 15, 20, 82, 135, 57, 26, 121, 40 } }, + { { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, + { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, + { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, + { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, + { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, + { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, + { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, + { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, + { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, + { 35, 27, 10, 146, 174, 171, 12, 26, 128 } }, + { { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, + { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, + { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, + { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, + { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, + { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, + { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, + { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, + { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, + { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } +}; + +static int PutI4Mode(VP8BitWriter* const bw, int mode, + const uint8_t* const prob) { + if (VP8PutBit(bw, mode != B_DC_PRED, prob[0])) { + if (VP8PutBit(bw, mode != B_TM_PRED, prob[1])) { + if (VP8PutBit(bw, mode != B_VE_PRED, prob[2])) { + if (!VP8PutBit(bw, mode >= B_LD_PRED, prob[3])) { + if (VP8PutBit(bw, mode != B_HE_PRED, prob[4])) { + VP8PutBit(bw, mode != B_RD_PRED, prob[5]); + } + } else { + if (VP8PutBit(bw, mode != B_LD_PRED, prob[6])) { + if (VP8PutBit(bw, mode != B_VL_PRED, prob[7])) { + VP8PutBit(bw, mode != B_HD_PRED, prob[8]); + } + } + } + } + } + } + return mode; +} + +static void PutI16Mode(VP8BitWriter* const bw, int mode) { + if (VP8PutBit(bw, (mode == TM_PRED || mode == H_PRED), 156)) { + VP8PutBit(bw, mode == TM_PRED, 128); // TM or HE + } else { + VP8PutBit(bw, mode == V_PRED, 163); // VE or DC + } +} + +static void PutUVMode(VP8BitWriter* const bw, int uv_mode) { + if (VP8PutBit(bw, uv_mode != DC_PRED, 142)) { + if (VP8PutBit(bw, uv_mode != V_PRED, 114)) { + VP8PutBit(bw, uv_mode != H_PRED, 183); // else: TM_PRED + } + } +} + +static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) { + if (VP8PutBit(bw, s >= 2, p[0])) p += 1; + VP8PutBit(bw, s & 1, p[1]); +} + +void VP8CodeIntraModes(VP8Encoder* const enc) { + VP8BitWriter* const bw = &enc->bw_; + VP8EncIterator it; + VP8IteratorInit(enc, &it); + do { + const VP8MBInfo* mb = it.mb_; + const uint8_t* preds = it.preds_; + if (enc->segment_hdr_.update_map_) { + PutSegment(bw, mb->segment_, enc->proba_.segments_); + } + if (enc->proba_.use_skip_proba_) { + VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_); + } + if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16 + PutI16Mode(bw, preds[0]); + } else { + const int preds_w = enc->preds_w_; + const uint8_t* top_pred = preds - preds_w; + int x, y; + for (y = 0; y < 4; ++y) { + int left = preds[-1]; + for (x = 0; x < 4; ++x) { + const uint8_t* const probas = kBModesProba[top_pred[x]][left]; + left = PutI4Mode(bw, preds[x], probas); + } + top_pred = preds; + preds += preds_w; + } + } + PutUVMode(bw, mb->uv_mode_); + } while (VP8IteratorNext(&it, 0)); +} + +//------------------------------------------------------------------------------ +// Paragraph 13 + +const uint8_t + VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { + { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 }, + { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 } + }, + { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + }, + { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + }, + { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, + { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } + } + } +}; + +void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas) { + int t, b, c, p; + for (t = 0; t < NUM_TYPES; ++t) { + for (b = 0; b < NUM_BANDS; ++b) { + for (c = 0; c < NUM_CTX; ++c) { + for (p = 0; p < NUM_PROBAS; ++p) { + const uint8_t p0 = probas->coeffs_[t][b][c][p]; + const int update = (p0 != VP8CoeffsProba0[t][b][c][p]); + if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) { + VP8PutValue(bw, p0, 8); + } + } + } + } + } + if (VP8PutBitUniform(bw, probas->use_skip_proba_)) { + VP8PutValue(bw, probas->skip_proba_, 8); + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/vp8enci.h b/external/libwebp/enc/vp8enci.h new file mode 100644 index 0000000000..f660eeec55 --- /dev/null +++ b/external/libwebp/enc/vp8enci.h @@ -0,0 +1,525 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// WebP encoder: internal header. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_ENC_VP8ENCI_H_ +#define WEBP_ENC_VP8ENCI_H_ + +#include // for memcpy() +#include "../webp/encode.h" +#include "../dsp/dsp.h" +#include "../utils/bit_writer.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Various defines and enums + +// version numbers +#define ENC_MAJ_VERSION 0 +#define ENC_MIN_VERSION 2 +#define ENC_REV_VERSION 1 + +// size of histogram used by CollectHistogram. +#define MAX_COEFF_THRESH 64 + +// intra prediction modes +enum { B_DC_PRED = 0, // 4x4 modes + B_TM_PRED = 1, + B_VE_PRED = 2, + B_HE_PRED = 3, + B_RD_PRED = 4, + B_VR_PRED = 5, + B_LD_PRED = 6, + B_VL_PRED = 7, + B_HD_PRED = 8, + B_HU_PRED = 9, + NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10 + + // Luma16 or UV modes + DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED, + H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED + }; + +enum { NUM_MB_SEGMENTS = 4, + MAX_NUM_PARTITIONS = 8, + NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC + NUM_BANDS = 8, + NUM_CTX = 3, + NUM_PROBAS = 11, + MAX_LF_LEVELS = 64, // Maximum loop filter level + MAX_VARIABLE_LEVEL = 67 // last (inclusive) level with variable cost + }; + +// YUV-cache parameters. Cache is 16-pixels wide. +// The original or reconstructed samples can be accessed using VP8Scan[] +// The predicted blocks can be accessed using offsets to yuv_p_ and +// the arrays VP8*ModeOffsets[]; +// +----+ YUV Samples area. See VP8Scan[] for accessing the blocks. +// Y_OFF |YYYY| <- original samples (enc->yuv_in_) +// |YYYY| +// |YYYY| +// |YYYY| +// U_OFF |UUVV| V_OFF (=U_OFF + 8) +// |UUVV| +// +----+ +// Y_OFF |YYYY| <- compressed/decoded samples ('yuv_out_') +// |YYYY| There are two buffers like this ('yuv_out_'/'yuv_out2_') +// |YYYY| +// |YYYY| +// U_OFF |UUVV| V_OFF +// |UUVV| +// x2 (for yuv_out2_) +// +----+ Prediction area ('yuv_p_', size = PRED_SIZE) +// I16DC16 |YYYY| Intra16 predictions (16x16 block each) +// |YYYY| +// |YYYY| +// |YYYY| +// I16TM16 |YYYY| +// |YYYY| +// |YYYY| +// |YYYY| +// I16VE16 |YYYY| +// |YYYY| +// |YYYY| +// |YYYY| +// I16HE16 |YYYY| +// |YYYY| +// |YYYY| +// |YYYY| +// +----+ Chroma U/V predictions (16x8 block each) +// C8DC8 |UUVV| +// |UUVV| +// C8TM8 |UUVV| +// |UUVV| +// C8VE8 |UUVV| +// |UUVV| +// C8HE8 |UUVV| +// |UUVV| +// +----+ Intra 4x4 predictions (4x4 block each) +// |YYYY| I4DC4 I4TM4 I4VE4 I4HE4 +// |YYYY| I4RD4 I4VR4 I4LD4 I4VL4 +// |YY..| I4HD4 I4HU4 I4TMP +// +----+ +#define BPS 16 // this is the common stride +#define Y_SIZE (BPS * 16) +#define UV_SIZE (BPS * 8) +#define YUV_SIZE (Y_SIZE + UV_SIZE) +#define PRED_SIZE (6 * 16 * BPS + 12 * BPS) +#define Y_OFF (0) +#define U_OFF (Y_SIZE) +#define V_OFF (U_OFF + 8) +#define ALIGN_CST 15 +#define DO_ALIGN(PTR) ((uintptr_t)((PTR) + ALIGN_CST) & ~ALIGN_CST) + +extern const int VP8Scan[16 + 4 + 4]; // in quant.c +extern const int VP8UVModeOffsets[4]; // in analyze.c +extern const int VP8I16ModeOffsets[4]; +extern const int VP8I4ModeOffsets[NUM_BMODES]; + +// Layout of prediction blocks +// intra 16x16 +#define I16DC16 (0 * 16 * BPS) +#define I16TM16 (1 * 16 * BPS) +#define I16VE16 (2 * 16 * BPS) +#define I16HE16 (3 * 16 * BPS) +// chroma 8x8, two U/V blocks side by side (hence: 16x8 each) +#define C8DC8 (4 * 16 * BPS) +#define C8TM8 (4 * 16 * BPS + 8 * BPS) +#define C8VE8 (5 * 16 * BPS) +#define C8HE8 (5 * 16 * BPS + 8 * BPS) +// intra 4x4 +#define I4DC4 (6 * 16 * BPS + 0) +#define I4TM4 (6 * 16 * BPS + 4) +#define I4VE4 (6 * 16 * BPS + 8) +#define I4HE4 (6 * 16 * BPS + 12) +#define I4RD4 (6 * 16 * BPS + 4 * BPS + 0) +#define I4VR4 (6 * 16 * BPS + 4 * BPS + 4) +#define I4LD4 (6 * 16 * BPS + 4 * BPS + 8) +#define I4VL4 (6 * 16 * BPS + 4 * BPS + 12) +#define I4HD4 (6 * 16 * BPS + 8 * BPS + 0) +#define I4HU4 (6 * 16 * BPS + 8 * BPS + 4) +#define I4TMP (6 * 16 * BPS + 8 * BPS + 8) + +typedef int64_t score_t; // type used for scores, rate, distortion +#define MAX_COST ((score_t)0x7fffffffffffffLL) + +#define QFIX 17 +#define BIAS(b) ((b) << (QFIX - 8)) +// Fun fact: this is the _only_ line where we're actually being lossy and +// discarding bits. +static WEBP_INLINE int QUANTDIV(int n, int iQ, int B) { + return (n * iQ + B) >> QFIX; +} +extern const uint8_t VP8Zigzag[16]; + +//------------------------------------------------------------------------------ +// Headers + +typedef uint32_t proba_t; // 16b + 16b +typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS]; +typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS]; +typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1]; +typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats + +typedef struct VP8Encoder VP8Encoder; + +// segment features +typedef struct { + int num_segments_; // Actual number of segments. 1 segment only = unused. + int update_map_; // whether to update the segment map or not. + // must be 0 if there's only 1 segment. + int size_; // bit-cost for transmitting the segment map +} VP8SegmentHeader; + +// Struct collecting all frame-persistent probabilities. +typedef struct { + uint8_t segments_[3]; // probabilities for segment tree + uint8_t skip_proba_; // final probability of being skipped. + ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 924 bytes + StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes + CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 11.4k + int dirty_; // if true, need to call VP8CalculateLevelCosts() + int use_skip_proba_; // Note: we always use skip_proba for now. + int nb_skip_; // number of skipped blocks +} VP8Proba; + +// Filter parameters. Not actually used in the code (we don't perform +// the in-loop filtering), but filled from user's config +typedef struct { + int simple_; // filtering type: 0=complex, 1=simple + int level_; // base filter level [0..63] + int sharpness_; // [0..7] + int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16 +} VP8FilterHeader; + +//------------------------------------------------------------------------------ +// Informations about the macroblocks. + +typedef struct { + // block type + unsigned int type_:2; // 0=i4x4, 1=i16x16 + unsigned int uv_mode_:2; + unsigned int skip_:1; + unsigned int segment_:2; + uint8_t alpha_; // quantization-susceptibility +} VP8MBInfo; + +typedef struct VP8Matrix { + uint16_t q_[16]; // quantizer steps + uint16_t iq_[16]; // reciprocals, fixed point. + uint16_t bias_[16]; // rounding bias + uint16_t zthresh_[16]; // value under which a coefficient is zeroed + uint16_t sharpen_[16]; // frequency boosters for slight sharpening +} VP8Matrix; + +typedef struct { + VP8Matrix y1_, y2_, uv_; // quantization matrices + int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral. + // Lower values indicate a lower risk of blurriness. + int beta_; // filter-susceptibility, range [0,255]. + int quant_; // final segment quantizer. + int fstrength_; // final in-loop filtering strength + // reactivities + int lambda_i16_, lambda_i4_, lambda_uv_; + int lambda_mode_, lambda_trellis_, tlambda_; + int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_; +} VP8SegmentInfo; + +// Handy transcient struct to accumulate score and info during RD-optimization +// and mode evaluation. +typedef struct { + score_t D, SD, R, score; // Distortion, spectral distortion, rate, score. + int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma. + int16_t y_ac_levels[16][16]; + int16_t uv_levels[4 + 4][16]; + int mode_i16; // mode number for intra16 prediction + uint8_t modes_i4[16]; // mode numbers for intra4 predictions + int mode_uv; // mode number of chroma prediction + uint32_t nz; // non-zero blocks +} VP8ModeScore; + +// Iterator structure to iterate through macroblocks, pointing to the +// right neighbouring data (samples, predictions, contexts, ...) +typedef struct { + int x_, y_; // current macroblock + int y_offset_, uv_offset_; // offset to the luma / chroma planes + int y_stride_, uv_stride_; // respective strides + uint8_t* yuv_in_; // borrowed from enc_ (for now) + uint8_t* yuv_out_; // '' + uint8_t* yuv_out2_; // '' + uint8_t* yuv_p_; // '' + VP8Encoder* enc_; // back-pointer + VP8MBInfo* mb_; // current macroblock + VP8BitWriter* bw_; // current bit-writer + uint8_t* preds_; // intra mode predictors (4x4 blocks) + uint32_t* nz_; // non-zero pattern + uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4 + uint8_t* i4_top_; // pointer to the current top boundary sample + int i4_; // current intra4x4 mode being tested + int top_nz_[9]; // top-non-zero context. + int left_nz_[9]; // left-non-zero. left_nz[8] is independent. + uint64_t bit_count_[4][3]; // bit counters for coded levels. + uint64_t luma_bits_; // macroblock bit-cost for luma + uint64_t uv_bits_; // macroblock bit-cost for chroma + LFStats* lf_stats_; // filter stats (borrowed from enc_) + int do_trellis_; // if true, perform extra level optimisation + int done_; // true when scan is finished + int percent0_; // saved initial progress percent +} VP8EncIterator; + + // in iterator.c +// must be called first. +void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it); +// restart a scan. +void VP8IteratorReset(VP8EncIterator* const it); +// import samples from source +void VP8IteratorImport(const VP8EncIterator* const it); +// export decimated samples +void VP8IteratorExport(const VP8EncIterator* const it); +// go to next macroblock. Returns !done_. If *block_to_save is non-null, will +// save the boundary values to top_/left_ arrays. block_to_save can be +// it->yuv_out_ or it->yuv_in_. +int VP8IteratorNext(VP8EncIterator* const it, + const uint8_t* const block_to_save); +// Report progression based on macroblock rows. Return 0 for user-abort request. +int VP8IteratorProgress(const VP8EncIterator* const it, + int final_delta_percent); +// Intra4x4 iterations +void VP8IteratorStartI4(VP8EncIterator* const it); +// returns true if not done. +int VP8IteratorRotateI4(VP8EncIterator* const it, + const uint8_t* const yuv_out); + +// Non-zero context setup/teardown +void VP8IteratorNzToBytes(VP8EncIterator* const it); +void VP8IteratorBytesToNz(VP8EncIterator* const it); + +// Helper functions to set mode properties +void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode); +void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes); +void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode); +void VP8SetSkip(const VP8EncIterator* const it, int skip); +void VP8SetSegment(const VP8EncIterator* const it, int segment); + +//------------------------------------------------------------------------------ +// Paginated token buffer + +// WIP: #define USE_TOKEN_BUFFER + +#ifdef USE_TOKEN_BUFFER + +#define MAX_NUM_TOKEN 2048 + +typedef struct VP8Tokens VP8Tokens; +struct VP8Tokens { + uint16_t tokens_[MAX_NUM_TOKEN]; // bit#15: bit, bits 0..14: slot + int left_; + VP8Tokens* next_; +}; + +typedef struct { + VP8Tokens* rows_; + uint16_t* tokens_; // set to (*last_)->tokens_ + VP8Tokens** last_; + int left_; + int error_; // true in case of malloc error +} VP8TBuffer; + +void VP8TBufferInit(VP8TBuffer* const b); // initialize an empty buffer +int VP8TBufferNewPage(VP8TBuffer* const b); // allocate a new page +void VP8TBufferClear(VP8TBuffer* const b); // de-allocate memory + +int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw, + const uint8_t* const probas); + +static WEBP_INLINE int VP8AddToken(VP8TBuffer* const b, + int bit, int proba_idx) { + if (b->left_ > 0 || VP8TBufferNewPage(b)) { + const int slot = --b->left_; + b->tokens_[slot] = (bit << 15) | proba_idx; + } + return bit; +} + +#endif // USE_TOKEN_BUFFER + +//------------------------------------------------------------------------------ +// VP8Encoder + +struct VP8Encoder { + const WebPConfig* config_; // user configuration and parameters + WebPPicture* pic_; // input / output picture + + // headers + VP8FilterHeader filter_hdr_; // filtering information + VP8SegmentHeader segment_hdr_; // segment information + + int profile_; // VP8's profile, deduced from Config. + + // dimension, in macroblock units. + int mb_w_, mb_h_; + int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1) + + // number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS) + int num_parts_; + + // per-partition boolean decoders. + VP8BitWriter bw_; // part0 + VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions + + int percent_; // for progress + + // transparency blob + int has_alpha_; + uint8_t* alpha_data_; // non-NULL if transparency is present + uint32_t alpha_data_size_; + + // enhancement layer + int use_layer_; + VP8BitWriter layer_bw_; + uint8_t* layer_data_; + size_t layer_data_size_; + + // quantization info (one set of DC/AC dequant factor per segment) + VP8SegmentInfo dqm_[NUM_MB_SEGMENTS]; + int base_quant_; // nominal quantizer value. Only used + // for relative coding of segments' quant. + int uv_alpha_; // U/V quantization susceptibility + // global offset of quantizers, shared by all segments + int dq_y1_dc_; + int dq_y2_dc_, dq_y2_ac_; + int dq_uv_dc_, dq_uv_ac_; + + // probabilities and statistics + VP8Proba proba_; + uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks + uint64_t sse_count_; // pixel count for the sse_[] stats + int coded_size_; + int residual_bytes_[3][4]; + int block_count_[3]; + + // quality/speed settings + int method_; // 0=fastest, 6=best/slowest. + int rd_opt_level_; // Deduced from method_. + int max_i4_header_bits_; // partition #0 safeness factor + + // Memory + VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1) + uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1) + uint32_t* nz_; // non-zero bit context: mb_w+1 + uint8_t* yuv_in_; // input samples + uint8_t* yuv_out_; // output samples + uint8_t* yuv_out2_; // secondary scratch out-buffer. swapped with yuv_out_. + uint8_t* yuv_p_; // scratch buffer for prediction + uint8_t *y_top_; // top luma samples. + uint8_t *uv_top_; // top u/v samples. + // U and V are packed into 16 pixels (8 U + 8 V) + uint8_t *y_left_; // left luma samples (adressable from index -1 to 15). + uint8_t *u_left_; // left u samples (adressable from index -1 to 7) + uint8_t *v_left_; // left v samples (adressable from index -1 to 7) + + LFStats *lf_stats_; // autofilter stats (if NULL, autofilter is off) +}; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + + // in tree.c +extern const uint8_t VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; +extern const uint8_t + VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; +// Reset the token probabilities to their initial (default) values +void VP8DefaultProbas(VP8Encoder* const enc); +// Write the token probabilities +void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas); +// Writes the partition #0 modes (that is: all intra modes) +void VP8CodeIntraModes(VP8Encoder* const enc); + + // in syntax.c +// Generates the final bitstream by coding the partition0 and headers, +// and appending an assembly of all the pre-coded token partitions. +// Return true if everything is ok. +int VP8EncWrite(VP8Encoder* const enc); +// Release memory allocated for bit-writing in VP8EncLoop & seq. +void VP8EncFreeBitWriters(VP8Encoder* const enc); + + // in frame.c +extern const uint8_t VP8EncBands[16 + 1]; +// Form all the four Intra16x16 predictions in the yuv_p_ cache +void VP8MakeLuma16Preds(const VP8EncIterator* const it); +// Form all the four Chroma8x8 predictions in the yuv_p_ cache +void VP8MakeChroma8Preds(const VP8EncIterator* const it); +// Form all the ten Intra4x4 predictions in the yuv_p_ cache +// for the 4x4 block it->i4_ +void VP8MakeIntra4Preds(const VP8EncIterator* const it); +// Rate calculation +int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd); +int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]); +int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd); +// Main stat / coding passes +int VP8EncLoop(VP8Encoder* const enc); +int VP8StatLoop(VP8Encoder* const enc); + + // in webpenc.c +// Assign an error code to a picture. Return false for convenience. +int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error); +int WebPReportProgress(const WebPPicture* const pic, + int percent, int* const percent_store); + + // in analysis.c +// Main analysis loop. Decides the segmentations and complexity. +// Assigns a first guess for Intra16 and uvmode_ prediction modes. +int VP8EncAnalyze(VP8Encoder* const enc); + + // in quant.c +// Sets up segment's quantization values, base_quant_ and filter strengths. +void VP8SetSegmentParams(VP8Encoder* const enc, float quality); +// Pick best modes and fills the levels. Returns true if skipped. +int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt); + + // in alpha.c +void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression +int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data +void VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data + + // in layer.c +void VP8EncInitLayer(VP8Encoder* const enc); // init everything +void VP8EncCodeLayerBlock(VP8EncIterator* it); // code one more macroblock +int VP8EncFinishLayer(VP8Encoder* const enc); // finalize coding +void VP8EncDeleteLayer(VP8Encoder* enc); // reclaim memory + + // in filter.c + +// SSIM utils +typedef struct { + double w, xm, ym, xxm, xym, yym; +} DistoStats; +void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst); +void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1, + const uint8_t* src2, int stride2, + int W, int H, DistoStats* const stats); +double VP8SSIMGet(const DistoStats* const stats); +double VP8SSIMGetSquaredError(const DistoStats* const stats); + +// autofilter +void VP8InitFilter(VP8EncIterator* const it); +void VP8StoreFilterStats(VP8EncIterator* const it); +void VP8AdjustFilterStrength(VP8EncIterator* const it); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_ENC_VP8ENCI_H_ */ diff --git a/external/libwebp/enc/vp8l.c b/external/libwebp/enc/vp8l.c new file mode 100644 index 0000000000..2abc30f464 --- /dev/null +++ b/external/libwebp/enc/vp8l.c @@ -0,0 +1,1155 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// main entry for the lossless encoder. +// +// Author: Vikas Arora (vikaas.arora@gmail.com) +// + +#include +#include +#include + +#include "./backward_references.h" +#include "./vp8enci.h" +#include "./vp8li.h" +#include "../dsp/lossless.h" +#include "../utils/bit_writer.h" +#include "../utils/huffman_encode.h" +#include "../utils/utils.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer. +#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024) +#define MAX_COLORS_FOR_GRAPH 64 + +// ----------------------------------------------------------------------------- +// Palette + +static int CompareColors(const void* p1, const void* p2) { + const uint32_t a = *(const uint32_t*)p1; + const uint32_t b = *(const uint32_t*)p2; + return (a < b) ? -1 : (a > b) ? 1 : 0; +} + +// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE, +// creates a palette and returns true, else returns false. +static int AnalyzeAndCreatePalette(const WebPPicture* const pic, + uint32_t palette[MAX_PALETTE_SIZE], + int* const palette_size) { + int i, x, y, key; + int num_colors = 0; + uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 }; + uint32_t colors[MAX_PALETTE_SIZE * 4]; + static const uint32_t kHashMul = 0x1e35a7bd; + const uint32_t* argb = pic->argb; + const int width = pic->width; + const int height = pic->height; + uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0] + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + if (argb[x] == last_pix) { + continue; + } + last_pix = argb[x]; + key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT; + while (1) { + if (!in_use[key]) { + colors[key] = last_pix; + in_use[key] = 1; + ++num_colors; + if (num_colors > MAX_PALETTE_SIZE) { + return 0; + } + break; + } else if (colors[key] == last_pix) { + // The color is already there. + break; + } else { + // Some other color sits there. + // Do linear conflict resolution. + ++key; + key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer. + } + } + } + argb += pic->argb_stride; + } + + // TODO(skal): could we reuse in_use[] to speed up ApplyPalette()? + num_colors = 0; + for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) { + if (in_use[i]) { + palette[num_colors] = colors[i]; + ++num_colors; + } + } + + qsort(palette, num_colors, sizeof(*palette), CompareColors); + *palette_size = num_colors; + return 1; +} + +static int AnalyzeEntropy(const uint32_t* argb, + int width, int height, int argb_stride, + double* const nonpredicted_bits, + double* const predicted_bits) { + int x, y; + const uint32_t* last_line = NULL; + uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0 + + VP8LHistogram* nonpredicted = NULL; + VP8LHistogram* predicted = + (VP8LHistogram*)malloc(2 * sizeof(*predicted)); + if (predicted == NULL) return 0; + nonpredicted = predicted + 1; + + VP8LHistogramInit(predicted, 0); + VP8LHistogramInit(nonpredicted, 0); + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const uint32_t pix = argb[x]; + const uint32_t pix_diff = VP8LSubPixels(pix, last_pix); + if (pix_diff == 0) continue; + if (last_line != NULL && pix == last_line[x]) { + continue; + } + last_pix = pix; + { + const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix); + const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff); + VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token); + VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token); + } + } + last_line = argb; + argb += argb_stride; + } + *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted); + *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted); + free(predicted); + return 1; +} + +static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) { + const WebPPicture* const pic = enc->pic_; + assert(pic != NULL && pic->argb != NULL); + + enc->use_palette_ = + AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_); + + if (image_hint == WEBP_HINT_GRAPH) { + if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) { + enc->use_palette_ = 0; + } + } + + if (!enc->use_palette_) { + if (image_hint == WEBP_HINT_PHOTO) { + enc->use_predict_ = 1; + enc->use_cross_color_ = 1; + } else { + double non_pred_entropy, pred_entropy; + if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride, + &non_pred_entropy, &pred_entropy)) { + return 0; + } + if (pred_entropy < 0.95 * non_pred_entropy) { + enc->use_predict_ = 1; + // TODO(vikasa): Observed some correlation of cross_color transform with + // predict. Need to investigate this further and add separate heuristic + // for setting use_cross_color flag. + enc->use_cross_color_ = 1; + } + } + } + + return 1; +} + +static int GetHuffBitLengthsAndCodes( + const VP8LHistogramSet* const histogram_image, + HuffmanTreeCode* const huffman_codes) { + int i, k; + int ok = 1; + uint64_t total_length_size = 0; + uint8_t* mem_buf = NULL; + const int histogram_image_size = histogram_image->size; + + // Iterate over all histograms and get the aggregate number of codes used. + for (i = 0; i < histogram_image_size; ++i) { + const VP8LHistogram* const histo = histogram_image->histograms[i]; + HuffmanTreeCode* const codes = &huffman_codes[5 * i]; + for (k = 0; k < 5; ++k) { + const int num_symbols = (k == 0) ? VP8LHistogramNumCodes(histo) + : (k == 4) ? NUM_DISTANCE_CODES + : 256; + codes[k].num_symbols = num_symbols; + total_length_size += num_symbols; + } + } + + // Allocate and Set Huffman codes. + { + uint16_t* codes; + uint8_t* lengths; + mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size, + sizeof(*lengths) + sizeof(*codes)); + if (mem_buf == NULL) { + ok = 0; + goto End; + } + codes = (uint16_t*)mem_buf; + lengths = (uint8_t*)&codes[total_length_size]; + for (i = 0; i < 5 * histogram_image_size; ++i) { + const int bit_length = huffman_codes[i].num_symbols; + huffman_codes[i].codes = codes; + huffman_codes[i].code_lengths = lengths; + codes += bit_length; + lengths += bit_length; + } + } + + // Create Huffman trees. + for (i = 0; i < histogram_image_size; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[5 * i]; + VP8LHistogram* const histo = histogram_image->histograms[i]; + ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0); + ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1); + ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2); + ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3); + ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4); + } + + End: + if (!ok) free(mem_buf); + return ok; +} + +static void StoreHuffmanTreeOfHuffmanTreeToBitMask( + VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) { + // RFC 1951 will calm you down if you are worried about this funny sequence. + // This sequence is tuned from that, but more weighted for lower symbol count, + // and more spiking histograms. + static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = { + 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + int i; + // Throw away trailing zeros: + int codes_to_store = CODE_LENGTH_CODES; + for (; codes_to_store > 4; --codes_to_store) { + if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { + break; + } + } + VP8LWriteBits(bw, 4, codes_to_store - 4); + for (i = 0; i < codes_to_store; ++i) { + VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]); + } +} + +static void ClearHuffmanTreeIfOnlyOneSymbol( + HuffmanTreeCode* const huffman_code) { + int k; + int count = 0; + for (k = 0; k < huffman_code->num_symbols; ++k) { + if (huffman_code->code_lengths[k] != 0) { + ++count; + if (count > 1) return; + } + } + for (k = 0; k < huffman_code->num_symbols; ++k) { + huffman_code->code_lengths[k] = 0; + huffman_code->codes[k] = 0; + } +} + +static void StoreHuffmanTreeToBitMask( + VP8LBitWriter* const bw, + const HuffmanTreeToken* const tokens, const int num_tokens, + const HuffmanTreeCode* const huffman_code) { + int i; + for (i = 0; i < num_tokens; ++i) { + const int ix = tokens[i].code; + const int extra_bits = tokens[i].extra_bits; + VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]); + switch (ix) { + case 16: + VP8LWriteBits(bw, 2, extra_bits); + break; + case 17: + VP8LWriteBits(bw, 3, extra_bits); + break; + case 18: + VP8LWriteBits(bw, 7, extra_bits); + break; + } + } +} + +static int StoreFullHuffmanCode(VP8LBitWriter* const bw, + const HuffmanTreeCode* const tree) { + int ok = 0; + uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 }; + uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 }; + const int max_tokens = tree->num_symbols; + int num_tokens; + HuffmanTreeCode huffman_code; + HuffmanTreeToken* const tokens = + (HuffmanTreeToken*)WebPSafeMalloc((uint64_t)max_tokens, sizeof(*tokens)); + if (tokens == NULL) return 0; + + huffman_code.num_symbols = CODE_LENGTH_CODES; + huffman_code.code_lengths = code_length_bitdepth; + huffman_code.codes = code_length_bitdepth_symbols; + + VP8LWriteBits(bw, 1, 0); + num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens); + { + int histogram[CODE_LENGTH_CODES] = { 0 }; + int i; + for (i = 0; i < num_tokens; ++i) { + ++histogram[tokens[i].code]; + } + + if (!VP8LCreateHuffmanTree(histogram, 7, &huffman_code)) { + goto End; + } + } + + StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth); + ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code); + { + int trailing_zero_bits = 0; + int trimmed_length = num_tokens; + int write_trimmed_length; + int length; + int i = num_tokens; + while (i-- > 0) { + const int ix = tokens[i].code; + if (ix == 0 || ix == 17 || ix == 18) { + --trimmed_length; // discount trailing zeros + trailing_zero_bits += code_length_bitdepth[ix]; + if (ix == 17) { + trailing_zero_bits += 3; + } else if (ix == 18) { + trailing_zero_bits += 7; + } + } else { + break; + } + } + write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12); + length = write_trimmed_length ? trimmed_length : num_tokens; + VP8LWriteBits(bw, 1, write_trimmed_length); + if (write_trimmed_length) { + const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1); + const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2; + VP8LWriteBits(bw, 3, nbitpairs - 1); + assert(trimmed_length >= 2); + VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2); + } + StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code); + } + ok = 1; + End: + free(tokens); + return ok; +} + +static int StoreHuffmanCode(VP8LBitWriter* const bw, + const HuffmanTreeCode* const huffman_code) { + int i; + int count = 0; + int symbols[2] = { 0, 0 }; + const int kMaxBits = 8; + const int kMaxSymbol = 1 << kMaxBits; + + // Check whether it's a small tree. + for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) { + if (huffman_code->code_lengths[i] != 0) { + if (count < 2) symbols[count] = i; + ++count; + } + } + + if (count == 0) { // emit minimal tree for empty cases + // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 + VP8LWriteBits(bw, 4, 0x01); + return 1; + } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) { + VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols. + VP8LWriteBits(bw, 1, count - 1); + if (symbols[0] <= 1) { + VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value. + VP8LWriteBits(bw, 1, symbols[0]); + } else { + VP8LWriteBits(bw, 1, 1); + VP8LWriteBits(bw, 8, symbols[0]); + } + if (count == 2) { + VP8LWriteBits(bw, 8, symbols[1]); + } + return 1; + } else { + return StoreFullHuffmanCode(bw, huffman_code); + } +} + +static void WriteHuffmanCode(VP8LBitWriter* const bw, + const HuffmanTreeCode* const code, int index) { + const int depth = code->code_lengths[index]; + const int symbol = code->codes[index]; + VP8LWriteBits(bw, depth, symbol); +} + +static void StoreImageToBitMask( + VP8LBitWriter* const bw, int width, int histo_bits, + const VP8LBackwardRefs* const refs, + const uint16_t* histogram_symbols, + const HuffmanTreeCode* const huffman_codes) { + // x and y trace the position in the image. + int x = 0; + int y = 0; + const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; + int i; + for (i = 0; i < refs->size; ++i) { + const PixOrCopy* const v = &refs->refs[i]; + const int histogram_ix = histogram_symbols[histo_bits ? + (y >> histo_bits) * histo_xsize + + (x >> histo_bits) : 0]; + const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix; + if (PixOrCopyIsCacheIdx(v)) { + const int code = PixOrCopyCacheIdx(v); + const int literal_ix = 256 + NUM_LENGTH_CODES + code; + WriteHuffmanCode(bw, codes, literal_ix); + } else if (PixOrCopyIsLiteral(v)) { + static const int order[] = { 1, 2, 0, 3 }; + int k; + for (k = 0; k < 4; ++k) { + const int code = PixOrCopyLiteral(v, order[k]); + WriteHuffmanCode(bw, codes + k, code); + } + } else { + int bits, n_bits; + int code, distance; + + PrefixEncode(v->len, &code, &n_bits, &bits); + WriteHuffmanCode(bw, codes, 256 + code); + VP8LWriteBits(bw, n_bits, bits); + + distance = PixOrCopyDistance(v); + PrefixEncode(distance, &code, &n_bits, &bits); + WriteHuffmanCode(bw, codes + 4, code); + VP8LWriteBits(bw, n_bits, bits); + } + x += PixOrCopyLength(v); + while (x >= width) { + x -= width; + ++y; + } + } +} + +// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 +static int EncodeImageNoHuffman(VP8LBitWriter* const bw, + const uint32_t* const argb, + int width, int height, int quality) { + int i; + int ok = 0; + VP8LBackwardRefs refs; + HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; + const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol + VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0); + if (histogram_image == NULL) return 0; + + // Calculate backward references from ARGB image. + if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) { + goto Error; + } + // Build histogram image and symbols from backward references. + VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]); + + // Create Huffman bit lengths and codes for each histogram image. + assert(histogram_image->size == 1); + if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { + goto Error; + } + + // No color cache, no Huffman image. + VP8LWriteBits(bw, 1, 0); + + // Store Huffman codes. + for (i = 0; i < 5; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + if (!StoreHuffmanCode(bw, codes)) { + goto Error; + } + ClearHuffmanTreeIfOnlyOneSymbol(codes); + } + + // Store actual literals. + StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes); + ok = 1; + + Error: + free(histogram_image); + VP8LClearBackwardRefs(&refs); + free(huffman_codes[0].codes); + return ok; +} + +static int EncodeImageInternal(VP8LBitWriter* const bw, + const uint32_t* const argb, + int width, int height, int quality, + int cache_bits, int histogram_bits) { + int ok = 0; + const int use_2d_locality = 1; + const int use_color_cache = (cache_bits > 0); + const uint32_t histogram_image_xysize = + VP8LSubSampleSize(width, histogram_bits) * + VP8LSubSampleSize(height, histogram_bits); + VP8LHistogramSet* histogram_image = + VP8LAllocateHistogramSet(histogram_image_xysize, 0); + int histogram_image_size = 0; + size_t bit_array_size = 0; + HuffmanTreeCode* huffman_codes = NULL; + VP8LBackwardRefs refs; + uint16_t* const histogram_symbols = + (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize, + sizeof(*histogram_symbols)); + assert(histogram_bits >= MIN_HUFFMAN_BITS); + assert(histogram_bits <= MAX_HUFFMAN_BITS); + + if (histogram_image == NULL || histogram_symbols == NULL) { + free(histogram_image); + free(histogram_symbols); + return 0; + } + + // Calculate backward references from ARGB image. + if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits, + use_2d_locality, &refs)) { + goto Error; + } + // Build histogram image and symbols from backward references. + if (!VP8LGetHistoImageSymbols(width, height, &refs, + quality, histogram_bits, cache_bits, + histogram_image, + histogram_symbols)) { + goto Error; + } + // Create Huffman bit lengths and codes for each histogram image. + histogram_image_size = histogram_image->size; + bit_array_size = 5 * histogram_image_size; + huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, + sizeof(*huffman_codes)); + if (huffman_codes == NULL || + !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { + goto Error; + } + + // Color Cache parameters. + VP8LWriteBits(bw, 1, use_color_cache); + if (use_color_cache) { + VP8LWriteBits(bw, 4, cache_bits); + } + + // Huffman image + meta huffman. + { + const int write_histogram_image = (histogram_image_size > 1); + VP8LWriteBits(bw, 1, write_histogram_image); + if (write_histogram_image) { + uint32_t* const histogram_argb = + (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize, + sizeof(*histogram_argb)); + int max_index = 0; + uint32_t i; + if (histogram_argb == NULL) goto Error; + for (i = 0; i < histogram_image_xysize; ++i) { + const int index = histogram_symbols[i] & 0xffff; + histogram_argb[i] = 0xff000000 | (index << 8); + if (index >= max_index) { + max_index = index + 1; + } + } + histogram_image_size = max_index; + + VP8LWriteBits(bw, 3, histogram_bits - 2); + ok = EncodeImageNoHuffman(bw, histogram_argb, + VP8LSubSampleSize(width, histogram_bits), + VP8LSubSampleSize(height, histogram_bits), + quality); + free(histogram_argb); + if (!ok) goto Error; + } + } + + // Store Huffman codes. + { + int i; + for (i = 0; i < 5 * histogram_image_size; ++i) { + HuffmanTreeCode* const codes = &huffman_codes[i]; + if (!StoreHuffmanCode(bw, codes)) goto Error; + ClearHuffmanTreeIfOnlyOneSymbol(codes); + } + } + // Free combined histograms. + free(histogram_image); + histogram_image = NULL; + + // Store actual literals. + StoreImageToBitMask(bw, width, histogram_bits, &refs, + histogram_symbols, huffman_codes); + ok = 1; + + Error: + if (!ok) free(histogram_image); + + VP8LClearBackwardRefs(&refs); + if (huffman_codes != NULL) { + free(huffman_codes->codes); + free(huffman_codes); + } + free(histogram_symbols); + return ok; +} + +// ----------------------------------------------------------------------------- +// Transforms + +// Check if it would be a good idea to subtract green from red and blue. We +// only impact entropy in red/blue components, don't bother to look at others. +static int EvalAndApplySubtractGreen(VP8LEncoder* const enc, + int width, int height, + VP8LBitWriter* const bw) { + if (!enc->use_palette_) { + int i; + const uint32_t* const argb = enc->argb_; + double bit_cost_before, bit_cost_after; + VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo)); + if (histo == NULL) return 0; + + VP8LHistogramInit(histo, 1); + for (i = 0; i < width * height; ++i) { + const uint32_t c = argb[i]; + ++histo->red_[(c >> 16) & 0xff]; + ++histo->blue_[(c >> 0) & 0xff]; + } + bit_cost_before = VP8LHistogramEstimateBits(histo); + + VP8LHistogramInit(histo, 1); + for (i = 0; i < width * height; ++i) { + const uint32_t c = argb[i]; + const int green = (c >> 8) & 0xff; + ++histo->red_[((c >> 16) - green) & 0xff]; + ++histo->blue_[((c >> 0) - green) & 0xff]; + } + bit_cost_after = VP8LHistogramEstimateBits(histo); + free(histo); + + // Check if subtracting green yields low entropy. + enc->use_subtract_green_ = (bit_cost_after < bit_cost_before); + if (enc->use_subtract_green_) { + VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); + VP8LWriteBits(bw, 2, SUBTRACT_GREEN); + VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); + } + } + return 1; +} + +static int ApplyPredictFilter(const VP8LEncoder* const enc, + int width, int height, int quality, + VP8LBitWriter* const bw) { + const int pred_bits = enc->transform_bits_; + const int transform_width = VP8LSubSampleSize(width, pred_bits); + const int transform_height = VP8LSubSampleSize(height, pred_bits); + + VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_, + enc->transform_data_); + VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); + VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM); + assert(pred_bits >= 2); + VP8LWriteBits(bw, 3, pred_bits - 2); + if (!EncodeImageNoHuffman(bw, enc->transform_data_, + transform_width, transform_height, quality)) { + return 0; + } + return 1; +} + +static int ApplyCrossColorFilter(const VP8LEncoder* const enc, + int width, int height, int quality, + VP8LBitWriter* const bw) { + const int ccolor_transform_bits = enc->transform_bits_; + const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); + const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); + const int step = (quality == 0) ? 32 : 8; + + VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step, + enc->argb_, enc->transform_data_); + VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); + VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM); + assert(ccolor_transform_bits >= 2); + VP8LWriteBits(bw, 3, ccolor_transform_bits - 2); + if (!EncodeImageNoHuffman(bw, enc->transform_data_, + transform_width, transform_height, quality)) { + return 0; + } + return 1; +} + +// ----------------------------------------------------------------------------- + +static void PutLE32(uint8_t* const data, uint32_t val) { + data[0] = (val >> 0) & 0xff; + data[1] = (val >> 8) & 0xff; + data[2] = (val >> 16) & 0xff; + data[3] = (val >> 24) & 0xff; +} + +static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, + size_t riff_size, size_t vp8l_size) { + uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { + 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', + 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, + }; + PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); + PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); + if (!pic->writer(riff, sizeof(riff), pic)) { + return VP8_ENC_ERROR_BAD_WRITE; + } + return VP8_ENC_OK; +} + +static int WriteImageSize(const WebPPicture* const pic, + VP8LBitWriter* const bw) { + const int width = pic->width - 1; + const int height = pic->height - 1; + assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); + + VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width); + VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height); + return !bw->error_; +} + +static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { + VP8LWriteBits(bw, 1, has_alpha); + VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION); + return !bw->error_; +} + +static WebPEncodingError WriteImage(const WebPPicture* const pic, + VP8LBitWriter* const bw, + size_t* const coded_size) { + WebPEncodingError err = VP8_ENC_OK; + const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); + const size_t webpll_size = VP8LBitWriterNumBytes(bw); + const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; + const size_t pad = vp8l_size & 1; + const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; + + err = WriteRiffHeader(pic, riff_size, vp8l_size); + if (err != VP8_ENC_OK) goto Error; + + if (!pic->writer(webpll_data, webpll_size, pic)) { + err = VP8_ENC_ERROR_BAD_WRITE; + goto Error; + } + + if (pad) { + const uint8_t pad_byte[1] = { 0 }; + if (!pic->writer(pad_byte, 1, pic)) { + err = VP8_ENC_ERROR_BAD_WRITE; + goto Error; + } + } + *coded_size = CHUNK_HEADER_SIZE + riff_size; + return VP8_ENC_OK; + + Error: + return err; +} + +// ----------------------------------------------------------------------------- + +// Allocates the memory for argb (W x H) buffer, 2 rows of context for +// prediction and transform data. +static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, + int width, int height) { + WebPEncodingError err = VP8_ENC_OK; + const int tile_size = 1 << enc->transform_bits_; + const uint64_t image_size = width * height; + const uint64_t argb_scratch_size = tile_size * width + width; + const uint64_t transform_data_size = + (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) * + (uint64_t)VP8LSubSampleSize(height, enc->transform_bits_); + const uint64_t total_size = + image_size + argb_scratch_size + transform_data_size; + uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem)); + if (mem == NULL) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + enc->argb_ = mem; + mem += image_size; + enc->argb_scratch_ = mem; + mem += argb_scratch_size; + enc->transform_data_ = mem; + enc->current_width_ = width; + + Error: + return err; +} + +// Bundles multiple (2, 4 or 8) pixels into a single pixel. +// Returns the new xsize. +static void BundleColorMap(const WebPPicture* const pic, + int xbits, uint32_t* bundled_argb, int xs) { + int y; + const int bit_depth = 1 << (3 - xbits); + uint32_t code = 0; + const uint32_t* argb = pic->argb; + const int width = pic->width; + const int height = pic->height; + + for (y = 0; y < height; ++y) { + int x; + for (x = 0; x < width; ++x) { + const int mask = (1 << xbits) - 1; + const int xsub = x & mask; + if (xsub == 0) { + code = 0; + } + // TODO(vikasa): simplify the bundling logic. + code |= (argb[x] & 0xff00) << (bit_depth * xsub); + bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code; + } + argb += pic->argb_stride; + } +} + +// Note: Expects "enc->palette_" to be set properly. +// Also, "enc->palette_" will be modified after this call and should not be used +// later. +static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw, + VP8LEncoder* const enc, int quality) { + WebPEncodingError err = VP8_ENC_OK; + int i, x, y; + const WebPPicture* const pic = enc->pic_; + uint32_t* argb = pic->argb; + const int width = pic->width; + const int height = pic->height; + uint32_t* const palette = enc->palette_; + const int palette_size = enc->palette_size_; + + // Replace each input pixel by corresponding palette index. + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + const uint32_t pix = argb[x]; + for (i = 0; i < palette_size; ++i) { + if (pix == palette[i]) { + argb[x] = 0xff000000u | (i << 8); + break; + } + } + } + argb += pic->argb_stride; + } + + // Save palette to bitstream. + VP8LWriteBits(bw, 1, TRANSFORM_PRESENT); + VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM); + assert(palette_size >= 1); + VP8LWriteBits(bw, 8, palette_size - 1); + for (i = palette_size - 1; i >= 1; --i) { + palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); + } + if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) { + err = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Error; + } + + if (palette_size <= 16) { + // Image can be packed (multiple pixels per uint32_t). + int xbits = 1; + if (palette_size <= 2) { + xbits = 3; + } else if (palette_size <= 4) { + xbits = 2; + } + err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); + if (err != VP8_ENC_OK) goto Error; + BundleColorMap(pic, xbits, enc->argb_, enc->current_width_); + } + + Error: + return err; +} + +// ----------------------------------------------------------------------------- + +static int GetHistoBits(const WebPConfig* const config, + const WebPPicture* const pic) { + const int width = pic->width; + const int height = pic->height; + const uint64_t hist_size = sizeof(VP8LHistogram); + // Make tile size a function of encoding method (Range: 0 to 6). + int histo_bits = 7 - config->method; + while (1) { + const uint64_t huff_image_size = VP8LSubSampleSize(width, histo_bits) * + VP8LSubSampleSize(height, histo_bits) * + hist_size; + if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; + ++histo_bits; + } + return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : + (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; +} + +static void InitEncParams(VP8LEncoder* const enc) { + const WebPConfig* const config = enc->config_; + const WebPPicture* const picture = enc->pic_; + const int method = config->method; + const float quality = config->quality; + enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4; + enc->histo_bits_ = GetHistoBits(config, picture); + enc->cache_bits_ = (quality <= 25.f) ? 0 : 7; +} + +// ----------------------------------------------------------------------------- +// VP8LEncoder + +static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, + const WebPPicture* const picture) { + VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc)); + if (enc == NULL) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + return NULL; + } + enc->config_ = config; + enc->pic_ = picture; + return enc; +} + +static void VP8LEncoderDelete(VP8LEncoder* enc) { + free(enc->argb_); + free(enc); +} + +// ----------------------------------------------------------------------------- +// Main call + +WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, + VP8LBitWriter* const bw) { + WebPEncodingError err = VP8_ENC_OK; + const int quality = (int)config->quality; + const int width = picture->width; + const int height = picture->height; + VP8LEncoder* const enc = VP8LEncoderNew(config, picture); + const size_t byte_position = VP8LBitWriterNumBytes(bw); + + if (enc == NULL) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + InitEncParams(enc); + + // --------------------------------------------------------------------------- + // Analyze image (entropy, num_palettes etc) + + if (!VP8LEncAnalyze(enc, config->image_hint)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + if (enc->use_palette_) { + err = ApplyPalette(bw, enc, quality); + if (err != VP8_ENC_OK) goto Error; + // Color cache is disabled for palette. + enc->cache_bits_ = 0; + } + + // In case image is not packed. + if (enc->argb_ == NULL) { + int y; + err = AllocateTransformBuffer(enc, width, height); + if (err != VP8_ENC_OK) goto Error; + for (y = 0; y < height; ++y) { + memcpy(enc->argb_ + y * width, + picture->argb + y * picture->argb_stride, + width * sizeof(*enc->argb_)); + } + enc->current_width_ = width; + } + + // --------------------------------------------------------------------------- + // Apply transforms and write transform data. + + if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + if (enc->use_predict_) { + if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) { + err = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Error; + } + } + + if (enc->use_cross_color_) { + if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) { + err = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Error; + } + } + + VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms. + + // --------------------------------------------------------------------------- + // Estimate the color cache size. + + if (enc->cache_bits_ > 0) { + if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_, + height, &enc->cache_bits_)) { + err = VP8_ENC_ERROR_INVALID_CONFIGURATION; + goto Error; + } + } + + // --------------------------------------------------------------------------- + // Encode and write the transformed image. + + if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height, + quality, enc->cache_bits_, enc->histo_bits_)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + if (picture->stats != NULL) { + WebPAuxStats* const stats = picture->stats; + stats->lossless_features = 0; + if (enc->use_predict_) stats->lossless_features |= 1; + if (enc->use_cross_color_) stats->lossless_features |= 2; + if (enc->use_subtract_green_) stats->lossless_features |= 4; + if (enc->use_palette_) stats->lossless_features |= 8; + stats->histogram_bits = enc->histo_bits_; + stats->transform_bits = enc->transform_bits_; + stats->cache_bits = enc->cache_bits_; + stats->palette_size = enc->palette_size_; + stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position); + } + + Error: + VP8LEncoderDelete(enc); + return err; +} + +int VP8LEncodeImage(const WebPConfig* const config, + const WebPPicture* const picture) { + int width, height; + int has_alpha; + size_t coded_size; + int percent = 0; + WebPEncodingError err = VP8_ENC_OK; + VP8LBitWriter bw; + + if (picture == NULL) return 0; + + if (config == NULL || picture->argb == NULL) { + err = VP8_ENC_ERROR_NULL_PARAMETER; + WebPEncodingSetError(picture, err); + return 0; + } + + width = picture->width; + height = picture->height; + if (!VP8LBitWriterInit(&bw, (width * height) >> 1)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + if (!WebPReportProgress(picture, 1, &percent)) { + UserAbort: + err = VP8_ENC_ERROR_USER_ABORT; + goto Error; + } + // Reset stats (for pure lossless coding) + if (picture->stats != NULL) { + WebPAuxStats* const stats = picture->stats; + memset(stats, 0, sizeof(*stats)); + stats->PSNR[0] = 99.f; + stats->PSNR[1] = 99.f; + stats->PSNR[2] = 99.f; + stats->PSNR[3] = 99.f; + stats->PSNR[4] = 99.f; + } + + // Write image size. + if (!WriteImageSize(picture, &bw)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + has_alpha = WebPPictureHasTransparency(picture); + // Write the non-trivial Alpha flag and lossless version. + if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { + err = VP8_ENC_ERROR_OUT_OF_MEMORY; + goto Error; + } + + if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort; + + // Encode main image stream. + err = VP8LEncodeStream(config, picture, &bw); + if (err != VP8_ENC_OK) goto Error; + + // TODO(skal): have a fine-grained progress report in VP8LEncodeStream(). + if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort; + + // Finish the RIFF chunk. + err = WriteImage(picture, &bw, &coded_size); + if (err != VP8_ENC_OK) goto Error; + + if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; + + // Save size. + if (picture->stats != NULL) { + picture->stats->coded_size += (int)coded_size; + picture->stats->lossless_size = (int)coded_size; + } + + if (picture->extra_info != NULL) { + const int mb_w = (width + 15) >> 4; + const int mb_h = (height + 15) >> 4; + memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); + } + + Error: + if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; + VP8LBitWriterDestroy(&bw); + if (err != VP8_ENC_OK) { + WebPEncodingSetError(picture, err); + return 0; + } + return 1; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/enc/vp8li.h b/external/libwebp/enc/vp8li.h new file mode 100644 index 0000000000..eae90dd61f --- /dev/null +++ b/external/libwebp/enc/vp8li.h @@ -0,0 +1,68 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Lossless encoder: internal header. +// +// Author: Vikas Arora (vikaas.arora@gmail.com) + +#ifndef WEBP_ENC_VP8LI_H_ +#define WEBP_ENC_VP8LI_H_ + +#include "./histogram.h" +#include "../utils/bit_writer.h" +#include "../webp/encode.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct { + const WebPConfig* config_; // user configuration and parameters + const WebPPicture* pic_; // input picture. + + uint32_t* argb_; // Transformed argb image data. + uint32_t* argb_scratch_; // Scratch memory for argb rows + // (used for prediction). + uint32_t* transform_data_; // Scratch memory for transform data. + int current_width_; // Corresponds to packed image width. + + // Encoding parameters derived from quality parameter. + int histo_bits_; + int transform_bits_; + int cache_bits_; // If equal to 0, don't use color cache. + + // Encoding parameters derived from image characteristics. + int use_cross_color_; + int use_subtract_green_; + int use_predict_; + int use_palette_; + int palette_size_; + uint32_t palette_[MAX_PALETTE_SIZE]; +} VP8LEncoder; + +//------------------------------------------------------------------------------ +// internal functions. Not public. + +// Encodes the picture. +// Returns 0 if config or picture is NULL or picture doesn't have valid argb +// input. +int VP8LEncodeImage(const WebPConfig* const config, + const WebPPicture* const picture); + +// Encodes the main image stream using the supplied bit writer. +WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, + VP8LBitWriter* const bw); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_ENC_VP8LI_H_ */ diff --git a/external/libwebp/enc/webpenc.c b/external/libwebp/enc/webpenc.c new file mode 100644 index 0000000000..3c275589fc --- /dev/null +++ b/external/libwebp/enc/webpenc.c @@ -0,0 +1,389 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// WebP encoder: main entry point +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include +#include + +#include "./vp8enci.h" +#include "./vp8li.h" +#include "../utils/utils.h" + +// #define PRINT_MEMORY_INFO + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#ifdef PRINT_MEMORY_INFO +#include +#endif + +//------------------------------------------------------------------------------ + +int WebPGetEncoderVersion(void) { + return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION; +} + +//------------------------------------------------------------------------------ +// WebPPicture +//------------------------------------------------------------------------------ + +static int DummyWriter(const uint8_t* data, size_t data_size, + const WebPPicture* const picture) { + // The following are to prevent 'unused variable' error message. + (void)data; + (void)data_size; + (void)picture; + return 1; +} + +int WebPPictureInitInternal(WebPPicture* picture, int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { + return 0; // caller/system version mismatch! + } + if (picture != NULL) { + memset(picture, 0, sizeof(*picture)); + picture->writer = DummyWriter; + WebPEncodingSetError(picture, VP8_ENC_OK); + } + return 1; +} + +//------------------------------------------------------------------------------ +// VP8Encoder +//------------------------------------------------------------------------------ + +static void ResetSegmentHeader(VP8Encoder* const enc) { + VP8SegmentHeader* const hdr = &enc->segment_hdr_; + hdr->num_segments_ = enc->config_->segments; + hdr->update_map_ = (hdr->num_segments_ > 1); + hdr->size_ = 0; +} + +static void ResetFilterHeader(VP8Encoder* const enc) { + VP8FilterHeader* const hdr = &enc->filter_hdr_; + hdr->simple_ = 1; + hdr->level_ = 0; + hdr->sharpness_ = 0; + hdr->i4x4_lf_delta_ = 0; +} + +static void ResetBoundaryPredictions(VP8Encoder* const enc) { + // init boundary values once for all + // Note: actually, initializing the preds_[] is only needed for intra4. + int i; + uint8_t* const top = enc->preds_ - enc->preds_w_; + uint8_t* const left = enc->preds_ - 1; + for (i = -1; i < 4 * enc->mb_w_; ++i) { + top[i] = B_DC_PRED; + } + for (i = 0; i < 4 * enc->mb_h_; ++i) { + left[i * enc->preds_w_] = B_DC_PRED; + } + enc->nz_[-1] = 0; // constant +} + +// Map configured quality level to coding tools used. +//-------------+---+---+---+---+---+---+ +// Quality | 0 | 1 | 2 | 3 | 4 | 5 + +//-------------+---+---+---+---+---+---+ +// dynamic prob| ~ | x | x | x | x | x | +//-------------+---+---+---+---+---+---+ +// rd-opt modes| | | x | x | x | x | +//-------------+---+---+---+---+---+---+ +// fast i4/i16 | x | x | | | | | +//-------------+---+---+---+---+---+---+ +// rd-opt i4/16| | | x | x | x | x | +//-------------+---+---+---+---+---+---+ +// Trellis | | x | | | x | x | +//-------------+---+---+---+---+---+---+ +// full-SNS | | | | | | x | +//-------------+---+---+---+---+---+---+ + +static void MapConfigToTools(VP8Encoder* const enc) { + const int method = enc->config_->method; + const int limit = 100 - enc->config_->partition_limit; + enc->method_ = method; + enc->rd_opt_level_ = (method >= 6) ? 3 + : (method >= 5) ? 2 + : (method >= 3) ? 1 + : 0; + enc->max_i4_header_bits_ = + 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block + (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. +} + +// Memory scaling with dimensions: +// memory (bytes) ~= 2.25 * w + 0.0625 * w * h +// +// Typical memory footprint (768x510 picture) +// Memory used: +// encoder: 33919 +// block cache: 2880 +// info: 3072 +// preds: 24897 +// top samples: 1623 +// non-zero: 196 +// lf-stats: 2048 +// total: 68635 +// Transcient object sizes: +// VP8EncIterator: 352 +// VP8ModeScore: 912 +// VP8SegmentInfo: 532 +// VP8Proba: 31032 +// LFStats: 2048 +// Picture size (yuv): 589824 + +static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, + WebPPicture* const picture) { + const int use_filter = + (config->filter_strength > 0) || (config->autofilter > 0); + const int mb_w = (picture->width + 15) >> 4; + const int mb_h = (picture->height + 15) >> 4; + const int preds_w = 4 * mb_w + 1; + const int preds_h = 4 * mb_h + 1; + const size_t preds_size = preds_w * preds_h * sizeof(uint8_t); + const int top_stride = mb_w * 16; + const size_t nz_size = (mb_w + 1) * sizeof(uint32_t); + const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t); + const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo); + const size_t samples_size = (2 * top_stride + // top-luma/u/v + 16 + 16 + 16 + 8 + 1 + // left y/u/v + 2 * ALIGN_CST) // align all + * sizeof(uint8_t); + const size_t lf_stats_size = + config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0; + VP8Encoder* enc; + uint8_t* mem; + const uint64_t size = (uint64_t)sizeof(VP8Encoder) // main struct + + ALIGN_CST // cache alignment + + cache_size // working caches + + info_size // modes info + + preds_size // prediction modes + + samples_size // top/left samples + + nz_size // coeff context bits + + lf_stats_size; // autofilter stats + +#ifdef PRINT_MEMORY_INFO + printf("===================================\n"); + printf("Memory used:\n" + " encoder: %ld\n" + " block cache: %ld\n" + " info: %ld\n" + " preds: %ld\n" + " top samples: %ld\n" + " non-zero: %ld\n" + " lf-stats: %ld\n" + " total: %ld\n", + sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size, + preds_size, samples_size, nz_size, lf_stats_size, size); + printf("Transcient object sizes:\n" + " VP8EncIterator: %ld\n" + " VP8ModeScore: %ld\n" + " VP8SegmentInfo: %ld\n" + " VP8Proba: %ld\n" + " LFStats: %ld\n", + sizeof(VP8EncIterator), sizeof(VP8ModeScore), + sizeof(VP8SegmentInfo), sizeof(VP8Proba), + sizeof(LFStats)); + printf("Picture size (yuv): %ld\n", + mb_w * mb_h * 384 * sizeof(uint8_t)); + printf("===================================\n"); +#endif + mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem)); + if (mem == NULL) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + return NULL; + } + enc = (VP8Encoder*)mem; + mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc)); + memset(enc, 0, sizeof(*enc)); + enc->num_parts_ = 1 << config->partitions; + enc->mb_w_ = mb_w; + enc->mb_h_ = mb_h; + enc->preds_w_ = preds_w; + enc->yuv_in_ = (uint8_t*)mem; + mem += YUV_SIZE; + enc->yuv_out_ = (uint8_t*)mem; + mem += YUV_SIZE; + enc->yuv_out2_ = (uint8_t*)mem; + mem += YUV_SIZE; + enc->yuv_p_ = (uint8_t*)mem; + mem += PRED_SIZE; + enc->mb_info_ = (VP8MBInfo*)mem; + mem += info_size; + enc->preds_ = ((uint8_t*)mem) + 1 + enc->preds_w_; + mem += preds_w * preds_h * sizeof(uint8_t); + enc->nz_ = 1 + (uint32_t*)mem; + mem += nz_size; + enc->lf_stats_ = lf_stats_size ? (LFStats*)DO_ALIGN(mem) : NULL; + mem += lf_stats_size; + + // top samples (all 16-aligned) + mem = (uint8_t*)DO_ALIGN(mem); + enc->y_top_ = (uint8_t*)mem; + enc->uv_top_ = enc->y_top_ + top_stride; + mem += 2 * top_stride; + mem = (uint8_t*)DO_ALIGN(mem + 1); + enc->y_left_ = (uint8_t*)mem; + mem += 16 + 16; + enc->u_left_ = (uint8_t*)mem; + mem += 16; + enc->v_left_ = (uint8_t*)mem; + mem += 8; + + enc->config_ = config; + enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; + enc->pic_ = picture; + enc->percent_ = 0; + + MapConfigToTools(enc); + VP8EncDspInit(); + VP8DefaultProbas(enc); + ResetSegmentHeader(enc); + ResetFilterHeader(enc); + ResetBoundaryPredictions(enc); + + VP8EncInitAlpha(enc); +#ifdef WEBP_EXPERIMENTAL_FEATURES + VP8EncInitLayer(enc); +#endif + + return enc; +} + +static void DeleteVP8Encoder(VP8Encoder* enc) { + if (enc != NULL) { + VP8EncDeleteAlpha(enc); +#ifdef WEBP_EXPERIMENTAL_FEATURES + VP8EncDeleteLayer(enc); +#endif + free(enc); + } +} + +//------------------------------------------------------------------------------ + +static double GetPSNR(uint64_t err, uint64_t size) { + return err ? 10. * log10(255. * 255. * size / err) : 99.; +} + +static void FinalizePSNR(const VP8Encoder* const enc) { + WebPAuxStats* stats = enc->pic_->stats; + const uint64_t size = enc->sse_count_; + const uint64_t* const sse = enc->sse_; + stats->PSNR[0] = (float)GetPSNR(sse[0], size); + stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); + stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); + stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); + stats->PSNR[4] = (float)GetPSNR(sse[3], size); +} + +static void StoreStats(VP8Encoder* const enc) { + WebPAuxStats* const stats = enc->pic_->stats; + if (stats != NULL) { + int i, s; + for (i = 0; i < NUM_MB_SEGMENTS; ++i) { + stats->segment_level[i] = enc->dqm_[i].fstrength_; + stats->segment_quant[i] = enc->dqm_[i].quant_; + for (s = 0; s <= 2; ++s) { + stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; + } + } + FinalizePSNR(enc); + stats->coded_size = enc->coded_size_; + for (i = 0; i < 3; ++i) { + stats->block_count[i] = enc->block_count_[i]; + } + } + WebPReportProgress(enc->pic_, 100, &enc->percent_); // done! +} + +int WebPEncodingSetError(const WebPPicture* const pic, + WebPEncodingError error) { + assert((int)error < VP8_ENC_ERROR_LAST); + assert((int)error >= VP8_ENC_OK); + ((WebPPicture*)pic)->error_code = error; + return 0; +} + +int WebPReportProgress(const WebPPicture* const pic, + int percent, int* const percent_store) { + if (percent_store != NULL && percent != *percent_store) { + *percent_store = percent; + if (pic->progress_hook && !pic->progress_hook(percent, pic)) { + // user abort requested + WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); + return 0; + } + } + return 1; // ok +} +//------------------------------------------------------------------------------ + +int WebPEncode(const WebPConfig* config, WebPPicture* pic) { + int ok; + + if (pic == NULL) + return 0; + WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far + if (config == NULL) // bad params + return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); + if (!WebPValidateConfig(config)) + return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); + if (pic->width <= 0 || pic->height <= 0) + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); + if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) + return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); + + if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); + + if (!config->lossless) { + VP8Encoder* enc = NULL; + if (pic->y == NULL || pic->u == NULL || pic->v == NULL) { + if (pic->argb != NULL) { + if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0; + } else { + return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); + } + } + + enc = InitVP8Encoder(config, pic); + if (enc == NULL) return 0; // pic->error is already set. + // Note: each of the tasks below account for 20% in the progress report. + ok = VP8EncAnalyze(enc) + && VP8StatLoop(enc) + && VP8EncLoop(enc) + && VP8EncFinishAlpha(enc) +#ifdef WEBP_EXPERIMENTAL_FEATURES + && VP8EncFinishLayer(enc) +#endif + && VP8EncWrite(enc); + StoreStats(enc); + if (!ok) { + VP8EncFreeBitWriters(enc); + } + DeleteVP8Encoder(enc); + } else { + if (pic->argb == NULL) + return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); + + ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. + } + + return ok; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/mux/Makefile.am b/external/libwebp/mux/Makefile.am new file mode 100644 index 0000000000..3beb240eef --- /dev/null +++ b/external/libwebp/mux/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src +lib_LTLIBRARIES = libwebpmux.la + +libwebpmux_la_SOURCES = +libwebpmux_la_SOURCES += demux.c +libwebpmux_la_SOURCES += muxedit.c +libwebpmux_la_SOURCES += muxi.h +libwebpmux_la_SOURCES += muxinternal.c +libwebpmux_la_SOURCES += muxread.c + +libwebpmuxinclude_HEADERS = +libwebpmuxinclude_HEADERS += ../webp/mux.h +libwebpmuxinclude_HEADERS += ../webp/types.h + +libwebpmux_la_LDFLAGS = -version-info 0:0:0 +libwebpmuxincludedir = $(includedir)/webp diff --git a/external/libwebp/mux/demux.c b/external/libwebp/mux/demux.c new file mode 100644 index 0000000000..4519f7d55b --- /dev/null +++ b/external/libwebp/mux/demux.c @@ -0,0 +1,902 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// WebP container demux. +// + +#include "../webp/mux.h" + +#include +#include + +#include "../webp/decode.h" // WebPGetInfo +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24) + +typedef struct { + size_t start_; // start location of the data + size_t end_; // end location + size_t riff_end_; // riff chunk end location, can be > end_. + size_t buf_size_; // size of the buffer + const uint8_t* buf_; +} MemBuffer; + +typedef struct { + size_t offset_; + size_t size_; +} ChunkData; + +typedef struct Frame { + int x_offset_, y_offset_; + int width_, height_; + int duration_; + int is_tile_; // this is an image fragment from a 'TILE'. + int frame_num_; // the referent frame number for use in assembling tiles. + int complete_; // img_components_ contains a full image. + ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH + struct Frame* next_; +} Frame; + +typedef struct Chunk { + ChunkData data_; + struct Chunk* next_; +} Chunk; + +struct WebPDemuxer { + MemBuffer mem_; + WebPDemuxState state_; + int is_ext_format_; + uint32_t feature_flags_; + int canvas_width_, canvas_height_; + int loop_count_; + int num_frames_; + Frame* frames_; + Chunk* chunks_; // non-image chunks +}; + +typedef enum { + PARSE_OK, + PARSE_NEED_MORE_DATA, + PARSE_ERROR +} ParseStatus; + +typedef struct ChunkParser { + uint8_t id[4]; + ParseStatus (*parse)(WebPDemuxer* const dmux); + int (*valid)(const WebPDemuxer* const dmux); +} ChunkParser; + +static ParseStatus ParseSingleImage(WebPDemuxer* const dmux); +static ParseStatus ParseVP8X(WebPDemuxer* const dmux); +static int IsValidSimpleFormat(const WebPDemuxer* const dmux); +static int IsValidExtendedFormat(const WebPDemuxer* const dmux); + +static const ChunkParser kMasterChunks[] = { + { { 'V', 'P', '8', ' ' }, ParseSingleImage, IsValidSimpleFormat }, + { { 'V', 'P', '8', 'L' }, ParseSingleImage, IsValidSimpleFormat }, + { { 'V', 'P', '8', 'X' }, ParseVP8X, IsValidExtendedFormat }, + { { '0', '0', '0', '0' }, NULL, NULL }, +}; + +// ----------------------------------------------------------------------------- +// MemBuffer + +static int RemapMemBuffer(MemBuffer* const mem, + const uint8_t* data, size_t size) { + if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + + mem->buf_ = data; + mem->end_ = mem->buf_size_ = size; + return 1; +} + +static int InitMemBuffer(MemBuffer* const mem, + const uint8_t* data, size_t size) { + memset(mem, 0, sizeof(*mem)); + return RemapMemBuffer(mem, data, size); +} + +// Return the remaining data size available in 'mem'. +static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) { + return (mem->end_ - mem->start_); +} + +// Return true if 'size' exceeds the end of the RIFF chunk. +static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) { + return (size > mem->riff_end_ - mem->start_); +} + +static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) { + mem->start_ += size; +} + +static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) { + mem->start_ -= size; +} + +static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) { + return mem->buf_ + mem->start_; +} + +static WEBP_INLINE uint8_t GetByte(MemBuffer* const mem) { + const uint8_t byte = mem->buf_[mem->start_]; + Skip(mem, 1); + return byte; +} + +// Read 16, 24 or 32 bits stored in little-endian order. +static WEBP_INLINE int ReadLE16s(const uint8_t* const data) { + return (int)(data[0] << 0) | (data[1] << 8); +} + +static WEBP_INLINE int ReadLE24s(const uint8_t* const data) { + return ReadLE16s(data) | (data[2] << 16); +} + +static WEBP_INLINE uint32_t ReadLE32(const uint8_t* const data) { + return (uint32_t)ReadLE24s(data) | (data[3] << 24); +} + +// In addition to reading, skip the read bytes. +static WEBP_INLINE int GetLE16s(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const int val = ReadLE16s(data); + Skip(mem, 2); + return val; +} + +static WEBP_INLINE int GetLE24s(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const int val = ReadLE24s(data); + Skip(mem, 3); + return val; +} + +static WEBP_INLINE uint32_t GetLE32(MemBuffer* const mem) { + const uint8_t* const data = mem->buf_ + mem->start_; + const uint32_t val = ReadLE32(data); + Skip(mem, 4); + return val; +} + +// ----------------------------------------------------------------------------- +// Secondary chunk parsing + +static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { + Chunk** c = &dmux->chunks_; + while (*c != NULL) c = &(*c)->next_; + *c = chunk; + chunk->next_ = NULL; +} + +// Add a frame to the end of the list, ensuring the last frame is complete. +// Returns true on success, false otherwise. +static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { + const Frame* last_frame = NULL; + Frame** f = &dmux->frames_; + while (*f != NULL) { + last_frame = *f; + f = &(*f)->next_; + } + if (last_frame != NULL && !last_frame->complete_) return 0; + *f = frame; + frame->next_ = NULL; + return 1; +} + +// Store image bearing chunks to 'frame'. +static ParseStatus StoreFrame(int frame_num, MemBuffer* const mem, + Frame* const frame) { + int alpha_chunks = 0; + int image_chunks = 0; + int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE); + ParseStatus status = PARSE_OK; + + if (done) return PARSE_NEED_MORE_DATA; + + do { + const size_t chunk_start_offset = mem->start_; + const uint32_t fourcc = GetLE32(mem); + const uint32_t payload_size = GetLE32(mem); + const uint32_t payload_size_padded = payload_size + (payload_size & 1); + const size_t payload_available = (payload_size_padded > MemDataSize(mem)) + ? MemDataSize(mem) : payload_size_padded; + const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available; + + if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR; + if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA; + + switch (fourcc) { + case MKFOURCC('A', 'L', 'P', 'H'): + if (alpha_chunks == 0) { + ++alpha_chunks; + frame->img_components_[1].offset_ = chunk_start_offset; + frame->img_components_[1].size_ = chunk_size; + frame->frame_num_ = frame_num; + Skip(mem, payload_available); + } else { + goto Done; + } + break; + case MKFOURCC('V', 'P', '8', ' '): + case MKFOURCC('V', 'P', '8', 'L'): + if (image_chunks == 0) { + int width = 0, height = 0; + ++image_chunks; + frame->img_components_[0].offset_ = chunk_start_offset; + frame->img_components_[0].size_ = chunk_size; + // Extract the width and height from the bitstream, tolerating + // failures when the data is incomplete. + if (!WebPGetInfo(mem->buf_ + frame->img_components_[0].offset_, + frame->img_components_[0].size_, &width, &height) && + status != PARSE_NEED_MORE_DATA) { + return PARSE_ERROR; + } + + frame->width_ = width; + frame->height_ = height; + frame->frame_num_ = frame_num; + frame->complete_ = (status == PARSE_OK); + Skip(mem, payload_available); + } else { + goto Done; + } + break; + Done: + default: + // Restore fourcc/size when moving up one level in parsing. + Rewind(mem, CHUNK_HEADER_SIZE); + done = 1; + break; + } + + if (mem->start_ == mem->riff_end_) { + done = 1; + } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { + status = PARSE_NEED_MORE_DATA; + } + } while (!done && status == PARSE_OK); + + return status; +} + +// Creates a new Frame if 'actual_size' is within bounds and 'mem' contains +// enough data ('min_size') to parse the payload. +// Returns PARSE_OK on success with *frame pointing to the new Frame. +// Returns PARSE_NEED_MORE_DATA with insufficient data, PARSE_ERROR otherwise. +static ParseStatus NewFrame(const MemBuffer* const mem, + uint32_t min_size, uint32_t expected_size, + uint32_t actual_size, Frame** frame) { + if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; + if (actual_size < expected_size) return PARSE_ERROR; + if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; + + *frame = (Frame*)calloc(1, sizeof(**frame)); + return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; +} + +// Parse a 'FRM ' chunk and any image bearing chunks that immediately follow. +// 'frame_chunk_size' is the previously validated, padded chunk size. +static ParseStatus ParseFrame( + WebPDemuxer* const dmux, uint32_t frame_chunk_size) { + const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const uint32_t min_size = frame_chunk_size + CHUNK_HEADER_SIZE; + int added_frame = 0; + MemBuffer* const mem = &dmux->mem_; + Frame* frame; + ParseStatus status = + NewFrame(mem, min_size, FRAME_CHUNK_SIZE, frame_chunk_size, &frame); + if (status != PARSE_OK) return status; + + frame->x_offset_ = 2 * GetLE24s(mem); + frame->y_offset_ = 2 * GetLE24s(mem); + frame->width_ = 1 + GetLE24s(mem); + frame->height_ = 1 + GetLE24s(mem); + frame->duration_ = 1 + GetLE24s(mem); + Skip(mem, frame_chunk_size - FRAME_CHUNK_SIZE); // skip any trailing data. + if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { + return PARSE_ERROR; + } + + // Store a (potentially partial) frame only if the animation flag is set + // and there is some data in 'frame'. + status = StoreFrame(dmux->num_frames_ + 1, mem, frame); + if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { + added_frame = AddFrame(dmux, frame); + if (added_frame) { + ++dmux->num_frames_; + } else { + status = PARSE_ERROR; + } + } + + if (!added_frame) free(frame); + return status; +} + +// Parse a 'TILE' chunk and any image bearing chunks that immediately follow. +// 'tile_chunk_size' is the previously validated, padded chunk size. +static ParseStatus ParseTile(WebPDemuxer* const dmux, + uint32_t tile_chunk_size) { + const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); + const uint32_t min_size = tile_chunk_size + CHUNK_HEADER_SIZE; + int added_tile = 0; + MemBuffer* const mem = &dmux->mem_; + Frame* frame; + ParseStatus status = + NewFrame(mem, min_size, TILE_CHUNK_SIZE, tile_chunk_size, &frame); + if (status != PARSE_OK) return status; + + frame->is_tile_ = 1; + frame->x_offset_ = 2 * GetLE24s(mem); + frame->y_offset_ = 2 * GetLE24s(mem); + Skip(mem, tile_chunk_size - TILE_CHUNK_SIZE); // skip any trailing data. + + // Store a (potentially partial) tile only if the tile flag is set + // and the tile contains some data. + status = StoreFrame(dmux->num_frames_, mem, frame); + if (status != PARSE_ERROR && has_tiles && frame->frame_num_ > 0) { + // Note num_frames_ is incremented only when all tiles have been consumed. + added_tile = AddFrame(dmux, frame); + if (!added_tile) status = PARSE_ERROR; + } + + if (!added_tile) free(frame); + return status; +} + +// General chunk storage starting with the header at 'start_offset' allowing +// the user to request the payload via a fourcc string. 'size' includes the +// header and the unpadded payload size. +// Returns true on success, false otherwise. +static int StoreChunk(WebPDemuxer* const dmux, + size_t start_offset, uint32_t size) { + Chunk* const chunk = (Chunk*)calloc(1, sizeof(*chunk)); + if (chunk == NULL) return 0; + + chunk->data_.offset_ = start_offset; + chunk->data_.size_ = size; + AddChunk(dmux, chunk); + return 1; +} + +// ----------------------------------------------------------------------------- +// Primary chunk parsing + +static int ReadHeader(MemBuffer* const mem) { + const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE; + uint32_t riff_size; + + // Basic file level validation. + if (MemDataSize(mem) < min_size) return 0; + if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) || + memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) { + return 0; + } + + riff_size = ReadLE32(GetBuffer(mem) + TAG_SIZE); + if (riff_size < CHUNK_HEADER_SIZE) return 0; + if (riff_size > MAX_CHUNK_PAYLOAD) return 0; + + // There's no point in reading past the end of the RIFF chunk + mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; + if (mem->buf_size_ > mem->riff_end_) { + mem->buf_size_ = mem->end_ = mem->riff_end_; + } + + Skip(mem, RIFF_HEADER_SIZE); + return 1; +} + +static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { + const size_t min_size = CHUNK_HEADER_SIZE; + MemBuffer* const mem = &dmux->mem_; + Frame* frame; + ParseStatus status; + + if (dmux->frames_ != NULL) return PARSE_ERROR; + if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; + if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; + + frame = (Frame*)calloc(1, sizeof(*frame)); + if (frame == NULL) return PARSE_ERROR; + + status = StoreFrame(1, &dmux->mem_, frame); + if (status != PARSE_ERROR) { + const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); + // Clear any alpha when the alpha flag is missing. + if (!has_alpha && frame->img_components_[1].size_ > 0) { + frame->img_components_[1].offset_ = 0; + frame->img_components_[1].size_ = 0; + } + + // Use the frame width/height as the canvas values for non-vp8x files. + if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { + dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + dmux->canvas_width_ = frame->width_; + dmux->canvas_height_ = frame->height_; + } + AddFrame(dmux, frame); + dmux->num_frames_ = 1; + } else { + free(frame); + } + + return status; +} + +static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { + MemBuffer* const mem = &dmux->mem_; + int loop_chunks = 0; + uint32_t vp8x_size; + ParseStatus status = PARSE_OK; + + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + dmux->is_ext_format_ = 1; + Skip(mem, TAG_SIZE); // VP8X + vp8x_size = GetLE32(mem); + if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; + vp8x_size += vp8x_size & 1; + if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; + if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; + + dmux->feature_flags_ = GetByte(mem); + Skip(mem, 3); // Reserved. + dmux->canvas_width_ = 1 + GetLE24s(mem); + dmux->canvas_height_ = 1 + GetLE24s(mem); + if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { + return PARSE_ERROR; // image final dimension is too large + } + Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. + dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + + if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; + if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; + + do { + int store_chunk = 1; + const size_t chunk_start_offset = mem->start_; + const uint32_t fourcc = GetLE32(mem); + const uint32_t chunk_size = GetLE32(mem); + const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1); + + if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; + if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; + + switch (fourcc) { + case MKFOURCC('V', 'P', '8', 'X'): { + return PARSE_ERROR; + } + case MKFOURCC('A', 'L', 'P', 'H'): + case MKFOURCC('V', 'P', '8', ' '): + case MKFOURCC('V', 'P', '8', 'L'): { + Rewind(mem, CHUNK_HEADER_SIZE); + status = ParseSingleImage(dmux); + break; + } + case MKFOURCC('L', 'O', 'O', 'P'): { + if (chunk_size_padded < LOOP_CHUNK_SIZE) return PARSE_ERROR; + + if (MemDataSize(mem) < chunk_size_padded) { + status = PARSE_NEED_MORE_DATA; + } else if (loop_chunks == 0) { + ++loop_chunks; + dmux->loop_count_ = GetLE16s(mem); + Skip(mem, chunk_size_padded - LOOP_CHUNK_SIZE); + } else { + store_chunk = 0; + goto Skip; + } + break; + } + case MKFOURCC('F', 'R', 'M', ' '): { + status = ParseFrame(dmux, chunk_size_padded); + break; + } + case MKFOURCC('T', 'I', 'L', 'E'): { + if (dmux->num_frames_ == 0) dmux->num_frames_ = 1; + status = ParseTile(dmux, chunk_size_padded); + break; + } + case MKFOURCC('I', 'C', 'C', 'P'): { + store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); + goto Skip; + } + case MKFOURCC('M', 'E', 'T', 'A'): { + store_chunk = !!(dmux->feature_flags_ & META_FLAG); + goto Skip; + } + Skip: + default: { + if (chunk_size_padded <= MemDataSize(mem)) { + if (store_chunk) { + // Store only the chunk header and unpadded size as only the payload + // will be returned to the user. + if (!StoreChunk(dmux, chunk_start_offset, + CHUNK_HEADER_SIZE + chunk_size)) { + return PARSE_ERROR; + } + } + Skip(mem, chunk_size_padded); + } else { + status = PARSE_NEED_MORE_DATA; + } + } + } + + if (mem->start_ == mem->riff_end_) { + break; + } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { + status = PARSE_NEED_MORE_DATA; + } + } while (status == PARSE_OK); + + return status; +} + +// ----------------------------------------------------------------------------- +// Format validation + +static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { + const Frame* const frame = dmux->frames_; + if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + + if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; + if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; + + if (frame->width_ <= 0 || frame->height_ <= 0) return 0; + return 1; +} + +static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { + const int has_tiles = !!(dmux->feature_flags_ & TILE_FLAG); + const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const Frame* f; + + if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + + if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; + if (dmux->loop_count_ < 0) return 0; + if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; + + for (f = dmux->frames_; f != NULL; f = f->next_) { + const int cur_frame_set = f->frame_num_; + int frame_count = 0, tile_count = 0; + + // Check frame properties and if the image is composed of tiles that each + // fragment came from a 'TILE'. + for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { + const ChunkData* const image = f->img_components_; + const ChunkData* const alpha = f->img_components_ + 1; + + if (!has_tiles && f->is_tile_) return 0; + if (!has_frames && f->frame_num_ > 1) return 0; + if (f->x_offset_ < 0 || f->y_offset_ < 0) return 0; + if (f->complete_) { + if (alpha->size_ == 0 && image->size_ == 0) return 0; + // Ensure alpha precedes image bitstream. + if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { + return 0; + } + + if (f->width_ <= 0 || f->height_ <= 0) return 0; + } else { + // Ensure alpha precedes image bitstream. + if (alpha->size_ > 0 && image->size_ > 0 && + alpha->offset_ > image->offset_) { + return 0; + } + // There shouldn't be any frames after an incomplete one. + if (f->next_ != NULL) return 0; + } + + tile_count += f->is_tile_; + ++frame_count; + } + if (!has_tiles && frame_count > 1) return 0; + if (tile_count > 0 && frame_count != tile_count) return 0; + if (f == NULL) break; + } + return 1; +} + +// ----------------------------------------------------------------------------- +// WebPDemuxer object + +static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { + dmux->state_ = WEBP_DEMUX_PARSING_HEADER; + dmux->loop_count_ = 1; + dmux->canvas_width_ = -1; + dmux->canvas_height_ = -1; + dmux->mem_ = *mem; +} + +WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, + WebPDemuxState* state, int version) { + const ChunkParser* parser; + int partial; + ParseStatus status = PARSE_ERROR; + MemBuffer mem; + WebPDemuxer* dmux; + + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL; + if (data == NULL || data->bytes_ == NULL || data->size_ == 0) return NULL; + + if (!InitMemBuffer(&mem, data->bytes_, data->size_)) return NULL; + if (!ReadHeader(&mem)) return NULL; + + partial = (mem.buf_size_ < mem.riff_end_); + if (!allow_partial && partial) return NULL; + + dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux)); + if (dmux == NULL) return NULL; + InitDemux(dmux, &mem); + + for (parser = kMasterChunks; parser->parse != NULL; ++parser) { + if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { + status = parser->parse(dmux); + if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; + if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; + break; + } + } + if (state) *state = dmux->state_; + + if (status == PARSE_ERROR) { + WebPDemuxDelete(dmux); + return NULL; + } + return dmux; +} + +void WebPDemuxDelete(WebPDemuxer* dmux) { + Chunk* c; + Frame* f; + if (dmux == NULL) return; + + for (f = dmux->frames_; f != NULL;) { + Frame* const cur_frame = f; + f = f->next_; + free(cur_frame); + } + for (c = dmux->chunks_; c != NULL;) { + Chunk* const cur_chunk = c; + c = c->next_; + free(cur_chunk); + } + free(dmux); +} + +// ----------------------------------------------------------------------------- + +uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { + if (dmux == NULL) return 0; + + switch (feature) { + case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_; + case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_; + case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_; + case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// Frame iteration + +// Find the first 'frame_num' frame. There may be multiple in a tiled frame. +static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { + const Frame* f; + for (f = dmux->frames_; f != NULL; f = f->next_) { + if (frame_num == f->frame_num_) break; + } + return f; +} + +// Returns tile 'tile_num' and the total count. +static const Frame* GetTile( + const Frame* const frame_set, int tile_num, int* const count) { + const int this_frame = frame_set->frame_num_; + const Frame* f = frame_set; + const Frame* tile = NULL; + int total; + + for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) { + if (++total == tile_num) tile = f; + } + *count = total; + return tile; +} + +static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, + const Frame* const frame, + size_t* const data_size) { + *data_size = 0; + if (frame != NULL) { + const ChunkData* const image = frame->img_components_; + const ChunkData* const alpha = frame->img_components_ + 1; + size_t start_offset = image->offset_; + *data_size = image->size_; + + // if alpha exists it precedes image, update the size allowing for + // intervening chunks. + if (alpha->size_ > 0) { + const size_t inter_size = (image->offset_ > 0) + ? image->offset_ - (alpha->offset_ + alpha->size_) + : 0; + start_offset = alpha->offset_; + *data_size += alpha->size_ + inter_size; + } + return mem_buf + start_offset; + } + return NULL; +} + +// Create a whole 'frame' from VP8 (+ alpha) or lossless. +static int SynthesizeFrame(const WebPDemuxer* const dmux, + const Frame* const first_frame, + int tile_num, WebPIterator* const iter) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + int num_tiles; + size_t payload_size = 0; + const Frame* const tile = GetTile(first_frame, tile_num, &num_tiles); + const uint8_t* const payload = GetFramePayload(mem_buf, tile, &payload_size); + if (payload == NULL) return 0; + + iter->frame_num_ = first_frame->frame_num_; + iter->num_frames_ = dmux->num_frames_; + iter->tile_num_ = tile_num; + iter->num_tiles_ = num_tiles; + iter->x_offset_ = tile->x_offset_; + iter->y_offset_ = tile->y_offset_; + iter->width_ = tile->width_; + iter->height_ = tile->height_; + iter->duration_ = tile->duration_; + iter->complete_ = tile->complete_; + iter->tile_.bytes_ = payload; + iter->tile_.size_ = payload_size; + // TODO(jzern): adjust offsets for 'TILE's embedded in 'FRM 's + return 1; +} + +static int SetFrame(int frame_num, WebPIterator* const iter) { + const Frame* frame; + const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; + if (dmux == NULL || frame_num < 0) return 0; + if (frame_num > dmux->num_frames_) return 0; + if (frame_num == 0) frame_num = dmux->num_frames_; + + frame = GetFrame(dmux, frame_num); + return SynthesizeFrame(dmux, frame, 1, iter); +} + +int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) { + if (iter == NULL) return 0; + + memset(iter, 0, sizeof(*iter)); + iter->private_ = (void*)dmux; + return SetFrame(frame, iter); +} + +int WebPDemuxNextFrame(WebPIterator* iter) { + if (iter == NULL) return 0; + return SetFrame(iter->frame_num_ + 1, iter); +} + +int WebPDemuxPrevFrame(WebPIterator* iter) { + if (iter == NULL) return 0; + if (iter->frame_num_ <= 1) return 0; + return SetFrame(iter->frame_num_ - 1, iter); +} + +int WebPDemuxSelectTile(WebPIterator* iter, int tile) { + if (iter != NULL && iter->private_ != NULL && tile > 0) { + const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; + const Frame* const frame = GetFrame(dmux, iter->frame_num_); + if (frame == NULL) return 0; + + return SynthesizeFrame(dmux, frame, tile, iter); + } + return 0; +} + +void WebPDemuxReleaseIterator(WebPIterator* iter) { + (void)iter; +} + +// ----------------------------------------------------------------------------- +// Chunk iteration + +static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* c; + int count = 0; + for (c = dmux->chunks_; c != NULL; c = c->next_) { + const uint8_t* const header = mem_buf + c->data_.offset_; + if (!memcmp(header, fourcc, TAG_SIZE)) ++count; + } + return count; +} + +static const Chunk* GetChunk(const WebPDemuxer* const dmux, + const char fourcc[4], int chunk_num) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* c; + int count = 0; + for (c = dmux->chunks_; c != NULL; c = c->next_) { + const uint8_t* const header = mem_buf + c->data_.offset_; + if (!memcmp(header, fourcc, TAG_SIZE)) ++count; + if (count == chunk_num) break; + } + return c; +} + +static int SetChunk(const char fourcc[4], int chunk_num, + WebPChunkIterator* const iter) { + const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; + int count; + + if (dmux == NULL || fourcc == NULL || chunk_num < 0) return 0; + count = ChunkCount(dmux, fourcc); + if (count == 0) return 0; + if (chunk_num == 0) chunk_num = count; + + if (chunk_num <= count) { + const uint8_t* const mem_buf = dmux->mem_.buf_; + const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num); + iter->chunk_.bytes_ = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE; + iter->chunk_.size_ = chunk->data_.size_ - CHUNK_HEADER_SIZE; + iter->num_chunks_ = count; + iter->chunk_num_ = chunk_num; + return 1; + } + return 0; +} + +int WebPDemuxGetChunk(const WebPDemuxer* dmux, + const char fourcc[4], int chunk_num, + WebPChunkIterator* iter) { + if (iter == NULL) return 0; + + memset(iter, 0, sizeof(*iter)); + iter->private_ = (void*)dmux; + return SetChunk(fourcc, chunk_num, iter); +} + +int WebPDemuxNextChunk(WebPChunkIterator* iter) { + if (iter != NULL) { + const char* const fourcc = + (const char*)iter->chunk_.bytes_ - CHUNK_HEADER_SIZE; + return SetChunk(fourcc, iter->chunk_num_ + 1, iter); + } + return 0; +} + +int WebPDemuxPrevChunk(WebPChunkIterator* iter) { + if (iter != NULL && iter->chunk_num_ > 1) { + const char* const fourcc = + (const char*)iter->chunk_.bytes_ - CHUNK_HEADER_SIZE; + return SetChunk(fourcc, iter->chunk_num_ - 1, iter); + } + return 0; +} + +void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { + (void)iter; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/mux/muxedit.c b/external/libwebp/mux/muxedit.c new file mode 100644 index 0000000000..08629d4ae2 --- /dev/null +++ b/external/libwebp/mux/muxedit.c @@ -0,0 +1,712 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Set and delete APIs for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "./muxi.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Life of a mux object. + +static void MuxInit(WebPMux* const mux) { + if (mux == NULL) return; + memset(mux, 0, sizeof(*mux)); +} + +WebPMux* WebPNewInternal(int version) { + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { + return NULL; + } else { + WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux)); + // If mux is NULL MuxInit is a noop. + MuxInit(mux); + return mux; + } +} + +static void DeleteAllChunks(WebPChunk** const chunk_list) { + while (*chunk_list) { + *chunk_list = ChunkDelete(*chunk_list); + } +} + +static void MuxRelease(WebPMux* const mux) { + if (mux == NULL) return; + MuxImageDeleteAll(&mux->images_); + DeleteAllChunks(&mux->vp8x_); + DeleteAllChunks(&mux->iccp_); + DeleteAllChunks(&mux->loop_); + DeleteAllChunks(&mux->meta_); + DeleteAllChunks(&mux->unknown_); +} + +void WebPMuxDelete(WebPMux* mux) { + // If mux is NULL MuxRelease is a noop. + MuxRelease(mux); + free(mux); +} + +//------------------------------------------------------------------------------ +// Helper method(s). + +// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). +#define SWITCH_ID_LIST(INDEX, LIST) \ + if (idx == (INDEX)) { \ + err = ChunkAssignData(&chunk, data, copy_data, kChunks[(INDEX)].tag); \ + if (err == WEBP_MUX_OK) { \ + err = ChunkSetNth(&chunk, (LIST), nth); \ + } \ + return err; \ + } + +static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth, + const WebPData* const data, int copy_data) { + WebPChunk chunk; + WebPMuxError err = WEBP_MUX_NOT_FOUND; + assert(mux != NULL); + assert(!IsWPI(kChunks[idx].id)); + + ChunkInit(&chunk); + SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); + SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); + SWITCH_ID_LIST(IDX_LOOP, &mux->loop_); + SWITCH_ID_LIST(IDX_META, &mux->meta_); + if (idx == IDX_UNKNOWN && data->size_ > TAG_SIZE) { + // For raw-data unknown chunk, the first four bytes should be the tag to be + // used for the chunk. + const WebPData tmp = { data->bytes_ + TAG_SIZE, data->size_ - TAG_SIZE }; + err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes_ + 0)); + if (err == WEBP_MUX_OK) + err = ChunkSetNth(&chunk, &mux->unknown_, nth); + } + return err; +} +#undef SWITCH_ID_LIST + +static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag, + const uint8_t* data, size_t size, + int copy_data) { + const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag); + const WebPData chunk_data = { data, size }; + assert(mux != NULL); + assert(size <= MAX_CHUNK_PAYLOAD); + assert(idx != IDX_NIL); + return MuxSet(mux, idx, nth, &chunk_data, copy_data); +} + +// Create data for frame/tile given image data, offsets and duration. +static WebPMuxError CreateFrameTileData(const WebPData* const image, + int x_offset, int y_offset, + int duration, int is_lossless, + int is_frame, + WebPData* const frame_tile) { + int width; + int height; + uint8_t* frame_tile_bytes; + const size_t frame_tile_size = kChunks[is_frame ? IDX_FRAME : IDX_TILE].size; + + const int ok = is_lossless ? + VP8LGetInfo(image->bytes_, image->size_, &width, &height, NULL) : + VP8GetInfo(image->bytes_, image->size_, image->size_, &width, &height); + if (!ok) return WEBP_MUX_INVALID_ARGUMENT; + + assert(width > 0 && height > 0 && duration > 0); + // Note: assertion on upper bounds is done in PutLE24(). + + frame_tile_bytes = (uint8_t*)malloc(frame_tile_size); + if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; + + PutLE24(frame_tile_bytes + 0, x_offset / 2); + PutLE24(frame_tile_bytes + 3, y_offset / 2); + + if (is_frame) { + PutLE24(frame_tile_bytes + 6, width - 1); + PutLE24(frame_tile_bytes + 9, height - 1); + PutLE24(frame_tile_bytes + 12, duration - 1); + } + + frame_tile->bytes_ = frame_tile_bytes; + frame_tile->size_ = frame_tile_size; + return WEBP_MUX_OK; +} + +// Outputs image data given a bitstream. The bitstream can either be a +// single-image WebP file or raw VP8/VP8L data. +// Also outputs 'is_lossless' to be true if the given bitstream is lossless. +static WebPMuxError GetImageData(const WebPData* const bitstream, + WebPData* const image, WebPData* const alpha, + int* const is_lossless) { + WebPDataInit(alpha); // Default: no alpha. + if (bitstream->size_ < TAG_SIZE || + memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) { + // It is NOT webp file data. Return input data as is. + *image = *bitstream; + } else { + // It is webp file data. Extract image data from it. + const WebPMuxImage* wpi; + WebPMux* const mux = WebPMuxCreate(bitstream, 0); + if (mux == NULL) return WEBP_MUX_BAD_DATA; + wpi = mux->images_; + assert(wpi != NULL && wpi->img_ != NULL); + *image = wpi->img_->data_; + if (wpi->alpha_ != NULL) { + *alpha = wpi->alpha_->data_; + } + WebPMuxDelete(mux); + } + *is_lossless = VP8LCheckSignature(image->bytes_, image->size_); + return WEBP_MUX_OK; +} + +static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) { + WebPMuxError err = WEBP_MUX_NOT_FOUND; + assert(chunk_list); + while (*chunk_list) { + WebPChunk* const chunk = *chunk_list; + if (chunk->tag_ == tag) { + *chunk_list = ChunkDelete(chunk); + err = WEBP_MUX_OK; + } else { + chunk_list = &chunk->next_; + } + } + return err; +} + +static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, CHUNK_INDEX idx) { + const WebPChunkId id = kChunks[idx].id; + WebPChunk** chunk_list; + + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; + + chunk_list = MuxGetChunkListFromId(mux, id); + if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + return DeleteChunks(chunk_list, kChunks[idx].tag); +} + +static WebPMuxError DeleteLoopCount(WebPMux* const mux) { + return MuxDeleteAllNamedData(mux, IDX_LOOP); +} + +//------------------------------------------------------------------------------ +// Set API(s). + +WebPMuxError WebPMuxSetImage(WebPMux* mux, + const WebPData* bitstream, int copy_data) { + WebPMuxError err; + WebPChunk chunk; + WebPMuxImage wpi; + WebPData image; + WebPData alpha; + int is_lossless; + int image_tag; + + if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || + bitstream->size_ > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // If given data is for a whole webp file, + // extract only the VP8/VP8L data from it. + err = GetImageData(bitstream, &image, &alpha, &is_lossless); + if (err != WEBP_MUX_OK) return err; + image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; + + // Delete the existing images. + MuxImageDeleteAll(&mux->images_); + + MuxImageInit(&wpi); + + if (alpha.bytes_ != NULL) { // Add alpha chunk. + ChunkInit(&chunk); + err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); + if (err != WEBP_MUX_OK) goto Err; + err = ChunkSetNth(&chunk, &wpi.alpha_, 1); + if (err != WEBP_MUX_OK) goto Err; + } + + // Add image chunk. + ChunkInit(&chunk); + err = ChunkAssignData(&chunk, &image, copy_data, image_tag); + if (err != WEBP_MUX_OK) goto Err; + err = ChunkSetNth(&chunk, &wpi.img_, 1); + if (err != WEBP_MUX_OK) goto Err; + + // Add this image to mux. + err = MuxImagePush(&wpi, &mux->images_); + if (err != WEBP_MUX_OK) goto Err; + + // All OK. + return WEBP_MUX_OK; + + Err: + // Something bad happened. + ChunkRelease(&chunk); + MuxImageRelease(&wpi); + return err; +} + +WebPMuxError WebPMuxSetMetadata(WebPMux* mux, const WebPData* metadata, + int copy_data) { + WebPMuxError err; + + if (mux == NULL || metadata == NULL || metadata->bytes_ == NULL || + metadata->size_ > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Delete the existing metadata chunk(s). + err = WebPMuxDeleteMetadata(mux); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Add the given metadata chunk. + return MuxSet(mux, IDX_META, 1, metadata, copy_data); +} + +WebPMuxError WebPMuxSetColorProfile(WebPMux* mux, const WebPData* color_profile, + int copy_data) { + WebPMuxError err; + + if (mux == NULL || color_profile == NULL || color_profile->bytes_ == NULL || + color_profile->size_ > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Delete the existing ICCP chunk(s). + err = WebPMuxDeleteColorProfile(mux); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Add the given ICCP chunk. + return MuxSet(mux, IDX_ICCP, 1, color_profile, copy_data); +} + +WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) { + WebPMuxError err; + uint8_t* data = NULL; + + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT; + + // Delete the existing LOOP chunk(s). + err = DeleteLoopCount(mux); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Add the given loop count. + data = (uint8_t*)malloc(kChunks[IDX_LOOP].size); + if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + + PutLE16(data, loop_count); + err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data, + kChunks[IDX_LOOP].size, 1); + free(data); + return err; +} + +static WebPMuxError MuxPushFrameTileInternal( + WebPMux* const mux, const WebPData* const bitstream, int x_offset, + int y_offset, int duration, int copy_data, uint32_t tag) { + WebPChunk chunk; + WebPData image; + WebPData alpha; + WebPMuxImage wpi; + WebPMuxError err; + WebPData frame_tile; + const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0; + int is_lossless; + int image_tag; + + // Sanity checks. + if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || + bitstream->size_ > MAX_CHUNK_PAYLOAD) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || + y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || + duration <= 0 || duration > MAX_DURATION) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Snap offsets to even positions. + x_offset &= ~1; + y_offset &= ~1; + + // If given data is for a whole webp file, + // extract only the VP8/VP8L data from it. + err = GetImageData(bitstream, &image, &alpha, &is_lossless); + if (err != WEBP_MUX_OK) return err; + image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; + + WebPDataInit(&frame_tile); + ChunkInit(&chunk); + MuxImageInit(&wpi); + + if (alpha.bytes_ != NULL) { + // Add alpha chunk. + err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); + if (err != WEBP_MUX_OK) goto Err; + err = ChunkSetNth(&chunk, &wpi.alpha_, 1); + if (err != WEBP_MUX_OK) goto Err; + ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. + } + + // Add image chunk. + err = ChunkAssignData(&chunk, &image, copy_data, image_tag); + if (err != WEBP_MUX_OK) goto Err; + err = ChunkSetNth(&chunk, &wpi.img_, 1); + if (err != WEBP_MUX_OK) goto Err; + ChunkInit(&chunk); // chunk owned by wpi.img_ now. + + // Create frame/tile data. + err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless, + is_frame, &frame_tile); + if (err != WEBP_MUX_OK) goto Err; + + // Add frame/tile chunk (with copy_data = 1). + err = ChunkAssignData(&chunk, &frame_tile, 1, tag); + if (err != WEBP_MUX_OK) goto Err; + WebPDataClear(&frame_tile); + err = ChunkSetNth(&chunk, &wpi.header_, 1); + if (err != WEBP_MUX_OK) goto Err; + ChunkInit(&chunk); // chunk owned by wpi.header_ now. + + // Add this WebPMuxImage to mux. + err = MuxImagePush(&wpi, &mux->images_); + if (err != WEBP_MUX_OK) goto Err; + + // All is well. + return WEBP_MUX_OK; + + Err: // Something bad happened. + WebPDataClear(&frame_tile); + ChunkRelease(&chunk); + MuxImageRelease(&wpi); + return err; +} + +WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPData* bitstream, + int x_offset, int y_offset, + int duration, int copy_data) { + return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset, + duration, copy_data, kChunks[IDX_FRAME].tag); +} + +WebPMuxError WebPMuxPushTile(WebPMux* mux, const WebPData* bitstream, + int x_offset, int y_offset, + int copy_data) { + return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset, + 1 /* unused duration */, copy_data, + kChunks[IDX_TILE].tag); +} + +//------------------------------------------------------------------------------ +// Delete API(s). + +WebPMuxError WebPMuxDeleteImage(WebPMux* mux) { + WebPMuxError err; + + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + err = MuxValidateForImage(mux); + if (err != WEBP_MUX_OK) return err; + + // All well, delete image. + MuxImageDeleteAll(&mux->images_); + return WEBP_MUX_OK; +} + +WebPMuxError WebPMuxDeleteMetadata(WebPMux* mux) { + return MuxDeleteAllNamedData(mux, IDX_META); +} + +WebPMuxError WebPMuxDeleteColorProfile(WebPMux* mux) { + return MuxDeleteAllNamedData(mux, IDX_ICCP); +} + +static WebPMuxError DeleteFrameTileInternal(WebPMux* const mux, uint32_t nth, + CHUNK_INDEX idx) { + const WebPChunkId id = kChunks[idx].id; + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + assert(idx == IDX_FRAME || idx == IDX_TILE); + return MuxImageDeleteNth(&mux->images_, nth, id); +} + +WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { + return DeleteFrameTileInternal(mux, nth, IDX_FRAME); +} + +WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint32_t nth) { + return DeleteFrameTileInternal(mux, nth, IDX_TILE); +} + +//------------------------------------------------------------------------------ +// Assembly of the WebP RIFF file. + +static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk, + int* const x_offset, int* const y_offset, + int* const duration) { + const uint32_t tag = frame_tile_chunk->tag_; + const int is_frame = (tag == kChunks[IDX_FRAME].tag); + const WebPData* const data = &frame_tile_chunk->data_; + const size_t expected_data_size = + is_frame ? FRAME_CHUNK_SIZE : TILE_CHUNK_SIZE; + assert(frame_tile_chunk != NULL); + assert(tag == kChunks[IDX_FRAME].tag || tag == kChunks[IDX_TILE].tag); + if (data->size_ != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; + + *x_offset = 2 * GetLE24(data->bytes_ + 0); + *y_offset = 2 * GetLE24(data->bytes_ + 3); + if (is_frame) *duration = 1 + GetLE24(data->bytes_ + 12); + return WEBP_MUX_OK; +} + +WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk, + int* const width, int* const height) { + const uint32_t tag = image_chunk->tag_; + const WebPData* const data = &image_chunk->data_; + int w, h; + int ok; + assert(image_chunk != NULL); + assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag); + ok = (tag == kChunks[IDX_VP8].tag) ? + VP8GetInfo(data->bytes_, data->size_, data->size_, &w, &h) : + VP8LGetInfo(data->bytes_, data->size_, &w, &h, NULL); + if (ok) { + *width = w; + *height = h; + return WEBP_MUX_OK; + } else { + return WEBP_MUX_BAD_DATA; + } +} + +static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, + int* const x_offset, int* const y_offset, + int* const duration, + int* const width, int* const height) { + const WebPChunk* const image_chunk = wpi->img_; + const WebPChunk* const frame_tile_chunk = wpi->header_; + + // Get offsets and duration from FRM/TILE chunk. + const WebPMuxError err = + GetFrameTileInfo(frame_tile_chunk, x_offset, y_offset, duration); + if (err != WEBP_MUX_OK) return err; + + // Get width and height from VP8/VP8L chunk. + return MuxGetImageWidthHeight(image_chunk, width, height); +} + +static WebPMuxError GetImageCanvasWidthHeight( + const WebPMux* const mux, uint32_t flags, + int* const width, int* const height) { + WebPMuxImage* wpi = NULL; + assert(mux != NULL); + assert(width != NULL && height != NULL); + + wpi = mux->images_; + assert(wpi != NULL); + assert(wpi->img_ != NULL); + + if (wpi->next_) { + int max_x = 0; + int max_y = 0; + int64_t image_area = 0; + // Aggregate the bounding box for animation frames & tiled images. + for (; wpi != NULL; wpi = wpi->next_) { + int x_offset, y_offset, duration, w, h; + const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, + &duration, &w, &h); + const int max_x_pos = x_offset + w; + const int max_y_pos = y_offset + h; + if (err != WEBP_MUX_OK) return err; + assert(x_offset < MAX_POSITION_OFFSET); + assert(y_offset < MAX_POSITION_OFFSET); + + if (max_x_pos > max_x) max_x = max_x_pos; + if (max_y_pos > max_y) max_y = max_y_pos; + image_area += w * h; + } + *width = max_x; + *height = max_y; + // Crude check to validate that there are no image overlaps/holes for tile + // images. Check that the aggregated image area for individual tiles exactly + // matches the image area of the constructed canvas. However, the area-match + // is necessary but not sufficient condition. + if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) { + *width = 0; + *height = 0; + return WEBP_MUX_INVALID_ARGUMENT; + } + } else { + // For a single image, extract the width & height from VP8/VP8L image-data. + int w, h; + const WebPChunk* const image_chunk = wpi->img_; + const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h); + if (err != WEBP_MUX_OK) return err; + *width = w; + *height = h; + } + return WEBP_MUX_OK; +} + +// VP8X format: +// Total Size : 10, +// Flags : 4 bytes, +// Width : 3 bytes, +// Height : 3 bytes. +static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { + WebPMuxError err = WEBP_MUX_OK; + uint32_t flags = 0; + int width = 0; + int height = 0; + uint8_t data[VP8X_CHUNK_SIZE]; + const size_t data_size = VP8X_CHUNK_SIZE; + const WebPMuxImage* images = NULL; + + assert(mux != NULL); + images = mux->images_; // First image. + if (images == NULL || images->img_ == NULL || + images->img_->data_.bytes_ == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // If VP8X chunk(s) is(are) already present, remove them (and later add new + // VP8X chunk with updated flags). + err = MuxDeleteAllNamedData(mux, IDX_VP8X); + if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; + + // Set flags. + if (mux->iccp_ != NULL && mux->iccp_->data_.bytes_ != NULL) { + flags |= ICCP_FLAG; + } + + if (mux->meta_ != NULL && mux->meta_->data_.bytes_ != NULL) { + flags |= META_FLAG; + } + + if (images->header_ != NULL) { + if (images->header_->tag_ == kChunks[IDX_TILE].tag) { + // This is a tiled image. + flags |= TILE_FLAG; + } else if (images->header_->tag_ == kChunks[IDX_FRAME].tag) { + // This is an image with animation. + flags |= ANIMATION_FLAG; + } + } + + if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { + flags |= ALPHA_FLAG; // Some images have an alpha channel. + } + + if (flags == 0) { + // For Simple Image, VP8X chunk should not be added. + return WEBP_MUX_OK; + } + + err = GetImageCanvasWidthHeight(mux, flags, &width, &height); + if (err != WEBP_MUX_OK) return err; + + if (width <= 0 || height <= 0) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (MuxHasLosslessImages(images)) { + // We have a file with a VP8X chunk having some lossless images. + // As lossless images implicitly contain alpha, force ALPHA_FLAG to be true. + // Note: This 'flags' update must NOT be done for a lossless image + // without a VP8X chunk! + flags |= ALPHA_FLAG; + } + + PutLE32(data + 0, flags); // VP8X chunk flags. + PutLE24(data + 4, width - 1); // canvas width. + PutLE24(data + 7, height - 1); // canvas height. + + err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, 1); + return err; +} + +WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { + size_t size = 0; + uint8_t* data = NULL; + uint8_t* dst = NULL; + int num_frames; + int num_loop_chunks; + WebPMuxError err; + + if (mux == NULL || assembled_data == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Remove LOOP chunk if unnecessary. + err = WebPMuxNumChunks(mux, kChunks[IDX_LOOP].id, &num_loop_chunks); + if (err != WEBP_MUX_OK) return err; + if (num_loop_chunks >= 1) { + err = WebPMuxNumChunks(mux, kChunks[IDX_FRAME].id, &num_frames); + if (err != WEBP_MUX_OK) return err; + if (num_frames == 0) { + err = DeleteLoopCount(mux); + if (err != WEBP_MUX_OK) return err; + } + } + + // Create VP8X chunk. + err = CreateVP8XChunk(mux); + if (err != WEBP_MUX_OK) return err; + + // Allocate data. + size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) + + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) + + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) + + RIFF_HEADER_SIZE; + + data = (uint8_t*)malloc(size); + if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + + // Emit header & chunks. + dst = MuxEmitRiffHeader(data, size); + dst = ChunkListEmit(mux->vp8x_, dst); + dst = ChunkListEmit(mux->iccp_, dst); + dst = ChunkListEmit(mux->loop_, dst); + dst = MuxImageListEmit(mux->images_, dst); + dst = ChunkListEmit(mux->meta_, dst); + dst = ChunkListEmit(mux->unknown_, dst); + assert(dst == data + size); + + // Validate mux. + err = MuxValidate(mux); + if (err != WEBP_MUX_OK) { + free(data); + data = NULL; + size = 0; + } + + // Finalize. + assembled_data->bytes_ = data; + assembled_data->size_ = size; + + return err; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/mux/muxi.h b/external/libwebp/mux/muxi.h new file mode 100644 index 0000000000..edd8c368cd --- /dev/null +++ b/external/libwebp/mux/muxi.h @@ -0,0 +1,271 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Internal header for mux library. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_MUX_MUXI_H_ +#define WEBP_MUX_MUXI_H_ + +#include +#include "../dec/vp8i.h" +#include "../dec/vp8li.h" +#include "../webp/format_constants.h" +#include "../webp/mux.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Defines and constants. + +// Chunk object. +typedef struct WebPChunk WebPChunk; +struct WebPChunk { + uint32_t tag_; + int owner_; // True if *data_ memory is owned internally. + // VP8X, Loop, and other internally created chunks + // like frame/tile are always owned. + WebPData data_; + WebPChunk* next_; +}; + +// MuxImage object. Store a full webp image (including frame/tile chunk, alpha +// chunk and VP8/VP8L chunk), +typedef struct WebPMuxImage WebPMuxImage; +struct WebPMuxImage { + WebPChunk* header_; // Corresponds to WEBP_CHUNK_FRAME/WEBP_CHUNK_TILE. + WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA. + WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE. + int is_partial_; // True if only some of the chunks are filled. + WebPMuxImage* next_; +}; + +// Main mux object. Stores data chunks. +struct WebPMux { + WebPMuxImage* images_; + WebPChunk* iccp_; + WebPChunk* meta_; + WebPChunk* loop_; + WebPChunk* vp8x_; + + WebPChunk* unknown_; +}; + +// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only. +// Note: the reason for having two enums ('WebPChunkId' and 'CHUNK_INDEX') is to +// allow two different chunks to have the same id (e.g. WebPChunkId +// 'WEBP_CHUNK_IMAGE' can correspond to CHUNK_INDEX 'IDX_VP8' or 'IDX_VP8L'). +typedef enum { + IDX_VP8X = 0, + IDX_ICCP, + IDX_LOOP, + IDX_FRAME, + IDX_TILE, + IDX_ALPHA, + IDX_VP8, + IDX_VP8L, + IDX_META, + IDX_UNKNOWN, + + IDX_NIL, + IDX_LAST_CHUNK +} CHUNK_INDEX; + +#define NIL_TAG 0x00000000u // To signal void chunk. + +#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24) + +typedef struct { + uint32_t tag; + WebPChunkId id; + uint32_t size; +} ChunkInfo; + +extern const ChunkInfo kChunks[IDX_LAST_CHUNK]; + +//------------------------------------------------------------------------------ +// Helper functions. + +// Read 16, 24 or 32 bits stored in little-endian order. +static WEBP_INLINE int GetLE16(const uint8_t* const data) { + return (int)(data[0] << 0) | (data[1] << 8); +} + +static WEBP_INLINE int GetLE24(const uint8_t* const data) { + return GetLE16(data) | (data[2] << 16); +} + +static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) { + return (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16); +} + +// Store 16, 24 or 32 bits in little-endian order. +static WEBP_INLINE void PutLE16(uint8_t* const data, int val) { + assert(val < (1 << 16)); + data[0] = (val >> 0); + data[1] = (val >> 8); +} + +static WEBP_INLINE void PutLE24(uint8_t* const data, int val) { + assert(val < (1 << 24)); + PutLE16(data, val & 0xffff); + data[2] = (val >> 16); +} + +static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { + PutLE16(data, (int)(val & 0xffff)); + PutLE16(data + 2, (int)(val >> 16)); +} + +static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) { + return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U); +} + +//------------------------------------------------------------------------------ +// Chunk object management. + +// Initialize. +void ChunkInit(WebPChunk* const chunk); + +// Get chunk index from chunk tag. Returns IDX_NIL if not found. +CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag); + +// Get chunk id from chunk tag. Returns WEBP_CHUNK_NIL if not found. +WebPChunkId ChunkGetIdFromTag(uint32_t tag); + +// Search for nth chunk with given 'tag' in the chunk list. +// nth = 0 means "last of the list". +WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); + +// Fill the chunk with the given data. +WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, + int copy_data, uint32_t tag); + +// Sets 'chunk' at nth position in the 'chunk_list'. +// nth = 0 has the special meaning "last of the list". +WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, + uint32_t nth); + +// Releases chunk and returns chunk->next_. +WebPChunk* ChunkRelease(WebPChunk* const chunk); + +// Deletes given chunk & returns chunk->next_. +WebPChunk* ChunkDelete(WebPChunk* const chunk); + +// Size of a chunk including header and padding. +static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { + const size_t data_size = chunk->data_.size_; + assert(data_size < MAX_CHUNK_PAYLOAD); + return SizeWithPadding(data_size); +} + +// Total size of a list of chunks. +size_t ChunksListDiskSize(const WebPChunk* chunk_list); + +// Write out the given list of chunks into 'dst'. +uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst); + +// Get the width & height of image stored in 'image_chunk'. +WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk, + int* const width, int* const height); + +//------------------------------------------------------------------------------ +// MuxImage object management. + +// Initialize. +void MuxImageInit(WebPMuxImage* const wpi); + +// Releases image 'wpi' and returns wpi->next. +WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi); + +// Delete image 'wpi' and return the next image in the list or NULL. +// 'wpi' can be NULL. +WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi); + +// Delete all images in 'wpi_list'. +void MuxImageDeleteAll(WebPMuxImage** const wpi_list); + +// Count number of images matching the given tag id in the 'wpi_list'. +int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id); + +// Check if given ID corresponds to an image related chunk. +static WEBP_INLINE int IsWPI(WebPChunkId id) { + switch (id) { + case WEBP_CHUNK_FRAME: + case WEBP_CHUNK_TILE: + case WEBP_CHUNK_ALPHA: + case WEBP_CHUNK_IMAGE: return 1; + default: return 0; + } +} + +// Get a reference to appropriate chunk list within an image given chunk tag. +static WEBP_INLINE WebPChunk** MuxImageGetListFromId( + const WebPMuxImage* const wpi, WebPChunkId id) { + assert(wpi != NULL); + switch (id) { + case WEBP_CHUNK_FRAME: + case WEBP_CHUNK_TILE: return (WebPChunk**)&wpi->header_; + case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_; + case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_; + default: return NULL; + } +} + +// Pushes 'wpi' at the end of 'wpi_list'. +WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list); + +// Delete nth image in the image list with given tag id. +WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, + WebPChunkId id); + +// Get nth image in the image list with given tag id. +WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, + WebPChunkId id, WebPMuxImage** wpi); + +// Total size of the given image. +size_t MuxImageDiskSize(const WebPMuxImage* const wpi); + +// Total size of a list of images. +size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list); + +// Write out the given image into 'dst'. +uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst); + +// Write out the given list of images into 'dst'. +uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst); + +//------------------------------------------------------------------------------ +// Helper methods for mux. + +// Checks if the given image list contains at least one lossless image. +int MuxHasLosslessImages(const WebPMuxImage* images); + +// Write out RIFF header into 'data', given total data size 'size'. +uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); + +// Returns the list where chunk with given ID is to be inserted in mux. +// Return value is NULL if this chunk should be inserted in mux->images_ list +// or if 'id' is not known. +WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); + +// Validates that the given mux has a single image. +WebPMuxError MuxValidateForImage(const WebPMux* const mux); + +// Validates the given mux object. +WebPMuxError MuxValidate(const WebPMux* const mux); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_MUX_MUXI_H_ */ diff --git a/external/libwebp/mux/muxinternal.c b/external/libwebp/mux/muxinternal.c new file mode 100644 index 0000000000..6c3c4fe60a --- /dev/null +++ b/external/libwebp/mux/muxinternal.c @@ -0,0 +1,576 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Internal objects and utils for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "./muxi.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define UNDEFINED_CHUNK_SIZE (-1) + +const ChunkInfo kChunks[] = { + { MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE }, + { MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('L', 'O', 'O', 'P'), WEBP_CHUNK_LOOP, LOOP_CHUNK_SIZE }, + { MKFOURCC('F', 'R', 'M', ' '), WEBP_CHUNK_FRAME, FRAME_CHUNK_SIZE }, + { MKFOURCC('T', 'I', 'L', 'E'), WEBP_CHUNK_TILE, TILE_CHUNK_SIZE }, + { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE }, + { MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE }, + + { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE } +}; + +//------------------------------------------------------------------------------ +// Life of a chunk object. + +void ChunkInit(WebPChunk* const chunk) { + assert(chunk); + memset(chunk, 0, sizeof(*chunk)); + chunk->tag_ = NIL_TAG; +} + +WebPChunk* ChunkRelease(WebPChunk* const chunk) { + WebPChunk* next; + if (chunk == NULL) return NULL; + if (chunk->owner_) { + WebPDataClear(&chunk->data_); + } + next = chunk->next_; + ChunkInit(chunk); + return next; +} + +//------------------------------------------------------------------------------ +// Chunk misc methods. + +CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) { + int i; + for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { + if (tag == kChunks[i].tag) return i; + } + return IDX_NIL; +} + +WebPChunkId ChunkGetIdFromTag(uint32_t tag) { + int i; + for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { + if (tag == kChunks[i].tag) return kChunks[i].id; + } + return WEBP_CHUNK_NIL; +} + +//------------------------------------------------------------------------------ +// Chunk search methods. + +// Returns next chunk in the chunk list with the given tag. +static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) { + while (chunk && chunk->tag_ != tag) { + chunk = chunk->next_; + } + return chunk; +} + +WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { + uint32_t iter = nth; + first = ChunkSearchNextInList(first, tag); + if (!first) return NULL; + + while (--iter != 0) { + WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag); + if (next_chunk == NULL) break; + first = next_chunk; + } + return ((nth > 0) && (iter > 0)) ? NULL : first; +} + +// Outputs a pointer to 'prev_chunk->next_', +// where 'prev_chunk' is the pointer to the chunk at position (nth - 1). +// Returns 1 if nth chunk was found, 0 otherwise. +static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth, + WebPChunk*** const location) { + uint32_t count = 0; + assert(chunk_list); + *location = chunk_list; + + while (*chunk_list) { + WebPChunk* const cur_chunk = *chunk_list; + ++count; + if (count == nth) return 1; // Found. + chunk_list = &cur_chunk->next_; + *location = chunk_list; + } + + // *chunk_list is ok to be NULL if adding at last location. + return (nth == 0 || (count == nth - 1)) ? 1 : 0; +} + +//------------------------------------------------------------------------------ +// Chunk writer methods. + +WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, + int copy_data, uint32_t tag) { + // For internally allocated chunks, always copy data & make it owner of data. + if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_LOOP].tag) { + copy_data = 1; + } + + ChunkRelease(chunk); + + if (data != NULL) { + if (copy_data) { + // Copy data. + chunk->data_.bytes_ = (uint8_t*)malloc(data->size_); + if (chunk->data_.bytes_ == NULL) return WEBP_MUX_MEMORY_ERROR; + memcpy((uint8_t*)chunk->data_.bytes_, data->bytes_, data->size_); + chunk->data_.size_ = data->size_; + + // Chunk is owner of data. + chunk->owner_ = 1; + } else { + // Don't copy data. + chunk->data_ = *data; + } + } + + chunk->tag_ = tag; + + return WEBP_MUX_OK; +} + +WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list, + uint32_t nth) { + WebPChunk* new_chunk; + + if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) { + return WEBP_MUX_NOT_FOUND; + } + + new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk)); + if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; + *new_chunk = *chunk; + new_chunk->next_ = *chunk_list; + *chunk_list = new_chunk; + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// Chunk deletion method(s). + +WebPChunk* ChunkDelete(WebPChunk* const chunk) { + WebPChunk* const next = ChunkRelease(chunk); + free(chunk); + return next; +} + +//------------------------------------------------------------------------------ +// Chunk serialization methods. + +size_t ChunksListDiskSize(const WebPChunk* chunk_list) { + size_t size = 0; + while (chunk_list) { + size += ChunkDiskSize(chunk_list); + chunk_list = chunk_list->next_; + } + return size; +} + +static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) { + const size_t chunk_size = chunk->data_.size_; + assert(chunk); + assert(chunk->tag_ != NIL_TAG); + PutLE32(dst + 0, chunk->tag_); + PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size); + assert(chunk_size == (uint32_t)chunk_size); + memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes_, chunk_size); + if (chunk_size & 1) + dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding. + return dst + ChunkDiskSize(chunk); +} + +uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) { + while (chunk_list) { + dst = ChunkEmit(chunk_list, dst); + chunk_list = chunk_list->next_; + } + return dst; +} + +//------------------------------------------------------------------------------ +// Manipulation of a WebPData object. + +void WebPDataInit(WebPData* webp_data) { + if (webp_data != NULL) { + memset(webp_data, 0, sizeof(*webp_data)); + } +} + +void WebPDataClear(WebPData* webp_data) { + if (webp_data != NULL) { + free((void*)webp_data->bytes_); + WebPDataInit(webp_data); + } +} + +int WebPDataCopy(const WebPData* src, WebPData* dst) { + if (src == NULL || dst == NULL) return 0; + + WebPDataInit(dst); + if (src->bytes_ != NULL && src->size_ != 0) { + dst->bytes_ = (uint8_t*)malloc(src->size_); + if (dst->bytes_ == NULL) return 0; + memcpy((void*)dst->bytes_, src->bytes_, src->size_); + dst->size_ = src->size_; + } + return 1; +} + +//------------------------------------------------------------------------------ +// Life of a MuxImage object. + +void MuxImageInit(WebPMuxImage* const wpi) { + assert(wpi); + memset(wpi, 0, sizeof(*wpi)); +} + +WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { + WebPMuxImage* next; + if (wpi == NULL) return NULL; + ChunkDelete(wpi->header_); + ChunkDelete(wpi->alpha_); + ChunkDelete(wpi->img_); + + next = wpi->next_; + MuxImageInit(wpi); + return next; +} + +//------------------------------------------------------------------------------ +// MuxImage search methods. + +int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { + int count = 0; + const WebPMuxImage* current; + for (current = wpi_list; current != NULL; current = current->next_) { + const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id); + if (wpi_chunk != NULL) { + const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); + if (wpi_chunk_id == id) ++count; + } + } + return count; +} + +// Outputs a pointer to 'prev_wpi->next_', +// where 'prev_wpi' is the pointer to the image at position (nth - 1). +// Returns 1 if nth image with given id was found, 0 otherwise. +static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth, + WebPChunkId id, + WebPMuxImage*** const location) { + uint32_t count = 0; + assert(wpi_list); + *location = wpi_list; + + // Search makes sense only for the following. + assert(id == WEBP_CHUNK_FRAME || id == WEBP_CHUNK_TILE || + id == WEBP_CHUNK_IMAGE); + assert(id != WEBP_CHUNK_IMAGE || nth == 1); + + if (nth == 0) { + nth = MuxImageCount(*wpi_list, id); + if (nth == 0) return 0; // Not found. + } + + while (*wpi_list) { + WebPMuxImage* const cur_wpi = *wpi_list; + const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(cur_wpi, id); + if (wpi_chunk != NULL) { + const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); + if (wpi_chunk_id == id) { + ++count; + if (count == nth) return 1; // Found. + } + } + wpi_list = &cur_wpi->next_; + *location = wpi_list; + } + return 0; // Not found. +} + +//------------------------------------------------------------------------------ +// MuxImage writer methods. + +WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) { + WebPMuxImage* new_wpi; + + while (*wpi_list != NULL) { + WebPMuxImage* const cur_wpi = *wpi_list; + if (cur_wpi->next_ == NULL) break; + wpi_list = &cur_wpi->next_; + } + + new_wpi = (WebPMuxImage*)malloc(sizeof(*new_wpi)); + if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR; + *new_wpi = *wpi; + new_wpi->next_ = NULL; + + if (*wpi_list != NULL) { + (*wpi_list)->next_ = new_wpi; + } else { + *wpi_list = new_wpi; + } + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage deletion methods. + +WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { + // Delete the components of wpi. If wpi is NULL this is a noop. + WebPMuxImage* const next = MuxImageRelease(wpi); + free(wpi); + return next; +} + +void MuxImageDeleteAll(WebPMuxImage** const wpi_list) { + while (*wpi_list) { + *wpi_list = MuxImageDelete(*wpi_list); + } +} + +WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, + WebPChunkId id) { + assert(wpi_list); + if (!SearchImageToGetOrDelete(wpi_list, nth, id, &wpi_list)) { + return WEBP_MUX_NOT_FOUND; + } + *wpi_list = MuxImageDelete(*wpi_list); + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage reader methods. + +WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, + WebPChunkId id, WebPMuxImage** wpi) { + assert(wpi_list); + assert(wpi); + if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id, + (WebPMuxImage***)&wpi_list)) { + return WEBP_MUX_NOT_FOUND; + } + *wpi = (WebPMuxImage*)*wpi_list; + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ +// MuxImage serialization methods. + +// Size of an image. +size_t MuxImageDiskSize(const WebPMuxImage* const wpi) { + size_t size = 0; + if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_); + if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_); + if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_); + return size; +} + +size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) { + size_t size = 0; + while (wpi_list) { + size += MuxImageDiskSize(wpi_list); + wpi_list = wpi_list->next_; + } + return size; +} + +uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { + // Ordering of chunks to be emitted is strictly as follows: + // 1. Frame/Tile chunk (if present). + // 2. Alpha chunk (if present). + // 3. VP8/VP8L chunk. + assert(wpi); + if (wpi->header_ != NULL) dst = ChunkEmit(wpi->header_, dst); + if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); + if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); + return dst; +} + +uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) { + while (wpi_list) { + dst = MuxImageEmit(wpi_list, dst); + wpi_list = wpi_list->next_; + } + return dst; +} + +//------------------------------------------------------------------------------ +// Helper methods for mux. + +int MuxHasLosslessImages(const WebPMuxImage* images) { + while (images != NULL) { + assert(images->img_ != NULL); + if (images->img_->tag_ == kChunks[IDX_VP8L].tag) { + return 1; + } + images = images->next_; + } + return 0; +} + +uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) { + PutLE32(data + 0, MKFOURCC('R', 'I', 'F', 'F')); + PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE); + assert(size == (uint32_t)size); + PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, MKFOURCC('W', 'E', 'B', 'P')); + return data + RIFF_HEADER_SIZE; +} + +WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { + assert(mux != NULL); + switch(id) { + case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_; + case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_; + case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_; + case WEBP_CHUNK_META: return (WebPChunk**)&mux->meta_; + case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_; + default: return NULL; + } +} + +WebPMuxError MuxValidateForImage(const WebPMux* const mux) { + const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); + const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_FRAME); + const int num_tiles = MuxImageCount(mux->images_, WEBP_CHUNK_TILE); + + if (num_images == 0) { + // No images in mux. + return WEBP_MUX_NOT_FOUND; + } else if (num_images == 1 && num_frames == 0 && num_tiles == 0) { + // Valid case (single image). + return WEBP_MUX_OK; + } else { + // Frame/Tile case OR an invalid mux. + return WEBP_MUX_INVALID_ARGUMENT; + } +} + +static int IsNotCompatible(int feature, int num_items) { + return (feature != 0) != (num_items > 0); +} + +#define NO_FLAG 0 + +// Test basic constraints: +// retrieval, maximum number of chunks by index (use -1 to skip) +// and feature incompatibility (use NO_FLAG to skip). +// On success returns WEBP_MUX_OK and stores the chunk count in *num. +static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx, + WebPFeatureFlags feature, + WebPFeatureFlags vp8x_flags, + int max, int* num) { + const WebPMuxError err = + WebPMuxNumChunks(mux, kChunks[idx].id, num); + if (err != WEBP_MUX_OK) return err; + if (max > -1 && *num > max) return WEBP_MUX_INVALID_ARGUMENT; + if (feature != NO_FLAG && IsNotCompatible(vp8x_flags & feature, *num)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + return WEBP_MUX_OK; +} + +WebPMuxError MuxValidate(const WebPMux* const mux) { + int num_iccp; + int num_meta; + int num_loop_chunks; + int num_frames; + int num_tiles; + int num_vp8x; + int num_images; + int num_alpha; + uint32_t flags; + WebPMuxError err; + + // Verify mux is not NULL. + if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + // Verify mux has at least one image. + if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + err = WebPMuxGetFeatures(mux, &flags); + if (err != WEBP_MUX_OK) return err; + + // At most one color profile chunk. + err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); + if (err != WEBP_MUX_OK) return err; + + // At most one XMP metadata. + err = ValidateChunk(mux, IDX_META, META_FLAG, flags, 1, &num_meta); + if (err != WEBP_MUX_OK) return err; + + // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent. + // At most one loop chunk. + err = ValidateChunk(mux, IDX_LOOP, NO_FLAG, flags, 1, &num_loop_chunks); + if (err != WEBP_MUX_OK) return err; + err = ValidateChunk(mux, IDX_FRAME, NO_FLAG, flags, -1, &num_frames); + if (err != WEBP_MUX_OK) return err; + + { + const int has_animation = !!(flags & ANIMATION_FLAG); + if (has_animation && (num_loop_chunks == 0 || num_frames == 0)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + if (!has_animation && (num_loop_chunks == 1 || num_frames > 0)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + } + + // Tiling: TILE_FLAG and tile chunk(s) are consistent. + err = ValidateChunk(mux, IDX_TILE, TILE_FLAG, flags, -1, &num_tiles); + if (err != WEBP_MUX_OK) return err; + + // Verify either VP8X chunk is present OR there is only one elem in + // mux->images_. + err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); + if (err != WEBP_MUX_OK) return err; + err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images); + if (err != WEBP_MUX_OK) return err; + if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT; + + // ALPHA_FLAG & alpha chunk(s) are consistent. + if (num_vp8x > 0 && MuxHasLosslessImages(mux->images_)) { + // Special case: we have a VP8X chunk as well as some lossless images. + if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT; + } else { + err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha); + if (err != WEBP_MUX_OK) return err; + } + + // num_tiles & num_images are consistent. + if (num_tiles > 0 && num_images != num_tiles) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + return WEBP_MUX_OK; +} + +#undef NO_FLAG + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/mux/muxread.c b/external/libwebp/mux/muxread.c new file mode 100644 index 0000000000..21c3cfbaeb --- /dev/null +++ b/external/libwebp/mux/muxread.c @@ -0,0 +1,411 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Read APIs for mux. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +#include +#include "./muxi.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Helper method(s). + +// Handy MACRO. +#define SWITCH_ID_LIST(INDEX, LIST) \ + if (idx == (INDEX)) { \ + const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ + kChunks[(INDEX)].tag); \ + if (chunk) { \ + *data = chunk->data_; \ + return WEBP_MUX_OK; \ + } else { \ + return WEBP_MUX_NOT_FOUND; \ + } \ + } + +static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx, + uint32_t nth, WebPData* const data) { + assert(mux != NULL); + assert(!IsWPI(kChunks[idx].id)); + WebPDataInit(data); + + SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_); + SWITCH_ID_LIST(IDX_ICCP, mux->iccp_); + SWITCH_ID_LIST(IDX_LOOP, mux->loop_); + SWITCH_ID_LIST(IDX_META, mux->meta_); + SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_); + return WEBP_MUX_NOT_FOUND; +} +#undef SWITCH_ID_LIST + +// Fill the chunk with the given data (includes chunk header bytes), after some +// verifications. +static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk, + const uint8_t* data, + size_t data_size, size_t riff_size, + int copy_data) { + uint32_t chunk_size; + WebPData chunk_data; + + // Sanity checks. + if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; + chunk_size = GetLE32(data + TAG_SIZE); + + { + const size_t chunk_disk_size = SizeWithPadding(chunk_size); + if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA; + if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA; + } + + // Data assignment. + chunk_data.bytes_ = data + CHUNK_HEADER_SIZE; + chunk_data.size_ = chunk_size; + return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); +} + +//------------------------------------------------------------------------------ +// Create a mux object from WebP-RIFF data. + +WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, + int version) { + size_t riff_size; + uint32_t tag; + const uint8_t* end; + WebPMux* mux = NULL; + WebPMuxImage* wpi = NULL; + const uint8_t* data; + size_t size; + WebPChunk chunk; + ChunkInit(&chunk); + + // Sanity checks. + if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { + return NULL; // version mismatch + } + if (bitstream == NULL) return NULL; + + data = bitstream->bytes_; + size = bitstream->size_; + + if (data == NULL) return NULL; + if (size < RIFF_HEADER_SIZE) return NULL; + if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') || + GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) { + return NULL; + } + + mux = WebPMuxNew(); + if (mux == NULL) return NULL; + + if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err; + + tag = GetLE32(data + RIFF_HEADER_SIZE); + if (tag != kChunks[IDX_VP8].tag && + tag != kChunks[IDX_VP8L].tag && + tag != kChunks[IDX_VP8X].tag) { + goto Err; // First chunk should be VP8, VP8L or VP8X. + } + + riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE)); + if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) { + goto Err; + } else { + if (riff_size < size) { // Redundant data after last chunk. + size = riff_size; // To make sure we don't read any data beyond mux_size. + } + } + + end = data + size; + data += RIFF_HEADER_SIZE; + size -= RIFF_HEADER_SIZE; + + wpi = (WebPMuxImage*)malloc(sizeof(*wpi)); + if (wpi == NULL) goto Err; + MuxImageInit(wpi); + + // Loop over chunks. + while (data != end) { + WebPChunkId id; + WebPMuxError err; + + err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data); + if (err != WEBP_MUX_OK) goto Err; + + id = ChunkGetIdFromTag(chunk.tag_); + + if (IsWPI(id)) { // An image chunk (frame/tile/alpha/vp8). + WebPChunk** wpi_chunk_ptr = + MuxImageGetListFromId(wpi, id); // Image chunk to set. + assert(wpi_chunk_ptr != NULL); + if (*wpi_chunk_ptr != NULL) goto Err; // Consecutive alpha chunks or + // consecutive frame/tile chunks. + if (ChunkSetNth(&chunk, wpi_chunk_ptr, 1) != WEBP_MUX_OK) goto Err; + if (id == WEBP_CHUNK_IMAGE) { + wpi->is_partial_ = 0; // wpi is completely filled. + // Add this to mux->images_ list. + if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err; + MuxImageInit(wpi); // Reset for reading next image. + } else { + wpi->is_partial_ = 1; // wpi is only partially filled. + } + } else { // A non-image chunk. + WebPChunk** chunk_list; + if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before + // getting all chunks of an image. + chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk. + if (chunk_list == NULL) chunk_list = &mux->unknown_; + if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err; + } + { + const size_t data_size = ChunkDiskSize(&chunk); + data += data_size; + size -= data_size; + } + ChunkInit(&chunk); + } + + // Validate mux if complete. + if (MuxValidate(mux) != WEBP_MUX_OK) goto Err; + + MuxImageDelete(wpi); + return mux; // All OK; + + Err: // Something bad happened. + ChunkRelease(&chunk); + MuxImageDelete(wpi); + WebPMuxDelete(mux); + return NULL; +} + +//------------------------------------------------------------------------------ +// Get API(s). + +WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { + WebPData data; + WebPMuxError err; + + if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; + *flags = 0; + + // Check if VP8X chunk is present. + err = MuxGet(mux, IDX_VP8X, 1, &data); + if (err == WEBP_MUX_NOT_FOUND) { + // Check if VP8/VP8L chunk is present. + err = WebPMuxGetImage(mux, &data); + WebPDataClear(&data); + return err; + } else if (err != WEBP_MUX_OK) { + return err; + } + + if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA; + + // All OK. Fill up flags. + *flags = GetLE32(data.bytes_); + return WEBP_MUX_OK; +} + +static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, + int height, uint32_t flags) { + const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; + assert(width >= 1 && height >= 1); + assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE); + assert(width * (uint64_t)height < MAX_IMAGE_AREA); + PutLE32(dst, MKFOURCC('V', 'P', '8', 'X')); + PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE); + PutLE32(dst + CHUNK_HEADER_SIZE, flags); + PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1); + PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1); + return dst + vp8x_size; +} + +// Assemble a single image WebP bitstream from 'wpi'. +static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi, + WebPData* const bitstream) { + uint8_t* dst; + + // Allocate data. + const int need_vp8x = (wpi->alpha_ != NULL); + const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0; + const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0; + // Note: No need to output FRM/TILE chunk for a single image. + const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + + ChunkDiskSize(wpi->img_); + uint8_t* const data = (uint8_t*)malloc(size); + if (data == NULL) return WEBP_MUX_MEMORY_ERROR; + + // Main RIFF header. + dst = MuxEmitRiffHeader(data, size); + + if (need_vp8x) { + int w, h; + WebPMuxError err; + assert(wpi->img_ != NULL); + err = MuxGetImageWidthHeight(wpi->img_, &w, &h); + if (err != WEBP_MUX_OK) { + free(data); + return err; + } + dst = EmitVP8XChunk(dst, w, h, ALPHA_FLAG); // VP8X. + dst = ChunkListEmit(wpi->alpha_, dst); // ALPH. + } + + // Bitstream. + dst = ChunkListEmit(wpi->img_, dst); + assert(dst == data + size); + + // Output. + bitstream->bytes_ = data; + bitstream->size_ = size; + return WEBP_MUX_OK; +} + +WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) { + WebPMuxError err; + WebPMuxImage* wpi = NULL; + + if (mux == NULL || bitstream == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + err = MuxValidateForImage(mux); + if (err != WEBP_MUX_OK) return err; + + // All well. Get the image. + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE, + &wpi); + assert(err == WEBP_MUX_OK); // Already tested above. + + return SynthesizeBitstream(wpi, bitstream); +} + +WebPMuxError WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) { + if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxGet(mux, IDX_META, 1, metadata); +} + +WebPMuxError WebPMuxGetColorProfile(const WebPMux* mux, + WebPData* color_profile) { + if (mux == NULL || color_profile == NULL) return WEBP_MUX_INVALID_ARGUMENT; + return MuxGet(mux, IDX_ICCP, 1, color_profile); +} + +WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) { + WebPData image; + WebPMuxError err; + + if (mux == NULL || loop_count == NULL) return WEBP_MUX_INVALID_ARGUMENT; + + err = MuxGet(mux, IDX_LOOP, 1, &image); + if (err != WEBP_MUX_OK) return err; + if (image.size_ < kChunks[WEBP_CHUNK_LOOP].size) return WEBP_MUX_BAD_DATA; + *loop_count = GetLE16(image.bytes_); + + return WEBP_MUX_OK; +} + +static WebPMuxError MuxGetFrameTileInternal( + const WebPMux* const mux, uint32_t nth, WebPData* const bitstream, + int* const x_offset, int* const y_offset, int* const duration, + uint32_t tag) { + const WebPData* frame_tile_data; + WebPMuxError err; + WebPMuxImage* wpi; + + const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0; + const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE; + const WebPChunkId id = kChunks[idx].id; + + if (mux == NULL || bitstream == NULL || + x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + // Get the nth WebPMuxImage. + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi); + if (err != WEBP_MUX_OK) return err; + + // Get frame chunk. + assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_. + frame_tile_data = &wpi->header_->data_; + + if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA; + *x_offset = 2 * GetLE24(frame_tile_data->bytes_ + 0); + *y_offset = 2 * GetLE24(frame_tile_data->bytes_ + 3); + if (is_frame) *duration = 1 + GetLE24(frame_tile_data->bytes_ + 12); + + return SynthesizeBitstream(wpi, bitstream); +} + +WebPMuxError WebPMuxGetFrame(const WebPMux* mux, uint32_t nth, + WebPData* bitstream, + int* x_offset, int* y_offset, int* duration) { + return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, + duration, kChunks[IDX_FRAME].tag); +} + +WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth, + WebPData* bitstream, + int* x_offset, int* y_offset) { + return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL, + kChunks[IDX_TILE].tag); +} + +// Get chunk index from chunk id. Returns IDX_NIL if not found. +static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) { + int i; + for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) { + if (id == kChunks[i].id) return i; + } + return IDX_NIL; +} + +// Count number of chunks matching 'tag' in the 'chunk_list'. +// If tag == NIL_TAG, any tag will be matched. +static int CountChunks(const WebPChunk* const chunk_list, uint32_t tag) { + int count = 0; + const WebPChunk* current; + for (current = chunk_list; current != NULL; current = current->next_) { + if (tag == NIL_TAG || current->tag_ == tag) { + count++; // Count chunks whose tags match. + } + } + return count; +} + +WebPMuxError WebPMuxNumChunks(const WebPMux* mux, + WebPChunkId id, int* num_elements) { + if (mux == NULL || num_elements == NULL) { + return WEBP_MUX_INVALID_ARGUMENT; + } + + if (IsWPI(id)) { + *num_elements = MuxImageCount(mux->images_, id); + } else { + WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); + if (chunk_list == NULL) { + *num_elements = 0; + } else { + const CHUNK_INDEX idx = ChunkGetIndexFromId(id); + *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); + } + } + + return WEBP_MUX_OK; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/Makefile.am b/external/libwebp/utils/Makefile.am new file mode 100644 index 0000000000..65054c036b --- /dev/null +++ b/external/libwebp/utils/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src +noinst_LTLIBRARIES = libwebputils.la + +libwebputils_la_SOURCES = +libwebputils_la_SOURCES += bit_reader.c +libwebputils_la_SOURCES += bit_reader.h +libwebputils_la_SOURCES += bit_writer.c +libwebputils_la_SOURCES += bit_writer.h +libwebputils_la_SOURCES += color_cache.c +libwebputils_la_SOURCES += color_cache.h +libwebputils_la_SOURCES += filters.c +libwebputils_la_SOURCES += filters.h +libwebputils_la_SOURCES += huffman.c +libwebputils_la_SOURCES += huffman.h +libwebputils_la_SOURCES += huffman_encode.c +libwebputils_la_SOURCES += huffman_encode.h +libwebputils_la_SOURCES += quant_levels.c +libwebputils_la_SOURCES += quant_levels.h +libwebputils_la_SOURCES += rescaler.c +libwebputils_la_SOURCES += rescaler.h +libwebputils_la_SOURCES += thread.c +libwebputils_la_SOURCES += thread.h +libwebputils_la_SOURCES += utils.c +libwebputils_la_SOURCES += utils.h + +libwebputilsinclude_HEADERS = ../webp/types.h +libwebputilsincludedir = $(includedir)/webp diff --git a/external/libwebp/utils/bit_reader.c b/external/libwebp/utils/bit_reader.c new file mode 100644 index 0000000000..1afb1db890 --- /dev/null +++ b/external/libwebp/utils/bit_reader.c @@ -0,0 +1,229 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Boolean decoder +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "./bit_reader.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MK(X) (((bit_t)(X) << (BITS)) | (MASK)) + +//------------------------------------------------------------------------------ +// VP8BitReader + +void VP8InitBitReader(VP8BitReader* const br, + const uint8_t* const start, const uint8_t* const end) { + assert(br != NULL); + assert(start != NULL); + assert(start <= end); + br->range_ = MK(255 - 1); + br->buf_ = start; + br->buf_end_ = end; + br->value_ = 0; + br->missing_ = 8; // to load the very first 8bits + br->eof_ = 0; +} + +const uint8_t kVP8Log2Range[128] = { + 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + +// range = (range << kVP8Log2Range[range]) + trailing 1's +const bit_t kVP8NewRange[128] = { + MK(127), MK(127), MK(191), MK(127), MK(159), MK(191), MK(223), MK(127), + MK(143), MK(159), MK(175), MK(191), MK(207), MK(223), MK(239), MK(127), + MK(135), MK(143), MK(151), MK(159), MK(167), MK(175), MK(183), MK(191), + MK(199), MK(207), MK(215), MK(223), MK(231), MK(239), MK(247), MK(127), + MK(131), MK(135), MK(139), MK(143), MK(147), MK(151), MK(155), MK(159), + MK(163), MK(167), MK(171), MK(175), MK(179), MK(183), MK(187), MK(191), + MK(195), MK(199), MK(203), MK(207), MK(211), MK(215), MK(219), MK(223), + MK(227), MK(231), MK(235), MK(239), MK(243), MK(247), MK(251), MK(127), + MK(129), MK(131), MK(133), MK(135), MK(137), MK(139), MK(141), MK(143), + MK(145), MK(147), MK(149), MK(151), MK(153), MK(155), MK(157), MK(159), + MK(161), MK(163), MK(165), MK(167), MK(169), MK(171), MK(173), MK(175), + MK(177), MK(179), MK(181), MK(183), MK(185), MK(187), MK(189), MK(191), + MK(193), MK(195), MK(197), MK(199), MK(201), MK(203), MK(205), MK(207), + MK(209), MK(211), MK(213), MK(215), MK(217), MK(219), MK(221), MK(223), + MK(225), MK(227), MK(229), MK(231), MK(233), MK(235), MK(237), MK(239), + MK(241), MK(243), MK(245), MK(247), MK(249), MK(251), MK(253), MK(127) +}; + +#undef MK + +void VP8LoadFinalBytes(VP8BitReader* const br) { + assert(br != NULL && br->buf_ != NULL); + // Only read 8bits at a time + if (br->buf_ < br->buf_end_) { + br->value_ |= (bit_t)(*br->buf_++) << ((BITS) - 8 + br->missing_); + br->missing_ -= 8; + } else { + br->eof_ = 1; + } +} + +//------------------------------------------------------------------------------ +// Higher-level calls + +uint32_t VP8GetValue(VP8BitReader* const br, int bits) { + uint32_t v = 0; + while (bits-- > 0) { + v |= VP8GetBit(br, 0x80) << bits; + } + return v; +} + +int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) { + const int value = VP8GetValue(br, bits); + return VP8Get(br) ? -value : value; +} + +//------------------------------------------------------------------------------ +// VP8LBitReader + +#define MAX_NUM_BIT_READ 25 + +static const uint32_t kBitMask[MAX_NUM_BIT_READ] = { + 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215 +}; + +void VP8LInitBitReader(VP8LBitReader* const br, + const uint8_t* const start, + size_t length) { + size_t i; + assert(br != NULL); + assert(start != NULL); + assert(length < 0xfffffff8u); // can't happen with a RIFF chunk. + + br->buf_ = start; + br->len_ = length; + br->val_ = 0; + br->pos_ = 0; + br->bit_pos_ = 0; + br->eos_ = 0; + br->error_ = 0; + for (i = 0; i < sizeof(br->val_) && i < br->len_; ++i) { + br->val_ |= ((uint64_t)br->buf_[br->pos_]) << (8 * i); + ++br->pos_; + } +} + +void VP8LBitReaderSetBuffer(VP8LBitReader* const br, + const uint8_t* const buf, size_t len) { + assert(br != NULL); + assert(buf != NULL); + assert(len < 0xfffffff8u); // can't happen with a RIFF chunk. + br->eos_ = (br->pos_ >= len); + br->buf_ = buf; + br->len_ = len; +} + +static void ShiftBytes(VP8LBitReader* const br) { + while (br->bit_pos_ >= 8 && br->pos_ < br->len_) { + br->val_ >>= 8; + br->val_ |= ((uint64_t)br->buf_[br->pos_]) << 56; + ++br->pos_; + br->bit_pos_ -= 8; + } +} + +void VP8LFillBitWindow(VP8LBitReader* const br) { + if (br->bit_pos_ >= 32) { +#if defined(__x86_64__) || defined(_M_X64) + if (br->pos_ + 8 < br->len_) { + br->val_ >>= 32; + // The expression below needs a little-endian arch to work correctly. + // This gives a large speedup for decoding speed. + br->val_ |= *(const uint64_t *)(br->buf_ + br->pos_) << 32; + br->pos_ += 4; + br->bit_pos_ -= 32; + } else { + // Slow path. + ShiftBytes(br); + } +#else + // Always the slow path. + ShiftBytes(br); +#endif + } + if (br->pos_ == br->len_ && br->bit_pos_ == 64) { + br->eos_ = 1; + } +} + +uint32_t VP8LReadOneBit(VP8LBitReader* const br) { + const uint32_t val = (br->val_ >> br->bit_pos_) & 1; + // Flag an error at end_of_stream. + if (!br->eos_) { + ++br->bit_pos_; + if (br->bit_pos_ >= 32) { + ShiftBytes(br); + } + // After this last bit is read, check if eos needs to be flagged. + if (br->pos_ == br->len_ && br->bit_pos_ == 64) { + br->eos_ = 1; + } + } else { + br->error_ = 1; + } + return val; +} + +uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) { + uint32_t val = 0; + assert(n_bits >= 0); + // Flag an error if end_of_stream or n_bits is more than allowed limit. + if (!br->eos_ && n_bits < MAX_NUM_BIT_READ) { + // If this read is going to cross the read buffer, set the eos flag. + if (br->pos_ == br->len_) { + if ((br->bit_pos_ + n_bits) >= 64) { + br->eos_ = 1; + if ((br->bit_pos_ + n_bits) > 64) return val; + } + } + val = (br->val_ >> br->bit_pos_) & kBitMask[n_bits]; + br->bit_pos_ += n_bits; + if (br->bit_pos_ >= 40) { + if (br->pos_ + 5 < br->len_) { + br->val_ >>= 40; + br->val_ |= + (((uint64_t)br->buf_[br->pos_ + 0]) << 24) | + (((uint64_t)br->buf_[br->pos_ + 1]) << 32) | + (((uint64_t)br->buf_[br->pos_ + 2]) << 40) | + (((uint64_t)br->buf_[br->pos_ + 3]) << 48) | + (((uint64_t)br->buf_[br->pos_ + 4]) << 56); + br->pos_ += 5; + br->bit_pos_ -= 40; + } + if (br->bit_pos_ >= 8) { + ShiftBytes(br); + } + } + } else { + br->error_ = 1; + } + return val; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/bit_reader.h b/external/libwebp/utils/bit_reader.h new file mode 100644 index 0000000000..b0324c951c --- /dev/null +++ b/external/libwebp/utils/bit_reader.h @@ -0,0 +1,201 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Boolean decoder +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora (vikaas.arora@gmail.com) + +#ifndef WEBP_UTILS_BIT_READER_H_ +#define WEBP_UTILS_BIT_READER_H_ + +#include "platform/CCPlatformConfig.h" + +#include +#ifdef _MSC_VER +#include // _byteswap_ulong +#endif +#include // For memcpy +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BITS 32 // can be 32, 16 or 8 +#define MASK ((((bit_t)1) << (BITS)) - 1) +#if (BITS == 32) +typedef uint64_t bit_t; // natural register type +typedef uint32_t lbit_t; // natural type for memory I/O +#elif (BITS == 16) +typedef uint32_t bit_t; +typedef uint16_t lbit_t; +#else +typedef uint32_t bit_t; +typedef uint8_t lbit_t; +#endif + +//------------------------------------------------------------------------------ +// Bitreader and code-tree reader + +typedef struct VP8BitReader VP8BitReader; +struct VP8BitReader { + const uint8_t* buf_; // next byte to be read + const uint8_t* buf_end_; // end of read buffer + int eof_; // true if input is exhausted + + // boolean decoder + bit_t range_; // current range minus 1. In [127, 254] interval. + bit_t value_; // current value + int missing_; // number of missing bits in value_ (8bit) +}; + +// Initialize the bit reader and the boolean decoder. +void VP8InitBitReader(VP8BitReader* const br, + const uint8_t* const start, const uint8_t* const end); + +// return the next value made of 'num_bits' bits +uint32_t VP8GetValue(VP8BitReader* const br, int num_bits); +static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) { + return VP8GetValue(br, 1); +} + +// return the next value with sign-extension. +int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits); + +// Read a bit with proba 'prob'. Speed-critical function! +extern const uint8_t kVP8Log2Range[128]; +extern const bit_t kVP8NewRange[128]; + +void VP8LoadFinalBytes(VP8BitReader* const br); // special case for the tail + +static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) { + assert(br && br->buf_); + // Read 'BITS' bits at a time if possible. + if (br->buf_ + sizeof(lbit_t) <= br->buf_end_) { + // convert memory type to register type (with some zero'ing!) + bit_t bits; + lbit_t in_bits = *(lbit_t*)br->buf_; + br->buf_ += (BITS) >> 3; +#if !defined(__BIG_ENDIAN__) +#if (BITS == 32) +#if (defined(__i386__) || defined(__x86_64__) ) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + __asm__ volatile("bswap %k0" : "=r"(in_bits) : "0"(in_bits)); + bits = (bit_t)in_bits; // 32b -> 64b zero-extension +#elif defined(_MSC_VER) && (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) + bits = _byteswap_ulong(in_bits); +#else + bits = (bit_t)(in_bits >> 24) | ((in_bits >> 8) & 0xff00) + | ((in_bits << 8) & 0xff0000) | (in_bits << 24); +#endif // x86 +#elif (BITS == 16) + // gcc will recognize a 'rorw $8, ...' here: + bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8); +#else // BITS == 8 + bits = (bit_t)in_bits; +#endif +#else // LITTLE_ENDIAN + bits = (bit_t)in_bits; +#endif + br->value_ |= bits << br->missing_; + br->missing_ -= (BITS); + } else { + VP8LoadFinalBytes(br); // no need to be inlined + } +} + +static WEBP_INLINE int VP8BitUpdate(VP8BitReader* const br, bit_t split) { + const bit_t value_split = split | (MASK); + if (br->missing_ > 0) { // Make sure we have a least BITS bits in 'value_' + VP8LoadNewBytes(br); + } + if (br->value_ > value_split) { + br->range_ -= value_split + 1; + br->value_ -= value_split + 1; + return 1; + } else { + br->range_ = value_split; + return 0; + } +} + +static WEBP_INLINE void VP8Shift(VP8BitReader* const br) { + // range_ is in [0..127] interval here. + const int idx = br->range_ >> (BITS); + const int shift = kVP8Log2Range[idx]; + br->range_ = kVP8NewRange[idx]; + br->value_ <<= shift; + br->missing_ += shift; +} + +static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) { + // It's important to avoid generating a 64bit x 64bit multiply here. + // We just need an 8b x 8b after all. + const bit_t split = + (bit_t)((uint32_t)(br->range_ >> (BITS)) * prob) << ((BITS) - 8); + const int bit = VP8BitUpdate(br, split); + if (br->range_ <= (((bit_t)0x7e << (BITS)) | (MASK))) { + VP8Shift(br); + } + return bit; +} + +static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) { + const bit_t split = (br->range_ >> 1); + const int bit = VP8BitUpdate(br, split); + VP8Shift(br); + return bit ? -v : v; +} + + +// ----------------------------------------------------------------------------- +// Bitreader + +typedef struct { + uint64_t val_; + const uint8_t* buf_; + size_t len_; + size_t pos_; + int bit_pos_; + int eos_; + int error_; +} VP8LBitReader; + +void VP8LInitBitReader(VP8LBitReader* const br, + const uint8_t* const start, + size_t length); + +// Sets a new data buffer. +void VP8LBitReaderSetBuffer(VP8LBitReader* const br, + const uint8_t* const buffer, size_t length); + +// Reads the specified number of bits from Read Buffer. +// Flags an error in case end_of_stream or n_bits is more than allowed limit. +// Flags eos if this read attempt is going to cross the read buffer. +uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits); + +// Reads one bit from Read Buffer. Flags an error in case end_of_stream. +// Flags eos after reading last bit from the buffer. +uint32_t VP8LReadOneBit(VP8LBitReader* const br); + +// VP8LReadOneBitUnsafe is faster than VP8LReadOneBit, but it can be called only +// 32 times after the last VP8LFillBitWindow. Any subsequent calls +// (without VP8LFillBitWindow) will return invalid data. +static WEBP_INLINE uint32_t VP8LReadOneBitUnsafe(VP8LBitReader* const br) { + const uint32_t val = (br->val_ >> br->bit_pos_) & 1; + ++br->bit_pos_; + return val; +} + +// Advances the Read buffer by 4 bytes to make room for reading next 32 bits. +void VP8LFillBitWindow(VP8LBitReader* const br); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_BIT_READER_H_ */ diff --git a/external/libwebp/utils/bit_writer.c b/external/libwebp/utils/bit_writer.c new file mode 100644 index 0000000000..671159cacd --- /dev/null +++ b/external/libwebp/utils/bit_writer.c @@ -0,0 +1,284 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Bit writing and boolean coder +// +// Author: Skal (pascal.massimino@gmail.com) +// Vikas Arora (vikaas.arora@gmail.com) + +#include +#include // for memcpy() +#include +#include "./bit_writer.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// VP8BitWriter + +static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) { + uint8_t* new_buf; + size_t new_size; + const uint64_t needed_size_64b = (uint64_t)bw->pos_ + extra_size; + const size_t needed_size = (size_t)needed_size_64b; + if (needed_size_64b != needed_size) { + bw->error_ = 1; + return 0; + } + if (needed_size <= bw->max_pos_) return 1; + // If the following line wraps over 32bit, the test just after will catch it. + new_size = 2 * bw->max_pos_; + if (new_size < needed_size) new_size = needed_size; + if (new_size < 1024) new_size = 1024; + new_buf = (uint8_t*)malloc(new_size); + if (new_buf == NULL) { + bw->error_ = 1; + return 0; + } + memcpy(new_buf, bw->buf_, bw->pos_); + free(bw->buf_); + bw->buf_ = new_buf; + bw->max_pos_ = new_size; + return 1; +} + +static void kFlush(VP8BitWriter* const bw) { + const int s = 8 + bw->nb_bits_; + const int32_t bits = bw->value_ >> s; + assert(bw->nb_bits_ >= 0); + bw->value_ -= bits << s; + bw->nb_bits_ -= 8; + if ((bits & 0xff) != 0xff) { + size_t pos = bw->pos_; + if (!BitWriterResize(bw, bw->run_ + 1)) { + return; + } + if (bits & 0x100) { // overflow -> propagate carry over pending 0xff's + if (pos > 0) bw->buf_[pos - 1]++; + } + if (bw->run_ > 0) { + const int value = (bits & 0x100) ? 0x00 : 0xff; + for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value; + } + bw->buf_[pos++] = bits; + bw->pos_ = pos; + } else { + bw->run_++; // delay writing of bytes 0xff, pending eventual carry. + } +} + +//------------------------------------------------------------------------------ +// renormalization + +static const uint8_t kNorm[128] = { // renorm_sizes[i] = 8 - log2(i) + 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + +// range = ((range + 1) << kVP8Log2Range[range]) - 1 +static const uint8_t kNewRange[128] = { + 127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239, + 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, + 247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, + 183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, + 243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, + 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, + 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, + 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, + 241, 243, 245, 247, 249, 251, 253, 127 +}; + +int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) { + const int split = (bw->range_ * prob) >> 8; + if (bit) { + bw->value_ += split + 1; + bw->range_ -= split + 1; + } else { + bw->range_ = split; + } + if (bw->range_ < 127) { // emit 'shift' bits out and renormalize + const int shift = kNorm[bw->range_]; + bw->range_ = kNewRange[bw->range_]; + bw->value_ <<= shift; + bw->nb_bits_ += shift; + if (bw->nb_bits_ > 0) kFlush(bw); + } + return bit; +} + +int VP8PutBitUniform(VP8BitWriter* const bw, int bit) { + const int split = bw->range_ >> 1; + if (bit) { + bw->value_ += split + 1; + bw->range_ -= split + 1; + } else { + bw->range_ = split; + } + if (bw->range_ < 127) { + bw->range_ = kNewRange[bw->range_]; + bw->value_ <<= 1; + bw->nb_bits_ += 1; + if (bw->nb_bits_ > 0) kFlush(bw); + } + return bit; +} + +void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits) { + int mask; + for (mask = 1 << (nb_bits - 1); mask; mask >>= 1) + VP8PutBitUniform(bw, value & mask); +} + +void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits) { + if (!VP8PutBitUniform(bw, value != 0)) + return; + if (value < 0) { + VP8PutValue(bw, ((-value) << 1) | 1, nb_bits + 1); + } else { + VP8PutValue(bw, value << 1, nb_bits + 1); + } +} + +//------------------------------------------------------------------------------ + +int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) { + bw->range_ = 255 - 1; + bw->value_ = 0; + bw->run_ = 0; + bw->nb_bits_ = -8; + bw->pos_ = 0; + bw->max_pos_ = 0; + bw->error_ = 0; + bw->buf_ = NULL; + return (expected_size > 0) ? BitWriterResize(bw, expected_size) : 1; +} + +uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) { + VP8PutValue(bw, 0, 9 - bw->nb_bits_); + bw->nb_bits_ = 0; // pad with zeroes + kFlush(bw); + return bw->buf_; +} + +int VP8BitWriterAppend(VP8BitWriter* const bw, + const uint8_t* data, size_t size) { + assert(data); + if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called + if (!BitWriterResize(bw, size)) return 0; + memcpy(bw->buf_ + bw->pos_, data, size); + bw->pos_ += size; + return 1; +} + +void VP8BitWriterWipeOut(VP8BitWriter* const bw) { + if (bw) { + free(bw->buf_); + memset(bw, 0, sizeof(*bw)); + } +} + +//------------------------------------------------------------------------------ +// VP8LBitWriter + +// Returns 1 on success. +static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) { + uint8_t* allocated_buf; + size_t allocated_size; + const size_t current_size = VP8LBitWriterNumBytes(bw); + const uint64_t size_required_64b = (uint64_t)current_size + extra_size; + const size_t size_required = (size_t)size_required_64b; + if (size_required != size_required_64b) { + bw->error_ = 1; + return 0; + } + if (bw->max_bytes_ > 0 && size_required <= bw->max_bytes_) return 1; + allocated_size = (3 * bw->max_bytes_) >> 1; + if (allocated_size < size_required) allocated_size = size_required; + // make allocated size multiple of 1k + allocated_size = (((allocated_size >> 10) + 1) << 10); + allocated_buf = (uint8_t*)malloc(allocated_size); + if (allocated_buf == NULL) { + bw->error_ = 1; + return 0; + } + memcpy(allocated_buf, bw->buf_, current_size); + free(bw->buf_); + bw->buf_ = allocated_buf; + bw->max_bytes_ = allocated_size; + memset(allocated_buf + current_size, 0, allocated_size - current_size); + return 1; +} + +int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) { + memset(bw, 0, sizeof(*bw)); + return VP8LBitWriterResize(bw, expected_size); +} + +void VP8LBitWriterDestroy(VP8LBitWriter* const bw) { + if (bw != NULL) { + free(bw->buf_); + memset(bw, 0, sizeof(*bw)); + } +} + +void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) { + if (n_bits < 1) return; +#if !defined(__BIG_ENDIAN__) + // Technically, this branch of the code can write up to 25 bits at a time, + // but in prefix encoding, the maximum number of bits written is 18 at a time. + { + uint8_t* const p = &bw->buf_[bw->bit_pos_ >> 3]; + uint32_t v = *(const uint32_t*)p; + v |= bits << (bw->bit_pos_ & 7); + *(uint32_t*)p = v; + bw->bit_pos_ += n_bits; + } +#else // BIG_ENDIAN + { + uint8_t* p = &bw->buf_[bw->bit_pos_ >> 3]; + const int bits_reserved_in_first_byte = bw->bit_pos_ & 7; + const int bits_left_to_write = n_bits - 8 + bits_reserved_in_first_byte; + // implicit & 0xff is assumed for uint8_t arithmetics + *p++ |= bits << bits_reserved_in_first_byte; + bits >>= 8 - bits_reserved_in_first_byte; + if (bits_left_to_write >= 1) { + *p++ = bits; + bits >>= 8; + if (bits_left_to_write >= 9) { + *p++ = bits; + bits >>= 8; + } + } + assert(n_bits <= 25); + *p = bits; + bw->bit_pos_ += n_bits; + } +#endif + if ((bw->bit_pos_ >> 3) > (bw->max_bytes_ - 8)) { + const uint64_t extra_size = 32768ULL + bw->max_bytes_; + if (extra_size != (size_t)extra_size || + !VP8LBitWriterResize(bw, (size_t)extra_size)) { + bw->bit_pos_ = 0; + bw->error_ = 1; + } + } +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/bit_writer.h b/external/libwebp/utils/bit_writer.h new file mode 100644 index 0000000000..f7ca08497f --- /dev/null +++ b/external/libwebp/utils/bit_writer.h @@ -0,0 +1,123 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Bit writing and boolean coder +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_BIT_WRITER_H_ +#define WEBP_UTILS_BIT_WRITER_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Bit-writing + +typedef struct VP8BitWriter VP8BitWriter; +struct VP8BitWriter { + int32_t range_; // range-1 + int32_t value_; + int run_; // number of outstanding bits + int nb_bits_; // number of pending bits + uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned. + size_t pos_; + size_t max_pos_; + int error_; // true in case of error +}; + +// Initialize the object. Allocates some initial memory based on expected_size. +int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size); +// Finalize the bitstream coding. Returns a pointer to the internal buffer. +uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw); +// Release any pending memory and zeroes the object. Not a mandatory call. +// Only useful in case of error, when the internal buffer hasn't been grabbed! +void VP8BitWriterWipeOut(VP8BitWriter* const bw); + +int VP8PutBit(VP8BitWriter* const bw, int bit, int prob); +int VP8PutBitUniform(VP8BitWriter* const bw, int bit); +void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits); +void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits); + +// Appends some bytes to the internal buffer. Data is copied. +int VP8BitWriterAppend(VP8BitWriter* const bw, + const uint8_t* data, size_t size); + +// return approximate write position (in bits) +static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) { + return (uint64_t)(bw->pos_ + bw->run_) * 8 + 8 + bw->nb_bits_; +} + +// Returns a pointer to the internal buffer. +static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) { + return bw->buf_; +} +// Returns the size of the internal buffer. +static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) { + return bw->pos_; +} + +//------------------------------------------------------------------------------ +// VP8LBitWriter +// TODO(vikasa): VP8LBitWriter is copied as-is from lossless code. There's scope +// of re-using VP8BitWriter. Will evaluate once basic lossless encoder is +// implemented. + +typedef struct { + uint8_t* buf_; + size_t bit_pos_; + size_t max_bytes_; + + // After all bits are written, the caller must observe the state of + // error_. A value of 1 indicates that a memory allocation failure + // has happened during bit writing. A value of 0 indicates successful + // writing of bits. + int error_; +} VP8LBitWriter; + +static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) { + return (bw->bit_pos_ + 7) >> 3; +} + +static WEBP_INLINE uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) { + return bw->buf_; +} + +// Returns 0 in case of memory allocation error. +int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size); + +void VP8LBitWriterDestroy(VP8LBitWriter* const bw); + +// This function writes bits into bytes in increasing addresses, and within +// a byte least-significant-bit first. +// +// The function can write up to 16 bits in one go with WriteBits +// Example: let's assume that 3 bits (Rs below) have been written already: +// +// BYTE-0 BYTE+1 BYTE+2 +// +// 0000 0RRR 0000 0000 0000 0000 +// +// Now, we could write 5 or less bits in MSB by just sifting by 3 +// and OR'ing to BYTE-0. +// +// For n bits, we take the last 5 bytes, OR that with high bits in BYTE-0, +// and locate the rest in BYTE+1 and BYTE+2. +// +// VP8LBitWriter's error_ flag is set in case of memory allocation error. +void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_BIT_WRITER_H_ */ diff --git a/external/libwebp/utils/color_cache.c b/external/libwebp/utils/color_cache.c new file mode 100644 index 0000000000..560f81db10 --- /dev/null +++ b/external/libwebp/utils/color_cache.c @@ -0,0 +1,44 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Color Cache for WebP Lossless +// +// Author: Jyrki Alakuijala (jyrki@google.com) + +#include +#include +#include "./color_cache.h" +#include "../utils/utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// VP8LColorCache. + +int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) { + const int hash_size = 1 << hash_bits; + assert(cc != NULL); + assert(hash_bits > 0); + cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size, + sizeof(*cc->colors_)); + if (cc->colors_ == NULL) return 0; + cc->hash_shift_ = 32 - hash_bits; + return 1; +} + +void VP8LColorCacheClear(VP8LColorCache* const cc) { + if (cc != NULL) { + free(cc->colors_); + cc->colors_ = NULL; + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif diff --git a/external/libwebp/utils/color_cache.h b/external/libwebp/utils/color_cache.h new file mode 100644 index 0000000000..13be629f36 --- /dev/null +++ b/external/libwebp/utils/color_cache.h @@ -0,0 +1,68 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Color Cache for WebP Lossless +// +// Authors: Jyrki Alakuijala (jyrki@google.com) +// Urvang Joshi (urvang@google.com) + +#ifndef WEBP_UTILS_COLOR_CACHE_H_ +#define WEBP_UTILS_COLOR_CACHE_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// Main color cache struct. +typedef struct { + uint32_t *colors_; // color entries + int hash_shift_; // Hash shift: 32 - hash_bits. +} VP8LColorCache; + +static const uint32_t kHashMul = 0x1e35a7bd; + +static WEBP_INLINE uint32_t VP8LColorCacheLookup( + const VP8LColorCache* const cc, uint32_t key) { + assert(key <= (~0U >> cc->hash_shift_)); + return cc->colors_[key]; +} + +static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc, + uint32_t argb) { + const uint32_t key = (kHashMul * argb) >> cc->hash_shift_; + cc->colors_[key] = argb; +} + +static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc, + uint32_t argb) { + return (kHashMul * argb) >> cc->hash_shift_; +} + +static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc, + uint32_t argb) { + const uint32_t key = (kHashMul * argb) >> cc->hash_shift_; + return cc->colors_[key] == argb; +} + +//------------------------------------------------------------------------------ + +// Initializes the color cache with 'hash_bits' bits for the keys. +// Returns false in case of memory error. +int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits); + +// Delete the memory associated to color cache. +void VP8LColorCacheClear(VP8LColorCache* const color_cache); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif // WEBP_UTILS_COLOR_CACHE_H_ diff --git a/external/libwebp/utils/filters.c b/external/libwebp/utils/filters.c new file mode 100644 index 0000000000..08f52a3d20 --- /dev/null +++ b/external/libwebp/utils/filters.c @@ -0,0 +1,229 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#include "./filters.h" +#include +#include +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Helpful macro. + +# define SANITY_CHECK(in, out) \ + assert(in != NULL); \ + assert(out != NULL); \ + assert(width > 0); \ + assert(height > 0); \ + assert(bpp > 0); \ + assert(stride >= width * bpp); + +static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred, + uint8_t* dst, int length, int inverse) { + int i; + if (inverse) { + for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i]; + } else { + for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i]; + } +} + +//------------------------------------------------------------------------------ +// Horizontal filter. + +static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in, + int width, int height, int bpp, int stride, int inverse, uint8_t* out) { + int h; + const uint8_t* preds = (inverse ? out : in); + SANITY_CHECK(in, out); + + // Filter line-by-line. + for (h = 0; h < height; ++h) { + // Leftmost pixel is predicted from above (except for topmost scanline). + if (h == 0) { + memcpy((void*)out, (const void*)in, bpp); + } else { + PredictLine(in, preds - stride, out, bpp, inverse); + } + PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); + preds += stride; + in += stride; + out += stride; + } +} + +static void HorizontalFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + DoHorizontalFilter(data, width, height, bpp, stride, 0, filtered_data); +} + +static void HorizontalUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + DoHorizontalFilter(data, width, height, bpp, stride, 1, recon_data); +} + +//------------------------------------------------------------------------------ +// Vertical filter. + +static WEBP_INLINE void DoVerticalFilter(const uint8_t* in, + int width, int height, int bpp, int stride, int inverse, uint8_t* out) { + int h; + const uint8_t* preds = (inverse ? out : in); + SANITY_CHECK(in, out); + + // Very first top-left pixel is copied. + memcpy((void*)out, (const void*)in, bpp); + // Rest of top scan-line is left-predicted. + PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); + + // Filter line-by-line. + for (h = 1; h < height; ++h) { + in += stride; + out += stride; + PredictLine(in, preds, out, bpp * width, inverse); + preds += stride; + } +} + +static void VerticalFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + DoVerticalFilter(data, width, height, bpp, stride, 0, filtered_data); +} + +static void VerticalUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + DoVerticalFilter(data, width, height, bpp, stride, 1, recon_data); +} + +//------------------------------------------------------------------------------ +// Gradient filter. + +static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) { + const int g = a + b - c; + return (g < 0) ? 0 : (g > 255) ? 255 : g; +} + +static WEBP_INLINE +void DoGradientFilter(const uint8_t* in, int width, int height, + int bpp, int stride, int inverse, uint8_t* out) { + const uint8_t* preds = (inverse ? out : in); + int h; + SANITY_CHECK(in, out); + + // left prediction for top scan-line + memcpy((void*)out, (const void*)in, bpp); + PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse); + + // Filter line-by-line. + for (h = 1; h < height; ++h) { + int w; + preds += stride; + in += stride; + out += stride; + // leftmost pixel: predict from above. + PredictLine(in, preds - stride, out, bpp, inverse); + for (w = bpp; w < width * bpp; ++w) { + const int pred = GradientPredictor(preds[w - bpp], + preds[w - stride], + preds[w - stride - bpp]); + out[w] = in[w] + (inverse ? pred : -pred); + } + } +} + +static void GradientFilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* filtered_data) { + DoGradientFilter(data, width, height, bpp, stride, 0, filtered_data); +} + +static void GradientUnfilter(const uint8_t* data, int width, int height, + int bpp, int stride, uint8_t* recon_data) { + DoGradientFilter(data, width, height, bpp, stride, 1, recon_data); +} + +#undef SANITY_CHECK + +// ----------------------------------------------------------------------------- +// Quick estimate of a potentially interesting filter mode to try, in addition +// to the default NONE. + +#define SMAX 16 +#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX) + +WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, + int width, int height, int stride) { + int i, j; + int bins[WEBP_FILTER_LAST][SMAX]; + memset(bins, 0, sizeof(bins)); + // We only sample every other pixels. That's enough. + for (j = 2; j < height - 1; j += 2) { + const uint8_t* const p = data + j * stride; + int mean = p[0]; + for (i = 2; i < width - 1; i += 2) { + const int diff0 = SDIFF(p[i], mean); + const int diff1 = SDIFF(p[i], p[i - 1]); + const int diff2 = SDIFF(p[i], p[i - width]); + const int grad_pred = + GradientPredictor(p[i - 1], p[i - width], p[i - width - 1]); + const int diff3 = SDIFF(p[i], grad_pred); + bins[WEBP_FILTER_NONE][diff0] = 1; + bins[WEBP_FILTER_HORIZONTAL][diff1] = 1; + bins[WEBP_FILTER_VERTICAL][diff2] = 1; + bins[WEBP_FILTER_GRADIENT][diff3] = 1; + mean = (3 * mean + p[i] + 2) >> 2; + } + } + { + WEBP_FILTER_TYPE filter, best_filter = WEBP_FILTER_NONE; + int best_score = 0x7fffffff; + for (filter = WEBP_FILTER_NONE; filter < WEBP_FILTER_LAST; ++filter) { + int score = 0; + for (i = 0; i < SMAX; ++i) { + if (bins[filter][i] > 0) { + score += i; + } + } + if (score < best_score) { + best_score = score; + best_filter = filter; + } + } + return best_filter; + } +} + +#undef SMAX +#undef SDIFF + +//------------------------------------------------------------------------------ + +const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { + NULL, // WEBP_FILTER_NONE + HorizontalFilter, // WEBP_FILTER_HORIZONTAL + VerticalFilter, // WEBP_FILTER_VERTICAL + GradientFilter // WEBP_FILTER_GRADIENT +}; + +const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { + NULL, // WEBP_FILTER_NONE + HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL + VerticalUnfilter, // WEBP_FILTER_VERTICAL + GradientUnfilter // WEBP_FILTER_GRADIENT +}; + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/filters.h b/external/libwebp/utils/filters.h new file mode 100644 index 0000000000..c5cdbd6deb --- /dev/null +++ b/external/libwebp/utils/filters.h @@ -0,0 +1,54 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Spatial prediction using various filters +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_UTILS_FILTERS_H_ +#define WEBP_UTILS_FILTERS_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// Filters. +typedef enum { + WEBP_FILTER_NONE = 0, + WEBP_FILTER_HORIZONTAL, + WEBP_FILTER_VERTICAL, + WEBP_FILTER_GRADIENT, + WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker + WEBP_FILTER_BEST, + WEBP_FILTER_FAST +} WEBP_FILTER_TYPE; + +typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, + int bpp, int stride, uint8_t* out); + +// Filter the given data using the given predictor. +// 'in' corresponds to a 2-dimensional pixel array of size (stride * height) +// in raster order. +// 'bpp' is number of bytes per pixel, and +// 'stride' is number of bytes per scan line (with possible padding). +// 'out' should be pre-allocated. +extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST]; + +// Reconstruct the original data from the given filtered data. +extern const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST]; + +// Fast estimate of a potentially good filter. +extern WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data, + int width, int height, int stride); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_FILTERS_H_ */ diff --git a/external/libwebp/utils/huffman.c b/external/libwebp/utils/huffman.c new file mode 100644 index 0000000000..41529cc9da --- /dev/null +++ b/external/libwebp/utils/huffman.c @@ -0,0 +1,238 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Utilities for building and looking up Huffman trees. +// +// Author: Urvang Joshi (urvang@google.com) + +#include +#include +#include "./huffman.h" +#include "../utils/utils.h" +#include "../webp/format_constants.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define NON_EXISTENT_SYMBOL (-1) + +static void TreeNodeInit(HuffmanTreeNode* const node) { + node->children_ = -1; // means: 'unassigned so far' +} + +static int NodeIsEmpty(const HuffmanTreeNode* const node) { + return (node->children_ < 0); +} + +static int IsFull(const HuffmanTree* const tree) { + return (tree->num_nodes_ == tree->max_nodes_); +} + +static void AssignChildren(HuffmanTree* const tree, + HuffmanTreeNode* const node) { + HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_; + node->children_ = (int)(children - node); + assert(children - node == (int)(children - node)); + tree->num_nodes_ += 2; + TreeNodeInit(children + 0); + TreeNodeInit(children + 1); +} + +static int TreeInit(HuffmanTree* const tree, int num_leaves) { + assert(tree != NULL); + if (num_leaves == 0) return 0; + // We allocate maximum possible nodes in the tree at once. + // Note that a Huffman tree is a full binary tree; and in a full binary tree + // with L leaves, the total number of nodes N = 2 * L - 1. + tree->max_nodes_ = 2 * num_leaves - 1; + tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_, + sizeof(*tree->root_)); + if (tree->root_ == NULL) return 0; + TreeNodeInit(tree->root_); // Initialize root. + tree->num_nodes_ = 1; + return 1; +} + +void HuffmanTreeRelease(HuffmanTree* const tree) { + if (tree != NULL) { + free(tree->root_); + tree->root_ = NULL; + tree->max_nodes_ = 0; + tree->num_nodes_ = 0; + } +} + +int HuffmanCodeLengthsToCodes(const int* const code_lengths, + int code_lengths_size, int* const huff_codes) { + int symbol; + int code_len; + int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; + int curr_code; + int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; + int max_code_length = 0; + + assert(code_lengths != NULL); + assert(code_lengths_size > 0); + assert(huff_codes != NULL); + + // Calculate max code length. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + if (code_lengths[symbol] > max_code_length) { + max_code_length = code_lengths[symbol]; + } + } + if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0; + + // Calculate code length histogram. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + ++code_length_hist[code_lengths[symbol]]; + } + code_length_hist[0] = 0; + + // Calculate the initial values of 'next_codes' for each code length. + // next_codes[code_len] denotes the code to be assigned to the next symbol + // of code length 'code_len'. + curr_code = 0; + next_codes[0] = -1; // Unused, as code length = 0 implies code doesn't exist. + for (code_len = 1; code_len <= max_code_length; ++code_len) { + curr_code = (curr_code + code_length_hist[code_len - 1]) << 1; + next_codes[code_len] = curr_code; + } + + // Get symbols. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + if (code_lengths[symbol] > 0) { + huff_codes[symbol] = next_codes[code_lengths[symbol]]++; + } else { + huff_codes[symbol] = NON_EXISTENT_SYMBOL; + } + } + return 1; +} + +static int TreeAddSymbol(HuffmanTree* const tree, + int symbol, int code, int code_length) { + HuffmanTreeNode* node = tree->root_; + const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_; + while (code_length-- > 0) { + if (node >= max_node) { + return 0; + } + if (NodeIsEmpty(node)) { + if (IsFull(tree)) return 0; // error: too many symbols. + AssignChildren(tree, node); + } else if (HuffmanTreeNodeIsLeaf(node)) { + return 0; // leaf is already occupied. + } + node += node->children_ + ((code >> code_length) & 1); + } + if (NodeIsEmpty(node)) { + node->children_ = 0; // turn newly created node into a leaf. + } else if (!HuffmanTreeNodeIsLeaf(node)) { + return 0; // trying to assign a symbol to already used code. + } + node->symbol_ = symbol; // Add symbol in this node. + return 1; +} + +int HuffmanTreeBuildImplicit(HuffmanTree* const tree, + const int* const code_lengths, + int code_lengths_size) { + int symbol; + int num_symbols = 0; + int root_symbol = 0; + + assert(tree != NULL); + assert(code_lengths != NULL); + + // Find out number of symbols and the root symbol. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + if (code_lengths[symbol] > 0) { + // Note: code length = 0 indicates non-existent symbol. + ++num_symbols; + root_symbol = symbol; + } + } + + // Initialize the tree. Will fail for num_symbols = 0 + if (!TreeInit(tree, num_symbols)) return 0; + + // Build tree. + if (num_symbols == 1) { // Trivial case. + const int max_symbol = code_lengths_size; + if (root_symbol < 0 || root_symbol >= max_symbol) { + HuffmanTreeRelease(tree); + return 0; + } + return TreeAddSymbol(tree, root_symbol, 0, 0); + } else { // Normal case. + int ok = 0; + + // Get Huffman codes from the code lengths. + int* const codes = + (int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes)); + if (codes == NULL) goto End; + + if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) { + goto End; + } + + // Add symbols one-by-one. + for (symbol = 0; symbol < code_lengths_size; ++symbol) { + if (code_lengths[symbol] > 0) { + if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) { + goto End; + } + } + } + ok = 1; + End: + free(codes); + ok = ok && IsFull(tree); + if (!ok) HuffmanTreeRelease(tree); + return ok; + } +} + +int HuffmanTreeBuildExplicit(HuffmanTree* const tree, + const int* const code_lengths, + const int* const codes, + const int* const symbols, int max_symbol, + int num_symbols) { + int ok = 0; + int i; + + assert(tree != NULL); + assert(code_lengths != NULL); + assert(codes != NULL); + assert(symbols != NULL); + + // Initialize the tree. Will fail if num_symbols = 0. + if (!TreeInit(tree, num_symbols)) return 0; + + // Add symbols one-by-one. + for (i = 0; i < num_symbols; ++i) { + if (codes[i] != NON_EXISTENT_SYMBOL) { + if (symbols[i] < 0 || symbols[i] >= max_symbol) { + goto End; + } + if (!TreeAddSymbol(tree, symbols[i], codes[i], code_lengths[i])) { + goto End; + } + } + } + ok = 1; + End: + ok = ok && IsFull(tree); + if (!ok) HuffmanTreeRelease(tree); + return ok; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/huffman.h b/external/libwebp/utils/huffman.h new file mode 100644 index 0000000000..70220a67fb --- /dev/null +++ b/external/libwebp/utils/huffman.h @@ -0,0 +1,78 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Utilities for building and looking up Huffman trees. +// +// Author: Urvang Joshi (urvang@google.com) + +#ifndef WEBP_UTILS_HUFFMAN_H_ +#define WEBP_UTILS_HUFFMAN_H_ + +#include +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// A node of a Huffman tree. +typedef struct { + int symbol_; + int children_; // delta offset to both children (contiguous) or 0 if leaf. +} HuffmanTreeNode; + +// Huffman Tree. +typedef struct HuffmanTree HuffmanTree; +struct HuffmanTree { + HuffmanTreeNode* root_; // all the nodes, starting at root. + int max_nodes_; // max number of nodes + int num_nodes_; // number of currently occupied nodes +}; + +// Returns true if the given node is a leaf of the Huffman tree. +static WEBP_INLINE int HuffmanTreeNodeIsLeaf( + const HuffmanTreeNode* const node) { + return (node->children_ == 0); +} + +// Go down one level. Most critical function. 'right_child' must be 0 or 1. +static WEBP_INLINE const HuffmanTreeNode* HuffmanTreeNextNode( + const HuffmanTreeNode* node, int right_child) { + return node + node->children_ + right_child; +} + +// Releases the nodes of the Huffman tree. +// Note: It does NOT free 'tree' itself. +void HuffmanTreeRelease(HuffmanTree* const tree); + +// Builds Huffman tree assuming code lengths are implicitly in symbol order. +// Returns false in case of error (invalid tree or memory error). +int HuffmanTreeBuildImplicit(HuffmanTree* const tree, + const int* const code_lengths, + int code_lengths_size); + +// Build a Huffman tree with explicitly given lists of code lengths, codes +// and symbols. Verifies that all symbols added are smaller than max_symbol. +// Returns false in case of an invalid symbol, invalid tree or memory error. +int HuffmanTreeBuildExplicit(HuffmanTree* const tree, + const int* const code_lengths, + const int* const codes, + const int* const symbols, int max_symbol, + int num_symbols); + +// Utility: converts Huffman code lengths to corresponding Huffman codes. +// 'huff_codes' should be pre-allocated. +// Returns false in case of error (memory allocation, invalid codes). +int HuffmanCodeLengthsToCodes(const int* const code_lengths, + int code_lengths_size, int* const huff_codes); + + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBP_UTILS_HUFFMAN_H_ diff --git a/external/libwebp/utils/huffman_encode.c b/external/libwebp/utils/huffman_encode.c new file mode 100644 index 0000000000..8ccd291d22 --- /dev/null +++ b/external/libwebp/utils/huffman_encode.c @@ -0,0 +1,439 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Entropy encoding (Huffman) for webp lossless. + +#include +#include +#include +#include "./huffman_encode.h" +#include "../utils/utils.h" +#include "../webp/format_constants.h" + +// ----------------------------------------------------------------------------- +// Util function to optimize the symbol map for RLE coding + +// Heuristics for selecting the stride ranges to collapse. +static int ValuesShouldBeCollapsedToStrideAverage(int a, int b) { + return abs(a - b) < 4; +} + +// Change the population counts in a way that the consequent +// Hufmann tree compression, especially its RLE-part, give smaller output. +static int OptimizeHuffmanForRle(int length, int* const counts) { + uint8_t* good_for_rle; + // 1) Let's make the Huffman code more compatible with rle encoding. + int i; + for (; length >= 0; --length) { + if (length == 0) { + return 1; // All zeros. + } + if (counts[length - 1] != 0) { + // Now counts[0..length - 1] does not have trailing zeros. + break; + } + } + // 2) Let's mark all population counts that already can be encoded + // with an rle code. + good_for_rle = (uint8_t*)calloc(length, 1); + if (good_for_rle == NULL) { + return 0; + } + { + // Let's not spoil any of the existing good rle codes. + // Mark any seq of 0's that is longer as 5 as a good_for_rle. + // Mark any seq of non-0's that is longer as 7 as a good_for_rle. + int symbol = counts[0]; + int stride = 0; + for (i = 0; i < length + 1; ++i) { + if (i == length || counts[i] != symbol) { + if ((symbol == 0 && stride >= 5) || + (symbol != 0 && stride >= 7)) { + int k; + for (k = 0; k < stride; ++k) { + good_for_rle[i - k - 1] = 1; + } + } + stride = 1; + if (i != length) { + symbol = counts[i]; + } + } else { + ++stride; + } + } + } + // 3) Let's replace those population counts that lead to more rle codes. + { + int stride = 0; + int limit = counts[0]; + int sum = 0; + for (i = 0; i < length + 1; ++i) { + if (i == length || good_for_rle[i] || + (i != 0 && good_for_rle[i - 1]) || + !ValuesShouldBeCollapsedToStrideAverage(counts[i], limit)) { + if (stride >= 4 || (stride >= 3 && sum == 0)) { + int k; + // The stride must end, collapse what we have, if we have enough (4). + int count = (sum + stride / 2) / stride; + if (count < 1) { + count = 1; + } + if (sum == 0) { + // Don't make an all zeros stride to be upgraded to ones. + count = 0; + } + for (k = 0; k < stride; ++k) { + // We don't want to change value at counts[i], + // that is already belonging to the next stride. Thus - 1. + counts[i - k - 1] = count; + } + } + stride = 0; + sum = 0; + if (i < length - 3) { + // All interesting strides have a count of at least 4, + // at least when non-zeros. + limit = (counts[i] + counts[i + 1] + + counts[i + 2] + counts[i + 3] + 2) / 4; + } else if (i < length) { + limit = counts[i]; + } else { + limit = 0; + } + } + ++stride; + if (i != length) { + sum += counts[i]; + if (stride >= 4) { + limit = (sum + stride / 2) / stride; + } + } + } + } + free(good_for_rle); + return 1; +} + +typedef struct { + int total_count_; + int value_; + int pool_index_left_; + int pool_index_right_; +} HuffmanTree; + +// A comparer function for two Huffman trees: sorts first by 'total count' +// (more comes first), and then by 'value' (more comes first). +static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) { + const HuffmanTree* const t1 = (const HuffmanTree*)ptr1; + const HuffmanTree* const t2 = (const HuffmanTree*)ptr2; + if (t1->total_count_ > t2->total_count_) { + return -1; + } else if (t1->total_count_ < t2->total_count_) { + return 1; + } else { + if (t1->value_ < t2->value_) { + return -1; + } + if (t1->value_ > t2->value_) { + return 1; + } + return 0; + } +} + +static void SetBitDepths(const HuffmanTree* const tree, + const HuffmanTree* const pool, + uint8_t* const bit_depths, int level) { + if (tree->pool_index_left_ >= 0) { + SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1); + SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1); + } else { + bit_depths[tree->value_] = level; + } +} + +// Create an optimal Huffman tree. +// +// (data,length): population counts. +// tree_limit: maximum bit depth (inclusive) of the codes. +// bit_depths[]: how many bits are used for the symbol. +// +// Returns 0 when an error has occurred. +// +// The catch here is that the tree cannot be arbitrarily deep +// +// count_limit is the value that is to be faked as the minimum value +// and this minimum value is raised until the tree matches the +// maximum length requirement. +// +// This algorithm is not of excellent performance for very long data blocks, +// especially when population counts are longer than 2**tree_limit, but +// we are not planning to use this with extremely long blocks. +// +// See http://en.wikipedia.org/wiki/Huffman_coding +static int GenerateOptimalTree(const int* const histogram, int histogram_size, + int tree_depth_limit, + uint8_t* const bit_depths) { + int count_min; + HuffmanTree* tree_pool; + HuffmanTree* tree; + int tree_size_orig = 0; + int i; + + for (i = 0; i < histogram_size; ++i) { + if (histogram[i] != 0) { + ++tree_size_orig; + } + } + + // 3 * tree_size is enough to cover all the nodes representing a + // population and all the inserted nodes combining two existing nodes. + // The tree pool needs 2 * (tree_size_orig - 1) entities, and the + // tree needs exactly tree_size_orig entities. + tree = (HuffmanTree*)WebPSafeMalloc(3ULL * tree_size_orig, sizeof(*tree)); + if (tree == NULL) return 0; + tree_pool = tree + tree_size_orig; + + // For block sizes with less than 64k symbols we never need to do a + // second iteration of this loop. + // If we actually start running inside this loop a lot, we would perhaps + // be better off with the Katajainen algorithm. + assert(tree_size_orig <= (1 << (tree_depth_limit - 1))); + for (count_min = 1; ; count_min *= 2) { + int tree_size = tree_size_orig; + // We need to pack the Huffman tree in tree_depth_limit bits. + // So, we try by faking histogram entries to be at least 'count_min'. + int idx = 0; + int j; + for (j = 0; j < histogram_size; ++j) { + if (histogram[j] != 0) { + const int count = + (histogram[j] < count_min) ? count_min : histogram[j]; + tree[idx].total_count_ = count; + tree[idx].value_ = j; + tree[idx].pool_index_left_ = -1; + tree[idx].pool_index_right_ = -1; + ++idx; + } + } + + // Build the Huffman tree. + qsort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees); + + if (tree_size > 1) { // Normal case. + int tree_pool_size = 0; + while (tree_size > 1) { // Finish when we have only one root. + int count; + tree_pool[tree_pool_size++] = tree[tree_size - 1]; + tree_pool[tree_pool_size++] = tree[tree_size - 2]; + count = tree_pool[tree_pool_size - 1].total_count_ + + tree_pool[tree_pool_size - 2].total_count_; + tree_size -= 2; + { + // Search for the insertion point. + int k; + for (k = 0; k < tree_size; ++k) { + if (tree[k].total_count_ <= count) { + break; + } + } + memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree)); + tree[k].total_count_ = count; + tree[k].value_ = -1; + + tree[k].pool_index_left_ = tree_pool_size - 1; + tree[k].pool_index_right_ = tree_pool_size - 2; + tree_size = tree_size + 1; + } + } + SetBitDepths(&tree[0], tree_pool, bit_depths, 0); + } else if (tree_size == 1) { // Trivial case: only one element. + bit_depths[tree[0].value_] = 1; + } + + { + // Test if this Huffman tree satisfies our 'tree_depth_limit' criteria. + int max_depth = bit_depths[0]; + for (j = 1; j < histogram_size; ++j) { + if (max_depth < bit_depths[j]) { + max_depth = bit_depths[j]; + } + } + if (max_depth <= tree_depth_limit) { + break; + } + } + } + free(tree); + return 1; +} + +// ----------------------------------------------------------------------------- +// Coding of the Huffman tree values + +static HuffmanTreeToken* CodeRepeatedValues(int repetitions, + HuffmanTreeToken* tokens, + int value, int prev_value) { + assert(value <= MAX_ALLOWED_CODE_LENGTH); + if (value != prev_value) { + tokens->code = value; + tokens->extra_bits = 0; + ++tokens; + --repetitions; + } + while (repetitions >= 1) { + if (repetitions < 3) { + int i; + for (i = 0; i < repetitions; ++i) { + tokens->code = value; + tokens->extra_bits = 0; + ++tokens; + } + break; + } else if (repetitions < 7) { + tokens->code = 16; + tokens->extra_bits = repetitions - 3; + ++tokens; + break; + } else { + tokens->code = 16; + tokens->extra_bits = 3; + ++tokens; + repetitions -= 6; + } + } + return tokens; +} + +static HuffmanTreeToken* CodeRepeatedZeros(int repetitions, + HuffmanTreeToken* tokens) { + while (repetitions >= 1) { + if (repetitions < 3) { + int i; + for (i = 0; i < repetitions; ++i) { + tokens->code = 0; // 0-value + tokens->extra_bits = 0; + ++tokens; + } + break; + } else if (repetitions < 11) { + tokens->code = 17; + tokens->extra_bits = repetitions - 3; + ++tokens; + break; + } else if (repetitions < 139) { + tokens->code = 18; + tokens->extra_bits = repetitions - 11; + ++tokens; + break; + } else { + tokens->code = 18; + tokens->extra_bits = 0x7f; // 138 repeated 0s + ++tokens; + repetitions -= 138; + } + } + return tokens; +} + +int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, + HuffmanTreeToken* tokens, int max_tokens) { + HuffmanTreeToken* const starting_token = tokens; + HuffmanTreeToken* const ending_token = tokens + max_tokens; + const int depth_size = tree->num_symbols; + int prev_value = 8; // 8 is the initial value for rle. + int i = 0; + assert(tokens != NULL); + while (i < depth_size) { + const int value = tree->code_lengths[i]; + int k = i + 1; + int runs; + while (k < depth_size && tree->code_lengths[k] == value) ++k; + runs = k - i; + if (value == 0) { + tokens = CodeRepeatedZeros(runs, tokens); + } else { + tokens = CodeRepeatedValues(runs, tokens, value, prev_value); + prev_value = value; + } + i += runs; + assert(tokens <= ending_token); + } + (void)ending_token; // suppress 'unused variable' warning + return (int)(tokens - starting_token); +} + +// ----------------------------------------------------------------------------- + +// Pre-reversed 4-bit values. +static const uint8_t kReversedBits[16] = { + 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf +}; + +static uint32_t ReverseBits(int num_bits, uint32_t bits) { + uint32_t retval = 0; + int i = 0; + while (i < num_bits) { + i += 4; + retval |= kReversedBits[bits & 0xf] << (MAX_ALLOWED_CODE_LENGTH + 1 - i); + bits >>= 4; + } + retval >>= (MAX_ALLOWED_CODE_LENGTH + 1 - num_bits); + return retval; +} + +// Get the actual bit values for a tree of bit depths. +static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) { + // 0 bit-depth means that the symbol does not exist. + int i; + int len; + uint32_t next_code[MAX_ALLOWED_CODE_LENGTH + 1]; + int depth_count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; + + assert(tree != NULL); + len = tree->num_symbols; + for (i = 0; i < len; ++i) { + const int code_length = tree->code_lengths[i]; + assert(code_length <= MAX_ALLOWED_CODE_LENGTH); + ++depth_count[code_length]; + } + depth_count[0] = 0; // ignore unused symbol + next_code[0] = 0; + { + uint32_t code = 0; + for (i = 1; i <= MAX_ALLOWED_CODE_LENGTH; ++i) { + code = (code + depth_count[i - 1]) << 1; + next_code[i] = code; + } + } + for (i = 0; i < len; ++i) { + const int code_length = tree->code_lengths[i]; + tree->codes[i] = ReverseBits(code_length, next_code[code_length]++); + } +} + +// ----------------------------------------------------------------------------- +// Main entry point + +int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit, + HuffmanTreeCode* const tree) { + const int num_symbols = tree->num_symbols; + if (!OptimizeHuffmanForRle(num_symbols, histogram)) { + return 0; + } + if (!GenerateOptimalTree(histogram, num_symbols, + tree_depth_limit, tree->code_lengths)) { + return 0; + } + // Create the actual bit codes for the bit lengths. + ConvertBitDepthsToSymbols(tree); + return 1; +} diff --git a/external/libwebp/utils/huffman_encode.h b/external/libwebp/utils/huffman_encode.h new file mode 100644 index 0000000000..cc3b38d330 --- /dev/null +++ b/external/libwebp/utils/huffman_encode.h @@ -0,0 +1,47 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Author: Jyrki Alakuijala (jyrki@google.com) +// +// Entropy encoding (Huffman) for webp lossless + +#ifndef WEBP_UTILS_HUFFMAN_ENCODE_H_ +#define WEBP_UTILS_HUFFMAN_ENCODE_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// Struct for holding the tree header in coded form. +typedef struct { + uint8_t code; // value (0..15) or escape code (16,17,18) + uint8_t extra_bits; // extra bits for escape codes +} HuffmanTreeToken; + +// Struct to represent the tree codes (depth and bits array). +typedef struct { + int num_symbols; // Number of symbols. + uint8_t* code_lengths; // Code lengths of the symbols. + uint16_t* codes; // Symbol Codes. +} HuffmanTreeCode; + +// Turn the Huffman tree into a token sequence. +// Returns the number of tokens used. +int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, + HuffmanTreeToken* tokens, int max_tokens); + +// Create an optimized tree, and tokenize it. +int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit, + HuffmanTreeCode* const tree); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif // WEBP_UTILS_HUFFMAN_ENCODE_H_ diff --git a/external/libwebp/utils/quant_levels.c b/external/libwebp/utils/quant_levels.c new file mode 100644 index 0000000000..f6884392aa --- /dev/null +++ b/external/libwebp/utils/quant_levels.c @@ -0,0 +1,154 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Quantize levels for specified number of quantization-levels ([2, 256]). +// Min and max values are preserved (usual 0 and 255 for alpha plane). +// +// Author: Skal (pascal.massimino@gmail.com) + +#include + +#include "./quant_levels.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define NUM_SYMBOLS 256 + +#define MAX_ITER 6 // Maximum number of convergence steps. +#define ERROR_THRESHOLD 1e-4 // MSE stopping criterion. + +// ----------------------------------------------------------------------------- +// Quantize levels. + +int QuantizeLevels(uint8_t* const data, int width, int height, + int num_levels, uint64_t* const sse) { + int freq[NUM_SYMBOLS] = { 0 }; + int q_level[NUM_SYMBOLS] = { 0 }; + double inv_q_level[NUM_SYMBOLS] = { 0 }; + int min_s = 255, max_s = 0; + const size_t data_size = height * width; + int i, num_levels_in, iter; + double last_err = 1.e38, err = 0.; + const double err_threshold = ERROR_THRESHOLD * data_size; + + if (data == NULL) { + return 0; + } + + if (width <= 0 || height <= 0) { + return 0; + } + + if (num_levels < 2 || num_levels > 256) { + return 0; + } + + { + size_t n; + num_levels_in = 0; + for (n = 0; n < data_size; ++n) { + num_levels_in += (freq[data[n]] == 0); + if (min_s > data[n]) min_s = data[n]; + if (max_s < data[n]) max_s = data[n]; + ++freq[data[n]]; + } + } + + if (num_levels_in <= num_levels) goto End; // nothing to do! + + // Start with uniformly spread centroids. + for (i = 0; i < num_levels; ++i) { + inv_q_level[i] = min_s + (double)(max_s - min_s) * i / (num_levels - 1); + } + + // Fixed values. Won't be changed. + q_level[min_s] = 0; + q_level[max_s] = num_levels - 1; + assert(inv_q_level[0] == min_s); + assert(inv_q_level[num_levels - 1] == max_s); + + // k-Means iterations. + for (iter = 0; iter < MAX_ITER; ++iter) { + double q_sum[NUM_SYMBOLS] = { 0 }; + double q_count[NUM_SYMBOLS] = { 0 }; + int s, slot = 0; + + // Assign classes to representatives. + for (s = min_s; s <= max_s; ++s) { + // Keep track of the nearest neighbour 'slot' + while (slot < num_levels - 1 && + 2 * s > inv_q_level[slot] + inv_q_level[slot + 1]) { + ++slot; + } + if (freq[s] > 0) { + q_sum[slot] += s * freq[s]; + q_count[slot] += freq[s]; + } + q_level[s] = slot; + } + + // Assign new representatives to classes. + if (num_levels > 2) { + for (slot = 1; slot < num_levels - 1; ++slot) { + const double count = q_count[slot]; + if (count > 0.) { + inv_q_level[slot] = q_sum[slot] / count; + } + } + } + + // Compute convergence error. + err = 0.; + for (s = min_s; s <= max_s; ++s) { + const double error = s - inv_q_level[q_level[s]]; + err += freq[s] * error * error; + } + + // Check for convergence: we stop as soon as the error is no + // longer improving. + if (last_err - err < err_threshold) break; + last_err = err; + } + + // Remap the alpha plane to quantized values. + { + // double->int rounding operation can be costly, so we do it + // once for all before remapping. We also perform the data[] -> slot + // mapping, while at it (avoid one indirection in the final loop). + uint8_t map[NUM_SYMBOLS]; + int s; + size_t n; + for (s = min_s; s <= max_s; ++s) { + const int slot = q_level[s]; + map[s] = (uint8_t)(inv_q_level[slot] + .5); + } + // Final pass. + for (n = 0; n < data_size; ++n) { + data[n] = map[data[n]]; + } + } + End: + // Store sum of squared error if needed. + if (sse != NULL) *sse = (uint64_t)err; + + return 1; +} + +int DequantizeLevels(uint8_t* const data, int width, int height) { + if (data == NULL || width <= 0 || height <= 0) return 0; + // TODO(skal): implement gradient smoothing. + (void)data; + (void)width; + (void)height; + return 1; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/quant_levels.h b/external/libwebp/utils/quant_levels.h new file mode 100644 index 0000000000..89ccafe40d --- /dev/null +++ b/external/libwebp/utils/quant_levels.h @@ -0,0 +1,39 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Alpha plane quantization utility +// +// Author: Vikas Arora (vikasa@google.com) + +#ifndef WEBP_UTILS_QUANT_LEVELS_H_ +#define WEBP_UTILS_QUANT_LEVELS_H_ + +#include + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// Replace the input 'data' of size 'width'x'height' with 'num-levels' +// quantized values. If not NULL, 'sse' will contain the sum of squared error. +// Valid range for 'num_levels' is [2, 256]. +// Returns false in case of error (data is NULL, or parameters are invalid). +int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels, + uint64_t* const sse); + +// Apply post-processing to input 'data' of size 'width'x'height' assuming +// that the source was quantized to a reduced number of levels. +// Returns false in case of error (data is NULL, invalid parameters, ...). +int DequantizeLevels(uint8_t* const data, int width, int height); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_QUANT_LEVELS_H_ */ diff --git a/external/libwebp/utils/rescaler.c b/external/libwebp/utils/rescaler.c new file mode 100644 index 0000000000..9825dcbc5f --- /dev/null +++ b/external/libwebp/utils/rescaler.c @@ -0,0 +1,152 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include "./rescaler.h" + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define RFIX 30 +#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX) + +void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, + uint8_t* const dst, int dst_width, int dst_height, + int dst_stride, int num_channels, int x_add, int x_sub, + int y_add, int y_sub, int32_t* const work) { + wrk->x_expand = (src_width < dst_width); + wrk->src_width = src_width; + wrk->src_height = src_height; + wrk->dst_width = dst_width; + wrk->dst_height = dst_height; + wrk->dst = dst; + wrk->dst_stride = dst_stride; + wrk->num_channels = num_channels; + // for 'x_expand', we use bilinear interpolation + wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub; + wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub; + wrk->y_accum = y_add; + wrk->y_add = y_add; + wrk->y_sub = y_sub; + wrk->fx_scale = (1 << RFIX) / x_sub; + wrk->fy_scale = (1 << RFIX) / y_sub; + wrk->fxy_scale = wrk->x_expand ? + ((int64_t)dst_height << RFIX) / (x_sub * src_height) : + ((int64_t)dst_height << RFIX) / (x_add * src_height); + wrk->irow = work; + wrk->frow = work + num_channels * dst_width; +} + +void WebPRescalerImportRow(WebPRescaler* const wrk, + const uint8_t* const src, int channel) { + const int x_stride = wrk->num_channels; + const int x_out_max = wrk->dst_width * wrk->num_channels; + int x_in = channel; + int x_out; + int accum = 0; + if (!wrk->x_expand) { + int sum = 0; + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + accum += wrk->x_add; + for (; accum > 0; accum -= wrk->x_sub) { + sum += src[x_in]; + x_in += x_stride; + } + { // Emit next horizontal pixel. + const int32_t base = src[x_in]; + const int32_t frac = base * (-accum); + x_in += x_stride; + wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac; + // fresh fractional start for next pixel + sum = (int)MULT_FIX(frac, wrk->fx_scale); + } + } + } else { // simple bilinear interpolation + int left = src[channel], right = src[channel]; + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + if (accum < 0) { + left = right; + x_in += x_stride; + right = src[x_in]; + accum += wrk->x_add; + } + wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; + accum -= wrk->x_sub; + } + } + // Accumulate the new row's contribution + for (x_out = channel; x_out < x_out_max; x_out += x_stride) { + wrk->irow[x_out] += wrk->frow[x_out]; + } +} + +uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) { + if (wrk->y_accum <= 0) { + int x_out; + uint8_t* const dst = wrk->dst; + int32_t* const irow = wrk->irow; + const int32_t* const frow = wrk->frow; + const int yscale = wrk->fy_scale * (-wrk->y_accum); + const int x_out_max = wrk->dst_width * wrk->num_channels; + + for (x_out = 0; x_out < x_out_max; ++x_out) { + const int frac = (int)MULT_FIX(frow[x_out], yscale); + const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; + irow[x_out] = frac; // new fractional start + } + wrk->y_accum += wrk->y_add; + wrk->dst += wrk->dst_stride; + return dst; + } else { + return NULL; + } +} + +#undef MULT_FIX +#undef RFIX + +//------------------------------------------------------------------------------ +// all-in-one calls + +int WebPRescalerImport(WebPRescaler* const wrk, int num_lines, + const uint8_t* src, int src_stride) { + int total_imported = 0; + while (total_imported < num_lines && wrk->y_accum > 0) { + int channel; + for (channel = 0; channel < wrk->num_channels; ++channel) { + WebPRescalerImportRow(wrk, src, channel); + } + src += src_stride; + ++total_imported; + wrk->y_accum -= wrk->y_sub; + } + return total_imported; +} + +int WebPRescalerExport(WebPRescaler* const rescaler) { + int total_exported = 0; + while (WebPRescalerHasPendingOutput(rescaler)) { + WebPRescalerExportRow(rescaler); + ++total_exported; + } + return total_exported; +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/rescaler.h b/external/libwebp/utils/rescaler.h new file mode 100644 index 0000000000..ef93d465f0 --- /dev/null +++ b/external/libwebp/utils/rescaler.h @@ -0,0 +1,76 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Rescaling functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_RESCALER_H_ +#define WEBP_UTILS_RESCALER_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include "../webp/types.h" + +// Structure used for on-the-fly rescaling +typedef struct { + int x_expand; // true if we're expanding in the x direction + int num_channels; // bytes to jump between pixels + int fy_scale, fx_scale; // fixed-point scaling factor + int64_t fxy_scale; // '' + // we need hpel-precise add/sub increments, for the downsampled U/V planes. + int y_accum; // vertical accumulator + int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst) + int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst) + int src_width, src_height; // source dimensions + int dst_width, dst_height; // destination dimensions + uint8_t* dst; + int dst_stride; + int32_t* irow, *frow; // work buffer +} WebPRescaler; + +// Initialize a rescaler given scratch area 'work' and dimensions of src & dst. +void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, + uint8_t* const dst, + int dst_width, int dst_height, int dst_stride, + int num_channels, + int x_add, int x_sub, + int y_add, int y_sub, + int32_t* const work); + +// Import a row of data and save its contribution in the rescaler. +// 'channel' denotes the channel number to be imported. +void WebPRescalerImportRow(WebPRescaler* const rescaler, + const uint8_t* const src, int channel); + +// Import multiple rows over all channels, until at least one row is ready to +// be exported. Returns the actual number of lines that were imported. +int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows, + const uint8_t* src, int src_stride); + +// Return true if there is pending output rows ready. +static WEBP_INLINE +int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) { + return (rescaler->y_accum <= 0); +} + +// Export one row from rescaler. Returns the pointer where output was written, +// or NULL if no row was pending. +uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk); + +// Export as many rows as possible. Return the numbers of rows written. +int WebPRescalerExport(WebPRescaler* const wrk); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_RESCALER_H_ */ diff --git a/external/libwebp/utils/thread.c b/external/libwebp/utils/thread.c new file mode 100644 index 0000000000..ce89cf9dc7 --- /dev/null +++ b/external/libwebp/utils/thread.c @@ -0,0 +1,247 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Multi-threaded worker +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include // for memset() +#include "./thread.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#ifdef WEBP_USE_THREAD + +#if defined(_WIN32) + +//------------------------------------------------------------------------------ +// simplistic pthread emulation layer + +#include + +// _beginthreadex requires __stdcall +#define THREADFN unsigned int __stdcall +#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) + +static int pthread_create(pthread_t* const thread, const void* attr, + unsigned int (__stdcall *start)(void*), void* arg) { + (void)attr; + *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ + 0, /* unsigned stack_size */ + start, + arg, + 0, /* unsigned initflag */ + NULL); /* unsigned *thrdaddr */ + if (*thread == NULL) return 1; + SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); + return 0; +} + +static int pthread_join(pthread_t thread, void** value_ptr) { + (void)value_ptr; + return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || + CloseHandle(thread) == 0); +} + +// Mutex +static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) { + (void)mutexattr; + InitializeCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_lock(pthread_mutex_t* const mutex) { + EnterCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_unlock(pthread_mutex_t* const mutex) { + LeaveCriticalSection(mutex); + return 0; +} + +static int pthread_mutex_destroy(pthread_mutex_t* const mutex) { + DeleteCriticalSection(mutex); + return 0; +} + +// Condition +static int pthread_cond_destroy(pthread_cond_t* const condition) { + int ok = 1; + ok &= (CloseHandle(condition->waiting_sem_) != 0); + ok &= (CloseHandle(condition->received_sem_) != 0); + ok &= (CloseHandle(condition->signal_event_) != 0); + return !ok; +} + +static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { + (void)cond_attr; + condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); + condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + if (condition->waiting_sem_ == NULL || + condition->received_sem_ == NULL || + condition->signal_event_ == NULL) { + pthread_cond_destroy(condition); + return 1; + } + return 0; +} + +static int pthread_cond_signal(pthread_cond_t* const condition) { + int ok = 1; + if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { + // a thread is waiting in pthread_cond_wait: allow it to be notified + ok = SetEvent(condition->signal_event_); + // wait until the event is consumed so the signaler cannot consume + // the event via its own pthread_cond_wait. + ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != + WAIT_OBJECT_0); + } + return !ok; +} + +static int pthread_cond_wait(pthread_cond_t* const condition, + pthread_mutex_t* const mutex) { + int ok; + // note that there is a consumer available so the signal isn't dropped in + // pthread_cond_signal + if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) + return 1; + // now unlock the mutex so pthread_cond_signal may be issued + pthread_mutex_unlock(mutex); + ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == + WAIT_OBJECT_0); + ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); + pthread_mutex_lock(mutex); + return !ok; +} + +#else // _WIN32 +# define THREADFN void* +# define THREAD_RETURN(val) val +#endif + +//------------------------------------------------------------------------------ + +static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop + WebPWorker* const worker = (WebPWorker*)ptr; + int done = 0; + while (!done) { + pthread_mutex_lock(&worker->mutex_); + while (worker->status_ == OK) { // wait in idling mode + pthread_cond_wait(&worker->condition_, &worker->mutex_); + } + if (worker->status_ == WORK) { + if (worker->hook) { + worker->had_error |= !worker->hook(worker->data1, worker->data2); + } + worker->status_ = OK; + } else if (worker->status_ == NOT_OK) { // finish the worker + done = 1; + } + // signal to the main thread that we're done (for Sync()) + pthread_cond_signal(&worker->condition_); + pthread_mutex_unlock(&worker->mutex_); + } + return THREAD_RETURN(NULL); // Thread is finished +} + +// main thread state control +static void WebPWorkerChangeState(WebPWorker* const worker, + WebPWorkerStatus new_status) { + // no-op when attempting to change state on a thread that didn't come up + if (worker->status_ < OK) return; + + pthread_mutex_lock(&worker->mutex_); + // wait for the worker to finish + while (worker->status_ != OK) { + pthread_cond_wait(&worker->condition_, &worker->mutex_); + } + // assign new status and release the working thread if needed + if (new_status != OK) { + worker->status_ = new_status; + pthread_cond_signal(&worker->condition_); + } + pthread_mutex_unlock(&worker->mutex_); +} + +#endif + +//------------------------------------------------------------------------------ + +void WebPWorkerInit(WebPWorker* const worker) { + memset(worker, 0, sizeof(*worker)); + worker->status_ = NOT_OK; +} + +int WebPWorkerSync(WebPWorker* const worker) { +#ifdef WEBP_USE_THREAD + WebPWorkerChangeState(worker, OK); +#endif + assert(worker->status_ <= OK); + return !worker->had_error; +} + +int WebPWorkerReset(WebPWorker* const worker) { + int ok = 1; + worker->had_error = 0; + if (worker->status_ < OK) { +#ifdef WEBP_USE_THREAD + if (pthread_mutex_init(&worker->mutex_, NULL) || + pthread_cond_init(&worker->condition_, NULL)) { + return 0; + } + pthread_mutex_lock(&worker->mutex_); + ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker); + if (ok) worker->status_ = OK; + pthread_mutex_unlock(&worker->mutex_); +#else + worker->status_ = OK; +#endif + } else if (worker->status_ > OK) { + ok = WebPWorkerSync(worker); + } + assert(!ok || (worker->status_ == OK)); + return ok; +} + +void WebPWorkerLaunch(WebPWorker* const worker) { +#ifdef WEBP_USE_THREAD + WebPWorkerChangeState(worker, WORK); +#else + if (worker->hook) + worker->had_error |= !worker->hook(worker->data1, worker->data2); +#endif +} + +void WebPWorkerEnd(WebPWorker* const worker) { + if (worker->status_ >= OK) { +#ifdef WEBP_USE_THREAD + WebPWorkerChangeState(worker, NOT_OK); + pthread_join(worker->thread_, NULL); + pthread_mutex_destroy(&worker->mutex_); + pthread_cond_destroy(&worker->condition_); +#else + worker->status_ = NOT_OK; +#endif + } + assert(worker->status_ == NOT_OK); +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/thread.h b/external/libwebp/utils/thread.h new file mode 100644 index 0000000000..3191890b76 --- /dev/null +++ b/external/libwebp/utils/thread.h @@ -0,0 +1,86 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Multi-threaded worker +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_THREAD_H_ +#define WEBP_UTILS_THREAD_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if WEBP_USE_THREAD + +#if defined(_WIN32) + +#include +typedef HANDLE pthread_t; +typedef CRITICAL_SECTION pthread_mutex_t; +typedef struct { + HANDLE waiting_sem_; + HANDLE received_sem_; + HANDLE signal_event_; +} pthread_cond_t; + +#else + +#include + +#endif /* _WIN32 */ +#endif /* WEBP_USE_THREAD */ + +// State of the worker thread object +typedef enum { + NOT_OK = 0, // object is unusable + OK, // ready to work + WORK // busy finishing the current task +} WebPWorkerStatus; + +// Function to be called by the worker thread. Takes two opaque pointers as +// arguments (data1 and data2), and should return false in case of error. +typedef int (*WebPWorkerHook)(void*, void*); + +// Synchronize object used to launch job in the worker thread +typedef struct { +#if WEBP_USE_THREAD + pthread_mutex_t mutex_; + pthread_cond_t condition_; + pthread_t thread_; +#endif + WebPWorkerStatus status_; + WebPWorkerHook hook; // hook to call + void* data1; // first argument passed to 'hook' + void* data2; // second argument passed to 'hook' + int had_error; // return value of the last call to 'hook' +} WebPWorker; + +// Must be called first, before any other method. +void WebPWorkerInit(WebPWorker* const worker); +// Must be called initialize the object and spawn the thread. Re-entrant. +// Will potentially launch the thread. Returns false in case of error. +int WebPWorkerReset(WebPWorker* const worker); +// Make sure the previous work is finished. Returns true if worker->had_error +// was not set and not error condition was triggered by the working thread. +int WebPWorkerSync(WebPWorker* const worker); +// Trigger the thread to call hook() with data1 and data2 argument. These +// hook/data1/data2 can be changed at any time before calling this function, +// but not be changed afterward until the next call to WebPWorkerSync(). +void WebPWorkerLaunch(WebPWorker* const worker); +// Kill the thread and terminate the object. To use the object again, one +// must call WebPWorkerReset() again. +void WebPWorkerEnd(WebPWorker* const worker); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_THREAD_H_ */ diff --git a/external/libwebp/utils/utils.c b/external/libwebp/utils/utils.c new file mode 100644 index 0000000000..673b7e284c --- /dev/null +++ b/external/libwebp/utils/utils.c @@ -0,0 +1,44 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Misc. common utility functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include "./utils.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Checked memory allocation + +static int CheckSizeArguments(uint64_t nmemb, size_t size) { + const uint64_t total_size = nmemb * size; + if (nmemb == 0) return 1; + if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0; + if (total_size != (size_t)total_size) return 0; + return 1; +} + +void* WebPSafeMalloc(uint64_t nmemb, size_t size) { + if (!CheckSizeArguments(nmemb, size)) return NULL; + return malloc((size_t)(nmemb * size)); +} + +void* WebPSafeCalloc(uint64_t nmemb, size_t size) { + if (!CheckSizeArguments(nmemb, size)) return NULL; + return calloc((size_t)nmemb, size); +} + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif diff --git a/external/libwebp/utils/utils.h b/external/libwebp/utils/utils.h new file mode 100644 index 0000000000..a034762556 --- /dev/null +++ b/external/libwebp/utils/utils.h @@ -0,0 +1,44 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Misc. common utility functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_UTILS_UTILS_H_ +#define WEBP_UTILS_UTILS_H_ + +#include "../webp/types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// Memory allocation + +// This is the maximum memory amount that libwebp will ever try to allocate. +#define WEBP_MAX_ALLOCABLE_MEMORY (1ULL << 40) + +// size-checking safe malloc/calloc: verify that the requested size is not too +// large, or return NULL. You don't need to call these for constructs like +// malloc(sizeof(foo)), but only if there's picture-dependent size involved +// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this +// safe malloc() borrows the signature from calloc(), pointing at the dangerous +// underlying multiply involved. +void* WebPSafeMalloc(uint64_t nmemb, size_t size); +// Note that WebPSafeCalloc() expects the second argument type to be 'size_t' +// in order to favor the "calloc(num_foo, sizeof(foo))" pattern. +void* WebPSafeCalloc(uint64_t nmemb, size_t size); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_UTILS_UTILS_H_ */ diff --git a/external/libwebp/webp/decode.h b/external/libwebp/webp/decode.h new file mode 100644 index 0000000000..43b6c58f4f --- /dev/null +++ b/external/libwebp/webp/decode.h @@ -0,0 +1,454 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Main decoding functions for WebP images. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_DECODE_H_ +#define WEBP_WEBP_DECODE_H_ + +#include "./types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define WEBP_DECODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b) + +// Return the decoder's version number, packed in hexadecimal using 8bits for +// each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN(int) WebPGetDecoderVersion(void); + +// Retrieve basic header information: width, height. +// This function will also validate the header and return 0 in +// case of formatting error. +// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant. +WEBP_EXTERN(int) WebPGetInfo(const uint8_t* data, size_t data_size, + int* width, int* height); + +// Decodes WebP images pointed to by 'data' and returns RGBA samples, along +// with the dimensions in *width and *height. The ordering of samples in +// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent). +// The returned pointer should be deleted calling free(). +// Returns NULL in case of error. +WEBP_EXTERN(uint8_t*) WebPDecodeRGBA(const uint8_t* data, size_t data_size, + int* width, int* height); + +// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data. +WEBP_EXTERN(uint8_t*) WebPDecodeARGB(const uint8_t* data, size_t data_size, + int* width, int* height); + +// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data. +WEBP_EXTERN(uint8_t*) WebPDecodeBGRA(const uint8_t* data, size_t data_size, + int* width, int* height); + +// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data. +// If the bitstream contains transparency, it is ignored. +WEBP_EXTERN(uint8_t*) WebPDecodeRGB(const uint8_t* data, size_t data_size, + int* width, int* height); + +// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data. +WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size, + int* width, int* height); + + +// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer +// returned is the Y samples buffer. Upon return, *u and *v will point to +// the U and V chroma data. These U and V buffers need NOT be free()'d, +// unlike the returned Y luma one. The dimension of the U and V planes +// are both (*width + 1) / 2 and (*height + 1)/ 2. +// Upon return, the Y buffer has a stride returned as '*stride', while U and V +// have a common stride returned as '*uv_stride'. +// Return NULL in case of error. +// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr +WEBP_EXTERN(uint8_t*) WebPDecodeYUV(const uint8_t* data, size_t data_size, + int* width, int* height, + uint8_t** u, uint8_t** v, + int* stride, int* uv_stride); + +// These five functions are variants of the above ones, that decode the image +// directly into a pre-allocated buffer 'output_buffer'. The maximum storage +// available in this buffer is indicated by 'output_buffer_size'. If this +// storage is not sufficient (or an error occurred), NULL is returned. +// Otherwise, output_buffer is returned, for convenience. +// The parameter 'output_stride' specifies the distance (in bytes) +// between scanlines. Hence, output_buffer_size is expected to be at least +// output_stride x picture-height. +WEBP_EXTERN(uint8_t*) WebPDecodeRGBAInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_EXTERN(uint8_t*) WebPDecodeARGBInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_EXTERN(uint8_t*) WebPDecodeBGRAInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// RGB and BGR variants. Here too the transparency information, if present, +// will be dropped and ignored. +WEBP_EXTERN(uint8_t*) WebPDecodeRGBInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); +WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto( + const uint8_t* data, size_t data_size, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly +// into pre-allocated luma/chroma plane buffers. This function requires the +// strides to be passed: one for the luma plane and one for each of the +// chroma ones. The size of each plane buffer is passed as 'luma_size', +// 'u_size' and 'v_size' respectively. +// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred +// during decoding (or because some buffers were found to be too small). +WEBP_EXTERN(uint8_t*) WebPDecodeYUVInto( + const uint8_t* data, size_t data_size, + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride); + +//------------------------------------------------------------------------------ +// Output colorspaces and buffer + +// Colorspaces +// Note: the naming describes the byte-ordering of packed samples in memory. +// For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,... +// Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels. +// RGB-565 and RGBA-4444 are also endian-agnostic and byte-oriented. +typedef enum { MODE_RGB = 0, MODE_RGBA = 1, + MODE_BGR = 2, MODE_BGRA = 3, + MODE_ARGB = 4, MODE_RGBA_4444 = 5, + MODE_RGB_565 = 6, + // RGB-premultiplied transparent modes (alpha value is preserved) + MODE_rgbA = 7, + MODE_bgrA = 8, + MODE_Argb = 9, + MODE_rgbA_4444 = 10, + // YUV modes must come after RGB ones. + MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0 + MODE_LAST = 13 + } WEBP_CSP_MODE; + +// Some useful macros: +static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) { + return (mode == MODE_rgbA || mode == MODE_bgrA || mode == MODE_Argb || + mode == MODE_rgbA_4444); +} + +static WEBP_INLINE int WebPIsAlphaMode(WEBP_CSP_MODE mode) { + return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB || + mode == MODE_RGBA_4444 || mode == MODE_YUVA || + WebPIsPremultipliedMode(mode)); +} + +static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) { + return (mode < MODE_YUV); +} + +//------------------------------------------------------------------------------ +// WebPDecBuffer: Generic structure for describing the output sample buffer. + +typedef struct { // view as RGBA + uint8_t* rgba; // pointer to RGBA samples + int stride; // stride in bytes from one scanline to the next. + size_t size; // total size of the *rgba buffer. +} WebPRGBABuffer; + +typedef struct { // view as YUVA + uint8_t* y, *u, *v, *a; // pointer to luma, chroma U/V, alpha samples + int y_stride; // luma stride + int u_stride, v_stride; // chroma strides + int a_stride; // alpha stride + size_t y_size; // luma plane size + size_t u_size, v_size; // chroma planes size + size_t a_size; // alpha-plane size +} WebPYUVABuffer; + +// Output buffer +typedef struct { + WEBP_CSP_MODE colorspace; // Colorspace. + int width, height; // Dimensions. + int is_external_memory; // If true, 'internal_memory' pointer is not used. + union { + WebPRGBABuffer RGBA; + WebPYUVABuffer YUVA; + } u; // Nameless union of buffer parameters. + uint32_t pad[4]; // padding for later use + + uint8_t* private_memory; // Internally allocated memory (only when + // is_external_memory is false). Should not be used + // externally, but accessed via the buffer union. +} WebPDecBuffer; + +// Internal, version-checked, entry point +WEBP_EXTERN(int) WebPInitDecBufferInternal(WebPDecBuffer*, int); + +// Initialize the structure as empty. Must be called before any other use. +// Returns false in case of version mismatch +static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) { + return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION); +} + +// Free any memory associated with the buffer. Must always be called last. +// Note: doesn't free the 'buffer' structure itself. +WEBP_EXTERN(void) WebPFreeDecBuffer(WebPDecBuffer* buffer); + +//------------------------------------------------------------------------------ +// Enumeration of the status codes + +typedef enum { + VP8_STATUS_OK = 0, + VP8_STATUS_OUT_OF_MEMORY, + VP8_STATUS_INVALID_PARAM, + VP8_STATUS_BITSTREAM_ERROR, + VP8_STATUS_UNSUPPORTED_FEATURE, + VP8_STATUS_SUSPENDED, + VP8_STATUS_USER_ABORT, + VP8_STATUS_NOT_ENOUGH_DATA +} VP8StatusCode; + +//------------------------------------------------------------------------------ +// Incremental decoding +// +// This API allows streamlined decoding of partial data. +// Picture can be incrementally decoded as data become available thanks to the +// WebPIDecoder object. This object can be left in a SUSPENDED state if the +// picture is only partially decoded, pending additional input. +// Code example: +// +// WebPInitDecBuffer(&buffer); +// buffer.colorspace = mode; +// ... +// WebPIDecoder* idec = WebPINewDecoder(&buffer); +// while (has_more_data) { +// // ... (get additional data) +// status = WebPIAppend(idec, new_data, new_data_size); +// if (status != VP8_STATUS_SUSPENDED || +// break; +// } +// +// // The above call decodes the current available buffer. +// // Part of the image can now be refreshed by calling to +// // WebPIDecGetRGB()/WebPIDecGetYUVA() etc. +// } +// WebPIDelete(idec); + +typedef struct WebPIDecoder WebPIDecoder; + +// Creates a new incremental decoder with the supplied buffer parameter. +// This output_buffer can be passed NULL, in which case a default output buffer +// is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer' +// is kept, which means that the lifespan of 'output_buffer' must be larger than +// that of the returned WebPIDecoder object. +// Returns NULL if the allocation failed. +WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer); + +// This function allocates and initializes an incremental-decoder object, which +// will output the RGB/A samples specified by 'csp' into a preallocated +// buffer 'output_buffer'. The size of this buffer is at least +// 'output_buffer_size' and the stride (distance in bytes between two scanlines) +// is specified by 'output_stride'. Returns NULL if the allocation failed. +WEBP_EXTERN(WebPIDecoder*) WebPINewRGB( + WEBP_CSP_MODE csp, + uint8_t* output_buffer, size_t output_buffer_size, int output_stride); + +// This function allocates and initializes an incremental-decoder object, which +// will output the raw luma/chroma samples into a preallocated planes. The luma +// plane is specified by its pointer 'luma', its size 'luma_size' and its stride +// 'luma_stride'. Similarly, the chroma-u plane is specified by the 'u', +// 'u_size' and 'u_stride' parameters, and the chroma-v plane by 'v' +// and 'v_size'. And same for the alpha-plane. The 'a' pointer can be pass +// NULL in case one is not interested in the transparency plane. +// Returns NULL if the allocation failed. +WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA( + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride, + uint8_t* a, size_t a_size, int a_stride); + +// Deprecated version of the above, without the alpha plane. +// Kept for backward compatibility. +WEBP_EXTERN(WebPIDecoder*) WebPINewYUV( + uint8_t* luma, size_t luma_size, int luma_stride, + uint8_t* u, size_t u_size, int u_stride, + uint8_t* v, size_t v_size, int v_stride); + +// Deletes the WebPIDecoder object and associated memory. Must always be called +// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded. +WEBP_EXTERN(void) WebPIDelete(WebPIDecoder* idec); + +// Copies and decodes the next available data. Returns VP8_STATUS_OK when +// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more +// data is expected. Returns error in other cases. +WEBP_EXTERN(VP8StatusCode) WebPIAppend( + WebPIDecoder* idec, const uint8_t* data, size_t data_size); + +// A variant of the above function to be used when data buffer contains +// partial data from the beginning. In this case data buffer is not copied +// to the internal memory. +// Note that the value of the 'data' pointer can change between calls to +// WebPIUpdate, for instance when the data buffer is resized to fit larger data. +WEBP_EXTERN(VP8StatusCode) WebPIUpdate( + WebPIDecoder* idec, const uint8_t* data, size_t data_size); + +// Returns the RGB/A image decoded so far. Returns NULL if output params +// are not initialized yet. The RGB/A output type corresponds to the colorspace +// specified during call to WebPINewDecoder() or WebPINewRGB(). +// *last_y is the index of last decoded row in raster scan order. Some pointers +// (*last_y, *width etc.) can be NULL if corresponding information is not +// needed. +WEBP_EXTERN(uint8_t*) WebPIDecGetRGB( + const WebPIDecoder* idec, int* last_y, + int* width, int* height, int* stride); + +// Same as above function to get a YUVA image. Returns pointer to the luma +// plane or NULL in case of error. If there is no alpha information +// the alpha pointer '*a' will be returned NULL. +WEBP_EXTERN(uint8_t*) WebPIDecGetYUVA( + const WebPIDecoder* idec, int* last_y, + uint8_t** u, uint8_t** v, uint8_t** a, + int* width, int* height, int* stride, int* uv_stride, int* a_stride); + +// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the +// alpha information (if present). Kept for backward compatibility. +static WEBP_INLINE uint8_t* WebPIDecGetYUV( + const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v, + int* width, int* height, int* stride, int* uv_stride) { + return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height, + stride, uv_stride, NULL); +} + +// Generic call to retrieve information about the displayable area. +// If non NULL, the left/right/width/height pointers are filled with the visible +// rectangular area so far. +// Returns NULL in case the incremental decoder object is in an invalid state. +// Otherwise returns the pointer to the internal representation. This structure +// is read-only, tied to WebPIDecoder's lifespan and should not be modified. +WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea( + const WebPIDecoder* idec, int* left, int* top, int* width, int* height); + +//------------------------------------------------------------------------------ +// Advanced decoding parametrization +// +// Code sample for using the advanced decoding API +/* + // A) Init a configuration object + WebPDecoderConfig config; + CHECK(WebPInitDecoderConfig(&config)); + + // B) optional: retrieve the bitstream's features. + CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK); + + // C) Adjust 'config', if needed + config.no_fancy = 1; + config.output.colorspace = MODE_BGRA; + // etc. + + // Note that you can also make config.output point to an externally + // supplied memory buffer, provided it's big enough to store the decoded + // picture. Otherwise, config.output will just be used to allocate memory + // and store the decoded picture. + + // D) Decode! + CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK); + + // E) Decoded image is now in config.output (and config.output.u.RGBA) + + // F) Reclaim memory allocated in config's object. It's safe to call + // this function even if the memory is external and wasn't allocated + // by WebPDecode(). + WebPFreeDecBuffer(&config.output); +*/ + +// Features gathered from the bitstream +typedef struct { + int width; // Width in pixels, as read from the bitstream. + int height; // Height in pixels, as read from the bitstream. + int has_alpha; // True if the bitstream contains an alpha channel. + + // Unused for now: + int bitstream_version; // should be 0 for now. TODO(later) + int no_incremental_decoding; // if true, using incremental decoding is not + // recommended. + int rotate; // TODO(later) + int uv_sampling; // should be 0 for now. TODO(later) + uint32_t pad[3]; // padding for later use +} WebPBitstreamFeatures; + +// Internal, version-checked, entry point +WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal( + const uint8_t*, size_t, WebPBitstreamFeatures*, int); + +// Retrieve features from the bitstream. The *features structure is filled +// with information gathered from the bitstream. +// Returns false in case of error or version mismatch. +// In case of error, features->bitstream_status will reflect the error code. +static WEBP_INLINE VP8StatusCode WebPGetFeatures( + const uint8_t* data, size_t data_size, + WebPBitstreamFeatures* features) { + return WebPGetFeaturesInternal(data, data_size, features, + WEBP_DECODER_ABI_VERSION); +} + +// Decoding options +typedef struct { + int bypass_filtering; // if true, skip the in-loop filtering + int no_fancy_upsampling; // if true, use faster pointwise upsampler + int use_cropping; // if true, cropping is applied _first_ + int crop_left, crop_top; // top-left position for cropping. + // Will be snapped to even values. + int crop_width, crop_height; // dimension of the cropping area + int use_scaling; // if true, scaling is applied _afterward_ + int scaled_width, scaled_height; // final resolution + int use_threads; // if true, use multi-threaded decoding + + // Unused for now: + int force_rotation; // forced rotation (to be applied _last_) + int no_enhancement; // if true, discard enhancement layer + uint32_t pad[6]; // padding for later use +} WebPDecoderOptions; + +// Main object storing the configuration for advanced decoding. +typedef struct { + WebPBitstreamFeatures input; // Immutable bitstream features (optional) + WebPDecBuffer output; // Output buffer (can point to external mem) + WebPDecoderOptions options; // Decoding options +} WebPDecoderConfig; + +// Internal, version-checked, entry point +WEBP_EXTERN(int) WebPInitDecoderConfigInternal(WebPDecoderConfig*, int); + +// Initialize the configuration as empty. This function must always be +// called first, unless WebPGetFeatures() is to be called. +// Returns false in case of mismatched version. +static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) { + return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); +} + +// Instantiate a new incremental decoder object with the requested +// configuration. The bitstream can be passed using 'data' and 'data_size' +// parameter, in which case the features will be parsed and stored into +// config->input. Otherwise, 'data' can be NULL and no parsing will occur. +// Note that 'config' can be NULL too, in which case a default configuration +// is used. +// The return WebPIDecoder object must always be deleted calling WebPIDelete(). +// Returns NULL in case of error (and config->status will then reflect +// the error condition). +WEBP_EXTERN(WebPIDecoder*) WebPIDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config); + +// Non-incremental version. This version decodes the full data at once, taking +// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK +// if the decoding was successful). +WEBP_EXTERN(VP8StatusCode) WebPDecode(const uint8_t* data, size_t data_size, + WebPDecoderConfig* config); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_WEBP_DECODE_H_ */ diff --git a/external/libwebp/webp/encode.h b/external/libwebp/webp/encode.h new file mode 100644 index 0000000000..2e37cfabe7 --- /dev/null +++ b/external/libwebp/webp/encode.h @@ -0,0 +1,463 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// WebP encoder: main interface +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_ENCODE_H_ +#define WEBP_WEBP_ENCODE_H_ + +#include "./types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define WEBP_ENCODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b) + +// Return the encoder's version number, packed in hexadecimal using 8bits for +// each of major/minor/revision. E.g: v2.5.7 is 0x020507. +WEBP_EXTERN(int) WebPGetEncoderVersion(void); + +//------------------------------------------------------------------------------ +// One-stop-shop call! No questions asked: + +// Returns the size of the compressed data (pointed to by *output), or 0 if +// an error occurred. The compressed data must be released by the caller +// using the call 'free(*output)'. +// These functions compress using the lossy format, and the quality_factor +// can go from 0 (smaller output, lower quality) to 100 (best quality, +// larger output). +WEBP_EXTERN(size_t) WebPEncodeRGB(const uint8_t* rgb, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeBGR(const uint8_t* bgr, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeRGBA(const uint8_t* rgba, + int width, int height, int stride, + float quality_factor, uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeBGRA(const uint8_t* bgra, + int width, int height, int stride, + float quality_factor, uint8_t** output); + +// These functions are the equivalent of the above, but compressing in a +// lossless manner. Files are usually larger than lossy format, but will +// not suffer any compression loss. +WEBP_EXTERN(size_t) WebPEncodeLosslessRGB(const uint8_t* rgb, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeLosslessBGR(const uint8_t* bgr, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeLosslessRGBA(const uint8_t* rgba, + int width, int height, int stride, + uint8_t** output); +WEBP_EXTERN(size_t) WebPEncodeLosslessBGRA(const uint8_t* bgra, + int width, int height, int stride, + uint8_t** output); + +//------------------------------------------------------------------------------ +// Coding parameters + +// Image characteristics hint for the underlying encoder. +typedef enum { + WEBP_HINT_DEFAULT = 0, // default preset. + WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot + WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting + WEBP_HINT_GRAPH, // Discrete tone image (graph, map-tile etc). + WEBP_HINT_LAST +} WebPImageHint; + +typedef struct { + int lossless; // Lossless encoding (0=lossy(default), 1=lossless). + float quality; // between 0 (smallest file) and 100 (biggest) + int method; // quality/speed trade-off (0=fast, 6=slower-better) + + WebPImageHint image_hint; // Hint for image type (lossless only for now). + + // Parameters related to lossy compression only: + int target_size; // if non-zero, set the desired target size in bytes. + // Takes precedence over the 'compression' parameter. + float target_PSNR; // if non-zero, specifies the minimal distortion to + // try to achieve. Takes precedence over target_size. + int segments; // maximum number of segments to use, in [1..4] + int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum. + int filter_strength; // range: [0 = off .. 100 = strongest] + int filter_sharpness; // range: [0 = off .. 7 = least sharp] + int filter_type; // filtering type: 0 = simple, 1 = strong (only used + // if filter_strength > 0 or autofilter > 0) + int autofilter; // Auto adjust filter's strength [0 = off, 1 = on] + int alpha_compression; // Algorithm for encoding the alpha plane (0 = none, + // 1 = compressed with WebP lossless). Default is 1. + int alpha_filtering; // Predictive filtering method for alpha plane. + // 0: none, 1: fast, 2: best. Default if 1. + int alpha_quality; // Between 0 (smallest size) and 100 (lossless). + // Default is 100. + int pass; // number of entropy-analysis passes (in [1..10]). + + int show_compressed; // if true, export the compressed picture back. + // In-loop filtering is not applied. + int preprocessing; // preprocessing filter (0=none, 1=segment-smooth) + int partitions; // log2(number of token partitions) in [0..3]. Default + // is set to 0 for easier progressive decoding. + int partition_limit; // quality degradation allowed to fit the 512k limit + // on prediction modes coding (0: no degradation, + // 100: maximum possible degradation). + + uint32_t pad[8]; // padding for later use +} WebPConfig; + +// Enumerate some predefined settings for WebPConfig, depending on the type +// of source picture. These presets are used when calling WebPConfigPreset(). +typedef enum { + WEBP_PRESET_DEFAULT = 0, // default preset. + WEBP_PRESET_PICTURE, // digital picture, like portrait, inner shot + WEBP_PRESET_PHOTO, // outdoor photograph, with natural lighting + WEBP_PRESET_DRAWING, // hand or line drawing, with high-contrast details + WEBP_PRESET_ICON, // small-sized colorful images + WEBP_PRESET_TEXT // text-like +} WebPPreset; + +// Internal, version-checked, entry point +WEBP_EXTERN(int) WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int); + +// Should always be called, to initialize a fresh WebPConfig structure before +// modification. Returns false in case of version mismatch. WebPConfigInit() +// must have succeeded before using the 'config' object. +// Note that the default values are lossless=0 and quality=75. +static WEBP_INLINE int WebPConfigInit(WebPConfig* config) { + return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f, + WEBP_ENCODER_ABI_VERSION); +} + +// This function will initialize the configuration according to a predefined +// set of parameters (referred to by 'preset') and a given quality factor. +// This function can be called as a replacement to WebPConfigInit(). Will +// return false in case of error. +static WEBP_INLINE int WebPConfigPreset(WebPConfig* config, + WebPPreset preset, float quality) { + return WebPConfigInitInternal(config, preset, quality, + WEBP_ENCODER_ABI_VERSION); +} + +// Returns true if 'config' is non-NULL and all configuration parameters are +// within their valid ranges. +WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* config); + +//------------------------------------------------------------------------------ +// Input / Output + +typedef struct WebPPicture WebPPicture; // main structure for I/O + +// Structure for storing auxiliary statistics (mostly for lossy encoding). +typedef struct { + int coded_size; // final size + + float PSNR[5]; // peak-signal-to-noise ratio for Y/U/V/All/Alpha + int block_count[3]; // number of intra4/intra16/skipped macroblocks + int header_bytes[2]; // approximate number of bytes spent for header + // and mode-partition #0 + int residual_bytes[3][4]; // approximate number of bytes spent for + // DC/AC/uv coefficients for each (0..3) segments. + int segment_size[4]; // number of macroblocks in each segments + int segment_quant[4]; // quantizer values for each segments + int segment_level[4]; // filtering strength for each segments [0..63] + + int alpha_data_size; // size of the transparency data + int layer_data_size; // size of the enhancement layer data + + // lossless encoder statistics + uint32_t lossless_features; // bit0:predictor bit1:cross-color transform + // bit2:subtract-green bit3:color indexing + int histogram_bits; // number of precision bits of histogram + int transform_bits; // precision bits for transform + int cache_bits; // number of bits for color cache lookup + int palette_size; // number of color in palette, if used + int lossless_size; // final lossless size + + uint32_t pad[4]; // padding for later use +} WebPAuxStats; + +// Signature for output function. Should return true if writing was successful. +// data/data_size is the segment of data to write, and 'picture' is for +// reference (and so one can make use of picture->custom_ptr). +typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size, + const WebPPicture* picture); + +// WebPMemoryWrite: a special WebPWriterFunction that writes to memory using +// the following WebPMemoryWriter object (to be set as a custom_ptr). +typedef struct { + uint8_t* mem; // final buffer (of size 'max_size', larger than 'size'). + size_t size; // final size + size_t max_size; // total capacity + uint32_t pad[1]; // padding for later use +} WebPMemoryWriter; + +// The following must be called first before any use. +WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer); + +// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon +// completion, writer.mem and writer.size will hold the coded data. +WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size, + const WebPPicture* picture); + +// Progress hook, called from time to time to report progress. It can return +// false to request an abort of the encoding process, or true otherwise if +// everything is OK. +typedef int (*WebPProgressHook)(int percent, const WebPPicture* picture); + +typedef enum { + // chroma sampling + WEBP_YUV420 = 0, // 4:2:0 + WEBP_YUV422 = 1, // 4:2:2 + WEBP_YUV444 = 2, // 4:4:4 + WEBP_YUV400 = 3, // grayscale + WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors + // alpha channel variants + WEBP_YUV420A = 4, + WEBP_YUV422A = 5, + WEBP_YUV444A = 6, + WEBP_YUV400A = 7, // grayscale + alpha + WEBP_CSP_ALPHA_BIT = 4 // bit that is set if alpha is present +} WebPEncCSP; + +// Encoding error conditions. +typedef enum { + VP8_ENC_OK = 0, + VP8_ENC_ERROR_OUT_OF_MEMORY, // memory error allocating objects + VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, // memory error while flushing bits + VP8_ENC_ERROR_NULL_PARAMETER, // a pointer parameter is NULL + VP8_ENC_ERROR_INVALID_CONFIGURATION, // configuration is invalid + VP8_ENC_ERROR_BAD_DIMENSION, // picture has invalid width/height + VP8_ENC_ERROR_PARTITION0_OVERFLOW, // partition is bigger than 512k + VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M + VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes + VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G + VP8_ENC_ERROR_USER_ABORT, // abort request by user + VP8_ENC_ERROR_LAST // list terminator. always last. +} WebPEncodingError; + +// maximum width/height allowed (inclusive), in pixels +#define WEBP_MAX_DIMENSION 16383 + +// Main exchange structure (input samples, output bytes, statistics) +struct WebPPicture { + + // INPUT + ////////////// + // Main flag for encoder selecting between ARGB or YUV input. + // It is recommended to use ARGB input (*argb, argb_stride) for lossless + // compression, and YUV input (*y, *u, *v, etc.) for lossy compression + // since these are the respective native colorspace for these formats. + int use_argb; + + // YUV input (mostly used for input to lossy compression) + WebPEncCSP colorspace; // colorspace: should be YUV420 for now (=Y'CbCr). + int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION) + uint8_t *y, *u, *v; // pointers to luma/chroma planes. + int y_stride, uv_stride; // luma/chroma strides. + uint8_t* a; // pointer to the alpha plane + int a_stride; // stride of the alpha plane + uint32_t pad1[2]; // padding for later use + + // ARGB input (mostly used for input to lossless compression) + uint32_t* argb; // Pointer to argb (32 bit) plane. + int argb_stride; // This is stride in pixels units, not bytes. + uint32_t pad2[3]; // padding for later use + + // OUTPUT + /////////////// + // Byte-emission hook, to store compressed bytes as they are ready. + WebPWriterFunction writer; // can be NULL + void* custom_ptr; // can be used by the writer. + + // map for extra information (only for lossy compression mode) + int extra_info_type; // 1: intra type, 2: segment, 3: quant + // 4: intra-16 prediction mode, + // 5: chroma prediction mode, + // 6: bit cost, 7: distortion + uint8_t* extra_info; // if not NULL, points to an array of size + // ((width + 15) / 16) * ((height + 15) / 16) that + // will be filled with a macroblock map, depending + // on extra_info_type. + + // STATS AND REPORTS + /////////////////////////// + // Pointer to side statistics (updated only if not NULL) + WebPAuxStats* stats; + + // Error code for the latest error encountered during encoding + WebPEncodingError error_code; + + // If not NULL, report progress during encoding. + WebPProgressHook progress_hook; + + void* user_data; // this field is free to be set to any value and + // used during callbacks (like progress-report e.g.). + + uint32_t pad3[3]; // padding for later use + + // Unused for now: original samples (for non-YUV420 modes) + uint8_t *u0, *v0; + int uv0_stride; + + uint32_t pad4[7]; // padding for later use + + // PRIVATE FIELDS + //////////////////// + void* memory_; // row chunk of memory for yuva planes + void* memory_argb_; // and for argb too. + void* pad5[2]; // padding for later use +}; + +// Internal, version-checked, entry point +WEBP_EXTERN(int) WebPPictureInitInternal(WebPPicture*, int); + +// Should always be called, to initialize the structure. Returns false in case +// of version mismatch. WebPPictureInit() must have succeeded before using the +// 'picture' object. +// Note that, by default, use_argb is false and colorspace is WEBP_YUV420. +static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) { + return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION); +} + +//------------------------------------------------------------------------------ +// WebPPicture utils + +// Convenience allocation / deallocation based on picture->width/height: +// Allocate y/u/v buffers as per colorspace/width/height specification. +// Note! This function will free the previous buffer if needed. +// Returns false in case of memory error. +WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* picture); + +// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*(). +// Note that this function does _not_ free the memory used by the 'picture' +// object itself. +// Besides memory (which is reclaimed) all other fields of 'picture' are +// preserved. +WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture); + +// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, +// *dst will fully own the copied pixels (this is not a view). +// Returns false in case of memory allocation error. +WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst); + +// Compute PSNR or SSIM distortion between two pictures. +// Result is in dB, stores in result[] in the Y/U/V/Alpha/All order. +// Returns false in case of error (pic1 and pic2 don't have same dimension, ...) +// Warning: this function is rather CPU-intensive. +WEBP_EXTERN(int) WebPPictureDistortion( + const WebPPicture* pic1, const WebPPicture* pic2, + int metric_type, // 0 = PSNR, 1 = SSIM + float result[5]); + +// self-crops a picture to the rectangle defined by top/left/width/height. +// Returns false in case of memory allocation error, or if the rectangle is +// outside of the source picture. +// The rectangle for the view is defined by the top-left corner pixel +// coordinates (left, top) as well as its width and height. This rectangle +// must be fully be comprised inside the 'src' source picture. If the source +// picture uses the YUV420 colorspace, the top and left coordinates will be +// snapped to even values. +WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture, + int left, int top, int width, int height); + +// Extracts a view from 'src' picture into 'dst'. The rectangle for the view +// is defined by the top-left corner pixel coordinates (left, top) as well +// as its width and height. This rectangle must be fully be comprised inside +// the 'src' source picture. If the source picture uses the YUV420 colorspace, +// the top and left coordinates will be snapped to even values. +// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed +// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so, +// the original dimension will be lost). +// Returns false in case of memory allocation error or invalid parameters. +WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src, + int left, int top, int width, int height, + WebPPicture* dst); + +// Returns true if the 'picture' is actually a view and therefore does +// not own the memory for pixels. +WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* picture); + +// Rescale a picture to new dimension width x height. +// Now gamma correction is applied. +// Returns false in case of error (invalid parameter or insufficient memory). +WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* pic, int width, int height); + +// Colorspace conversion function to import RGB samples. +// Previous buffer will be free'd, if any. +// *rgb buffer should have a size of at least height * rgb_stride. +// Returns false in case of memory error. +WEBP_EXTERN(int) WebPPictureImportRGB( + WebPPicture* picture, const uint8_t* rgb, int rgb_stride); +// Same, but for RGBA buffer. +WEBP_EXTERN(int) WebPPictureImportRGBA( + WebPPicture* picture, const uint8_t* rgba, int rgba_stride); +// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format +// input buffer ignoring the alpha channel. Avoids needing to copy the data +// to a temporary 24-bit RGB buffer to import the RGB only. +WEBP_EXTERN(int) WebPPictureImportRGBX( + WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride); + +// Variants of the above, but taking BGR(A|X) input. +WEBP_EXTERN(int) WebPPictureImportBGR( + WebPPicture* picture, const uint8_t* bgr, int bgr_stride); +WEBP_EXTERN(int) WebPPictureImportBGRA( + WebPPicture* picture, const uint8_t* bgra, int bgra_stride); +WEBP_EXTERN(int) WebPPictureImportBGRX( + WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride); + +// Converts picture->argb data to the YUVA format specified by 'colorspace'. +// Upon return, picture->use_argb is set to false. The presence of real +// non-opaque transparent values is detected, and 'colorspace' will be +// adjusted accordingly. Note that this method is lossy. +// Returns false in case of error. +WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture, + WebPEncCSP colorspace); + +// Converts picture->yuv to picture->argb and sets picture->use_argb to true. +// The input format must be YUV_420 or YUV_420A. +// Note that the use of this method is discouraged if one has access to the +// raw ARGB samples, since using YUV420 is comparatively lossy. Also, the +// conversion from YUV420 to ARGB incurs a small loss too. +// Returns false in case of error. +WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture); + +// Helper function: given a width x height plane of YUV(A) samples +// (with stride 'stride'), clean-up the YUV samples under fully transparent +// area, to help compressibility (no guarantee, though). +WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture); + +// Scan the picture 'picture' for the presence of non fully opaque alpha values. +// Returns true in such case. Otherwise returns false (indicating that the +// alpha plane can be ignored altogether e.g.). +WEBP_EXTERN(int) WebPPictureHasTransparency(const WebPPicture* picture); + +//------------------------------------------------------------------------------ +// Main call + +// Main encoding call, after config and picture have been initialized. +// 'picture' must be less than 16384x16384 in dimension (cf WEBP_MAX_DIMENSION), +// and the 'config' object must be a valid one. +// Returns false in case of error, true otherwise. +// In case of error, picture->error_code is updated accordingly. +// 'picture' can hold the source samples in both YUV(A) or ARGB input, depending +// on the value of 'picture->use_argb'. It is highly recommended to use +// the former for lossy encoding, and the latter for lossless encoding +// (when config.lossless is true). Automatic conversion from one format to +// another is provided but they both incur some loss. +WEBP_EXTERN(int) WebPEncode(const WebPConfig* config, WebPPicture* picture); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_WEBP_ENCODE_H_ */ diff --git a/external/libwebp/webp/format_constants.h b/external/libwebp/webp/format_constants.h new file mode 100644 index 0000000000..7ce498f672 --- /dev/null +++ b/external/libwebp/webp/format_constants.h @@ -0,0 +1,90 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Internal header for constants related to WebP file format. +// +// Author: Urvang (urvang@google.com) + +#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_ +#define WEBP_WEBP_FORMAT_CONSTANTS_H_ + +// VP8 related constants. +#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data. +#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition +#define VP8_MAX_PARTITION_SIZE (1 << 24) // max size for token partition +#define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data. + +// VP8L related constants. +#define VP8L_SIGNATURE_SIZE 1 // VP8L signature size. +#define VP8L_MAGIC_BYTE 0x2f // VP8L signature byte. +#define VP8L_IMAGE_SIZE_BITS 14 // Number of bits used to store + // width and height. +#define VP8L_VERSION_BITS 3 // 3 bits reserved for version. +#define VP8L_VERSION 0 // version 0 +#define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header. + +#define MAX_PALETTE_SIZE 256 +#define MAX_CACHE_BITS 11 +#define HUFFMAN_CODES_PER_META_CODE 5 +#define ARGB_BLACK 0xff000000 + +#define DEFAULT_CODE_LENGTH 8 +#define MAX_ALLOWED_CODE_LENGTH 15 + +#define NUM_LITERAL_CODES 256 +#define NUM_LENGTH_CODES 24 +#define NUM_DISTANCE_CODES 40 +#define CODE_LENGTH_CODES 19 + +#define MIN_HUFFMAN_BITS 2 // min number of Huffman bits +#define MAX_HUFFMAN_BITS 9 // max number of Huffman bits + +#define TRANSFORM_PRESENT 1 // The bit to be written when next data + // to be read is a transform. +#define NUM_TRANSFORMS 4 // Maximum number of allowed transform + // in a bitstream. +typedef enum { + PREDICTOR_TRANSFORM = 0, + CROSS_COLOR_TRANSFORM = 1, + SUBTRACT_GREEN = 2, + COLOR_INDEXING_TRANSFORM = 3 +} VP8LImageTransformType; + +// Alpha related constants. +#define ALPHA_HEADER_LEN 1 +#define ALPHA_NO_COMPRESSION 0 +#define ALPHA_LOSSLESS_COMPRESSION 1 +#define ALPHA_PREPROCESSED_LEVELS 1 + +// Mux related constants. +#define TAG_SIZE 4 // Size of a chunk tag (e.g. "VP8L"). +#define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size. +#define CHUNK_HEADER_SIZE 8 // Size of a chunk header. +#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP"). +#define FRAME_CHUNK_SIZE 15 // Size of a FRM chunk. +#define LOOP_CHUNK_SIZE 2 // Size of a LOOP chunk. +#define TILE_CHUNK_SIZE 6 // Size of a TILE chunk. +#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. + +#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used. +#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected +#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not. +#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present. +#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h +#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry + +#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. +#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. +#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count +#define MAX_DURATION (1 << 24) // maximum duration +#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/tile x/y offset + +// Maximum chunk payload is such that adding the header and padding won't +// overflow a uint32_t. +#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1) + +#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */ diff --git a/external/libwebp/webp/mux.h b/external/libwebp/webp/mux.h new file mode 100644 index 0000000000..5139af80fa --- /dev/null +++ b/external/libwebp/webp/mux.h @@ -0,0 +1,604 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// RIFF container manipulation for WEBP images. +// +// Authors: Urvang (urvang@google.com) +// Vikas (vikasa@google.com) + +// This API allows manipulation of WebP container images containing features +// like Color profile, XMP metadata, Animation and Tiling. +// +// Code Example#1: Creating a MUX with image data, color profile and XMP +// metadata. +// +// int copy_data = 0; +// WebPMux* mux = WebPMuxNew(); +// // ... (Prepare image data). +// WebPMuxSetImage(mux, &image, copy_data); +// // ... (Prepare ICCP color profile data). +// WebPMuxSetColorProfile(mux, &icc_profile, copy_data); +// // ... (Prepare XMP metadata). +// WebPMuxSetMetadata(mux, &xmp, copy_data); +// // Get data from mux in WebP RIFF format. +// WebPMuxAssemble(mux, &output_data); +// WebPMuxDelete(mux); +// // ... (Consume output_data; e.g. write output_data.bytes_ to file). +// WebPDataClear(&output_data); +// +// Code Example#2: Get image and color profile data from a WebP file. +// +// int copy_data = 0; +// // ... (Read data from file). +// WebPMux* mux = WebPMuxCreate(&data, copy_data); +// WebPMuxGetImage(mux, &image); +// // ... (Consume image; e.g. call WebPDecode() to decode the data). +// WebPMuxGetColorProfile(mux, &icc_profile); +// // ... (Consume icc_data). +// WebPMuxDelete(mux); +// free(data); + +#ifndef WEBP_WEBP_MUX_H_ +#define WEBP_WEBP_MUX_H_ + +#include "./types.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define WEBP_MUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b) + +// Error codes +typedef enum { + WEBP_MUX_OK = 1, + WEBP_MUX_NOT_FOUND = 0, + WEBP_MUX_INVALID_ARGUMENT = -1, + WEBP_MUX_BAD_DATA = -2, + WEBP_MUX_MEMORY_ERROR = -3, + WEBP_MUX_NOT_ENOUGH_DATA = -4 +} WebPMuxError; + +// Flag values for different features used in VP8X chunk. +typedef enum { + TILE_FLAG = 0x00000001, + ANIMATION_FLAG = 0x00000002, + ICCP_FLAG = 0x00000004, + META_FLAG = 0x00000008, + ALPHA_FLAG = 0x00000010 +} WebPFeatureFlags; + +// IDs for different types of chunks. +typedef enum { + WEBP_CHUNK_VP8X, // VP8X + WEBP_CHUNK_ICCP, // ICCP + WEBP_CHUNK_LOOP, // LOOP + WEBP_CHUNK_FRAME, // FRM + WEBP_CHUNK_TILE, // TILE + WEBP_CHUNK_ALPHA, // ALPH + WEBP_CHUNK_IMAGE, // VP8/VP8L + WEBP_CHUNK_META, // META + WEBP_CHUNK_UNKNOWN, // Other chunks. + WEBP_CHUNK_NIL +} WebPChunkId; + +typedef struct WebPMux WebPMux; // main opaque object. + +// Data type used to describe 'raw' data, e.g., chunk data +// (ICC profile, metadata) and WebP compressed image data. +typedef struct { + const uint8_t* bytes_; + size_t size_; +} WebPData; + +//------------------------------------------------------------------------------ +// Manipulation of a WebPData object. + +// Initializes the contents of the 'webp_data' object with default values. +WEBP_EXTERN(void) WebPDataInit(WebPData* webp_data); + +// Clears the contents of the 'webp_data' object by calling free(). Does not +// deallocate the object itself. +WEBP_EXTERN(void) WebPDataClear(WebPData* webp_data); + +// Allocates necessary storage for 'dst' and copies the contents of 'src'. +// Returns true on success. +WEBP_EXTERN(int) WebPDataCopy(const WebPData* src, WebPData* dst); + +//------------------------------------------------------------------------------ +// Life of a Mux object + +// Internal, version-checked, entry point +WEBP_EXTERN(WebPMux*) WebPNewInternal(int); + +// Creates an empty mux object. +// Returns: +// A pointer to the newly created empty mux object. +static WEBP_INLINE WebPMux* WebPMuxNew(void) { + return WebPNewInternal(WEBP_MUX_ABI_VERSION); +} + +// Deletes the mux object. +// Parameters: +// mux - (in/out) object to be deleted +WEBP_EXTERN(void) WebPMuxDelete(WebPMux* mux); + +//------------------------------------------------------------------------------ +// Mux creation. + +// Internal, version-checked, entry point +WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int); + +// Creates a mux object from raw data given in WebP RIFF format. +// Parameters: +// bitstream - (in) the bitstream data in WebP RIFF format +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// A pointer to the mux object created from given data - on success. +// NULL - In case of invalid data or memory error. +static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream, + int copy_data) { + return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION); +} + +//------------------------------------------------------------------------------ +// Single Image. + +// Sets the image in the mux object. Any existing images (including frame/tile) +// will be removed. +// Parameters: +// mux - (in/out) object in which the image is to be set +// bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image +// WebP file (non-animated and non-tiled) +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(WebPMux* mux, + const WebPData* bitstream, + int copy_data); + +// Gets image data from the mux object. +// The content of 'bitstream' is allocated using malloc(), and NOT +// owned by the 'mux' object. It MUST be deallocated by the caller by calling +// WebPDataClear(). +// Parameters: +// mux - (in) object from which the image is to be fetched +// bitstream - (out) the image data +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL +// OR mux contains animation/tiling. +// WEBP_MUX_NOT_FOUND - if image is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux, + WebPData* bitstream); + +// Deletes the image in the mux object. +// Parameters: +// mux - (in/out) object from which the image is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// OR if mux contains animation/tiling. +// WEBP_MUX_NOT_FOUND - if image is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux); + +//------------------------------------------------------------------------------ +// XMP Metadata. + +// Sets the XMP metadata in the mux object. Any existing metadata chunk(s) will +// be removed. +// Parameters: +// mux - (in/out) object to which the XMP metadata is to be added +// metadata - (in) the XMP metadata data to be added +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or metadata is NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxSetMetadata(WebPMux* mux, + const WebPData* metadata, + int copy_data); + +// Gets a reference to the XMP metadata in the mux object. +// The caller should NOT free the returned data. +// Parameters: +// mux - (in) object from which the XMP metadata is to be fetched +// metadata - (out) XMP metadata +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux or metadata is NULL. +// WEBP_MUX_NOT_FOUND - if metadata is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetMetadata(const WebPMux* mux, + WebPData* metadata); + +// Deletes the XMP metadata in the mux object. +// Parameters: +// mux - (in/out) object from which XMP metadata is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// WEBP_MUX_NOT_FOUND - If mux does not contain metadata. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxDeleteMetadata(WebPMux* mux); + +//------------------------------------------------------------------------------ +// ICC Color Profile. + +// Sets the color profile in the mux object. Any existing color profile chunk(s) +// will be removed. +// Parameters: +// mux - (in/out) object to which the color profile is to be added +// color_profile - (in) the color profile data to be added +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or color_profile is NULL +// WEBP_MUX_MEMORY_ERROR - on memory allocation error +// WEBP_MUX_OK - on success +WEBP_EXTERN(WebPMuxError) WebPMuxSetColorProfile(WebPMux* mux, + const WebPData* color_profile, + int copy_data); + +// Gets a reference to the color profile in the mux object. +// The caller should NOT free the returned data. +// Parameters: +// mux - (in) object from which the color profile data is to be fetched +// color_profile - (out) color profile data +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux or color_profile is NULL. +// WEBP_MUX_NOT_FOUND - if color profile is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetColorProfile(const WebPMux* mux, + WebPData* color_profile); + +// Deletes the color profile in the mux object. +// Parameters: +// mux - (in/out) object from which color profile is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// WEBP_MUX_NOT_FOUND - If mux does not contain color profile. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxDeleteColorProfile(WebPMux* mux); + +//------------------------------------------------------------------------------ +// Animation. + +// Adds an animation frame at the end of the mux object. +// Note: as WebP only supports even offsets, any odd offset will be snapped to +// an even location using: offset &= ~1 +// Parameters: +// mux - (in/out) object to which an animation frame is to be added +// bitstream - (in) the image data corresponding to the frame. It can either +// be a raw VP8/VP8L bitstream or a single-image WebP file +// (non-animated and non-tiled) +// x_offset - (in) x-offset of the frame to be added +// y_offset - (in) y-offset of the frame to be added +// duration - (in) duration of the frame to be added (in milliseconds) +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame( + WebPMux* mux, const WebPData* bitstream, + int x_offset, int y_offset, int duration, int copy_data); + +// TODO(urvang): Create a struct as follows to reduce argument list size: +// typedef struct { +// WebPData bitstream; +// int x_offset, y_offset; +// int duration; +// } FrameInfo; + +// Gets the nth animation frame from the mux object. +// The content of 'bitstream' is allocated using malloc(), and NOT +// owned by the 'mux' object. It MUST be deallocated by the caller by calling +// WebPDataClear(). +// nth=0 has a special meaning - last position. +// Parameters: +// mux - (in) object from which the info is to be fetched +// nth - (in) index of the frame in the mux object +// bitstream - (out) the image data +// x_offset - (out) x-offset of the returned frame +// y_offset - (out) y-offset of the returned frame +// duration - (out) duration of the returned frame (in milliseconds) +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset, +// y_offset, or duration is NULL +// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. +// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame( + const WebPMux* mux, uint32_t nth, WebPData* bitstream, + int* x_offset, int* y_offset, int* duration); + +// Deletes an animation frame from the mux object. +// nth=0 has a special meaning - last position. +// Parameters: +// mux - (in/out) object from which a frame is to be deleted +// nth - (in) The position from which the frame is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object +// before deletion. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth); + +// Sets the animation loop count in the mux object. Any existing loop count +// value(s) will be removed. +// Parameters: +// mux - (in/out) object in which loop chunk is to be set/added +// loop_count - (in) animation loop count value. +// Note that loop_count of zero denotes infinite loop. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxSetLoopCount(WebPMux* mux, int loop_count); + +// Gets the animation loop count from the mux object. +// Parameters: +// mux - (in) object from which the loop count is to be fetched +// loop_count - (out) the loop_count value present in the LOOP chunk +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either of mux or loop_count is NULL +// WEBP_MUX_NOT_FOUND - if loop chunk is not present in mux object. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* mux, + int* loop_count); + +//------------------------------------------------------------------------------ +// Tiling. + +// Adds a tile at the end of the mux object. +// Note: as WebP only supports even offsets, any odd offset will be snapped to +// an even location using: offset &= ~1 +// Parameters: +// mux - (in/out) object to which a tile is to be added. +// bitstream - (in) the image data corresponding to the frame. It can either +// be a raw VP8/VP8L bitstream or a single-image WebP file +// (non-animated and non-tiled) +// x_offset - (in) x-offset of the tile to be added +// y_offset - (in) y-offset of the tile to be added +// copy_data - (in) value 1 indicates given data WILL copied to the mux, and +// value 0 indicates data will NOT be copied. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxPushTile( + WebPMux* mux, const WebPData* bitstream, + int x_offset, int y_offset, int copy_data); + +// Gets the nth tile from the mux object. +// The content of 'bitstream' is allocated using malloc(), and NOT +// owned by the 'mux' object. It MUST be deallocated by the caller by calling +// WebPDataClear(). +// nth=0 has a special meaning - last position. +// Parameters: +// mux - (in) object from which the info is to be fetched +// nth - (in) index of the tile in the mux object +// bitstream - (out) the image data +// x_offset - (out) x-offset of the returned tile +// y_offset - (out) y-offset of the returned tile +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset or +// y_offset is NULL +// WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object. +// WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetTile( + const WebPMux* mux, uint32_t nth, WebPData* bitstream, + int* x_offset, int* y_offset); + +// Deletes a tile from the mux object. +// nth=0 has a special meaning - last position +// Parameters: +// mux - (in/out) object from which a tile is to be deleted +// nth - (in) The position from which the tile is to be deleted +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL +// WEBP_MUX_NOT_FOUND - If there are less than nth tiles in the mux object +// before deletion. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* mux, uint32_t nth); + +//------------------------------------------------------------------------------ +// Misc Utilities. + +// Gets the feature flags from the mux object. +// Parameters: +// mux - (in) object from which the features are to be fetched +// flags - (out) the flags specifying which features are present in the +// mux object. This will be an OR of various flag values. +// Enum 'WebPFeatureFlags' can be used to test individual flag values. +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL +// WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object. +// WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid. +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux, + uint32_t* flags); + +// Gets number of chunks having tag value tag in the mux object. +// Parameters: +// mux - (in) object from which the info is to be fetched +// id - (in) chunk id specifying the type of chunk +// num_elements - (out) number of chunks with the given chunk id +// Returns: +// WEBP_MUX_INVALID_ARGUMENT - if either mux, or num_elements is NULL +// WEBP_MUX_OK - on success. +WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux, + WebPChunkId id, int* num_elements); + +// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'. +// This function also validates the mux object. +// Note: The content of 'assembled_data' will be ignored and overwritten. +// Also, the content of 'assembled_data' is allocated using malloc(), and NOT +// owned by the 'mux' object. It MUST be deallocated by the caller by calling +// WebPDataClear(). +// Parameters: +// mux - (in/out) object whose chunks are to be assembled +// assembled_data - (out) assembled WebP data +// Returns: +// WEBP_MUX_BAD_DATA - if mux object is invalid. +// WEBP_MUX_INVALID_ARGUMENT - if either mux, output_data or output_size is +// NULL. +// WEBP_MUX_MEMORY_ERROR - on memory allocation error. +// WEBP_MUX_OK - on success +WEBP_EXTERN(WebPMuxError) WebPMuxAssemble(WebPMux* mux, + WebPData* assembled_data); + +//------------------------------------------------------------------------------ +// Demux API. +// Enables extraction of image and extended format data from WebP files. + +#define WEBP_DEMUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b) + +typedef struct WebPDemuxer WebPDemuxer; + +typedef enum { + WEBP_DEMUX_PARSING_HEADER, // Not enough data to parse full header. + WEBP_DEMUX_PARSED_HEADER, // Header parsing complete, data may be available. + WEBP_DEMUX_DONE // Entire file has been parsed. +} WebPDemuxState; + +//------------------------------------------------------------------------------ +// Life of a Demux object + +// Internal, version-checked, entry point +WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal( + const WebPData*, int, WebPDemuxState*, int); + +// Parses the WebP file given by 'data'. +// A complete WebP file must be present in 'data' for the function to succeed. +// Returns a WebPDemuxer object on successful parse, NULL otherwise. +static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { + return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION); +} + +// Parses the WebP file given by 'data'. +// If 'state' is non-NULL it will be set to indicate the status of the demuxer. +// Returns a WebPDemuxer object on successful parse, NULL otherwise. +static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( + const WebPData* data, WebPDemuxState* state) { + return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION); +} + +// Frees memory associated with 'dmux'. +WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux); + +//------------------------------------------------------------------------------ +// Data/information extraction. + +typedef enum { + WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk. + WEBP_FF_CANVAS_WIDTH, + WEBP_FF_CANVAS_HEIGHT, + WEBP_FF_LOOP_COUNT +} WebPFormatFeature; + +// Get the 'feature' value from the 'dmux'. +// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial() +// returned a state > WEBP_DEMUX_PARSING_HEADER. +WEBP_EXTERN(uint32_t) WebPDemuxGetI( + const WebPDemuxer* dmux, WebPFormatFeature feature); + +//------------------------------------------------------------------------------ +// Frame iteration. + +typedef struct { + int frame_num_; + int num_frames_; + int tile_num_; + int num_tiles_; + int x_offset_, y_offset_; // offset relative to the canvas. + int width_, height_; // dimensions of this frame or tile. + int duration_; // display duration in milliseconds. + int complete_; // true if 'tile_' contains a full frame. partial images may + // still be decoded with the WebP incremental decoder. + WebPData tile_; // The frame or tile given by 'frame_num_' and 'tile_num_'. + + uint32_t pad[4]; // padding for later use + void* private_; +} WebPIterator; + +// Retrieves frame 'frame_number' from 'dmux'. +// 'iter->tile_' points to the first tile on return from this function. +// Individual tiles may be extracted using WebPDemuxSetTile(). +// Setting 'frame_number' equal to 0 will return the last frame of the image. +// Returns false if 'dmux' is NULL or frame 'frame_number' is not present. +// Call WebPDemuxReleaseIterator() when use of the iterator is complete. +// NOTE: 'dmux' must persist for the lifetime of 'iter'. +WEBP_EXTERN(int) WebPDemuxGetFrame( + const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); + +// Sets 'iter->tile_' to point to the next ('iter->frame_num_' + 1) or previous +// ('iter->frame_num_' - 1) frame. These functions do not loop. +// Returns true on success, false otherwise. +WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter); +WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter); + +// Sets 'iter->tile_' to reflect tile number 'tile_number'. +// Returns true if tile 'tile_number' is present, false otherwise. +WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number); + +// Releases any memory associated with 'iter'. +// Must be called before destroying the associated WebPDemuxer with +// WebPDemuxDelete(). +WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter); + +//------------------------------------------------------------------------------ +// Chunk iteration. + +typedef struct { + // The current and total number of chunks with the fourcc given to + // WebPDemuxGetChunk(). + int chunk_num_; + int num_chunks_; + WebPData chunk_; // The payload of the chunk. + + uint32_t pad[6]; // padding for later use + void* private_; +} WebPChunkIterator; + +// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from +// 'dmux'. +// 'fourcc' is a character array containing the fourcc of the chunk to return, +// e.g., "ICCP", "META", "EXIF", etc. +// Setting 'chunk_number' equal to 0 will return the last chunk in a set. +// Returns true if the chunk is found, false otherwise. Image related chunk +// payloads are accessed through WebPDemuxGetFrame() and related functions. +// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete. +// NOTE: 'dmux' must persist for the lifetime of the iterator. +WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux, + const char fourcc[4], int chunk_number, + WebPChunkIterator* iter); + +// Sets 'iter->chunk_' to point to the next ('iter->chunk_num_' + 1) or previous +// ('iter->chunk_num_' - 1) chunk. These functions do not loop. +// Returns true on success, false otherwise. +WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter); +WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter); + +// Releases any memory associated with 'iter'. +// Must be called before destroying the associated WebPDemuxer with +// WebPDemuxDelete(). +WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter); + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif /* WEBP_WEBP_MUX_H_ */ diff --git a/external/libwebp/webp/types.h b/external/libwebp/webp/types.h new file mode 100644 index 0000000000..3e27190bef --- /dev/null +++ b/external/libwebp/webp/types.h @@ -0,0 +1,45 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Common types +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_WEBP_TYPES_H_ +#define WEBP_WEBP_TYPES_H_ + +#include // for size_t + +#ifndef _MSC_VER +#include +#ifdef __STRICT_ANSI__ +#define WEBP_INLINE +#else /* __STRICT_ANSI__ */ +#define WEBP_INLINE inline +#endif +#else +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; +typedef long long int int64_t; +#define WEBP_INLINE __forceinline +#endif /* _MSC_VER */ + +#ifndef WEBP_EXTERN +// This explicitly marks library functions and allows for changing the +// signature for e.g., Windows DLL builds. +#define WEBP_EXTERN(type) extern type +#endif /* WEBP_EXTERN */ + +// Macro to check ABI compatibility (same major revision number) +#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) + +#endif /* WEBP_WEBP_TYPES_H_ */ diff --git a/install-deps-linux.sh b/install-deps-linux.sh index aed005614c..bedd9e60d6 100755 --- a/install-deps-linux.sh +++ b/install-deps-linux.sh @@ -5,7 +5,7 @@ DEPENDS+=' libxmu-dev' DEPENDS+=' libglu1-mesa-dev' DEPENDS+=' libgl2ps-dev' DEPENDS+=' libxi-dev' -DEPENDS+=' libglfw-dev' +DEPENDS+=' libsdl2-dev' DEPENDS+=' g++' DEPENDS+=' libzip-dev' DEPENDS+=' libcurl4-gnutls-dev' diff --git a/plugin/jsbindings/auto/jsb_pluginx_protocols_auto.cpp b/plugin/jsbindings/auto/jsb_pluginx_protocols_auto.cpp index aa6f3e2fe5..9ad4624a55 100644 --- a/plugin/jsbindings/auto/jsb_pluginx_protocols_auto.cpp +++ b/plugin/jsbindings/auto/jsb_pluginx_protocols_auto.cpp @@ -742,10 +742,18 @@ JSBool js_pluginx_protocols_ProtocolAds_showAds(JSContext *cx, uint32_t argc, js js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::plugin::ProtocolAds* cobj = (cocos2d::plugin::ProtocolAds *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + if (argc == 1) { + TAdsInfo arg0; + ok &= jsval_to_TAdsInfo(cx, argv[0], &arg0); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + cobj->showAds(arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; + } if (argc == 2) { TAdsInfo arg0; cocos2d::plugin::ProtocolAds::AdsPos arg1; - #pragma warning NO CONVERSION TO NATIVE FOR TAdsInfo; + ok &= jsval_to_TAdsInfo(cx, argv[0], &arg0); ok &= jsval_to_int32(cx, argv[1], (int32_t *)&arg1); JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); cobj->showAds(arg0, arg1); @@ -753,7 +761,7 @@ JSBool js_pluginx_protocols_ProtocolAds_showAds(JSContext *cx, uint32_t argc, js return JS_TRUE; } - JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 2); + JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1); return JS_FALSE; } JSBool js_pluginx_protocols_ProtocolAds_hideAds(JSContext *cx, uint32_t argc, jsval *vp) @@ -766,7 +774,7 @@ JSBool js_pluginx_protocols_ProtocolAds_hideAds(JSContext *cx, uint32_t argc, js JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); if (argc == 1) { TAdsInfo arg0; - #pragma warning NO CONVERSION TO NATIVE FOR TAdsInfo; + ok &= jsval_to_TAdsInfo(cx, argv[0], &arg0); JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); cobj->hideAds(arg0); JS_SET_RVAL(cx, vp, JSVAL_VOID); @@ -893,7 +901,7 @@ void js_register_pluginx_protocols_ProtocolAds(JSContext *cx, JSObject *global) }; static JSFunctionSpec funcs[] = { - JS_FN("showAds", js_pluginx_protocols_ProtocolAds_showAds, 2, JSPROP_PERMANENT | JSPROP_ENUMERATE), + JS_FN("showAds", js_pluginx_protocols_ProtocolAds_showAds, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("hideAds", js_pluginx_protocols_ProtocolAds_hideAds, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("queryPoints", js_pluginx_protocols_ProtocolAds_queryPoints, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("spendPoints", js_pluginx_protocols_ProtocolAds_spendPoints, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), @@ -1143,7 +1151,7 @@ JSBool js_pluginx_protocols_ProtocolSocial_configDeveloperInfo(JSContext *cx, ui JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); if (argc == 1) { TSocialDeveloperInfo arg0; - #pragma warning NO CONVERSION TO NATIVE FOR TSocialDeveloperInfo; + ok &= jsval_to_TSocialDeveloperInfo(cx, argv[0], &arg0); JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); cobj->configDeveloperInfo(arg0); JS_SET_RVAL(cx, vp, JSVAL_VOID); @@ -1163,7 +1171,7 @@ JSBool js_pluginx_protocols_ProtocolSocial_unlockAchievement(JSContext *cx, uint JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); if (argc == 1) { TAchievementInfo arg0; - #pragma warning NO CONVERSION TO NATIVE FOR TAchievementInfo; + ok &= jsval_to_TAchievementInfo(cx, argv[0], &arg0); JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); cobj->unlockAchievement(arg0); JS_SET_RVAL(cx, vp, JSVAL_VOID); @@ -1295,7 +1303,7 @@ JSBool js_pluginx_protocols_ProtocolUser_configDeveloperInfo(JSContext *cx, uint JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); if (argc == 1) { TUserDeveloperInfo arg0; - #pragma warning NO CONVERSION TO NATIVE FOR TUserDeveloperInfo; + ok &= jsval_to_TUserDeveloperInfo(cx, argv[0], &arg0); JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); cobj->configDeveloperInfo(arg0); JS_SET_RVAL(cx, vp, JSVAL_VOID); diff --git a/plugin/plugins/flurry/proj.android/ForManifest.xml b/plugin/plugins/flurry/proj.android/ForManifest.xml index 01f67fb069..b0b12ee53c 100644 --- a/plugin/plugins/flurry/proj.android/ForManifest.xml +++ b/plugin/plugins/flurry/proj.android/ForManifest.xml @@ -1,5 +1,12 @@ + + + + + diff --git a/plugin/plugins/flurry/proj.android/sdk/FlurryAgent.jar.REMOVED.git-id b/plugin/plugins/flurry/proj.android/sdk/FlurryAgent.jar.REMOVED.git-id index 8cad603b42..b6d3696ee1 100644 --- a/plugin/plugins/flurry/proj.android/sdk/FlurryAgent.jar.REMOVED.git-id +++ b/plugin/plugins/flurry/proj.android/sdk/FlurryAgent.jar.REMOVED.git-id @@ -1 +1 @@ -0fd2439e2bfeee847ea873ee45b6177b5208db97 \ No newline at end of file +9076d822b8a15910bd7053ecb2651c84ce98c726 \ No newline at end of file diff --git a/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AdsFlurry.java b/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AdsFlurry.java new file mode 100644 index 0000000000..ae7d4f77e0 --- /dev/null +++ b/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AdsFlurry.java @@ -0,0 +1,246 @@ +/**************************************************************************** +Copyright (c) 2012-2013 cocos2d-x.org + +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 +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. +****************************************************************************/ +package org.cocos2dx.plugin; + +import java.util.Hashtable; +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import com.flurry.android.FlurryAdListener; +import com.flurry.android.FlurryAdSize; +import com.flurry.android.FlurryAdType; +import com.flurry.android.FlurryAds; +import com.flurry.android.FlurryAgent; + +public class AdsFlurry implements InterfaceAds, FlurryAdListener { + + private Context mContext = null; + protected static String TAG = "AdsFlurry"; + + private FrameLayout mBannerView = null; + private WindowManager mWm = null; + private AdsFlurry mAdapter = null; + + protected static void LogE(String msg, Exception e) { + Log.e(TAG, msg, e); + e.printStackTrace(); + } + + private static boolean isDebug = false; + protected static void LogD(String msg) { + if (isDebug) { + Log.d(TAG, msg); + } + } + + public AdsFlurry(Context context) { + mContext = context; + mAdapter = this; + } + + @Override + public void setDebugMode(boolean isDebugMode) { + isDebug = isDebugMode; + FlurryAgent.setLogEnabled(isDebug); + if (isDebugMode) { + FlurryAgent.setLogLevel(Log.DEBUG); + } + } + + @Override + public String getSDKVersion() { + return "3.2.1"; + } + + @Override + public String getPluginVersion() { + return "0.2.0"; + } + + @Override + public void configDeveloperInfo(Hashtable devInfo) { + final Hashtable curInfo = devInfo; + PluginWrapper.runOnMainThread(new Runnable(){ + @Override + public void run() { + try { + String appKey = curInfo.get("FlurryAppKey"); + FlurryAgent.onStartSession(mContext, appKey); + FlurryAds.setAdListener(mAdapter); + FlurryAds.initializeAds(mContext); + } catch (Exception e) { + LogE("Error during configDeveloperInfo.", e); + } + } + }); + } + + @Override + public void showAds(Hashtable adsInfo, int pos) { + final Hashtable curInfo = adsInfo; + final int curPos = pos; + PluginWrapper.runOnMainThread(new Runnable(){ + @Override + public void run() { + try + { + String spaceID = curInfo.get("FlurryAdsID"); + if (null == spaceID || TextUtils.isEmpty(spaceID)) + { + LogD("Value of 'FlurryAdsID' should not be empty"); + return; + } + + String strSize = curInfo.get("FlurryAdsSize"); + int size = Integer.parseInt(strSize); + if (size != 1 && size != 2 && size != 3) { + LogD("Valur of 'FlurryAdsSize' should be one of '1', '2', '3'"); + return; + } + + FlurryAdSize eSize = FlurryAdSize.BANNER_TOP; + switch (size) + { + case 1: + eSize = FlurryAdSize.BANNER_TOP; + break; + case 2: + eSize = FlurryAdSize.BANNER_BOTTOM; + break; + case 3: + eSize = FlurryAdSize.FULLSCREEN; + break; + default: + break; + } + + if (null == mWm) { + mWm = (WindowManager) mContext.getSystemService("window"); + } + if (null != mBannerView) { + mWm.removeView(mBannerView); + mBannerView = null; + } + mBannerView = new FrameLayout(mContext); + AdsWrapper.addAdView(mWm, mBannerView, curPos); + + FlurryAds.fetchAd(mContext, spaceID, mBannerView, eSize); + } catch (Exception e) { + LogE("Error during showAds", e); + } + } + }); + } + + @Override + public void hideAds(Hashtable adsInfo) { + final Hashtable curInfo = adsInfo; + PluginWrapper.runOnGLThread(new Runnable(){ + @Override + public void run() { + try + { + String spaceID = curInfo.get("FlurryAdsID"); + if (null == spaceID || TextUtils.isEmpty(spaceID)) + { + LogD("Value of 'FlurryAdsID' should not be empty"); + return; + } + + FlurryAds.removeAd(mContext, spaceID, (ViewGroup) mBannerView); + } catch (Exception e) { + LogE("Error during hideAds", e); + } + } + }); + } + + @Override + public void queryPoints() { + // TODO Auto-generated method stub + + } + + @Override + public void spendPoints(int points) { + // TODO Auto-generated method stub + + } + + @Override + public void onAdClicked(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onAdClosed(String arg0) { + AdsWrapper.onAdsResult(this, AdsWrapper.RESULT_CODE_AdsDismissed, "Ads will be dismissed"); + } + + @Override + public void onAdOpened(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onApplicationExit(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onRenderFailed(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onVideoCompleted(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public boolean shouldDisplayAd(String arg0, FlurryAdType arg1) { + AdsWrapper.onAdsResult(this, AdsWrapper.RESULT_CODE_AdsShown, "Ads will be shown"); + return true; + } + + @Override + public void spaceDidFailToReceiveAd(String arg0) { + LogD("param : " + arg0); + AdsWrapper.onAdsResult(this, AdsWrapper.RESULT_CODE_UnknownError, "Failed to receive Ads of flurry"); + } + + @Override + public void spaceDidReceiveAd(String arg0) { + AdsWrapper.onAdsResult(this, AdsWrapper.RESULT_CODE_AdsReceived, "Ads of flurry received"); + } +} diff --git a/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AnalyticsFlurry.java b/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AnalyticsFlurry.java index ce9eae4909..3e4eaef73a 100644 --- a/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AnalyticsFlurry.java +++ b/plugin/plugins/flurry/proj.android/src/org/cocos2dx/plugin/AnalyticsFlurry.java @@ -120,7 +120,7 @@ public class AnalyticsFlurry implements InterfaceAnalytics { @Override public String getSDKVersion() { - return "3.2.0"; + return "3.2.1"; } protected void logTimedEventBeginWithParams(JSONObject eventInfo) { diff --git a/plugin/plugins/flurry/proj.ios/AdsFlurry.h b/plugin/plugins/flurry/proj.ios/AdsFlurry.h new file mode 100644 index 0000000000..c2ae1af2ef --- /dev/null +++ b/plugin/plugins/flurry/proj.ios/AdsFlurry.h @@ -0,0 +1,53 @@ +/**************************************************************************** +Copyright (c) 2013 cocos2d-x.org + +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 +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. +****************************************************************************/ +#import "InterfaceAds.h" +#import "FlurryAdDelegate.h" + +@interface AdsFlurry : NSObject +{ + +} + +@property BOOL debug; + +/** + interfaces of protocol : InterfaceAds + */ +- (void) configDeveloperInfo: (NSMutableDictionary*) devInfo; +- (void) showAds: (NSMutableDictionary*) info position:(int) pos; +- (void) hideAds: (NSMutableDictionary*) info; +- (void) queryPoints; +- (void) spendPoints: (int) points; +- (void) setDebugMode: (BOOL) isDebugMode; +- (NSString*) getSDKVersion; +- (NSString*) getPluginVersion; + +/** + interfaces of protocol : FlurryAdDelegate + */ +- (void) spaceDidReceiveAd:(NSString*)adSpace; +- (void) spaceDidFailToReceiveAd:(NSString*)adSpace error:(NSError *)error; +- (BOOL) spaceShouldDisplay:(NSString*)adSpace interstitial:(BOOL)interstitial; + +@end diff --git a/plugin/plugins/flurry/proj.ios/AdsFlurry.m b/plugin/plugins/flurry/proj.ios/AdsFlurry.m new file mode 100644 index 0000000000..3d5d69b338 --- /dev/null +++ b/plugin/plugins/flurry/proj.ios/AdsFlurry.m @@ -0,0 +1,139 @@ +/**************************************************************************** +Copyright (c) 2012-2013 cocos2d-x.org + +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 +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. +****************************************************************************/ +#import "AdsFlurry.h" +#import "Flurry.h" +#import "FlurryAds.h" +#import "AdsWrapper.h" + +#define OUTPUT_LOG(...) if (self.debug) NSLog(__VA_ARGS__); + +@implementation AdsFlurry + +@synthesize debug = __debug; + + +#pragma mark Interfaces for ProtocolAds impl + +- (void) configDeveloperInfo: (NSMutableDictionary*) devInfo +{ + NSString* appKey = [devInfo objectForKey:@"FlurryAppKey"]; + if (appKey) { + [Flurry startSession:appKey]; + } + + [FlurryAds initialize:[AdsWrapper getCurrentRootViewController]]; + [FlurryAds setAdDelegate:self]; +} + +- (void) showAds: (NSMutableDictionary*) info position:(int) pos +{ + NSString* strSpaceID = [info objectForKey:@"FlurryAdsID"]; + if (! strSpaceID || [strSpaceID length] == 0) { + OUTPUT_LOG(@"Value of 'FlurryAdsID' should not be empty"); + return; + } + + NSString* strSize = [info objectForKey:@"FlurryAdsSize"]; + int size = [strSize intValue]; + if (size != 1 && size != 2 && size != 3) { + OUTPUT_LOG(@"Value of 'FlurryAdsSize' should be one of '1', '2', '3' "); + return; + } + + UIViewController* controller = [AdsWrapper getCurrentRootViewController]; + if (controller) { + [FlurryAds fetchAndDisplayAdForSpace:strSpaceID view:controller.view size:size]; + } +} + +- (void) hideAds: (NSMutableDictionary*) info +{ + NSString* strSpaceID = [info objectForKey:@"FlurryAdsID"]; + if (! strSpaceID || [strSpaceID length] == 0) { + OUTPUT_LOG(@"Value of 'FlurryAdsID' should not be empty"); + return; + } + + [FlurryAds removeAdFromSpace:strSpaceID]; +} + +- (void) queryPoints +{ + +} + +- (void) spendPoints: (int) points +{ + +} + +- (void) setDebugMode: (BOOL) isDebugMode +{ + OUTPUT_LOG(@"Flurry setDebugMode invoked(%d)", isDebugMode); + self.debug = isDebugMode; + [Flurry setDebugLogEnabled:isDebugMode]; + + if (self.debug) { + [FlurryAds enableTestAds:YES]; + } +} + +- (NSString*) getSDKVersion +{ + return @"4.2.1"; +} + +- (NSString*) getPluginVersion +{ + return @"0.2.0"; +} + +#pragma mark Interfaces for FlurryAdDelegate impl + +- (void) spaceDidReceiveAd:(NSString*)adSpace +{ + [AdsWrapper onAdsResult:self withRet:kAdsReceived withMsg:@"Ads of flurry received"]; +} + +- (void) spaceDidFailToReceiveAd:(NSString*)adSpace error:(NSError *)error +{ + NSString* strMsg = [[error userInfo] objectForKey:@"NSLocalizedDescription"]; + if (! strMsg) { + strMsg = @"Failed to receive ads"; + } + [AdsWrapper onAdsResult:self withRet:kUnknownError withMsg:strMsg]; +} + +- (BOOL) spaceShouldDisplay:(NSString*)adSpace interstitial:(BOOL)interstitial +{ + [AdsWrapper onAdsResult:self withRet:kAdsShown withMsg:@"Ads will be shown"]; + return YES; +} + +- (void) spaceWillDismiss:(NSString *)adSpace +{ + [AdsWrapper onAdsResult:self withRet:kAdsDismissed withMsg:@"Ads will be dismissed"]; +} + +@end diff --git a/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAdDelegate.h b/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAdDelegate.h new file mode 100755 index 0000000000..3a8a80aaf0 --- /dev/null +++ b/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAdDelegate.h @@ -0,0 +1,324 @@ +// +// FlurryAdDelegate.h +// Flurry +// +// Copyright 2010 - 2012 Flurry, Inc. All rights reserved. +// +// Methods in this header file are for use with Flurry +// + +#import + +typedef enum { + WEB_BANNER = 1, + WEB_TAKEOVER = 2, + VIDEO_TAKEOVER = 3, + AD_BANNER = 4, + AD_TAKEOVER = 5, + NETWORK_BANNER = 6, + NETWORK_TAKEOVER = 7 +} FlurryAdType; + +/*! + * @brief Provides all available delegates for receiving callbacks related to Ad Serving. + * + * Set of methods that allow developers to manage and take actions within + * different phases of App ad display. + * + * @note This class serves as a delegate for FlurryAds. \n + * For additional information on how to use Flurry's Ads SDK to + * attract high-quality users and monetize your user base see Support Center - Publisher. + * @author 2010 - 2012 Flurry, Inc. All Rights Reserved. + * @version 4.2.0 + * + */ +@protocol FlurryAdDelegate + +@optional + +/*! + * @brief Invoked when an ad is received for the specified @c adSpace. + * @since 4.1 + * + * This method informs the app that an ad has been received and is available for display. + * + * @see FlurryAds#fetchAdForSpace:frame:size: for details on the method that will invoke this delegate. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ +- (void) spaceDidReceiveAd:(NSString*)adSpace; + +/*! + * @brief Invoked when an ad can not be retrieved for the specified @c adSpace. + * @since 4.1 + * + * This method informs the app that an ad has failed to be received for the given adSpace. + * + * @see FlurryAds#fetchAdForSpace:frame:size: for details on the method that will invoke this delegate. + * + * @param adSpace The placement of an ad in your app, where placement may + * @param error The error, if known, that caused ads not to be received. + * be splash screen for SPLASH_AD. + */ +- (void) spaceDidFailToReceiveAd:(NSString*)adSpace error:(NSError *)error; + +/*! + * @brief Invoked when an ad is about to display on the specified @c adSpace. + * @since 4.1.0 + * + * This method informs the app that an ad is about to be displayed. You can decide at this point not to show this ad by simply returning NO. + * + * @see FlurryAds#displayAdForSpace:view: for details on the method that will invoke this delegate. \n + * FlurryAds#fetchAndDisplayAdForSpace:view:size: for details on the method that will invoke this delegate. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param interstitial YES/NO if the space to display will be an interstitial. + */ +- (BOOL) spaceShouldDisplay:(NSString*)adSpace interstitial:(BOOL)interstitial; + +/*! + * @brief [Deprecated] This method is deprecated. -[spaceShouldDisplay:interstitial:] should be used. + */ +- (BOOL)spaceShouldDisplay:(NSString*)adSpace forType:(FlurryAdType)type; + +/*! + * @brief Invoked when an ad fails to render. + * @since 4.0.0 + * + * This method informs the user an ad was retrieved, however, was unsuccessful in displaying to the user (could be lost network connectivity for example). + * + * @see FlurryAds#displayAdForSpace:view: for details on the method that will invoke this delegate. \n + * FlurryAds#fetchAndDisplayAdForSpace:view:size: for details on the method that will invoke this delegate. + * + * @param adSpace The placement of an ad in your app, where placement may + * @param error The error, if known, that caused ads not to be rendered. + * be splash screen for SPLASH_AD. + */ +- (void) spaceDidFailToRender:(NSString *)space error:(NSError *)error; + +/*! + * @brief Invoked when the ad will be removed. + * @since 4.1 + * + * This method informs the app that an ad will be removed. + * + * @param adSpace The placement of an ad in your app, where placement may be splash screen for SPLASH_AD. + * @param interstitial YES/NO indicates if space being removed is an interstitial + * + */ +- (void)spaceWillDismiss:(NSString *)adSpace interstitial:(BOOL)interstitial; + +/*! + * @brief Invoked when the ad has been removed. + * @since 4.0.0 + * + * This method informs the app that an ad has closed. You can use this to resume app + * states. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param interstitial YES/NO indicates if space being removed is an interstitial + */ +- (void)spaceDidDismiss:(NSString *)adSpace interstitial:(BOOL)interstitial; + +/*! + * @brief Invoked when the ad has been selected that will take the user out of the app. + * @since 4.0.0 + * + * This method informs the app that an ad has been clicked and the user is about to be taken outside the app. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ +- (void)spaceWillLeaveApplication:(NSString *)adSpace; + +/*! + * @brief Invoked when a space will be expanded. + * @since 4.1 + * + * This method informs the app an ad space (typcially a banner) will be expanded. Apps should pause their state when they receive this notification + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ +- (void) spaceWillExpand:(NSString *)adSpace; + +/*! + * @brief Invoked when a space will be collapsed. + * @since 4.1 + * + * This method informs the app an ad space (typcially a banner) will be collapsed. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ +- (void) spaceWillCollapse:(NSString *)adSpace; + +/*! + * @brief Invoked when a space has been collapsed. + * @since 4.1 + * + * This method informs the app an ad space (typcially a banner) has been collapsed. Apps should resume their state when they receive this notification + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ + - (void) spaceDidCollapse:(NSString *)adSpace; + +/*! + * @brief Informational callback invoked when an ad is clicked for the specified @c adSpace. + * @since 4.1 + * + * This method informs the app that an ad has been clicked. This should not be used to adjust state of an app. It is only intended for informational purposes. + * + * @param adSpace The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ +- (void) spaceDidReceiveClick:(NSString*)adSpace; + + +/*! + * @brief Invoked when a video finishes playing + * @since 4.2.0 + * + * This method informs the app that a video associated with an ad has finished playing + * + * @param adSpace The placement of an ad in your app, where placement may be splash screen for SPLASH_AD. + * + */ +- (void)videoDidFinish:(NSString *)adSpace; + + +@optional + +#pragma mark App Keys +/** @name Third party network Calls + * Optional calls to pass information needed to display ads through 3rd parties. + */ +//@{ + +/*! + * @brief The Millennial APID. + * @since 4.0.0 + * + * This is the id for your app as set in Millennial, found here: https://developer.millennialmedia.com/Application/index.php#manageApps. + */ +- (NSString *)appSpotMillennialAppKey; //your millennial APID, found here: https://developer.millennialmedia.com/Application/index.php#manageApps + +/*! + * @brief The Millennial APID for interstitials. + * @since 4.0.0 + * + * This is the id for your app as set in Millennial, found here: https://developer.millennialmedia.com/Application/index.php#manageApps. + */ +- (NSString *)appSpotMillennialInterstitalAppKey; + +/*! + * @brief The InMobi APID. + * @since 4.0.0 + * + * This is the id for your app as set in InMobi, found here: https://www.inmobi.com/pub/mysite.html?platFormType=all + */ +- (NSString *)appSpotInMobiAppKey; + +/*! + * @brief The AdMob Publisher Id. + * @since 4.0.0 + * + * This is the id for your app as set in AdMob, found here: http://www.admob.com/my_sites/ (click manage settings) + */ +- (NSString *)appSpotAdMobPublisherID; + +/*! + * @brief The Mobclix Application Id. + * @since 4.0.0 + * + * This is the id for your app as set in Mobclix + */ +- (NSString *)appSpotMobclixApplicationID; + +/*! + * @brief The Jumptap Publisher Id. + * @since 4.1.2 + * + * This is the pub id for your app as set in Jumptap + */ +- (NSString *)appSpotJumptapPublisherID; + +/*! + * @brief The Jumptap Site Id. + * @since 4.1.2 + * + * This is the site id for your app as set in Jumptap. It is an optional parameter. + */ +- (NSString *)appSpotJumptapSiteID; + +/*! + * @brief Jumptap Banner Ad Spot ID + * @since 4.1.2 + * + * This is the ad spot id for a Banner (320x50) ad spot set in JumpTap + */ +- (NSString *)appSpotJumptapBannerAdSpotID; + +/*! + * @brief Jumptap Leaderboard Ad Spot ID + * @since 4.1.2 + * + * This is the ad spot id for a Leaderboard (720x90) ad spot set in JumpTap + */ +- (NSString *)appSpotJumptapLeaderboardAdSpotID; + +/*! + * @brief Jumptap Medium Rectange Ad Spot ID + * @since 4.1.2 + * + * This is the ad spot id for a Medium Rectangle (320x50) ad spot set in JumpTap. + * The Medium Rectangle Ad Spot ID will be used whenever the ad frame can fit it + * (e.g. interstitial ads). + */ +- (NSString *)appSpotJumptapMediumRectangleAdSpotID; + +/*! + * @brief The Greystripe Application Id. + * @since 4.0.0 + * + * This is the id for your app as set in Greystripe + */ +- (NSString *)appSpotGreystripeApplicationID; + + +#pragma mark Information + + +#pragma mark Callbacks + +/*! + * @brief [Deprecated] Allow you to set your rootViewController. + * @since 4.0.0 + * @deprecated + * + * This method has been deprecated. Please call FlurryAds#initialze: instead. + * + */ +- (id)appSpotRootViewController; + +#pragma mark Optional settings + +/** + Some networks support accelerometer-enabled ads. + */ +/*! + * @brief For networks that support accelerometer-enabled ads. + * @since 4.0.0 + * + * This method allows you to enable accelerometer based ads for networks that support this setting via the client sdk. Set to NO if your app uses the accelerometer + to avoid conflict. Set to YES if you want the special ads. Default is NO. + */ +- (BOOL)appSpotAccelerometerEnabled; + +//@} + +@end diff --git a/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAds.h b/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAds.h new file mode 100755 index 0000000000..2da4f42530 --- /dev/null +++ b/plugin/plugins/flurry/proj.ios/FlurryAds/FlurryAds.h @@ -0,0 +1,464 @@ +// +// FlurryAds.h +// Flurry iOS Analytics Agent +// +// Copyright 2009-2012 Flurry, Inc. All rights reserved. +// +// Methods in this header file are for use by Flurry Publishers + +#import + +typedef enum { + BANNER_TOP = 1, + BANNER_BOTTOM = 2, + FULLSCREEN = 3, +} FlurryAdSize; + +@protocol FlurryCustomAdNetwork; +@protocol FlurryCustomAdNetworkProperties; + +/*! + * @brief Provides all available methods for displaying ads. + * + * Set of methods that allow publishers to configure, target, and deliver ads to their customers. + * + * @note This class depends on Flurry.h. + * For information on how to use Flurry's Ads SDK to + * attract high-quality users and monetize your user base see Support Center - Publishers. + * + * @author 2009 - 2012 Flurry, Inc. All Rights Reserved. + * @version 4.2.0 + * + */ +@interface FlurryAds : NSObject { +} + +/*! + * @brief Retrieves an ad for the given @c space. + * @since 4.1.0 + * + * This method will attempt to retrieve ads for the given space from the Flurry server. + * + * @note The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. For example, if you are displaying a full screen ad on your + * splash screen and after level completeion, you may have the following spaces + * @c @"SPLASH_AD" and @c @"LEVEL_AD". + * + * @see #removeAdFromSpace: for details on manually removing an ad from a view. \n + * FlurryAdDelegate#spaceDidReceiveAd: for details on the notification of ads being received. + * FlurryAdDelegate#spaceDidFailToReceiveAd:error: for details on notification of failure to receive ads from this request. + * #displayAdForSpace: for details on displaying an available ad. + * + * @code + * - (void)fetchAd:(NSString *)placement + { + // Placement may be SPLASH_AD as noted above + [FlurryAds fetchAdForSpace:placement view:self.view.frame size:FULLSCREEN]; + } + + // Show whenever delegate is invoked + - (void) spaceDidReceiveAd:(NSString *)adSpace { + // Received Ad + [FlurryAds displayAdForSpace:adSpace]; + } + // Alternatively, try to display at a certain point in the app + - (void) levelComplete { + if([FlurryAds adReadyForSpace:adSpace]) { + [FlurryAds displayAdForSpace:adSpace]; + } + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param frame The frame of the view that will be used for the ad container. Note: for fullscreen ads, this value is not used (you can pass in bounds of window). + * @param size The default size of an ad space. This can be overriden on the server. See @c FlurryAdSize in the FlurryAds.h file for allowable values. + */ ++(void) fetchAdForSpace:(NSString*)space frame:(CGRect)frame size:(FlurryAdSize)size; + +/*! + * @brief Returns if an ad is currently ready to display for a given @c space. + * @since 4.1.0 + * + * This method will verify if there is an ad is currently available for this + * user. If an ad is not available, you may call #fetchAdForSpace:view:size: to load a new ad. + * + * @note If this method returns YES, an ad will be available when you attempt to display an ad. However, it is still advisable to listen to the delegate FlurryAdsDelegate#spaceDidFailToRender:. \n + The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. For example, if you are displaying a full screen ad on your + * splash screen and after level completeion, you may have the following spaces + * @c @"SPLASH_AD" and @c @"LEVEL_AD". + * + * @see #fetchAdForSpace:view:size: for details on retrieving an ad.\n + #displayAdForSpace: for details on displaying the available ad. + * + * @code + * - (void)showButtonForAd:(NSString *)placement + { + // Placement may be SPLASH_AD as noted above + if([FlurryAds adReadyForSpace:placement]) + { + // Show button that ads are available. + } + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * + * @return YES/NO to indicate if an ad is ready to be displayed. + */ ++(BOOL) adReadyForSpace:(NSString*)space; + +/*! + * @brief Display an ad for the given @c space. + * @since 4.1.0 + * + * This method will display an ad if one is ready for display on the device. + * + * @note The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. Only one ad will show at a time for any given ad space. For example, if you are displaying a full screen ad on your + * splash screen and after level completeion, you may have the following spaces + * @c @"SPLASH_AD" and @c @"LEVEL_AD". + * + * @see #fetchAdForSpace:view:size: for details on retrieving an ad.\n + #adReadyForSpace: for details on verifying is an ad is ready to be displayed. \n + * #removeAdFromSpace: for details on manually removing an ad from a view. \n + * FlurryAdDelegate#spaceShouldDisplay:forType: for details on controlling whether an ad will display immediately before it is set to be rendered to the user. + * FlurryAdDelegate#spaceDidFailToRender:error: for details on notification of error in rendering an ad for this request. + * + * @code + * - (void)showFullscreenAd:(NSString *)placement + { + // Placement may be SPLASH_AD as noted above + if([FlurryAds adReadyForSpace:placement]) + { + [FlurryAds displayAdForSpace:placement onView:view]; + } + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * @param view The view to place the ad. The view frame should be identical to the view frame passed in #fetchAdForSpace:frame:size. Note view is not used for interstitials. + * be splash screen for SPLASH_AD. + */ ++ (void)displayAdForSpace:(NSString*)space onView:(UIView *)view; + +/*! + * @brief Display an ad for the given interstitial @c space. + * @since 4.1.0 + * + * This method will display an interstitial ad if one is ready for display on the device for specified UIViewController instance + * + * @note The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. Only one ad will show at a time for any given ad space. For example, if you are displaying a full screen ad on your + * splash screen and after level completeion, you may have the following spaces + * @c @"SPLASH_AD" and @c @"LEVEL_AD". + * + * @see #fetchAdForSpace:view:size: for details on retrieving an ad.\n + #adReadyForSpace: for details on verifying is an ad is ready to be displayed. \n + * #removeAdFromSpace: for details on manually removing an ad from a view. \n + * FlurryAdDelegate#spaceShouldDisplay:forType: for details on controlling whether an ad will display immediately before it is set to be rendered to the user. + * FlurryAdDelegate#spaceDidFailToRender:error: for details on notification of error in rendering an ad for this request. + * + * @code + * in UIViewController based class: + * - (void)showFullscreenAd:(NSString *)placement + { + // Placement may be SPLASH_AD as noted above + if([FlurryAds adReadyForSpace:placement]) + { + [FlurryAds displayAdForSpace:placement modallyForViewController:self]; + } + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * @param viewController The viewController to show the fullscreen ad modally. + * Note this method should not be used for banners. + */ + + (void)displayAdForSpace:(NSString*)space modallyForViewController:(UIViewController *)viewController; + +/*! + * @brief [Deprecated] Check if an ad is available for the given @c space. + * @since 4.0.0 + * @deprecated + * + * [Deprecated] This method will verify with the Flurry server if an ad is currently available for this + * user. If an ad is not available, we recommend not providing the user the + * option to view. For example, you may have a button that reads "See other great apps!". + * That button should only be displayed if this method returns YES. + * + * @note This method has been deprecated. + * + * @see #fetchAdForSpace:view:size: for replacement method.\n + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param view The UIView in your app that the ad will be placed as a subview. Note: for fullscreen ads, this view is not used as a container. + * @param size The default size of an ad space. This can be overriden on the server. See @c FlurryAdSize in the FlurryAds.h file for allowable values. + * @param timeout The maximum amount of time to wait for the server to return a result. Set this to 0 to check the cache and return immediately. + * + * @return YES/NO to indicate if an ad is available. + */ ++(BOOL) isAdAvailableForSpace:(NSString*)space view:(UIView *)view size:(FlurryAdSize)size timeout:(int64_t)timeout; + +/*! + * @brief [Deprecated] Display an ad for the given @c space. + * @since 4.0.0 + * @deprecated + * + * [Deprecated] This method will display an ad if one is available from the Flurry server for this + * user. + * + * @note This method has been deprecated. + * + * @see #fetchAndDisplayAdForSpace:view:size:timeout: for replacement method + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param view The UIView in your app that the ad will be placed as a subview. Note: for fullscreen ads, this view is not used as a container. + * @param size The default size of an ad space. This can be overriden on the server. See @c FlurryAdSize in the FlurryAds.h file for allowable values. + * @param timeout The maximum amount of time to wait for the server to return a valid ad. Set this to 0 to display an ad in the background (e.g. - for showing banners). + * + * @return YES/NO to indicate if an ad is available. + */ ++ (BOOL)showAdForSpace:(NSString*)space view:(UIView *)viewContainer size:(FlurryAdSize)size timeout:(int64_t)timeout; + +/*! + * @brief Fetch and Display an ad for the given @c space. + * @since 4.0.0 + * + * This method will display an ad if one is available from the Flurry server for this + * user. + * + * @note If this method returns YES, an ad is available for the space within @c timeout. \n + * This is a blocking method that allows you to change the user experience based on availability of an ad. If you would like to display an ad asynchronously, just set timeout to 0. This is useful in the case of banners for instance where the user should not wait for its display. If you are loading async with timeout set to 0, ignore the return value of this method and rely exclusively on the relevant delegate methods listed below\n + * The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. Only one ad will show at a time for any given ad space. For example, if you are displaying a full screen ad on your + * splash screen and after level completeion, you may have the following spaces + * @c @"SPLASH_AD" and @c @"LEVEL_AD". + * + * @see #adReadyForSpace: for details on verifying is an ad is ready to be displayed. \n + * #removeAdFromSpace: for details on manually removing an ad from a view. \n + * FlurryAdDelegate#spaceDidReceiveAd: for details on the notification of ads being received. + * FlurryAdDelegate#spaceDidFailToReceiveAd:error: for details on notification of failure to receive ads from this request. + * FlurryAdDelegate#spaceShouldDisplay:forType: for details on controlling whether an ad will display immediately before it is set to be rendered to the user. + * FlurryAdDelegate#spaceDidFailToRender:error: for details on notification of error in rendering an ad for this request. + * + * @code + * - (void)showFullscreenAd:(NSString *)placement + { + // Placement may be SPLASH_AD as noted above + [FlurryAds fetchAndDisplayAdForSpace:placement view:self.view size:FULLSCREEN timeout:3000]; + + } + + - (void)viewWillAppear:(BOOL)animated + { + // Show a banner whenever this view appears + // Display banner ad completely asyncrhonously by providing timeout == 0 + [FlurryAds fetchAndDisplayAdForSpace:@"VIEW_XYZ_BANNER_AD" view:self.view size:BANNER_BOTTOM timeout:0]; + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + * @param view The UIView in your app that the ad will be placed as a subview. Note: for fullscreen ads, this view is not used as a container. + * @param size The default size of an ad space. This can be overriden on the server. See @c FlurryAdSize in the FlurryAds.h file for allowable values. + */ ++ (void)fetchAndDisplayAdForSpace:(NSString*)space view:(UIView *)viewContainer size:(FlurryAdSize)size; + +/*! + * @brief Removes an ad for the given @c space. + * @since 4.0.0 + * + * This method will remove an ad if one is currently displaying. + * + * @note The @c space simply represents the placement of the ad in your app and should be + * unique for each placement. Only one ad will show at a time for any given ad space. + * + * @see #isAdAvailableForSpace:view:size:timeout: for details on displaying an available ad. \n + * #removeAdFromSpace: for details on manually removing an ad from a view. \n + * FlurryAdDelegate#spaceShouldDisplay:forType: for details on controlling whether an ad will display immediately before it is set to be rendered to the user. + * + * @code + * - (void)viewDidUnload + { + // Remove a banner whenever this view dissapears + [FlurryAds removeAdFromSpace:@"VIEW_XYZ_BANNER_AD"]; + } + * @endcode + * + * @param space The placement of an ad in your app, where placement may + * be splash screen for SPLASH_AD. + */ ++ (void) removeAdFromSpace:(NSString*)space; + +/*! + * @brief Initializes the ad serving system. + * @since 4.0 + * + * This method initializes the ad serving system and can be used to pre-cache ads from the server (this is done when ad spaces are configured on the server). + * + * @note This method must be called sometime after Flurry#startSession:. + * + * @code + * - (void)applicationDidFinishLaunching:(UIApplication *)application + { + // Optional Flurry startup methods + [Flurry startSession:@"YOUR_API_KEY"]; + [FlurryAds setAdDelegate:self]; + [FlurryAds initialize:myWindow.rootViewController]; + + // .... + } + * @endcode + * + * @param rvc The primary root view controller of your app. + * + */ ++ (void) initialize: (UIViewController *)rvc; + +/*! + * @brief Sets the object to receive various delegate methods. + * @since 4.0 + * + * This method allows you to register an object that will receive + * notifications at different phases of ad serving. + * + * @see FlurryAdDelegate.h for details on delegates available. + * + * @code + * - (void)applicationDidFinishLaunching:(UIApplication *)application + { + // Optional Flurry startup methods + [Flurry startSession:@"YOUR_API_KEY"]; + [FlurryAds setAdDelegate:self]; + + // .... + } + * @endcode + * + * @param delegate The object to receive notifications of various ad actions. + * + */ ++ (void)setAdDelegate:(id)delegate; + +/*! + * @brief Informs server to send test ads. + * @since 4.0 + * + * This method allows you to request test ads from the server. These ads do not generate revenue so it is CRITICAL this call is removed prior to app submission. + * + * + * @code + * - (void)applicationDidFinishLaunching:(UIApplication *)application + { + // Optional Flurry startup methods + [Flurry startSession:@"YOUR_API_KEY"]; + [FlurryAds enableTestAds:YES]; + + // .... + } + * @endcode + * + * @param enable YES to receive test ads to the device. Not including this method is equivalent to passing NO. + * + */ ++ (void)enableTestAds:(BOOL)enable; + +/*! + * @brief Sets a dictionary of key/value pairs, which will be transmitted to Flurry servers when a user clicks on an ad. + * @since 4.0.0 + * + * UserCookies allow the developer to specify information on a user executing an ad action. There is one UserCookie object, and on each ad click that UserCookie is transmitted to the Flurry servers. The UserCookie key/value pairs will be transmitted back to the developer via the app callback if one is set. This is useful for rewarded inventory, to identify which of your users should be rewarded when a reward callback is sent. + * + * @note Calling this method with a nil or empty dictionary has no effect. Calling this method a second time with a valid dictionary will replace the previous entries. To clear previously set userCookies, you must call #clearUserCookies. + * @see #clearUserCookies for details on removing user cookies set through this method. + * + * @code + * - (void)applicationDidFinishLaunching:(UIApplication *)application + { + // Optional Flurry startup methods + [Flurry startSession:@"YOUR_API_KEY"]; + + NSDictionary *cookies = + [NSDictionary dictionaryWithObjectsAndKeys:@"xyz123", // Parameter Value + @"UserCharacterId", // Parameter Name + nil]; + [FlurryAds setUserCookies:cookies]; + + // .... + } + * @endcode + * + * @param userCookies The information about the user executing ad actions. Note: do not transmit personally identifiable information in the user cookies. + */ ++ (void) setUserCookies:(NSDictionary *) userCookies; + +/*! + * @brief Removes a previously set dictionary of key/value pairs. + * @since 4.0.0 + * + * This method removes information from the one UserCookie object. + * + * @see #setUserCookies: for details on setting user cookies. + * + */ ++ (void) clearUserCookies; + +/*! + * @brief Sets a dictionary of key/value pairs, which will be transmitted to Flurry servers when an ad is requested. + * @since 4.0.0 + * + * Keywords allow the developer to specify information on a user executing an ad action for the purposes of targeting. There is one keywords object that is transmitted to the Flurry servers on each ad request. If corresponding keywords are matched on the ad server, a subset of targeted ads will be delivered. This allows partners to supply information they track internally, which is not available to Flurry's targeting system. + * + * @note Calling this method with a nil or empty dictionary has no effect. Calling this method a second time with a valid dictionary will replace the previous entries. To clear previously set keywords, you must call #clearKeywords. + * @see #clearKeywords for details on removing keywords set through this method. + * + * @code + * - (void)applicationDidFinishLaunching:(UIApplication *)application + { + // Optional Flurry startup methods + [Flurry startSession:@"YOUR_API_KEY"]; + + // Specify that user loves vacations + NSDictionary *keywords = + [NSDictionary dictionaryWithObjectsAndKeys:@"vacation", // Parameter Value + @"UserPreference", // Parameter Name + nil]; + [FlurryAds setKeywords:keywords]; + + // .... + } + * @endcode + * + * @param keywords The information about the user to be used in targeting an ad. Note: do not transmit personally identifiable information in keywords. + */ ++ (void) setKeywordsForTargeting:(NSDictionary*) keywords; + +/*! + * @brief Removes a previously set dictionary of key/value pairs. + * @since 4.0.0 + * + * This method removes information from the one keywords object. + * + * @see #setKeywords: for details on setting keywords. + * + */ ++ (void) clearKeywords; + +/*! + * @brief Method to add a custom ad network to be served through the standard Flurry ad system. + * @since 4.0.0 + * + * This method adds a network with the necessary publisher supplied properties to the Flurry sdk. + * + * @see @c FlurryCustomAdNetwork and @c FlurryCustomAdNetworkProperties for details. + * + */ ++ (void) addCustomAdNetwork:(Class)adNetworkClass withProperties:(id)adNetworkProperties; + + +@end \ No newline at end of file diff --git a/plugin/plugins/flurry/proj.ios/FlurryAds/libFlurryAds.a.REMOVED.git-id b/plugin/plugins/flurry/proj.ios/FlurryAds/libFlurryAds.a.REMOVED.git-id new file mode 100644 index 0000000000..edbadc3482 --- /dev/null +++ b/plugin/plugins/flurry/proj.ios/FlurryAds/libFlurryAds.a.REMOVED.git-id @@ -0,0 +1 @@ +ad04773003101a8d05f3afb8fe384a2087bd476b \ No newline at end of file diff --git a/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj b/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj index 560071669c..c6bbdb8237 100644 --- a/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj +++ b/plugin/plugins/flurry/proj.ios/PluginFlurry.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ FA09A376168AFD41008C1C7B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA09A375168AFD41008C1C7B /* Foundation.framework */; }; + FA73FC9117A11B84007E23C2 /* AdsFlurry.m in Sources */ = {isa = PBXBuildFile; fileRef = FA73FC8F17A11B84007E23C2 /* AdsFlurry.m */; }; + FA73FC9617A11E24007E23C2 /* libFlurryAds.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73FC9517A11E24007E23C2 /* libFlurryAds.a */; }; FAB6DFDD1756F22200C90D89 /* libFlurry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FAB6DFDB1756F22200C90D89 /* libFlurry.a */; }; FAB6DFE01756F29800C90D89 /* AnalyticsFlurry.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB6DFDF1756F29800C90D89 /* AnalyticsFlurry.m */; }; /* End PBXBuildFile section */ @@ -27,6 +29,12 @@ /* Begin PBXFileReference section */ FA09A372168AFD41008C1C7B /* libPluginFlurry.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPluginFlurry.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA09A375168AFD41008C1C7B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + FA73FC8E17A11B84007E23C2 /* AdsFlurry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdsFlurry.h; sourceTree = ""; }; + FA73FC8F17A11B84007E23C2 /* AdsFlurry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdsFlurry.m; sourceTree = ""; }; + FA73FC9017A11B84007E23C2 /* PluginFlurry-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PluginFlurry-Prefix.pch"; sourceTree = ""; }; + FA73FC9317A11E24007E23C2 /* FlurryAdDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlurryAdDelegate.h; sourceTree = ""; }; + FA73FC9417A11E24007E23C2 /* FlurryAds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlurryAds.h; sourceTree = ""; }; + FA73FC9517A11E24007E23C2 /* libFlurryAds.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libFlurryAds.a; sourceTree = ""; }; FA86650E168BE22D0073E055 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; FAB6DFD81756F22200C90D89 /* Flurry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Flurry.h; sourceTree = ""; }; FAB6DFDB1756F22200C90D89 /* libFlurry.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libFlurry.a; sourceTree = ""; }; @@ -41,6 +49,7 @@ files = ( FA09A376168AFD41008C1C7B /* Foundation.framework in Frameworks */, FAB6DFDD1756F22200C90D89 /* libFlurry.a in Frameworks */, + FA73FC9617A11E24007E23C2 /* libFlurryAds.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -50,10 +59,14 @@ FA09A367168AFD41008C1C7B = { isa = PBXGroup; children = ( + FA73FC8E17A11B84007E23C2 /* AdsFlurry.h */, + FA73FC8F17A11B84007E23C2 /* AdsFlurry.m */, + FA73FC9017A11B84007E23C2 /* PluginFlurry-Prefix.pch */, FAB6DFDE1756F29800C90D89 /* AnalyticsFlurry.h */, FAB6DFDF1756F29800C90D89 /* AnalyticsFlurry.m */, FAB6DFD81756F22200C90D89 /* Flurry.h */, FAB6DFDB1756F22200C90D89 /* libFlurry.a */, + FA73FC9217A11E24007E23C2 /* FlurryAds */, FA09A374168AFD41008C1C7B /* Frameworks */, FA09A373168AFD41008C1C7B /* Products */, ); @@ -76,6 +89,16 @@ name = Frameworks; sourceTree = ""; }; + FA73FC9217A11E24007E23C2 /* FlurryAds */ = { + isa = PBXGroup; + children = ( + FA73FC9317A11E24007E23C2 /* FlurryAdDelegate.h */, + FA73FC9417A11E24007E23C2 /* FlurryAds.h */, + FA73FC9517A11E24007E23C2 /* libFlurryAds.a */, + ); + path = FlurryAds; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,6 +151,7 @@ buildActionMask = 2147483647; files = ( FAB6DFE01756F29800C90D89 /* AnalyticsFlurry.m in Sources */, + FA73FC9117A11B84007E23C2 /* AdsFlurry.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -200,6 +224,7 @@ "$(inherited)", "\"$(SRCROOT)/../platform/ios\"", "\"$(SRCROOT)\"", + "\"$(SRCROOT)/FlurryAds\"", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = PluginFlurry; @@ -221,6 +246,7 @@ "$(inherited)", "\"$(SRCROOT)/../platform/ios\"", "\"$(SRCROOT)\"", + "\"$(SRCROOT)/FlurryAds\"", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = PluginFlurry; diff --git a/plugin/samples/HelloAnalytics-JS/Classes/AppDelegate.cpp b/plugin/samples/HelloAnalytics-JS/Classes/AppDelegate.cpp index 9889832122..2e5330a1b8 100644 --- a/plugin/samples/HelloAnalytics-JS/Classes/AppDelegate.cpp +++ b/plugin/samples/HelloAnalytics-JS/Classes/AppDelegate.cpp @@ -23,7 +23,7 @@ AppDelegate::AppDelegate() AppDelegate::~AppDelegate() { - ScriptEngineManager::purgeSharedManager(); + ScriptEngineManager::destroyInstance(); } bool AppDelegate::applicationDidFinishLaunching() @@ -61,8 +61,8 @@ bool AppDelegate::applicationDidFinishLaunching() void AppDelegate::applicationDidEnterBackground() { Director::getInstance()->stopAnimation(); - SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); - SimpleAudioEngine::sharedEngine()->pauseAllEffects(); + SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); + SimpleAudioEngine::getInstance()->pauseAllEffects(); ScriptingCore* sc = ScriptingCore::getInstance(); jsval nsval; @@ -76,8 +76,8 @@ void AppDelegate::applicationDidEnterBackground() void AppDelegate::applicationWillEnterForeground() { Director::getInstance()->startAnimation(); - SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); - SimpleAudioEngine::sharedEngine()->resumeAllEffects(); + SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); + SimpleAudioEngine::getInstance()->resumeAllEffects(); ScriptingCore* sc = ScriptingCore::getInstance(); jsval nsval; diff --git a/plugin/samples/HelloAnalytics-JS/proj.android/build_native.sh b/plugin/samples/HelloAnalytics-JS/proj.android/build_native.sh index 62e0ebf499..fe1ce83858 100755 --- a/plugin/samples/HelloAnalytics-JS/proj.android/build_native.sh +++ b/plugin/samples/HelloAnalytics-JS/proj.android/build_native.sh @@ -35,6 +35,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory PLUGIN_ROOT="$DIR/../../.." diff --git a/plugin/samples/HelloAnalytics-JS/proj.android/jni/Application.mk b/plugin/samples/HelloAnalytics-JS/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100644 --- a/plugin/samples/HelloAnalytics-JS/proj.android/jni/Application.mk +++ b/plugin/samples/HelloAnalytics-JS/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/plugin/samples/HelloIAP-JS/Classes/AppDelegate.cpp b/plugin/samples/HelloIAP-JS/Classes/AppDelegate.cpp index f697317084..f3005181cb 100644 --- a/plugin/samples/HelloIAP-JS/Classes/AppDelegate.cpp +++ b/plugin/samples/HelloIAP-JS/Classes/AppDelegate.cpp @@ -23,7 +23,7 @@ AppDelegate::AppDelegate() AppDelegate::~AppDelegate() { - ScriptEngineManager::purgeSharedManager(); + ScriptEngineManager::destroyInstance(); } bool AppDelegate::applicationDidFinishLaunching() diff --git a/plugin/samples/HelloIAP-JS/proj.android/build_native.sh b/plugin/samples/HelloIAP-JS/proj.android/build_native.sh index 2cdd8693a5..65fa2e8c22 100755 --- a/plugin/samples/HelloIAP-JS/proj.android/build_native.sh +++ b/plugin/samples/HelloIAP-JS/proj.android/build_native.sh @@ -35,6 +35,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory PLUGIN_ROOT="$DIR/../../.." diff --git a/plugin/samples/HelloIAP-JS/proj.android/jni/Application.mk b/plugin/samples/HelloIAP-JS/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100755 --- a/plugin/samples/HelloIAP-JS/proj.android/jni/Application.mk +++ b/plugin/samples/HelloIAP-JS/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/plugin/samples/HelloPlugins/Classes/AppDelegate.cpp b/plugin/samples/HelloPlugins/Classes/AppDelegate.cpp index e77c27e7ef..458f96c4e1 100644 --- a/plugin/samples/HelloPlugins/Classes/AppDelegate.cpp +++ b/plugin/samples/HelloPlugins/Classes/AppDelegate.cpp @@ -40,7 +40,7 @@ void AppDelegate::applicationDidEnterBackground() { Director::getInstance()->stopAnimation(); // if you use SimpleAudioEngine, it must be pause - // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); + // SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); } // this function will be called when the app is active again @@ -48,5 +48,5 @@ void AppDelegate::applicationWillEnterForeground() { Director::getInstance()->startAnimation(); // if you use SimpleAudioEngine, it must resume here - // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); + // SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); } diff --git a/plugin/samples/HelloPlugins/Classes/Configs.h b/plugin/samples/HelloPlugins/Classes/Configs.h index 932428be14..815fcbd7e7 100644 --- a/plugin/samples/HelloPlugins/Classes/Configs.h +++ b/plugin/samples/HelloPlugins/Classes/Configs.h @@ -8,4 +8,43 @@ */ #define TEST_UC 0 +#define APP_NAME "HelloPlugins" + +/** + @brief Developer information of flurry + */ +#define FLURRY_KEY_IOS "KMGG7CD9WPK2TW4X9VR8" +#define FLURRY_KEY_ANDROID "SPKFH8KMPGHMMBWRBT5W" + +/** + @brief Developer information of Umeng + */ +#define UMENG_KEY_IOS "50d2b18c5270152187000097" +#define UMENG_KEY_ANDROID "" // umeng key for android is setted in AndroidManifest.xml + +/** + @brief Developer information of Admob + */ +#define ADMOB_ID_IOS "a1517500cc8f794" +#define ADMOB_ID_ANDROID "a1516fb6b16b12f" + +/** + @brief Developer information of Nd91 + */ +#define ND91_APPID "100010" +#define ND91_APPKEY "C28454605B9312157C2F76F27A9BCA2349434E546A6E9C75"; +#define ND91_ORIENTATION "landscape" + +/** + @brief Developer information of QH360 + */ +#define QH360_EXCHANGE_RATE "1" + +/** + @brief Developer information of UC + */ +#define UC_CPID "20087" +#define UC_GAME_ID "119474" +#define UC_SERVER_ID "1333" + #endif // __CONFIGS_H__ diff --git a/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.cpp b/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.cpp index 2df4bc307a..95de02478f 100644 --- a/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.cpp @@ -24,12 +24,14 @@ THE SOFTWARE. #include "TestAdsScene.h" #include "PluginManager.h" #include "HelloWorldScene.h" +#include "Configs.h" USING_NS_CC; using namespace cocos2d::plugin; const std::string s_aTestCases[] = { "Admob", + "Flurry", }; const std::string s_aTestPoses[] = { @@ -66,21 +68,28 @@ bool TestAds::init() { return false; } - + + _listener = new MyAdsListener(); _admob = dynamic_cast(PluginManager::getInstance()->loadPlugin("AdsAdmob")); + _flurryAds = dynamic_cast(PluginManager::getInstance()->loadPlugin("AdsFlurry")); TAdsDeveloperInfo devInfo; #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS - devInfo["AdmobID"] = "a1517500cc8f794"; + devInfo["AdmobID"] = ADMOB_ID_IOS; + devInfo["FlurryAppKey"] = FLURRY_KEY_IOS; #elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID - devInfo["AdmobID"] = "a1516fb6b16b12f"; + devInfo["AdmobID"] = ADMOB_ID_ANDROID; + devInfo["FlurryAppKey"] = FLURRY_KEY_ANDROID; #endif _admob->configDeveloperInfo(devInfo); - _listener = new MyAdsListener(); _admob->setAdsListener(_listener); _admob->setDebugMode(true); + _flurryAds->configDeveloperInfo(devInfo); + _flurryAds->setAdsListener(_listener); + _flurryAds->setDebugMode(true); + Size visibleSize = Director::getInstance()->getVisibleSize(); Point origin = Director::getInstance()->getVisibleOrigin(); Point posMid = Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2); @@ -143,6 +152,8 @@ bool TestAds::init() // init the AdsInfo adInfo["AdmobType"] = "1"; adInfo["AdmobSizeEnum"] = "1"; + adInfo["FlurryAdsID"] = "BANNER_MAIN_VC"; + adInfo["FlurryAdsSize"] = "2"; this->addChild(pMenu, 1); @@ -190,6 +201,10 @@ void TestAds::caseChanged(Object* pSender) _ads = _admob; strLog = "Admob"; break; + case 1: + _ads = _flurryAds; + strLog = "Flurry Ads"; + break; default: break; } diff --git a/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.h b/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.h index ffabe943f6..09539a2013 100644 --- a/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.h +++ b/plugin/samples/HelloPlugins/Classes/TestAds/TestAdsScene.h @@ -58,6 +58,7 @@ public: private: cocos2d::plugin::ProtocolAds* _admob; + cocos2d::plugin::ProtocolAds* _flurryAds; MyAdsListener* _listener; cocos2d::MenuItemToggle* _caseItem; diff --git a/plugin/samples/HelloPlugins/Classes/TestAnalytics/TestAnalyticsScene.cpp b/plugin/samples/HelloPlugins/Classes/TestAnalytics/TestAnalyticsScene.cpp index a49d39051b..ae90b861f2 100644 --- a/plugin/samples/HelloPlugins/Classes/TestAnalytics/TestAnalyticsScene.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestAnalytics/TestAnalyticsScene.cpp @@ -24,16 +24,11 @@ THE SOFTWARE. #include "TestAnalyticsScene.h" #include "PluginManager.h" #include "HelloWorldScene.h" +#include "Configs.h" using namespace cocos2d; using namespace cocos2d::plugin; -// The app key of flurry -#define FLURRY_KEY_IOS "KMGG7CD9WPK2TW4X9VR8" -#define FLURRY_KEY_ANDROID "SPKFH8KMPGHMMBWRBT5W" -#define UMENG_KEY_IOS "50d2b18c5270152187000097" -#define UMENG_KEY_ANDROID "" // umeng key for android is setted in AndroidManifest.xml - enum { TAG_LOG_EVENT_ID = 0, TAG_LOG_EVENT_ID_KV, @@ -118,7 +113,7 @@ bool TestAnalytics::init() std::string strVer = _pluginAnalytics->getSDKVersion(); char ret[256] = { 0 }; sprintf(ret, "Plugin : %s, Ver : %s", strName.c_str(), strVer.c_str()); - LabelTTF* pLabel = LabelTTF::create(ret, "Arial", 18, Point(visibleSize.width, 0), kTextAlignmentCenter); + LabelTTF* pLabel = LabelTTF::create(ret, "Arial", 18, Point(visibleSize.width, 0), Label::HAlignment::CENTER); pLabel->setPosition(Point(visibleSize.width / 2, yPos - 80)); addChild(pLabel); diff --git a/plugin/samples/HelloPlugins/Classes/TestIAP/MyPurchase.cpp b/plugin/samples/HelloPlugins/Classes/TestIAP/MyPurchase.cpp index 02dcdb51e7..bd809fe491 100644 --- a/plugin/samples/HelloPlugins/Classes/TestIAP/MyPurchase.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestIAP/MyPurchase.cpp @@ -24,6 +24,7 @@ THE SOFTWARE. #include "MyPurchase.h" #include "PluginManager.h" #include "cocos2d.h" +#include "Configs.h" using namespace cocos2d::plugin; using namespace cocos2d; @@ -90,9 +91,9 @@ void MyPurchase::loadIAPPlugin() { TIAPDeveloperInfo pNdInfo; - pNdInfo["Nd91AppId"] = "100010"; - pNdInfo["Nd91AppKey"] = "C28454605B9312157C2F76F27A9BCA2349434E546A6E9C75"; - pNdInfo["Nd91Orientation"] = "landscape"; + pNdInfo["Nd91AppId"] = ND91_APPID; + pNdInfo["Nd91AppKey"] = ND91_APPKEY; + pNdInfo["Nd91Orientation"] = ND91_ORIENTATION; if (pNdInfo.empty()) { char msg[256] = { 0 }; sprintf(msg, "Developer info is empty. PLZ fill your Nd91 info in %s(nearby line %d)", __FILE__, __LINE__); diff --git a/plugin/samples/HelloPlugins/Classes/TestIAPOnline/MyIAPOLManager.cpp b/plugin/samples/HelloPlugins/Classes/TestIAPOnline/MyIAPOLManager.cpp index 83da784f39..e58cb44f97 100644 --- a/plugin/samples/HelloPlugins/Classes/TestIAPOnline/MyIAPOLManager.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestIAPOnline/MyIAPOLManager.cpp @@ -78,8 +78,8 @@ void MyIAPOLManager::loadPlugins() // init qh360 plugin s_pQH360 = dynamic_cast(PluginManager::getInstance()->loadPlugin("IAPOnlineQH360")); TIAPDeveloperInfo pQH360Info; - pQH360Info["QHAppName"] = "HelloPlugins"; - pQH360Info["QHExchangeRate"] = "1"; + pQH360Info["QHAppName"] = APP_NAME; + pQH360Info["QHExchangeRate"] = QH360_EXCHANGE_RATE; s_pQH360->setDebugMode(true); s_pQH360->configDeveloperInfo(pQH360Info); @@ -88,9 +88,9 @@ void MyIAPOLManager::loadPlugins() { TIAPDeveloperInfo pNdInfo; - pNdInfo["Nd91AppId"] = "100010"; - pNdInfo["Nd91AppKey"] = "C28454605B9312157C2F76F27A9BCA2349434E546A6E9C75"; - pNdInfo["Nd91Orientation"] = "landscape"; + pNdInfo["Nd91AppId"] = ND91_APPID; + pNdInfo["Nd91AppKey"] = ND91_APPKEY; + pNdInfo["Nd91Orientation"] = ND91_ORIENTATION; s_pNd91 = dynamic_cast(PluginManager::getInstance()->loadPlugin("IAPOnlineNd91")); s_pNd91->setDebugMode(true); s_pNd91->configDeveloperInfo(pNdInfo); @@ -103,9 +103,9 @@ void MyIAPOLManager::loadPlugins() if (NULL != s_pUC) { TIAPDeveloperInfo pUCInfo; - pUCInfo["UCCpID"] = "20087"; - pUCInfo["UCGameID"] = "119474"; - pUCInfo["UCServerID"] = "1333"; + pUCInfo["UCCpID"] = UC_CPID; + pUCInfo["UCGameID"] = UC_GAME_ID; + pUCInfo["UCServerID"] = UC_SERVER_ID; s_pUC->setDebugMode(true); s_pUC->configDeveloperInfo(pUCInfo); s_pUC->setResultListener(s_pRetListener); diff --git a/plugin/samples/HelloPlugins/Classes/TestSocial/MySocialManager.cpp b/plugin/samples/HelloPlugins/Classes/TestSocial/MySocialManager.cpp index 21d790296a..bee711519e 100644 --- a/plugin/samples/HelloPlugins/Classes/TestSocial/MySocialManager.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestSocial/MySocialManager.cpp @@ -24,6 +24,7 @@ THE SOFTWARE. #include "MySocialManager.h" #include "PluginManager.h" #include "cocos2d.h" +#include "Configs.h" using namespace cocos2d::plugin; using namespace cocos2d; @@ -66,9 +67,9 @@ void MySocialManager::loadPlugins() if (NULL != _pNd91) { TSocialDeveloperInfo pNdInfo; - pNdInfo["Nd91AppId"] = "100010"; - pNdInfo["Nd91AppKey"] = "C28454605B9312157C2F76F27A9BCA2349434E546A6E9C75"; - pNdInfo["Nd91Orientation"] = "landscape"; + pNdInfo["Nd91AppId"] = ND91_APPID; + pNdInfo["Nd91AppKey"] = ND91_APPKEY; + pNdInfo["Nd91Orientation"] = ND91_ORIENTATION; if (pNdInfo.empty()) { char msg[256] = { 0 }; sprintf(msg, "Developer info is empty. PLZ fill your Nd91 info in %s(nearby line %d)", __FILE__, __LINE__); diff --git a/plugin/samples/HelloPlugins/Classes/TestUser/MyUserManager.cpp b/plugin/samples/HelloPlugins/Classes/TestUser/MyUserManager.cpp index 456b525969..b7865413ea 100644 --- a/plugin/samples/HelloPlugins/Classes/TestUser/MyUserManager.cpp +++ b/plugin/samples/HelloPlugins/Classes/TestUser/MyUserManager.cpp @@ -24,6 +24,7 @@ THE SOFTWARE. #include "MyUserManager.h" #include "PluginManager.h" #include "cocos2d.h" +#include "Configs.h" using namespace cocos2d::plugin; using namespace cocos2d; @@ -89,9 +90,9 @@ void MyUserManager::loadPlugin() if (NULL != _nd91) { TUserDeveloperInfo pNdInfo; - pNdInfo["Nd91AppId"] = "100010"; - pNdInfo["Nd91AppKey"] = "C28454605B9312157C2F76F27A9BCA2349434E546A6E9C75"; - pNdInfo["Nd91Orientation"] = "landscape"; + pNdInfo["Nd91AppId"] = ND91_APPID; + pNdInfo["Nd91AppKey"] = ND91_APPKEY; + pNdInfo["Nd91Orientation"] = ND91_ORIENTATION; if (pNdInfo.empty()) { char msg[256] = { 0 }; sprintf(msg, "Developer info is empty. PLZ fill your Nd91 info in %s(nearby line %d)", __FILE__, __LINE__); @@ -109,9 +110,9 @@ void MyUserManager::loadPlugin() if (NULL != _uc) { TUserDeveloperInfo pUCInfo; - pUCInfo["UCCpID"] = "20087"; - pUCInfo["UCGameID"] = "119474"; - pUCInfo["UCServerID"] = "1333"; + pUCInfo["UCCpID"] = UC_CPID; + pUCInfo["UCGameID"] = UC_GAME_ID; + pUCInfo["UCServerID"] = UC_SERVER_ID; if (pUCInfo.empty()) { char msg[256] = { 0 }; sprintf(msg, "Developer info is empty. PLZ fill your UC info in %s(nearby line %d)", __FILE__, __LINE__); diff --git a/plugin/samples/HelloPlugins/proj.android/AndroidManifest.xml b/plugin/samples/HelloPlugins/proj.android/AndroidManifest.xml index dfd7dcb2e6..9837e46cbb 100644 --- a/plugin/samples/HelloPlugins/proj.android/AndroidManifest.xml +++ b/plugin/samples/HelloPlugins/proj.android/AndroidManifest.xml @@ -32,6 +32,11 @@ + + + diff --git a/plugin/samples/HelloPlugins/proj.android/build_native.sh b/plugin/samples/HelloPlugins/proj.android/build_native.sh index a76848a0e4..ba5e6b061d 100755 --- a/plugin/samples/HelloPlugins/proj.android/build_native.sh +++ b/plugin/samples/HelloPlugins/proj.android/build_native.sh @@ -35,6 +35,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory PLUGIN_ROOT="$DIR/../../.." diff --git a/plugin/samples/HelloPlugins/proj.android/jni/Application.mk b/plugin/samples/HelloPlugins/proj.android/jni/Application.mk index 43499d7113..9caa13be80 100644 --- a/plugin/samples/HelloPlugins/proj.android/jni/Application.mk +++ b/plugin/samples/HelloPlugins/proj.android/jni/Application.mk @@ -1,3 +1,3 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -DCOCOS2D_DEBUG=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/plugin/tools/tojs/conversions.yaml b/plugin/tools/tojs/conversions.yaml index 992588048b..13f00a8389 100644 --- a/plugin/tools/tojs/conversions.yaml +++ b/plugin/tools/tojs/conversions.yaml @@ -40,8 +40,12 @@ conversions: TIAPDeveloperInfo: "ok &= jsval_to_TIAPDeveloperInfo(cx, ${in_value}, &${out_value})" TPaymentInfo: "ok &= jsval_to_TPaymentInfo(cx, ${in_value}, &${out_value})" TAdsDeveloperInfo: "ok &= jsval_to_TAdsDeveloperInfo(cx, ${in_value}, &${out_value})" + TAdsInfo: "ok &= jsval_to_TAdsInfo(cx, ${in_value}, &${out_value})" TShareDeveloperInfo: "ok &= jsval_to_TShareDeveloperInfo(cx, ${in_value}, &${out_value})" TShareInfo: "ok &= jsval_to_TShareInfo(cx, ${in_value}, &${out_value})" + TUserDeveloperInfo: "ok &= jsval_to_TUserDeveloperInfo(cx, ${in_value}, &${out_value})" + TSocialDeveloperInfo: "ok &= jsval_to_TSocialDeveloperInfo(cx, ${in_value}, &${out_value})" + TAchievementInfo: "ok &= jsval_to_TAchievementInfo(cx, ${in_value}, &${out_value})" LogEventParamMap*: | LogEventParamMap ${out_value}_tmp; ${($level + 0) * '\t'}do { @@ -62,11 +66,6 @@ conversions: float: "${out_value} = DOUBLE_TO_JSVAL(${in_value})" double: "${out_value} = DOUBLE_TO_JSVAL(${in_value})" TProductInfo: "${out_value} = TProductInfo_to_jsval(cx, ${in_value})" - TIAPDeveloperInfo: "${out_value} = TIAPDeveloperInfo_to_jsval(cx, ${in_value})" - TPaymentInfo: "${out_value} = TPaymentInfo_to_jsval(cx, ${in_value})" - TAdsDeveloperInfo: "${out_value} = TAdsDeveloperInfo_to_jsval(cx, ${in_value})" - TShareDeveloperInfo: "${out_value} = TShareDeveloperInfo_to_jsval(cx, ${in_value})" - TShareInfo: "${out_value} = TShareInfo_to_jsval(cx, ${in_value})" LogEventParamMap*: "${out_value} = LogEventParamMap_to_jsval(cx, ${in_value})" long: "${out_value} = long_to_jsval(cx, ${in_value})" diff --git a/plugin/tools/toolsForGame/addPluginForGame.sh b/plugin/tools/toolsForGame/addPluginForGame.sh index 2e117f1f5a..e2ee084316 100755 --- a/plugin/tools/toolsForGame/addPluginForGame.sh +++ b/plugin/tools/toolsForGame/addPluginForGame.sh @@ -41,11 +41,11 @@ if [ -d "${TARGET_ROOT}" ]; then # Modify mk file MK_FILE_PATH="${GAME_PROJECT_DIR}"/jni/Android.mk - ${SHELL_DIR}/modifyMk.sh "${MK_FILE_PATH}" + ${SHELL_DIR}/modifyMK.sh "${MK_FILE_PATH}" # Modify Application.mk file (add stl & rtti configuration) APP_MK_FILE_PATH="${GAME_PROJECT_DIR}"/jni/Application.mk - ${SHELL_DIR}/modifyAppMk.sh "${APP_MK_FILE_PATH}" + ${SHELL_DIR}/modifyAppMK.sh "${APP_MK_FILE_PATH}" # Combin ForRes directory to the res directory of game project GAME_RES_DIR="${GAME_PROJECT_DIR}"/res diff --git a/rpm/cocos2d-x.spec b/rpm/cocos2d-x.spec new file mode 100644 index 0000000000..c997278f21 --- /dev/null +++ b/rpm/cocos2d-x.spec @@ -0,0 +1,81 @@ +Name: cocos2d-x +Version: 1.0.0 +Release: 2 +Summary: Cocos2D-X Cross-Platform 2D Games Framework + +Group: System/GUI/Other +License: MIT +URL: http://cocos2d-x.org +Source: %{name}-%{version}.tar.bz2 +BuildRequires: pkgconfig(egl) +BuildRequires: pkgconfig(glesv2) +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Gui) +BuildRequires: pkgconfig(Qt5Multimedia) +BuildRequires: pkgconfig(Qt5Sensors) +BuildRequires: pkgconfig(zlib) +BuildRequires: pkgconfig(fontconfig) +BuildRequires: pkgconfig(freetype2) +BuildRequires: pkgconfig(libpng) +BuildRequires: pkgconfig(libtiff-4) +BuildRequires: libjpeg-turbo-devel +BuildRequires: pkgconfig(libcurl) + +%description +cocos2d-x is a multi-platform 2D game framework in C++, +branched on cocos2d-iphone and licensed under MIT. + +%package tests +Summary: Cocos2D-X Test Applications +Group: Development/Libraries +Requires: %{name} = %{version} + +%description tests +cocos2d-x is a multi-platform 2D game framework in C++, +branched on cocos2d-iphone and licensed under MIT. + +This package contains test applications for Cocos2D-X. + +%package devel +Summary: Cocos2D-X Development Libraries +Group: Development/Libraries +Requires: %{name} = %{version} + +%description devel +cocos2d-x is a multi-platform 2D game framework in C++, +branched on cocos2d-iphone and licensed under MIT. + +This package contains development libraries for Cocos2D-X. + +%prep +%setup -q + +%build +%qmake5 +make + +%install +make INSTALL_ROOT=%{buildroot} install + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-,root,root,-) +%doc README.mdown licenses +%{_libdir}/lib*.so.* + +%files tests +%defattr(-,root,root,-) +%doc README.mdown +/opt/cocos2dx_TestCpp/* +/usr/share/applications/*.desktop + +%files devel +%defattr(-,root,root,-) +%doc README.mdown AUTHORS CHANGELOG +%{_libdir}/lib*.so +#%{_includedir}/*/*.h diff --git a/samples/Cpp/AssetsManagerTest/proj.android/build_native.sh b/samples/Cpp/AssetsManagerTest/proj.android/build_native.sh index 12e6564c5b..cbf74a57d7 100755 --- a/samples/Cpp/AssetsManagerTest/proj.android/build_native.sh +++ b/samples/Cpp/AssetsManagerTest/proj.android/build_native.sh @@ -49,6 +49,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Cpp/AssetsManagerTest/proj.android/jni/Application.mk b/samples/Cpp/AssetsManagerTest/proj.android/jni/Application.mk index 83aeced7b6..7d9d576f0c 100644 --- a/samples/Cpp/AssetsManagerTest/proj.android/jni/Application.mk +++ b/samples/Cpp/AssetsManagerTest/proj.android/jni/Application.mk @@ -1,4 +1,3 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 \ No newline at end of file diff --git a/samples/Cpp/HelloCpp/Classes/HelloWorldScene.cpp b/samples/Cpp/HelloCpp/Classes/HelloWorldScene.cpp index e07234d078..90d1aa3266 100644 --- a/samples/Cpp/HelloCpp/Classes/HelloWorldScene.cpp +++ b/samples/Cpp/HelloCpp/Classes/HelloWorldScene.cpp @@ -41,8 +41,7 @@ bool HelloWorld::init() "CloseSelected.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback,this)); - closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , - origin.y + closeItem->getContentSize().height/2)); + closeItem->setPosition(origin + Point(visibleSize) - Point(closeItem->getContentSize() / 2)); // create menu, it's an autorelease object Menu* menu = Menu::create(closeItem, NULL); @@ -68,7 +67,7 @@ bool HelloWorld::init() Sprite* sprite = Sprite::create("HelloWorld.png"); // position the sprite on the center of the screen - sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); + sprite->setPosition(Point(visibleSize / 2) + origin); // add the sprite as a child to this layer this->addChild(sprite, 0); diff --git a/samples/Cpp/HelloCpp/proj.android/build_native.sh b/samples/Cpp/HelloCpp/proj.android/build_native.sh index 5a91b70245..684f0d9886 100755 --- a/samples/Cpp/HelloCpp/proj.android/build_native.sh +++ b/samples/Cpp/HelloCpp/proj.android/build_native.sh @@ -49,6 +49,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Cpp/HelloCpp/proj.android/jni/Application.mk b/samples/Cpp/HelloCpp/proj.android/jni/Application.mk index d06f06e718..988bf2fadc 100644 --- a/samples/Cpp/HelloCpp/proj.android/jni/Application.mk +++ b/samples/Cpp/HelloCpp/proj.android/jni/Application.mk @@ -1,3 +1,2 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_DEBUG=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 \ No newline at end of file diff --git a/samples/Cpp/HelloCpp/proj.emscripten/main.cpp b/samples/Cpp/HelloCpp/proj.emscripten/main.cpp index 0ca97400a4..2f1356c548 100644 --- a/samples/Cpp/HelloCpp/proj.emscripten/main.cpp +++ b/samples/Cpp/HelloCpp/proj.emscripten/main.cpp @@ -13,7 +13,7 @@ int main(int argc, char **argv) // create the application instance AppDelegate app; - EGLView* eglView = EGLView::getInstance(); + EGLView::getInstance(); return Application::getInstance()->run(); } diff --git a/samples/Cpp/HelloCpp/proj.qt5/HelloCpp.pro b/samples/Cpp/HelloCpp/proj.qt5/HelloCpp.pro new file mode 100644 index 0000000000..3f194de311 --- /dev/null +++ b/samples/Cpp/HelloCpp/proj.qt5/HelloCpp.pro @@ -0,0 +1,14 @@ + +include(../../../../cocos2dx/proj.qt5/common.pri) + +TARGET = HelloCpp + +INCLUDEPATH += .. +INCLUDEPATH += ../Classes + +SOURCES += main.cpp +SOURCES += ../Classes/AppDelegate.cpp +SOURCES += ../Classes/HelloWorldScene.cpp + +LIBS += $${LINK_AGAINST_COCOS2DX} + diff --git a/samples/Cpp/HelloCpp/proj.qt5/main.cpp b/samples/Cpp/HelloCpp/proj.qt5/main.cpp new file mode 100644 index 0000000000..f48c450399 --- /dev/null +++ b/samples/Cpp/HelloCpp/proj.qt5/main.cpp @@ -0,0 +1,21 @@ + +#include "../Classes/AppDelegate.h" +#include "cocos2d.h" + +#include +#include +#include +#include + +USING_NS_CC; + +int main(int argc, char **argv) +{ + // create the application instance + AppDelegate app; + + CCEGLView* eglView = CCEGLView::sharedOpenGLView(); + eglView->setFrameSize(800, 480); + + return CCApplication::sharedApplication()->run(); +} diff --git a/samples/Cpp/SimpleGame/Classes/HelloWorldScene.h b/samples/Cpp/SimpleGame/Classes/HelloWorldScene.h index bb5ac961dc..7a48f48bad 100644 --- a/samples/Cpp/SimpleGame/Classes/HelloWorldScene.h +++ b/samples/Cpp/SimpleGame/Classes/HelloWorldScene.h @@ -3,7 +3,7 @@ #include "cocos2d.h" -#include "SimpleAudioEngine.h" +//#include "SimpleAudioEngine.h" class HelloWorld : public cocos2d::LayerColor { @@ -44,4 +44,4 @@ protected: }; -#endif // __HELLOWORLD_SCENE_H__ \ No newline at end of file +#endif // __HELLOWORLD_SCENE_H__ diff --git a/samples/Cpp/SimpleGame/proj.android/build_native.sh b/samples/Cpp/SimpleGame/proj.android/build_native.sh index 29be776c45..25feecb480 100755 --- a/samples/Cpp/SimpleGame/proj.android/build_native.sh +++ b/samples/Cpp/SimpleGame/proj.android/build_native.sh @@ -49,6 +49,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Cpp/SimpleGame/proj.android/jni/Application.mk b/samples/Cpp/SimpleGame/proj.android/jni/Application.mk index d06f06e718..988bf2fadc 100644 --- a/samples/Cpp/SimpleGame/proj.android/jni/Application.mk +++ b/samples/Cpp/SimpleGame/proj.android/jni/Application.mk @@ -1,3 +1,2 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_DEBUG=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 \ No newline at end of file diff --git a/samples/Cpp/SimpleGame/proj.qt5/SimpleGame.pro b/samples/Cpp/SimpleGame/proj.qt5/SimpleGame.pro new file mode 100644 index 0000000000..9626f7c123 --- /dev/null +++ b/samples/Cpp/SimpleGame/proj.qt5/SimpleGame.pro @@ -0,0 +1,16 @@ + +include(../../../../cocos2dx/proj.qt5/common.pri) + +TARGET = SimpleGame + +INCLUDEPATH += .. +INCLUDEPATH += ../Classes + +SOURCES += main.cpp +SOURCES += ../Classes/AppDelegate.cpp +SOURCES += ../Classes/HelloWorldScene.cpp +SOURCES += ../Classes/GameOverScene.cpp + +LIBS += $${LINK_AGAINST_COCOS2DX} +LIBS += $${LINK_AGAINST_COCOSDENSHION} + diff --git a/samples/Cpp/SimpleGame/proj.qt5/main.cpp b/samples/Cpp/SimpleGame/proj.qt5/main.cpp new file mode 100644 index 0000000000..fbaeec114b --- /dev/null +++ b/samples/Cpp/SimpleGame/proj.qt5/main.cpp @@ -0,0 +1,20 @@ +#include "../Classes/AppDelegate.h" +#include "cocos2d.h" + +#include +#include +#include +#include + +USING_NS_CC; + +int main(int argc, char **argv) +{ + // create the application instance + AppDelegate app; + + CCEGLView* eglView = CCEGLView::sharedOpenGLView(); + eglView->setFrameSize(800, 480); + + return CCApplication::sharedApplication()->run(); +} diff --git a/samples/Cpp/TestCpp/Classes/Box2DTest/Box2dTest.cpp b/samples/Cpp/TestCpp/Classes/Box2DTest/Box2dTest.cpp index aa75313475..73c09022b0 100644 --- a/samples/Cpp/TestCpp/Classes/Box2DTest/Box2dTest.cpp +++ b/samples/Cpp/TestCpp/Classes/Box2DTest/Box2dTest.cpp @@ -141,7 +141,7 @@ void Box2DTestLayer::draw() Layer::draw(); #if CC_ENABLE_BOX2D_INTEGRATION - ccGLEnableVertexAttribs( VERTEX_ATTRIB_FLAG_POSITION ); + GL::enableVertexAttribs( cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION ); kmGLPushMatrix(); diff --git a/samples/Cpp/TestCpp/Classes/Box2DTestBed/Test.h b/samples/Cpp/TestCpp/Classes/Box2DTestBed/Test.h index bbad5e2725..a2dc2b9243 100644 --- a/samples/Cpp/TestCpp/Classes/Box2DTestBed/Test.h +++ b/samples/Cpp/TestCpp/Classes/Box2DTestBed/Test.h @@ -153,10 +153,10 @@ public: virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); } // Callbacks for derived classes. - virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); } - virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); } - virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold); - virtual void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse) + virtual void BeginContact(b2Contact* contact) override { B2_NOT_USED(contact); } + virtual void EndContact(b2Contact* contact) override { B2_NOT_USED(contact); } + virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override; + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override { B2_NOT_USED(contact); B2_NOT_USED(impulse); diff --git a/samples/Cpp/TestCpp/Classes/ClippingNodeTest/ClippingNodeTest.cpp b/samples/Cpp/TestCpp/Classes/ClippingNodeTest/ClippingNodeTest.cpp index 9f9733ad6e..970dbbe058 100644 --- a/samples/Cpp/TestCpp/Classes/ClippingNodeTest/ClippingNodeTest.cpp +++ b/samples/Cpp/TestCpp/Classes/ClippingNodeTest/ClippingNodeTest.cpp @@ -784,13 +784,14 @@ void RawStencilBufferTest6::setup() { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) Point winPoint = Point(Director::getInstance()->getWinSize()); - unsigned char bits = 0; + //by default, glReadPixels will pack data with 4 bytes allignment + unsigned char bits[4] = {0,0,0,0}; glStencilMask(~0); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); glFlush(); glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &bits); - LabelTTF *clearToZeroLabel = LabelTTF::create(String::createWithFormat("00=%02x", bits)->getCString(), "Arial", 20); + LabelTTF *clearToZeroLabel = LabelTTF::create(String::createWithFormat("00=%02x", bits[0])->getCString(), "Arial", 20); clearToZeroLabel->setPosition( Point((winPoint.x / 3) * 1, winPoint.y - 10) ); this->addChild(clearToZeroLabel); glStencilMask(0x0F); @@ -798,7 +799,7 @@ void RawStencilBufferTest6::setup() glClear(GL_STENCIL_BUFFER_BIT); glFlush(); glReadPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &bits); - LabelTTF *clearToMaskLabel = LabelTTF::create(String::createWithFormat("0a=%02x", bits)->getCString(), "Arial", 20); + LabelTTF *clearToMaskLabel = LabelTTF::create(String::createWithFormat("0a=%02x", bits[0])->getCString(), "Arial", 20); clearToMaskLabel->setPosition( Point((winPoint.x / 3) * 2, winPoint.y - 10) ); this->addChild(clearToMaskLabel); #endif diff --git a/samples/Cpp/TestCpp/Classes/EffectsTest/EffectsTest.cpp b/samples/Cpp/TestCpp/Classes/EffectsTest/EffectsTest.cpp index 9603c0a0ae..655f063324 100644 --- a/samples/Cpp/TestCpp/Classes/EffectsTest/EffectsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/EffectsTest/EffectsTest.cpp @@ -366,6 +366,12 @@ TextLayer::TextLayer(void) ActionInterval* sc2_back = sc2->reverse(); tamara->runAction( RepeatForever::create(Sequence::create(sc2, sc2_back, NULL)) ); + LabelTTF* label = LabelTTF::create((effectsList[actionIdx]).c_str(), "Marker Felt", 32); + + label->setPosition( Point(VisibleRect::center().x,VisibleRect::top().y-80) ); + addChild(label); + label->setTag( kTagLabel ); + schedule( schedule_selector(TextLayer::checkAnim) ); } diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp index 244d5a7807..7224f6dc69 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp @@ -17,11 +17,12 @@ SEL_MenuHandler AnimationsTestLayer::onResolveCCBCCMenuItemSelector(Object * pTa return NULL; } -Control::Handler AnimationsTestLayer::onResolveCCBCCControlSelector(Object *pTarget, const char*pSelectorName) { - CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onControlButtonIdleClicked", AnimationsTestLayer::onControlButtonIdleClicked); - CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onControlButtonWaveClicked", AnimationsTestLayer::onControlButtonWaveClicked); - CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onControlButtonJumpClicked", AnimationsTestLayer::onControlButtonJumpClicked); - CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onControlButtonFunkyClicked", AnimationsTestLayer::onControlButtonFunkyClicked); +Control::Handler AnimationsTestLayer::onResolveCCBCCControlSelector(Object *pTarget, const char*pSelectorName) +{ + CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onCCControlButtonIdleClicked", AnimationsTestLayer::onControlButtonIdleClicked); + CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onCCControlButtonWaveClicked", AnimationsTestLayer::onControlButtonWaveClicked); + CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onCCControlButtonJumpClicked", AnimationsTestLayer::onControlButtonJumpClicked); + CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onCCControlButtonFunkyClicked", AnimationsTestLayer::onControlButtonFunkyClicked); return NULL; } diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp index a0d395531c..17a7ba9d1c 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp @@ -17,13 +17,13 @@ SEL_MenuHandler ButtonTestLayer::onResolveCCBCCMenuItemSelector(Object * pTarget } Control::Handler ButtonTestLayer::onResolveCCBCCControlSelector(Object * pTarget, const char * pSelectorName) { - CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onControlButtonClicked", ButtonTestLayer::onControlButtonClicked); + CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onCCControlButtonClicked", ButtonTestLayer::onControlButtonClicked); return NULL; } bool ButtonTestLayer::onAssignCCBMemberVariable(Object * pTarget, const char * pMemberVariableName, Node * pNode) { - CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "mControlEventLabel", LabelBMFont *, this->mControlEventLabel); + CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "mCCControlEventLabel", LabelBMFont *, this->mControlEventLabel); return false; } diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp index c6d7b62f98..72c85fe9d8 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp @@ -22,7 +22,7 @@ Control::Handler TimelineCallbackTestLayer::onResolveCCBCCControlSelector(Object return NULL; } -SEL_CallFuncN TimelineCallbackTestLayer::onResolveCCBCallFuncSelector(Object * pTarget, const char* pSelectorName) +SEL_CallFuncN TimelineCallbackTestLayer::onResolveCCBCCCallFuncSelector(Object * pTarget, const char* pSelectorName) { CCB_SELECTORRESOLVER_CALLFUNC_GLUE(this, "onCallback1", TimelineCallbackTestLayer::onCallback1); CCB_SELECTORRESOLVER_CALLFUNC_GLUE(this, "onCallback2", TimelineCallbackTestLayer::onCallback2); diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.h b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.h index bcf40bb17c..213c70c1e9 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.h +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.h @@ -17,7 +17,7 @@ class TimelineCallbackTestLayer virtual cocos2d::SEL_MenuHandler onResolveCCBCCMenuItemSelector(cocos2d::Object * pTarget, const char * pSelectorName); virtual cocos2d::extension::Control::Handler onResolveCCBCCControlSelector(cocos2d::Object * pTarget, const char * pSelectorName); - virtual cocos2d::SEL_CallFuncN onResolveCCBCallFuncSelector(Object * pTarget, const char* pSelectorName); + virtual cocos2d::SEL_CallFuncN onResolveCCBCCCallFuncSelector(Object * pTarget, const char* pSelectorName); virtual bool onAssignCCBMemberVariable(cocos2d::Object * pTarget, const char * pMemberVariableName, cocos2d::Node * node); void onCallback1(Node* sender); diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp index 771948a5d3..76c2df61ec 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp @@ -75,7 +75,7 @@ void HttpClientTest::onMenuGetTestClicked(cocos2d::Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://just-make-this-request-failed.com"); - request->setRequestType(HttpRequest::kHttpGet); + request->setRequestType(HttpRequest::Type::GET); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); request->setTag("GET test1"); HttpClient::getInstance()->send(request); @@ -87,7 +87,7 @@ void HttpClientTest::onMenuGetTestClicked(cocos2d::Object *sender) HttpRequest* request = new HttpRequest(); // required fields request->setUrl("http://httpbin.org/ip"); - request->setRequestType(HttpRequest::kHttpGet); + request->setRequestType(HttpRequest::Type::GET); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); // optional fields request->setTag("GET test2"); @@ -102,7 +102,7 @@ void HttpClientTest::onMenuGetTestClicked(cocos2d::Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/get"); - request->setRequestType(HttpRequest::kHttpGet); + request->setRequestType(HttpRequest::Type::GET); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); request->setTag("GET test3"); HttpClient::getInstance()->send(request); @@ -120,7 +120,7 @@ void HttpClientTest::onMenuPostTestClicked(cocos2d::Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/post"); - request->setRequestType(HttpRequest::kHttpPost); + request->setRequestType(HttpRequest::Type::POST); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); // write the post data @@ -136,7 +136,7 @@ void HttpClientTest::onMenuPostTestClicked(cocos2d::Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/post"); - request->setRequestType(HttpRequest::kHttpPost); + request->setRequestType(HttpRequest::Type::POST); std::vector headers; headers.push_back("Content-Type: application/json; charset=utf-8"); request->setHeaders(headers); @@ -159,7 +159,7 @@ void HttpClientTest::onMenuPostBinaryTestClicked(cocos2d::Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/post"); - request->setRequestType(HttpRequest::kHttpPost); + request->setRequestType(HttpRequest::Type::POST); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); // write the post data @@ -182,7 +182,7 @@ void HttpClientTest::onMenuPutTestClicked(Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/put"); - request->setRequestType(HttpRequest::kHttpPut); + request->setRequestType(HttpRequest::Type::PUT); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); // write the post data @@ -198,7 +198,7 @@ void HttpClientTest::onMenuPutTestClicked(Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/put"); - request->setRequestType(HttpRequest::kHttpPut); + request->setRequestType(HttpRequest::Type::PUT); std::vector headers; headers.push_back("Content-Type: application/json; charset=utf-8"); request->setHeaders(headers); @@ -223,7 +223,7 @@ void HttpClientTest::onMenuDeleteTestClicked(Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://just-make-this-request-failed.com"); - request->setRequestType(HttpRequest::kHttpDelete); + request->setRequestType(HttpRequest::Type::DELETE); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); request->setTag("DELETE test1"); HttpClient::getInstance()->send(request); @@ -234,7 +234,7 @@ void HttpClientTest::onMenuDeleteTestClicked(Object *sender) { HttpRequest* request = new HttpRequest(); request->setUrl("http://httpbin.org/delete"); - request->setRequestType(HttpRequest::kHttpDelete); + request->setRequestType(HttpRequest::Type::DELETE); request->setResponseCallback(this, httpresponse_selector(HttpClientTest::onHttpRequestCompleted)); request->setTag("DELETE test2"); HttpClient::getInstance()->send(request); diff --git a/samples/Cpp/TestCpp/Classes/FileUtilsTest/FileUtilsTest.cpp b/samples/Cpp/TestCpp/Classes/FileUtilsTest/FileUtilsTest.cpp index f8444c4ae9..b05cae1fa0 100644 --- a/samples/Cpp/TestCpp/Classes/FileUtilsTest/FileUtilsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/FileUtilsTest/FileUtilsTest.cpp @@ -181,9 +181,9 @@ void TestSearchPath::onEnter() if (fp) { size_t ret = fwrite(szBuf, 1, strlen(szBuf), fp); - CCASSERT(ret == 0, "fwrite function returned nonzero value"); + CCASSERT(ret != 0, "fwrite function returned zero value"); fclose(fp); - if (ret == 0) + if (ret != 0) log("Writing file to writable path succeed."); } diff --git a/samples/Cpp/TestCpp/Classes/MutiTouchTest/MutiTouchTest.cpp b/samples/Cpp/TestCpp/Classes/MutiTouchTest/MutiTouchTest.cpp index 0a2b9875cb..1ebfc2d410 100644 --- a/samples/Cpp/TestCpp/Classes/MutiTouchTest/MutiTouchTest.cpp +++ b/samples/Cpp/TestCpp/Classes/MutiTouchTest/MutiTouchTest.cpp @@ -1,12 +1,12 @@ #include "MutiTouchTest.h" -static Color3B s_TouchColors[CC_MAX_TOUCHES] = { - Color3B::YELLOW, - Color3B::BLUE, - Color3B::GREEN, - Color3B::RED, - Color3B::MAGENTA +static const Color3B* s_TouchColors[CC_MAX_TOUCHES] = { + &Color3B::YELLOW, + &Color3B::BLUE, + &Color3B::GREEN, + &Color3B::RED, + &Color3B::MAGENTA }; class TouchPoint : public Node @@ -79,7 +79,7 @@ void MutiTouchTestLayer::ccTouchesBegan(Set *touches, Event *event) Point location = touch->getLocation(); touchPoint->setTouchPos(location); - touchPoint->setTouchColor(s_TouchColors[touch->getID()]); + touchPoint->setTouchColor(*s_TouchColors[touch->getID()]); addChild(touchPoint); s_dic.setObject(touchPoint, touch->getID()); diff --git a/samples/Cpp/TestCpp/Classes/RenderTextureTest/RenderTextureTest.cpp b/samples/Cpp/TestCpp/Classes/RenderTextureTest/RenderTextureTest.cpp index 8c93958856..4ba33e79b1 100644 --- a/samples/Cpp/TestCpp/Classes/RenderTextureTest/RenderTextureTest.cpp +++ b/samples/Cpp/TestCpp/Classes/RenderTextureTest/RenderTextureTest.cpp @@ -448,15 +448,13 @@ RenderTextureTestDepthStencil::RenderTextureTestDepthStencil() //! mark sprite quad into stencil buffer glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - glColorMask(0, 0, 0, 1); + glStencilFunc(GL_NEVER, 1, 0xFF); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); sprite->visit(); //! move sprite half width and height, and draw only where not marked - sprite->setPosition(sprite->getPosition() + Point(sprite->getContentSize().width * sprite->getScale(), sprite->getContentSize().height * sprite->getScale() * 0.5)); + sprite->setPosition(sprite->getPosition() + Point(sprite->getContentSize().width * sprite->getScale() * 0.5, sprite->getContentSize().height * sprite->getScale() * 0.5)); glStencilFunc(GL_NOTEQUAL, 1, 0xFF); - glColorMask(1, 1, 1, 1); sprite->visit(); rend->end(); diff --git a/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.cpp b/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.cpp index f3e7aa92a2..0a18f30c50 100644 --- a/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.cpp +++ b/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.cpp @@ -64,6 +64,11 @@ static std::function createFunctions[] = CL(TextureDrawInRect), CL(TextureETC1), + + CL(TextureConvertRGB888), + CL(TextureConvertRGBA8888), + CL(TextureConvertI8), + CL(TextureConvertAI88), }; static unsigned int TEST_CASE_COUNT = sizeof(createFunctions) / sizeof(createFunctions[0]); @@ -1998,3 +2003,152 @@ std::string TextureETC1::subtitle() { return "only supported on android"; } + + +static void addImageToDemo(TextureDemo& demo, float x, float y, const char* path, Texture2D::PixelFormat format) +{ + Texture2D::setDefaultAlphaPixelFormat(format); + Sprite *sprite = Sprite::create(path); + sprite->setPosition(Point(x, y)); + demo.addChild(sprite, 0); + + // remove texture from texture manager + TextureCache::getInstance()->removeTexture(sprite->getTexture()); +} + +//TextureConvertRGB888 +void TextureConvertRGB888::onEnter() +{ + TextureDemo::onEnter(); + + Size s = Director::getInstance()->getWinSize(); + + LayerColor *background = LayerColor::create(Color4B(255,0,0,255), s.width, s.height); + addChild(background, -1); + + const char* img = "Images/test_image_rgb888.png"; + addImageToDemo(*this, 1*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA8888); + addImageToDemo(*this, 2*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB888); + addImageToDemo(*this, 3*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGB565); + addImageToDemo(*this, 4*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::A8); + addImageToDemo(*this, 5*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::I8); + addImageToDemo(*this, 6*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::AI88); + addImageToDemo(*this, 7*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA4444); + addImageToDemo(*this, 8*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB5A1); + + // restore default + Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT); + TextureCache::getInstance()->dumpCachedTextureInfo(); +} + +std::string TextureConvertRGB888::title() +{ + return "RGB888 convert test"; +} + +std::string TextureConvertRGB888::subtitle() +{ + return "RGBA8888,RGB888,RGB565,A8,I8,AI88,RGBA4444,RGB5A1"; +} +//TextureConvertRGBA8888 +void TextureConvertRGBA8888::onEnter() +{ + TextureDemo::onEnter(); + + Size s = Director::getInstance()->getWinSize(); + + LayerColor *background = LayerColor::create(Color4B(255,0,0,255), s.width, s.height); + addChild(background, -1); + + const char* img = "Images/test_image_rgba8888.png"; + addImageToDemo(*this, 1*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA8888); + addImageToDemo(*this, 2*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB888); + addImageToDemo(*this, 3*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGB565); + addImageToDemo(*this, 4*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::A8); + addImageToDemo(*this, 5*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::I8); + addImageToDemo(*this, 6*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::AI88); + addImageToDemo(*this, 7*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA4444); + addImageToDemo(*this, 8*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB5A1); + + // restore default + Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT); + TextureCache::getInstance()->dumpCachedTextureInfo(); +} + +std::string TextureConvertRGBA8888::title() +{ + return "RGBA8888 convert test"; +} + +std::string TextureConvertRGBA8888::subtitle() +{ + return "RGBA8888,RGB888,RGB565,A8,I8,AI88,RGBA4444,RGB5A1"; +} +//TextureConvertI8 +void TextureConvertI8::onEnter() +{ + TextureDemo::onEnter(); + + Size s = Director::getInstance()->getWinSize(); + + LayerColor *background = LayerColor::create(Color4B(255,0,0,255), s.width, s.height); + addChild(background, -1); + + const char* img = "Images/test_image_i8.png"; + addImageToDemo(*this, 1*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA8888); + addImageToDemo(*this, 2*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB888); + addImageToDemo(*this, 3*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGB565); + addImageToDemo(*this, 4*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::A8); + addImageToDemo(*this, 5*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::I8); + addImageToDemo(*this, 6*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::AI88); + addImageToDemo(*this, 7*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA4444); + addImageToDemo(*this, 8*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB5A1); + + // restore default + Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT); + TextureCache::getInstance()->dumpCachedTextureInfo(); +} + +std::string TextureConvertI8::title() +{ + return "I8 convert test"; +} + +std::string TextureConvertI8::subtitle() +{ + return "RGBA8888,RGB888,RGB565,A8,I8,AI88,RGBA4444,RGB5A1"; +} +//TextureConvertAI88 +void TextureConvertAI88::onEnter() +{ + TextureDemo::onEnter(); + + Size s = Director::getInstance()->getWinSize(); + + LayerColor *background = LayerColor::create(Color4B(255,0,0,255), s.width, s.height); + addChild(background, -1); + + const char* img = "Images/test_image_ai88.png"; + addImageToDemo(*this, 1*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA8888); + addImageToDemo(*this, 2*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB888); + addImageToDemo(*this, 3*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGB565); + addImageToDemo(*this, 4*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::A8); + addImageToDemo(*this, 5*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::I8); + addImageToDemo(*this, 6*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::AI88); + addImageToDemo(*this, 7*s.width/9, s.height/2+32, img, Texture2D::PixelFormat::RGBA4444); + addImageToDemo(*this, 8*s.width/9, s.height/2-32, img, Texture2D::PixelFormat::RGB5A1); + + // restore default + Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT); + TextureCache::getInstance()->dumpCachedTextureInfo(); +} + +std::string TextureConvertAI88::title() +{ + return "AI88 convert test"; +} + +std::string TextureConvertAI88::subtitle() +{ + return "RGBA8888,RGB888,RGB565,A8,I8,AI88,RGBA4444,RGB5A1"; +} diff --git a/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.h b/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.h index 581c4b59bb..4891a34d84 100644 --- a/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.h +++ b/samples/Cpp/TestCpp/Classes/Texture2dTest/Texture2dTest.h @@ -453,4 +453,40 @@ public: virtual std::string subtitle(); }; +// RGB888 texture convert test +class TextureConvertRGB888 : public TextureDemo +{ +public: + virtual void onEnter(); + virtual std::string title(); + virtual std::string subtitle(); +}; + +// RGBA8888 texture convert test +class TextureConvertRGBA8888 : public TextureDemo +{ +public: + virtual void onEnter(); + virtual std::string title(); + virtual std::string subtitle(); +}; + +// I8 texture convert test +class TextureConvertI8 : public TextureDemo +{ +public: + virtual void onEnter(); + virtual std::string title(); + virtual std::string subtitle(); +}; + +// AI88 texture convert test +class TextureConvertAI88 : public TextureDemo +{ +public: + virtual void onEnter(); + virtual std::string title(); + virtual std::string subtitle(); +}; + #endif // __TEXTURE2D_TEST_H__ diff --git a/samples/Cpp/TestCpp/proj.android/build_native.sh b/samples/Cpp/TestCpp/proj.android/build_native.sh index 9172deb176..dba0c405ec 100755 --- a/samples/Cpp/TestCpp/proj.android/build_native.sh +++ b/samples/Cpp/TestCpp/proj.android/build_native.sh @@ -49,6 +49,21 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Cpp/TestCpp/proj.android/jni/Application.mk b/samples/Cpp/TestCpp/proj.android/jni/Application.mk index 43499d7113..9caa13be80 100644 --- a/samples/Cpp/TestCpp/proj.android/jni/Application.mk +++ b/samples/Cpp/TestCpp/proj.android/jni/Application.mk @@ -1,3 +1,3 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -DCOCOS2D_DEBUG=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro b/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro new file mode 100644 index 0000000000..34bf701b04 --- /dev/null +++ b/samples/Cpp/TestCpp/proj.qt5/TestCpp.pro @@ -0,0 +1,127 @@ + +include(../../../../cocos2dx/proj.qt5/common.pri) + +TARGET = cocos2dx_TestCpp + +INCLUDEPATH += .. +INCLUDEPATH += ../Classes + +SOURCES += main.cpp +SOURCES += ../Classes/AccelerometerTest/AccelerometerTest.cpp \ + ../Classes/ActionManagerTest/ActionManagerTest.cpp \ + ../Classes/ActionsEaseTest/ActionsEaseTest.cpp \ + ../Classes/ActionsProgressTest/ActionsProgressTest.cpp \ + ../Classes/ActionsTest/ActionsTest.cpp \ + ../Classes/Box2DTest/Box2dTest.cpp \ + ../Classes/Box2DTestBed/Box2dView.cpp \ + ../Classes/Box2DTestBed/GLES-Render.cpp \ + ../Classes/Box2DTestBed/Test.cpp \ + ../Classes/Box2DTestBed/TestEntries.cpp \ + ../Classes/BugsTest/Bug-1159.cpp \ + ../Classes/BugsTest/Bug-1174.cpp \ + ../Classes/BugsTest/Bug-350.cpp \ + ../Classes/BugsTest/Bug-422.cpp \ + ../Classes/BugsTest/Bug-458/Bug-458.cpp \ + ../Classes/BugsTest/Bug-458/QuestionContainerSprite.cpp \ + ../Classes/BugsTest/Bug-624.cpp \ + ../Classes/BugsTest/Bug-886.cpp \ + ../Classes/BugsTest/Bug-899.cpp \ + ../Classes/BugsTest/Bug-914.cpp \ + ../Classes/BugsTest/BugsTest.cpp \ + ../Classes/ChipmunkTest/ChipmunkTest.cpp \ + ../Classes/ClickAndMoveTest/ClickAndMoveTest.cpp \ + ../Classes/ClippingNodeTest/ClippingNodeTest.cpp \ + ../Classes/CocosDenshionTest/CocosDenshionTest.cpp \ + ../Classes/CurlTest/CurlTest.cpp \ + ../Classes/CurrentLanguageTest/CurrentLanguageTest.cpp \ + ../Classes/DrawPrimitivesTest/DrawPrimitivesTest.cpp \ + ../Classes/EffectsAdvancedTest/EffectsAdvancedTest.cpp \ + ../Classes/EffectsTest/EffectsTest.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/CocosBuilderTest.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/HelloCocosBuilder/HelloCocosBuilderLayer.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/MenuTest/MenuTestLayer.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/TestHeader/TestHeaderLayer.cpp \ + ../Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlButtonTest/CCControlButtonTest.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlColourPicker/CCControlColourPickerTest.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlScene.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSceneManager.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSliderTest/CCControlSliderTest.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlSwitchTest/CCControlSwitchTest.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlPotentiometerTest/CCControlPotentiometerTest.cpp \ + ../Classes/ExtensionsTest/ControlExtensionTest/CCControlStepperTest/CCControlStepperTest.cpp \ + ../Classes/ExtensionsTest/TableViewTest/TableViewTestScene.cpp \ + ../Classes/ExtensionsTest/TableViewTest/CustomTableViewCell.cpp \ + ../Classes/ExtensionsTest/ExtensionsTest.cpp \ + ../Classes/ExtensionsTest/NotificationCenterTest/NotificationCenterTest.cpp \ + ../Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/ComponentsTestScene.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/EnemyController.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/GameOverScene.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/PlayerController.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/ProjectileController.cpp \ + ../Classes/ExtensionsTest/ComponentsTest/SceneController.cpp \ + ../Classes/ExtensionsTest/ArmatureTest/ArmatureScene.cpp \ + ../Classes/ExtensionsTest/Scale9SpriteTest/Scale9SpriteTest.cpp \ + ../Classes/FontTest/FontTest.cpp \ + ../Classes/IntervalTest/IntervalTest.cpp \ + ../Classes/KeyboardTest/KeyboardTest.cpp \ + ../Classes/KeypadTest/KeypadTest.cpp \ + ../Classes/LabelTest/LabelTest.cpp \ + ../Classes/LayerTest/LayerTest.cpp \ + ../Classes/MenuTest/MenuTest.cpp \ + ../Classes/MotionStreakTest/MotionStreakTest.cpp \ + ../Classes/MutiTouchTest/MutiTouchTest.cpp \ + ../Classes/NodeTest/NodeTest.cpp \ + ../Classes/ParallaxTest/ParallaxTest.cpp \ + ../Classes/ParticleTest/ParticleTest.cpp \ + ../Classes/PerformanceTest/PerformanceNodeChildrenTest.cpp \ + ../Classes/PerformanceTest/PerformanceParticleTest.cpp \ + ../Classes/PerformanceTest/PerformanceSpriteTest.cpp \ + ../Classes/PerformanceTest/PerformanceTest.cpp \ + ../Classes/PerformanceTest/PerformanceTextureTest.cpp \ + ../Classes/PerformanceTest/PerformanceTouchesTest.cpp \ + ../Classes/RenderTextureTest/RenderTextureTest.cpp \ + ../Classes/RotateWorldTest/RotateWorldTest.cpp \ + ../Classes/SceneTest/SceneTest.cpp \ + ../Classes/SchedulerTest/SchedulerTest.cpp \ + ../Classes/ShaderTest/ShaderTest.cpp \ + ../Classes/SpriteTest/SpriteTest.cpp \ + ../Classes/TextInputTest/TextInputTest.cpp \ + ../Classes/Texture2dTest/Texture2dTest.cpp \ + ../Classes/TexturePackerEncryptionTest/TextureAtlasEncryptionTest.cpp \ + ../Classes/TextureCacheTest/TextureCacheTest.cpp \ + ../Classes/TileMapTest/TileMapTest.cpp \ + ../Classes/TouchesTest/Ball.cpp \ + ../Classes/TouchesTest/Paddle.cpp \ + ../Classes/TouchesTest/TouchesTest.cpp \ + ../Classes/TransitionsTest/TransitionsTest.cpp \ + ../Classes/UserDefaultTest/UserDefaultTest.cpp \ + ../Classes/ZwoptexTest/ZwoptexTest.cpp \ + ../Classes/FileUtilsTest/FileUtilsTest.cpp \ + ../Classes/SpineTest/SpineTest.cpp \ + ../Classes/DataVisitorTest/DataVisitorTest.cpp \ + ../Classes/ConfigurationTest/ConfigurationTest.cpp \ + ../Classes/controller.cpp \ + ../Classes/testBasic.cpp \ + ../Classes/AppDelegate.cpp \ + ../Classes/BaseTest.cpp \ + ../Classes/VisibleRect.cpp + +LIBS += $${LINK_AGAINST_COCOS2DX} +LIBS += $${LINK_AGAINST_COCOSDENSHION} +LIBS += $${LINK_AGAINST_COCOSEXTENSION} + +INSTALLS += target +target.path = /opt/$${TARGET} + +INSTALLS += desktop +desktop.files = $${TARGET}.desktop +desktop.path = $${DESKTOP_INSTALL_DIR} + +INSTALLS += resources +resources.files = icon.png ../Resources +resources.path = /opt/$${TARGET} + diff --git a/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop b/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop new file mode 100644 index 0000000000..8447988c7f --- /dev/null +++ b/samples/Cpp/TestCpp/proj.qt5/cocos2dx_TestCpp.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Application +Name=Cocos2D-X +Icon=/opt/cocos2dx_TestCpp/icon.png +Exec=/opt/cocos2dx_TestCpp/cocos2dx_TestCpp diff --git a/samples/Cpp/TestCpp/proj.qt5/main.cpp b/samples/Cpp/TestCpp/proj.qt5/main.cpp new file mode 100644 index 0000000000..c77a203887 --- /dev/null +++ b/samples/Cpp/TestCpp/proj.qt5/main.cpp @@ -0,0 +1,19 @@ +#include "../Classes/AppDelegate.h" +#include "cocos2d.h" +#include "CCEGLView.h" + +#include +#include +#include +#include + +USING_NS_CC; + +int main(int argc, char **argv) +{ + // create the application instance + AppDelegate app; + CCEGLView* eglView = CCEGLView::sharedOpenGLView(); + eglView->setFrameSize(800, 480); + return CCApplication::sharedApplication()->run(); +} diff --git a/samples/Javascript/CocosDragonJS/Classes/AppDelegate.cpp b/samples/Javascript/CocosDragonJS/Classes/AppDelegate.cpp index 54248f8c7a..f4032775d8 100644 --- a/samples/Javascript/CocosDragonJS/Classes/AppDelegate.cpp +++ b/samples/Javascript/CocosDragonJS/Classes/AppDelegate.cpp @@ -25,7 +25,7 @@ AppDelegate::AppDelegate() AppDelegate::~AppDelegate() { - ScriptEngineManager::purgeSharedManager(); + ScriptEngineManager::destroyInstance(); } bool AppDelegate::applicationDidFinishLaunching() @@ -43,8 +43,8 @@ bool AppDelegate::applicationDidFinishLaunching() std::vector resDirOrders; - TargetPlatform platform = Application::getInstance()->getTargetPlatform(); - if (platform == kTargetIphone || platform == kTargetIpad || platform == kTargetMacOS) + Platform platform = Application::getInstance()->getTargetPlatform(); + if (platform == Application::Platform::OS_IPHONE || platform == Application::Platform::OS_IPAD || platform == Application::Platform::OS_MAC) { std::vector searchPaths = FileUtils::getInstance()->getSearchPaths(); searchPaths.insert(searchPaths.begin(), "Published files iOS"); @@ -75,7 +75,7 @@ bool AppDelegate::applicationDidFinishLaunching() } } - else if (platform == kTargetAndroid || platform == kTargetWindows) + else if (platform == Application::Platform::OS_ANDROID || platform == Application::Platform::OS_WINDOWS) { if (screenSize.height > 960) { diff --git a/samples/Javascript/CocosDragonJS/proj.android/build_native.sh b/samples/Javascript/CocosDragonJS/proj.android/build_native.sh index a897fde8c3..5d50201a71 100755 --- a/samples/Javascript/CocosDragonJS/proj.android/build_native.sh +++ b/samples/Javascript/CocosDragonJS/proj.android/build_native.sh @@ -58,6 +58,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Javascript/CocosDragonJS/proj.android/jni/Application.mk b/samples/Javascript/CocosDragonJS/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100644 --- a/samples/Javascript/CocosDragonJS/proj.android/jni/Application.mk +++ b/samples/Javascript/CocosDragonJS/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Javascript/CrystalCraze/Classes/AppDelegate.cpp b/samples/Javascript/CrystalCraze/Classes/AppDelegate.cpp index 5c96cee8e8..2ff4bce996 100644 --- a/samples/Javascript/CrystalCraze/Classes/AppDelegate.cpp +++ b/samples/Javascript/CrystalCraze/Classes/AppDelegate.cpp @@ -40,8 +40,8 @@ bool AppDelegate::applicationDidFinishLaunching() std::vector searchPaths; std::vector resDirOrders; - TargetPlatform platform = Application::getInstance()->getTargetPlatform(); - if (platform == kTargetIphone || platform == kTargetIpad || platform == kTargetMacOS) + Application::Platform platform = Application::getInstance()->getTargetPlatform(); + if (platform == Application::Platform::OS_IPHONE || platform == Application::Platform::OS_IPAD || platform == Application::Platform::OS_MAC) { searchPaths.push_back("Published-iOS"); // Resources/Published-iOS FileUtils::getInstance()->setSearchPaths(searchPaths); @@ -58,7 +58,7 @@ bool AppDelegate::applicationDidFinishLaunching() FileUtils::getInstance()->setSearchResolutionsOrder(resDirOrders); } - else if (platform == kTargetAndroid || platform == kTargetWindows) + else if (platform == Application::Platform::OS_ANDROID || platform == Application::Platform::OS_WINDOWS) { // Comments it since opengles2.0 only supports texture size within 2048x2048. // if (screenSize.height > 1024) diff --git a/samples/Javascript/CrystalCraze/proj.android/build_native.sh b/samples/Javascript/CrystalCraze/proj.android/build_native.sh index 11415396fa..379ec6da8c 100755 --- a/samples/Javascript/CrystalCraze/proj.android/build_native.sh +++ b/samples/Javascript/CrystalCraze/proj.android/build_native.sh @@ -58,6 +58,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Javascript/CrystalCraze/proj.android/jni/Application.mk b/samples/Javascript/CrystalCraze/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100644 --- a/samples/Javascript/CrystalCraze/proj.android/jni/Application.mk +++ b/samples/Javascript/CrystalCraze/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Javascript/MoonWarriors/proj.android/build_native.sh b/samples/Javascript/MoonWarriors/proj.android/build_native.sh index 92128a413e..42484a8394 100755 --- a/samples/Javascript/MoonWarriors/proj.android/build_native.sh +++ b/samples/Javascript/MoonWarriors/proj.android/build_native.sh @@ -57,6 +57,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Javascript/MoonWarriors/proj.android/jni/Application.mk b/samples/Javascript/MoonWarriors/proj.android/jni/Application.mk index 9fa21e684e..4014245067 100644 --- a/samples/Javascript/MoonWarriors/proj.android/jni/Application.mk +++ b/samples/Javascript/MoonWarriors/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT= -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Javascript/Shared b/samples/Javascript/Shared index 4b2abcc698..714ea94824 160000 --- a/samples/Javascript/Shared +++ b/samples/Javascript/Shared @@ -1 +1 @@ -Subproject commit 4b2abcc698d5186c6c8d5cb336a6eefea0c15b52 +Subproject commit 714ea9482432a94a2d58ca265c97c61b5b369919 diff --git a/samples/Javascript/TestJavascript/proj.android/build_native.sh b/samples/Javascript/TestJavascript/proj.android/build_native.sh index 3bae11c304..4bbde54d56 100755 --- a/samples/Javascript/TestJavascript/proj.android/build_native.sh +++ b/samples/Javascript/TestJavascript/proj.android/build_native.sh @@ -57,6 +57,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Javascript/TestJavascript/proj.android/jni/Application.mk b/samples/Javascript/TestJavascript/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100644 --- a/samples/Javascript/TestJavascript/proj.android/jni/Application.mk +++ b/samples/Javascript/TestJavascript/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Javascript/WatermelonWithMe/Classes/AppDelegate.cpp b/samples/Javascript/WatermelonWithMe/Classes/AppDelegate.cpp index 7ea95f5ebf..6919f85fe9 100644 --- a/samples/Javascript/WatermelonWithMe/Classes/AppDelegate.cpp +++ b/samples/Javascript/WatermelonWithMe/Classes/AppDelegate.cpp @@ -21,7 +21,7 @@ AppDelegate::AppDelegate() AppDelegate::~AppDelegate() { - ScriptEngineManager::purgeSharedManager(); + ScriptEngineManager::destroyInstance(); } bool AppDelegate::applicationDidFinishLaunching() diff --git a/samples/Javascript/WatermelonWithMe/proj.android/build_native.sh b/samples/Javascript/WatermelonWithMe/proj.android/build_native.sh index 8545f0a954..71d135c9c6 100755 --- a/samples/Javascript/WatermelonWithMe/proj.android/build_native.sh +++ b/samples/Javascript/WatermelonWithMe/proj.android/build_native.sh @@ -57,6 +57,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Javascript/WatermelonWithMe/proj.android/jni/Application.mk b/samples/Javascript/WatermelonWithMe/proj.android/jni/Application.mk index 8e3c31147c..ee9712a9d8 100644 --- a/samples/Javascript/WatermelonWithMe/proj.android/jni/Application.mk +++ b/samples/Javascript/WatermelonWithMe/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 -std=c++11 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Lua/HelloLua/proj.android/build_native.sh b/samples/Lua/HelloLua/proj.android/build_native.sh index ffbe9e564f..7a7144497f 100755 --- a/samples/Lua/HelloLua/proj.android/build_native.sh +++ b/samples/Lua/HelloLua/proj.android/build_native.sh @@ -49,6 +49,20 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../../.." diff --git a/samples/Lua/HelloLua/proj.android/jni/Application.mk b/samples/Lua/HelloLua/proj.android/jni/Application.mk index 60500cd560..daad673c2b 100644 --- a/samples/Lua/HelloLua/proj.android/jni/Application.mk +++ b/samples/Lua/HelloLua/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_DEBUG=1 -std=c++11 APP_CPPFLAGS += -fexceptions -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Lua/HelloLua/proj.tizen/.cproject b/samples/Lua/HelloLua/proj.tizen/.cproject index e5a122e016..da7db8be8d 100644 --- a/samples/Lua/HelloLua/proj.tizen/.cproject +++ b/samples/Lua/HelloLua/proj.tizen/.cproject @@ -71,7 +71,7 @@ - @@ -157,6 +157,7 @@ + @@ -185,6 +186,7 @@ + @@ -608,7 +610,7 @@ - diff --git a/samples/Lua/TestLua/Resources/luaScript/ActionsTest/ActionsTest.lua b/samples/Lua/TestLua/Resources/luaScript/ActionsTest/ActionsTest.lua index 89f6232fee..bfd2c86334 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ActionsTest/ActionsTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ActionsTest/ActionsTest.lua @@ -284,18 +284,6 @@ end -------------------------------------- -- ActionCardinalSpline -------------------------------------- -local function drawCardinalSpline(array) - kmGLPushMatrix() - kmGLTranslatef(50, 50, 0) - ccDrawCardinalSpline(array, 0, 100) - kmGLPopMatrix() - - kmGLPushMatrix() - kmGLTranslatef(size.width / 2, 50, 0) - ccDrawCardinalSpline(array, 1, 100) - kmGLPopMatrix() -end - local function ActionCardinalSpline() local layer = CCLayer:create() initWithLayer(layer) @@ -323,7 +311,25 @@ local function ActionCardinalSpline() kathia:setPosition(CCPoint(size.width / 2, 50)) kathia:runAction(seq2) - drawCardinalSpline(array) + local function drawCardinalSpline() + kmGLPushMatrix() + kmGLTranslatef(50, 50, 0) + CCDrawPrimitives.ccDrawCardinalSpline(array, 0, 100) + kmGLPopMatrix() + + kmGLPushMatrix() + kmGLTranslatef(size.width / 2, 50, 0) + CCDrawPrimitives.ccDrawCardinalSpline(array, 1, 100) + kmGLPopMatrix() + end + + array:retain() + local glNode = gl.glNodeCreate() + glNode:setContentSize(CCSize(size.width, size.height)) + glNode:setAnchorPoint(CCPoint(0.5, 0.5)) + glNode:registerScriptDrawHandler(drawCardinalSpline) + layer:addChild(glNode,-10) + glNode:setPosition( size.width / 2, size.height / 2) Helper.titleLabel:setString("CardinalSplineBy / CardinalSplineAt") Helper.subtitleLabel:setString("Cardinal Spline paths.\nTesting different tensions for one array") @@ -333,15 +339,6 @@ end -------------------------------------- -- ActionCatmullRom -------------------------------------- -local function drawCatmullRom(array1, array2) - kmGLPushMatrix() - kmGLTranslatef(50, 50, 0) - ccDrawCatmullRom(array1, 50) - kmGLPopMatrix() - - ccDrawCatmullRom(array2,50) -end - local function ActionCatmullRom() local layer = CCLayer:create() initWithLayer(layer) @@ -376,10 +373,26 @@ local function ActionCatmullRom() local seq2 = CCSequence:createWithTwoActions(action2, reverse2) kathia:runAction(seq2) - drawCatmullRom(array, array2) + local function drawCatmullRom() + kmGLPushMatrix() + kmGLTranslatef(50, 50, 0) + CCDrawPrimitives.ccDrawCatmullRom(array, 50) + kmGLPopMatrix() - Helper.titleLabel:setString("CatmullRomBy / CatmullRomTo") - Helper.subtitleLabel:setString("Catmull Rom spline paths. Testing reverse too") + CCDrawPrimitives.ccDrawCatmullRom(array2,50) + end + + array:retain() + array2:retain() + local glNode = gl.glNodeCreate() + glNode:setContentSize(CCSize(size.width, size.height)) + glNode:setAnchorPoint(CCPoint(0.5, 0.5)) + glNode:registerScriptDrawHandler(drawCatmullRom) + layer:addChild(glNode,-10) + glNode:setPosition( size.width / 2, size.height / 2) + + Helper.titleLabel:setString("CatmullRomBy / CatmullRomTo") + Helper.subtitleLabel:setString("Catmull Rom spline paths. Testing reverse too") return layer end @@ -957,6 +970,21 @@ local function ActionFollow() layer:runAction(CCFollow:create(grossini, CCRect(0, 0, size.width * 2 - 100, size.height))) + local function draw() + local winSize = CCDirector:getInstance():getWinSize() + local x = winSize.width * 2 - 100 + local y = winSize.height + local vertices = { CCPoint(5, 5), CCPoint(x - 5, 5), CCPoint(x - 5,y - 5), CCPoint(5,y - 5) } + CCDrawPrimitives.ccDrawPoly(vertices, 4, true) + end + + local glNode = gl.glNodeCreate() + glNode:setContentSize(CCSize(size.width, size.height)) + glNode:setAnchorPoint(CCPoint(0.5, 0.5)) + glNode:registerScriptDrawHandler(draw) + layer:addChild(glNode,-10) + glNode:setPosition( size.width / 2, size.height / 2) + Helper.subtitleLabel:setString("Follow action") return layer end diff --git a/samples/Lua/TestLua/Resources/luaScript/DrawPrimitivesTest/DrawPrimitivesTest.lua b/samples/Lua/TestLua/Resources/luaScript/DrawPrimitivesTest/DrawPrimitivesTest.lua index b984fb4e37..dbd1d6a235 100644 --- a/samples/Lua/TestLua/Resources/luaScript/DrawPrimitivesTest/DrawPrimitivesTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/DrawPrimitivesTest/DrawPrimitivesTest.lua @@ -1,8 +1,8 @@ -require "DrawPrimitives" + local function drawPrimitivesMainLayer() local kItemTagBasic = 1000 - local testCount = 1 + local testCount = 2 local maxCases = testCount local curCase = 0 local size = CCDirector:getInstance():getWinSize() @@ -86,60 +86,69 @@ local function drawPrimitivesMainLayer() glNode:setAnchorPoint(CCPoint(0.5, 0.5)) local function primitivesDraw() - ccDrawLine(VisibleRect:leftBottom(), VisibleRect:rightTop() ) + CCDrawPrimitives.ccDrawLine(VisibleRect:leftBottom(), VisibleRect:rightTop() ) gl.lineWidth( 5.0 ) - ccDrawColor4B(255,0,0,255) - ccDrawLine( VisibleRect:leftTop(), VisibleRect:rightBottom() ) + CCDrawPrimitives.ccDrawColor4B(255,0,0,255) + CCDrawPrimitives.ccDrawLine( VisibleRect:leftTop(), VisibleRect:rightBottom() ) - ccPointSize(64) - ccDrawColor4B(0, 0, 255, 128) - ccDrawPoint(VisibleRect:center()) + + + CCDrawPrimitives.ccPointSize(64) + CCDrawPrimitives.ccDrawColor4B(0, 0, 255, 128) + CCDrawPrimitives.ccDrawPoint(VisibleRect:center()) local points = {CCPoint(60,60), CCPoint(70,70), CCPoint(60,70), CCPoint(70,60) } - ccPointSize(4) - ccDrawColor4B(0,255,255,255) - ccDrawPoints(points,4) + CCDrawPrimitives.ccPointSize(4) + CCDrawPrimitives.ccDrawColor4B(0,255,255,255) + CCDrawPrimitives.ccDrawPoints(points,4) gl.lineWidth(16) - ccDrawColor4B(0, 255, 0, 255) - ccDrawCircle( VisibleRect:center(), 100, 0, 10, false) + CCDrawPrimitives.ccDrawColor4B(0, 255, 0, 255) + CCDrawPrimitives.ccDrawCircle( VisibleRect:center(), 100, 0, 10, false) gl.lineWidth(2) - ccDrawColor4B(0, 255, 255, 255) - ccDrawCircle( VisibleRect:center(), 50, math.pi / 2, 50, true) - + CCDrawPrimitives.ccDrawColor4B(0, 255, 255, 255) + CCDrawPrimitives.ccDrawCircle( VisibleRect:center(), 50, math.pi / 2, 50, true) + gl.lineWidth(2) - ccDrawColor4B(255, 0, 255, 255) - ccDrawSolidCircle( VisibleRect:center() + CCPoint(140,0), 40, math.rad(90), 50, 1.0, 1.0) + CCDrawPrimitives.ccDrawColor4B(255, 0, 255, 255) + CCDrawPrimitives.ccDrawSolidCircle( VisibleRect:center() + CCPoint(140,0), 40, math.rad(90), 50, 1.0, 1.0) - - ccDrawColor4B(255, 255, 0, 255) gl.lineWidth(10) + CCDrawPrimitives.ccDrawColor4B(255, 255, 0, 255) local yellowPoints = { CCPoint(0,0), CCPoint(50,50), CCPoint(100,50), CCPoint(100,100), CCPoint(50,100)} - ccDrawPoly( yellowPoints, 5, false) + CCDrawPrimitives.ccDrawPoly( yellowPoints, 5, false) gl.lineWidth(1) local filledVertices = { CCPoint(0,120), CCPoint(50,120), CCPoint(50,170), CCPoint(25,200), CCPoint(0,170) } - local colorFilled = { 0.5, 0.5, 1, 1 } - ccDrawSolidPoly(filledVertices, 5, colorFilled) + CCDrawPrimitives.ccDrawSolidPoly(filledVertices, 5, Color4F(0.5, 0.5, 1, 1)) - ccDrawColor4B(255, 0, 255, 255) gl.lineWidth(2) + CCDrawPrimitives.ccDrawColor4B(255, 0, 255, 255) local closePoints= { CCPoint(30,130), CCPoint(30,230), CCPoint(50,200) } - ccDrawPoly( closePoints, 3, true) + CCDrawPrimitives.ccDrawPoly( closePoints, 3, true) - ccDrawQuadBezier(VisibleRect:leftTop(), VisibleRect:center(), VisibleRect:rightTop(), 50) + CCDrawPrimitives.ccDrawQuadBezier(VisibleRect:leftTop(), VisibleRect:center(), VisibleRect:rightTop(), 50) - ccDrawCubicBezier(VisibleRect:center(), CCPoint(VisibleRect:center().x + 30, VisibleRect:center().y + 50), CCPoint(VisibleRect:center().x + 60,VisibleRect:center().y - 50), VisibleRect:right(), 100) + CCDrawPrimitives.ccDrawCubicBezier(VisibleRect:center(), CCPoint(VisibleRect:center().x + 30, VisibleRect:center().y + 50), CCPoint(VisibleRect:center().x + 60,VisibleRect:center().y - 50), VisibleRect:right(), 100) local solidvertices = {CCPoint(60,160), CCPoint(70,190), CCPoint(100,190), CCPoint(90,160)} - local colorsolid= { 1, 1, 0, 1 } - ccDrawSolidPoly( solidvertices, 4, colorsolid ) + CCDrawPrimitives.ccDrawSolidPoly( solidvertices, 4, Color4F(1, 1, 0, 1) ) + + local array = CCPointArray:create(20) + array:addControlPoint(CCPoint(0, 0)) + array:addControlPoint(CCPoint(size.width / 2 - 30, 0)) + array:addControlPoint(CCPoint(size.width / 2 - 30, size.height - 80)) + array:addControlPoint(CCPoint(0, size.height - 80)) + array:addControlPoint(CCPoint(0, 0)) + CCDrawPrimitives.ccDrawCatmullRom( array, 5) + + CCDrawPrimitives.ccDrawCardinalSpline( array, 0,100) gl.lineWidth(1) - ccDrawColor4B(255,255,255,255) - ccPointSize(1) + CCDrawPrimitives.ccDrawColor4B(255,255,255,255) + CCDrawPrimitives.ccPointSize(1) end glNode:registerScriptDrawHandler(primitivesDraw) @@ -149,9 +158,54 @@ local function drawPrimitivesMainLayer() return layer end + local function createDrawNodeTest() + local layer = CCLayer:create() + + InitTitle(layer) + + local draw = CCDrawNode:create() + layer:addChild(draw, 10) + + --Draw 10 circles + for i=1, 10 do + draw:drawDot(CCPoint(size.width/2, size.height/2), 10*(10-i), Color4F(math.random(0,1), math.random(0,1), math.random(0,1), 1)) + end + + --Draw polygons + points = { CCPoint(size.height/4, 0), CCPoint(size.width, size.height / 5), CCPoint(size.width / 3 * 2, size.height) } + draw:drawPolygon(points, table.getn(points), Color4F(1,0,0,0.5), 4, Color4F(0,0,1,1)) + + local o = 80 + local w = 20 + local h = 50 + local star1 = { CCPoint( o + w, o - h), CCPoint(o + w * 2, o), CCPoint(o + w * 2 + h, o + w), CCPoint(o + w * 2, o + w * 2) } + + draw:drawPolygon(star1, table.getn(star1), Color4F(1,0,0,0.5), 1, Color4F(0,0,1,1)) + + o = 180 + w = 20 + h = 50 + local star2 = { + CCPoint(o, o), CCPoint(o + w, o - h), CCPoint(o + w * 2, o), --lower spike + CCPoint(o + w * 2 + h, o + w ), CCPoint(o + w * 2, o + w * 2), --right spike + CCPoint(o + w, o + w * 2 + h), CCPoint(o, o + w * 2), --top spike + CCPoint(o - h, o + w), --left spike + }; + + draw:drawPolygon(star2, table.getn(star2), Color4F(1,0,0,0.5), 1, Color4F(0,0,1,1)) + + draw:drawSegment(CCPoint(20,size.height), CCPoint(20,size.height/2), 10, Color4F(0, 1, 0, 1)) + + draw:drawSegment(CCPoint(10,size.height/2), CCPoint(size.width/2, size.height/2), 40, Color4F(1, 0, 1, 0.5)) + + return layer + end + local function createLayerByCurCase(curCase) if 0 == curCase then return createDrawPrimitivesEffect() + elseif 1 == curCase then + return createDrawNodeTest() end end diff --git a/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua b/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua index 3a1041f636..63707baeb8 100644 --- a/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua @@ -333,8 +333,8 @@ end function Atlas4.draw() local s = CCDirector:getInstance():getWinSize() - ccDrawLine( CCPoint(0, s.height/2), CCPoint(s.width, s.height/2) ) - ccDrawLine( CCPoint(s.width/2, 0), CCPoint(s.width/2, s.height) ) + CCDrawPrimitives.ccDrawLine( CCPoint(0, s.height/2), CCPoint(s.width, s.height/2) ) + CCDrawPrimitives.ccDrawLine( CCPoint(s.width/2, 0), CCPoint(s.width/2, s.height) ) end function Atlas4.step(dt) diff --git a/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua b/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua index 6f43f1fbef..4bdc7c1a45 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua @@ -655,7 +655,7 @@ local function DemoBigFlower() -- size, in pixels emitter:setStartSize(80.0) emitter:setStartSizeVar(40.0) - emitter:setEndSize(kParticleStartSizeEqualToEndSize) + emitter:setEndSize(kCCParticleStartSizeEqualToEndSize) -- emits per second emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife()) @@ -728,7 +728,7 @@ local function DemoRotFlower() -- size, in pixels emitter:setStartSize(30.0) emitter:setStartSizeVar(0) - emitter:setEndSize(kParticleStartSizeEqualToEndSize) + emitter:setEndSize(kCCParticleStartSizeEqualToEndSize) -- emits per second emitter:setEmissionRate(emitter:getTotalParticles() / emitter:getLife()) diff --git a/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua b/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua index ce4d95e5ff..2440455ac6 100644 --- a/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua @@ -695,10 +695,10 @@ local function draw() glLineWidth(3) - ccDrawLine( CCPoint(x, y), CCPoint((x+width), y) ) - ccDrawLine( CCPoint((x+width), y), CCPoint((x+width), (y+height)) ) - ccDrawLine( CCPoint((x+width), (y+height)), CCPoint(x, (y+height)) ) - ccDrawLine( CCPoint(x, (y+height)), CCPoint(x, y) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x, y), CCPoint((x+width), y) ) + CCDrawPrimitives.ccDrawLine( CCPoint((x+width), y), CCPoint((x+width), (y+height)) ) + CCDrawPrimitives.ccDrawLine( CCPoint((x+width), (y+height)), CCPoint(x, (y+height)) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x, (y+height)), CCPoint(x, y) ) glLineWidth(1) end @@ -764,10 +764,10 @@ local function draw() glLineWidth(3) - ccDrawLine( CCPoint(x,y), CCPoint(x+width,y) ) - ccDrawLine( CCPoint(x+width,y), CCPoint(x+width,y+height) ) - ccDrawLine( CCPoint(x+width,y+height), CCPoint(x,y+height) ) - ccDrawLine( CCPoint(x,y+height), CCPoint(x,y) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x,y), CCPoint(x+width,y) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x+width,y), CCPoint(x+width,y+height) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x+width,y+height), CCPoint(x,y+height) ) + CCDrawPrimitives.ccDrawLine( CCPoint(x,y+height), CCPoint(x,y) ) glLineWidth(1) end diff --git a/samples/Lua/TestLua/proj.android/build_native.sh b/samples/Lua/TestLua/proj.android/build_native.sh index 8ac23114e7..661dde8e12 100755 --- a/samples/Lua/TestLua/proj.android/build_native.sh +++ b/samples/Lua/TestLua/proj.android/build_native.sh @@ -49,6 +49,21 @@ echo "NDK_ROOT not defined. Please define NDK_ROOT in your environment or in loc exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + + if [ -z "${COCOS2DX_ROOT+aaa}" ]; then # ... if COCOS2DX_ROOT is not set # ... find current working directory diff --git a/samples/Lua/TestLua/proj.android/jni/Application.mk b/samples/Lua/TestLua/proj.android/jni/Application.mk index 60500cd560..daad673c2b 100644 --- a/samples/Lua/TestLua/proj.android/jni/Application.mk +++ b/samples/Lua/TestLua/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_DEBUG=1 -std=c++11 APP_CPPFLAGS += -fexceptions -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/samples/Lua/TestLua/proj.tizen/.cproject b/samples/Lua/TestLua/proj.tizen/.cproject index 95aeb52a26..704b78679e 100644 --- a/samples/Lua/TestLua/proj.tizen/.cproject +++ b/samples/Lua/TestLua/proj.tizen/.cproject @@ -60,7 +60,7 @@ - @@ -140,6 +140,7 @@ + @@ -166,6 +167,7 @@ + @@ -537,7 +539,7 @@ - diff --git a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id index 7e141425af..543b758f11 100644 --- a/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/samples.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -27e33687fe11748b4214aa67ea2e3e658e43178c \ No newline at end of file +daaf13ab82feffbd1c8e201d76cb83ed8f2dabca \ No newline at end of file diff --git a/scripting/javascript/bindings/XMLHTTPRequest.cpp b/scripting/javascript/bindings/XMLHTTPRequest.cpp index 4186aa807d..28052510ea 100644 --- a/scripting/javascript/bindings/XMLHTTPRequest.cpp +++ b/scripting/javascript/bindings/XMLHTTPRequest.cpp @@ -601,10 +601,10 @@ JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, open) } if (meth.compare("post") == 0 || meth.compare("POST") == 0) { - cc_request->setRequestType(cocos2d::extension::HttpRequest::kHttpPost); + cc_request->setRequestType(cocos2d::extension::HttpRequest::Type::POST); } else { - cc_request->setRequestType(cocos2d::extension::HttpRequest::kHttpGet); + cc_request->setRequestType(cocos2d::extension::HttpRequest::Type::GET); } cc_request->setUrl(url.c_str()); diff --git a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id index c3d23499cb..43f4662e33 100644 --- a/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id +++ b/scripting/javascript/bindings/cocos2d_specifics.cpp.REMOVED.git-id @@ -1 +1 @@ -044ec2b4004e74ab49c48a703b1ffd743da7eaa3 \ No newline at end of file +e7d44ce7f120b3a7eaabe8079dfee33b25fdf284 \ No newline at end of file diff --git a/scripting/javascript/bindings/generated b/scripting/javascript/bindings/generated index 4d493e5616..14bfdc37af 160000 --- a/scripting/javascript/bindings/generated +++ b/scripting/javascript/bindings/generated @@ -1 +1 @@ -Subproject commit 4d493e5616b1c88ed9cb771394c939d7222be9f1 +Subproject commit 14bfdc37af1e2c28ec6f8568d9034bc747478ec5 diff --git a/scripting/javascript/bindings/js/jsb_deprecated.js b/scripting/javascript/bindings/js/jsb_deprecated.js index efaf19f4c2..2257f0fb5f 100644 --- a/scripting/javascript/bindings/js/jsb_deprecated.js +++ b/scripting/javascript/bindings/js/jsb_deprecated.js @@ -55,5 +55,9 @@ var cc = cc || {}; return cc.Node.prototype.getNumberOfRunningActionsInTarget.apply(this, arguments); }; + cc.TMXTiledMap.prototype.propertiesForGID = function() { + logW("cc.TMXTiledMap.propertiesForGID", "cc.TMXTiledMap.getPropertiesForGID"); + return cc.TMXTiledMap.prototype.getPropertiesForGID.apply(this, arguments); + }; })(); diff --git a/scripting/javascript/bindings/jsb_opengl_manual.cpp b/scripting/javascript/bindings/jsb_opengl_manual.cpp index 797498b1c1..e7aac467ee 100644 --- a/scripting/javascript/bindings/jsb_opengl_manual.cpp +++ b/scripting/javascript/bindings/jsb_opengl_manual.cpp @@ -39,487 +39,489 @@ // Helper functions that link "glGenXXXs" (OpenGL ES 2.0 spec), with "gl.createXXX" (WebGL spec) JSBool JSB_glGenTextures(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); + JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); - GLuint texture; - glGenTextures(1, &texture); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(texture)); - return JS_TRUE; + GLuint texture; + glGenTextures(1, &texture); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(texture)); + return JS_TRUE; } JSBool JSB_glGenBuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); + JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); - GLuint buffer; - glGenBuffers(1, &buffer); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(buffer)); - return JS_TRUE; + GLuint buffer; + glGenBuffers(1, &buffer); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(buffer)); + return JS_TRUE; } JSBool JSB_glGenRenderbuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); + JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); - GLuint renderbuffers; - glGenRenderbuffers(1, &renderbuffers); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(renderbuffers)); - return JS_TRUE; + GLuint renderbuffers; + glGenRenderbuffers(1, &renderbuffers); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(renderbuffers)); + return JS_TRUE; } JSBool JSB_glGenFramebuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); + JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); - GLuint framebuffers; - glGenFramebuffers(1, &framebuffers); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(framebuffers)); - return JS_TRUE; + GLuint framebuffers; + glGenFramebuffers(1, &framebuffers); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(framebuffers)); + return JS_TRUE; } JSBool JSB_glDeleteTextures(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - glDeleteTextures(1, &arg0); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; + glDeleteTextures(1, &arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; } JSBool JSB_glDeleteBuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - glDeleteBuffers(1, &arg0); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; + glDeleteBuffers(1, &arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; } JSBool JSB_glDeleteRenderbuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - glDeleteRenderbuffers(1, &arg0); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; + glDeleteRenderbuffers(1, &arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; } JSBool JSB_glDeleteFramebuffers(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - glDeleteFramebuffers(1, &arg0); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; + glDeleteFramebuffers(1, &arg0); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; } JSBool JSB_glShaderSource(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; const char *arg1; + JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; const char *arg1; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - ok &= jsval_to_charptr(cx, *argvp++, &arg1); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + ok &= jsval_to_charptr(cx, *argvp++, &arg1); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - glShaderSource(arg0, 1, &arg1, NULL); - JS_SET_RVAL(cx, vp, JSVAL_VOID); - return JS_TRUE; + glShaderSource(arg0, 1, &arg1, NULL); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; } JSBool JSB_glGetShaderiv(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0, arg1; + JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0, arg1; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - ok &= jsval_to_uint( cx, *argvp++, &arg1 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + ok &= jsval_to_uint( cx, *argvp++, &arg1 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLint ret; - glGetShaderiv(arg0, arg1, &ret); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(ret)); - return JS_TRUE; + GLint ret; + glGetShaderiv(arg0, arg1, &ret); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(ret)); + return JS_TRUE; } JSBool JSB_glGetProgramiv(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0, arg1; + JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0, arg1; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - ok &= jsval_to_uint( cx, *argvp++, &arg1 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + ok &= jsval_to_uint( cx, *argvp++, &arg1 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLint ret; - glGetProgramiv(arg0, arg1, &ret); - JS_SET_RVAL(cx, vp, INT_TO_JSVAL(ret)); - return JS_TRUE; + GLint ret; + glGetProgramiv(arg0, arg1, &ret); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(ret)); + return JS_TRUE; } JSBool JSB_glGetProgramInfoLog(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetProgramiv(arg0, GL_INFO_LOG_LENGTH, &length); - GLchar* src = new GLchar[length]; - glGetProgramInfoLog(arg0, length, NULL, src); - - JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); - CC_SAFE_DELETE_ARRAY(src); - return JS_TRUE; + GLsizei length; + glGetProgramiv(arg0, GL_INFO_LOG_LENGTH, &length); + GLchar* src = new GLchar[length]; + glGetProgramInfoLog(arg0, length, NULL, src); + + JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); + CC_SAFE_DELETE_ARRAY(src); + return JS_TRUE; } // DOMString? getShaderInfoLog(WebGLShader? shader); JSBool JSB_glGetShaderInfoLog(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetShaderiv(arg0, GL_INFO_LOG_LENGTH, &length); - GLchar* src = new GLchar[length]; - glGetShaderInfoLog(arg0, length, NULL, src); - - JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); - CC_SAFE_DELETE_ARRAY(src); - return JS_TRUE; + GLsizei length; + glGetShaderiv(arg0, GL_INFO_LOG_LENGTH, &length); + GLchar* src = new GLchar[length]; + glGetShaderInfoLog(arg0, length, NULL, src); + + JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); + CC_SAFE_DELETE_ARRAY(src); + return JS_TRUE; } // DOMString? getShaderSource(WebGLShader? shader); JSBool JSB_glGetShaderSource(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetShaderiv(arg0, GL_SHADER_SOURCE_LENGTH, &length); - GLchar* src = new GLchar[length]; - glGetShaderSource(arg0, length, NULL, src); + GLsizei length; + glGetShaderiv(arg0, GL_SHADER_SOURCE_LENGTH, &length); + GLchar* src = new GLchar[length]; + glGetShaderSource(arg0, length, NULL, src); - JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); - CC_SAFE_DELETE_ARRAY(src); - return JS_TRUE; + JS_SET_RVAL(cx, vp, charptr_to_jsval(cx, src)); + CC_SAFE_DELETE_ARRAY(src); + return JS_TRUE; } -// interface WebGLActiveInfo { -// readonly attribute GLint size; -// readonly attribute GLenum type; -// readonly attribute DOMString name; +// interface WebGLActiveInfo { +// readonly attribute GLint size; +// readonly attribute GLenum type; +// readonly attribute DOMString name; // WebGLActiveInfo? getActiveAttrib(WebGLProgram? program, GLuint index); JSBool JSB_glGetActiveAttrib(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0, arg1; + JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0, arg1; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - ok &= jsval_to_uint( cx, *argvp++, &arg1 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + ok &= jsval_to_uint( cx, *argvp++, &arg1 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetProgramiv(arg0, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length); - GLchar* buffer = new GLchar[length]; - GLint size = -1; - GLenum type = -1; + GLsizei length; + glGetProgramiv(arg0, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length); + GLchar* buffer = new GLchar[length]; + GLint size = -1; + GLenum type = -1; - glGetActiveAttrib(arg0, arg1, length, NULL, &size, &type, buffer); + glGetActiveAttrib(arg0, arg1, length, NULL, &size, &type, buffer); - jsval retval = JSVAL_VOID; + jsval retval = JSVAL_VOID; - JSObject *object = JS_NewObject(cx, NULL, NULL, NULL ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error creating JS Object"); + JSObject *object = JS_NewObject(cx, NULL, NULL, NULL ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error creating JS Object"); - if (!JS_DefineProperty(cx, object, "size", INT_TO_JSVAL(size), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || - !JS_DefineProperty(cx, object, "type", INT_TO_JSVAL(type), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || - !JS_DefineProperty(cx, object, "name", charptr_to_jsval(cx, buffer), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) ) - return JS_FALSE; + if (!JS_DefineProperty(cx, object, "size", INT_TO_JSVAL(size), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || + !JS_DefineProperty(cx, object, "type", INT_TO_JSVAL(type), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || + !JS_DefineProperty(cx, object, "name", charptr_to_jsval(cx, buffer), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) ) + return JS_FALSE; - retval = OBJECT_TO_JSVAL(object); + retval = OBJECT_TO_JSVAL(object); - JS_SET_RVAL(cx, vp, retval); - CC_SAFE_DELETE_ARRAY(buffer); - return JS_TRUE; + JS_SET_RVAL(cx, vp, retval); + CC_SAFE_DELETE_ARRAY(buffer); + return JS_TRUE; } -// interface WebGLActiveInfo { -// readonly attribute GLint size; -// readonly attribute GLenum type; -// readonly attribute DOMString name; -// }; +// interface WebGLActiveInfo { +// readonly attribute GLint size; +// readonly attribute GLenum type; +// readonly attribute DOMString name; +// }; // WebGLActiveInfo? getActiveUniform(WebGLProgram? program, GLuint index); JSBool JSB_glGetActiveUniform(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0, arg1; + JSB_PRECONDITION2( argc == 2, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0, arg1; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - ok &= jsval_to_uint( cx, *argvp++, &arg1 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + ok &= jsval_to_uint( cx, *argvp++, &arg1 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetProgramiv(arg0, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length); - GLchar* buffer = new GLchar[length]; - GLint size = -1; - GLenum type = -1; + GLsizei length; + glGetProgramiv(arg0, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length); + GLchar* buffer = new GLchar[length]; + GLint size = -1; + GLenum type = -1; - glGetActiveUniform(arg0, arg1, length, NULL, &size, &type, buffer); + glGetActiveUniform(arg0, arg1, length, NULL, &size, &type, buffer); - jsval retval = JSVAL_VOID; + jsval retval = JSVAL_VOID; - JSObject *object = JS_NewObject(cx, NULL, NULL, NULL ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error creating JS Object"); + JSObject *object = JS_NewObject(cx, NULL, NULL, NULL ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error creating JS Object"); - if (!JS_DefineProperty(cx, object, "size", INT_TO_JSVAL(size), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || - !JS_DefineProperty(cx, object, "type", INT_TO_JSVAL(type), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || - !JS_DefineProperty(cx, object, "name", charptr_to_jsval(cx, buffer), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) ) - return JS_FALSE; + if (!JS_DefineProperty(cx, object, "size", INT_TO_JSVAL(size), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || + !JS_DefineProperty(cx, object, "type", INT_TO_JSVAL(type), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) || + !JS_DefineProperty(cx, object, "name", charptr_to_jsval(cx, buffer), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) ) + return JS_FALSE; - retval = OBJECT_TO_JSVAL(object); + retval = OBJECT_TO_JSVAL(object); - JS_SET_RVAL(cx, vp, retval); - CC_SAFE_DELETE_ARRAY(buffer); - return JS_TRUE; + JS_SET_RVAL(cx, vp, retval); + CC_SAFE_DELETE_ARRAY(buffer); + return JS_TRUE; } // sequence? getAttachedShaders(WebGLProgram? program); JSBool JSB_glGetAttachedShaders(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); - jsval *argvp = JS_ARGV(cx,vp); - JSBool ok = JS_TRUE; - uint32_t arg0; + JSB_PRECONDITION2( argc == 1, cx, JS_FALSE, "Invalid number of arguments" ); + jsval *argvp = JS_ARGV(cx,vp); + JSBool ok = JS_TRUE; + uint32_t arg0; - ok &= jsval_to_uint( cx, *argvp++, &arg0 ); - JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); + ok &= jsval_to_uint( cx, *argvp++, &arg0 ); + JSB_PRECONDITION2(ok, cx, JS_FALSE, "Error processing arguments"); - GLsizei length; - glGetProgramiv(arg0, GL_ATTACHED_SHADERS, &length); - GLuint* buffer = new GLuint[length]; - memset(buffer, 0, length * sizeof(GLuint)); - glGetAttachedShaders(arg0, length, NULL, buffer); + GLsizei length; + glGetProgramiv(arg0, GL_ATTACHED_SHADERS, &length); + GLuint* buffer = new GLuint[length]; + memset(buffer, 0, length * sizeof(GLuint)); + //Fix bug 2448, it seems that glGetAttachedShaders will crash if we send NULL to the third parameter (eg Windows), same as in lua binding + GLsizei realShaderCount = 0; + glGetAttachedShaders(arg0, length, &realShaderCount, buffer); + + JSObject *jsobj = JS_NewArrayObject(cx, length, NULL); + JSB_PRECONDITION2(jsobj, cx, JS_FALSE, "Error creating JS Object"); - JSObject *jsobj = JS_NewArrayObject(cx, length, NULL); - JSB_PRECONDITION2(jsobj, cx, JS_FALSE, "Error creating JS Object"); + for( int i=0; i? getSupportedExtensions(); JSBool JSB_glGetSupportedExtensions(JSContext *cx, uint32_t argc, jsval *vp) { - JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); + JSB_PRECONDITION2( argc == 0, cx, JS_FALSE, "Invalid number of arguments" ); - const GLubyte *extensions = glGetString(GL_EXTENSIONS); + const GLubyte *extensions = glGetString(GL_EXTENSIONS); - JSObject *jsobj = JS_NewArrayObject(cx, 0, NULL); - JSB_PRECONDITION2(jsobj, cx, JS_FALSE, "Error creating JS Object"); + JSObject *jsobj = JS_NewArrayObject(cx, 0, NULL); + JSB_PRECONDITION2(jsobj, cx, JS_FALSE, "Error creating JS Object"); - // copy, to be able to add '\0' - size_t len = strlen((char*)extensions); - GLubyte* copy = new GLubyte[len+1]; - strncpy((char*)copy, (const char*)extensions, len ); + // copy, to be able to add '\0' + size_t len = strlen((char*)extensions); + GLubyte* copy = new GLubyte[len+1]; + strncpy((char*)copy, (const char*)extensions, len ); - int start_extension=0; - int element=0; - for( int i=0; iclean(); } @@ -756,4 +758,20 @@ void LuaEngine::extendScrollView(lua_State* lua_S) lua_rawset(lua_S,-3); } } + +void LuaEngine::extendDrawNode(lua_State* lua_S) +{ + if (NULL == lua_S) + return; + + lua_pushstring(lua_S,"CCDrawNode"); + lua_rawget(lua_S,LUA_REGISTRYINDEX); + if (lua_istable(lua_S,-1)) + { + lua_pushstring(lua_S,"drawPolygon"); + lua_pushcfunction(lua_S,tolua_Cocos2d_CCDrawNode_drawPolygon00); + lua_rawset(lua_S,-3); + } + +} NS_CC_END diff --git a/scripting/lua/cocos2dx_support/CCLuaEngine.h b/scripting/lua/cocos2dx_support/CCLuaEngine.h index f4c493283e..b051508eaf 100644 --- a/scripting/lua/cocos2dx_support/CCLuaEngine.h +++ b/scripting/lua/cocos2dx_support/CCLuaEngine.h @@ -145,6 +145,7 @@ private: void extendWebsocket(lua_State* lua_S); void extendGLNode(lua_State* lua_S); void extendScrollView(lua_State* lua_S); + void extendDrawNode(lua_State* lua_S); private: static LuaEngine* _defaultEngine; LuaStack *_stack; diff --git a/scripting/lua/cocos2dx_support/LuaCocos2d.cpp.REMOVED.git-id b/scripting/lua/cocos2dx_support/LuaCocos2d.cpp.REMOVED.git-id index 4ae2a7c361..7017d444aa 100644 --- a/scripting/lua/cocos2dx_support/LuaCocos2d.cpp.REMOVED.git-id +++ b/scripting/lua/cocos2dx_support/LuaCocos2d.cpp.REMOVED.git-id @@ -1 +1 @@ -ab4c02a68cfeccde64ff6b990aba6925d8e7787d \ No newline at end of file +b594adf598be0fbf5ca9ad804255069bc13405d5 \ No newline at end of file diff --git a/scripting/lua/cocos2dx_support/LuaOpengl.cpp.REMOVED.git-id b/scripting/lua/cocos2dx_support/LuaOpengl.cpp.REMOVED.git-id index b46045d3c2..a66e8aaade 100644 --- a/scripting/lua/cocos2dx_support/LuaOpengl.cpp.REMOVED.git-id +++ b/scripting/lua/cocos2dx_support/LuaOpengl.cpp.REMOVED.git-id @@ -1 +1 @@ -d515328a92ac0cf64fb7b1ee9d1b0b200d36c473 \ No newline at end of file +c5e888a17cf2f8757160b2baa5f876b59ddbf89e \ No newline at end of file diff --git a/scripting/lua/cocos2dx_support/LuaOpengl.h b/scripting/lua/cocos2dx_support/LuaOpengl.h index 605d66c320..c72e000e83 100644 --- a/scripting/lua/cocos2dx_support/LuaOpengl.h +++ b/scripting/lua/cocos2dx_support/LuaOpengl.h @@ -15,6 +15,7 @@ class GLNode:public cocos2d::Node virtual void draw(); }; +TOLUA_API int tolua_Cocos2d_CCDrawNode_drawPolygon00(lua_State* tolua_S); TOLUA_API int tolua_opengl_open(lua_State* tolua_S); diff --git a/scripting/lua/proj.qt5/lua.pro b/scripting/lua/proj.qt5/lua.pro new file mode 100644 index 0000000000..6af3270aeb --- /dev/null +++ b/scripting/lua/proj.qt5/lua.pro @@ -0,0 +1,30 @@ + +include(../../../cocos2dx/proj.qt5/common.pri) + +TEMPLATE = lib +CONFIG += static +CONFIG += c++11 + +SOURCES += $$files(../lua/*.c) +SOURCES += $$files(../tolua/*.c) +SOURCES += $$files(../cocos2dx_support/*.c) +SOURCES += $$files(../cocos2dx_support/*.cpp) + +DEFINES += CC_TARGET_OS_MAC + +INCLUDEPATH += .. +INCLUDEPATH += ../lua +INCLUDEPATH += ../tolua +INCLUDEPATH += ../Classes +INCLUDEPATH += ../../../CocosDenshion/include +INCLUDEPATH += ../../../extensions +INCLUDEPATH += ../../../external/chipmunk/include/chipmunk +INCLUDEPATH += ../../../cocos2dx/include +INCLUDEPATH += ../../../cocos2dx +INCLUDEPATH += ../../../cocos2dx/platform/qt5 +INCLUDEPATH += ../../../cocos2dx/kazmath/include + +# XXX SHAREDLIBS += -lextension + +TARGET = $${LIB_OUTPUT_DIR}/lua + diff --git a/scripting/lua/proj.tizen/.project b/scripting/lua/proj.tizen/.project index f627d695f2..f4c4696d14 100644 --- a/scripting/lua/proj.tizen/.project +++ b/scripting/lua/proj.tizen/.project @@ -102,15 +102,4 @@ PARENT-1-PROJECT_LOC/tolua - - - 1370773087313 - src/cocos2dx_support - 6 - - org.eclipse.ui.ide.multiFilter - 1.0-name-matches-false-false-Lua_web_socket* - - - diff --git a/scripting/lua/script/Deprecated.lua b/scripting/lua/script/Deprecated.lua index 8ff13c5c9f..cd0ccf6cde 100644 --- a/scripting/lua/script/Deprecated.lua +++ b/scripting/lua/script/Deprecated.lua @@ -775,18 +775,118 @@ rawset(CCTMXObjectGroup,"objectNamed", CCTMXObjectGroupDeprecated.objectNamed) --functions of WebSocket will be deprecated begin -local WebSocketDeprecated = { } -function WebSocketDeprecated.sendTextMsg(self, string) - deprecatedTip("WebSocket:sendTextMsg","WebSocket:sendString") - return self:sendString(string) -end -rawset(WebSocket,"sendTextMsg", WebSocketDeprecated.sendTextMsg) +local targetPlatform = CCApplication:getInstance():getTargetPlatform() +if (kTargetIphone == targetPlatform) or (kTargetIpad == targetPlatform) or (kTargetAndroid == targetPlatform) or (kTargetWindows == targetPlatform) then + local WebSocketDeprecated = { } + function WebSocketDeprecated.sendTextMsg(self, string) + deprecatedTip("WebSocket:sendTextMsg","WebSocket:sendString") + return self:sendString(string) + end + rawset(WebSocket,"sendTextMsg", WebSocketDeprecated.sendTextMsg) -function WebSocketDeprecated.sendBinaryMsg(self, table,tablesize) - deprecatedTip("WebSocket:sendBinaryMsg","WebSocket:sendString") - string.char(unpack(table)) - return self:sendString(string.char(unpack(table))) + function WebSocketDeprecated.sendBinaryMsg(self, table,tablesize) + deprecatedTip("WebSocket:sendBinaryMsg","WebSocket:sendString") + string.char(unpack(table)) + return self:sendString(string.char(unpack(table))) + end + rawset(WebSocket,"sendBinaryMsg", WebSocketDeprecated.sendBinaryMsg) end -rawset(WebSocket,"sendBinaryMsg", WebSocketDeprecated.sendBinaryMsg) --functions of WebSocket will be deprecated end + +--functions of CCDrawPrimitives will be deprecated begin +local CCDrawPrimitivesDeprecated = { } +function CCDrawPrimitivesDeprecated.ccDrawPoint(pt) + deprecatedTip("ccDrawPoint","CCDrawPrimitives.ccDrawPoint") + return CCDrawPrimitives.ccDrawPoint(pt) +end +rawset(_G, "ccDrawPoint", CCDrawPrimitivesDeprecated.ccDrawPoint) + +function CCDrawPrimitivesDeprecated.ccDrawLine(origin,destination) + deprecatedTip("ccDrawLine","CCDrawPrimitives.ccDrawLine") + return CCDrawPrimitives.ccDrawLine(origin,destination) +end +rawset(_G, "ccDrawLine", CCDrawPrimitivesDeprecated.ccDrawLine) + +function CCDrawPrimitivesDeprecated.ccDrawRect(origin,destination) + deprecatedTip("ccDrawRect","CCDrawPrimitives.ccDrawRect") + return CCDrawPrimitives.ccDrawRect(origin,destination) +end +rawset(_G, "ccDrawRect", CCDrawPrimitivesDeprecated.ccDrawRect) + +function CCDrawPrimitivesDeprecated.ccDrawSolidRect(origin,destination,color) + deprecatedTip("ccDrawSolidRect","CCDrawPrimitives.ccDrawSolidRect") + return CCDrawPrimitives.ccDrawSolidRect(origin,destination,color) +end +rawset(_G, "ccDrawSolidRect", CCDrawPrimitivesDeprecated.ccDrawSolidRect) + +-- params:... may represent two param(xScale,yScale) or nil +function CCDrawPrimitivesDeprecated.ccDrawCircle(center,radius,angle,segments,drawLineToCenter,...) + deprecatedTip("ccDrawCircle","CCDrawPrimitives.ccDrawCircle") + return CCDrawPrimitives.ccDrawCircle(center,radius,angle,segments,drawLineToCenter,...) +end +rawset(_G, "ccDrawCircle", CCDrawPrimitivesDeprecated.ccDrawCircle) + +-- params:... may represent two param(xScale,yScale) or nil +function CCDrawPrimitivesDeprecated.ccDrawSolidCircle(center,radius,angle,segments,...) + deprecatedTip("ccDrawSolidCircle","CCDrawPrimitives.ccDrawSolidCircle") + return CCDrawPrimitives.ccDrawSolidCircle(center,radius,angle,segments,...) +end +rawset(_G, "ccDrawSolidCircle", CCDrawPrimitivesDeprecated.ccDrawSolidCircle) + +function CCDrawPrimitivesDeprecated.ccDrawQuadBezier(origin,control,destination,segments) + deprecatedTip("ccDrawQuadBezier","CCDrawPrimitives.ccDrawQuadBezier") + return CCDrawPrimitives.ccDrawQuadBezier(origin,control,destination,segments) +end +rawset(_G, "ccDrawQuadBezier", CCDrawPrimitivesDeprecated.ccDrawQuadBezier) + +function CCDrawPrimitivesDeprecated.ccDrawCubicBezier(origin,control1,control2,destination,segments) + deprecatedTip("ccDrawCubicBezier","CCDrawPrimitives.ccDrawCubicBezier") + return CCDrawPrimitives.ccDrawCubicBezier(origin,control1,control2,destination,segments) +end +rawset(_G, "ccDrawCubicBezier", CCDrawPrimitivesDeprecated.ccDrawCubicBezier) + +function CCDrawPrimitivesDeprecated.ccDrawCatmullRom(arrayOfControlPoints,segments) + deprecatedTip("ccDrawCatmullRom","CCDrawPrimitives.ccDrawCatmullRom") + return CCDrawPrimitives.ccDrawCatmullRom(arrayOfControlPoints,segments) +end +rawset(_G, "ccDrawCatmullRom", CCDrawPrimitivesDeprecated.ccDrawCatmullRom) + +function CCDrawPrimitivesDeprecated.ccDrawCardinalSpline(config,tension,segments) + deprecatedTip("ccDrawCardinalSpline","CCDrawPrimitives.ccDrawCardinalSpline") + return CCDrawPrimitives.ccDrawCardinalSpline(config,tension,segments) +end +rawset(_G, "ccDrawCardinalSpline", CCDrawPrimitivesDeprecated.ccDrawCardinalSpline) + +function CCDrawPrimitivesDeprecated.ccDrawColor4B(r,g,b,a) + deprecatedTip("ccDrawColor4B","CCDrawPrimitives.ccDrawColor4B") + return CCDrawPrimitives.ccDrawColor4B(r,g,b,a) +end +rawset(_G, "ccDrawColor4B", CCDrawPrimitivesDeprecated.ccDrawColor4B) + +function CCDrawPrimitivesDeprecated.ccDrawColor4F(r,g,b,a) + deprecatedTip("ccDrawColor4F","CCDrawPrimitives.ccDrawColor4F") + return CCDrawPrimitives.ccDrawColor4F(r,g,b,a) +end +rawset(_G, "ccDrawColor4F", CCDrawPrimitivesDeprecated.ccDrawColor4F) + +function CCDrawPrimitivesDeprecated.ccPointSize(pointSize) + deprecatedTip("ccPointSize","CCDrawPrimitives.ccPointSize") + return CCDrawPrimitives.ccPointSize(pointSize) +end +rawset(_G, "ccPointSize", CCDrawPrimitivesDeprecated.ccPointSize) +--functions of CCDrawPrimitives will be deprecated end + +--enums of CCParticleSystem will be deprecated begin +_G["kParticleStartSizeEqualToEndSize"] = _G["kCCParticleStartSizeEqualToEndSize"] +_G["kParticleDurationInfinity"] = _G["kCCParticleDurationInfinity"] +--enums of CCParticleSystem will be deprecated end + +--enums of CCRenderTexture will be deprecated begin +local CCRenderTextureDeprecated = { } +function CCRenderTextureDeprecated.newCCImage(self) + deprecatedTip("CCRenderTexture:newCCImage","CCRenderTexture:newImage") + return self:newImage() +end +rawset(CCRenderTexture, "newCCImage", CCRenderTextureDeprecated.newCCImage) +--enums of CCRenderTexture will be deprecated end diff --git a/template/multi-platform-cpp/Classes/AppDelegate.cpp b/template/multi-platform-cpp/Classes/AppDelegate.cpp index 1c065df82b..27677ac1ad 100644 --- a/template/multi-platform-cpp/Classes/AppDelegate.cpp +++ b/template/multi-platform-cpp/Classes/AppDelegate.cpp @@ -13,22 +13,22 @@ AppDelegate::~AppDelegate() bool AppDelegate::applicationDidFinishLaunching() { // initialize director - Director* pDirector = Director::getInstance(); - EGLView* pEGLView = EGLView::getInstance(); + Director* director = Director::getInstance(); + EGLView* eglView = EGLView::getInstance(); - pDirector->setOpenGLView(pEGLView); + director->setOpenGLView(eglView); // turn on display FPS - pDirector->setDisplayStats(true); + director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this - pDirector->setAnimationInterval(1.0 / 60); + director->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object - Scene *pScene = HelloWorld::scene(); + Scene *scene = HelloWorld::scene(); // run - pDirector->runWithScene(pScene); + director->runWithScene(scene); return true; } diff --git a/template/multi-platform-cpp/Classes/HelloWorldScene.cpp b/template/multi-platform-cpp/Classes/HelloWorldScene.cpp index b635359243..c2f4896258 100644 --- a/template/multi-platform-cpp/Classes/HelloWorldScene.cpp +++ b/template/multi-platform-cpp/Classes/HelloWorldScene.cpp @@ -35,18 +35,18 @@ bool HelloWorld::init() // you may modify it. // add a "close" icon to exit the progress. it's an autorelease object - MenuItemImage *pCloseItem = MenuItemImage::create( + MenuItemImage *closeItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); - pCloseItem->setPosition(Point(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 , - origin.y + pCloseItem->getContentSize().height/2)); + closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , + origin.y + closeItem->getContentSize().height/2)); // create menu, it's an autorelease object - Menu* pMenu = Menu::create(pCloseItem, NULL); - pMenu->setPosition(Point::ZERO); - this->addChild(pMenu, 1); + Menu* menu = Menu::create(closeItem, NULL); + menu->setPosition(Point::ZERO); + this->addChild(menu, 1); ///////////////////////////// // 3. add your codes below... @@ -54,23 +54,23 @@ bool HelloWorld::init() // add a label shows "Hello World" // create and initialize a label - LabelTTF* pLabel = LabelTTF::create("Hello World", "Arial", 24); + LabelTTF* label = LabelTTF::create("Hello World", "Arial", 24); // position the label on the center of the screen - pLabel->setPosition(Point(origin.x + visibleSize.width/2, - origin.y + visibleSize.height - pLabel->getContentSize().height)); + label->setPosition(Point(origin.x + visibleSize.width/2, + origin.y + visibleSize.height - label->getContentSize().height)); // add the label as a child to this layer - this->addChild(pLabel, 1); + this->addChild(label, 1); // add "HelloWorld" splash screen" - Sprite* pSprite = Sprite::create("HelloWorld.png"); + Sprite* sprite = Sprite::create("HelloWorld.png"); // position the sprite on the center of the screen - pSprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); + sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer - this->addChild(pSprite, 0); + this->addChild(sprite, 0); return true; } diff --git a/template/multi-platform-cpp/proj.android/build_native.sh b/template/multi-platform-cpp/proj.android/build_native.sh index 53cbb80e4b..62f24ecb8c 100755 --- a/template/multi-platform-cpp/proj.android/build_native.sh +++ b/template/multi-platform-cpp/proj.android/build_native.sh @@ -35,6 +35,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../.." diff --git a/template/multi-platform-cpp/proj.android/jni/Application.mk b/template/multi-platform-cpp/proj.android/jni/Application.mk index 43499d7113..b20df4f373 100644 --- a/template/multi-platform-cpp/proj.android/jni/Application.mk +++ b/template/multi-platform-cpp/proj.android/jni/Application.mk @@ -1,3 +1,2 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -DCOCOS2D_DEBUG=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 diff --git a/template/multi-platform-cpp/proj.ios/HelloCpp.xcodeproj/project.pbxproj b/template/multi-platform-cpp/proj.ios/HelloCpp.xcodeproj/project.pbxproj index 567f421cb9..8f34754a1c 100644 --- a/template/multi-platform-cpp/proj.ios/HelloCpp.xcodeproj/project.pbxproj +++ b/template/multi-platform-cpp/proj.ios/HelloCpp.xcodeproj/project.pbxproj @@ -605,6 +605,7 @@ "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-O2"; PRODUCT_NAME = HelloCpp; PROVISIONING_PROFILE = ""; @@ -655,6 +656,7 @@ "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = HelloCpp; PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; diff --git a/template/multi-platform-cpp/proj.mac/HelloCpp.xcodeproj/project.pbxproj b/template/multi-platform-cpp/proj.mac/HelloCpp.xcodeproj/project.pbxproj index 7812472c83..0b2bb502bc 100644 --- a/template/multi-platform-cpp/proj.mac/HelloCpp.xcodeproj/project.pbxproj +++ b/template/multi-platform-cpp/proj.mac/HelloCpp.xcodeproj/project.pbxproj @@ -574,6 +574,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CODE_SIGN_IDENTITY = ""; @@ -621,6 +622,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CODE_SIGN_IDENTITY = ""; @@ -664,7 +666,7 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -677,7 +679,7 @@ C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; diff --git a/template/multi-platform-js/Classes/AppDelegate.cpp b/template/multi-platform-js/Classes/AppDelegate.cpp index ae91b478d4..f086f7b889 100644 --- a/template/multi-platform-js/Classes/AppDelegate.cpp +++ b/template/multi-platform-js/Classes/AppDelegate.cpp @@ -29,14 +29,14 @@ AppDelegate::~AppDelegate() bool AppDelegate::applicationDidFinishLaunching() { // initialize director - Director *pDirector = Director::getInstance(); - pDirector->setOpenGLView(EGLView::getInstance()); + Director *director = Director::getInstance(); + director->setOpenGLView(EGLView::getInstance()); // turn on display FPS - pDirector->setDisplayStats(true); + director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this - pDirector->setAnimationInterval(1.0 / 60); + director->setAnimationInterval(1.0 / 60); ScriptingCore* sc = ScriptingCore::getInstance(); sc->addRegisterCallback(register_all_cocos2dx); @@ -52,8 +52,8 @@ bool AppDelegate::applicationDidFinishLaunching() sc->start(); - ScriptEngineProtocol *pEngine = ScriptingCore::getInstance(); - ScriptEngineManager::getInstance()->setScriptEngine(pEngine); + ScriptEngineProtocol *engine = ScriptingCore::getInstance(); + ScriptEngineManager::getInstance()->setScriptEngine(engine); ScriptingCore::getInstance()->runScript("main.js"); return true; diff --git a/template/multi-platform-js/proj.android/build_native.sh b/template/multi-platform-js/proj.android/build_native.sh index 6388af5a7a..149635b305 100755 --- a/template/multi-platform-js/proj.android/build_native.sh +++ b/template/multi-platform-js/proj.android/build_native.sh @@ -43,6 +43,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../.." diff --git a/template/multi-platform-js/proj.android/jni/Application.mk b/template/multi-platform-js/proj.android/jni/Application.mk index 4e46d23deb..ee36f34b40 100644 --- a/template/multi-platform-js/proj.android/jni/Application.mk +++ b/template/multi-platform-js/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1 APP_CPPFLAGS += -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/template/multi-platform-js/proj.ios/HelloJavascript.xcodeproj/project.pbxproj b/template/multi-platform-js/proj.ios/HelloJavascript.xcodeproj/project.pbxproj index 18d64274cf..5f0ecf7c0d 100644 --- a/template/multi-platform-js/proj.ios/HelloJavascript.xcodeproj/project.pbxproj +++ b/template/multi-platform-js/proj.ios/HelloJavascript.xcodeproj/project.pbxproj @@ -693,6 +693,7 @@ "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( "-lxml2", "-lz", @@ -741,6 +742,7 @@ "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/ios/libraries\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( "-lxml2", "-lz", diff --git a/template/multi-platform-lua/Classes/AppDelegate.cpp b/template/multi-platform-lua/Classes/AppDelegate.cpp index 05fb3205e1..8f8b0f5a3f 100644 --- a/template/multi-platform-lua/Classes/AppDelegate.cpp +++ b/template/multi-platform-lua/Classes/AppDelegate.cpp @@ -3,10 +3,6 @@ #include "AppDelegate.h" #include "CCLuaEngine.h" #include "SimpleAudioEngine.h" -#include "Lua_extensions_CCB.h" -#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) -#include "Lua_web_socket.h" -#endif using namespace CocosDenshion; @@ -24,30 +20,21 @@ AppDelegate::~AppDelegate() bool AppDelegate::applicationDidFinishLaunching() { // initialize director - Director *pDirector = Director::getInstance(); - pDirector->setOpenGLView(EGLView::getInstance()); + Director *director = Director::getInstance(); + director->setOpenGLView(EGLView::getInstance()); // turn on display FPS - pDirector->setDisplayStats(true); + director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this - pDirector->setAnimationInterval(1.0 / 60); + director->setAnimationInterval(1.0 / 60); // register lua engine - LuaEngine* pEngine = LuaEngine::getInstance(); - ScriptEngineManager::getInstance()->setScriptEngine(pEngine); - - LuaStack *pStack = pEngine->getLuaStack(); - lua_State *tolua_s = pStack->getLuaState(); - tolua_extensions_ccb_open(tolua_s); -#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) - pStack = pEngine->getLuaStack(); - tolua_s = pStack->getLuaState(); - tolua_web_socket_open(tolua_s); -#endif + LuaEngine* engine = LuaEngine::getInstance(); + ScriptEngineManager::getInstance()->setScriptEngine(engine); std::string path = FileUtils::getInstance()->fullPathForFilename("hello.lua"); - pEngine->executeScriptFile(path.c_str()); + engine->executeScriptFile(path.c_str()); return true; } diff --git a/template/multi-platform-lua/proj.android/build_native.sh b/template/multi-platform-lua/proj.android/build_native.sh index bca05d0902..6728b60a2e 100755 --- a/template/multi-platform-lua/proj.android/build_native.sh +++ b/template/multi-platform-lua/proj.android/build_native.sh @@ -35,6 +35,20 @@ echo "please define NDK_ROOT" exit 1 fi +# For compatibility of android-ndk-r9, 4.7 was removed from r9 +if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.7" ]; then + export NDK_TOOLCHAIN_VERSION=4.7 + echo "The Selected NDK toolchain version was 4.7 !" +else + if [ -d "${NDK_ROOT}/toolchains/arm-linux-androideabi-4.8" ]; then + export NDK_TOOLCHAIN_VERSION=4.8 + echo "The Selected NDK toolchain version was 4.8 !" + else + echo "Couldn't find the gcc toolchain." + exit 1 + fi +fi + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../.." diff --git a/template/multi-platform-lua/proj.android/jni/Application.mk b/template/multi-platform-lua/proj.android/jni/Application.mk index edebaebf65..95acd5331a 100644 --- a/template/multi-platform-lua/proj.android/jni/Application.mk +++ b/template/multi-platform-lua/proj.android/jni/Application.mk @@ -1,4 +1,4 @@ APP_STL := gnustl_static APP_CPPFLAGS := -frtti -DCOCOS2D_DEBUG=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 APP_CPPFLAGS += -fexceptions -NDK_TOOLCHAIN_VERSION=4.7 + diff --git a/template/multi-platform-lua/proj.ios/HelloLua.xcodeproj/project.pbxproj b/template/multi-platform-lua/proj.ios/HelloLua.xcodeproj/project.pbxproj index 32008ad704..80b06ce627 100644 --- a/template/multi-platform-lua/proj.ios/HelloLua.xcodeproj/project.pbxproj +++ b/template/multi-platform-lua/proj.ios/HelloLua.xcodeproj/project.pbxproj @@ -15,6 +15,13 @@ 15C1569C1683138E00D239F2 /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156951683138E00D239F2 /* Icon-72.png */; }; 15C1569D1683138E00D239F2 /* Icon-114.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156961683138E00D239F2 /* Icon-114.png */; }; 15C1569E1683138E00D239F2 /* Icon-144.png in Resources */ = {isa = PBXBuildFile; fileRef = 15C156971683138E00D239F2 /* Icon-144.png */; }; + 1A0227AC17A3AA3500B867AD /* AudioEngine.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227A517A3AA3500B867AD /* AudioEngine.lua */; }; + 1A0227AD17A3AA3500B867AD /* CCBReaderLoad.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227A617A3AA3500B867AD /* CCBReaderLoad.lua */; }; + 1A0227AE17A3AA3500B867AD /* Cocos2dConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227A717A3AA3500B867AD /* Cocos2dConstants.lua */; }; + 1A0227AF17A3AA3500B867AD /* Deprecated.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227A817A3AA3500B867AD /* Deprecated.lua */; }; + 1A0227B017A3AA3500B867AD /* DrawPrimitives.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227A917A3AA3500B867AD /* DrawPrimitives.lua */; }; + 1A0227B117A3AA3500B867AD /* Opengl.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227AA17A3AA3500B867AD /* Opengl.lua */; }; + 1A0227B217A3AA3500B867AD /* OpenglConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1A0227AB17A3AA3500B867AD /* OpenglConstants.lua */; }; 1AC3622F16D47C5C000847F2 /* background.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 1AC3622316D47C5C000847F2 /* background.mp3 */; }; 1AC3623016D47C5C000847F2 /* background.ogg in Resources */ = {isa = PBXBuildFile; fileRef = 1AC3622416D47C5C000847F2 /* background.ogg */; }; 1AC3623116D47C5C000847F2 /* crop.png in Resources */ = {isa = PBXBuildFile; fileRef = 1AC3622516D47C5C000847F2 /* crop.png */; }; @@ -33,8 +40,6 @@ 1AF4C3F51786633E00122817 /* libCocosDenshion iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C3E31786631700122817 /* libCocosDenshion iOS.a */; }; 1AF4C3F61786633E00122817 /* libluabindings iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C3E71786631700122817 /* libluabindings iOS.a */; }; 1AF4C403178663F200122817 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AF4C402178663F200122817 /* libz.dylib */; }; - 466AF68B179FCC03002EE9BB /* DrawPrimitives.lua in Resources */ = {isa = PBXBuildFile; fileRef = 466AF68A179FCC03002EE9BB /* DrawPrimitives.lua */; }; - 466AF68D179FCC09002EE9BB /* Deprecated.lua in Resources */ = {isa = PBXBuildFile; fileRef = 466AF68C179FCC09002EE9BB /* Deprecated.lua */; }; F293B3CD15EB7BE500256477 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3CC15EB7BE500256477 /* QuartzCore.framework */; }; F293B3CF15EB7BE500256477 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3CE15EB7BE500256477 /* OpenGLES.framework */; }; F293B3D115EB7BE500256477 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F293B3D015EB7BE500256477 /* OpenAL.framework */; }; @@ -194,6 +199,13 @@ 15C156951683138E00D239F2 /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-72.png"; sourceTree = SOURCE_ROOT; }; 15C156961683138E00D239F2 /* Icon-114.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-114.png"; sourceTree = SOURCE_ROOT; }; 15C156971683138E00D239F2 /* Icon-144.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-144.png"; sourceTree = SOURCE_ROOT; }; + 1A0227A517A3AA3500B867AD /* AudioEngine.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = AudioEngine.lua; path = ../../../scripting/lua/script/AudioEngine.lua; sourceTree = ""; }; + 1A0227A617A3AA3500B867AD /* CCBReaderLoad.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CCBReaderLoad.lua; path = ../../../scripting/lua/script/CCBReaderLoad.lua; sourceTree = ""; }; + 1A0227A717A3AA3500B867AD /* Cocos2dConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cocos2dConstants.lua; path = ../../../scripting/lua/script/Cocos2dConstants.lua; sourceTree = ""; }; + 1A0227A817A3AA3500B867AD /* Deprecated.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Deprecated.lua; path = ../../../scripting/lua/script/Deprecated.lua; sourceTree = ""; }; + 1A0227A917A3AA3500B867AD /* DrawPrimitives.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DrawPrimitives.lua; path = ../../../scripting/lua/script/DrawPrimitives.lua; sourceTree = ""; }; + 1A0227AA17A3AA3500B867AD /* Opengl.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Opengl.lua; path = ../../../scripting/lua/script/Opengl.lua; sourceTree = ""; }; + 1A0227AB17A3AA3500B867AD /* OpenglConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = OpenglConstants.lua; path = ../../../scripting/lua/script/OpenglConstants.lua; sourceTree = ""; }; 1AC3622316D47C5C000847F2 /* background.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = background.mp3; path = ../Resources/background.mp3; sourceTree = ""; }; 1AC3622416D47C5C000847F2 /* background.ogg */ = {isa = PBXFileReference; lastKnownFileType = file; name = background.ogg; path = ../Resources/background.ogg; sourceTree = ""; }; 1AC3622516D47C5C000847F2 /* crop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = crop.png; path = ../Resources/crop.png; sourceTree = ""; }; @@ -209,8 +221,6 @@ 1AF4C3B8178662A500122817 /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; 1AF4C3B91786631600122817 /* cocos2d_libs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = cocos2d_libs.xcodeproj; path = ../../../cocos2d_libs.xcodeproj; sourceTree = ""; }; 1AF4C402178663F200122817 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - 466AF68A179FCC03002EE9BB /* DrawPrimitives.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file; name = DrawPrimitives.lua; path = ../../../scripting/lua/script/DrawPrimitives.lua; sourceTree = ""; }; - 466AF68C179FCC09002EE9BB /* Deprecated.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file; name = Deprecated.lua; path = ../../../scripting/lua/script/Deprecated.lua; sourceTree = ""; }; F293B3C815EB7BE500256477 /* HelloLua.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloLua.app; sourceTree = BUILT_PRODUCTS_DIR; }; F293B3CC15EB7BE500256477 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; F293B3CE15EB7BE500256477 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -255,6 +265,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1A0227A417A3AA1A00B867AD /* Lua Common */ = { + isa = PBXGroup; + children = ( + 1A0227A517A3AA3500B867AD /* AudioEngine.lua */, + 1A0227A617A3AA3500B867AD /* CCBReaderLoad.lua */, + 1A0227A717A3AA3500B867AD /* Cocos2dConstants.lua */, + 1A0227A817A3AA3500B867AD /* Deprecated.lua */, + 1A0227A917A3AA3500B867AD /* DrawPrimitives.lua */, + 1A0227AA17A3AA3500B867AD /* Opengl.lua */, + 1A0227AB17A3AA3500B867AD /* OpenglConstants.lua */, + ); + name = "Lua Common"; + sourceTree = ""; + }; 1AF4C3BA1786631600122817 /* Products */ = { isa = PBXGroup; children = ( @@ -279,11 +303,10 @@ F293B3BD15EB7BE500256477 = { isa = PBXGroup; children = ( - 466AF68C179FCC09002EE9BB /* Deprecated.lua */, - 466AF68A179FCC03002EE9BB /* DrawPrimitives.lua */, 1AF4C3B91786631600122817 /* cocos2d_libs.xcodeproj */, F293BB7C15EB830F00256477 /* Classes */, F293B3CB15EB7BE500256477 /* Frameworks */, + 1A0227A417A3AA1A00B867AD /* Lua Common */, F293B6E815EB807E00256477 /* Other Sources */, F293B3C915EB7BE500256477 /* Products */, F293BC4615EB859D00256477 /* Resources */, @@ -541,12 +564,17 @@ 1AC3623416D47C5C000847F2 /* farm.jpg in Resources */, 1AC3623516D47C5C000847F2 /* fonts in Resources */, 1AC3623616D47C5C000847F2 /* hello.lua in Resources */, - 466AF68B179FCC03002EE9BB /* DrawPrimitives.lua in Resources */, 1AC3623716D47C5C000847F2 /* hello2.lua in Resources */, 1AC3623816D47C5C000847F2 /* land.png in Resources */, 1AC3623916D47C5C000847F2 /* menu1.png in Resources */, - 466AF68D179FCC09002EE9BB /* Deprecated.lua in Resources */, 1AC3623A16D47C5C000847F2 /* menu2.png in Resources */, + 1A0227AC17A3AA3500B867AD /* AudioEngine.lua in Resources */, + 1A0227AD17A3AA3500B867AD /* CCBReaderLoad.lua in Resources */, + 1A0227AE17A3AA3500B867AD /* Cocos2dConstants.lua in Resources */, + 1A0227AF17A3AA3500B867AD /* Deprecated.lua in Resources */, + 1A0227B017A3AA3500B867AD /* DrawPrimitives.lua in Resources */, + 1A0227B117A3AA3500B867AD /* Opengl.lua in Resources */, + 1A0227B217A3AA3500B867AD /* OpenglConstants.lua in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -707,6 +735,7 @@ "\"$(SRCROOT)/../../../scripting/lua/luajit/ios\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -756,6 +785,7 @@ "\"$(SRCROOT)/../../../scripting/lua/luajit/ios\"", "\"$(SRCROOT)/../../../external/libwebsockets/ios/lib\"", ); + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/cocos2dx/textures/CCTextureETC.h b/template/multi-platform-lua/proj.mac/AppController.h similarity index 66% rename from cocos2dx/textures/CCTextureETC.h rename to template/multi-platform-lua/proj.mac/AppController.h index 96053a4954..96c717304b 100644 --- a/cocos2dx/textures/CCTextureETC.h +++ b/template/multi-platform-lua/proj.mac/AppController.h @@ -1,5 +1,5 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2010 cocos2d-x.org http://www.cocos2d-x.org @@ -22,36 +22,21 @@ THE SOFTWARE. ****************************************************************************/ -#ifndef __CCETCTEXTURE_H__ -#define __CCETCTEXTURE_H__ +#pragma once -#include "cocoa/CCObject.h" -#include "platform/CCPlatformMacros.h" -#include "CCGL.h" +#import "cocos2d.h" +#import "EAGLView.h" -NS_CC_BEGIN +@interface AppController : NSObject + { + NSWindow *window; + CCEAGLView *glView; + } -class CC_DLL TextureETC : public Object -{ -public: - TextureETC(); - virtual ~TextureETC(); + @property (nonatomic, assign) IBOutlet NSWindow* window; + @property (nonatomic, assign) IBOutlet CCEAGLView* glView; - bool initWithFile(const char* file); + -(IBAction) toggleFullScreen:(id)sender; + -(IBAction) exitFullScreen:(id)sender; - unsigned int getName() const; - unsigned int getWidth() const; - unsigned int getHeight() const; - -private: - bool loadTexture(const char* file); - -private: - GLuint _name; - unsigned int _width; - unsigned int _height; -}; - -NS_CC_END - -#endif /* defined(__CCETCTEXTURE_H__) */ +@end diff --git a/template/multi-platform-lua/proj.mac/AppController.mm b/template/multi-platform-lua/proj.mac/AppController.mm new file mode 100644 index 0000000000..86368aa3c2 --- /dev/null +++ b/template/multi-platform-lua/proj.mac/AppController.mm @@ -0,0 +1,84 @@ +/**************************************************************************** + Copyright (c) 2010 cocos2d-x.org + + 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 + 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. + ****************************************************************************/ + +#import "AppController.h" +#import "AppDelegate.h" + +static AppDelegate s_sharedApplication; + +@implementation AppController + + @synthesize window, glView; + + -(void) applicationDidFinishLaunching:(NSNotification *)aNotification + { + // create the window + // note that using NSResizableWindowMask causes the window to be a little + // smaller and therefore ipad graphics are not loaded + NSRect rect = NSMakeRect(100, 100, 480, 320); + window = [[NSWindow alloc] initWithContentRect:rect + styleMask:( NSClosableWindowMask | NSTitledWindowMask ) + backing:NSBackingStoreBuffered + defer:YES]; + + // allocate our GL view + // (isn't there already a shared CCEAGLView?) + glView = [[CCEAGLView alloc] initWithFrame:rect]; + + // set window parameters + [window becomeFirstResponder]; + [window setContentView:glView]; + [window setTitle:@"HelloLua"]; + [window makeKeyAndOrderFront:self]; + [window setAcceptsMouseMovedEvents:NO]; + + cocos2d::Application::getInstance()->run(); + } + + -(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication + { + return YES; + } + + -(void) dealloc + { + cocos2d::Director::getInstance()->end(); + [super dealloc]; + } + +#pragma mark - +#pragma mark IB Actions + + -(IBAction) toggleFullScreen:(id)sender + { + CCEAGLView* pView = [CCEAGLView sharedEGLView]; + [pView setFullScreen:!pView.isFullScreen]; + } + + -(IBAction) exitFullScreen:(id)sender + { + [[CCEAGLView sharedEGLView] setFullScreen:NO]; + } + +@end diff --git a/template/multi-platform-lua/proj.mac/HelloLua.xcodeproj/project.pbxproj b/template/multi-platform-lua/proj.mac/HelloLua.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..5aab5d9d64 --- /dev/null +++ b/template/multi-platform-lua/proj.mac/HelloLua.xcodeproj/project.pbxproj @@ -0,0 +1,844 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 150181DE17A6636600E674E5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181DD17A6636600E674E5 /* QuartzCore.framework */; }; + 150181E517A663C800E674E5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02E6817A647C90035E92B /* Foundation.framework */; }; + 150181E817A6647000E674E5 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02FAA17A65D810035E92B /* OpenAL.framework */; }; + 150181EA17A6670300E674E5 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181E917A6670300E674E5 /* OpenGL.framework */; }; + 150181F017A667DA00E674E5 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181DF17A6637B00E674E5 /* AudioToolbox.framework */; }; + 150181F117A6684F00E674E5 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181EC17A6679B00E674E5 /* ApplicationServices.framework */; }; + 150181F217A6686400E674E5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181EE17A667BC00E674E5 /* Cocoa.framework */; }; + 150181F417A6695400E674E5 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181F317A6695400E674E5 /* libz.dylib */; }; + 150181F617A6696400E674E5 /* libcurl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 150181F517A6696400E674E5 /* libcurl.dylib */; }; + 1501821D17A6706400E674E5 /* libcocos2dx Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02F0717A64D060035E92B /* libcocos2dx Mac.a */; }; + 1501821E17A6706400E674E5 /* libcocos2dx-extensions Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02F0917A64D060035E92B /* libcocos2dx-extensions Mac.a */; }; + 1501821F17A6706400E674E5 /* libCocosDenshion Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02F0F17A64D060035E92B /* libCocosDenshion Mac.a */; }; + 1501822017A6706400E674E5 /* libluabindings Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02F1317A64D060035E92B /* libluabindings Mac.a */; }; + 1501825917A74F8000E674E5 /* AudioEngine.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825217A74F8000E674E5 /* AudioEngine.lua */; }; + 1501825A17A74F8000E674E5 /* CCBReaderLoad.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825317A74F8000E674E5 /* CCBReaderLoad.lua */; }; + 1501825B17A74F8000E674E5 /* Cocos2dConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825417A74F8000E674E5 /* Cocos2dConstants.lua */; }; + 1501825C17A74F8000E674E5 /* Deprecated.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825517A74F8000E674E5 /* Deprecated.lua */; }; + 1501825D17A74F8000E674E5 /* DrawPrimitives.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825617A74F8000E674E5 /* DrawPrimitives.lua */; }; + 1501825E17A74F8000E674E5 /* Opengl.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825717A74F8000E674E5 /* Opengl.lua */; }; + 1501825F17A74F8000E674E5 /* OpenglConstants.lua in Resources */ = {isa = PBXBuildFile; fileRef = 1501825817A74F8000E674E5 /* OpenglConstants.lua */; }; + 1501826E17A7513400E674E5 /* libchipmunk Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15A02F0B17A64D060035E92B /* libchipmunk Mac.a */; }; + 15A02F3817A64D1E0035E92B /* background.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2417A64D1E0035E92B /* background.mp3 */; }; + 15A02F3917A64D1E0035E92B /* background.ogg in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2517A64D1E0035E92B /* background.ogg */; }; + 15A02F3C17A64D1E0035E92B /* crop.png in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2817A64D1E0035E92B /* crop.png */; }; + 15A02F3E17A64D1E0035E92B /* dog.png in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2A17A64D1E0035E92B /* dog.png */; }; + 15A02F4017A64D1E0035E92B /* effect1.wav in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2C17A64D1E0035E92B /* effect1.wav */; }; + 15A02F4117A64D1E0035E92B /* farm.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F2D17A64D1E0035E92B /* farm.jpg */; }; + 15A02F4317A64D1E0035E92B /* hello.lua in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F3017A64D1E0035E92B /* hello.lua */; }; + 15A02F4417A64D1E0035E92B /* hello2.lua in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F3117A64D1E0035E92B /* hello2.lua */; }; + 15A02F4517A64D1E0035E92B /* land.png in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F3217A64D1E0035E92B /* land.png */; }; + 15A02F4617A64D1E0035E92B /* menu1.png in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F3317A64D1E0035E92B /* menu1.png */; }; + 15A02F4717A64D1E0035E92B /* menu2.png in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F3417A64D1E0035E92B /* menu2.png */; }; + 15A02F4D17A64D390035E92B /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 15A02F4B17A64D390035E92B /* AppDelegate.cpp */; }; + 15A02F7017A64DFB0035E92B /* AppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 15A02F6417A64DFB0035E92B /* AppController.mm */; }; + 15A02F7317A64DFB0035E92B /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F6D17A64DFB0035E92B /* Icon.icns */; }; + 15A02F7417A64DFB0035E92B /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F6E17A64DFB0035E92B /* Info.plist */; }; + 15A02F7517A64DFB0035E92B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 15A02F6F17A64DFB0035E92B /* main.m */; }; + 15A02F7B17A64E2A0035E92B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F7717A64E2A0035E92B /* InfoPlist.strings */; }; + 15A02F7C17A64E2A0035E92B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 15A02F7917A64E2A0035E92B /* MainMenu.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1501822117A6714D00E674E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 1551A33E158F2AB200E66CFE; + remoteInfo = "cocos2dx Mac"; + }; + 1501822317A6714D00E674E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = A03F2FC117814595006731B9; + remoteInfo = "cocos2dx-extensions Mac"; + }; + 1501822517A6714D00E674E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = A03F2E9817814268006731B9; + remoteInfo = "CocosDenshion Mac"; + }; + 1501822717A6714D00E674E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 1A6FB50417854BC200CDF010; + remoteInfo = "luabindings Mac"; + }; + 1501826C17A7512B00E674E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = A03F2B781780BD04006731B9; + remoteInfo = "chipmunk Mac"; + }; + 15A02F0617A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 1551A33F158F2AB200E66CFE; + remoteInfo = "cocos2dx Mac"; + }; + 15A02F0817A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A03F2FD617814595006731B9; + remoteInfo = "cocos2dx-extensions Mac"; + }; + 15A02F0A17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A03F2CB81780BD04006731B9; + remoteInfo = "chipmunk Mac"; + }; + 15A02F0C17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A03F2D9B1780BDF7006731B9; + remoteInfo = "box2d Mac"; + }; + 15A02F0E17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A03F2ED617814268006731B9; + remoteInfo = "CocosDenshion Mac"; + }; + 15A02F1017A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A03F31FD1781479B006731B9; + remoteInfo = "jsbindings Mac"; + }; + 15A02F1217A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 1A6FB53017854BC300CDF010; + remoteInfo = "luabindings Mac"; + }; + 15A02F1417A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A4D641783777C0073F6A7; + remoteInfo = "cocos2dx iOS"; + }; + 15A02F1617A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A4EFC1783867C0073F6A7; + remoteInfo = "cocos2dx-extensions iOS"; + }; + 15A02F1817A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A4F3B178387670073F6A7; + remoteInfo = "chipmunk iOS"; + }; + 15A02F1A17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A4F9E1783876B0073F6A7; + remoteInfo = "box2d iOS"; + }; + 15A02F1C17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A4FB4178387730073F6A7; + remoteInfo = "CocosDenshion iOS"; + }; + 15A02F1E17A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A07A5030178387750073F6A7; + remoteInfo = "jsbindings iOS"; + }; + 15A02F2017A64D060035E92B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 1A119791178526AA00D62A44; + remoteInfo = "luabindings iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 150181DD17A6636600E674E5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 150181DF17A6637B00E674E5 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + 150181E917A6670300E674E5 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 150181EC17A6679B00E674E5 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; }; + 150181EE17A667BC00E674E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 150181F317A6695400E674E5 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 150181F517A6696400E674E5 /* libcurl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcurl.dylib; path = usr/lib/libcurl.dylib; sourceTree = SDKROOT; }; + 1501825217A74F8000E674E5 /* AudioEngine.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AudioEngine.lua; sourceTree = ""; }; + 1501825317A74F8000E674E5 /* CCBReaderLoad.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CCBReaderLoad.lua; sourceTree = ""; }; + 1501825417A74F8000E674E5 /* Cocos2dConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cocos2dConstants.lua; sourceTree = ""; }; + 1501825517A74F8000E674E5 /* Deprecated.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Deprecated.lua; sourceTree = ""; }; + 1501825617A74F8000E674E5 /* DrawPrimitives.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DrawPrimitives.lua; sourceTree = ""; }; + 1501825717A74F8000E674E5 /* Opengl.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Opengl.lua; sourceTree = ""; }; + 1501825817A74F8000E674E5 /* OpenglConstants.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OpenglConstants.lua; sourceTree = ""; }; + 15A02E6017A647C90035E92B /* HelloLua.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloLua.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 15A02E6817A647C90035E92B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = cocos2d_libs.xcodeproj; path = ../../../cocos2d_libs.xcodeproj; sourceTree = ""; }; + 15A02F2417A64D1E0035E92B /* background.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = background.mp3; sourceTree = ""; }; + 15A02F2517A64D1E0035E92B /* background.ogg */ = {isa = PBXFileReference; lastKnownFileType = file; path = background.ogg; sourceTree = ""; }; + 15A02F2817A64D1E0035E92B /* crop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = crop.png; sourceTree = ""; }; + 15A02F2A17A64D1E0035E92B /* dog.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dog.png; sourceTree = ""; }; + 15A02F2C17A64D1E0035E92B /* effect1.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = effect1.wav; sourceTree = ""; }; + 15A02F2D17A64D1E0035E92B /* farm.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = farm.jpg; sourceTree = ""; }; + 15A02F3017A64D1E0035E92B /* hello.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hello.lua; sourceTree = ""; }; + 15A02F3117A64D1E0035E92B /* hello2.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hello2.lua; sourceTree = ""; }; + 15A02F3217A64D1E0035E92B /* land.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = land.png; sourceTree = ""; }; + 15A02F3317A64D1E0035E92B /* menu1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu1.png; sourceTree = ""; }; + 15A02F3417A64D1E0035E92B /* menu2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu2.png; sourceTree = ""; }; + 15A02F4B17A64D390035E92B /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = ""; }; + 15A02F4C17A64D390035E92B /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 15A02F6317A64DFB0035E92B /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; + 15A02F6417A64DFB0035E92B /* AppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppController.mm; sourceTree = ""; }; + 15A02F6D17A64DFB0035E92B /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; + 15A02F6E17A64DFB0035E92B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 15A02F6F17A64DFB0035E92B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 15A02F7817A64E2A0035E92B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = ""; }; + 15A02F7A17A64E2A0035E92B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = MainMenu.xib; sourceTree = ""; }; + 15A02F7D17A64EF30035E92B /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; + 15A02FAA17A65D810035E92B /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 15A02E5D17A647C90035E92B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1501826E17A7513400E674E5 /* libchipmunk Mac.a in Frameworks */, + 1501821D17A6706400E674E5 /* libcocos2dx Mac.a in Frameworks */, + 1501821E17A6706400E674E5 /* libcocos2dx-extensions Mac.a in Frameworks */, + 1501821F17A6706400E674E5 /* libCocosDenshion Mac.a in Frameworks */, + 1501822017A6706400E674E5 /* libluabindings Mac.a in Frameworks */, + 150181F417A6695400E674E5 /* libz.dylib in Frameworks */, + 150181F617A6696400E674E5 /* libcurl.dylib in Frameworks */, + 150181F117A6684F00E674E5 /* ApplicationServices.framework in Frameworks */, + 150181F017A667DA00E674E5 /* AudioToolbox.framework in Frameworks */, + 150181E517A663C800E674E5 /* Foundation.framework in Frameworks */, + 150181F217A6686400E674E5 /* Cocoa.framework in Frameworks */, + 150181EA17A6670300E674E5 /* OpenGL.framework in Frameworks */, + 150181DE17A6636600E674E5 /* QuartzCore.framework in Frameworks */, + 150181E817A6647000E674E5 /* OpenAL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1501825117A74F8000E674E5 /* Lua Common */ = { + isa = PBXGroup; + children = ( + 1501825217A74F8000E674E5 /* AudioEngine.lua */, + 1501825317A74F8000E674E5 /* CCBReaderLoad.lua */, + 1501825417A74F8000E674E5 /* Cocos2dConstants.lua */, + 1501825517A74F8000E674E5 /* Deprecated.lua */, + 1501825617A74F8000E674E5 /* DrawPrimitives.lua */, + 1501825717A74F8000E674E5 /* Opengl.lua */, + 1501825817A74F8000E674E5 /* OpenglConstants.lua */, + ); + name = "Lua Common"; + path = ../../../scripting/lua/script; + sourceTree = ""; + }; + 15A02E5717A647C90035E92B = { + isa = PBXGroup; + children = ( + 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */, + 15A02F4A17A64D390035E92B /* Classes */, + 15A02E6217A647C90035E92B /* Frameworks */, + 15A02F6217A64DFB0035E92B /* Mac */, + 1501825117A74F8000E674E5 /* Lua Common */, + 15A02E6117A647C90035E92B /* Products */, + 15A02F2217A64D1E0035E92B /* Resources */, + ); + sourceTree = ""; + }; + 15A02E6117A647C90035E92B /* Products */ = { + isa = PBXGroup; + children = ( + 15A02E6017A647C90035E92B /* HelloLua.app */, + ); + name = Products; + sourceTree = ""; + }; + 15A02E6217A647C90035E92B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 150181F517A6696400E674E5 /* libcurl.dylib */, + 150181F317A6695400E674E5 /* libz.dylib */, + 150181EC17A6679B00E674E5 /* ApplicationServices.framework */, + 150181EE17A667BC00E674E5 /* Cocoa.framework */, + 150181E917A6670300E674E5 /* OpenGL.framework */, + 150181DF17A6637B00E674E5 /* AudioToolbox.framework */, + 150181DD17A6636600E674E5 /* QuartzCore.framework */, + 15A02E6817A647C90035E92B /* Foundation.framework */, + 15A02FAA17A65D810035E92B /* OpenAL.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 15A02EF417A64D050035E92B /* Products */ = { + isa = PBXGroup; + children = ( + 15A02F0717A64D060035E92B /* libcocos2dx Mac.a */, + 15A02F0917A64D060035E92B /* libcocos2dx-extensions Mac.a */, + 15A02F0B17A64D060035E92B /* libchipmunk Mac.a */, + 15A02F0D17A64D060035E92B /* libbox2d Mac.a */, + 15A02F0F17A64D060035E92B /* libCocosDenshion Mac.a */, + 15A02F1117A64D060035E92B /* libjsbindings Mac.a */, + 15A02F1317A64D060035E92B /* libluabindings Mac.a */, + 15A02F1517A64D060035E92B /* libcocos2dx iOS.a */, + 15A02F1717A64D060035E92B /* libcocos2dx-extensions iOS.a */, + 15A02F1917A64D060035E92B /* libchipmunk iOS.a */, + 15A02F1B17A64D060035E92B /* libbox2d iOS.a */, + 15A02F1D17A64D060035E92B /* libCocosDenshion iOS.a */, + 15A02F1F17A64D060035E92B /* libjsbindings iOS.a */, + 15A02F2117A64D060035E92B /* libluabindings iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 15A02F2217A64D1E0035E92B /* Resources */ = { + isa = PBXGroup; + children = ( + 15A02F2417A64D1E0035E92B /* background.mp3 */, + 15A02F2517A64D1E0035E92B /* background.ogg */, + 15A02F2817A64D1E0035E92B /* crop.png */, + 15A02F2A17A64D1E0035E92B /* dog.png */, + 15A02F2C17A64D1E0035E92B /* effect1.wav */, + 15A02F2D17A64D1E0035E92B /* farm.jpg */, + 15A02F3017A64D1E0035E92B /* hello.lua */, + 15A02F3117A64D1E0035E92B /* hello2.lua */, + 15A02F3217A64D1E0035E92B /* land.png */, + 15A02F3317A64D1E0035E92B /* menu1.png */, + 15A02F3417A64D1E0035E92B /* menu2.png */, + ); + name = Resources; + path = ../Resources; + sourceTree = ""; + }; + 15A02F4A17A64D390035E92B /* Classes */ = { + isa = PBXGroup; + children = ( + 15A02F4B17A64D390035E92B /* AppDelegate.cpp */, + 15A02F4C17A64D390035E92B /* AppDelegate.h */, + ); + name = Classes; + path = ../Classes; + sourceTree = ""; + }; + 15A02F6217A64DFB0035E92B /* Mac */ = { + isa = PBXGroup; + children = ( + 15A02F7D17A64EF30035E92B /* Prefix.pch */, + 15A02F6317A64DFB0035E92B /* AppController.h */, + 15A02F6417A64DFB0035E92B /* AppController.mm */, + 15A02F7617A64E2A0035E92B /* en.lproj */, + 15A02F6D17A64DFB0035E92B /* Icon.icns */, + 15A02F6E17A64DFB0035E92B /* Info.plist */, + 15A02F6F17A64DFB0035E92B /* main.m */, + ); + name = Mac; + sourceTree = ""; + }; + 15A02F7617A64E2A0035E92B /* en.lproj */ = { + isa = PBXGroup; + children = ( + 15A02F7717A64E2A0035E92B /* InfoPlist.strings */, + 15A02F7917A64E2A0035E92B /* MainMenu.xib */, + ); + path = en.lproj; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 15A02E5F17A647C90035E92B /* HelloLua */ = { + isa = PBXNativeTarget; + buildConfigurationList = 15A02E9117A647CA0035E92B /* Build configuration list for PBXNativeTarget "HelloLua" */; + buildPhases = ( + 15A02E5C17A647C90035E92B /* Sources */, + 15A02E5D17A647C90035E92B /* Frameworks */, + 15A02E5E17A647C90035E92B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1501826D17A7512B00E674E5 /* PBXTargetDependency */, + 1501822217A6714D00E674E5 /* PBXTargetDependency */, + 1501822417A6714D00E674E5 /* PBXTargetDependency */, + 1501822617A6714D00E674E5 /* PBXTargetDependency */, + 1501822817A6714D00E674E5 /* PBXTargetDependency */, + ); + name = HelloLua; + productName = HelloLua; + productReference = 15A02E6017A647C90035E92B /* HelloLua.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 15A02E5817A647C90035E92B /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + ORGANIZATIONNAME = "Cocos2d-x"; + }; + buildConfigurationList = 15A02E5B17A647C90035E92B /* Build configuration list for PBXProject "HelloLua" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 15A02E5717A647C90035E92B; + productRefGroup = 15A02E6117A647C90035E92B /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 15A02EF417A64D050035E92B /* Products */; + ProjectRef = 15A02EF317A64D050035E92B /* cocos2d_libs.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 15A02E5F17A647C90035E92B /* HelloLua */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 15A02F0717A64D060035E92B /* libcocos2dx Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libcocos2dx Mac.a"; + remoteRef = 15A02F0617A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F0917A64D060035E92B /* libcocos2dx-extensions Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libcocos2dx-extensions Mac.a"; + remoteRef = 15A02F0817A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F0B17A64D060035E92B /* libchipmunk Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libchipmunk Mac.a"; + remoteRef = 15A02F0A17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F0D17A64D060035E92B /* libbox2d Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libbox2d Mac.a"; + remoteRef = 15A02F0C17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F0F17A64D060035E92B /* libCocosDenshion Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libCocosDenshion Mac.a"; + remoteRef = 15A02F0E17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1117A64D060035E92B /* libjsbindings Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libjsbindings Mac.a"; + remoteRef = 15A02F1017A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1317A64D060035E92B /* libluabindings Mac.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libluabindings Mac.a"; + remoteRef = 15A02F1217A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1517A64D060035E92B /* libcocos2dx iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libcocos2dx iOS.a"; + remoteRef = 15A02F1417A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1717A64D060035E92B /* libcocos2dx-extensions iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libcocos2dx-extensions iOS.a"; + remoteRef = 15A02F1617A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1917A64D060035E92B /* libchipmunk iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libchipmunk iOS.a"; + remoteRef = 15A02F1817A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1B17A64D060035E92B /* libbox2d iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libbox2d iOS.a"; + remoteRef = 15A02F1A17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1D17A64D060035E92B /* libCocosDenshion iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libCocosDenshion iOS.a"; + remoteRef = 15A02F1C17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F1F17A64D060035E92B /* libjsbindings iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libjsbindings iOS.a"; + remoteRef = 15A02F1E17A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 15A02F2117A64D060035E92B /* libluabindings iOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libluabindings iOS.a"; + remoteRef = 15A02F2017A64D060035E92B /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 15A02E5E17A647C90035E92B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 15A02F3817A64D1E0035E92B /* background.mp3 in Resources */, + 15A02F3917A64D1E0035E92B /* background.ogg in Resources */, + 15A02F3C17A64D1E0035E92B /* crop.png in Resources */, + 15A02F3E17A64D1E0035E92B /* dog.png in Resources */, + 15A02F4017A64D1E0035E92B /* effect1.wav in Resources */, + 15A02F4117A64D1E0035E92B /* farm.jpg in Resources */, + 15A02F4317A64D1E0035E92B /* hello.lua in Resources */, + 15A02F4417A64D1E0035E92B /* hello2.lua in Resources */, + 15A02F4517A64D1E0035E92B /* land.png in Resources */, + 15A02F4617A64D1E0035E92B /* menu1.png in Resources */, + 15A02F4717A64D1E0035E92B /* menu2.png in Resources */, + 15A02F7317A64DFB0035E92B /* Icon.icns in Resources */, + 15A02F7417A64DFB0035E92B /* Info.plist in Resources */, + 15A02F7B17A64E2A0035E92B /* InfoPlist.strings in Resources */, + 15A02F7C17A64E2A0035E92B /* MainMenu.xib in Resources */, + 1501825917A74F8000E674E5 /* AudioEngine.lua in Resources */, + 1501825A17A74F8000E674E5 /* CCBReaderLoad.lua in Resources */, + 1501825B17A74F8000E674E5 /* Cocos2dConstants.lua in Resources */, + 1501825C17A74F8000E674E5 /* Deprecated.lua in Resources */, + 1501825D17A74F8000E674E5 /* DrawPrimitives.lua in Resources */, + 1501825E17A74F8000E674E5 /* Opengl.lua in Resources */, + 1501825F17A74F8000E674E5 /* OpenglConstants.lua in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 15A02E5C17A647C90035E92B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 15A02F4D17A64D390035E92B /* AppDelegate.cpp in Sources */, + 15A02F7017A64DFB0035E92B /* AppController.mm in Sources */, + 15A02F7517A64DFB0035E92B /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1501822217A6714D00E674E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "cocos2dx Mac"; + targetProxy = 1501822117A6714D00E674E5 /* PBXContainerItemProxy */; + }; + 1501822417A6714D00E674E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "cocos2dx-extensions Mac"; + targetProxy = 1501822317A6714D00E674E5 /* PBXContainerItemProxy */; + }; + 1501822617A6714D00E674E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CocosDenshion Mac"; + targetProxy = 1501822517A6714D00E674E5 /* PBXContainerItemProxy */; + }; + 1501822817A6714D00E674E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "luabindings Mac"; + targetProxy = 1501822717A6714D00E674E5 /* PBXContainerItemProxy */; + }; + 1501826D17A7512B00E674E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "chipmunk Mac"; + targetProxy = 1501826C17A7512B00E674E5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 15A02F7717A64E2A0035E92B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 15A02F7817A64E2A0035E92B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 15A02F7917A64E2A0035E92B /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 15A02F7A17A64E2A0035E92B /* en */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 15A02E8F17A647CA0035E92B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = macosx; + }; + name = Debug; + }; + 15A02E9017A647CA0035E92B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx; + }; + name = Release; + }; + 15A02E9217A647CA0035E92B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_CONSTANT_CONVERSION = NO; + CLANG_WARN_EMPTY_BODY = NO; + CLANG_WARN_ENUM_CONVERSION = NO; + CLANG_WARN_INT_CONVERSION = NO; + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + USE_FILE32API, + CC_TARGET_OS_MAC, + "COCOS2D_DEBUG=1", + "CC_ENABLE_CHIPMUNK_INTEGRATION=1", + CC_KEYBOARD_SUPPORT, + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../../cocos2dx\"", + "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", + "\"$(SRCROOT)/../../../scripting/lua/tolua\"", + "\"$(SRCROOT)/../../../scripting/lua/luajit/include\"", + "\"$(SRCROOT)/../../../scripting/lua/cocos2dx_support\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/mac\"", + "\"$(SRCROOT)/../../../cocos2dx/include\"", + "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", + "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", + "\"$(SRCROOT)/../../../external\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/mac\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/mac/Simulation\"", + "\"$(SRCROOT)/../../../extensions\"", + ); + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(SRCROOT)/../../../cocos2dx/platform/third_party/mac/libraries", + "$(inherited)", + "\"$(SRCROOT)/../../../scripting/lua/luajit/mac\"", + ); + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "-O2"; + "OTHER_LDFLAGS[arch=x86_64]" = ( + "-pagezero_size", + 10000, + "-image_base", + 100000000, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "i386 x86_64"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 15A02E9317A647CA0035E92B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_CONSTANT_CONVERSION = NO; + CLANG_WARN_EMPTY_BODY = NO; + CLANG_WARN_ENUM_CONVERSION = NO; + CLANG_WARN_INT_CONVERSION = NO; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + CC_TARGET_OS_MAC, + USE_FILE32API, + "CC_ENABLE_CHIPMUNK_INTEGRATION=1", + CC_KEYBOARD_SUPPORT, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../../cocos2dx\"", + "\"$(SRCROOT)/../../../cocos2dx/kazmath/include\"", + "\"$(SRCROOT)/../../../scripting/lua/tolua\"", + "\"$(SRCROOT)/../../../scripting/lua/luajit/include\"", + "\"$(SRCROOT)/../../../scripting/lua/cocos2dx_support\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/mac\"", + "\"$(SRCROOT)/../../../cocos2dx/include\"", + "\"$(SRCROOT)/../../../CocosDenshion/include\"", + "\"$(SRCROOT)/../../../external/chipmunk/include/chipmunk\"", + "\"$(SRCROOT)/../../../external/chipmunk/include/constraints\"", + "\"$(SRCROOT)/../../../external\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/third_party/mac\"", + "\"$(SRCROOT)/../../../cocos2dx/platform/mac/Simulation\"", + "\"$(SRCROOT)/../../../extensions\"", + ); + INFOPLIST_FILE = Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; + LIBRARY_SEARCH_PATHS = ( + "$(SRCROOT)/../../../cocos2dx/platform/third_party/mac/libraries", + "$(inherited)", + "\"$(SRCROOT)/../../../scripting/lua/luajit/mac\"", + ); + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + "OTHER_LDFLAGS[arch=x86_64]" = ( + "-pagezero_size", + 10000, + "-image_base", + 100000000, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "i386 x86_64"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 15A02E5B17A647C90035E92B /* Build configuration list for PBXProject "HelloLua" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 15A02E8F17A647CA0035E92B /* Debug */, + 15A02E9017A647CA0035E92B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 15A02E9117A647CA0035E92B /* Build configuration list for PBXNativeTarget "HelloLua" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 15A02E9217A647CA0035E92B /* Debug */, + 15A02E9317A647CA0035E92B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 15A02E5817A647C90035E92B /* Project object */; +} diff --git a/template/multi-platform-lua/proj.mac/Icon.icns b/template/multi-platform-lua/proj.mac/Icon.icns new file mode 100644 index 0000000000..285dee82b3 Binary files /dev/null and b/template/multi-platform-lua/proj.mac/Icon.icns differ diff --git a/template/multi-platform-lua/proj.mac/Prefix.pch b/template/multi-platform-lua/proj.mac/Prefix.pch new file mode 100644 index 0000000000..46c36a7e99 --- /dev/null +++ b/template/multi-platform-lua/proj.mac/Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Paralaxer' target in the 'Paralaxer' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/template/multi-platform-lua/proj.mac/en.lproj/InfoPlist.strings b/template/multi-platform-lua/proj.mac/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000..477b28ff8f --- /dev/null +++ b/template/multi-platform-lua/proj.mac/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/template/multi-platform-lua/proj.mac/en.lproj/MainMenu.xib b/template/multi-platform-lua/proj.mac/en.lproj/MainMenu.xib new file mode 100644 index 0000000000..9f99439250 --- /dev/null +++ b/template/multi-platform-lua/proj.mac/en.lproj/MainMenu.xib @@ -0,0 +1,812 @@ + + + + 1060 + 10K549 + 1938 + 1038.36 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 1938 + + + YES + NSMenuItem + NSCustomObject + NSMenu + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + HelloCpp + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + HelloCpp + + YES + + + About HelloCpp + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide HelloCpp + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit HelloCpp + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + YES + + + Toggle Fullscreen + f + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + YES + + + HelloCpp Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + AppController + + + NSFontManager + + + + + YES + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + performZoom: + + + + 240 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + showHelp: + + + + 493 + + + + toggleFullScreen: + + + + 537 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 57 + + + YES + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + YES + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + YES + + + + + + 296 + + + YES + + + + + + 420 + + + + + 490 + + + YES + + + + + + 491 + + + YES + + + + + + 492 + + + + + 494 + + + + + 536 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 129.IBPluginDependency + 130.IBPluginDependency + 131.IBPluginDependency + 134.IBPluginDependency + 136.IBPluginDependency + 143.IBPluginDependency + 144.IBPluginDependency + 145.IBPluginDependency + 149.IBPluginDependency + 150.IBPluginDependency + 19.IBPluginDependency + 23.IBPluginDependency + 236.IBPluginDependency + 239.IBPluginDependency + 24.IBPluginDependency + 29.IBPluginDependency + 295.IBPluginDependency + 296.IBPluginDependency + 420.IBPluginDependency + 490.IBPluginDependency + 491.IBPluginDependency + 492.IBPluginDependency + 494.IBPluginDependency + 5.IBPluginDependency + 536.IBPluginDependency + 56.IBPluginDependency + 57.IBPluginDependency + 58.IBPluginDependency + 92.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + + + + YES + + + + + 541 + + + + YES + + AppController + NSObject + + YES + + YES + exitFullScreen: + toggleFullScreen: + + + YES + id + id + + + + YES + + YES + exitFullScreen: + toggleFullScreen: + + + YES + + exitFullScreen: + id + + + toggleFullScreen: + id + + + + + YES + + YES + glView + window + + + YES + EAGLView + Window + + + + YES + + YES + glView + window + + + YES + + glView + EAGLView + + + window + Window + + + + + IBProjectSource + ./Classes/AppController.h + + + + EAGLView + NSOpenGLView + + IBProjectSource + ./Classes/EAGLView.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + YES + + YES + NSMenuCheckmark + NSMenuMixedState + + + YES + {9, 8} + {7, 2} + + + + diff --git a/template/multi-platform-lua/proj.mac/main.m b/template/multi-platform-lua/proj.mac/main.m new file mode 100644 index 0000000000..97d9b73282 --- /dev/null +++ b/template/multi-platform-lua/proj.mac/main.m @@ -0,0 +1,30 @@ +/**************************************************************************** + Copyright (c) 2010 cocos2d-x.org + + 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 + 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. + ****************************************************************************/ + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **)argv); +} diff --git a/tools/bindings-generator b/tools/bindings-generator index 6c084a87f6..4b76994a1f 160000 --- a/tools/bindings-generator +++ b/tools/bindings-generator @@ -1 +1 @@ -Subproject commit 6c084a87f667091088dfb46c3a8ef2b4cc84897b +Subproject commit 4b76994a1f54a78bdac944fcd5cae41d42123447 diff --git a/tools/project_creator/create_project.py b/tools/project_creator/create_project.py index 482bd177f2..88a3060ca1 100755 --- a/tools/project_creator/create_project.py +++ b/tools/project_creator/create_project.py @@ -7,7 +7,7 @@ # define global variables PLATFORMS = { "cpp" : ["ios", "android", "win32", "mac", "linux"], - "lua" : ["ios", "android", "win32", "linux"], + "lua" : ["ios", "android", "win32", "mac","linux"], "javascript" : ["ios", "android", "win32"] } @@ -95,8 +95,9 @@ def processPlatformProjects(context, platform): proj_path = os.path.join(context["dst_project_path"], "proj." + platform) java_package_path = "" - # read json config file or the current platform - f = open("%s.json" % platform) + # read json config file for the current platform + conf_path = os.path.join(context["script_dir"], "%s.json" % platform) + f = open(conf_path) data = json.load(f) # rename package path, like "org.cocos2dx.hello" to "com.company.game". This is a special process for android diff --git a/tools/tojs/README.mdown b/tools/tojs/README.mdown index c447a072fa..d0897de1d5 100644 --- a/tools/tojs/README.mdown +++ b/tools/tojs/README.mdown @@ -1,7 +1,7 @@ How to Use bindings-generator ================== -On Windows: +On Windows (Not available from 3.0-pre-alpha0, the reason is that Clang3.3 can't work perfectly on windows, therefore, disable windows support temporary.): ------------ * Make sure that you have installed `android-ndk-r8d` or higher version. diff --git a/tools/tojs/genbindings-win32.bat b/tools/tojs/genbindings-win32.bat deleted file mode 100644 index 6a620c69ed..0000000000 --- a/tools/tojs/genbindings-win32.bat +++ /dev/null @@ -1,69 +0,0 @@ -@echo off - -:: This script is used to generate jsbinding glue codes. -:: You should modify PYTHON_ROOT and NDK_ROOT to work under your environment. -:: Android ndk version must be at least ndk-r8d. - -set PYTHON_ROOT=C:/Python27 -set NDK_ROOT=C:/android-ndk-r8d - -set PATH=%PATH%;%cd%/win32;%PYTHON_ROOT% -set COCOS2DX_ROOT=%cd%/../.. -set "COCOS2DX_ROOT=%COCOS2DX_ROOT:\=/%" -set CXX_GENERATOR_ROOT=%COCOS2DX_ROOT%/tools/bindings-generator -set TO_JS_ROOT=%COCOS2DX_ROOT%/tools/tojs -set "CXX_GENERATOR_ROOT=%CXX_GENERATOR_ROOT:\=/%" -set OUTPUT_DIR=%COCOS2DX_ROOT%/scripting/javascript/bindings/generated -set "OUTPUT_DIR=%OUTPUT_DIR:/=\%" -set CLANG_ROOT=%NDK_ROOT%/toolchains/llvm-3.1/prebuilt/windows - -:: write userconf.ini - -set _CONF_INI_FILE=%cd%\userconf.ini -if exist %_CONF_INI_FILE% del /Q %_CONF_INI_FILE% - - -echo -echo generating userconf.ini... -echo --- -echo [DEFAULT] > %_CONF_INI_FILE% -echo androidndkdir=%NDK_ROOT% >> %_CONF_INI_FILE% -echo clangllvmdir=%CLANG_ROOT% >> %_CONF_INI_FILE% -echo cocosdir=%COCOS2DX_ROOT% >> %_CONF_INI_FILE% -echo cxxgeneratordir=%CXX_GENERATOR_ROOT% >> %_CONF_INI_FILE% -echo extra_flags=-D__ARM_EABI__ -D__GNUC__=2 >> %_CONF_INI_FILE% -echo --- - - - -:: Generate bindings for cocos2dx -echo Generating bindings for cocos2dx... - -python %CXX_GENERATOR_ROOT%/generator.py %TO_JS_ROOT%/cocos2dx.ini -s cocos2d-x -o %OUTPUT_DIR% -n jsb_cocos2dx_auto -if %errorlevel% neq 0 goto ERROR - -echo "Generating bindings for cocos2dx_extension..." - -python %CXX_GENERATOR_ROOT%/generator.py %TO_JS_ROOT%/cocos2dx_extension.ini -s cocos2dx_extension -o %OUTPUT_DIR% -n jsb_cocos2dx_extension_auto -if %errorlevel% neq 0 goto ERROR - -:: Change the generated file format from DOS to UNIX. -pushd "%OUTPUT_DIR%" -dos2unix * -popd - -echo --------------------------------- -echo Generating bindings succeeds. -echo --------------------------------- - -goto QUIT - -:ERROR -echo --------------------------------- -echo Generating bindings fails. -echo --------------------------------- - -:QUIT - -pause - diff --git a/tools/tojs/win32/cygiconv-2.dll.REMOVED.git-id b/tools/tojs/win32/cygiconv-2.dll.REMOVED.git-id deleted file mode 100644 index 304f71e385..0000000000 --- a/tools/tojs/win32/cygiconv-2.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -f8bcb5d3cb13f170075570db09276e65d4f435ed \ No newline at end of file diff --git a/tools/tojs/win32/cygwin1.dll.REMOVED.git-id b/tools/tojs/win32/cygwin1.dll.REMOVED.git-id deleted file mode 100644 index 1448e4df9a..0000000000 --- a/tools/tojs/win32/cygwin1.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -71cde86196932ad943470198ad5fcbafd47ea949 \ No newline at end of file diff --git a/tools/tojs/win32/libclang.dll.REMOVED.git-id b/tools/tojs/win32/libclang.dll.REMOVED.git-id deleted file mode 100644 index 44d359c68c..0000000000 --- a/tools/tojs/win32/libclang.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -bdb8f0397dc43d13bcc1b5c6bee3ff132c6b230b \ No newline at end of file diff --git a/tools/tolua++/CCDrawNode.pkg b/tools/tolua++/CCDrawNode.pkg new file mode 100644 index 0000000000..f8a28cef5e --- /dev/null +++ b/tools/tolua++/CCDrawNode.pkg @@ -0,0 +1,22 @@ +class CCDrawNode : public CCNode +{ + static CCDrawNode* create(); + + CCDrawNode(); + + virtual ~CCDrawNode(); + + virtual bool init(); + + void drawDot(const CCPoint &pos, float radius, const Color4F &color); + + void drawSegment(const CCPoint &from, const CCPoint &to, float radius, const Color4F &color); + + void clear(); + + const BlendFunc& getBlendFunc() const; + + void setBlendFunc(const BlendFunc &blendFunc); + + virtual void draw(); +}; diff --git a/tools/tolua++/CCDrawingPrimitives.pkg b/tools/tolua++/CCDrawingPrimitives.pkg deleted file mode 100644 index 2a46584e55..0000000000 --- a/tools/tolua++/CCDrawingPrimitives.pkg +++ /dev/null @@ -1,19 +0,0 @@ - -void ccDrawPoint(CCPoint point); -void ccDrawPoints(const CCPoint *points, unsigned int numberOfPoints); -void ccDrawLine(CCPoint origin, CCPoint destination); -void ccDrawRect(CCPoint origin, CCPoint destination); -void ccDrawSolidRect(CCPoint origin, CCPoint destination, Color4F color); -void ccDrawPoly(const CCPoint *vertices, unsigned int numOfVertices, bool closePolygon); -void ccDrawSolidPoly(const CCPoint* poli, unsigned int numberOfPoints, Color4F color); -void ccDrawCircle(const CCPoint& center, float radius, float angle, unsigned int segments, bool drawLineToCenter, float xScale = 1.0f, float yScale = 1.0f); -void ccDrawQuadBezier(CCPoint origin, CCPoint control, CCPoint destination, unsigned int segments); -void ccDrawCubicBezier(CCPoint origin, CCPoint control1, CCPoint control2, CCPoint destination, unsigned int segments); -void ccDrawCatmullRom(CCPointArray* arrayOfControlPoints, unsigned int segments); -void ccDrawCardinalSpline(CCPointArray* config, float tension, unsigned int segments); -void ccDrawColor4B(GLubyte r, GLubyte g, GLubyte b, GLubyte a); -void ccDrawColor4F(GLubyte r, GLubyte g, GLubyte b, GLubyte a); -void ccPointSize(GLfloat pointSize); - -// glew.h API: -// void glLineWidth(GLfloat width); diff --git a/tools/tolua++/CCImage.pkg b/tools/tolua++/CCImage.pkg index 0e339c3aa1..87638721a9 100644 --- a/tools/tolua++/CCImage.pkg +++ b/tools/tolua++/CCImage.pkg @@ -27,11 +27,15 @@ class CCImage : public CCObject kAlignTopLeft = 0x11, ///< Horizontal left and vertical top. }ETextAlign; + typedef enum + { + kColorGray = 0, + kColorRGB, + }EColorType; - bool initWithImageFile(const char * strPath, EImageFormat imageType = kFmtPng); + bool initWithImageFile(const char * strPath); bool initWithImageData(void * pData, int nDataLen, - EImageFormat eFmt = kFmtUnKnown, int nWidth = 0, int nHeight = 0, int nBitsPerComponent = 8); @@ -50,7 +54,7 @@ class CCImage : public CCObject bool hasAlpha(); bool isPremultipliedAlpha(); bool saveToFile(const char *pszFilePath, bool bIsToRGB = true); - unsigned short getWidth(); - unsigned short getHeight(); - int getBitsPerComponent(); + int getWidth(); + int getHeight(); + int getBitPerPixel(); }; diff --git a/tools/tolua++/CCTextureCache.pkg b/tools/tolua++/CCTextureCache.pkg index 9a00040ac9..b0dfa15d3d 100644 --- a/tools/tolua++/CCTextureCache.pkg +++ b/tools/tolua++/CCTextureCache.pkg @@ -1,20 +1,18 @@ - -class CCTextureCache : public CCObject -{ - CCTexture2D* addImage(const char* fileimage); - CCTexture2D* addUIImage(CCImage *image, const char *key); - CCTexture2D* textureForKey(const char* key); - - CCTexture2D* addPVRImage(const char* filename); - - void removeAllTextures(); - void removeUnusedTextures(); - void removeTexture(CCTexture2D* texture); - void removeTextureForKey(const char *textureKeyName); - void dumpCachedTextureInfo(); - - static void reloadAllTextures(); - - static CCTextureCache * getInstance(); - static void destroyInstance(); -}; + +class CCTextureCache : public CCObject +{ + CCTexture2D* addImage(const char* fileimage); + CCTexture2D* addUIImage(CCImage *image, const char *key); + CCTexture2D* textureForKey(const char* key); + + void removeAllTextures(); + void removeUnusedTextures(); + void removeTexture(CCTexture2D* texture); + void removeTextureForKey(const char *textureKeyName); + void dumpCachedTextureInfo(); + + static void reloadAllTextures(); + + static CCTextureCache * getInstance(); + static void destroyInstance(); +}; diff --git a/tools/tolua++/Cocos2d.pkg b/tools/tolua++/Cocos2d.pkg index 685a0d274d..d0ff69ca65 100644 --- a/tools/tolua++/Cocos2d.pkg +++ b/tools/tolua++/Cocos2d.pkg @@ -13,7 +13,6 @@ $pfile "CCEGLViewProtocol.pkg" $pfile "CCProtocols.pkg" $pfile "CCFileUtils.pkg" -$pfile "CCDrawingPrimitives.pkg" $pfile "CCAffineTransform.pkg" $pfile "CCApplication.pkg" $pfile "CCTouchDispatcher.pkg" @@ -86,3 +85,4 @@ $pfile "CCControlPotentiometer.pkg" $pfile "CCControlStepper.pkg" $pfile "CCEditBox.pkg" $pfile "CCInteger.pkg" +$pfile "CCDrawNode.pkg" diff --git a/tools/tolua++/basic.lua b/tools/tolua++/basic.lua index ee50a6b941..110591b59c 100644 --- a/tools/tolua++/basic.lua +++ b/tools/tolua++/basic.lua @@ -198,6 +198,7 @@ local CCObjectTypes = { "CCControlSwitch", "CCEditBox", "CCInteger", + "CCDrawNode", } -- register CCObject types diff --git a/tools/travis-scripts/before-install.sh b/tools/travis-scripts/before-install.sh index c08f5ebc70..07ff3e10a2 100755 --- a/tools/travis-scripts/before-install.sh +++ b/tools/travis-scripts/before-install.sh @@ -95,6 +95,8 @@ if [ "$GEN_JSB"x = "YES"x ]; then install_llvm elif [ "$PLATFORM"x = "linux"x ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + # OpenMW team provides SDL2 package. + sudo apt-add-repository -y ppa:openmw/build sudo apt-get update sudo apt-get install gcc-4.7 g++-4.7 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6