From 0d5c7027083d41b6512b722234b05dd7701649e9 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Thu, 13 Feb 2014 21:08:43 +0800 Subject: [PATCH] move labelttf's platform-dependent code from CCImage to CCDevice --- .../project.pbxproj.REMOVED.git-id | 2 +- cocos/2d/Android.mk | 1 + cocos/2d/CCTexture2D.cpp | 127 ++--- cocos/2d/CMakeLists.txt | 3 +- cocos/2d/cocos2d.vcxproj | 3 +- cocos/2d/cocos2d.vcxproj.filters | 9 +- cocos/2d/platform/CCDevice.h | 17 + .../{CCImageCommon_cpp.h => CCImage.cpp} | 0 cocos/2d/platform/CCImage.h | 60 --- cocos/2d/platform/android/Android.mk | 1 - cocos/2d/platform/android/CCDevice.cpp | 163 ++++++ cocos/2d/platform/android/CCImage.cpp | 251 --------- cocos/2d/platform/ios/CCDevice.mm | 312 +++++++++++ cocos/2d/platform/ios/CCImage.mm | 350 +------------ cocos/2d/platform/linux/CCDevice.cpp | 431 +++++++++++++++ cocos/2d/platform/linux/CCImage.cpp | 494 ------------------ cocos/2d/platform/mac/CCDevice.cpp | 51 -- .../platform/mac/{CCImage.mm => CCDevice.mm} | 110 ++-- cocos/2d/platform/win32/CCDevice.cpp | 403 ++++++++++++++ cocos/2d/platform/win32/CCImage.cpp | 448 ---------------- 20 files changed, 1425 insertions(+), 1811 deletions(-) rename cocos/2d/platform/{CCImageCommon_cpp.h => CCImage.cpp} (100%) delete mode 100644 cocos/2d/platform/android/CCImage.cpp delete mode 100644 cocos/2d/platform/linux/CCImage.cpp delete mode 100644 cocos/2d/platform/mac/CCDevice.cpp rename cocos/2d/platform/mac/{CCImage.mm => CCDevice.mm} (81%) delete mode 100644 cocos/2d/platform/win32/CCImage.cpp diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index d0de5e36a3..294c135f19 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -490db6577af8dba2213a78e7eeef17d1dc60db3a \ No newline at end of file +635f17db87974af37b9774d3c038ce25808e3d27 \ No newline at end of file diff --git a/cocos/2d/Android.mk b/cocos/2d/Android.mk index 06baeeef45..9932cd34a9 100644 --- a/cocos/2d/Android.mk +++ b/cocos/2d/Android.mk @@ -115,6 +115,7 @@ platform/CCGLViewProtocol.cpp \ platform/CCFileUtils.cpp \ platform/CCSAXParser.cpp \ platform/CCThread.cpp \ +platform/CCImage.cpp \ renderer/CCCustomCommand.cpp \ renderer/CCFrustum.cpp \ renderer/CCGroupCommand.cpp \ diff --git a/cocos/2d/CCTexture2D.cpp b/cocos/2d/CCTexture2D.cpp index 17ec6d2e3f..3c69c7f614 100644 --- a/cocos/2d/CCTexture2D.cpp +++ b/cocos/2d/CCTexture2D.cpp @@ -43,6 +43,7 @@ THE SOFTWARE. #include "CCGLProgram.h" #include "ccGLStateCache.h" #include "CCShaderCache.h" +#include "platform/CCDevice.h" #if CC_ENABLE_CACHE_TEXTURE_DATA #include "CCTextureCache.h" @@ -1039,28 +1040,30 @@ bool Texture2D::initWithString(const char *text, const char *fontName, float fon bool Texture2D::initWithString(const char *text, const FontDefinition& textDefinition) { + if(!text || 0 == strlen(text)) + return false; #if CC_ENABLE_CACHE_TEXTURE_DATA // cache the texture data VolatileTextureMgr::addStringTexture(this, text, textDefinition); #endif bool ret = false; - Image::TextAlign align; + Device::TextAlign align; if (TextVAlignment::TOP == textDefinition._vertAlignment) { - align = (TextHAlignment::CENTER == textDefinition._alignment) ? Image::TextAlign::TOP - : (TextHAlignment::LEFT == textDefinition._alignment) ? Image::TextAlign::TOP_LEFT : Image::TextAlign::TOP_RIGHT; + align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::TOP + : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::TOP_LEFT : Device::TextAlign::TOP_RIGHT; } else if (TextVAlignment::CENTER == textDefinition._vertAlignment) { - align = (TextHAlignment::CENTER == textDefinition._alignment) ? Image::TextAlign::CENTER - : (TextHAlignment::LEFT == textDefinition._alignment) ? Image::TextAlign::LEFT : Image::TextAlign::RIGHT; + align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::CENTER + : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::LEFT : Device::TextAlign::RIGHT; } else if (TextVAlignment::BOTTOM == textDefinition._vertAlignment) { - align = (TextHAlignment::CENTER == textDefinition._alignment) ? Image::TextAlign::BOTTOM - : (TextHAlignment::LEFT == textDefinition._alignment) ? Image::TextAlign::BOTTOM_LEFT : Image::TextAlign::BOTTOM_RIGHT; + align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::BOTTOM + : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::BOTTOM_LEFT : Device::TextAlign::BOTTOM_RIGHT; } else { @@ -1068,93 +1071,37 @@ bool Texture2D::initWithString(const char *text, const FontDefinition& textDefin return false; } -#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) - - // handle shadow parameters - bool shadowEnabled = false; - float shadowDX = 0.0f; - float shadowDY = 0.0f; - float shadowBlur = 0.0f; - float shadowOpacity = 0.0f; - - if ( textDefinition._shadow._shadowEnabled ) - { - shadowEnabled = true; - shadowDX = textDefinition._shadow._shadowOffset.width; - shadowDY = textDefinition._shadow._shadowOffset.height; - shadowBlur = textDefinition._shadow._shadowBlur; - shadowOpacity = textDefinition._shadow._shadowOpacity; - } - - // handle stroke parameters - bool strokeEnabled = false; - float strokeColorR = 0.0f; - float strokeColorG = 0.0f; - float strokeColorB = 0.0f; - float strokeSize = 0.0f; - - if ( textDefinition._stroke._strokeEnabled ) - { - strokeEnabled = true; - strokeColorR = textDefinition._stroke._strokeColor.r / 255.0f; - strokeColorG = textDefinition._stroke._strokeColor.g / 255.0f; - strokeColorB = textDefinition._stroke._strokeColor.b / 255.0f; - strokeSize = textDefinition._stroke._strokeSize; - } - - Image* image = new Image(); - do - { - CC_BREAK_IF(nullptr == image); - - ret = image->initWithStringShadowStroke(text, - (int)textDefinition._dimensions.width, - (int)textDefinition._dimensions.height, - align, - textDefinition._fontName.c_str(), - textDefinition._fontSize, - textDefinition._fontFillColor.r / 255.0f, - textDefinition._fontFillColor.g / 255.0f, - textDefinition._fontFillColor.b / 255.0f, - shadowEnabled, - shadowDX, - shadowDY, - shadowOpacity, - shadowBlur, - strokeEnabled, - strokeColorR, - strokeColorG, - strokeColorB, - strokeSize); - - - CC_BREAK_IF(!ret); - ret = initWithImage(image); - - } while (0); - - CC_SAFE_RELEASE(image); - - return ret; - -#else +#if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) && (CC_TARGET_PLATFORM != CC_PLATFORM_IOS) bool requestUnsupported = textDefinition._shadow._shadowEnabled || textDefinition._stroke._strokeEnabled; CCASSERT(requestUnsupported == false, "Currently shadow and stroke only supported on iOS and Android!"); - - Image* image = new Image(); - do - { - CC_BREAK_IF(nullptr == image); - ret = image->initWithString(text, (int)textDefinition._dimensions.width, (int)textDefinition._dimensions.height, align, textDefinition._fontName.c_str(), (int)textDefinition._fontSize); - CC_BREAK_IF(!ret); - ret = initWithImage(image); - } while (0); - - CC_SAFE_RELEASE(image); - - return ret; #endif + + PixelFormat pixelFormat = g_defaultAlphaPixelFormat; + unsigned char* outTempData = nullptr; + ssize_t outTempDataLen = 0; + + int imageWidth; + int imageHeight; + Data outData = Device::getTextureDataForText(text,textDefinition,align,imageWidth,imageHeight); + if(outData.isNull()) + return false; + + Size imageSize = Size((float)imageWidth, (float)imageHeight); + pixelFormat = convertDataToFormat(outData.getBytes(), imageWidth*imageHeight*4, PixelFormat::RGBA8888, pixelFormat, &outTempData, &outTempDataLen); + + ret = initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize); + + if (outTempData != nullptr && outTempData != outData.getBytes()) + { + delete [] outTempData; + } +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX) + _hasPremultipliedAlpha = true; +#else + _hasPremultipliedAlpha = false; +#endif + return ret; } diff --git a/cocos/2d/CMakeLists.txt b/cocos/2d/CMakeLists.txt index 18133edc9d..43e552f704 100644 --- a/cocos/2d/CMakeLists.txt +++ b/cocos/2d/CMakeLists.txt @@ -8,7 +8,6 @@ set(PLATFORM_SRC platform/win32/CCCommon.cpp platform/win32/CCApplication.cpp platform/win32/CCGLView.cpp - platform/win32/CCImage.cpp platform/win32/CCDevice.cpp ) @@ -22,7 +21,6 @@ set(PLATFORM_SRC platform/linux/CCCommon.cpp platform/linux/CCApplication.cpp platform/desktop/CCGLView.cpp - platform/linux/CCImage.cpp platform/linux/CCDevice.cpp ) @@ -136,6 +134,7 @@ set(COCOS2D_SRC platform/CCThread.cpp platform/CCGLViewProtocol.cpp platform/CCFileUtils.cpp + platform/CCImage.cpp ../../external/edtaa3func/edtaa3func.cpp renderer/CCCustomCommand.cpp renderer/CCFrustum.cpp diff --git a/cocos/2d/cocos2d.vcxproj b/cocos/2d/cocos2d.vcxproj index 8a158e44f0..f6f71ee254 100644 --- a/cocos/2d/cocos2d.vcxproj +++ b/cocos/2d/cocos2d.vcxproj @@ -306,6 +306,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou + @@ -313,7 +314,6 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou - @@ -508,7 +508,6 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou - diff --git a/cocos/2d/cocos2d.vcxproj.filters b/cocos/2d/cocos2d.vcxproj.filters index 29491e4794..30c886db92 100644 --- a/cocos/2d/cocos2d.vcxproj.filters +++ b/cocos/2d/cocos2d.vcxproj.filters @@ -357,9 +357,6 @@ platform\win32 - - platform\win32 - platform\win32 @@ -598,6 +595,9 @@ platform\desktop + + platform + @@ -885,9 +885,6 @@ platform - - platform - platform diff --git a/cocos/2d/platform/CCDevice.h b/cocos/2d/platform/CCDevice.h index 0bea8f2000..acbdd7a885 100644 --- a/cocos/2d/platform/CCDevice.h +++ b/cocos/2d/platform/CCDevice.h @@ -28,12 +28,27 @@ THE SOFTWARE. #include "CCPlatformMacros.h" #include "ccMacros.h" +#include "CCData.h" NS_CC_BEGIN +struct FontDefinition; + class CC_DLL Device { public: + enum class TextAlign + { + CENTER = 0x33, ///< Horizontal center and vertical center. + TOP = 0x13, ///< Horizontal center and vertical top. + TOP_RIGHT = 0x12, ///< Horizontal right and vertical top. + RIGHT = 0x32, ///< Horizontal right and vertical center. + BOTTOM_RIGHT = 0x22, ///< Horizontal right and vertical bottom. + BOTTOM = 0x23, ///< Horizontal center and vertical bottom. + BOTTOM_LEFT = 0x21, ///< Horizontal left and vertical bottom. + LEFT = 0x31, ///< Horizontal left and vertical center. + TOP_LEFT = 0x11, ///< Horizontal left and vertical top. + }; /** * Gets the DPI of device * @return The DPI of device. @@ -49,6 +64,8 @@ public: */ static void setAccelerometerInterval(float interval); + static Data getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &widht,int &height); + private: CC_DISALLOW_IMPLICIT_CONSTRUCTORS(Device); }; diff --git a/cocos/2d/platform/CCImageCommon_cpp.h b/cocos/2d/platform/CCImage.cpp similarity index 100% rename from cocos/2d/platform/CCImageCommon_cpp.h rename to cocos/2d/platform/CCImage.cpp diff --git a/cocos/2d/platform/CCImage.h b/cocos/2d/platform/CCImage.h index 03de5e6eba..7ef352507b 100644 --- a/cocos/2d/platform/CCImage.h +++ b/cocos/2d/platform/CCImage.h @@ -94,19 +94,6 @@ public: UNKOWN }; - enum class TextAlign - { - CENTER = 0x33, ///< Horizontal center and vertical center. - TOP = 0x13, ///< Horizontal center and vertical top. - TOP_RIGHT = 0x12, ///< Horizontal right and vertical top. - RIGHT = 0x32, ///< Horizontal right and vertical center. - BOTTOM_RIGHT = 0x22, ///< Horizontal right and vertical bottom. - BOTTOM = 0x23, ///< Horizontal center and vertical bottom. - BOTTOM_LEFT = 0x21, ///< Horizontal left and vertical bottom. - LEFT = 0x31, ///< Horizontal left and vertical center. - TOP_LEFT = 0x11, ///< Horizontal left and vertical top. - }; - /** @brief Load the image from the specified path. @param path the absolute file path. @@ -127,53 +114,6 @@ public: // @warning kFmtRawData only support RGBA8888 bool initWithRawData(const unsigned char * data, ssize_t dataLen, int width, int height, int bitsPerComponent, bool preMulti = false); - /** - @brief Create image with specified string. - @param text the text the image will show (cannot be nil). - @param width the image width, if 0, the width will match the text's width. - @param height the image height, if 0, the height will match the text's height. - @param alignMask the test Alignment - @param fontName the name of the font used to draw the text. If nil, use the default system font. - @param size the font size, if 0, use the system default size. - * @js NA - * @lua NA - */ - bool initWithString( - const char * text, - int width = 0, - int height = 0, - TextAlign alignMask = TextAlign::CENTER, - const char * fontName = 0, - int size = 0); - - #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) - - bool initWithStringShadowStroke( - const char * pText, - int nWidth = 0, - int nHeight = 0, - TextAlign eAlignMask = TextAlign::CENTER, - const char * pFontName = 0, - int nSize = 0, - float textTintR = 1, - float textTintG = 1, - float textTintB = 1, - bool shadow = false, - float shadowOffsetX = 0.0, - float shadowOffsetY = 0.0, - float shadowOpacity = 0.0, - float shadowBlur = 0.0, - bool stroke = false, - float strokeR = 1, - float strokeG = 1, - float strokeB = 1, - float strokeSize = 1 - - ); - - #endif - - // Getters inline unsigned char * getData() { return _data; } inline ssize_t getDataLen() { return _dataLen; } diff --git a/cocos/2d/platform/android/Android.mk b/cocos/2d/platform/android/Android.mk index 3d27ede872..f84ea6d5ca 100644 --- a/cocos/2d/platform/android/Android.mk +++ b/cocos/2d/platform/android/Android.mk @@ -12,7 +12,6 @@ CCCommon.cpp \ CCDevice.cpp \ CCGLView.cpp \ CCFileUtilsAndroid.cpp \ -CCImage.cpp \ nativeactivity.cpp \ jni/DPIJni.cpp \ jni/IMEJni.cpp \ diff --git a/cocos/2d/platform/android/CCDevice.cpp b/cocos/2d/platform/android/CCDevice.cpp index 74ea1cd858..f30790afb7 100644 --- a/cocos/2d/platform/android/CCDevice.cpp +++ b/cocos/2d/platform/android/CCDevice.cpp @@ -27,8 +27,14 @@ THE SOFTWARE. #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID #include "platform/CCDevice.h" +#include +#include +#include +#include "ccTypes.h" #include "jni/DPIJni.h" +#include "jni/JniHelper.h" #include "nativeactivity.h" +#include "platform/CCFileUtils.h" NS_CC_BEGIN @@ -59,7 +65,164 @@ void Device::setAccelerometerInterval(float interval) setAccelerometerIntervalJni(interval); } +class BitmapDC +{ +public: + + BitmapDC() + : _data(NULL) + , _width(0) + , _height(0) + { + } + + ~BitmapDC(void) + { + if (_data) + { + delete [] _data; + } + } + + bool getBitmapFromJavaShadowStroke( const char *text, + int nWidth, + int nHeight, + Device::TextAlign eAlignMask, + const char * pFontName, + float fontSize, + float textTintR = 1.0, + float textTintG = 1.0, + float textTintB = 1.0, + bool shadow = false, + float shadowDeltaX = 0.0, + float shadowDeltaY = 0.0, + float shadowBlur = 0.0, + float shadowOpacity = 0.0, + bool stroke = false, + float strokeColorR = 0.0, + float strokeColorG = 0.0, + float strokeColorB = 0.0, + float strokeSize = 0.0 ) + { + JniMethodInfo methodInfo; + if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmapShadowStroke", + "(Ljava/lang/String;Ljava/lang/String;IFFFIIIZFFFFZFFFF)Z")) + { + CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__); + return false; + } + + // Do a full lookup for the font path using FileUtils in case the given font name is a relative path to a font file asset, + // or the path has been mapped to a different location in the app package: + std::string fullPathOrFontName = FileUtils::getInstance()->fullPathForFilename(pFontName); + + // If the path name returned includes the 'assets' dir then that needs to be removed, because the android.content.Context + // requires this portion of the path to be omitted for assets inside the app package. + if (fullPathOrFontName.find("assets/") == 0) + { + fullPathOrFontName = fullPathOrFontName.substr(strlen("assets/")); // Chop out the 'assets/' portion of the path. + } + + /**create bitmap + * this method call Cococs2dx.createBitmap()(java code) to create the bitmap, the java code + * will call Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC() to init the width, height + * and data. + * use this approach to decrease the jni call number + */ + jstring jstrText = methodInfo.env->NewStringUTF(text); + jstring jstrFont = methodInfo.env->NewStringUTF(fullPathOrFontName.c_str()); + + if(!shadow) + { + shadowDeltaX = 0.0f; + shadowDeltaY = 0.0f; + shadowBlur = 0.0f; + shadowOpacity = 0.0f; + } + if (!stroke) + { + strokeColorR = 0.0f; + strokeColorG = 0.0f; + strokeColorB = 0.0f; + strokeSize = 0.0f; + } + if(!methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID, jstrText, + jstrFont, (int)fontSize, textTintR, textTintG, textTintB, eAlignMask, nWidth, nHeight, shadow, shadowDeltaX, -shadowDeltaY, shadowBlur, shadowOpacity, stroke, strokeColorR, strokeColorG, strokeColorB, strokeSize)) + { + return false; + } + + methodInfo.env->DeleteLocalRef(jstrText); + methodInfo.env->DeleteLocalRef(jstrFont); + methodInfo.env->DeleteLocalRef(methodInfo.classID); + + return true; + } + +public: + int _width; + int _height; + unsigned char *_data; + JNIEnv *env; +}; + +static BitmapDC& sharedBitmapDC() +{ + static BitmapDC s_BmpDC; + return s_BmpDC; +} + +Data Device::getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &width,int &height) +{ + Data ret; + do + { + BitmapDC &dc = sharedBitmapDC(); + + if(! dc.getBitmapFromJavaShadowStroke(text, + (int)textDefinition._dimensions.width, + (int)textDefinition._dimensions.height, + align, textDefinition._fontName.c_str(), + textDefinition._fontSize, + textDefinition._fontFillColor.r / 255.0f, + textDefinition._fontFillColor.g / 255.0f, + textDefinition._fontFillColor.b / 255.0f, + textDefinition._shadow._shadowEnabled, + textDefinition._shadow._shadowOffset.width, + textDefinition._shadow._shadowOffset.height, + textDefinition._shadow._shadowBlur, + textDefinition._shadow._shadowOpacity, + textDefinition._stroke._strokeEnabled, + textDefinition._stroke._strokeColor.r / 255.0f, + textDefinition._stroke._strokeColor.g / 255.0f, + textDefinition._stroke._strokeColor.b / 255.0f, + textDefinition._stroke._strokeSize )) { break;}; + + width = dc._width; + height = dc._height; + ret.fastSet(dc._data,width * height * 4); + } while (0); + + return ret; +} + NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +// this method is called by Cocos2dxBitmap +extern "C" +{ + /** + * this method is called by java code to init width, height and pixels data + */ + JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC(JNIEnv* env, jobject thiz, int width, int height, jbyteArray pixels) + { + int size = width * height * 4; + cocos2d::BitmapDC& bitmapDC = cocos2d::sharedBitmapDC(); + bitmapDC._width = width; + bitmapDC._height = height; + bitmapDC._data = new unsigned char[size]; + env->GetByteArrayRegion(pixels, 0, size, (jbyte*)bitmapDC._data); + } +}; diff --git a/cocos/2d/platform/android/CCImage.cpp b/cocos/2d/platform/android/CCImage.cpp deleted file mode 100644 index 213ed4d6ee..0000000000 --- a/cocos/2d/platform/android/CCImage.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2014 Chukong Technologies Inc. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -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 "CCPlatformConfig.h" -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID - -#define __CC_PLATFORM_IMAGE_CPP__ -#include "platform/CCImageCommon_cpp.h" -#include "CCPlatformMacros.h" -#include "platform/CCImage.h" -#include "platform/CCFileUtils.h" -#include "jni/JniHelper.h" - -#include -#include -#include - -NS_CC_BEGIN - -class BitmapDC -{ -public: - - BitmapDC() - : _data(NULL) - , _width(0) - , _height(0) - { - } - - ~BitmapDC(void) - { - if (_data) - { - delete [] _data; - } - } - - bool getBitmapFromJavaShadowStroke( const char *text, - int nWidth, - int nHeight, - Image::TextAlign eAlignMask, - const char * pFontName, - float fontSize, - float textTintR = 1.0, - float textTintG = 1.0, - float textTintB = 1.0, - bool shadow = false, - float shadowDeltaX = 0.0, - float shadowDeltaY = 0.0, - float shadowBlur = 0.0, - float shadowOpacity = 0.0, - bool stroke = false, - float strokeColorR = 0.0, - float strokeColorG = 0.0, - float strokeColorB = 0.0, - float strokeSize = 0.0 ) - { - JniMethodInfo methodInfo; - if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmapShadowStroke", - "(Ljava/lang/String;Ljava/lang/String;IFFFIIIZFFFFZFFFF)Z")) - { - CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__); - return false; - } - - - - // Do a full lookup for the font path using FileUtils in case the given font name is a relative path to a font file asset, - // or the path has been mapped to a different location in the app package: - std::string fullPathOrFontName = FileUtils::getInstance()->fullPathForFilename(pFontName); - - // If the path name returned includes the 'assets' dir then that needs to be removed, because the android.content.Context - // requires this portion of the path to be omitted for assets inside the app package. - if (fullPathOrFontName.find("assets/") == 0) - { - fullPathOrFontName = fullPathOrFontName.substr(strlen("assets/")); // Chop out the 'assets/' portion of the path. - } - - /**create bitmap - * this method call Cococs2dx.createBitmap()(java code) to create the bitmap, the java code - * will call Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC() to init the width, height - * and data. - * use this approach to decrease the jni call number - */ - jstring jstrText = methodInfo.env->NewStringUTF(text); - jstring jstrFont = methodInfo.env->NewStringUTF(fullPathOrFontName.c_str()); - - if(!methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID, jstrText, - jstrFont, (int)fontSize, textTintR, textTintG, textTintB, eAlignMask, nWidth, nHeight, shadow, shadowDeltaX, -shadowDeltaY, shadowBlur, shadowOpacity, stroke, strokeColorR, strokeColorG, strokeColorB, strokeSize)) - { - return false; - } - - - methodInfo.env->DeleteLocalRef(jstrText); - methodInfo.env->DeleteLocalRef(jstrFont); - methodInfo.env->DeleteLocalRef(methodInfo.classID); - - return true; - } - - - bool getBitmapFromJava(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) - { - return getBitmapFromJavaShadowStroke( text, nWidth, nHeight, eAlignMask, pFontName, fontSize ); - } - -public: - int _width; - int _height; - unsigned char *_data; - JNIEnv *env; -}; - -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(); - - CC_BREAK_IF(! dc.getBitmapFromJava(pText, nWidth, nHeight, eAlignMask, pFontName, nSize)); - - // assign the dc._data to _data in order to save time - _data = dc._data; - CC_BREAK_IF(! _data); - - _width = (short)dc._width; - _height = (short)dc._height; - _preMulti = true; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - _dataLen = _width * _height * 4; - - bRet = true; - } while (0); - - return bRet; -} - -bool Image::initWithStringShadowStroke( - const char * pText, - int nWidth , - int nHeight , - TextAlign eAlignMask , - const char * pFontName , - int nSize , - float textTintR, - float textTintG, - float textTintB, - bool shadow, - float shadowOffsetX, - float shadowOffsetY, - float shadowOpacity, - float shadowBlur, - bool stroke, - float strokeR, - float strokeG, - float strokeB, - float strokeSize) -{ - bool bRet = false; - do - { - CC_BREAK_IF(! pText); - - BitmapDC &dc = sharedBitmapDC(); - - - CC_BREAK_IF(! dc.getBitmapFromJavaShadowStroke(pText, nWidth, nHeight, eAlignMask, pFontName, - nSize, textTintR, textTintG, textTintB, shadow, - shadowOffsetX, shadowOffsetY, shadowBlur, shadowOpacity, - stroke, strokeR, strokeG, strokeB, strokeSize )); - - - // assign the dc._data to _data in order to save time - _data = dc._data; - - CC_BREAK_IF(! _data); - - _width = (short)dc._width; - _height = (short)dc._height; - _preMulti = true; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - _dataLen = _width * _height * 4; - - // ok - bRet = true; - - } while (0); - - return bRet; -} - -NS_CC_END - -// this method is called by Cocos2dxBitmap -extern "C" -{ - /** - * this method is called by java code to init width, height and pixels data - */ - JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC(JNIEnv* env, jobject thiz, int width, int height, jbyteArray pixels) - { - int size = width * height * 4; - cocos2d::BitmapDC& bitmapDC = cocos2d::sharedBitmapDC(); - bitmapDC._width = width; - bitmapDC._height = height; - bitmapDC._data = new unsigned char[size]; - env->GetByteArrayRegion(pixels, 0, size, (jbyte*)bitmapDC._data); - } -}; - -#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID diff --git a/cocos/2d/platform/ios/CCDevice.mm b/cocos/2d/platform/ios/CCDevice.mm index cbf04d092f..fa6f51132c 100644 --- a/cocos/2d/platform/ios/CCDevice.mm +++ b/cocos/2d/platform/ios/CCDevice.mm @@ -177,7 +177,319 @@ void Device::setAccelerometerInterval(float interval) [[CCAccelerometerDispatcher sharedAccelerometerDispather] setAccelerometerInterval:interval]; } +typedef struct +{ + unsigned int height; + unsigned int width; + bool isPremultipliedAlpha; + bool hasShadow; + CGSize shadowOffset; + float shadowBlur; + float shadowOpacity; + bool hasStroke; + float strokeColorR; + float strokeColorG; + float strokeColorB; + float strokeSize; + float tintColorR; + float tintColorG; + float tintColorB; + + unsigned char* data; + +} tImageInfo; + +static CGSize _calculateStringSize(NSString *str, id font, CGSize *constrainSize) +{ + NSArray *listItems = [str componentsSeparatedByString: @"\n"]; + CGSize dim = CGSizeZero; + CGSize textRect = CGSizeZero; + textRect.width = constrainSize->width > 0 ? constrainSize->width + : 0x7fffffff; + textRect.height = constrainSize->height > 0 ? constrainSize->height + : 0x7fffffff; + + + for (NSString *s in listItems) + { + CGSize tmp = [s sizeWithFont:font constrainedToSize:textRect]; + + if (tmp.width > dim.width) + { + dim.width = tmp.width; + } + + dim.height += tmp.height; + } + + return dim; +} + +// refer Image::ETextAlign +#define ALIGN_TOP 1 +#define ALIGN_CENTER 3 +#define ALIGN_BOTTOM 2 + +static bool _initWithString(const char * text, cocos2d::Device::TextAlign align, const char * fontName, int size, tImageInfo* info) +{ + bool bRet = false; + do + { + CC_BREAK_IF(! text || ! info); + + NSString * str = [NSString stringWithUTF8String:text]; + NSString * fntName = [NSString stringWithUTF8String:fontName]; + + CGSize dim, constrainSize; + + constrainSize.width = info->width; + constrainSize.height = info->height; + + // On iOS custom fonts must be listed beforehand in the App info.plist (in order to be usable) and referenced only the by the font family name itself when + // calling [UIFont fontWithName]. Therefore even if the developer adds 'SomeFont.ttf' or 'fonts/SomeFont.ttf' to the App .plist, the font must + // be referenced as 'SomeFont' when calling [UIFont fontWithName]. Hence we strip out the folder path components and the extension here in order to get just + // the font family name itself. This stripping step is required especially for references to user fonts stored in CCB files; CCB files appear to store + // the '.ttf' extensions when referring to custom fonts. + fntName = [[fntName lastPathComponent] stringByDeletingPathExtension]; + + // create the font + id font = [UIFont fontWithName:fntName size:size]; + + if (font) + { + dim = _calculateStringSize(str, font, &constrainSize); + } + else + { + if (!font) + { + font = [UIFont systemFontOfSize:size]; + } + + if (font) + { + dim = _calculateStringSize(str, font, &constrainSize); + } + } + + CC_BREAK_IF(! font); + + // compute start point + int startH = 0; + if (constrainSize.height > dim.height) + { + // vertical alignment + unsigned int vAlignment = ((int)align >> 4) & 0x0F; + if (vAlignment == ALIGN_TOP) + { + startH = 0; + } + else if (vAlignment == ALIGN_CENTER) + { + startH = (constrainSize.height - dim.height) / 2; + } + else + { + startH = constrainSize.height - dim.height; + } + } + + // adjust text rect + if (constrainSize.width > 0 && constrainSize.width > dim.width) + { + dim.width = constrainSize.width; + } + if (constrainSize.height > 0 && constrainSize.height > dim.height) + { + dim.height = constrainSize.height; + } + + + // compute the padding needed by shadow and stroke + float shadowStrokePaddingX = 0.0f; + float shadowStrokePaddingY = 0.0f; + + if ( info->hasStroke ) + { + shadowStrokePaddingX = ceilf(info->strokeSize); + shadowStrokePaddingY = ceilf(info->strokeSize); + } + + if ( info->hasShadow ) + { + shadowStrokePaddingX = std::max(shadowStrokePaddingX, (float)fabs(info->shadowOffset.width)); + shadowStrokePaddingY = std::max(shadowStrokePaddingY, (float)fabs(info->shadowOffset.height)); + } + + // add the padding (this could be 0 if no shadow and no stroke) + dim.width += shadowStrokePaddingX; + dim.height += shadowStrokePaddingY; + + + unsigned char* data = new unsigned char[(int)(dim.width * dim.height * 4)]; + memset(data, 0, (int)(dim.width * dim.height * 4)); + + // draw text + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(data, + dim.width, + dim.height, + 8, + (int)(dim.width) * 4, + colorSpace, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + if (!context) + { + CGColorSpaceRelease(colorSpace); + delete[] data; + break; + } + + // text color + CGContextSetRGBFillColor(context, info->tintColorR, info->tintColorG, info->tintColorB, 1); + // move Y rendering to the top of the image + CGContextTranslateCTM(context, 0.0f, (dim.height - shadowStrokePaddingY) ); + CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential + + // store the current context + UIGraphicsPushContext(context); + + // measure text size with specified font and determine the rectangle to draw text in + unsigned uHoriFlag = (int)align & 0x0f; + UITextAlignment testAlign = (UITextAlignment)((2 == uHoriFlag) ? UITextAlignmentRight + : (3 == uHoriFlag) ? UITextAlignmentCenter + : UITextAlignmentLeft); + + + // take care of stroke if needed + if ( info->hasStroke ) + { + CGContextSetTextDrawingMode(context, kCGTextFillStroke); + CGContextSetRGBStrokeColor(context, info->strokeColorR, info->strokeColorG, info->strokeColorB, 1); + CGContextSetLineWidth(context, info->strokeSize); + } + + // take care of shadow if needed + if ( info->hasShadow ) + { + CGSize offset; + offset.height = info->shadowOffset.height; + offset.width = info->shadowOffset.width; + CGFloat shadowColorValues[] = {0, 0, 0, info->shadowOpacity}; + CGColorRef shadowColor = CGColorCreate (colorSpace, shadowColorValues); + + CGContextSetShadowWithColor(context, offset, info->shadowBlur, shadowColor); + + CGColorRelease (shadowColor); + } + + CGColorSpaceRelease(colorSpace); + + + // normal fonts + //if( [font isKindOfClass:[UIFont class] ] ) + //{ + // [str drawInRect:CGRectMake(0, startH, dim.width, dim.height) withFont:font lineBreakMode:(UILineBreakMode)UILineBreakModeWordWrap alignment:align]; + //} + //else // ZFont class + //{ + // [FontLabelStringDrawingHelper drawInRect:str rect:CGRectMake(0, startH, dim.width, dim.height) withZFont:font lineBreakMode:(UILineBreakMode)UILineBreakModeWordWrap + ////alignment:align]; + //} + + + + // compute the rect used for rendering the text + // based on wether shadows or stroke are enabled + + float textOriginX = 0.0; + float textOrigingY = 0.0; + + float textWidth = dim.width - shadowStrokePaddingX; + float textHeight = dim.height - shadowStrokePaddingY; + + + if ( info->shadowOffset.width < 0 ) + { + textOriginX = shadowStrokePaddingX; + } + else + { + textOriginX = 0.0; + } + + if (info->shadowOffset.height > 0) + { + textOrigingY = startH; + } + else + { + textOrigingY = startH - shadowStrokePaddingY; + } + + CGRect rect = CGRectMake(textOriginX, textOrigingY, textWidth, textHeight); + + CGContextBeginTransparencyLayerWithRect(context, rect, nullptr); + // actually draw the text in the context + // XXX: ios7 casting + [str drawInRect: rect withFont:font lineBreakMode:NSLineBreakByWordWrapping alignment:(NSTextAlignment)testAlign]; + + CGContextEndTransparencyLayer(context); + + // pop the context + UIGraphicsPopContext(); + + // release the context + CGContextRelease(context); + + // output params + info->data = data; + info->isPremultipliedAlpha = true; + info->width = dim.width; + info->height = dim.height; + bRet = true; + + } while (0); + + return bRet; +} + + +Data Device::getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &width,int &height) +{ + Data ret; + + do { + tImageInfo info = {0}; + info.width = textDefinition._dimensions.width; + info.height = textDefinition._dimensions.height; + info.hasShadow = textDefinition._shadow._shadowEnabled; + info.shadowOffset.width = textDefinition._shadow._shadowOffset.width; + info.shadowOffset.height = textDefinition._shadow._shadowOffset.height; + info.shadowBlur = textDefinition._shadow._shadowBlur; + info.shadowOpacity = textDefinition._shadow._shadowOpacity; + info.hasStroke = textDefinition._stroke._strokeEnabled; + info.strokeColorR = textDefinition._stroke._strokeColor.r; + info.strokeColorG = textDefinition._stroke._strokeColor.g; + info.strokeColorB = textDefinition._stroke._strokeColor.b; + info.strokeSize = textDefinition._stroke._strokeSize; + info.tintColorR = textDefinition._fontFillColor.r; + info.tintColorG = textDefinition._fontFillColor.g; + info.tintColorB = textDefinition._fontFillColor.b; + + if (! _initWithString(text, align, textDefinition._fontName.c_str(), textDefinition._fontSize, &info)) + { + break; + } + height = (short)info.height; + widht = (short)info.width; + ret.fastSet(info.data,width * height * 4); + } while (0); + + return ret; +} NS_CC_END #endif // CC_PLATFORM_IOS + diff --git a/cocos/2d/platform/ios/CCImage.mm b/cocos/2d/platform/ios/CCImage.mm index 4d5ba92fe9..483c703a7c 100644 --- a/cocos/2d/platform/ios/CCImage.mm +++ b/cocos/2d/platform/ios/CCImage.mm @@ -26,10 +26,7 @@ THE SOFTWARE. #include "CCPlatformConfig.h" #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS -#include "CCImageCommon_cpp.h" - #import "CCImage.h" -#import "CCFileUtils.h" #import "platform/CCCommon.h" #import @@ -38,354 +35,9 @@ THE SOFTWARE. #include - -typedef struct -{ - unsigned int height; - unsigned int width; - bool isPremultipliedAlpha; - bool hasShadow; - CGSize shadowOffset; - float shadowBlur; - float shadowOpacity; - bool hasStroke; - float strokeColorR; - float strokeColorG; - float strokeColorB; - float strokeSize; - float tintColorR; - float tintColorG; - float tintColorB; - - unsigned char* data; - -} tImageInfo; - -static CGSize _calculateStringSize(NSString *str, id font, CGSize *constrainSize) -{ - NSArray *listItems = [str componentsSeparatedByString: @"\n"]; - CGSize dim = CGSizeZero; - CGSize textRect = CGSizeZero; - textRect.width = constrainSize->width > 0 ? constrainSize->width - : 0x7fffffff; - textRect.height = constrainSize->height > 0 ? constrainSize->height - : 0x7fffffff; - - - for (NSString *s in listItems) - { - CGSize tmp = [s sizeWithFont:font constrainedToSize:textRect]; - - if (tmp.width > dim.width) - { - dim.width = tmp.width; - } - - dim.height += tmp.height; - } - - return dim; -} - -// refer Image::ETextAlign -#define ALIGN_TOP 1 -#define ALIGN_CENTER 3 -#define ALIGN_BOTTOM 2 - -static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, const char * fontName, int size, tImageInfo* info) -{ - bool bRet = false; - do - { - CC_BREAK_IF(! text || ! info); - - NSString * str = [NSString stringWithUTF8String:text]; - NSString * fntName = [NSString stringWithUTF8String:fontName]; - - CGSize dim, constrainSize; - - constrainSize.width = info->width; - constrainSize.height = info->height; - - // On iOS custom fonts must be listed beforehand in the App info.plist (in order to be usable) and referenced only the by the font family name itself when - // calling [UIFont fontWithName]. Therefore even if the developer adds 'SomeFont.ttf' or 'fonts/SomeFont.ttf' to the App .plist, the font must - // be referenced as 'SomeFont' when calling [UIFont fontWithName]. Hence we strip out the folder path components and the extension here in order to get just - // the font family name itself. This stripping step is required especially for references to user fonts stored in CCB files; CCB files appear to store - // the '.ttf' extensions when referring to custom fonts. - fntName = [[fntName lastPathComponent] stringByDeletingPathExtension]; - - // create the font - id font = [UIFont fontWithName:fntName size:size]; - - if (font) - { - dim = _calculateStringSize(str, font, &constrainSize); - } - else - { - if (!font) - { - font = [UIFont systemFontOfSize:size]; - } - - if (font) - { - dim = _calculateStringSize(str, font, &constrainSize); - } - } - - CC_BREAK_IF(! font); - - // compute start point - int startH = 0; - if (constrainSize.height > dim.height) - { - // vertical alignment - unsigned int vAlignment = ((int)align >> 4) & 0x0F; - if (vAlignment == ALIGN_TOP) - { - startH = 0; - } - else if (vAlignment == ALIGN_CENTER) - { - startH = (constrainSize.height - dim.height) / 2; - } - else - { - startH = constrainSize.height - dim.height; - } - } - - // adjust text rect - if (constrainSize.width > 0 && constrainSize.width > dim.width) - { - dim.width = constrainSize.width; - } - if (constrainSize.height > 0 && constrainSize.height > dim.height) - { - dim.height = constrainSize.height; - } - - - // compute the padding needed by shadow and stroke - float shadowStrokePaddingX = 0.0f; - float shadowStrokePaddingY = 0.0f; - - if ( info->hasStroke ) - { - shadowStrokePaddingX = ceilf(info->strokeSize); - shadowStrokePaddingY = ceilf(info->strokeSize); - } - - if ( info->hasShadow ) - { - shadowStrokePaddingX = std::max(shadowStrokePaddingX, (float)fabs(info->shadowOffset.width)); - shadowStrokePaddingY = std::max(shadowStrokePaddingY, (float)fabs(info->shadowOffset.height)); - } - - // add the padding (this could be 0 if no shadow and no stroke) - dim.width += shadowStrokePaddingX; - dim.height += shadowStrokePaddingY; - - - unsigned char* data = new unsigned char[(int)(dim.width * dim.height * 4)]; - memset(data, 0, (int)(dim.width * dim.height * 4)); - - // draw text - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate(data, - dim.width, - dim.height, - 8, - (int)(dim.width) * 4, - colorSpace, - kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); - if (!context) - { - CGColorSpaceRelease(colorSpace); - delete[] data; - break; - } - - // text color - CGContextSetRGBFillColor(context, info->tintColorR, info->tintColorG, info->tintColorB, 1); - // move Y rendering to the top of the image - CGContextTranslateCTM(context, 0.0f, (dim.height - shadowStrokePaddingY) ); - CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential - - // store the current context - UIGraphicsPushContext(context); - - // measure text size with specified font and determine the rectangle to draw text in - unsigned uHoriFlag = (int)align & 0x0f; - UITextAlignment testAlign = (UITextAlignment)((2 == uHoriFlag) ? UITextAlignmentRight - : (3 == uHoriFlag) ? UITextAlignmentCenter - : UITextAlignmentLeft); - - - // take care of stroke if needed - if ( info->hasStroke ) - { - CGContextSetTextDrawingMode(context, kCGTextFillStroke); - CGContextSetRGBStrokeColor(context, info->strokeColorR, info->strokeColorG, info->strokeColorB, 1); - CGContextSetLineWidth(context, info->strokeSize); - } - - // take care of shadow if needed - if ( info->hasShadow ) - { - CGSize offset; - offset.height = info->shadowOffset.height; - offset.width = info->shadowOffset.width; - CGFloat shadowColorValues[] = {0, 0, 0, info->shadowOpacity}; - CGColorRef shadowColor = CGColorCreate (colorSpace, shadowColorValues); - - CGContextSetShadowWithColor(context, offset, info->shadowBlur, shadowColor); - - CGColorRelease (shadowColor); - } - - CGColorSpaceRelease(colorSpace); - - - // normal fonts - //if( [font isKindOfClass:[UIFont class] ] ) - //{ - // [str drawInRect:CGRectMake(0, startH, dim.width, dim.height) withFont:font lineBreakMode:(UILineBreakMode)UILineBreakModeWordWrap alignment:align]; - //} - //else // ZFont class - //{ - // [FontLabelStringDrawingHelper drawInRect:str rect:CGRectMake(0, startH, dim.width, dim.height) withZFont:font lineBreakMode:(UILineBreakMode)UILineBreakModeWordWrap - ////alignment:align]; - //} - - - - // compute the rect used for rendering the text - // based on wether shadows or stroke are enabled - - float textOriginX = 0.0; - float textOrigingY = 0.0; - - float textWidth = dim.width - shadowStrokePaddingX; - float textHeight = dim.height - shadowStrokePaddingY; - - - if ( info->shadowOffset.width < 0 ) - { - textOriginX = shadowStrokePaddingX; - } - else - { - textOriginX = 0.0; - } - - if (info->shadowOffset.height > 0) - { - textOrigingY = startH; - } - else - { - textOrigingY = startH - shadowStrokePaddingY; - } - - CGRect rect = CGRectMake(textOriginX, textOrigingY, textWidth, textHeight); - - CGContextBeginTransparencyLayerWithRect(context, rect, nullptr); - // actually draw the text in the context - // XXX: ios7 casting - [str drawInRect: rect withFont:font lineBreakMode:NSLineBreakByWordWrapping alignment:(NSTextAlignment)testAlign]; - - CGContextEndTransparencyLayer(context); - - // pop the context - UIGraphicsPopContext(); - - // release the context - CGContextRelease(context); - - // output params - info->data = data; - info->isPremultipliedAlpha = true; - info->width = dim.width; - info->height = dim.height; - bRet = true; - - } while (0); - - return bRet; -} - NS_CC_BEGIN -bool Image::initWithString( - const char * pText, - int nWidth /* = 0 */, - int nHeight /* = 0 */, - TextAlign eAlignMask /* = kAlignCenter */, - const char * pFontName /* = nil */, - int nSize /* = 0 */) -{ - return initWithStringShadowStroke(pText, nWidth, nHeight, eAlignMask , pFontName, nSize); -} - -bool Image::initWithStringShadowStroke( - const char * text, - int width , - int height , - TextAlign alignMask , - const char * fontName , - int size , - float textTintR, - float textTintG, - float textTintB, - bool shadow, - float shadowOffsetX, - float shadowOffsetY, - float shadowOpacity, - float shadowBlur, - bool stroke, - float strokeR, - float strokeG, - float strokeB, - float strokeSize) -{ - - - - tImageInfo info = {0}; - info.width = width; - info.height = height; - info.hasShadow = shadow; - info.shadowOffset.width = shadowOffsetX; - info.shadowOffset.height = shadowOffsetY; - info.shadowBlur = shadowBlur; - info.shadowOpacity = shadowOpacity; - info.hasStroke = stroke; - info.strokeColorR = strokeR; - info.strokeColorG = strokeG; - info.strokeColorB = strokeB; - info.strokeSize = strokeSize; - info.tintColorR = textTintR; - info.tintColorG = textTintG; - info.tintColorB = textTintB; - - - if (! _initWithString(text, alignMask, fontName, size, &info)) - { - return false; - } - _height = (short)info.height; - _width = (short)info.width; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - _preMulti = info.isPremultipliedAlpha; - _data = info.data; - _dataLen = _width * _height * 4; - - return true; -} - -bool Image::saveToFile(const std::string& filename, bool isToRGB) +bool cocos2d::Image::saveToFile(const std::string& filename, bool isToRGB) { bool saveToPNG = false; bool needToCopyPixels = false; diff --git a/cocos/2d/platform/linux/CCDevice.cpp b/cocos/2d/platform/linux/CCDevice.cpp index 683522a337..b062a658a7 100644 --- a/cocos/2d/platform/linux/CCDevice.cpp +++ b/cocos/2d/platform/linux/CCDevice.cpp @@ -30,6 +30,51 @@ THE SOFTWARE. #include #include +#include +#include +#include +#include +#include +#include +#include "platform/CCFileUtils.h" + +#include "ft2build.h" +#include FT_FREETYPE_H + +using namespace std; + +// as FcFontMatch is quite an expensive call, cache the results of getFontFile +static std::map fontCache; + +struct LineBreakGlyph { + FT_UInt glyphIndex; + int paintPosition; + int glyphWidth; + + int bearingX; + int kerning; + int horizAdvance; +}; + +struct LineBreakLine { + LineBreakLine() : lineWidth(0) {} + + std::vector glyphs; + int lineWidth; + + void reset() { + glyphs.clear(); + lineWidth = 0; + } + + void calculateWidth() { + lineWidth = 0; + if ( glyphs.empty() == false ) { + lineWidth = glyphs.at(glyphs.size() - 1).paintPosition + glyphs.at(glyphs.size() - 1).glyphWidth; + } + } +}; + NS_CC_BEGIN int Device::getDPI() @@ -67,6 +112,392 @@ void Device::setAccelerometerInterval(float interval) } +class BitmapDC +{ +public: + BitmapDC() { + libError = FT_Init_FreeType( &library ); + FcInit(); + _data = NULL; + reset(); + } + + ~BitmapDC() { + FT_Done_FreeType(library); + FcFini(); + + reset(); + } + + void reset() { + iMaxLineWidth = 0; + iMaxLineHeight = 0; + textLines.clear(); + } + + int utf8(char **p) + { + if ((**p & 0x80) == 0x00) + { + int a = *((*p)++); + + return a; + } + if ((**p & 0xE0) == 0xC0) + { + int a = *((*p)++) & 0x1F; + int b = *((*p)++) & 0x3F; + + return (a << 6) | b; + } + if ((**p & 0xF0) == 0xE0) + { + int a = *((*p)++) & 0x0F; + int b = *((*p)++) & 0x3F; + int c = *((*p)++) & 0x3F; + + return (a << 12) | (b << 6) | c; + } + if ((**p & 0xF8) == 0xF0) + { + int a = *((*p)++) & 0x07; + int b = *((*p)++) & 0x3F; + int c = *((*p)++) & 0x3F; + int d = *((*p)++) & 0x3F; + + return (a << 18) | (b << 12) | (c << 8) | d; + } + return 0; + } + + bool isBreakPoint(FT_UInt currentCharacter, FT_UInt previousCharacter) { + if ( previousCharacter == '-' || previousCharacter == '/' || previousCharacter == '\\' ) { + // we can insert a line break after one of these characters + return true; + } + return false; + } + + bool divideString(FT_Face face, const char* sText, int iMaxWidth, int iMaxHeight) { + const char* pText = sText; + textLines.clear(); + iMaxLineWidth = 0; + + FT_UInt unicode; + FT_UInt prevCharacter = 0; + FT_UInt glyphIndex = 0; + FT_UInt prevGlyphIndex = 0; + FT_Vector delta; + LineBreakLine currentLine; + + int currentPaintPosition = 0; + int lastBreakIndex = -1; + bool hasKerning = FT_HAS_KERNING( face ); + while ((unicode=utf8((char**)&pText))) { + if (unicode == '\n') { + currentLine.calculateWidth(); + iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); + textLines.push_back(currentLine); + currentLine.reset(); + prevGlyphIndex = 0; + prevCharacter = 0; + lastBreakIndex = -1; + currentPaintPosition = 0; + continue; + } + + if ( isBreakPoint(unicode, prevCharacter) ) { + lastBreakIndex = currentLine.glyphs.size() - 1; + } + + glyphIndex = FT_Get_Char_Index(face, unicode); + if (FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT)) { + return false; + } + + if (isspace(unicode)) { + currentPaintPosition += face->glyph->metrics.horiAdvance >> 6; + prevGlyphIndex = glyphIndex; + prevCharacter = unicode; + lastBreakIndex = currentLine.glyphs.size(); + continue; + } + + LineBreakGlyph glyph; + glyph.glyphIndex = glyphIndex; + glyph.glyphWidth = face->glyph->metrics.width >> 6; + glyph.bearingX = face->glyph->metrics.horiBearingX >> 6; + glyph.horizAdvance = face->glyph->metrics.horiAdvance >> 6; + glyph.kerning = 0; + + if (prevGlyphIndex != 0 && hasKerning) { + FT_Get_Kerning(face, prevGlyphIndex, glyphIndex, FT_KERNING_DEFAULT, &delta); + glyph.kerning = delta.x >> 6; + } + + if (iMaxWidth > 0 && currentPaintPosition + glyph.bearingX + glyph.kerning + glyph.glyphWidth > iMaxWidth) { + + int glyphCount = currentLine.glyphs.size(); + if ( lastBreakIndex >= 0 && lastBreakIndex < glyphCount && currentPaintPosition + glyph.bearingX + glyph.kerning + glyph.glyphWidth - currentLine.glyphs.at(lastBreakIndex).paintPosition < iMaxWidth ) { + // we insert a line break at our last break opportunity + std::vector tempGlyphs; + std::vector::iterator it = currentLine.glyphs.begin(); + std::advance(it, lastBreakIndex); + tempGlyphs.insert(tempGlyphs.begin(), it, currentLine.glyphs.end()); + currentLine.glyphs.erase(it, currentLine.glyphs.end()); + currentLine.calculateWidth(); + iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); + textLines.push_back(currentLine); + currentLine.reset(); + currentPaintPosition = 0; + for ( it = tempGlyphs.begin(); it != tempGlyphs.end(); it++ ) { + if ( currentLine.glyphs.empty() ) { + currentPaintPosition = -(*it).bearingX; + (*it).kerning = 0; + } + (*it).paintPosition = currentPaintPosition + (*it).bearingX + (*it).kerning; + currentLine.glyphs.push_back((*it)); + currentPaintPosition += (*it).kerning + (*it).horizAdvance; + } + } else { + // the current word is too big to fit into one line, insert line break right here + currentPaintPosition = 0; + glyph.kerning = 0; + currentLine.calculateWidth(); + iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); + textLines.push_back(currentLine); + currentLine.reset(); + } + + prevGlyphIndex = 0; + prevCharacter = 0; + lastBreakIndex = -1; + } else { + prevGlyphIndex = glyphIndex; + prevCharacter = unicode; + } + + if ( currentLine.glyphs.empty() ) { + currentPaintPosition = -glyph.bearingX; + } + glyph.paintPosition = currentPaintPosition + glyph.bearingX + glyph.kerning; + currentLine.glyphs.push_back(glyph); + currentPaintPosition += glyph.kerning + glyph.horizAdvance; + } + + if ( currentLine.glyphs.empty() == false ) { + currentLine.calculateWidth(); + iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); + textLines.push_back(currentLine); + } + return true; + } + + /** + * compute the start pos of every line + */ + int computeLineStart(FT_Face face, Device::TextAlign eAlignMask, int line) { + int lineWidth = textLines.at(line).lineWidth; + if (eAlignMask == Device::TextAlign::CENTER || eAlignMask == Device::TextAlign::TOP || eAlignMask == Device::TextAlign::BOTTOM) { + return (iMaxLineWidth - lineWidth) / 2; + } else if (eAlignMask == Device::TextAlign::RIGHT || eAlignMask == Device::TextAlign::TOP_RIGHT || eAlignMask == Device::TextAlign::BOTTOM_RIGHT) { + return (iMaxLineWidth - lineWidth); + } + + // left or other situation + return 0; + } + + int computeLineStartY( FT_Face face, Device::TextAlign eAlignMask, int txtHeight, int borderHeight ){ + int baseLinePos = ceilf(FT_MulFix( face->bbox.yMax, face->size->metrics.y_scale )/64.0f); + if (eAlignMask == Device::TextAlign::CENTER || eAlignMask == Device::TextAlign::LEFT || eAlignMask == Device::TextAlign::RIGHT) { + //vertical center + return (borderHeight - txtHeight) / 2 + baseLinePos; + } else if (eAlignMask == Device::TextAlign::BOTTOM_RIGHT || eAlignMask == Device::TextAlign::BOTTOM || eAlignMask == Device::TextAlign::BOTTOM_LEFT) { + //vertical bottom + return borderHeight - txtHeight + baseLinePos; + } + + // top alignment + return baseLinePos; + } + + std::string getFontFile(const char* family_name) { + std::string fontPath = family_name; + + std::map::iterator it = fontCache.find(family_name); + if ( it != fontCache.end() ) { + return it->second; + } + + // check if the parameter is a font file shipped with the application + std::string lowerCasePath = fontPath; + std::transform(lowerCasePath.begin(), lowerCasePath.end(), lowerCasePath.begin(), ::tolower); + if ( lowerCasePath.find(".ttf") != std::string::npos ) { + fontPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fontPath.c_str()); + + FILE *f = fopen(fontPath.c_str(), "r"); + if ( f ) { + fclose(f); + fontCache.insert(std::pair(family_name, fontPath)); + return fontPath; + } + } + + // use fontconfig to match the parameter against the fonts installed on the system + FcPattern *pattern = FcPatternBuild (0, FC_FAMILY, FcTypeString, family_name, (char *) 0); + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern *font = FcFontMatch(0, pattern, &result); + if ( font ) { + FcChar8 *s = NULL; + if ( FcPatternGetString(font, FC_FILE, 0, &s) == FcResultMatch ) { + fontPath = (const char*)s; + + FcPatternDestroy(font); + FcPatternDestroy(pattern); + + fontCache.insert(std::pair(family_name, fontPath)); + return fontPath; + } + FcPatternDestroy(font); + } + FcPatternDestroy(pattern); + + return family_name; + } + + bool getBitmap(const char *text, int nWidth, int nHeight, Device::TextAlign eAlignMask, const char * pFontName, float fontSize) { + if (libError) { + return false; + } + + FT_Face face; + std::string fontfile = getFontFile(pFontName); + if ( FT_New_Face(library, fontfile.c_str(), 0, &face) ) { + //no valid font found use default + if ( FT_New_Face(library, "/usr/share/fonts/truetype/freefont/FreeSerif.ttf", 0, &face) ) { + return false; + } + } + + //select utf8 charmap + if ( FT_Select_Charmap(face, FT_ENCODING_UNICODE) ) { + FT_Done_Face(face); + return false; + } + + if ( FT_Set_Pixel_Sizes(face, fontSize, fontSize) ) { + FT_Done_Face(face); + return false; + } + + if ( divideString(face, text, nWidth, nHeight) == false ) { + FT_Done_Face(face); + return false; + } + + //compute the final line width + iMaxLineWidth = MAX(iMaxLineWidth, nWidth); + + //compute the final line height + iMaxLineHeight = ceilf(FT_MulFix( face->bbox.yMax - face->bbox.yMin, face->size->metrics.y_scale )/64.0f); + int lineHeight = face->size->metrics.height>>6; + if ( textLines.size() > 0 ) { + iMaxLineHeight += (lineHeight * (textLines.size() -1)); + } + int txtHeight = iMaxLineHeight; + iMaxLineHeight = MAX(iMaxLineHeight, nHeight); + + _data = new unsigned char[iMaxLineWidth * iMaxLineHeight * 4]; + memset(_data,0, iMaxLineWidth * iMaxLineHeight*4); + + int iCurYCursor = computeLineStartY(face, eAlignMask, txtHeight, iMaxLineHeight); + + int lineCount = textLines.size(); + for (int line = 0; line < lineCount; line++) { + int iCurXCursor = computeLineStart(face, eAlignMask, line); + + int glyphCount = textLines.at(line).glyphs.size(); + for (int i = 0; i < glyphCount; i++) { + LineBreakGlyph glyph = textLines.at(line).glyphs.at(i); + + if (FT_Load_Glyph(face, glyph.glyphIndex, FT_LOAD_RENDER)) { + continue; + } + + FT_Bitmap& bitmap = face->glyph->bitmap; + int yoffset = iCurYCursor - (face->glyph->metrics.horiBearingY >> 6); + int xoffset = iCurXCursor + glyph.paintPosition; + + for (int y = 0; y < bitmap.rows; ++y) { + int iY = yoffset + y; + if (iY>=iMaxLineHeight) { + //exceed the height truncate + break; + } + iY *= iMaxLineWidth; + + int bitmap_y = y * bitmap.width; + + for (int x = 0; x < bitmap.width; ++x) { + unsigned char cTemp = bitmap.buffer[bitmap_y + x]; + if (cTemp == 0) { + continue; + } + + int iX = xoffset + x; + + int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp; + *(int*) &_data[(iY + iX) * 4 + 0] = iTemp; + } + } + } + // step to next line + iCurYCursor += lineHeight; + } + + // free face + FT_Done_Face(face); + return true; + } + +public: + FT_Library library; + + unsigned char *_data; + int libError; + std::vector textLines; + int iMaxLineWidth; + int iMaxLineHeight; +}; + +static BitmapDC& sharedBitmapDC() +{ + static BitmapDC s_BmpDC; + return s_BmpDC; +} + +Data Device::getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &width,int &height) +{ + Data ret; + do + { + BitmapDC &dc = sharedBitmapDC(); + + CC_BREAK_IF(! dc.getBitmap(text, textDefinition._dimensions.width, textDefinition._dimensions.height, align, textDefinition._fontName.c_str(), textDefinition._fontSize)); + CC_BREAK_IF(! dc._data); + width = dc.iMaxLineWidth; + height = dc.iMaxLineHeight; + dc.reset(); + ret.fastSet(dc._data,width * height * 4); + } while (0); + + return ret; +} + NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_LINUX diff --git a/cocos/2d/platform/linux/CCImage.cpp b/cocos/2d/platform/linux/CCImage.cpp deleted file mode 100644 index 8add509d35..0000000000 --- a/cocos/2d/platform/linux/CCImage.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/**************************************************************************** -Copyright (c) 2011 Laschweinski -Copyright (c) 2013-2014 Chukong Technologies Inc. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -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 "CCPlatformConfig.h" -#if CC_TARGET_PLATFORM == CC_PLATFORM_LINUX - -#include - -#include -#include -#include -#include -#include - -#include "platform/CCFileUtils.h" -#include "CCPlatformMacros.h" -#define __CC_PLATFORM_IMAGE_CPP__ -#include "platform/CCImageCommon_cpp.h" -#include "platform/CCImage.h" -#include "platform/linux/CCApplication.h" - -#include "ft2build.h" -#include "CCStdC.h" - -#include FT_FREETYPE_H - -using namespace std; - -// as FcFontMatch is quite an expensive call, cache the results of getFontFile -static std::map fontCache; - -struct LineBreakGlyph { - FT_UInt glyphIndex; - int paintPosition; - int glyphWidth; - - int bearingX; - int kerning; - int horizAdvance; -}; - -struct LineBreakLine { - LineBreakLine() : lineWidth(0) {} - - std::vector glyphs; - int lineWidth; - - void reset() { - glyphs.clear(); - lineWidth = 0; - } - - void calculateWidth() { - lineWidth = 0; - if ( glyphs.empty() == false ) { - lineWidth = glyphs.at(glyphs.size() - 1).paintPosition + glyphs.at(glyphs.size() - 1).glyphWidth; - } - } -}; - -NS_CC_BEGIN - -class BitmapDC -{ -public: - BitmapDC() { - libError = FT_Init_FreeType( &library ); - FcInit(); - _data = NULL; - reset(); - } - - ~BitmapDC() { - FT_Done_FreeType(library); - FcFini(); - //data will be deleted by Image -// if (_data) { -// delete _data; -// } - reset(); - } - - void reset() { - iMaxLineWidth = 0; - iMaxLineHeight = 0; - textLines.clear(); - } - - int utf8(char **p) - { - if ((**p & 0x80) == 0x00) - { - int a = *((*p)++); - - return a; - } - if ((**p & 0xE0) == 0xC0) - { - int a = *((*p)++) & 0x1F; - int b = *((*p)++) & 0x3F; - - return (a << 6) | b; - } - if ((**p & 0xF0) == 0xE0) - { - int a = *((*p)++) & 0x0F; - int b = *((*p)++) & 0x3F; - int c = *((*p)++) & 0x3F; - - return (a << 12) | (b << 6) | c; - } - if ((**p & 0xF8) == 0xF0) - { - int a = *((*p)++) & 0x07; - int b = *((*p)++) & 0x3F; - int c = *((*p)++) & 0x3F; - int d = *((*p)++) & 0x3F; - - return (a << 18) | (b << 12) | (c << 8) | d; - } - return 0; - } - - bool isBreakPoint(FT_UInt currentCharacter, FT_UInt previousCharacter) { - if ( previousCharacter == '-' || previousCharacter == '/' || previousCharacter == '\\' ) { - // we can insert a line break after one of these characters - return true; - } - return false; - } - - bool divideString(FT_Face face, const char* sText, int iMaxWidth, int iMaxHeight) { - const char* pText = sText; - textLines.clear(); - iMaxLineWidth = 0; - - FT_UInt unicode; - FT_UInt prevCharacter = 0; - FT_UInt glyphIndex = 0; - FT_UInt prevGlyphIndex = 0; - FT_Vector delta; - LineBreakLine currentLine; - - int currentPaintPosition = 0; - int lastBreakIndex = -1; - bool hasKerning = FT_HAS_KERNING( face ); - while ((unicode=utf8((char**)&pText))) { - if (unicode == '\n') { - currentLine.calculateWidth(); - iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); - textLines.push_back(currentLine); - currentLine.reset(); - prevGlyphIndex = 0; - prevCharacter = 0; - lastBreakIndex = -1; - currentPaintPosition = 0; - continue; - } - - if ( isBreakPoint(unicode, prevCharacter) ) { - lastBreakIndex = currentLine.glyphs.size() - 1; - } - - glyphIndex = FT_Get_Char_Index(face, unicode); - if (FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT)) { - return false; - } - - if (isspace(unicode)) { - currentPaintPosition += face->glyph->metrics.horiAdvance >> 6; - prevGlyphIndex = glyphIndex; - prevCharacter = unicode; - lastBreakIndex = currentLine.glyphs.size(); - continue; - } - - LineBreakGlyph glyph; - glyph.glyphIndex = glyphIndex; - glyph.glyphWidth = face->glyph->metrics.width >> 6; - glyph.bearingX = face->glyph->metrics.horiBearingX >> 6; - glyph.horizAdvance = face->glyph->metrics.horiAdvance >> 6; - glyph.kerning = 0; - - if (prevGlyphIndex != 0 && hasKerning) { - FT_Get_Kerning(face, prevGlyphIndex, glyphIndex, FT_KERNING_DEFAULT, &delta); - glyph.kerning = delta.x >> 6; - } - - if (iMaxWidth > 0 && currentPaintPosition + glyph.bearingX + glyph.kerning + glyph.glyphWidth > iMaxWidth) { - - int glyphCount = currentLine.glyphs.size(); - if ( lastBreakIndex >= 0 && lastBreakIndex < glyphCount && currentPaintPosition + glyph.bearingX + glyph.kerning + glyph.glyphWidth - currentLine.glyphs.at(lastBreakIndex).paintPosition < iMaxWidth ) { - // we insert a line break at our last break opportunity - std::vector tempGlyphs; - std::vector::iterator it = currentLine.glyphs.begin(); - std::advance(it, lastBreakIndex); - tempGlyphs.insert(tempGlyphs.begin(), it, currentLine.glyphs.end()); - currentLine.glyphs.erase(it, currentLine.glyphs.end()); - currentLine.calculateWidth(); - iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); - textLines.push_back(currentLine); - currentLine.reset(); - currentPaintPosition = 0; - for ( it = tempGlyphs.begin(); it != tempGlyphs.end(); it++ ) { - if ( currentLine.glyphs.empty() ) { - currentPaintPosition = -(*it).bearingX; - (*it).kerning = 0; - } - (*it).paintPosition = currentPaintPosition + (*it).bearingX + (*it).kerning; - currentLine.glyphs.push_back((*it)); - currentPaintPosition += (*it).kerning + (*it).horizAdvance; - } - } else { - // the current word is too big to fit into one line, insert line break right here - currentPaintPosition = 0; - glyph.kerning = 0; - currentLine.calculateWidth(); - iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); - textLines.push_back(currentLine); - currentLine.reset(); - } - - prevGlyphIndex = 0; - prevCharacter = 0; - lastBreakIndex = -1; - } else { - prevGlyphIndex = glyphIndex; - prevCharacter = unicode; - } - - if ( currentLine.glyphs.empty() ) { - currentPaintPosition = -glyph.bearingX; - } - glyph.paintPosition = currentPaintPosition + glyph.bearingX + glyph.kerning; - currentLine.glyphs.push_back(glyph); - currentPaintPosition += glyph.kerning + glyph.horizAdvance; - } - - if ( currentLine.glyphs.empty() == false ) { - currentLine.calculateWidth(); - iMaxLineWidth = max(iMaxLineWidth, currentLine.lineWidth); - textLines.push_back(currentLine); - } - return true; - } - - /** - * compute the start pos of every line - */ - int computeLineStart(FT_Face face, Image::TextAlign eAlignMask, int line) { - 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::TOP_RIGHT || eAlignMask == Image::TextAlign::BOTTOM_RIGHT) { - return (iMaxLineWidth - lineWidth); - } - - // left or other situation - return 0; - } - - int computeLineStartY( FT_Face face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){ - int baseLinePos = ceilf(FT_MulFix( face->bbox.yMax, face->size->metrics.y_scale )/64.0f); - if (eAlignMask == Image::TextAlign::CENTER || eAlignMask == Image::TextAlign::LEFT || eAlignMask == Image::TextAlign::RIGHT) { - //vertical center - return (borderHeight - txtHeight) / 2 + baseLinePos; - } else if (eAlignMask == Image::TextAlign::BOTTOM_RIGHT || eAlignMask == Image::TextAlign::BOTTOM || eAlignMask == Image::TextAlign::BOTTOM_LEFT) { - //vertical bottom - return borderHeight - txtHeight + baseLinePos; - } - - // top alignment - return baseLinePos; - } - - std::string getFontFile(const char* family_name) { - std::string fontPath = family_name; - - std::map::iterator it = fontCache.find(family_name); - if ( it != fontCache.end() ) { - return it->second; - } - - // check if the parameter is a font file shipped with the application - std::string lowerCasePath = fontPath; - std::transform(lowerCasePath.begin(), lowerCasePath.end(), lowerCasePath.begin(), ::tolower); - if ( lowerCasePath.find(".ttf") != std::string::npos ) { - fontPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fontPath.c_str()); - - FILE *f = fopen(fontPath.c_str(), "r"); - if ( f ) { - fclose(f); - fontCache.insert(std::pair(family_name, fontPath)); - return fontPath; - } - } - - // use fontconfig to match the parameter against the fonts installed on the system - FcPattern *pattern = FcPatternBuild (0, FC_FAMILY, FcTypeString, family_name, (char *) 0); - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcResult result; - FcPattern *font = FcFontMatch(0, pattern, &result); - if ( font ) { - FcChar8 *s = NULL; - if ( FcPatternGetString(font, FC_FILE, 0, &s) == FcResultMatch ) { - fontPath = (const char*)s; - - FcPatternDestroy(font); - FcPatternDestroy(pattern); - - fontCache.insert(std::pair(family_name, fontPath)); - return fontPath; - } - FcPatternDestroy(font); - } - FcPatternDestroy(pattern); - - return family_name; - } - - bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) { - if (libError) { - return false; - } - - FT_Face face; - std::string fontfile = getFontFile(pFontName); - if ( FT_New_Face(library, fontfile.c_str(), 0, &face) ) { - //no valid font found use default - if ( FT_New_Face(library, "/usr/share/fonts/truetype/freefont/FreeSerif.ttf", 0, &face) ) { - return false; - } - } - - //select utf8 charmap - if ( FT_Select_Charmap(face, FT_ENCODING_UNICODE) ) { - FT_Done_Face(face); - return false; - } - - if ( FT_Set_Pixel_Sizes(face, fontSize, fontSize) ) { - FT_Done_Face(face); - return false; - } - - if ( divideString(face, text, nWidth, nHeight) == false ) { - FT_Done_Face(face); - return false; - } - - //compute the final line width - iMaxLineWidth = MAX(iMaxLineWidth, nWidth); - - //compute the final line height - iMaxLineHeight = ceilf(FT_MulFix( face->bbox.yMax - face->bbox.yMin, face->size->metrics.y_scale )/64.0f); - int lineHeight = face->size->metrics.height>>6; - if ( textLines.size() > 0 ) { - iMaxLineHeight += (lineHeight * (textLines.size() -1)); - } - int txtHeight = iMaxLineHeight; - iMaxLineHeight = MAX(iMaxLineHeight, nHeight); - - _data = new unsigned char[iMaxLineWidth * iMaxLineHeight * 4]; - memset(_data,0, iMaxLineWidth * iMaxLineHeight*4); - - int iCurYCursor = computeLineStartY(face, eAlignMask, txtHeight, iMaxLineHeight); - - int lineCount = textLines.size(); - for (int line = 0; line < lineCount; line++) { - int iCurXCursor = computeLineStart(face, eAlignMask, line); - - int glyphCount = textLines.at(line).glyphs.size(); - for (int i = 0; i < glyphCount; i++) { - LineBreakGlyph glyph = textLines.at(line).glyphs.at(i); - - if (FT_Load_Glyph(face, glyph.glyphIndex, FT_LOAD_RENDER)) { - continue; - } - - FT_Bitmap& bitmap = face->glyph->bitmap; - int yoffset = iCurYCursor - (face->glyph->metrics.horiBearingY >> 6); - int xoffset = iCurXCursor + glyph.paintPosition; - - for (int y = 0; y < bitmap.rows; ++y) { - int iY = yoffset + y; - if (iY>=iMaxLineHeight) { - //exceed the height truncate - break; - } - iY *= iMaxLineWidth; - - int bitmap_y = y * bitmap.width; - - for (int x = 0; x < bitmap.width; ++x) { - unsigned char cTemp = bitmap.buffer[bitmap_y + x]; - if (cTemp == 0) { - continue; - } - - int iX = xoffset + x; - - int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp; - *(int*) &_data[(iY + iX) * 4 + 0] = iTemp; - } - } - } - // step to next line - iCurYCursor += lineHeight; - } - - // free face - FT_Done_Face(face); - return true; - } - -public: - FT_Library library; - - unsigned char *_data; - int libError; - std::vector textLines; - int iMaxLineWidth; - int iMaxLineHeight; -}; - -static BitmapDC& sharedBitmapDC() -{ - static BitmapDC s_BmpDC; - return s_BmpDC; -} - -bool Image::initWithString( - const char * text, - int width/* = 0*/, - int height/* = 0*/, - TextAlign alignMask/* = kAlignCenter*/, - const char * fontName/* = nil*/, - int size/* = 0*/) -{ - bool ret = false; - do - { - CC_BREAK_IF(!text || 0 == strlen(text)); - - BitmapDC &dc = sharedBitmapDC(); - - CC_BREAK_IF(! dc.getBitmap(text, width, height, alignMask, fontName, size)); - - // 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; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - _preMulti = true; - _dataLen = _width * _height * 4; - - ret = true; - - dc.reset(); - }while (0); - - //do nothing - return ret; -} - -NS_CC_END - -#endif // CC_TARGET_PLATFORM == CC_PLATFORM_LINUX diff --git a/cocos/2d/platform/mac/CCDevice.cpp b/cocos/2d/platform/mac/CCDevice.cpp deleted file mode 100644 index ec90cc36b6..0000000000 --- a/cocos/2d/platform/mac/CCDevice.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2014 Chukong Technologies Inc. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -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 "CCPlatformConfig.h" -#if CC_TARGET_PLATFORM == CC_PLATFORM_MAC - -#include "platform/CCDevice.h" - -NS_CC_BEGIN - -int Device::getDPI() -{ -//TODO: - return 160; -} - -void Device::setAccelerometerEnabled(bool isEnabled) -{ - -} - -void Device::setAccelerometerInterval(float interval) -{ - -} - -NS_CC_END - -#endif // CC_TARGET_PLATFORM == CC_PLATFORM_MAC diff --git a/cocos/2d/platform/mac/CCImage.mm b/cocos/2d/platform/mac/CCDevice.mm similarity index 81% rename from cocos/2d/platform/mac/CCImage.mm rename to cocos/2d/platform/mac/CCDevice.mm index 5d27e0f9d0..dc0581b634 100644 --- a/cocos/2d/platform/mac/CCImage.mm +++ b/cocos/2d/platform/mac/CCDevice.mm @@ -26,21 +26,30 @@ THE SOFTWARE. #include "CCPlatformConfig.h" #if CC_TARGET_PLATFORM == CC_PLATFORM_MAC -#include "CCImageCommon_cpp.h" +#include "platform/CCDevice.h" #include #include -#include "CCDirector.h" -#include "ccMacros.h" -#include "CCImage.h" -#include "CCFileUtils.h" -#include "CCTexture2D.h" #include -#include -#include -#include +#include "ccTypes.h" NS_CC_BEGIN +int Device::getDPI() +{ +//TODO: + return 160; +} + +void Device::setAccelerometerEnabled(bool isEnabled) +{ + +} + +void Device::setAccelerometerInterval(float interval) +{ + +} + typedef struct { int height; @@ -50,10 +59,10 @@ typedef struct unsigned char* data; } tImageInfo; -static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, const char * fontName, int size, tImageInfo* info, cocos2d::Color3B* strokeColor) +static bool _initWithString(const char * text, Device::TextAlign align, const char * fontName, int size, tImageInfo* info, Color3B* strokeColor) { bool ret = false; - + CCASSERT(text, "Invalid pText"); CCASSERT(info, "Invalid pInfo"); @@ -62,10 +71,10 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, // font NSFont *font = [[NSFontManager sharedFontManager] - fontWithFamily:[NSString stringWithUTF8String:fontName] + fontWithFamily:[NSString stringWithUTF8String:fontName] traits:NSUnboldFontMask | NSUnitalicFontMask - weight:0 - size:size]; + weight:0 + size:size]; if (font == nil) { font = [[NSFontManager sharedFontManager] @@ -89,20 +98,20 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, unsigned horiFlag = (int)align & 0x0f; unsigned vertFlag = ((int)align >> 4) & 0x0f; NSTextAlignment textAlign = (2 == horiFlag) ? NSRightTextAlignment - : (3 == horiFlag) ? NSCenterTextAlignment - : NSLeftTextAlignment; + : (3 == horiFlag) ? NSCenterTextAlignment + : NSLeftTextAlignment; NSMutableParagraphStyle *paragraphStyle = [[[NSMutableParagraphStyle alloc] init] autorelease]; [paragraphStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]]; [paragraphStyle setLineBreakMode:NSLineBreakByCharWrapping]; [paragraphStyle setAlignment:textAlign]; - + // attribute NSDictionary* tokenAttributesDict = [NSDictionary dictionaryWithObjectsAndKeys: foregroundColor,NSForegroundColorAttributeName, font, NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil]; - + // linebreak if (info->width > 0) { if ([string sizeWithAttributes:tokenAttributesDict].width > info->width) { @@ -124,29 +133,29 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, string = lineBreak; } } - + NSAttributedString *stringWithAttributes =[[[NSAttributedString alloc] initWithString:string - attributes:tokenAttributesDict] autorelease]; - + attributes:tokenAttributesDict] autorelease]; + NSSize realDimensions = [stringWithAttributes size]; // Mac crashes if the width or height is 0 CC_BREAK_IF(realDimensions.width <= 0 || realDimensions.height <= 0); - + CGSize dimensions = CGSizeMake(info->width, info->height); - + if(dimensions.width <= 0 && dimensions.height <= 0) { dimensions.width = realDimensions.width; dimensions.height = realDimensions.height; } else if (dimensions.height <= 0) { dimensions.height = realDimensions.height; } - + NSInteger POTWide = dimensions.width; NSInteger POTHigh = MAX(dimensions.height, realDimensions.height); unsigned char* data; //Alignment - + CGFloat xPadding = 0; switch (textAlign) { case NSLeftTextAlignment: xPadding = 0; break; @@ -154,7 +163,7 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, case NSRightTextAlignment: xPadding = dimensions.width-realDimensions.width; break; default: break; } - + // 1: TOP // 2: BOTTOM // 3: CENTER @@ -166,7 +175,7 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, NSRect textRect = NSMakeRect(xPadding, POTHigh - dimensions.height + yPadding, realDimensions.width, realDimensions.height); //Disable antialias - [[NSGraphicsContext currentContext] setShouldAntialias:NO]; + [[NSGraphicsContext currentContext] setShouldAntialias:NO]; NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(POTWide, POTHigh)]; @@ -175,7 +184,7 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, // patch for mac retina display and lableTTF [[NSAffineTransform transform] set]; - //[stringWithAttributes drawAtPoint:NSMakePoint(xPadding, offsetY)]; // draw at offset position + //[stringWithAttributes drawAtPoint:NSMakePoint(xPadding, offsetY)]; // draw at offset position [stringWithAttributes drawInRect:textRect]; //[stringWithAttributes drawInRect:textRect withAttributes:tokenAttributesDict]; NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, POTWide, POTHigh)]; @@ -202,36 +211,25 @@ static bool _initWithString(const char * text, cocos2d::Image::TextAlign align, return ret; } -bool Image::initWithString( - const char * text, - int width, - int height, - TextAlign alignMask, - const char * fontName, - int size) +Data Device::getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &width,int &height) { - tImageInfo info = {0}; - info.width = width; - info.height = height; - - if (! _initWithString(text, alignMask, fontName, size, &info, nullptr)) //pStrokeColor)) - { - return false; - } - _height = (short)info.height; - _width = (short)info.width; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - _preMulti = info.isPremultipliedAlpha; - if (_data) { - CC_SAFE_DELETE_ARRAY(_data); - } - _data = info.data; - _dataLen = _width * _height * 4; - - return true; + Data ret; + do { + tImageInfo info = {0}; + info.width = textDefinition._dimensions.width; + info.height = textDefinition._dimensions.height; + + if (! _initWithString(text, align, textDefinition._fontName.c_str(), textDefinition._fontSize, &info, nullptr)) //pStrokeColor)) + { + break; + } + height = (short)info.height; + widht = (short)info.width; + ret.fastSet(info.data,width * height * 4); + } while (0); + + return ret; } - - NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_MAC diff --git a/cocos/2d/platform/win32/CCDevice.cpp b/cocos/2d/platform/win32/CCDevice.cpp index 50c0bb579c..257ce3dd89 100644 --- a/cocos/2d/platform/win32/CCDevice.cpp +++ b/cocos/2d/platform/win32/CCDevice.cpp @@ -27,6 +27,7 @@ THE SOFTWARE. #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #include "platform/CCDevice.h" +#include "platform/CCFileUtils.h" #include "CCStdC.h" NS_CC_BEGIN @@ -51,6 +52,408 @@ void Device::setAccelerometerEnabled(bool isEnabled) void Device::setAccelerometerInterval(float interval) {} +class BitmapDC +{ +public: + BitmapDC(HWND hWnd = NULL) + : _DC(NULL) + , _bmp(NULL) + , _font((HFONT)GetStockObject(DEFAULT_GUI_FONT)) + , _wnd(NULL) + { + _wnd = hWnd; + HDC hdc = GetDC(hWnd); + _DC = CreateCompatibleDC(hdc); + ReleaseDC(hWnd, hdc); + } + + ~BitmapDC() + { + prepareBitmap(0, 0); + if (_DC) + { + DeleteDC(_DC); + } + /*HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + if (hDefFont != _font) + { + DeleteObject(_font); + _font = hDefFont; + } + // release temp font resource + if (_curFontPath.size() > 0) + { + wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); + if (pwszBuffer) + { + RemoveFontResource(pwszBuffer); + SendMessage( _wnd, WM_FONTCHANGE, 0, 0); + delete [] pwszBuffer; + pwszBuffer = NULL; + } + }*/ + removeCustomFont(); + } + + wchar_t * utf8ToUtf16(std::string nString) + { + wchar_t * pwszBuffer = NULL; + do + { + if (nString.size() < 0) + { + break; + } + // utf-8 to utf-16 + int nLen = nString.size(); + int nBufLen = nLen + 1; + pwszBuffer = new wchar_t[nBufLen]; + CC_BREAK_IF(! pwszBuffer); + memset(pwszBuffer,0,nBufLen); + nLen = MultiByteToWideChar(CP_UTF8, 0, nString.c_str(), nLen, pwszBuffer, nBufLen); + pwszBuffer[nLen] = '\0'; + } while (0); + return pwszBuffer; + + } + + bool setFont(const char * pFontName = NULL, int nSize = 0) + { + bool bRet = false; + do + { + std::string fontName = pFontName; + std::string fontPath; + HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + LOGFONTA tNewFont = {0}; + LOGFONTA tOldFont = {0}; + GetObjectA(hDefFont, sizeof(tNewFont), &tNewFont); + if (fontName.c_str()) + { + // create font from ttf file + int nFindttf = fontName.find(".ttf"); + int nFindTTF = fontName.find(".TTF"); + if (nFindttf >= 0 || nFindTTF >= 0) + { + fontPath = FileUtils::getInstance()->fullPathForFilename(fontName.c_str()); + int nFindPos = fontName.rfind("/"); + fontName = &fontName[nFindPos+1]; + nFindPos = fontName.rfind("."); + fontName = fontName.substr(0,nFindPos); + } + tNewFont.lfCharSet = DEFAULT_CHARSET; + strcpy_s(tNewFont.lfFaceName, LF_FACESIZE, fontName.c_str()); + } + if (nSize) + { + tNewFont.lfHeight = -nSize; + } + GetObjectA(_font, sizeof(tOldFont), &tOldFont); + + if (tOldFont.lfHeight == tNewFont.lfHeight + && 0 == strcmp(tOldFont.lfFaceName, tNewFont.lfFaceName)) + { + // already has the font + bRet = true; + break; + } + + // delete old font + removeCustomFont(); + + if (fontPath.size() > 0) + { + _curFontPath = fontPath; + wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); + if (pwszBuffer) + { + if(AddFontResource(pwszBuffer)) + { + SendMessage( _wnd, WM_FONTCHANGE, 0, 0); + } + delete [] pwszBuffer; + pwszBuffer = NULL; + } + } + + _font = nullptr; + + // disable Cleartype + tNewFont.lfQuality = ANTIALIASED_QUALITY; + + // create new font + _font = CreateFontIndirectA(&tNewFont); + if (! _font) + { + // create failed, use default font + _font = hDefFont; + break; + } + + bRet = true; + } while (0); + return bRet; + } + + SIZE sizeWithText(const wchar_t * pszText, int nLen, DWORD dwFmt, LONG nWidthLimit) + { + SIZE tRet = {0}; + do + { + CC_BREAK_IF(! pszText || nLen <= 0); + + RECT rc = {0, 0, 0, 0}; + DWORD dwCalcFmt = DT_CALCRECT; + + if (nWidthLimit > 0) + { + rc.right = nWidthLimit; + dwCalcFmt |= DT_WORDBREAK + | (dwFmt & DT_CENTER) + | (dwFmt & DT_RIGHT); + } + // use current font to measure text extent + HGDIOBJ hOld = SelectObject(_DC, _font); + + // measure text size + DrawTextW(_DC, pszText, nLen, &rc, dwCalcFmt); + SelectObject(_DC, hOld); + + tRet.cx = rc.right; + tRet.cy = rc.bottom; + } while (0); + + return tRet; + } + + bool prepareBitmap(int nWidth, int nHeight) + { + // release bitmap + if (_bmp) + { + DeleteObject(_bmp); + _bmp = NULL; + } + if (nWidth > 0 && nHeight > 0) + { + _bmp = CreateBitmap(nWidth, nHeight, 1, 32, NULL); + if (! _bmp) + { + return false; + } + } + return true; + } + + int drawText(const char * pszText, SIZE& tSize, Device::TextAlign eAlign) + { + int nRet = 0; + wchar_t * pwszBuffer = 0; + do + { + CC_BREAK_IF(! pszText); + + DWORD dwFmt = DT_WORDBREAK; + DWORD dwHoriFlag = (int)eAlign & 0x0f; + DWORD dwVertFlag = ((int)eAlign & 0xf0) >> 4; + + switch (dwHoriFlag) + { + case 1: // left + dwFmt |= DT_LEFT; + break; + case 2: // right + dwFmt |= DT_RIGHT; + break; + case 3: // center + dwFmt |= DT_CENTER; + break; + } + + int nLen = strlen(pszText); + // utf-8 to utf-16 + int nBufLen = nLen + 1; + pwszBuffer = new wchar_t[nBufLen]; + CC_BREAK_IF(! pwszBuffer); + + memset(pwszBuffer, 0, sizeof(wchar_t)*nBufLen); + nLen = MultiByteToWideChar(CP_UTF8, 0, pszText, nLen, pwszBuffer, nBufLen); + + SIZE newSize = sizeWithText(pwszBuffer, nLen, dwFmt, tSize.cx); + + RECT rcText = {0}; + // if content width is 0, use text size as content size + if (tSize.cx <= 0) + { + tSize = newSize; + rcText.right = newSize.cx; + rcText.bottom = newSize.cy; + } + else + { + + LONG offsetX = 0; + LONG offsetY = 0; + rcText.right = newSize.cx; // store the text width to rectangle + + // calculate text horizontal offset + if (1 != dwHoriFlag // and text isn't align to left + && newSize.cx < tSize.cx) // and text's width less then content width, + { // then need adjust offset of X. + offsetX = (2 == dwHoriFlag) ? tSize.cx - newSize.cx // align to right + : (tSize.cx - newSize.cx) / 2; // align to center + } + + // if content height is 0, use text height as content height + // else if content height less than text height, use content height to draw text + if (tSize.cy <= 0) + { + tSize.cy = newSize.cy; + dwFmt |= DT_NOCLIP; + rcText.bottom = newSize.cy; // store the text height to rectangle + } + else if (tSize.cy < newSize.cy) + { + // content height larger than text height need, clip text to rect + rcText.bottom = tSize.cy; + } + else + { + rcText.bottom = newSize.cy; // store the text height to rectangle + + // content larger than text, need adjust vertical position + dwFmt |= DT_NOCLIP; + + // calculate text vertical offset + offsetY = (2 == dwVertFlag) ? tSize.cy - newSize.cy // align to bottom + : (3 == dwVertFlag) ? (tSize.cy - newSize.cy) / 2 // align to middle + : 0; // align to top + } + + if (offsetX || offsetY) + { + OffsetRect(&rcText, offsetX, offsetY); + } + } + + CC_BREAK_IF(! prepareBitmap(tSize.cx, tSize.cy)); + + // draw text + HGDIOBJ hOldFont = SelectObject(_DC, _font); + HGDIOBJ hOldBmp = SelectObject(_DC, _bmp); + + SetBkMode(_DC, TRANSPARENT); + SetTextColor(_DC, RGB(255, 255, 255)); // white color + + // draw text + nRet = DrawTextW(_DC, pwszBuffer, nLen, &rcText, dwFmt); + //DrawTextA(_DC, pszText, nLen, &rcText, dwFmt); + + SelectObject(_DC, hOldBmp); + SelectObject(_DC, hOldFont); + } while (0); + CC_SAFE_DELETE_ARRAY(pwszBuffer); + return nRet; + } + + CC_SYNTHESIZE_READONLY(HDC, _DC, DC); + CC_SYNTHESIZE_READONLY(HBITMAP, _bmp, Bitmap); +private: + + friend class Image; + HFONT _font; + HWND _wnd; + std::string _curFontPath; + + void removeCustomFont() + { + HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + if (hDefFont != _font) + { + DeleteObject(_font); + _font = hDefFont; + } + // release temp font resource + if (_curFontPath.size() > 0) + { + wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); + if (pwszBuffer) + { + RemoveFontResource(pwszBuffer); + SendMessage( _wnd, WM_FONTCHANGE, 0, 0); + delete [] pwszBuffer; + pwszBuffer = NULL; + } + _curFontPath.clear(); + } + } +}; + +static BitmapDC& sharedBitmapDC() +{ + static BitmapDC s_BmpDC; + return s_BmpDC; +} + +Data Device::getTextureDataForText(const char * text,const FontDefinition& textDefinition,TextAlign align,int &width,int &height) +{ + Data ret; + do + { + BitmapDC& dc = sharedBitmapDC(); + + if (! dc.setFont(textDefinition._fontName.c_str(), textDefinition._fontSize)) + { + log("Can't found font(%s), use system default", textDefinition._fontName.c_str()); + } + + // draw text + SIZE size = {textDefinition._dimensions.width, textDefinition._dimensions.height}; + CC_BREAK_IF(! dc.drawText(text, size, align)); + + int dataLen = size.cx * size.cy * 4; + unsigned char* dataBuf = new unsigned char[dataLen]; + CC_BREAK_IF(! dataBuf); + + struct + { + BITMAPINFOHEADER bmiHeader; + int mask[4]; + } bi = {0}; + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + CC_BREAK_IF(! GetDIBits(dc.getDC(), dc.getBitmap(), 0, 0, + NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS)); + + width = (short)size.cx; + height = (short)size.cy; + + // copy pixed data + bi.bmiHeader.biHeight = (bi.bmiHeader.biHeight > 0) + ? - bi.bmiHeader.biHeight : bi.bmiHeader.biHeight; + GetDIBits(dc.getDC(), dc.getBitmap(), 0, height, dataBuf, + (LPBITMAPINFO)&bi, DIB_RGB_COLORS); + + // change pixel's alpha value to 255, when it's RGB != 0 + COLORREF * pPixel = NULL; + for (int y = 0; y < height; ++y) + { + pPixel = (COLORREF *)dataBuf + y * width; + for (int x = 0; x < width; ++x) + { + COLORREF& clr = *pPixel; + if (GetRValue(clr) || GetGValue(clr) || GetBValue(clr)) + { + clr |= 0xff000000; + } + ++pPixel; + } + } + + ret.fastSet(dataBuf,dataLen); + } while (0); + return ret; +} + NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 diff --git a/cocos/2d/platform/win32/CCImage.cpp b/cocos/2d/platform/win32/CCImage.cpp deleted file mode 100644 index a753d3e9c7..0000000000 --- a/cocos/2d/platform/win32/CCImage.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2014 Chukong Technologies Inc. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -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 "CCPlatformConfig.h" -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 - -#if _MSC_VER -#include -#endif -#include "platform/CCImageCommon_cpp.h" - -NS_CC_BEGIN - -/** -@brief A memory DC which uses to draw text on bitmap. -*/ -class BitmapDC -{ -public: - BitmapDC(HWND hWnd = NULL) - : _DC(NULL) - , _bmp(NULL) - , _font((HFONT)GetStockObject(DEFAULT_GUI_FONT)) - , _wnd(NULL) - { - _wnd = hWnd; - HDC hdc = GetDC(hWnd); - _DC = CreateCompatibleDC(hdc); - ReleaseDC(hWnd, hdc); - } - - ~BitmapDC() - { - prepareBitmap(0, 0); - if (_DC) - { - DeleteDC(_DC); - } - HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - if (hDefFont != _font) - { - DeleteObject(_font); - _font = hDefFont; - } - // release temp font resource - if (_curFontPath.size() > 0) - { - wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); - if (pwszBuffer) - { - RemoveFontResource(pwszBuffer); - SendMessage( _wnd, WM_FONTCHANGE, 0, 0); - delete [] pwszBuffer; - pwszBuffer = NULL; - } - } - } - - wchar_t * utf8ToUtf16(std::string nString) - { - wchar_t * pwszBuffer = NULL; - do - { - if (nString.size() < 0) - { - break; - } - // utf-8 to utf-16 - int nLen = nString.size(); - int nBufLen = nLen + 1; - pwszBuffer = new wchar_t[nBufLen]; - CC_BREAK_IF(! pwszBuffer); - memset(pwszBuffer,0,nBufLen); - nLen = MultiByteToWideChar(CP_UTF8, 0, nString.c_str(), nLen, pwszBuffer, nBufLen); - pwszBuffer[nLen] = '\0'; - } while (0); - return pwszBuffer; - - } - - bool setFont(const char * pFontName = NULL, int nSize = 0) - { - bool bRet = false; - do - { - std::string fontName = pFontName; - std::string fontPath; - HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - LOGFONTA tNewFont = {0}; - LOGFONTA tOldFont = {0}; - GetObjectA(hDefFont, sizeof(tNewFont), &tNewFont); - if (fontName.c_str()) - { - // create font from ttf file - int nFindttf = fontName.find(".ttf"); - int nFindTTF = fontName.find(".TTF"); - if (nFindttf >= 0 || nFindTTF >= 0) - { - fontPath = FileUtils::getInstance()->fullPathForFilename(fontName.c_str()); - int nFindPos = fontName.rfind("/"); - fontName = &fontName[nFindPos+1]; - nFindPos = fontName.rfind("."); - fontName = fontName.substr(0,nFindPos); - } - tNewFont.lfCharSet = DEFAULT_CHARSET; - strcpy_s(tNewFont.lfFaceName, LF_FACESIZE, fontName.c_str()); - } - if (nSize) - { - tNewFont.lfHeight = -nSize; - } - GetObjectA(_font, sizeof(tOldFont), &tOldFont); - - if (tOldFont.lfHeight == tNewFont.lfHeight - && 0 == strcmp(tOldFont.lfFaceName, tNewFont.lfFaceName)) - { - // already has the font - bRet = true; - break; - } - - // delete old font - if (_font != hDefFont) - { - DeleteObject(_font); - // release old font register - if (_curFontPath.size() > 0) - { - wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); - if (pwszBuffer) - { - if(RemoveFontResource(pwszBuffer)) - { - SendMessage( _wnd, WM_FONTCHANGE, 0, 0); - } - delete [] pwszBuffer; - pwszBuffer = NULL; - } - } - if (fontPath.size() > 0) - _curFontPath = fontPath; - else - _curFontPath.clear(); - // register temp font - if (_curFontPath.size() > 0) - { - wchar_t * pwszBuffer = utf8ToUtf16(_curFontPath); - if (pwszBuffer) - { - if(AddFontResource(pwszBuffer)) - { - SendMessage( _wnd, WM_FONTCHANGE, 0, 0); - } - delete [] pwszBuffer; - pwszBuffer = NULL; - } - } - } - _font = NULL; - - // disable Cleartype - tNewFont.lfQuality = ANTIALIASED_QUALITY; - - // create new font - _font = CreateFontIndirectA(&tNewFont); - if (! _font) - { - // create failed, use default font - _font = hDefFont; - break; - } - - bRet = true; - } while (0); - return bRet; - } - - SIZE sizeWithText(const wchar_t * pszText, int nLen, DWORD dwFmt, LONG nWidthLimit) - { - SIZE tRet = {0}; - do - { - CC_BREAK_IF(! pszText || nLen <= 0); - - RECT rc = {0, 0, 0, 0}; - DWORD dwCalcFmt = DT_CALCRECT; - - if (nWidthLimit > 0) - { - rc.right = nWidthLimit; - dwCalcFmt |= DT_WORDBREAK - | (dwFmt & DT_CENTER) - | (dwFmt & DT_RIGHT); - } - // use current font to measure text extent - HGDIOBJ hOld = SelectObject(_DC, _font); - - // measure text size - DrawTextW(_DC, pszText, nLen, &rc, dwCalcFmt); - SelectObject(_DC, hOld); - - tRet.cx = rc.right; - tRet.cy = rc.bottom; - } while (0); - - return tRet; - } - - bool prepareBitmap(int nWidth, int nHeight) - { - // release bitmap - if (_bmp) - { - DeleteObject(_bmp); - _bmp = NULL; - } - if (nWidth > 0 && nHeight > 0) - { - _bmp = CreateBitmap(nWidth, nHeight, 1, 32, NULL); - if (! _bmp) - { - return false; - } - } - return true; - } - - int drawText(const char * pszText, SIZE& tSize, Image::TextAlign eAlign) - { - int nRet = 0; - wchar_t * pwszBuffer = 0; - do - { - CC_BREAK_IF(! pszText); - - DWORD dwFmt = DT_WORDBREAK; - DWORD dwHoriFlag = (int)eAlign & 0x0f; - DWORD dwVertFlag = ((int)eAlign & 0xf0) >> 4; - - switch (dwHoriFlag) - { - case 1: // left - dwFmt |= DT_LEFT; - break; - case 2: // right - dwFmt |= DT_RIGHT; - break; - case 3: // center - dwFmt |= DT_CENTER; - break; - } - - int nLen = strlen(pszText); - // utf-8 to utf-16 - int nBufLen = nLen + 1; - pwszBuffer = new wchar_t[nBufLen]; - CC_BREAK_IF(! pwszBuffer); - - memset(pwszBuffer, 0, sizeof(wchar_t)*nBufLen); - nLen = MultiByteToWideChar(CP_UTF8, 0, pszText, nLen, pwszBuffer, nBufLen); - - SIZE newSize = sizeWithText(pwszBuffer, nLen, dwFmt, tSize.cx); - - RECT rcText = {0}; - // if content width is 0, use text size as content size - if (tSize.cx <= 0) - { - tSize = newSize; - rcText.right = newSize.cx; - rcText.bottom = newSize.cy; - } - else - { - - LONG offsetX = 0; - LONG offsetY = 0; - rcText.right = newSize.cx; // store the text width to rectangle - - // calculate text horizontal offset - if (1 != dwHoriFlag // and text isn't align to left - && newSize.cx < tSize.cx) // and text's width less then content width, - { // then need adjust offset of X. - offsetX = (2 == dwHoriFlag) ? tSize.cx - newSize.cx // align to right - : (tSize.cx - newSize.cx) / 2; // align to center - } - - // if content height is 0, use text height as content height - // else if content height less than text height, use content height to draw text - if (tSize.cy <= 0) - { - tSize.cy = newSize.cy; - dwFmt |= DT_NOCLIP; - rcText.bottom = newSize.cy; // store the text height to rectangle - } - else if (tSize.cy < newSize.cy) - { - // content height larger than text height need, clip text to rect - rcText.bottom = tSize.cy; - } - else - { - rcText.bottom = newSize.cy; // store the text height to rectangle - - // content larger than text, need adjust vertical position - dwFmt |= DT_NOCLIP; - - // calculate text vertical offset - offsetY = (2 == dwVertFlag) ? tSize.cy - newSize.cy // align to bottom - : (3 == dwVertFlag) ? (tSize.cy - newSize.cy) / 2 // align to middle - : 0; // align to top - } - - if (offsetX || offsetY) - { - OffsetRect(&rcText, offsetX, offsetY); - } - } - - CC_BREAK_IF(! prepareBitmap(tSize.cx, tSize.cy)); - - // draw text - HGDIOBJ hOldFont = SelectObject(_DC, _font); - HGDIOBJ hOldBmp = SelectObject(_DC, _bmp); - - SetBkMode(_DC, TRANSPARENT); - SetTextColor(_DC, RGB(255, 255, 255)); // white color - - // draw text - nRet = DrawTextW(_DC, pwszBuffer, nLen, &rcText, dwFmt); - //DrawTextA(_DC, pszText, nLen, &rcText, dwFmt); - - SelectObject(_DC, hOldBmp); - SelectObject(_DC, hOldFont); - } while (0); - CC_SAFE_DELETE_ARRAY(pwszBuffer); - return nRet; - } - - CC_SYNTHESIZE_READONLY(HDC, _DC, DC); - CC_SYNTHESIZE_READONLY(HBITMAP, _bmp, Bitmap); -private: - friend class Image; - HFONT _font; - HWND _wnd; - std::string _curFontPath; -}; - -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(); - - if (! dc.setFont(pFontName, nSize)) - { - log("Can't found font(%s), use system default", pFontName); - } - - // draw text - SIZE size = {nWidth, nHeight}; - CC_BREAK_IF(! dc.drawText(pText, size, eAlignMask)); - - _dataLen = size.cx * size.cy * 4; - _data = new unsigned char[_dataLen]; - CC_BREAK_IF(! _data); - - struct - { - BITMAPINFOHEADER bmiHeader; - int mask[4]; - } bi = {0}; - bi.bmiHeader.biSize = sizeof(bi.bmiHeader); - CC_BREAK_IF(! GetDIBits(dc.getDC(), dc.getBitmap(), 0, 0, - NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS)); - - _width = (short)size.cx; - _height = (short)size.cy; - _preMulti = false; - _renderFormat = Texture2D::PixelFormat::RGBA8888; - // copy pixed data - bi.bmiHeader.biHeight = (bi.bmiHeader.biHeight > 0) - ? - bi.bmiHeader.biHeight : bi.bmiHeader.biHeight; - GetDIBits(dc.getDC(), dc.getBitmap(), 0, _height, _data, - (LPBITMAPINFO)&bi, DIB_RGB_COLORS); - - // change pixel's alpha value to 255, when it's RGB != 0 - COLORREF * pPixel = NULL; - for (int y = 0; y < _height; ++y) - { - pPixel = (COLORREF *)_data + y * _width; - for (int x = 0; x < _width; ++x) - { - COLORREF& clr = *pPixel; - if (GetRValue(clr) || GetGValue(clr) || GetBValue(clr)) - { - clr |= 0xff000000; - } - ++pPixel; - } - } - - bRet = true; - } while (0); - - return bRet; -} - -NS_CC_END - -#endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32